@docx-editor.dev/telemetry 0.0.1 → 2.30.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 +89 -7
  2. package/THIRD_PARTY_NOTICES.md +22 -0
  3. package/dist/chunk-6BTB6Y3H.cjs +1 -0
  4. package/dist/chunk-7SYLCJFQ.cjs +1 -0
  5. package/dist/chunk-AL2YERWY.cjs +1 -0
  6. package/dist/chunk-DT2KMPUJ.js +1 -0
  7. package/dist/chunk-E2HR5DHZ.cjs +2 -0
  8. package/dist/chunk-E3FTXDLH.js +1 -0
  9. package/dist/chunk-JM4KJB6O.js +4 -0
  10. package/dist/chunk-PZZC5AXX.cjs +1 -0
  11. package/dist/chunk-QDOUVRQA.cjs +4 -0
  12. package/dist/chunk-RSWAOCAT.js +1 -0
  13. package/dist/chunk-W5HFB5EV.js +1 -0
  14. package/dist/chunk-WGWKNKUT.cjs +1 -0
  15. package/dist/chunk-WHVIRIUW.js +1 -0
  16. package/dist/chunk-WLWS5CZT.js +2 -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 +355 -0
  23. package/dist/index.d.ts +355 -0
  24. package/dist/index.js +1 -0
  25. package/dist/ingest/index.cjs +1 -0
  26. package/dist/ingest/index.d.cts +116 -0
  27. package/dist/ingest/index.d.ts +116 -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-CCq2Ng0B.d.cts +229 -0
  34. package/dist/pipeline-CCq2Ng0B.d.ts +229 -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
package/README.md CHANGED
@@ -1,17 +1,99 @@
1
1
  # @docx-editor.dev/telemetry
2
2
 
3
- This version is a placeholder. It reserves the package name and contains no code.
3
+ Anonymous diagnostics, metrics, and error reporting for `@docx-editor.dev` editors and collaboration servers. Send them to OpenTelemetry, Prometheus, Sentry, or your own logger.
4
4
 
5
- The first release with code is 2.29.0. Install that version or a later one:
5
+ Built-in diagnostics contain codes, booleans, bucketed sizes and counts, and timings. They exclude document text, file names, author names, font names, and room names. You control any attributes you add and any data your monitoring SDKs collect. The package sends data only through exporters you configure.
6
6
 
