@docx-editor.dev/telemetry

v2.29.0 · 7 published subpaths with full TypeScript signatures and JSDoc.

npmv2.29.0licenseEigenPal Prosourcegithub

Subpaths

@docx-editor.dev/telemetry/otel

OpenTelemetry: metrics and traces through the OpenTelemetry SDK you already run. This entry depends only on `@opentelemetry/api`; your SDK decides where data goes (OTLP to a collector, Datadog, Grafana, Honeycomb, New Relic, and others).

@docx-editor.dev/telemetry/sentry

Sentry: actionable failures become issues grouped by code; everything else becomes a breadcrumb, so it appears beside your own errors without using your event quota.

@docx-editor.dev/telemetry/prometheus

Prometheus: an in-process registry in the text exposition format, and `/metrics` handlers for Node-style servers ([metricsHandler](metricsHandler)) and Fetch-style servers ([fetchMetricsHandler](fetchMetricsHandler)). No dependency on `prom-client`; a `prom-client` registry merges into the same endpoint.

@docx-editor.dev/telemetry/server

Room telemetry for any Yjs collaboration server: rooms, connections, the people in each room, the memory each room holds, and why connections and messages were refused.

@docx-editor.dev/telemetry/hocuspocus

Hocuspocus: room telemetry in one call. It adds one extension that runs before all others and times each load and store from the first hook to the last, and it observes your hooks and the extensions you pass in `extensions`, so a refusal any of them throws is counted.

@docx-editor.dev/telemetry/ingest

Receive editor telemetry on your server and forward it to a log service, such as Better Stack, Axiom, or Datadog Logs. Pair it with `httpExporter` in the browser: the browser posts to your route, and only your server holds the log service's token.

Package root

- @docx-editor.dev/telemetry: [createTelemetry](createTelemetry) for editors, the console, callback, memory, and HTTP exporters, and [browserPrivacySignals](browserPrivacySignals). - @docx-editor.dev/telemetry/ingest: a route that receives telemetry from httpExporter and forwards it to a log service. - @docx-editor.dev/telemetry/otel: OpenTelemetry metrics and traces through your SDK. - @docx-editor.dev/telemetry/sentry: Sentry issues and breadcrumbs. - @docx-editor.dev/telemetry/prometheus: a /metrics endpoint. - @docx-editor.dev/telemetry/server: room telemetry for any Yjs server. - @docx-editor.dev/telemetry/hocuspocus: room telemetry for Hocuspocus in one call.

Functions (9)

browserPrivacySignalsfunctionSource ↗

A consent function that follows the browser's privacy signals: it returns false when the visitor sends Global Privacy Control or Do Not Track, or when optOutKey is set to off. Outside a browser page, such as during server rendering, it returns false. Combine it with your consent manager when you have one.

declare function browserPrivacySignals(options?: BrowserPrivacySignalsOptions): () => boolean;
```ts
import { browserPrivacySignals, createTelemetry } from '@docx-editor.dev/telemetry';

const privacy = browserPrivacySignals({ optOutKey: 'my-app:telemetry' });
export const telemetry = createTelemetry({
  exporters: [],
  consent: () => privacy() && consentManager.analytics,
});
```

callbackExporterfunctionSource ↗

Send each event to your own function: Datadog RUM, PostHog, a logger, or an API route.

onMetric receives every measurement. A performance summary arrives as one histogram sample for each timing in it, at the middle of the timing's band, so the bucket counts are exact. To chart percentiles, read p50Ms and p95Ms from the performance event instead.

declare function callbackExporter(onEvent: (event: TelemetryEvent) => void, onMetric?: (record: MetricRecord) => void): TelemetryExporter;
```ts
callbackExporter((event) =>
  isFailure(event)
    ? datadogRum.addError(new Error(event.kind), event)
    : datadogRum.addAction(event.kind, event)
);
```

consoleExporterfunctionSource ↗

Print each event with its hint and docs link. Use it during development to see why a document did not open or why a tracked change was refused.

declare function consoleExporter(options?: ConsoleExporterOptions): TelemetryExporter;
```ts
createTelemetry({ exporters: [consoleExporter()] });
// An agent deletes a picture while changes are tracked:
// [docx-editor] edit refused: edit.tracked-operation-unsupported (automation, tracked)
//   This editing API operation cannot be recorded as a tracked change, so nothing was ...
//   https://docx-editor.dev/docs/2.x/guides/diagnostics#edit-tracked-operation-unsupported
```

createTelemetryfunctionSource ↗

Create a telemetry client for editors.

Nothing is sent unless you pass an exporter. With consent, nothing is sent while it is false; without it, events are sent. Every event is anonymous: codes, enums, and bucketed numbers only.

declare function createTelemetry(options: TelemetryOptions): Telemetry;
```ts
import { createTelemetry, consoleExporter } from '@docx-editor.dev/telemetry';

export const telemetry = createTelemetry({
  exporters: [consoleExporter()],
  include: { documentOpen: true, trackedChanges: true },
});
```

explainDiagnosticfunctionSource ↗

What a diagnostic code means and what to do about it.

declare function explainDiagnostic(code: DiagnosticCode): DiagnosticExplanation;
```ts
editor.on('diagnostic', (event) => {
  if (event.kind === 'edit.rejected') console.warn(explainDiagnostic(event.code).hint);
});
```

httpExporterfunctionSource ↗

Batch events and POST them as a JSON array to your own endpoint.

While the page is open, events wait up to flushIntervalMs for a batch of batchSize, and each batch goes out with an ordinary fetch; so does a telemetry.flush() you call. When the page is hidden or closes, everything waiting goes out with sendBeacon. A closing page may send only about 64 KiB in all, so delivery while closing is best effort: batches beyond that are dropped and reported to onError. If consent is withdrawn, events still waiting are discarded.

declare function httpExporter(options: HttpExporterOptions): TelemetryExporter;
```ts
import { createTelemetry, httpExporter } from '@docx-editor.dev/telemetry';

export const telemetry = createTelemetry({
  exporters: [httpExporter({ url: '/api/telemetry' })],
  include: { documentOpen: true, editing: true, trackedChanges: true, performance: true },
});
```

isFailurefunctionSource ↗

Whether an event is a failure: a refused open, a refused edit other than an expected one (a stale range, a read-only document, protected content, a session or refresh not ready yet), an unreadable payload, a font that did not load, or a collaboration error. A missing font that was substituted and a tracked change someone else already reviewed are not. Use it in a callback to send failures as errors and the rest as actions or logs.

declare function isFailure(event: TelemetryEvent): boolean;
```ts
callbackExporter((event) => {
  const code = 'code' in event ? event.code : undefined;
  if (isFailure(event)) myLogger.error(event.kind, { code, hint: event.hint });
  else myLogger.info(event.kind);
});
```

memoryExporterfunctionSource ↗

Keep events and metrics in memory, for tests in your own suite.

declare function memoryExporter(): MemoryExporter;
```ts
const memory = memoryExporter();
const telemetry = createTelemetry({ exporters: [memory] });
// ...open a file that fails...
expect(memory.events).toContainEqual(
  expect.objectContaining({ code: 'open.missing-main-document' })
);
```

prometheusNamefunctionSource ↗

The Prometheus name of a metric: dots become underscores, the unit becomes a suffix, and a counter ends in _total, as the OpenTelemetry Prometheus exporter writes it.

declare function prometheusName(definition: MetricDefinition): string;
```ts
prometheusName(METRICS.editRejections); // 'docx_editor_edit_rejections_total'
prometheusName(METRICS.editorInteractionDuration); // 'docx_editor_editor_interaction_duration_seconds'
```

Interfaces (26)

BrowserPrivacySignalsOptionsinterfaceSource ↗

Options for [browserPrivacySignals](browserPrivacySignals).

interface BrowserPrivacySignalsOptions
MemberTypeSummary
optOutKey?stringA `localStorage` key that opts the visitor out when its value is `off`, such as one your privacy settings page writes. Omit it to read only the browser signals.

CollaborationParticipantsDiagnosticinterface

The number of people in the collaboration room changed.

interface CollaborationParticipantsDiagnostic extends DiagnosticBase
MemberTypeSummary
countnumberPeople present, this editor included. A person with two tabs counts twice.
kind'collab.participants'

CollaborationStatusDiagnosticinterface

A collaboration session changed status: it joined, disconnected, failed, or healed.