7
- ```bash
8
- npm install @docx-editor.dev/telemetry@^2.29.0
7
+ ## Install the package
8
+
9
+ The package is available in version 2.29.0 and later.
10
+
11
+ ```sh
12
+ npm install @docx-editor.dev/telemetry @docx-editor.dev/core
13
+ ```
14
+
15
+ Add `@opentelemetry/api` or `@hocuspocus/server` only for the exporters and server integrations that you use. The Sentry exporter takes the Sentry SDK your app already loads.
16
+
17
+ ## Editors
18
+
19
+ ```ts
20
+ import { createTelemetry } from '@docx-editor.dev/telemetry';
21
+ import { otelExporter } from '@docx-editor.dev/telemetry/otel';
22
+ import { sentryExporter } from '@docx-editor.dev/telemetry/sentry';
23
+ import * as Sentry from '@sentry/react';
24
+
25
+ export const telemetry = createTelemetry({
26
+ // Sentry for failures, OpenTelemetry for metrics such as typing delay.
27
+ exporters: [sentryExporter(Sentry), otelExporter()],
28
+ include: {
29
+ documentOpen: true,
30
+ documentSave: true,
31
+ trackedChanges: true,
32
+ editing: true,
33
+ performance: true,
34
+ sessions: true,
35
+ },
36
+ consent: () => consentManager.analytics === true, // your consent manager
37
+ });
38
+
39
+ // Outside your component, so the array is stable across renders:
40
+ export const MODULES = [telemetry.module];
41
+ // <DocxEditor document={bytes} modules={MODULES} />
42
+ ```
43
+
44
+ Use `consoleExporter()` to view diagnostics during development. For example, the following diagnostic explains why the editing API refused a tracked picture deletion:
45
+
46
+ ```text
47
+ [docx-editor] edit refused: edit.tracked-operation-unsupported (automation, tracked)
48
+ This editing API operation cannot be recorded as a tracked change, so nothing was applied. Use text edits such as range.insertText or range.delete, which tracking records. Never switch tracking off to make the edit succeed.
49
+ https://docx-editor.dev/docs/2.x/guides/diagnostics#edit-tracked-operation-unsupported
50
+ ```
51
+
52
+ The `performance` area measures typing delay and engine layout and paint times. Send it to an exporter that records metrics, such as `otelExporter()`. The Sentry exporter records performance only as breadcrumbs.
53
+
54
+ The `sessions` area counts editor sessions, active editing time, and edits by origin, so you can compute edit failure rates. The `documentSave` area reports each `save()` call with its outcome and duration. For queries and dashboards, see [Measure sessions, edits, and saves](https://docx-editor.dev/docs/2.x/telemetry/sessions).
55
+
56
+ ## Collaboration servers
57
+
58
+ ```ts
59
+ import { Server } from '@hocuspocus/server';
60
+ import { withCollaborationTelemetry } from '@docx-editor.dev/telemetry/hocuspocus';
61
+ import { metricsHandler, prometheusRegistry } from '@docx-editor.dev/telemetry/prometheus';
62
+
63
+ const metrics = prometheusRegistry();
64
+ const { config, rooms } = withCollaborationTelemetry(
65
+ { port: 1234, onAuthenticate, onLoadDocument, onStoreDocument },
66
+ { exporters: [metrics] }
67
+ );
68
+ new Server(config);
69
+
70
+ app.get('/metrics', metricsHandler(metrics));
71
+ app.get('/admin/rooms', requireAdmin, (_request, response) => response.json(rooms.list()));
9
72
  ```
10
73
 
11
- `@docx-editor.dev/telemetry` sends anonymous diagnostics and metrics from docx-editor editors and collaboration servers to OpenTelemetry, Prometheus, Sentry, or a log service. It never sends document content or personal data.
74
+ For other Yjs servers, use `roomTelemetry` from `@docx-editor.dev/telemetry/server`.
75
+
76
+ ## Dashboards
77
+
78
+ Grafana dashboards show editor input delay, engine timings, document opens, and refused edits. They also show collaboration rooms, people, memory, and refusals.
79
+
80
+ ![The Editor experience dashboard: input delay median and 95th percentile, presses over 1 second, opens succeeding, open time, metric sources reporting, unexpected refusals, and charts of input delay over time, by delay band, and by document size.](https://raw.githubusercontent.com/eigenpal/docx-editor/main/docs/site/content/telemetry/images/editor-experience.png)
81
+
82
+ Download [`editor-experience.json`](https://raw.githubusercontent.com/eigenpal/docx-editor/main/assets/observability/grafana/editor-experience.json) and [`collaboration.json`](https://raw.githubusercontent.com/eigenpal/docx-editor/main/assets/observability/grafana/collaboration.json), then import them into Grafana. For the setup each one needs, see [Dashboards](https://docx-editor.dev/docs/2.x/telemetry/dashboards).
83
+
84
+ ## Entry points
85
+
86
+ | Entry | Contents |
87
+ | --- | --- |
88
+ | `@docx-editor.dev/telemetry` | `createTelemetry`, `consoleExporter`, `callbackExporter`, `memoryExporter`, `isFailure`, `failureCount`, `explainDiagnostic`, the metric catalog |
89
+ | `@docx-editor.dev/telemetry/otel` | `otelExporter`, through your OpenTelemetry SDK |
90
+ | `@docx-editor.dev/telemetry/sentry` | `sentryExporter`, `dropEditorBreadcrumbs`, `EDITOR_SELECTORS` |
91
+ | `@docx-editor.dev/telemetry/prometheus` | `prometheusRegistry`, `metricsHandler`, `fetchMetricsHandler`, for server processes. Browser metrics go through `otelExporter()` and an OpenTelemetry collector. |
92
+ | `@docx-editor.dev/telemetry/server` | `roomTelemetry`, `hmacRoomLabel` |
93
+ | `@docx-editor.dev/telemetry/hocuspocus` | `withCollaborationTelemetry`, `serveMetrics`, `requireBearerToken`, `hmacRoomLabel` |
12
94
 
13
- For more information, see [Telemetry](https://docx-editor.dev/docs/2.x/telemetry) in the docx-editor documentation.
95
+ For the full guide, see [Telemetry](https://docx-editor.dev/docs/2.x/telemetry).
14
96
 
15
97
  ## License
16
98
 
17
- EigenPal Pro License. See [LICENSE.md](LICENSE.md).
99
+ EigenPal Pro License. See [LICENSE.md](./LICENSE.md).
@@ -0,0 +1,22 @@
1
+ # Third-party notices
2
+
3
+ `@docx-editor.dev/telemetry` is distributed under LicenseRef-EigenPal-Pro-Evaluation-1.0. Its published bundles also contain
4
+ source from the open-source packages listed below, redistributed here under
5
+ their own licenses, reproduced in full.
6
+
7
+ Those copies are not verbatim. The build inlines, minifies and tree-shakes
8
+ them, and includes only the parts each bundle reaches, so what ships is a
9
+ modified form of the original source.
10
+
11
+ The terms of LicenseRef-EigenPal-Pro-Evaluation-1.0 do not apply to the portions of these bundles
12
+ derived from the packages listed below. Those portions are licensed to you
13
+ under their own terms.
14
+
15
+ This file covers code copied INTO the published bundles. Packages this one
16
+ declares as `dependencies` or `peerDependencies` are installed separately by
17
+ the consumer and are not repeated here.
18
+
19
+ Generated by `bun run notices:generate` from the build's esbuild metafile.
20
+ Do not edit by hand.
21
+
22
+ No third-party code is bundled into this package.
@@ -0,0 +1 @@
1
+ 'use strict';var chunkAL2YERWY_cjs=require('./chunk-AL2YERWY.cjs'),chunk7SYLCJFQ_cjs=require('./chunk-7SYLCJFQ.cjs');var A=50,R="2.30.0";function M(o){let i=[...o.exporters],T=Object.freeze({...chunk7SYLCJFQ_cjs.c(o.resource??{},"resource")}),d=[...o.metricLabels??[]],m=new Map,b=new Set;function y(e){if(d.length===0)return e;let r={...e};for(let t of d){let n=r[t];if(n===void 0)continue;let s=String(n),a=m.get(t);if(a||m.set(t,a=new Set),!a.has(s)){if(a.size>=A){r[t]="other";continue}a.add(s);}}return r}let f=false;function p(e,r){if(!b.has(r)){b.add(r);try{if(o.onExporterError){let t=o.onExporterError(e,r);t&&typeof t.then=="function"&&Promise.resolve(t).catch(()=>{});}else console.warn(`[docx-editor telemetry] exporter "${r}" failed`,e);}catch{}}}function c(e,r){try{let t=r();if(!t||typeof t.then!="function")return;Promise.resolve(t).then(void 0,n=>p(n,e.name));}catch(t){p(t,e.name);}}function v(){let e=o.consent??true;if(typeof e=="boolean")return e;try{return e()===!0}catch{return false}}function u(){return !f&&v()}let E=false,_=()=>E||globalThis.document?.visibilityState==="hidden";for(let e of i)c(e,()=>e.attach?.({consented:v,pageClosing:_}));async function g(e){await Promise.all(i.map(async r=>{try{await e(r);}catch(t){p(t,r.name);}}));}return {resource:T,consented:u,event(e){if(!u())return;let r=chunk7SYLCJFQ_cjs.b(e);if("dropped"in r){this.metric(chunkAL2YERWY_cjs.a.droppedEvents,1,{reason:r.dropped});return}for(let t of i)t.event&&c(t,()=>t.event(r.event));},metric(e,r,t={}){if(!u()||!Number.isFinite(r))return;let n={definition:e,value:r,attributes:y(chunk7SYLCJFQ_cjs.c(t,e.name,[...e.labels,...d]))};for(let s of i)s.metric&&c(s,()=>s.metric(n));},forget(e,r){let t=chunk7SYLCJFQ_cjs.c(r,e.name,e.labels);for(let n of i)n.forget&&c(n,()=>n.forget(e,t));},declare(e,r={}){if(!u())return;let t=y(chunk7SYLCJFQ_cjs.c(r,e.name,[...e.labels,...d]));for(let n of i)n.declare&&c(n,()=>n.declare(e,t));},flush:()=>g(e=>e.flush?.()),setPageClosing(e){E=e;},async shutdown(){f||(f=true,await g(e=>e.shutdown?e.shutdown():e.flush?.()));}}}exports.a=A;exports.b=R;exports.c=M;
@@ -0,0 +1 @@
1
+ 'use strict';var chunkWGWKNKUT_cjs=require('./chunk-WGWKNKUT.cjs'),core=require('@docx-editor.dev/core');var O=new Set(core.diagnosticCodes());function f(e){return new Set(Object.keys(e))}var B=f({package:true,"content-types":true,relationships:true,"main-document":true,glossary:true,styles:true,numbering:true,settings:true,"web-settings":true,"font-table":true,theme:true,header:true,footer:true,footnotes:true,endnotes:true,comments:true,people:true,"custom-xml":true,"document-properties":true,media:true,embedding:true,other:true}),z=f({Error:true,TypeError:true,RangeError:true,ReferenceError:true,SyntaxError:true,other:true}),P=f({accept:true,reject:true,reassign:true}),F=f({"open-mount":true,"open-layout":true,command:true,"review-item":true,automation:true,save:true}),U=f({insert:true,delete:true,replace:true,moveFrom:true,moveTo:true,format:true,paragraphMark:true,structural:true}),G=f({rPrChange:true,pPrChange:true,sectPrChange:true,tblPrChange:true,tblPrExChange:true,tblGridChange:true,trPrChange:true,tcPrChange:true,numberingChange:true,other:true}),g=e=>e.phase==="active"||e.phase==="end",N={"document.open":{codes:"open",numbers:{durationMs:e=>e.outcome==="opened"}},"edit.rejected":{codes:"edit",numbers:{repeated:true}},"review.skipped":{codes:"review",numbers:{count:true}},"font.failed":{codes:"font",numbers:{repeated:true}},history:{codes:"history",numbers:{repeated:true}},"custom-node":{codes:"custom-node",numbers:{repeated:true}},"collab.status":{codes:"collab",numbers:{repeated:true,connectMs:e=>e.status==="ready"&&e.repeated===void 0}},"collab.participants":{numbers:{count:true}},performance:{codes:"performance",numbers:{windowMs:true}},"document.save":{codes:"save",numbers:{durationMs:true}},session:{numbers:{durationMs:g,activeMs:g,inputEdits:g,commandEdits:g,automationEdits:g}}},x=N,w={kind:new Set(Object.keys(N)),code:O,outcome:new Set(["opened","saved","rejected"]),phase:new Set(["start","active","end"]),origin:new Set(["command","input","automation"]),command:new Set(core.diagnosticCommands()),sizeBucket:/^(?:\d+(?:KiB|MiB)?-\d+(?:KiB|MiB)|512MiB\+)$/,pagesBucket:new Set(["0","1","2-9","10-99","100-999","1000+"]),editorSessionId:/^e_(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|[0-9a-f]{16,64}|[0-9a-z]{6,12}_[0-9a-z]{1,8})$/,engineVersion:/^(?:development|\d{1,4}\.\d{1,4}\.\d{1,4}(?:-[0-9A-Za-z.]{1,20})?)$/,status:new Set(["initializing","ready","disconnected","error","destroyed"]),previous:new Set(["none","initializing","ready","disconnected","error","destroyed"]),cause:new Set(core.diagnosticCauses()),part:B,errorName:z,stage:F,operation:P,changeKind:U,formattingKind:G},C=1e6,V=720*60*60*1e3,m={min:0,max:C,integer:true},h={min:0,max:V,integer:false},b={...h,removeAboveMax:true};function c(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>=t.min&&e<=t.max&&(!t.integer||Number.isInteger(e))}var S={schemaVersion:{min:1,max:1e3,integer:true},time:{min:0,max:864e13,integer:false},durationMs:b,count:m,repeated:{min:1,max:C,integer:true},connectMs:b,windowMs:b,activeMs:b,inputEdits:m,commandEdits:m,automationEdits:m},L=new Set(["schemaVersion","time"]);function Z(e,t){if(L.has(e))return true;let o=x[t.kind]?.numbers,r=o&&Object.hasOwn(o,e)?o[e]:void 0;return r===true||typeof r=="function"&&r(t)}var v=new Set(["tracked","recovering"]),E=new Set;function u(e,t=e){E.has(t)||chunkWGWKNKUT_cjs.a()==="production"||(E.add(t),console.warn(`[docx-editor telemetry] ${e}`));}function R(e,t){let o=Object.hasOwn(w,e)?w[e]:void 0;return o?o instanceof RegExp?o.test(t):o.has(t):false}function Q(e){let t=e;if(typeof t.kind!="string"||!R("kind",t.kind))return u("dropped an event of an unknown kind; core and telemetry versions may differ","kind"),{dropped:"unknown-kind"};let o=t.kind,r=typeof t.code=="string"?t.code:void 0,s=x[o]?.codes;if(r!==void 0&&(!O.has(r)||!s||!r.startsWith(`${s}.`)))return u("dropped an event with an unknown code; core and telemetry versions may differ","code"),{dropped:"unknown-code"};let a=r?core.explainDiagnostic(r):void 0,d={};for(let[n,i]of Object.entries(t)){if(n==="resource"||n==="attributes")continue;if(n==="shape"){let l=Y(i);if(!l)return u('dropped an event whose "shape" is not a valid document shape',"shape"),{dropped:"invalid-field"};d.shape=l;continue}if(A.has(n)){if(o!=="performance"){u(`removed "${n}", which only performance events carry`,`on:${n}`);continue}let l=X(i);if(!l)return u(`dropped an event whose "${n}" is not a valid timing summary`,`timing:${n}`),{dropped:"invalid-field"};d[n]=l;continue}if(n==="hint"||n==="docs"){a&&i===a[n]&&(d[n]=i);continue}let p=Object.hasOwn(S,n);if(p&&!Z(n,t)){u(`removed "${n}", which a ${o} event does not carry`,`on:${o}:${n}`);continue}let D=Object.hasOwn(w,n)||p||v.has(n),y=p?S[n]:void 0;if(y&&c(i,y))d[n]=i;else if(y?.removeAboveMax&&typeof i=="number"&&i>y.max){u(`removed "${n}", which is longer than the guard accepts`,`long:${n}`);continue}else if(typeof i=="boolean"&&v.has(n))d[n]=i;else if(typeof i=="string"&&R(n,i))d[n]=i;else {if(D)return u(`dropped an event whose "${n}" is not a valid value`,`field:${n}`),{dropped:"invalid-field"};u(`dropped the field "${n}", which is not an anonymous diagnostic field`,`extra:${n}`);}}return o==="performance"&&![...A].some(n=>d[n]!==void 0)?(u("dropped a performance summary without timings","performance:empty"),{dropped:"invalid-field"}):(d.resource=e.resource,d.attributes=e.attributes??{},{event:Object.freeze(d)})}var A=new Set(["interaction","layout","paint"]),H=["count","p50Ms","p95Ms","maxMs"],W=8;function X(e){if(!e||typeof e!="object")return null;let t=e,o=[...H,"bands"];if(Object.keys(t).some(i=>!o.includes(i)))return null;let{count:r,p50Ms:s,p95Ms:a,maxMs:d,bands:n}=t;return !c(r,m)||r<1||!c(s,h)||!c(a,h)||!c(d,h)||s>a||a>d||!Array.isArray(n)||n.length!==W||!n.every(i=>c(i,m))||n.reduce((i,p)=>i+p,0)!==r?null:Object.freeze({count:r,p50Ms:s,p95Ms:a,maxMs:d,bands:Object.freeze([...n])})}var M=["parts","paragraphs","reviewItems","embeddedFonts"];function Y(e){if(!e||typeof e!="object")return null;let t=e;if(Object.keys(t).some(r=>!M.includes(r)))return null;let o={};for(let r of M){let s=t[r];if(typeof s!="string"||!R("pagesBucket",s))return null;o[r]=s;}return Object.freeze(o)}var $=/^[A-Za-z_][A-Za-z0-9_.-]{0,63}$/,j=/^[A-Za-z0-9_.:+-]{0,64}$/;function ee(e,t,o){let r={};for(let[s,a]of Object.entries(e)){if(!$.test(s)||o&&!o.includes(s)){u(`dropped the attribute "${s.slice(0,40)}" on ${t}`,`attribute:${t}:${s}`);continue}typeof a=="number"||typeof a=="boolean"?r[s]=a:typeof a=="string"&&(r[s]=o&&!j.test(a)?"other":a.slice(0,256));}return r}function ne(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t={};for(let[o,r]of Object.entries(e))$.test(o)&&(typeof r=="boolean"||typeof r=="number"&&Number.isFinite(r)||typeof r=="string"&&r&&j.test(r))&&(t[o]=r);return Object.keys(t).length?t:void 0}exports.a=C;exports.b=Q;exports.c=ee;exports.d=ne;
@@ -0,0 +1 @@
1
+ 'use strict';var o="docx_editor.version",s=[.005,.01,.025,.05,.1,.25,.5,1,2.5,5,10,30,60],l=[1024,16*1024,64*1024,256*1024,1024*1024,4*1024*1024,16*1024*1024,64*1024*1024,256*1024*1024,1024*1024*1024],a=[.016,.033,.05,.1,.2,.5,1],d=[1,2,3,5,10,20,50,100,250],p=[1e3,1e4,5e4,1e5,25e4,5e5,1e6],g=[.1,.25,.5,.75,.9,.95,1],c=[60,300,900,3600,4*3600,24*3600,168*3600],h=[10,30,60,300,900,1800,3600,2*3600,4*3600,8*3600,24*3600];function e(t,r,n,m,u=[],i){return Object.freeze({name:t,kind:r,unit:n,description:m,labels:u,...i?{buckets:i}:{}})}var b=Object.freeze({documentOpens:e("docx_editor.document.opens","counter","{open}","Documents opened or refused, by outcome, refusal code, engine reason, and part role.",["outcome","code","cause","part",o]),documentOpenDuration:e("docx_editor.document.open.duration","histogram","s","Time from the start of an open to the laid-out document.",[o],s),documentSaves:e("docx_editor.document.saves","counter","{save}","Calls to save() that returned the document or failed, by outcome and failure code.",["outcome","code",o]),documentSaveDuration:e("docx_editor.document.save.duration","histogram","s","Time from a save() call to the saved bytes, pending edits included. Successful saves only.",[o],s),edits:e("docx_editor.edits","counter","{edit}","Edits that changed the document, by origin: input, command, or automation. Refused edits are in docx_editor.edit.rejections, and edits by collaborators are not counted. Counted when a session summary is sent, up to a minute after the edit.",["origin",o]),editRejections:e("docx_editor.edit.rejections","counter","{edit}","Edits, commands, and tracked changes refused, by public code and engine reason.",["code","cause","origin","tracked",o]),reviewSkipped:e("docx_editor.review.skipped","counter","{change}","Tracked changes skipped by accept, reject, or reassign requests, by engine reason, operation, and change kind.",["code","cause","operation","change_kind",o]),fontFailures:e("docx_editor.font.failures","counter","{failure}","Font faces that failed to load and were substituted.",["code",o]),historyDiagnostics:e("docx_editor.history.diagnostics","counter","{event}","Undo steps that did not group as the gesture intended, by code.",["code",o]),customNodeDiagnostics:e("docx_editor.custom_node.diagnostics","counter","{node}","Custom node payloads that could not be read, by code.",["code",o]),collabClientStatusTransitions:e("docx_editor.collab.client.status_transitions","counter","{transition}","Collaboration status changes on clients, by new status and failure code.",["status","code",o]),collabClientConnectDuration:e("docx_editor.collab.client.connect.duration","histogram","s","Time from an editor attaching a room to its first ready status, when the editor attached before the room was ready.",[o],s),collabClientParticipants:e("docx_editor.collab.client.participants","histogram","{participant}","People in the room, as each client sees it when the count changes.",[o],d),editorSessions:e("docx_editor.editor.sessions","counter","{session}","Editor sessions started and ended, by phase. An editor ends when it is destroyed or its page closes.",["phase",o]),editorSessionDuration:e("docx_editor.editor.session.duration","histogram","s","Time from the creation of an editor to its end, idle time included. Recorded when the session ends.",[o],h),editorActiveTime:e("docx_editor.editor.active_time","counter","s","Seconds of use: time between key presses, pointer presses, and edits that are at most 30 seconds apart. Counted when a session summary is sent.",[o]),editorInteractionDuration:e("docx_editor.editor.interaction.duration","histogram","s","Key presses and pointer presses on the pages, to the next frame on screen, by page count bucket. Bucket counts are exact; the sum is estimated from the bands.",["pages",o],a),editorLayoutDuration:e("docx_editor.editor.layout.duration","histogram","s","Engine layout passes after edits and view changes, background work included, by page count bucket. Bucket counts are exact; the sum is estimated from the bands.",["pages",o],a),editorPaintDuration:e("docx_editor.editor.paint.duration","histogram","s","Engine paints of the pages, by page count bucket. Bucket counts are exact; the sum is estimated from the bands.",["pages",o],a),droppedEvents:e("docx_editor.telemetry.dropped_events","counter","{event}","Events the anonymity guard dropped, by reason. Usually a version mismatch.",["reason",o]),roomsActive:e("docx_editor.collab.rooms.active","gauge","{room}","Rooms loaded."),connectionsActive:e("docx_editor.collab.connections.active","gauge","{connection}","Open client connections. One person with two tabs is two connections."),participantsActive:e("docx_editor.collab.participants.active","gauge","{participant}","People present in all rooms, from awareness states."),roomParticipants:e("docx_editor.collab.room.participants","histogram","{participant}","People present in each room, sampled once per room per interval.",[],d),roomParticipantsMax:e("docx_editor.collab.room.participants.max","gauge","{participant}","People in the fullest room now."),roomMemory:e("docx_editor.collab.room.memory","histogram","By","Bytes each room holds, sampled per room: encoded state, blobs, and updates not yet stored.",["kind"],l),roomsMemory:e("docx_editor.collab.rooms.memory","gauge","By","Bytes all rooms hold together at the last sample.",["kind"]),roomNodes:e("docx_editor.collab.room.nodes","histogram","{node}","Shared document nodes per room, live and tombstoned.",["state"],p),roomResourceUsage:e("docx_editor.collab.room.resource_usage","histogram","1","Share of each room resource limit in use, from 0 to 1.",["resource"],g),roomAge:e("docx_editor.collab.room.age","histogram","s","How long each room has been loaded.",[],c),roomIdle:e("docx_editor.collab.room.idle","histogram","s","Time since each room last changed.",[],c),roomLoadDuration:e("docx_editor.collab.room.load.duration","histogram","s","Time to load a room, by outcome.",["outcome"],s),roomStoreDuration:e("docx_editor.collab.room.store.duration","histogram","s","Time to store a room, by outcome.",["outcome"],s),admissionRejections:e("docx_editor.collab.admission.rejections","counter","{connection}","Connections refused at admission, by reason.",["reason"]),messageRefusals:e("docx_editor.collab.message.refusals","counter","{message}","Messages refused before they applied, by reason, such as room-generation-changed.",["reason"]),updates:e("docx_editor.collab.updates","counter","{update}","Document updates applied to rooms."),updateBytes:e("docx_editor.collab.update.bytes","counter","By","Bytes of document updates applied to rooms."),roomParticipantsByRoom:e("docx_editor.collab.room.participants.current","gauge","{participant}","People in each room, labeled by room. Recorded only with perRoomSeries.",["room"]),roomMemoryByRoom:e("docx_editor.collab.room.memory.current","gauge","By","Bytes each room holds, labeled by room and kind. Recorded only with perRoomSeries.",["room","kind"]),migrations:e("docx_editor.collab.migrations","counter","{room}","Room migrations, by outcome.",["outcome"])}),y={s:"seconds",By:"bytes"};function _(t){let r=t.name.replace(/[^a-zA-Z0-9_]/g,"_"),n=t.unit==="1"?t.kind==="gauge"?"ratio":void 0:y[t.unit];return n&&!r.endsWith(`_${n}`)&&(r+=`_${n}`),t.kind==="counter"&&(r+="_total"),r}exports.a=b;exports.b=_;
@@ -0,0 +1 @@
1
+ function n(){try{return process.env.NODE_ENV}catch{return}}export{n as a};
@@ -0,0 +1,2 @@
1
+ 'use strict';function l(e,o){return {name:"callback",event:e,...o?{metric:o}:{}}}function n(e){let o=e,r=["operation","changeKind","formattingKind","cause","errorName","stage","part"].map(t=>o[t]).filter(t=>typeof t=="string");return r.length?` [${r.join(", ")}]`:""}function i(e){let o=e.repeated?` (and ${e.repeated} more)`:"";switch(e.kind){case "document.open":return e.outcome==="rejected"?`document refused: ${e.code}${n(e)}`:e.pagesBucket===void 0?`document opened: ${e.sizeBucket}, ${e.durationMs} ms`:`document opened: ${e.pagesBucket} pages, ${e.sizeBucket}, ${e.durationMs} ms`;case "edit.rejected":{let r=e.command?`${e.origin} ${e.command}`:e.origin;return `edit refused: ${e.code}${n(e)} (${r}, ${e.tracked?"tracked":"untracked"})${o}`}case "review.skipped":return `tracked changes skipped: ${e.code}${n(e)} x${e.count}`;case "font.failed":return `font substituted: ${e.code}${o}`;case "history":return `undo history: ${e.code}${o}`;case "custom-node":return `custom node payload unreadable: ${e.code}${o}`;case "collab.participants":return `collaboration: ${e.count} ${e.count===1?"person":"people"} in the room`;case "collab.status":{let r=e.code?`: ${e.code}`:"",t=e.connectMs!==void 0?` after ${e.connectMs} ms`:"";return `collaboration ${e.status}${r}${e.recovering?" (recovering)":""}${t}`}case "performance":{let r=[s("key presses and clicks",e.interaction),s("layout",e.layout),s("paint",e.paint)].filter(Boolean),t=e.pagesBucket===void 0?"":`, ${e.pagesBucket} pages`;return `performance over ${Math.round(e.windowMs/1e3)} s${t}: ${r.join("; ")}`}case "document.save":return e.outcome==="saved"?`document saved: ${e.sizeBucket}, ${e.durationMs} ms`:`save failed: ${e.code}${n(e)} after ${e.durationMs} ms`;case "session":{if(e.phase==="start")return "editor session started";let r=e.inputEdits+e.commandEdits+e.automationEdits,t=`${Math.round(e.activeMs/1e3)} s active, ${r} ${r===1?"edit":"edits"}`;return e.phase==="end"?`editor session ended after ${Math.round(e.durationMs/1e3)} s: ${t}`:`editor activity over ${Math.round(e.durationMs/1e3)} s: ${t}`}}}function s(e,o){return o?`${e} p50 ${o.p50Ms} ms, p95 ${o.p95Ms} ms, max ${o.maxMs} ms (x${o.count})`:""}function a(e){return e.repeated===void 0&&c(e)}function p(e){return c(e)?e.repeated??1:0}function c(e){switch(e.kind){case "document.open":return e.outcome==="rejected";case "document.save":return e.outcome==="rejected";case "collab.participants":case "history":case "performance":case "session":return false;case "collab.status":return e.status==="error"&&e.code!=="collab.authentication-failed"&&e.code!=="collab.room-generation-changed";case "edit.rejected":return !d.has(e.code);case "font.failed":return e.code!=="font.missing";case "review.skipped":return e.code!=="review.stale-revision";default:return true}}var d=new Set(["edit.stale-target","edit.read-only","edit.protected-content","edit.refresh-in-progress","edit.collaboration-not-ready"]);function m(e={}){let o=e.console??console;return {name:"console",event(r){let t=[`[docx-editor] ${i(r)}`];r.hint&&t.push(` ${r.hint}`),r.docs&&t.push(` ${r.docs}`),(a(r)||r.kind==="performance"&&r.code!==void 0?o.warn:o.info).call(o,t.join(`
2
+ `));},...e.metrics?{metric(r){o.info(`[docx-editor] ${r.definition.name} ${r.value}`,r.attributes);}}:{}}}function $(){let e=[],o=[];return {name:"memory",events:e,metrics:o,event:r=>{e.push(r);},metric:r=>{o.push(r);},clear(){e.length=0,o.length=0;}}}exports.a=l;exports.b=i;exports.c=a;exports.d=p;exports.e=m;exports.f=$;
@@ -0,0 +1 @@
1
+ import {c}from'./chunk-WHVIRIUW.js';import {a}from'./chunk-RSWAOCAT.js';import {createHmac}from'crypto';import {readCollaborationResourceUsage}from'@docx-editor.dev/pro/collaboration';import {diagnosticCodes}from'@docx-editor.dev/core';import {isCollaborationFailureCode}from'@docx-editor.dev/core/collaboration';import*as M from'yjs';function X(r){if(typeof r!="string"||r.length===0)throw new TypeError("hmacRoomLabel needs a non-empty secret, such as an environment variable.");let o=c=>`room-${createHmac("sha256",r).update(c).digest("hex").slice(0,16)}`;return C.add(o),o}var C=new WeakSet;function z(r,o){if(!r)return "permission-denied";let c=r,u=typeof r=="string"?r:typeof r=="object"?c.reason??c.code??(typeof c.message=="string"&&o.has(c.message.toLowerCase())?c.message:void 0):void 0;if(u===void 0)return "other";if(typeof u=="number")return Y[u]??"other";if(typeof u!="string")return "other";if(isCollaborationFailureCode(u))return u;let b=u.toLowerCase();return o.has(b)?b:"other"}var Y={4401:"unauthorized",4403:"forbidden"},F=diagnosticCodes().map(r=>r.replace(/^collab\./,"")).filter(isCollaborationFailureCode),$=["unauthorized","forbidden","permission-denied","unknown-room","rate-limited"];function Z(r){let o=c(r),c$1=new Set([...$,...r.reasons??[]].map(e=>e.toLowerCase())),u=r.measureState??true;for(let e of new Set([...c$1,...F,"other"]))o.declare(a.admissionRejections,{reason:e}),o.declare(a.messageRefusals,{reason:e});for(let e of ["success","failure"])o.declare(a.roomLoadDuration,{outcome:e}),o.declare(a.roomStoreDuration,{outcome:e});for(let e of ["migrated","unchanged","failed"])o.declare(a.migrations,{outcome:e});o.declare(a.updates),o.declare(a.updateBytes);let b=e=>{try{return z(r.reasonOf?.(e)??e,c$1)}catch{return "other"}},B=r.perRoomSeries===true;if(B&&r.roomLabel&&!C.has(r.roomLabel))throw new TypeError("perRoomSeries puts the room label into every series, so it accepts only the default label or hmacRoomLabel(secret). A custom roomLabel could put a room name in a metric.");for(let e of r.exporters)e.metric||console.warn(`[docx-editor telemetry] exporter "${e.name}" records no metrics, and room telemetry sends only metrics. Use otelExporter or prometheusRegistry on a server.`);let m=new Set,E=0,_=r.roomLabel??(()=>`room-${E+=1}`),f=()=>Date.now();function g(){let e=0,n=0,t=0;for(let a of m){let l=w(a);e+=a.connections,n+=l,t=Math.max(t,l);}o.metric(a.roomsActive,m.size),o.metric(a.connectionsActive,e),o.metric(a.participantsActive,n),o.metric(a.roomParticipantsMax,t);}function S(e,n){let t=e==="load"?a.roomLoadDuration:a.roomStoreDuration,a$1=globalThis.performance?.now()??f(),l=n?.pendingBytes??0,y=false;return i=>{y||(y=true,o.metric(t,G(a$1),{outcome:i}),i==="success"&&e==="store"&&n&&(n.pendingBytes=Math.max(0,n.pendingBytes-l)));}}async function x(e,n,t){let a=S(e,t);try{let l=await n();return a("success"),l}catch(l){throw a("failure"),l}}function O(e,n){try{j(e,n);}catch{e.changed=true;}}function j(e,n){if(e.changed||!e.sampled){e.changed=false,e.sampled=true,u&&(e.stateBytes=M.encodeStateAsUpdate(e.doc).byteLength);try{let t=readCollaborationResourceUsage(e.doc);e.blobBytes=t.blobBytes,e.nodes=t.nodes;let a={nodes:t.nodes/t.maxNodes,relationships:t.relationships/t.maxRelationships,parts:t.parts/t.maxParts,blobBytes:t.blobBytes/t.maxBlobBytes};e.limitRatio=Math.max(...Object.values(a)),e.ratios=a,e.nodeStates={live:t.nodes-t.tombstonedNodes,tombstoned:t.tombstonedNodes};}catch{}}for(let[t,a$1]of Object.entries(e.ratios??{}))o.metric(a.roomResourceUsage,a$1,{resource:t});for(let[t,a$1]of Object.entries(e.nodeStates??{}))o.metric(a.roomNodes,a$1,{state:t});if(o.metric(a.roomParticipants,w(e)),e.stateBytes!==null&&o.metric(a.roomMemory,e.stateBytes,{kind:"state"}),e.blobBytes!==null&&o.metric(a.roomMemory,e.blobBytes,{kind:"blobs"}),o.metric(a.roomMemory,e.pendingBytes,{kind:"pending_updates"}),o.metric(a.roomAge,(n-e.openedAt)/1e3),o.metric(a.roomIdle,(n-e.lastChange)/1e3),B){let t=e.handle.label;o.metric(a.roomParticipantsByRoom,w(e),{room:t});for(let[a$1,l]of A(e))o.metric(a.roomMemoryByRoom,l,{room:t,kind:a$1});}}function h(){let e={state:0,blobs:0,pending_updates:0};for(let n of m)e.state+=n.stateBytes??0,e.blobs+=n.blobBytes??0,e.pending_updates+=n.pendingBytes;for(let[n,t]of Object.entries(e))o.metric(a.roomsMemory,t,{kind:n});g();}function D(){let e=f();for(let n of m)O(n,e);h();}let v=false;async function H(){if(!v){v=true;try{let e=f();for(let n of [...m])m.has(n)&&O(n,e),await new Promise(t=>setTimeout(t,0));h();}finally{v=false;}}}h();let T=r.sampleInterval??6e4,k=T===false?null:setInterval(()=>{H();},T);return k?.unref?.(),{open(e,n={}){let t=f(),a$1=(d,p)=>{if(i.changed=true,i.loading>0)return;i.lastChange=f();let R=p?.source;R==="redis"||R==="local"&&p.skipStoreHooks===true||(i.pendingBytes+=d.byteLength,o.metric(a.updates,1),o.metric(a.updateBytes,d.byteLength));},l=d=>{let{added:p,removed:R}=d??{};(p?.length??0)+(R?.length??0)>0&&g();};e.on("update",a$1),n.awareness?.on("change",l);let y={label:_(n.name??""),async time(d,p){d==="load"&&(i.loading+=1);try{return await x(d,p,i)}finally{d==="load"&&(i.loading-=1);}},begin:d=>S(d,i),connected(){i.connections+=1,g();},disconnected(){i.connections=Math.max(0,i.connections-1),g();},close(){if(m.delete(i)){if(i.dispose(),B){let d=y.label;o.forget(a.roomParticipantsByRoom,{room:d});for(let[p]of A(i))o.forget(a.roomMemoryByRoom,{room:d,kind:p});}h();}}},i={handle:y,doc:e,awareness:n.awareness,openedAt:t,lastChange:t,connections:0,pendingBytes:0,changed:true,loading:0,sampled:false,stateBytes:null,blobBytes:null,nodes:null,limitRatio:null,dispose(){e.off("update",a$1),n.awareness?.off("change",l);}};return m.add(i),g(),y},rejected(e){o.metric(a.admissionRejections,1,{reason:b(e)});},refused(e){o.metric(a.messageRefusals,1,{reason:b(e)});},migrated(e){o.metric(a.migrations,1,{outcome:e});},time:(e,n)=>x(e,n),begin:e=>S(e),list(){let e=f();return [...m].map(n=>({room:n.handle.label,participants:w(n),connections:n.connections,stateBytes:n.stateBytes,blobBytes:n.blobBytes,pendingBytes:n.pendingBytes,nodes:n.nodes,limitRatio:n.limitRatio,ageSeconds:Math.round((e-n.openedAt)/1e3),idleSeconds:Math.round((e-n.lastChange)/1e3)}))},sample:D,flush:()=>o.flush(),async shutdown(){k&&clearInterval(k);for(let e of [...m])e.handle.close();await o.shutdown();}}}function A(r){return [["state",r.stateBytes??0],["blobs",r.blobBytes??0],["pending_updates",r.pendingBytes]]}function w(r){if(!r.awareness)return r.connections;try{return r.awareness.getStates().size}catch{return r.connections}}function G(r){return Math.max(0,((globalThis.performance?.now()??Date.now())-r)/1e3)}export{X as a,Z as b};
@@ -0,0 +1,4 @@
1
+ import {b as b$1}from'./chunk-RSWAOCAT.js';var f="text/plain; version=0.0.4; charset=utf-8";function b(r){return r.replace(/\\/g,"\\\\").replace(/\n/g,"\\n").replace(/"/g,'\\"')}function u(r,i){let t=Object.keys(r).sort().map(e=>`${e.replace(/[^a-zA-Z0-9_]/g,"_")}="${b(String(r[e]))}"`);return i&&t.push(i),t.length?`{${t.join(",")}}`:""}function p(r){return Object.keys(r).sort().map(i=>`${i}\0${String(r[i])}`).join("")}function l(r){return r===1/0?"+Inf":r===-1/0?"-Inf":Number.isNaN(r)?"NaN":String(r)}function y(){let r=new Map,i=(t,e)=>{let s=r.get(t.name);s||(s={definition:t,series:new Map},r.set(t.name,s));let o=p(e),n=s.series.get(o);return n||(n={labels:e,value:0},t.kind==="histogram"&&(n.buckets=new Array((t.buckets??[]).length).fill(0),n.sum=0),s.series.set(o,n)),n};return {name:"prometheus",metric(t){let{definition:e,value:s,attributes:o}=t,n=i(e,o);e.kind==="counter"?n.value+=Math.max(0,s):e.kind==="gauge"?n.value=s:(n.value+=1,n.sum+=s,(e.buckets??[]).forEach((a,c)=>{s<=a&&(n.buckets[c]+=1);}));},declare(t,e){i(t,e);},forget(t,e){r.get(t.name)?.series.delete(p(e));},metrics(){let t=[];for(let{definition:e,series:s}of r.values()){let o=b$1(e);t.push(`# HELP ${o} ${e.description.replace(/\n/g," ")}`),t.push(`# TYPE ${o} ${e.kind}`);for(let n of s.values()){if(e.kind!=="histogram"){t.push(`${o}${u(n.labels)} ${l(n.value)}`);continue}(e.buckets??[]).forEach((a,c)=>{let d=`le="${l(a)}"`;t.push(`${o}_bucket${u(n.labels,d)} ${n.buckets[c]}`);}),t.push(`${o}_bucket${u(n.labels,'le="+Inf"')} ${n.value}`),t.push(`${o}_sum${u(n.labels)} ${l(n.sum)}`),t.push(`${o}_count${u(n.labels)} ${n.value}`);}}return t.length?`${t.join(`
2
+ `)}
3
+ `:""},reset(){r.clear();}}}async function g(r,i){return (await Promise.all([r,...i.merge??[]].map(e=>e.metrics()))).filter(Boolean).join(`
4
+ `)}function $(r,i={}){return async(t,e)=>{let s;try{s=await g(r,i);}catch{e.statusCode=500,e.end("metrics unavailable");return}e.statusCode=200,e.setHeader("Content-Type",f),e.end(s);}}function x(r,i={}){return async()=>{try{return new Response(await g(r,i),{headers:{"Content-Type":f}})}catch{return new Response("metrics unavailable",{status:500})}}}export{f as a,y as b,$ as c,x as d};
@@ -0,0 +1 @@
1
+ 'use strict';var chunk6BTB6Y3H_cjs=require('./chunk-6BTB6Y3H.cjs'),chunkAL2YERWY_cjs=require('./chunk-AL2YERWY.cjs'),crypto=require('crypto'),collaboration$1=require('@docx-editor.dev/pro/collaboration'),core=require('@docx-editor.dev/core'),collaboration=require('@docx-editor.dev/core/collaboration'),M=require('yjs');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var M__namespace=/*#__PURE__*/_interopNamespace(M);function X(r){if(typeof r!="string"||r.length===0)throw new TypeError("hmacRoomLabel needs a non-empty secret, such as an environment variable.");let o=c=>`room-${crypto.createHmac("sha256",r).update(c).digest("hex").slice(0,16)}`;return C.add(o),o}var C=new WeakSet;function z(r,o){if(!r)return "permission-denied";let c=r,u=typeof r=="string"?r:typeof r=="object"?c.reason??c.code??(typeof c.message=="string"&&o.has(c.message.toLowerCase())?c.message:void 0):void 0;if(u===void 0)return "other";if(typeof u=="number")return Y[u]??"other";if(typeof u!="string")return "other";if(collaboration.isCollaborationFailureCode(u))return u;let b=u.toLowerCase();return o.has(b)?b:"other"}var Y={4401:"unauthorized",4403:"forbidden"},F=core.diagnosticCodes().map(r=>r.replace(/^collab\./,"")).filter(collaboration.isCollaborationFailureCode),$=["unauthorized","forbidden","permission-denied","unknown-room","rate-limited"];function Z(r){let o=chunk6BTB6Y3H_cjs.c(r),c=new Set([...$,...r.reasons??[]].map(e=>e.toLowerCase())),u=r.measureState??true;for(let e of new Set([...c,...F,"other"]))o.declare(chunkAL2YERWY_cjs.a.admissionRejections,{reason:e}),o.declare(chunkAL2YERWY_cjs.a.messageRefusals,{reason:e});for(let e of ["success","failure"])o.declare(chunkAL2YERWY_cjs.a.roomLoadDuration,{outcome:e}),o.declare(chunkAL2YERWY_cjs.a.roomStoreDuration,{outcome:e});for(let e of ["migrated","unchanged","failed"])o.declare(chunkAL2YERWY_cjs.a.migrations,{outcome:e});o.declare(chunkAL2YERWY_cjs.a.updates),o.declare(chunkAL2YERWY_cjs.a.updateBytes);let b=e=>{try{return z(r.reasonOf?.(e)??e,c)}catch{return "other"}},B=r.perRoomSeries===true;if(B&&r.roomLabel&&!C.has(r.roomLabel))throw new TypeError("perRoomSeries puts the room label into every series, so it accepts only the default label or hmacRoomLabel(secret). A custom roomLabel could put a room name in a metric.");for(let e of r.exporters)e.metric||console.warn(`[docx-editor telemetry] exporter "${e.name}" records no metrics, and room telemetry sends only metrics. Use otelExporter or prometheusRegistry on a server.`);let m=new Set,E=0,_=r.roomLabel??(()=>`room-${E+=1}`),f=()=>Date.now();function g(){let e=0,n=0,t=0;for(let a of m){let l=w(a);e+=a.connections,n+=l,t=Math.max(t,l);}o.metric(chunkAL2YERWY_cjs.a.roomsActive,m.size),o.metric(chunkAL2YERWY_cjs.a.connectionsActive,e),o.metric(chunkAL2YERWY_cjs.a.participantsActive,n),o.metric(chunkAL2YERWY_cjs.a.roomParticipantsMax,t);}function S(e,n){let t=e==="load"?chunkAL2YERWY_cjs.a.roomLoadDuration:chunkAL2YERWY_cjs.a.roomStoreDuration,a=globalThis.performance?.now()??f(),l=n?.pendingBytes??0,y=false;return i=>{y||(y=true,o.metric(t,G(a),{outcome:i}),i==="success"&&e==="store"&&n&&(n.pendingBytes=Math.max(0,n.pendingBytes-l)));}}async function x(e,n,t){let a=S(e,t);try{let l=await n();return a("success"),l}catch(l){throw a("failure"),l}}function O(e,n){try{j(e,n);}catch{e.changed=true;}}function j(e,n){if(e.changed||!e.sampled){e.changed=false,e.sampled=true,u&&(e.stateBytes=M__namespace.encodeStateAsUpdate(e.doc).byteLength);try{let t=collaboration$1.readCollaborationResourceUsage(e.doc);e.blobBytes=t.blobBytes,e.nodes=t.nodes;let a={nodes:t.nodes/t.maxNodes,relationships:t.relationships/t.maxRelationships,parts:t.parts/t.maxParts,blobBytes:t.blobBytes/t.maxBlobBytes};e.limitRatio=Math.max(...Object.values(a)),e.ratios=a,e.nodeStates={live:t.nodes-t.tombstonedNodes,tombstoned:t.tombstonedNodes};}catch{}}for(let[t,a]of Object.entries(e.ratios??{}))o.metric(chunkAL2YERWY_cjs.a.roomResourceUsage,a,{resource:t});for(let[t,a]of Object.entries(e.nodeStates??{}))o.metric(chunkAL2YERWY_cjs.a.roomNodes,a,{state:t});if(o.metric(chunkAL2YERWY_cjs.a.roomParticipants,w(e)),e.stateBytes!==null&&o.metric(chunkAL2YERWY_cjs.a.roomMemory,e.stateBytes,{kind:"state"}),e.blobBytes!==null&&o.metric(chunkAL2YERWY_cjs.a.roomMemory,e.blobBytes,{kind:"blobs"}),o.metric(chunkAL2YERWY_cjs.a.roomMemory,e.pendingBytes,{kind:"pending_updates"}),o.metric(chunkAL2YERWY_cjs.a.roomAge,(n-e.openedAt)/1e3),o.metric(chunkAL2YERWY_cjs.a.roomIdle,(n-e.lastChange)/1e3),B){let t=e.handle.label;o.metric(chunkAL2YERWY_cjs.a.roomParticipantsByRoom,w(e),{room:t});for(let[a,l]of A(e))o.metric(chunkAL2YERWY_cjs.a.roomMemoryByRoom,l,{room:t,kind:a});}}function h(){let e={state:0,blobs:0,pending_updates:0};for(let n of m)e.state+=n.stateBytes??0,e.blobs+=n.blobBytes??0,e.pending_updates+=n.pendingBytes;for(let[n,t]of Object.entries(e))o.metric(chunkAL2YERWY_cjs.a.roomsMemory,t,{kind:n});g();}function D(){let e=f();for(let n of m)O(n,e);h();}let v=false;async function H(){if(!v){v=true;try{let e=f();for(let n of [...m])m.has(n)&&O(n,e),await new Promise(t=>setTimeout(t,0));h();}finally{v=false;}}}h();let T=r.sampleInterval??6e4,k=T===false?null:setInterval(()=>{H();},T);return k?.unref?.(),{open(e,n={}){let t=f(),a=(d,p)=>{if(i.changed=true,i.loading>0)return;i.lastChange=f();let R=p?.source;R==="redis"||R==="local"&&p.skipStoreHooks===true||(i.pendingBytes+=d.byteLength,o.metric(chunkAL2YERWY_cjs.a.updates,1),o.metric(chunkAL2YERWY_cjs.a.updateBytes,d.byteLength));},l=d=>{let{added:p,removed:R}=d??{};(p?.length??0)+(R?.length??0)>0&&g();};e.on("update",a),n.awareness?.on("change",l);let y={label:_(n.name??""),async time(d,p){d==="load"&&(i.loading+=1);try{return await x(d,p,i)}finally{d==="load"&&(i.loading-=1);}},begin:d=>S(d,i),connected(){i.connections+=1,g();},disconnected(){i.connections=Math.max(0,i.connections-1),g();},close(){if(m.delete(i)){if(i.dispose(),B){let d=y.label;o.forget(chunkAL2YERWY_cjs.a.roomParticipantsByRoom,{room:d});for(let[p]of A(i))o.forget(chunkAL2YERWY_cjs.a.roomMemoryByRoom,{room:d,kind:p});}h();}}},i={handle:y,doc:e,awareness:n.awareness,openedAt:t,lastChange:t,connections:0,pendingBytes:0,changed:true,loading:0,sampled:false,stateBytes:null,blobBytes:null,nodes:null,limitRatio:null,dispose(){e.off("update",a),n.awareness?.off("change",l);}};return m.add(i),g(),y},rejected(e){o.metric(chunkAL2YERWY_cjs.a.admissionRejections,1,{reason:b(e)});},refused(e){o.metric(chunkAL2YERWY_cjs.a.messageRefusals,1,{reason:b(e)});},migrated(e){o.metric(chunkAL2YERWY_cjs.a.migrations,1,{outcome:e});},time:(e,n)=>x(e,n),begin:e=>S(e),list(){let e=f();return [...m].map(n=>({room:n.handle.label,participants:w(n),connections:n.connections,stateBytes:n.stateBytes,blobBytes:n.blobBytes,pendingBytes:n.pendingBytes,nodes:n.nodes,limitRatio:n.limitRatio,ageSeconds:Math.round((e-n.openedAt)/1e3),idleSeconds:Math.round((e-n.lastChange)/1e3)}))},sample:D,flush:()=>o.flush(),async shutdown(){k&&clearInterval(k);for(let e of [...m])e.handle.close();await o.shutdown();}}}function A(r){return [["state",r.stateBytes??0],["blobs",r.blobBytes??0],["pending_updates",r.pendingBytes]]}function w(r){if(!r.awareness)return r.connections;try{return r.awareness.getStates().size}catch{return r.connections}}function G(r){return Math.max(0,((globalThis.performance?.now()??Date.now())-r)/1e3)}exports.a=X;exports.b=Z;
@@ -0,0 +1,4 @@
1
+ 'use strict';var chunkAL2YERWY_cjs=require('./chunk-AL2YERWY.cjs');var f="text/plain; version=0.0.4; charset=utf-8";function b(r){return r.replace(/\\/g,"\\\\").replace(/\n/g,"\\n").replace(/"/g,'\\"')}function u(r,i){let t=Object.keys(r).sort().map(e=>`${e.replace(/[^a-zA-Z0-9_]/g,"_")}="${b(String(r[e]))}"`);return i&&t.push(i),t.length?`{${t.join(",")}}`:""}function p(r){return Object.keys(r).sort().map(i=>`${i}\0${String(r[i])}`).join("")}function l(r){return r===1/0?"+Inf":r===-1/0?"-Inf":Number.isNaN(r)?"NaN":String(r)}function y(){let r=new Map,i=(t,e)=>{let s=r.get(t.name);s||(s={definition:t,series:new Map},r.set(t.name,s));let o=p(e),n=s.series.get(o);return n||(n={labels:e,value:0},t.kind==="histogram"&&(n.buckets=new Array((t.buckets??[]).length).fill(0),n.sum=0),s.series.set(o,n)),n};return {name:"prometheus",metric(t){let{definition:e,value:s,attributes:o}=t,n=i(e,o);e.kind==="counter"?n.value+=Math.max(0,s):e.kind==="gauge"?n.value=s:(n.value+=1,n.sum+=s,(e.buckets??[]).forEach((a,c)=>{s<=a&&(n.buckets[c]+=1);}));},declare(t,e){i(t,e);},forget(t,e){r.get(t.name)?.series.delete(p(e));},metrics(){let t=[];for(let{definition:e,series:s}of r.values()){let o=chunkAL2YERWY_cjs.b(e);t.push(`# HELP ${o} ${e.description.replace(/\n/g," ")}`),t.push(`# TYPE ${o} ${e.kind}`);for(let n of s.values()){if(e.kind!=="histogram"){t.push(`${o}${u(n.labels)} ${l(n.value)}`);continue}(e.buckets??[]).forEach((a,c)=>{let d=`le="${l(a)}"`;t.push(`${o}_bucket${u(n.labels,d)} ${n.buckets[c]}`);}),t.push(`${o}_bucket${u(n.labels,'le="+Inf"')} ${n.value}`),t.push(`${o}_sum${u(n.labels)} ${l(n.sum)}`),t.push(`${o}_count${u(n.labels)} ${n.value}`);}}return t.length?`${t.join(`
2
+ `)}
3
+ `:""},reset(){r.clear();}}}async function g(r,i){return (await Promise.all([r,...i.merge??[]].map(e=>e.metrics()))).filter(Boolean).join(`
4
+ `)}function $(r,i={}){return async(t,e)=>{let s;try{s=await g(r,i);}catch{e.statusCode=500,e.end("metrics unavailable");return}e.statusCode=200,e.setHeader("Content-Type",f),e.end(s);}}function x(r,i={}){return async()=>{try{return new Response(await g(r,i),{headers:{"Content-Type":f}})}catch{return new Response("metrics unavailable",{status:500})}}}exports.a=f;exports.b=y;exports.c=$;exports.d=x;
@@ -0,0 +1 @@
1
+ var o="docx_editor.version",s=[.005,.01,.025,.05,.1,.25,.5,1,2.5,5,10,30,60],l=[1024,16*1024,64*1024,256*1024,1024*1024,4*1024*1024,16*1024*1024,64*1024*1024,256*1024*1024,1024*1024*1024],a=[.016,.033,.05,.1,.2,.5,1],d=[1,2,3,5,10,20,50,100,250],p=[1e3,1e4,5e4,1e5,25e4,5e5,1e6],g=[.1,.25,.5,.75,.9,.95,1],c=[60,300,900,3600,4*3600,24*3600,168*3600],h=[10,30,60,300,900,1800,3600,2*3600,4*3600,8*3600,24*3600];function e(t,r,n,m,u=[],i){return Object.freeze({name:t,kind:r,unit:n,description:m,labels:u,...i?{buckets:i}:{}})}var b=Object.freeze({documentOpens:e("docx_editor.document.opens","counter","{open}","Documents opened or refused, by outcome, refusal code, engine reason, and part role.",["outcome","code","cause","part",o]),documentOpenDuration:e("docx_editor.document.open.duration","histogram","s","Time from the start of an open to the laid-out document.",[o],s),documentSaves:e("docx_editor.document.saves","counter","{save}","Calls to save() that returned the document or failed, by outcome and failure code.",["outcome","code",o]),documentSaveDuration:e("docx_editor.document.save.duration","histogram","s","Time from a save() call to the saved bytes, pending edits included. Successful saves only.",[o],s),edits:e("docx_editor.edits","counter","{edit}","Edits that changed the document, by origin: input, command, or automation. Refused edits are in docx_editor.edit.rejections, and edits by collaborators are not counted. Counted when a session summary is sent, up to a minute after the edit.",["origin",o]),editRejections:e("docx_editor.edit.rejections","counter","{edit}","Edits, commands, and tracked changes refused, by public code and engine reason.",["code","cause","origin","tracked",o]),reviewSkipped:e("docx_editor.review.skipped","counter","{change}","Tracked changes skipped by accept, reject, or reassign requests, by engine reason, operation, and change kind.",["code","cause","operation","change_kind",o]),fontFailures:e("docx_editor.font.failures","counter","{failure}","Font faces that failed to load and were substituted.",["code",o]),historyDiagnostics:e("docx_editor.history.diagnostics","counter","{event}","Undo steps that did not group as the gesture intended, by code.",["code",o]),customNodeDiagnostics:e("docx_editor.custom_node.diagnostics","counter","{node}","Custom node payloads that could not be read, by code.",["code",o]),collabClientStatusTransitions:e("docx_editor.collab.client.status_transitions","counter","{transition}","Collaboration status changes on clients, by new status and failure code.",["status","code",o]),collabClientConnectDuration:e("docx_editor.collab.client.connect.duration","histogram","s","Time from an editor attaching a room to its first ready status, when the editor attached before the room was ready.",[o],s),collabClientParticipants:e("docx_editor.collab.client.participants","histogram","{participant}","People in the room, as each client sees it when the count changes.",[o],d),editorSessions:e("docx_editor.editor.sessions","counter","{session}","Editor sessions started and ended, by phase. An editor ends when it is destroyed or its page closes.",["phase",o]),editorSessionDuration:e("docx_editor.editor.session.duration","histogram","s","Time from the creation of an editor to its end, idle time included. Recorded when the session ends.",[o],h),editorActiveTime:e("docx_editor.editor.active_time","counter","s","Seconds of use: time between key presses, pointer presses, and edits that are at most 30 seconds apart. Counted when a session summary is sent.",[o]),editorInteractionDuration:e("docx_editor.editor.interaction.duration","histogram","s","Key presses and pointer presses on the pages, to the next frame on screen, by page count bucket. Bucket counts are exact; the sum is estimated from the bands.",["pages",o],a),editorLayoutDuration:e("docx_editor.editor.layout.duration","histogram","s","Engine layout passes after edits and view changes, background work included, by page count bucket. Bucket counts are exact; the sum is estimated from the bands.",["pages",o],a),editorPaintDuration:e("docx_editor.editor.paint.duration","histogram","s","Engine paints of the pages, by page count bucket. Bucket counts are exact; the sum is estimated from the bands.",["pages",o],a),droppedEvents:e("docx_editor.telemetry.dropped_events","counter","{event}","Events the anonymity guard dropped, by reason. Usually a version mismatch.",["reason",o]),roomsActive:e("docx_editor.collab.rooms.active","gauge","{room}","Rooms loaded."),connectionsActive:e("docx_editor.collab.connections.active","gauge","{connection}","Open client connections. One person with two tabs is two connections."),participantsActive:e("docx_editor.collab.participants.active","gauge","{participant}","People present in all rooms, from awareness states."),roomParticipants:e("docx_editor.collab.room.participants","histogram","{participant}","People present in each room, sampled once per room per interval.",[],d),roomParticipantsMax:e("docx_editor.collab.room.participants.max","gauge","{participant}","People in the fullest room now."),roomMemory:e("docx_editor.collab.room.memory","histogram","By","Bytes each room holds, sampled per room: encoded state, blobs, and updates not yet stored.",["kind"],l),roomsMemory:e("docx_editor.collab.rooms.memory","gauge","By","Bytes all rooms hold together at the last sample.",["kind"]),roomNodes:e("docx_editor.collab.room.nodes","histogram","{node}","Shared document nodes per room, live and tombstoned.",["state"],p),roomResourceUsage:e("docx_editor.collab.room.resource_usage","histogram","1","Share of each room resource limit in use, from 0 to 1.",["resource"],g),roomAge:e("docx_editor.collab.room.age","histogram","s","How long each room has been loaded.",[],c),roomIdle:e("docx_editor.collab.room.idle","histogram","s","Time since each room last changed.",[],c),roomLoadDuration:e("docx_editor.collab.room.load.duration","histogram","s","Time to load a room, by outcome.",["outcome"],s),roomStoreDuration:e("docx_editor.collab.room.store.duration","histogram","s","Time to store a room, by outcome.",["outcome"],s),admissionRejections:e("docx_editor.collab.admission.rejections","counter","{connection}","Connections refused at admission, by reason.",["reason"]),messageRefusals:e("docx_editor.collab.message.refusals","counter","{message}","Messages refused before they applied, by reason, such as room-generation-changed.",["reason"]),updates:e("docx_editor.collab.updates","counter","{update}","Document updates applied to rooms."),updateBytes:e("docx_editor.collab.update.bytes","counter","By","Bytes of document updates applied to rooms."),roomParticipantsByRoom:e("docx_editor.collab.room.participants.current","gauge","{participant}","People in each room, labeled by room. Recorded only with perRoomSeries.",["room"]),roomMemoryByRoom:e("docx_editor.collab.room.memory.current","gauge","By","Bytes each room holds, labeled by room and kind. Recorded only with perRoomSeries.",["room","kind"]),migrations:e("docx_editor.collab.migrations","counter","{room}","Room migrations, by outcome.",["outcome"])}),y={s:"seconds",By:"bytes"};function _(t){let r=t.name.replace(/[^a-zA-Z0-9_]/g,"_"),n=t.unit==="1"?t.kind==="gauge"?"ratio":void 0:y[t.unit];return n&&!r.endsWith(`_${n}`)&&(r+=`_${n}`),t.kind==="counter"&&(r+="_total"),r}export{b as a,_ as b};
@@ -0,0 +1 @@
1
+ import {a}from'./chunk-DT2KMPUJ.js';import {diagnosticCodes,diagnosticCauses,diagnosticCommands,explainDiagnostic}from'@docx-editor.dev/core';var O=new Set(diagnosticCodes());function f(e){return new Set(Object.keys(e))}var B=f({package:true,"content-types":true,relationships:true,"main-document":true,glossary:true,styles:true,numbering:true,settings:true,"web-settings":true,"font-table":true,theme:true,header:true,footer:true,footnotes:true,endnotes:true,comments:true,people:true,"custom-xml":true,"document-properties":true,media:true,embedding:true,other:true}),z=f({Error:true,TypeError:true,RangeError:true,ReferenceError:true,SyntaxError:true,other:true}),P=f({accept:true,reject:true,reassign:true}),F=f({"open-mount":true,"open-layout":true,command:true,"review-item":true,automation:true,save:true}),U=f({insert:true,delete:true,replace:true,moveFrom:true,moveTo:true,format:true,paragraphMark:true,structural:true}),G=f({rPrChange:true,pPrChange:true,sectPrChange:true,tblPrChange:true,tblPrExChange:true,tblGridChange:true,trPrChange:true,tcPrChange:true,numberingChange:true,other:true}),g=e=>e.phase==="active"||e.phase==="end",N={"document.open":{codes:"open",numbers:{durationMs:e=>e.outcome==="opened"}},"edit.rejected":{codes:"edit",numbers:{repeated:true}},"review.skipped":{codes:"review",numbers:{count:true}},"font.failed":{codes:"font",numbers:{repeated:true}},history:{codes:"history",numbers:{repeated:true}},"custom-node":{codes:"custom-node",numbers:{repeated:true}},"collab.status":{codes:"collab",numbers:{repeated:true,connectMs:e=>e.status==="ready"&&e.repeated===void 0}},"collab.participants":{numbers:{count:true}},performance:{codes:"performance",numbers:{windowMs:true}},"document.save":{codes:"save",numbers:{durationMs:true}},session:{numbers:{durationMs:g,activeMs:g,inputEdits:g,commandEdits:g,automationEdits:g}}},x=N,w={kind:new Set(Object.keys(N)),code:O,outcome:new Set(["opened","saved","rejected"]),phase:new Set(["start","active","end"]),origin:new Set(["command","input","automation"]),command:new Set(diagnosticCommands()),sizeBucket:/^(?:\d+(?:KiB|MiB)?-\d+(?:KiB|MiB)|512MiB\+)$/,pagesBucket:new Set(["0","1","2-9","10-99","100-999","1000+"]),editorSessionId:/^e_(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|[0-9a-f]{16,64}|[0-9a-z]{6,12}_[0-9a-z]{1,8})$/,engineVersion:/^(?:development|\d{1,4}\.\d{1,4}\.\d{1,4}(?:-[0-9A-Za-z.]{1,20})?)$/,status:new Set(["initializing","ready","disconnected","error","destroyed"]),previous:new Set(["none","initializing","ready","disconnected","error","destroyed"]),cause:new Set(diagnosticCauses()),part:B,errorName:z,stage:F,operation:P,changeKind:U,formattingKind:G},C=1e6,V=720*60*60*1e3,m={min:0,max:C,integer:true},h={min:0,max:V,integer:false},b={...h,removeAboveMax:true};function c(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>=t.min&&e<=t.max&&(!t.integer||Number.isInteger(e))}var S={schemaVersion:{min:1,max:1e3,integer:true},time:{min:0,max:864e13,integer:false},durationMs:b,count:m,repeated:{min:1,max:C,integer:true},connectMs:b,windowMs:b,activeMs:b,inputEdits:m,commandEdits:m,automationEdits:m},L=new Set(["schemaVersion","time"]);function Z(e,t){if(L.has(e))return true;let o=x[t.kind]?.numbers,r=o&&Object.hasOwn(o,e)?o[e]:void 0;return r===true||typeof r=="function"&&r(t)}var v=new Set(["tracked","recovering"]),E=new Set;function u(e,t=e){E.has(t)||a()==="production"||(E.add(t),console.warn(`[docx-editor telemetry] ${e}`));}function R(e,t){let o=Object.hasOwn(w,e)?w[e]:void 0;return o?o instanceof RegExp?o.test(t):o.has(t):false}function Q(e){let t=e;if(typeof t.kind!="string"||!R("kind",t.kind))return u("dropped an event of an unknown kind; core and telemetry versions may differ","kind"),{dropped:"unknown-kind"};let o=t.kind,r=typeof t.code=="string"?t.code:void 0,s=x[o]?.codes;if(r!==void 0&&(!O.has(r)||!s||!r.startsWith(`${s}.`)))return u("dropped an event with an unknown code; core and telemetry versions may differ","code"),{dropped:"unknown-code"};let a=r?explainDiagnostic(r):void 0,d={};for(let[n,i]of Object.entries(t)){if(n==="resource"||n==="attributes")continue;if(n==="shape"){let l=Y(i);if(!l)return u('dropped an event whose "shape" is not a valid document shape',"shape"),{dropped:"invalid-field"};d.shape=l;continue}if(A.has(n)){if(o!=="performance"){u(`removed "${n}", which only performance events carry`,`on:${n}`);continue}let l=X(i);if(!l)return u(`dropped an event whose "${n}" is not a valid timing summary`,`timing:${n}`),{dropped:"invalid-field"};d[n]=l;continue}if(n==="hint"||n==="docs"){a&&i===a[n]&&(d[n]=i);continue}let p=Object.hasOwn(S,n);if(p&&!Z(n,t)){u(`removed "${n}", which a ${o} event does not carry`,`on:${o}:${n}`);continue}let D=Object.hasOwn(w,n)||p||v.has(n),y=p?S[n]:void 0;if(y&&c(i,y))d[n]=i;else if(y?.removeAboveMax&&typeof i=="number"&&i>y.max){u(`removed "${n}", which is longer than the guard accepts`,`long:${n}`);continue}else if(typeof i=="boolean"&&v.has(n))d[n]=i;else if(typeof i=="string"&&R(n,i))d[n]=i;else {if(D)return u(`dropped an event whose "${n}" is not a valid value`,`field:${n}`),{dropped:"invalid-field"};u(`dropped the field "${n}", which is not an anonymous diagnostic field`,`extra:${n}`);}}return o==="performance"&&![...A].some(n=>d[n]!==void 0)?(u("dropped a performance summary without timings","performance:empty"),{dropped:"invalid-field"}):(d.resource=e.resource,d.attributes=e.attributes??{},{event:Object.freeze(d)})}var A=new Set(["interaction","layout","paint"]),H=["count","p50Ms","p95Ms","maxMs"],W=8;function X(e){if(!e||typeof e!="object")return null;let t=e,o=[...H,"bands"];if(Object.keys(t).some(i=>!o.includes(i)))return null;let{count:r,p50Ms:s,p95Ms:a,maxMs:d,bands:n}=t;return !c(r,m)||r<1||!c(s,h)||!c(a,h)||!c(d,h)||s>a||a>d||!Array.isArray(n)||n.length!==W||!n.every(i=>c(i,m))||n.reduce((i,p)=>i+p,0)!==r?null:Object.freeze({count:r,p50Ms:s,p95Ms:a,maxMs:d,bands:Object.freeze([...n])})}var M=["parts","paragraphs","reviewItems","embeddedFonts"];function Y(e){if(!e||typeof e!="object")return null;let t=e;if(Object.keys(t).some(r=>!M.includes(r)))return null;let o={};for(let r of M){let s=t[r];if(typeof s!="string"||!R("pagesBucket",s))return null;o[r]=s;}return Object.freeze(o)}var $=/^[A-Za-z_][A-Za-z0-9_.-]{0,63}$/,j=/^[A-Za-z0-9_.:+-]{0,64}$/;function ee(e,t,o){let r={};for(let[s,a]of Object.entries(e)){if(!$.test(s)||o&&!o.includes(s)){u(`dropped the attribute "${s.slice(0,40)}" on ${t}`,`attribute:${t}:${s}`);continue}typeof a=="number"||typeof a=="boolean"?r[s]=a:typeof a=="string"&&(r[s]=o&&!j.test(a)?"other":a.slice(0,256));}return r}function ne(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t={};for(let[o,r]of Object.entries(e))$.test(o)&&(typeof r=="boolean"||typeof r=="number"&&Number.isFinite(r)||typeof r=="string"&&r&&j.test(r))&&(t[o]=r);return Object.keys(t).length?t:void 0}export{C as a,Q as b,ee as c,ne as d};
@@ -0,0 +1 @@
1
+ 'use strict';function n(){try{return process.env.NODE_ENV}catch{return}}exports.a=n;
@@ -0,0 +1 @@
1
+ import {a}from'./chunk-RSWAOCAT.js';import {c,b}from'./chunk-W5HFB5EV.js';var A=50,R="2.30.0";function M(o){let i=[...o.exporters],T=Object.freeze({...c(o.resource??{},"resource")}),d=[...o.metricLabels??[]],m=new Map,b$1=new Set;function y(e){if(d.length===0)return e;let r={...e};for(let t of d){let n=r[t];if(n===void 0)continue;let s=String(n),a=m.get(t);if(a||m.set(t,a=new Set),!a.has(s)){if(a.size>=A){r[t]="other";continue}a.add(s);}}return r}let f=false;function p(e,r){if(!b$1.has(r)){b$1.add(r);try{if(o.onExporterError){let t=o.onExporterError(e,r);t&&typeof t.then=="function"&&Promise.resolve(t).catch(()=>{});}else console.warn(`[docx-editor telemetry] exporter "${r}" failed`,e);}catch{}}}function c$1(e,r){try{let t=r();if(!t||typeof t.then!="function")return;Promise.resolve(t).then(void 0,n=>p(n,e.name));}catch(t){p(t,e.name);}}function v(){let e=o.consent??true;if(typeof e=="boolean")return e;try{return e()===!0}catch{return false}}function u(){return !f&&v()}let E=false,_=()=>E||globalThis.document?.visibilityState==="hidden";for(let e of i)c$1(e,()=>e.attach?.({consented:v,pageClosing:_}));async function g(e){await Promise.all(i.map(async r=>{try{await e(r);}catch(t){p(t,r.name);}}));}return {resource:T,consented:u,event(e){if(!u())return;let r=b(e);if("dropped"in r){this.metric(a.droppedEvents,1,{reason:r.dropped});return}for(let t of i)t.event&&c$1(t,()=>t.event(r.event));},metric(e,r,t={}){if(!u()||!Number.isFinite(r))return;let n={definition:e,value:r,attributes:y(c(t,e.name,[...e.labels,...d]))};for(let s of i)s.metric&&c$1(s,()=>s.metric(n));},forget(e,r){let t=c(r,e.name,e.labels);for(let n of i)n.forget&&c$1(n,()=>n.forget(e,t));},declare(e,r={}){if(!u())return;let t=y(c(r,e.name,[...e.labels,...d]));for(let n of i)n.declare&&c$1(n,()=>n.declare(e,t));},flush:()=>g(e=>e.flush?.()),setPageClosing(e){E=e;},async shutdown(){f||(f=true,await g(e=>e.shutdown?e.shutdown():e.flush?.()));}}}export{A as a,R as b,M as c};
@@ -0,0 +1,2 @@
1
+ function l(e,o){return {name:"callback",event:e,...o?{metric:o}:{}}}function n(e){let o=e,r=["operation","changeKind","formattingKind","cause","errorName","stage","part"].map(t=>o[t]).filter(t=>typeof t=="string");return r.length?` [${r.join(", ")}]`:""}function i(e){let o=e.repeated?` (and ${e.repeated} more)`:"";switch(e.kind){case "document.open":return e.outcome==="rejected"?`document refused: ${e.code}${n(e)}`:e.pagesBucket===void 0?`document opened: ${e.sizeBucket}, ${e.durationMs} ms`:`document opened: ${e.pagesBucket} pages, ${e.sizeBucket}, ${e.durationMs} ms`;case "edit.rejected":{let r=e.command?`${e.origin} ${e.command}`:e.origin;return `edit refused: ${e.code}${n(e)} (${r}, ${e.tracked?"tracked":"untracked"})${o}`}case "review.skipped":return `tracked changes skipped: ${e.code}${n(e)} x${e.count}`;case "font.failed":return `font substituted: ${e.code}${o}`;case "history":return `undo history: ${e.code}${o}`;case "custom-node":return `custom node payload unreadable: ${e.code}${o}`;case "collab.participants":return `collaboration: ${e.count} ${e.count===1?"person":"people"} in the room`;case "collab.status":{let r=e.code?`: ${e.code}`:"",t=e.connectMs!==void 0?` after ${e.connectMs} ms`:"";return `collaboration ${e.status}${r}${e.recovering?" (recovering)":""}${t}`}case "performance":{let r=[s("key presses and clicks",e.interaction),s("layout",e.layout),s("paint",e.paint)].filter(Boolean),t=e.pagesBucket===void 0?"":`, ${e.pagesBucket} pages`;return `performance over ${Math.round(e.windowMs/1e3)} s${t}: ${r.join("; ")}`}case "document.save":return e.outcome==="saved"?`document saved: ${e.sizeBucket}, ${e.durationMs} ms`:`save failed: ${e.code}${n(e)} after ${e.durationMs} ms`;case "session":{if(e.phase==="start")return "editor session started";let r=e.inputEdits+e.commandEdits+e.automationEdits,t=`${Math.round(e.activeMs/1e3)} s active, ${r} ${r===1?"edit":"edits"}`;return e.phase==="end"?`editor session ended after ${Math.round(e.durationMs/1e3)} s: ${t}`:`editor activity over ${Math.round(e.durationMs/1e3)} s: ${t}`}}}function s(e,o){return o?`${e} p50 ${o.p50Ms} ms, p95 ${o.p95Ms} ms, max ${o.maxMs} ms (x${o.count})`:""}function a(e){return e.repeated===void 0&&c(e)}function p(e){return c(e)?e.repeated??1:0}function c(e){switch(e.kind){case "document.open":return e.outcome==="rejected";case "document.save":return e.outcome==="rejected";case "collab.participants":case "history":case "performance":case "session":return false;case "collab.status":return e.status==="error"&&e.code!=="collab.authentication-failed"&&e.code!=="collab.room-generation-changed";case "edit.rejected":return !d.has(e.code);case "font.failed":return e.code!=="font.missing";case "review.skipped":return e.code!=="review.stale-revision";default:return true}}var d=new Set(["edit.stale-target","edit.read-only","edit.protected-content","edit.refresh-in-progress","edit.collaboration-not-ready"]);function m(e={}){let o=e.console??console;return {name:"console",event(r){let t=[`[docx-editor] ${i(r)}`];r.hint&&t.push(` ${r.hint}`),r.docs&&t.push(` ${r.docs}`),(a(r)||r.kind==="performance"&&r.code!==void 0?o.warn:o.info).call(o,t.join(`
2
+ `));},...e.metrics?{metric(r){o.info(`[docx-editor] ${r.definition.name} ${r.value}`,r.attributes);}}:{}}}function $(){let e=[],o=[];return {name:"memory",events:e,metrics:o,event:r=>{e.push(r);},metric:r=>{o.push(r);},clear(){e.length=0,o.length=0;}}}export{l as a,i as b,a as c,p as d,m as e,$ as f};
@@ -0,0 +1 @@
1
+ 'use strict';var chunkQDOUVRQA_cjs=require('../chunk-QDOUVRQA.cjs'),chunkPZZC5AXX_cjs=require('../chunk-PZZC5AXX.cjs');require('../chunk-6BTB6Y3H.cjs'),require('../chunk-AL2YERWY.cjs'),require('../chunk-7SYLCJFQ.cjs'),require('../chunk-WGWKNKUT.cjs');var crypto=require('crypto');function U(a){if(typeof a!="string"||a.length===0)throw new TypeError("requireBearerToken needs a non-empty secret, such as METRICS_TOKEN.");let n=Buffer.from(`Bearer ${a}`);return c=>{let l=c.headers?.authorization,i=Buffer.from(typeof l=="string"?l:"");return i.length===n.length&&crypto.timingSafeEqual(i,n)}}function $(a,n={}){if(n.rooms&&!n.authorize)throw new TypeError("serveMetrics needs authorize when it serves rooms: the list is private.");let c=n.path??"/metrics",l=chunkQDOUVRQA_cjs.c(a,n.merge?{merge:n.merge}:{}),i=0;return async({request:u,response:f})=>{let g=(u.url??"").split("?")[0],w=n.rooms?.path;if(g!==c&&g!==w){await n.next?.({request:u,response:f});return}throw n.authorize&&!A(n.authorize,u)?(f.writeHead(403),f.end()):g===c?(n.sampleBeforeScrape&&Date.now()-i>=5e3&&(i=Date.now(),n.sampleBeforeScrape.sample()),await l(u,f)):(f.writeHead(200,{"Content-Type":"application/json"}),f.end(JSON.stringify(n.rooms.telemetry.list()))),null}}function I(a,n){let c=chunkPZZC5AXX_cjs.b(n),l=new Map,i=new Map,u=new Map,f=e=>typeof e.afterLoadDocument=="function",g=1+(a.extensions??[]).filter(e=>f(e)).length+(f(a)?1:0),w=e=>{let r=(u.get(e)??0)+1;u.set(e,r),!(r<g)&&(u.delete(e),y(i,e,"success"));},p=new Map,R=e=>typeof e.afterStoreDocument=="function",M=1+(a.extensions??[]).filter(e=>R(e)).length+(R(a)?1:0),D=e=>{let r=(p.get(e)??0)+1;p.set(e,r),!(r<M)&&(p.delete(e),y(m,e,"success"));},v=e=>{u.delete(e),y(i,e,"failure"),l.get(e)?.close(),l.delete(e);},m=new Map,h=new Map,P=(e,r)=>`${e}\0${r}`,y=(e,r,s)=>{e.get(r)?.(s),e.delete(r);},q={extensionName:"docx-editor-telemetry",priority:Number.MAX_SAFE_INTEGER,async onLoadDocument({documentName:e}){y(i,e,"failure"),i.set(e,c.begin("load"));},async afterLoadDocument({documentName:e,document:r}){l.get(e)?.close(),l.set(e,c.open(r,{name:e,awareness:r.awareness})),u.set(e,0),w(e);},async onStoreDocument({documentName:e}){m.delete(e),p.delete(e);let r=l.get(e);m.set(e,r?r.begin("store"):c.begin("store"));},async afterStoreDocument({documentName:e}){p.set(e,0),D(e);},async connected({documentName:e,socketId:r}){let s=l.get(e),o=P(r,e);if(!s)return;let t=h.get(o);t?t.count+=1:h.set(o,{room:s,count:1}),s.connected();},async onDisconnect({documentName:e,socketId:r}){let s=P(r,e),o=h.get(s);o&&(o.room.disconnected(),o.count-=1,o.count===0&&h.delete(s));},async afterUnloadDocument({documentName:e}){u.delete(e),p.delete(e),y(i,e,"failure"),m.delete(e),l.get(e)?.close(),l.delete(e);},async onDestroy(){await c.shutdown();}},T=e=>{let r=e,s={},o=(t,d,j)=>{let b=r[t];typeof b=="function"&&(s[t]=async S=>{let k;try{k=await b.call(e,S);}catch(O){throw d(O,S),O}return j?.(S),k});};return o("onConnect",t=>c.rejected(t)),o("onAuthenticate",t=>c.rejected(t)),o("onTokenSync",t=>c.rejected(t)),o("beforeHandleMessage",t=>c.refused(t)),o("onLoadDocument",(t,{documentName:d})=>y(i,d??"","failure")),o("afterLoadDocument",(t,{documentName:d})=>v(d??""),({documentName:t})=>w(t??"")),o("afterStoreDocument",(t,{documentName:d})=>{p.delete(d??""),y(m,d??"",L(t)?"success":"failure");},({documentName:t})=>D(t??"")),o("onStoreDocument",(t,{documentName:d})=>{L(t)?m.delete(d??""):y(m,d??"","failure");}),s},C=T(a),E=(a.extensions??[]).map(e=>{let r=T(e);return new Proxy(Object.create(Object.getPrototypeOf(e)),{get(s,o){if(Object.hasOwn(r,o))return r[o];let t=Reflect.get(e,o,e);return typeof t=="function"&&o!=="constructor"?t.bind(e):t},set(s,o,t){return Reflect.set(e,o,t,e)},has:(s,o)=>Reflect.has(e,o),ownKeys:()=>Reflect.ownKeys(e),getOwnPropertyDescriptor(s,o){let t=Reflect.getOwnPropertyDescriptor(e,o);return t?{...t,configurable:true}:void 0}})});return {config:{...a,...C,extensions:[q,...E]},rooms:c}}function A(a,n){try{return a(n)===!0}catch{return false}}function L(a){return a?.name==="SkipFurtherHooksError"}Object.defineProperty(exports,"hmacRoomLabel",{enumerable:true,get:function(){return chunkPZZC5AXX_cjs.a}});exports.requireBearerToken=U;exports.serveMetrics=$;exports.withCollaborationTelemetry=I;
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Hocuspocus: room telemetry in one call. It adds one extension that runs before all others
3
+ * and times each load and store from the first hook to the last, and it observes your hooks
4
+ * and the extensions you pass in `extensions`, so a refusal any of them throws is counted.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { onRequestPayload, ServerConfiguration } from '@hocuspocus/server';
9
+ import { MetricsHandlerOptions, PrometheusTextSource } from '../prometheus/index.cjs';
10
+ import { RoomTelemetry, RoomTelemetryOptions } from '../server/index.cjs';
11
+ export { AwarenessLike, RoomHandle, RoomOperation, RoomStats, SettleOperation, hmacRoomLabel } from '../server/index.cjs';
12
+ export { b as TelemetryExporter, T as TelemetryPipelineOptions } from '../pipeline-CCq2Ng0B.cjs';
13
+ import 'yjs';
14
+ import '@docx-editor.dev/core';
15
+
16
+ /**
17
+ * Hocuspocus: room telemetry in one call. It adds one extension that runs before all others
18
+ * and times each load and store from the first hook to the last, and it observes your hooks
19
+ * and the extensions you pass in `extensions`, so a refusal any of them throws is counted.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+
24
+ /** Options for {@link serveMetrics}. @public */
25
+ interface ServeMetricsOptions extends MetricsHandlerOptions {
26
+ /** The path Prometheus scrapes. Defaults to `/metrics`. */
27
+ readonly path?: string;
28
+ /**
29
+ * Also serve `rooms.list()` as JSON at this path. It lists every room, so `authorize` is
30
+ * required with it.
31
+ */
32
+ readonly rooms?: {
33
+ readonly telemetry: RoomTelemetry;
34
+ readonly path: string;
35
+ };
36
+ /**
37
+ * Return false to answer 403. Use {@link requireBearerToken} for a shared scrape token.
38
+ * Applies to both paths.
39
+ */
40
+ readonly authorize?: (request: onRequestPayload['request']) => boolean;
41
+ /** Your own `onRequest`, called for every request this hook does not answer. */
42
+ readonly next?: (payload: onRequestPayload) => Promise<unknown>;
43
+ /**
44
+ * Sample this room telemetry before a scrape, for a server that sets `sampleInterval: false`.
45
+ * At most one sample is taken every 5 seconds, so several scrapers do not add extra samples.
46
+ */
47
+ readonly sampleBeforeScrape?: RoomTelemetry;
48
+ }
49
+ /**
50
+ * An `authorize` check for a shared token, sent as `Authorization: Bearer <token>`. The
51
+ * comparison takes the same time whatever the token, and an empty secret throws at startup
52
+ * rather than letting every request in.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * serveMetrics(metrics, { authorize: requireBearerToken(process.env.METRICS_TOKEN) });
57
+ * ```
58
+ *
59
+ * @public
60
+ */
61
+ declare function requireBearerToken(secret: string | undefined): (request: onRequestPayload['request']) => boolean;
62
+ /**
63
+ * An `onRequest` hook that serves Prometheus metrics from the Hocuspocus HTTP server itself,
64
+ * for a deployment without a separate web framework. Other requests fall through to the
65
+ * default handler.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * new Server({
70
+ * ...config,
71
+ * onRequest: serveMetrics(metrics, {
72
+ * rooms: { telemetry: rooms, path: '/rooms' },
73
+ * authorize: requireBearerToken(process.env.METRICS_TOKEN),
74
+ * }),
75
+ * });
76
+ * ```
77
+ *
78
+ * @public
79
+ */
80
+ declare function serveMetrics(registry: PrometheusTextSource, options?: ServeMetricsOptions): (payload: onRequestPayload) => Promise<void>;
81
+ /** What {@link withCollaborationTelemetry} returns. @public */
82
+ interface CollaborationTelemetry<C> {
83
+ /** Your configuration with observed hooks. Pass it to `new Server(config)`. */
84
+ readonly config: C;
85
+ /** The room telemetry, for `list()`, `sample()`, and `shutdown()`. */
86
+ readonly rooms: RoomTelemetry;
87
+ }
88
+ /**
89
+ * Add room telemetry to a Hocuspocus configuration.
90
+ *
91
+ * It records rooms, connections, the people in each room (from awareness), room memory and
92
+ * size, load and store times, and why connections and messages were refused. Your hooks and
93
+ * your `extensions` run exactly as before, with the same arguments, return values, and `this`;
94
+ * their errors are rethrown. Extensions added later with `server.configure` are not observed.
95
+ * Requires `@hocuspocus/server` 4.6 or later.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * import { Server } from '@hocuspocus/server';
100
+ * import { withCollaborationTelemetry } from '@docx-editor.dev/telemetry/hocuspocus';
101
+ * import { prometheusRegistry, metricsHandler } from '@docx-editor.dev/telemetry/prometheus';
102
+ *
103
+ * const metrics = prometheusRegistry();
104
+ * const { config, rooms } = withCollaborationTelemetry(
105
+ * { port: 1234, onAuthenticate, extensions: [new Database({ fetch, store })] },
106
+ * { exporters: [metrics] }
107
+ * );
108
+ * const server = new Server(config); // telemetry flushes when the server is destroyed
109
+ *
110
+ * app.get('/metrics', metricsHandler(metrics));
111
+ * ```
112
+ *
113
+ * @public
114
+ */
115
+ declare function withCollaborationTelemetry<C extends Partial<ServerConfiguration>>(config: C, options: RoomTelemetryOptions): CollaborationTelemetry<C>;
116
+
117
+ export { MetricsHandlerOptions, PrometheusTextSource, RoomTelemetry, RoomTelemetryOptions, requireBearerToken, serveMetrics, withCollaborationTelemetry };
118
+ export type { CollaborationTelemetry, ServeMetricsOptions };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Hocuspocus: room telemetry in one call. It adds one extension that runs before all others
3
+ * and times each load and store from the first hook to the last, and it observes your hooks
4
+ * and the extensions you pass in `extensions`, so a refusal any of them throws is counted.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { onRequestPayload, ServerConfiguration } from '@hocuspocus/server';
9
+ import { MetricsHandlerOptions, PrometheusTextSource } from '../prometheus/index.js';
10
+ import { RoomTelemetry, RoomTelemetryOptions } from '../server/index.js';
11
+ export { AwarenessLike, RoomHandle, RoomOperation, RoomStats, SettleOperation, hmacRoomLabel } from '../server/index.js';
12
+ export { b as TelemetryExporter, T as TelemetryPipelineOptions } from '../pipeline-CCq2Ng0B.js';
13
+ import 'yjs';
14
+ import '@docx-editor.dev/core';
15
+
16
+ /**
17
+ * Hocuspocus: room telemetry in one call. It adds one extension that runs before all others
18
+ * and times each load and store from the first hook to the last, and it observes your hooks
19
+ * and the extensions you pass in `extensions`, so a refusal any of them throws is counted.
20
+ *
21
+ * @packageDocumentation
22
+ */
23
+
24
+ /** Options for {@link serveMetrics}. @public */
25
+ interface ServeMetricsOptions extends MetricsHandlerOptions {
26
+ /** The path Prometheus scrapes. Defaults to `/metrics`. */
27
+ readonly path?: string;
28
+ /**
29
+ * Also serve `rooms.list()` as JSON at this path. It lists every room, so `authorize` is
30
+ * required with it.
31
+ */
32
+ readonly rooms?: {
33
+ readonly telemetry: RoomTelemetry;
34
+ readonly path: string;
35
+ };
36
+ /**
37
+ * Return false to answer 403. Use {@link requireBearerToken} for a shared scrape token.
38
+ * Applies to both paths.
39
+ */
40
+ readonly authorize?: (request: onRequestPayload['request']) => boolean;
41
+ /** Your own `onRequest`, called for every request this hook does not answer. */
42
+ readonly next?: (payload: onRequestPayload) => Promise<unknown>;
43
+ /**
44
+ * Sample this room telemetry before a scrape, for a server that sets `sampleInterval: false`.
45
+ * At most one sample is taken every 5 seconds, so several scrapers do not add extra samples.
46
+ */
47
+ readonly sampleBeforeScrape?: RoomTelemetry;
48
+ }
49
+ /**
50
+ * An `authorize` check for a shared token, sent as `Authorization: Bearer <token>`. The
51
+ * comparison takes the same time whatever the token, and an empty secret throws at startup
52
+ * rather than letting every request in.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * serveMetrics(metrics, { authorize: requireBearerToken(process.env.METRICS_TOKEN) });
57
+ * ```
58
+ *
59
+ * @public
60
+ */
61
+ declare function requireBearerToken(secret: string | undefined): (request: onRequestPayload['request']) => boolean;
62
+ /**
63
+ * An `onRequest` hook that serves Prometheus metrics from the Hocuspocus HTTP server itself,
64
+ * for a deployment without a separate web framework. Other requests fall through to the
65
+ * default handler.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * new Server({
70
+ * ...config,
71
+ * onRequest: serveMetrics(metrics, {
72
+ * rooms: { telemetry: rooms, path: '/rooms' },
73
+ * authorize: requireBearerToken(process.env.METRICS_TOKEN),
74
+ * }),
75
+ * });
76
+ * ```
77
+ *
78
+ * @public
79
+ */
80
+ declare function serveMetrics(registry: PrometheusTextSource, options?: ServeMetricsOptions): (payload: onRequestPayload) => Promise<void>;
81
+ /** What {@link withCollaborationTelemetry} returns. @public */
82
+ interface CollaborationTelemetry<C> {
83
+ /** Your configuration with observed hooks. Pass it to `new Server(config)`. */
84
+ readonly config: C;
85
+ /** The room telemetry, for `list()`, `sample()`, and `shutdown()`. */
86
+ readonly rooms: RoomTelemetry;
87
+ }
88
+ /**
89
+ * Add room telemetry to a Hocuspocus configuration.
90
+ *
91
+ * It records rooms, connections, the people in each room (from awareness), room memory and
92
+ * size, load and store times, and why connections and messages were refused. Your hooks and
93
+ * your `extensions` run exactly as before, with the same arguments, return values, and `this`;
94
+ * their errors are rethrown. Extensions added later with `server.configure` are not observed.
95
+ * Requires `@hocuspocus/server` 4.6 or later.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * import { Server } from '@hocuspocus/server';
100
+ * import { withCollaborationTelemetry } from '@docx-editor.dev/telemetry/hocuspocus';
101
+ * import { prometheusRegistry, metricsHandler } from '@docx-editor.dev/telemetry/prometheus';
102
+ *
103
+ * const metrics = prometheusRegistry();
104
+ * const { config, rooms } = withCollaborationTelemetry(
105
+ * { port: 1234, onAuthenticate, extensions: [new Database({ fetch, store })] },
106
+ * { exporters: [metrics] }
107
+ * );
108
+ * const server = new Server(config); // telemetry flushes when the server is destroyed
109
+ *
110
+ * app.get('/metrics', metricsHandler(metrics));
111
+ * ```
112
+ *
113
+ * @public
114
+ */
115
+ declare function withCollaborationTelemetry<C extends Partial<ServerConfiguration>>(config: C, options: RoomTelemetryOptions): CollaborationTelemetry<C>;
116
+
117
+ export { MetricsHandlerOptions, PrometheusTextSource, RoomTelemetry, RoomTelemetryOptions, requireBearerToken, serveMetrics, withCollaborationTelemetry };
118
+ export type { CollaborationTelemetry, ServeMetricsOptions };
@@ -0,0 +1 @@
1
+ import {c}from'../chunk-JM4KJB6O.js';import {b}from'../chunk-E3FTXDLH.js';export{a as hmacRoomLabel}from'../chunk-E3FTXDLH.js';import'../chunk-WHVIRIUW.js';import'../chunk-RSWAOCAT.js';import'../chunk-W5HFB5EV.js';import'../chunk-DT2KMPUJ.js';import {timingSafeEqual}from'crypto';function U(a){if(typeof a!="string"||a.length===0)throw new TypeError("requireBearerToken needs a non-empty secret, such as METRICS_TOKEN.");let n=Buffer.from(`Bearer ${a}`);return c=>{let l=c.headers?.authorization,i=Buffer.from(typeof l=="string"?l:"");return i.length===n.length&&timingSafeEqual(i,n)}}function $(a,n={}){if(n.rooms&&!n.authorize)throw new TypeError("serveMetrics needs authorize when it serves rooms: the list is private.");let c$1=n.path??"/metrics",l=c(a,n.merge?{merge:n.merge}:{}),i=0;return async({request:u,response:f})=>{let g=(u.url??"").split("?")[0],w=n.rooms?.path;if(g!==c$1&&g!==w){await n.next?.({request:u,response:f});return}throw n.authorize&&!A(n.authorize,u)?(f.writeHead(403),f.end()):g===c$1?(n.sampleBeforeScrape&&Date.now()-i>=5e3&&(i=Date.now(),n.sampleBeforeScrape.sample()),await l(u,f)):(f.writeHead(200,{"Content-Type":"application/json"}),f.end(JSON.stringify(n.rooms.telemetry.list()))),null}}function I(a,n){let c=b(n),l=new Map,i=new Map,u=new Map,f=e=>typeof e.afterLoadDocument=="function",g=1+(a.extensions??[]).filter(e=>f(e)).length+(f(a)?1:0),w=e=>{let r=(u.get(e)??0)+1;u.set(e,r),!(r<g)&&(u.delete(e),y(i,e,"success"));},p=new Map,R=e=>typeof e.afterStoreDocument=="function",M=1+(a.extensions??[]).filter(e=>R(e)).length+(R(a)?1:0),D=e=>{let r=(p.get(e)??0)+1;p.set(e,r),!(r<M)&&(p.delete(e),y(m,e,"success"));},v=e=>{u.delete(e),y(i,e,"failure"),l.get(e)?.close(),l.delete(e);},m=new Map,h=new Map,P=(e,r)=>`${e}\0${r}`,y=(e,r,s)=>{e.get(r)?.(s),e.delete(r);},q={extensionName:"docx-editor-telemetry",priority:Number.MAX_SAFE_INTEGER,async onLoadDocument({documentName:e}){y(i,e,"failure"),i.set(e,c.begin("load"));},async afterLoadDocument({documentName:e,document:r}){l.get(e)?.close(),l.set(e,c.open(r,{name:e,awareness:r.awareness})),u.set(e,0),w(e);},async onStoreDocument({documentName:e}){m.delete(e),p.delete(e);let r=l.get(e);m.set(e,r?r.begin("store"):c.begin("store"));},async afterStoreDocument({documentName:e}){p.set(e,0),D(e);},async connected({documentName:e,socketId:r}){let s=l.get(e),o=P(r,e);if(!s)return;let t=h.get(o);t?t.count+=1:h.set(o,{room:s,count:1}),s.connected();},async onDisconnect({documentName:e,socketId:r}){let s=P(r,e),o=h.get(s);o&&(o.room.disconnected(),o.count-=1,o.count===0&&h.delete(s));},async afterUnloadDocument({documentName:e}){u.delete(e),p.delete(e),y(i,e,"failure"),m.delete(e),l.get(e)?.close(),l.delete(e);},async onDestroy(){await c.shutdown();}},T=e=>{let r=e,s={},o=(t,d,j)=>{let b=r[t];typeof b=="function"&&(s[t]=async S=>{let k;try{k=await b.call(e,S);}catch(O){throw d(O,S),O}return j?.(S),k});};return o("onConnect",t=>c.rejected(t)),o("onAuthenticate",t=>c.rejected(t)),o("onTokenSync",t=>c.rejected(t)),o("beforeHandleMessage",t=>c.refused(t)),o("onLoadDocument",(t,{documentName:d})=>y(i,d??"","failure")),o("afterLoadDocument",(t,{documentName:d})=>v(d??""),({documentName:t})=>w(t??"")),o("afterStoreDocument",(t,{documentName:d})=>{p.delete(d??""),y(m,d??"",L(t)?"success":"failure");},({documentName:t})=>D(t??"")),o("onStoreDocument",(t,{documentName:d})=>{L(t)?m.delete(d??""):y(m,d??"","failure");}),s},C=T(a),E=(a.extensions??[]).map(e=>{let r=T(e);return new Proxy(Object.create(Object.getPrototypeOf(e)),{get(s,o){if(Object.hasOwn(r,o))return r[o];let t=Reflect.get(e,o,e);return typeof t=="function"&&o!=="constructor"?t.bind(e):t},set(s,o,t){return Reflect.set(e,o,t,e)},has:(s,o)=>Reflect.has(e,o),ownKeys:()=>Reflect.ownKeys(e),getOwnPropertyDescriptor(s,o){let t=Reflect.getOwnPropertyDescriptor(e,o);return t?{...t,configurable:true}:void 0}})});return {config:{...a,...C,extensions:[q,...E]},rooms:c}}function A(a,n){try{return a(n)===!0}catch{return false}}function L(a){return a?.name==="SkipFurtherHooksError"}export{U as requireBearerToken,$ as serveMetrics,I as withCollaborationTelemetry};