interface CollaborationStatusDiagnostic extends DiagnosticBase
MemberTypeSummary
code?CollaborationDiagnosticCodeWhy the session holds `status`, when something is wrong.
connectMs?numberMilliseconds from the editor attaching the session to its first `ready`. Present only on that change, and only when the editor saw the wait: a session that was already ready when the editor attached, as `useHocuspocusCollaboration` makes it, reports none.
kind'collab.status'
previousCollaborationStatus | 'none'The status before this change; `'none'` for the first status the editor saw.
recoveringbooleanTrue when the session will heal on its own; wait instead of rejoining.
statusCollaborationStatus

ConsoleExporterOptionsinterfaceSource ↗

Options for [consoleExporter](consoleExporter).

interface ConsoleExporterOptions
MemberTypeSummary
console?Pick<Console, 'info' | 'warn'>Where to print. Defaults to the global `console`.
metrics?booleanAlso print every metric measurement. Defaults to `false`.

CustomNodeDiagnosticEventinterface

A custom node's stored payload could not be read. The node and its data are not named.

interface CustomNodeDiagnosticEvent extends DiagnosticBase
MemberTypeSummary
codeCustomNodeDiagnosticCode
kind'custom-node'

DiagnosticBaseinterface

Fields every diagnostic carries.

interface DiagnosticBase
MemberTypeSummary
editorSessionIdstringRandom for each editor instance and never stored, so one open failure can be linked to the edits after it. It identifies no person and no document.
schemaVersionnumber[DIAGNOSTIC_SCHEMA_VERSION](DIAGNOSTIC_SCHEMA_VERSION) when the event was made.
timenumberMilliseconds since the epoch.

DiagnosticExplanationinterface

What a diagnostic code means and what to do about it.

Both strings are constants written for developers. They never contain document content, so an exporter can send them with the event.

interface DiagnosticExplanation
MemberTypeSummary
docsstringThe documentation anchor for this code, such as `…/guides/diagnostics#edit-read-only`.
hintstringOne or two sentences: the cause, then the action.

DiagnosticFailureDetailinterface

Anonymous detail of a failure, for the engineer who fixes it. Every field is optional and comes from a closed list: never a part name, an element name, a message, or document text.

interface DiagnosticFailureDetail
MemberTypeSummary
cause?stringThe engine's own reason, such as `undeclared-prefix` under `open.xml-malformed`, or `exception` for an error the engine did not expect. Causes can change between engine versions: match on `code`, and include the `cause` when you report a problem. See `diagnosticCauses()` for every value.
errorName?DiagnosticErrorNameThe class of the exception when `cause` is `exception`. Its message is never reported.
stage?FailureStageWhere the exception was caught, when `cause` is `exception`.

DocumentShapeinterface

The bucketed shape of an opened document.

interface DocumentShape
MemberTypeSummary
embeddedFontsCountBucket
paragraphsCountBucket
partsCountBucketXML parts in the package.
reviewItemsCountBucketTracked changes and comments, as the review queue lists them.

EditRejectedDiagnosticinterface

An edit, a command or a tracked change was refused.

interface EditRejectedDiagnostic extends DiagnosticBase, DiagnosticFailureDetail
MemberTypeSummary
codeEditDiagnosticCode
command?EditorCommand['type']The command type for `origin: 'command'`, such as `'insertTable'`.
kind'edit.rejected'
originEditRejectionOrigin`'command'` for `exec(...)`, `'input'` for typing, clipboard, drag and pointer edits, and `'automation'` for a batch from the editing API.
trackedbooleanTrue when the editor was suggesting (tracking changes) at the time.

FontFailedDiagnosticinterface

A font failed to load. The editor kept working with a substitute.

interface FontFailedDiagnostic extends DiagnosticBase
MemberTypeSummary
codeFontDiagnosticCode
kind'font.failed'

HistoryDiagnosticEventinterface

The undo history did not group edits as the gesture intended. Informational.

interface HistoryDiagnosticEvent extends DiagnosticBase
MemberTypeSummary
codeHistoryDiagnosticCode
kind'history'

HttpExporterOptionsinterfaceSource ↗

Options for [httpExporter](httpExporter).

interface HttpExporterOptions
MemberTypeSummary
batchSize?numberEvents per request, from 1 to 50. Defaults to 20. A full batch is sent at once. The limit matches the default `maxEvents` of `telemetryRoute`, which refuses a longer list.
flushIntervalMs?numberHow long an event waits for its batch to fill, in milliseconds. Defaults to 10 000.
headers?Readonly<Record<string, string>>Extra request headers. A browser cannot set headers on `sendBeacon`, so with headers, the batches sent while the page closes use `fetch` with `keepalive` instead.
onError?(error: unknown) => voidCalled when a request fails, or when batches are dropped because the page closed with more than the browser lets it send. Telemetry never throws into your app.
urlstringWhere to POST. Use a route on your own origin, which then forwards to your log service, so the service's token never reaches the browser. See `@docx-editor.dev/telemetry/ingest`.

MemoryExporterinterfaceSource ↗

An exporter that keeps what it receives. Returned by [memoryExporter](memoryExporter).

interface MemoryExporter extends TelemetryExporter
MemberTypeSummary
clearForget everything received so far.
eventsreadonly TelemetryEvent[]
metricsreadonly MetricRecord[]

MetricDefinitioninterfaceSource ↗

One metric in the catalog.

interface MetricDefinition
MemberTypeSummary
buckets?readonly number[]Histogram bucket upper bounds, in the metric's unit.
descriptionstring
kindMetricKind
labelsreadonly string[]The label keys this metric may carry. Each value is a bounded enum.
namestringOpenTelemetry name, such as `docx_editor.collab.room.load.duration`.
unitstringUCUM unit as OpenTelemetry writes it: `s`, `By`, `1`, or a `{annotation}`.

MetricRecordinterfaceSource ↗

One metric measurement.

interface MetricRecord
MemberTypeSummary
attributesAttributes
definitionMetricDefinition
valuenumberA counter increment, a gauge value, or a histogram sample, in the metric's unit.

PerformanceDiagnosticinterface

How the editor performed while it was used: one summary per window, never one event per key press. Sent after a minute of use, when the page is hidden, and when the editor is destroyed, if anything was measured since the last summary.

interface PerformanceDiagnostic extends DiagnosticBase
MemberTypeSummary
code?PerformanceDiagnosticCodePresent when the summary needs attention: `performance.slow-interaction` when at least 20 presses were timed and more than one in 20 took over 200 ms.
interaction?TimingSummaryKey presses and pointer presses on the pages, from the browser event to the next frame on screen: the delay a person feels. Presses queued behind slow work count with their full delay. Presses of modifier keys alone, and presses while the page is hidden, are not timed.
kind'performance'
layout?TimingSummaryEngine layout passes that the person causes, by an edit or a view change such as zoom. Each pass includes its main-thread work in the background, and the work of a pass that a newer edit replaced. Layouts that loading causes are not here: the opening layout, which `document.open` reports as `durationMs`, and layouts after fonts or images arrive.
pagesBucket?CountBucketPages in the document at the last paint.
paint?TimingSummaryEngine paints of the pages.
windowMsnumberMilliseconds from the window's first timing to the summary.

ReviewSkippedDiagnosticinterface

An accept, reject or re-author request skipped one or more tracked changes. One event for each code and kind of change in the request.

interface ReviewSkippedDiagnostic extends DiagnosticBase
MemberTypeSummary
cause?stringFor `review.revision-unsupported`, the engine condition that refused the change, such as `unaddressed` (no `w:id` or author) or `unrecorded-properties`. See `diagnosticCauses()`.
changeKind?ReviewChangeKindThe kind of the skipped changes, absent when the change no longer exists.
codeReviewDiagnosticCode
countnumberHow many items were skipped for this code and kind in the one request.
formattingKind?FormattingChangeKindFor `changeKind: 'format'`, which property change it is.
kind'review.skipped'
operation?ReviewOperationWhat the request asked: accept, reject, or attribute to another author.
part?DocumentPartKindThe role of the part the changes are in, such as `'footnotes'`. Never its name.

TelemetryinterfaceSource ↗

A configured telemetry client. Create it once, outside any component.

interface Telemetry
MemberTypeSummary
flushSend summaries of open deduplication windows, then flush every exporter.
moduleEditorModuleRegister this in the editor's `modules`. It observes every editor created with it, from the first open on.
moduleForA module for one editor, whose events also carry `attributes`, such as its collaboration room, document, or workspace. Create one for each editor, and keep it stable across renders. Use it in place of `module`, not next to it.
recordRecord one diagnostic yourself, for example from a runtime you created without `module`. Use `module` or `record`, not both, or every event is recorded twice. `attributes` are added to this event, as `moduleFor` adds them.
shutdownFlush, then stop. Later events are dropped.

TelemetryAreaOptionsinterfaceSource ↗

Options for one area.

interface TelemetryAreaOptions
MemberTypeSummary
sampleRate?numberShare of events to send, from 0 to 1. Metrics count every event, except that a `performance` rate of 0 turns performance off, metrics included. Defaults to 1. Each event is sampled on its own, except in `performance`: there the choice is made once for each editor, which sends all of its summaries or none.

TelemetryEventContextinterfaceSource ↗

Context the package adds to every diagnostic before it reaches an exporter.

interface TelemetryEventContext
MemberTypeSummary
attributesAttributesYour identifiers for this event: the client's `attributes`, then the values of the `moduleFor` module of the editor that sent it, such as a room, a document, or a user. Empty when you set none. The engine never adds a value here.
docs?stringThe documentation section for the event's code.
engineVersionstringThe version of the editor packages. Core and this package release together.
hint?stringThe fixed hint for the event's code. A constant, never document content.
repeated?numberPresent only on a summary: the event that closes a deduplication window repeats the first one, with the number of identical events folded into it beyond the first. Count it, do not treat it as a new failure. Its `time` is the first event's. The Sentry exporter records summaries as breadcrumbs.
resourceAttributesThe host's own values from `createTelemetry({ resource })`, such as `service.name`. The host decides what goes here, and every event carries it.

TelemetryExporterinterfaceSource ↗

Where telemetry goes. Implement event, metric, or both.

An exporter never throws into the editor or the server: a failure is caught and reported once through onExporterError.

interface TelemetryExporter
```ts
const toMyLogger: TelemetryExporter = {
  name: 'my-logger',
  event: (event) => myLogger.warn(event.kind, { code: 'code' in event ? event.code : undefined }),
};
```
MemberTypeSummary
attachCalled once when a telemetry client or room server takes the exporter. An exporter that holds events, such as a batching one, reads `consented()` before it sends, so events queued before consent was withdrawn are discarded, not sent.
declareStart a series at zero before its first measurement. A scraper that sees a counter first at 1 cannot count that first increase, so the room server declares its known series when it starts. Optional: an exporter without it creates each series at its first measurement.
event
flushSend anything buffered. Called by `flush()` and when a page is hidden.
forgetDrop a series that no longer exists, such as a closed room's per-room gauge. Optional: an exporter without it keeps the series until it expires on its own.
metric
namestringShown in `onExporterError` reports.
shutdownFlush and release resources. Called by `shutdown()`.

TelemetryExporterContextinterfaceSource ↗

What a telemetry client tells an exporter it takes.

interface TelemetryExporterContext
MemberTypeSummary
consentedWhether the host's consent is given, read now.
pageClosingWhether the page is hidden or closing, read now. While it is, a browser exporter sends with `sendBeacon` or `keepalive`, which still deliver after the page goes away.

TelemetryOptionsinterfaceSource ↗

Options for [createTelemetry](createTelemetry).

interface TelemetryOptions extends TelemetryPipelineOptions
MemberTypeSummary
attributes?Attributes | (() => Attributes)Your identifiers on every event, such as a tenant or a pseudonymous user id. A function is read at each event, so it can follow sign-in and tenant switches. Events only: to label metrics with a key, list it in `metricLabels`. For values that belong to one editor, such as its room or document, use [Telemetry.moduleFor](Telemetry.moduleFor).
dedupeWindowMs?numberIdentical refusals inside this window are sent once, then summarized with `repeated`. Holding Backspace on a locked drawing is one event, not hundreds. Defaults to 10 000 ms. Set 0 to send every event.
documentShape?'basic' | 'detailed'How much of an opened document's shape to send. `'basic'`, the default, sends the size and page buckets. `'detailed'` also sends part, paragraph, review item, and embedded font buckets: useful to group open times, but several counts together describe a document more closely, so ask for it only when you need it.
filter?(event: TelemetryEvent) => booleanWhich events go to your exporters, after the privacy check and sampling. Metrics still count every event. A filter that throws drops the event.
include?TelemetryIncludeThe areas to record. Omitted, every area is on.

TelemetryPipelineOptionsinterfaceSource ↗

Options shared by the editor client and the room server.

interface TelemetryPipelineOptions
MemberTypeSummary
exportersreadonly TelemetryExporter[]Where telemetry goes. Nothing is recorded or sent without at least one exporter.
metricLabels?readonly string[]Keys of your own attributes that may also label metrics, such as `tenant.tier` or `app.region`. Only for values with few distinct values: each value makes a new series. After [MAX_METRIC_LABEL_VALUES](MAX_METRIC_LABEL_VALUES) distinct values of one key, later values become `other`. Never list a user, document, or room id here; put those on events instead.
onExporterError?(error: unknown, exporter: string) => voidTold once per exporter when it throws. Defaults to one `console.warn`.
resource?AttributesValues added to every event, such as `{ 'service.name': 'contracts-app' }`. Metrics do not carry them: set resource attributes on your OpenTelemetry SDK or Prometheus target instead. You own these values: do not put a user, a document, or a room name here.

TimingSummaryinterface

Timings of one kind over a performance window. Every value is in milliseconds, rounded to whole milliseconds.

interface TimingSummary
MemberTypeSummary
bandsreadonly number[]Timings per band, always exact. Eight counts: up to 16, 33, 50, 100, 200, 500, and 1000 ms, then over 1000 ms. A metrics backend builds a histogram from these.
countnumberTimings measured in the window.
maxMsnumberThe slowest timing, always exact.
p50MsnumberMedian. Exact up to 2048 timings; above that, from a uniform sample of 2048.
p95Msnumber95th percentile, from the same sample as the median.

Type aliases (28)

AttributestypeSource ↗

Attributes or resource values, keyed by name.

type Attributes = Readonly<Record<string, AttributeValue>>;

AttributeValuetypeSource ↗

A metric attribute or a resource value.

type AttributeValue = string | number | boolean;

ByteSizeBuckettype

A coarse size, in powers of two, so a size cannot single out one document. '0-64KiB' covers everything under 64 KiB; '512MiB+' everything above.

type ByteSizeBucket = '0-64KiB' | '64-128KiB' | '128-256KiB' | '256-512KiB' | '512KiB-1MiB' | '1-2MiB' | '2-4MiB' | '4-8MiB' | '8-16MiB' | '16-32MiB' | '32-64MiB' | '64-128MiB' | '128-256MiB' | '256-512MiB' | '512MiB+';

CollaborationDiagnosticCodetype

Why a collaboration session failed or refused work: collab. and the session's own public [CollaborationFailureCode](CollaborationFailureCode), such as collab.authentication-failed.

type CollaborationDiagnosticCode = `collab.${CollaborationFailureCode}`;

CountBuckettype

A coarse count: '0', '1', '2-9', '10-99', '100-999', '1000+'.

type CountBucket = '0' | '1' | '2-9' | '10-99' | '100-999' | '1000+';

CustomNodeDiagnosticCodetype

Why a custom node's stored payload could not be read. The node name is never reported.

type CustomNodeDiagnosticCode = 'custom-node.payload-invalid' | 'custom-node.payload-missing';

DiagnosticCodetype

Every public diagnostic code. Codes are stable: a new one is additive, none is renamed.

type DiagnosticCode = DocumentOpenDiagnosticCode | EditDiagnosticCode | ReviewDiagnosticCode | FontDiagnosticCode | HistoryDiagnosticCode | CustomNodeDiagnosticCode | PerformanceDiagnosticCode | CollaborationDiagnosticCode;

DiagnosticErrorNametype

The class of an unexpected exception, for a failure the engine did not name. The message is never reported, because it can quote document content.

type DiagnosticErrorName = 'Error' | 'TypeError' | 'RangeError' | 'ReferenceError' | 'SyntaxError' | 'other';

DocumentOpenDiagnostictype

A document opened, or failed to open.

type DocumentOpenDiagnostic = DiagnosticBase & {
    readonly kind: 'document.open';
} & ({
    readonly outcome: 'opened';
    readonly sizeBucket: ByteSizeBucket;
    readonly pagesBucket?: CountBucket;
    readonly shape?: DocumentShape;
    readonly durationMs: number;
} | (DiagnosticFailureDetail & {
    readonly outcome: 'rejected';
    readonly code: DocumentOpenDiagnosticCode;
    readonly sizeBucket?: ByteSizeBucket;
    readonly part?: DocumentPartKind;
}));

DocumentOpenDiagnosticCodetype

Why a document could not be opened.

type DocumentOpenDiagnosticCode = 'open.unsupported-source' | 'open.zip-corrupt' | 'open.zip-invalid-entry-name' | 'open.zip-entry-limit' | 'open.zip-size-limit' | 'open.zip-ratio-limit' | 'open.xml-malformed' | 'open.xml-dtd-forbidden' | 'open.xml-part-size-limit' | 'open.xml-depth-limit' | 'open.xml-element-limit' | 'open.invalid-limits' | 'open.content-types-invalid' | 'open.missing-main-document' | 'open.relationships-invalid' | 'open.relationship-limit' | 'open.part-limit' | 'open.failed';

DocumentPartKindtype

Which kind of package part a failure is in, by its role, never by its name: a part's real name is file data. A name outside the standard layout reports 'other'.

type DocumentPartKind = 'package' | 'content-types' | 'relationships' | 'main-document' | 'glossary' | 'styles' | 'numbering' | 'settings' | 'web-settings' | 'font-table' | 'theme' | 'header' | 'footer' | 'footnotes' | 'endnotes' | 'comments' | 'people' | 'custom-xml' | 'document-properties' | 'media' | 'embedding' | 'other';

EditDiagnosticCodetype

Why an edit, a command or a tracked change was refused.

type EditDiagnosticCode = 'edit.read-only' | 'edit.protected-content' | 'edit.suggesting-needs-author' | 'edit.review-module-required' | 'edit.tracked-drawing-delete-unsupported' | 'edit.tracked-structure-unsupported' | 'edit.tracked-operation-unsupported' | 'edit.tracking-mode-unsupported' | 'edit.tracking-author-required' | 'edit.tracking-unsupported-host' | 'edit.revision-unsupported' | 'edit.tracking-required' | 'edit.tracked-image-replace-unsupported' | 'edit.picture-selected' | 'edit.cross-structure-join' | 'edit.indivisible-content' | 'edit.field-structure' | 'edit.section-mark' | 'edit.table-structure-unsupported' | 'edit.table-insert-refused' | 'edit.table-of-contents-refused' | 'edit.unsupported-content' | 'edit.operation-unsupported' | 'edit.unsupported-story' | 'edit.unmapped-change' | 'edit.stale-target' | 'edit.invalid-argument' | 'edit.resource-limit' | 'edit.refresh-in-progress' | 'edit.collaboration-not-ready' | 'edit.collaboration-text-limit' | 'edit.internal-invariant' | 'edit.refused';

EditorDiagnostictype

One anonymous diagnostic. Switch on kind to narrow code.

type EditorDiagnostic = DocumentOpenDiagnostic | EditRejectedDiagnostic | ReviewSkippedDiagnostic | FontFailedDiagnostic | HistoryDiagnosticEvent | CustomNodeDiagnosticEvent | CollaborationStatusDiagnostic | CollaborationParticipantsDiagnostic | PerformanceDiagnostic;
```ts
editor.on('diagnostic', (event) => {
  if (event.kind === 'edit.rejected') {
    console.warn(event.code, explainDiagnostic(event.code).hint);
  }
});
```

EditorDiagnosticKindtype

The kind of every [EditorDiagnostic](EditorDiagnostic).

type EditorDiagnosticKind = EditorDiagnostic['kind'];

EditRejectionOrigintype

Where a refused edit came from.

type EditRejectionOrigin = 'command' | 'input' | 'automation';

FailureStagetype

Where an exception the engine did not expect was caught: the mount of an open, a later layout slice of an open, a command, a single review action, or an editing API batch.

type FailureStage = 'open-mount' | 'open-layout' | 'command' | 'review-item' | 'automation';

FontDiagnosticCodetype

Why a font did not load. The family name is never reported.

type FontDiagnosticCode = 'font.shaper-unavailable' | 'font.load-failed' | 'font.missing' | 'font.integrity-mismatch' | 'font.malformed' | 'font.size-limit' | 'font.unsupported-face';

FormattingChangeKindtype

Which property change a formatting change is, by its OOXML element. A name outside this list reports 'other'.

type FormattingChangeKind = 'rPrChange' | 'pPrChange' | 'sectPrChange' | 'tblPrChange' | 'tblPrExChange' | 'tblGridChange' | 'trPrChange' | 'tcPrChange' | 'numberingChange' | 'other';

HistoryDiagnosticCodetype

Why the undo history did not group edits as one step. Informational: nothing was refused.

type HistoryDiagnosticCode = 'history.split' | 'history.possible-ungrouped-gesture' | 'history.possible-fragmented-gesture';

MetricIdtypeSource ↗

A key of [METRICS](METRICS).

type MetricId = keyof typeof METRICS;

MetricKindtypeSource ↗

How a metric aggregates.

type MetricKind = 'counter' | 'gauge' | 'histogram';

PerformanceDiagnosticCodetype

Why a performance summary needs attention. Informational: nothing was refused.

type PerformanceDiagnosticCode = 'performance.slow-interaction';

ReviewChangeKindtype

The kind of a tracked change, as the review queue lists it.

type ReviewChangeKind = 'insert' | 'delete' | 'replace' | 'moveFrom' | 'moveTo' | 'format' | 'paragraphMark' | 'structural';

ReviewDiagnosticCodetype

Why accepting, rejecting or re-authoring a tracked change skipped an item.

type ReviewDiagnosticCode = 'review.revision-unsupported' | 'review.incomplete-group' | 'review.retained-structure' | 'review.stale-revision';

ReviewOperationtype

What a tracked-change request was asked to do.

type ReviewOperation = 'accept' | 'reject' | 'reassign';

TelemetryAreatypeSource ↗

The areas you can switch on. Each one selects diagnostic kinds:

- documentOpen: documents opened and refused (document.open). - editing: edits and commands refused while changes are not tracked (edit.rejected). - trackedChanges: refusals while suggesting, refusals about tracking itself, and skipped tracked changes (edit.rejected with tracked: true, review.skipped). - fonts: fonts that failed and were substituted (font.failed). - history: undo steps that did not group as the gesture intended (history). - customNodes: custom node payloads that could not be read (custom-node). - collaborationClient: collaboration status changes and room size (collab.*). - performance: how fast the editor responds: key presses and clicks to the next frame, and engine layout and paint times, as one summary per minute of use (performance).

type TelemetryArea = 'documentOpen' | 'editing' | 'trackedChanges' | 'fonts' | 'history' | 'customNodes' | 'collaborationClient' | 'performance';

TelemetryEventtypeSource ↗

A diagnostic as an exporter receives it. Switch on kind to narrow it.

type TelemetryEvent = EditorDiagnostic & TelemetryEventContext;

TelemetryIncludetypeSource ↗

Which areas to record. An area that is absent or false records nothing.

type TelemetryInclude = {
    readonly [A in TelemetryArea]?: boolean | TelemetryAreaOptions;
};

Variables (3)

ENGINE_VERSIONconstSource ↗

The version of the editor packages, or 'development' when running from source.

ENGINE_VERSION: string

MAX_METRIC_LABEL_VALUESconstSource ↗

Distinct values one of your metric labels may take before later values become other.

MAX_METRIC_LABEL_VALUES = 50

METRICSconstSource ↗

Every metric the package records.

METRICS: Readonly<{
    documentOpens: MetricDefinition;
    documentOpenDuration: MetricDefinition;
    editRejections: MetricDefinition;
    reviewSkipped: MetricDefinition;
    fontFailures: MetricDefinition;
    historyDiagnostics: MetricDefinition;
    customNodeDiagnostics: MetricDefinition;
    collabClientStatusTransitions: MetricDefinition;
    collabClientConnectDuration: MetricDefinition;
    collabClientParticipants: MetricDefinition;
    editorInteractionDuration: MetricDefinition;
    editorLayoutDuration: MetricDefinition;
    editorPaintDuration: MetricDefinition;
    droppedEvents: MetricDefinition;
    roomsActive: MetricDefinition;
    connectionsActive: MetricDefinition;
    participantsActive: MetricDefinition;
    roomParticipants: MetricDefinition;
    roomParticipantsMax: MetricDefinition;
    roomMemory: MetricDefinition;
    roomsMemory: MetricDefinition;
    roomNodes: MetricDefinition;
    roomResourceUsage: MetricDefinition;
    roomAge: MetricDefinition;
    roomIdle: MetricDefinition;
    roomLoadDuration: MetricDefinition;
    roomStoreDuration: MetricDefinition;
    admissionRejections: MetricDefinition;
    messageRefusals: MetricDefinition;
    updates: MetricDefinition;
    updateBytes: MetricDefinition;
    roomParticipantsByRoom: MetricDefinition;
    roomMemoryByRoom: MetricDefinition;
    migrations: MetricDefinition;
}>
```ts
import { METRICS, prometheusName } from '@docx-editor.dev/telemetry';
prometheusName(METRICS.roomLoadDuration); // 'docx_editor_collab_room_load_duration_seconds'
```