writetrack 0.10.2 → 0.11.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.
Binary file
@@ -18,6 +18,8 @@ export interface WriteTrackPluginOptions {
18
18
  persist?: boolean;
19
19
  /** Callback fired every second with active session time. */
20
20
  onTick?: (data: { activeTime: number; totalTime: number }) => void;
21
+ /** Callback invoked when the tracker is created and ready (persistence loaded if applicable). Avoids polling for tracker availability. */
22
+ onReady?: (tracker: WriteTrack) => void;
21
23
  }
22
24
 
23
25
  /**
@@ -1 +1 @@
1
- import{Plugin as a}from"ckeditor5";import{WriteTrack as c}from"writetrack";var n=class extends a{constructor(){super(...arguments);this._tracker=null;this._isTracking=!1;this._destroyed=!1}static get pluginName(){return"WriteTrack"}get tracker(){return this._tracker}get isTracking(){return this._isTracking}init(){let e=this.editor,t=e.config.get("writetrack")||{},o=t.autoStart!==!1;e.ui.once("ready",()=>{if(this._destroyed)return;let s=e.ui.getEditableElement();s&&(e.model.document.on("change:data",(r,i)=>{i.isUndo?this._currentSource="undo":i.isTyping?this._currentSource="keyboard":this._currentSource!=="paste"&&this._currentSource!=="drop"&&(this._currentSource=void 0)}),e.editing.view.document.on("clipboardInput",(r,i)=>{this._currentSource=i.method==="drop"?"drop":"paste"}),this._tracker=new c({target:s,license:t.license,userId:t.userId,contentId:t.contentId,metadata:t.metadata,wasmUrl:t.wasmUrl,persist:t.persist,cursorPositionProvider:()=>{let r=e.model.document.selection.getFirstPosition();return r?r.offset:0},inputSourceProvider:()=>this._currentSource}),t.onTick&&this._tracker.on("tick",t.onTick),o&&(t.persist?this._tracker.ready.then(()=>{this._tracker&&(this._tracker.start(),this._isTracking=!0)}):(this._tracker.start(),this._isTracking=!0)))})}destroy(){this._destroyed=!0,this._tracker&&(this._tracker.stop(),this._tracker=null,this._isTracking=!1),super.destroy()}};export{n as WriteTrackPlugin};
1
+ import{Plugin as a}from"ckeditor5";import{WriteTrack as c}from"writetrack";var n=class extends a{constructor(){super(...arguments);this._tracker=null;this._isTracking=!1;this._destroyed=!1}static get pluginName(){return"WriteTrack"}get tracker(){return this._tracker}get isTracking(){return this._isTracking}init(){let e=this.editor,t=e.config.get("writetrack")||{},o=t.autoStart!==!1;e.ui.once("ready",()=>{if(this._destroyed)return;let s=e.ui.getEditableElement();s&&(e.model.document.on("change:data",(r,i)=>{i.isUndo?this._currentSource="undo":i.isTyping?this._currentSource="keyboard":this._currentSource!=="paste"&&this._currentSource!=="drop"&&(this._currentSource=void 0)}),e.editing.view.document.on("clipboardInput",(r,i)=>{this._currentSource=i.method==="drop"?"drop":"paste"}),this._tracker=new c({target:s,license:t.license,userId:t.userId,contentId:t.contentId,metadata:t.metadata,wasmUrl:t.wasmUrl,persist:t.persist,cursorPositionProvider:()=>{let r=e.model.document.selection.getFirstPosition();return r?r.offset:0},inputSourceProvider:()=>this._currentSource}),t.onTick&&this._tracker.on("tick",t.onTick),o?t.persist?this._tracker.ready.then(()=>{this._tracker&&(this._tracker.start(),this._isTracking=!0,t.onReady?.(this._tracker))}):(this._tracker.start(),this._isTracking=!0,t.onReady?.(this._tracker)):t.persist?this._tracker.ready.then(()=>{this._tracker&&t.onReady?.(this._tracker)}):t.onReady?.(this._tracker))})}destroy(){this._destroyed=!0,this._tracker&&(this._tracker.stop(),this._tracker=null,this._isTracking=!1),super.destroy()}};export{n as WriteTrackPlugin};
@@ -1,9 +1,9 @@
1
1
  import { K as KeystrokeEvent, C as ClipboardEvent, U as UndoRedoEvent, S as SelectionEvent, P as ProgrammaticInsertionEvent, a as CompositionEvent, I as InputSource, W as WriteTrackDataSchema } from './index-Cy91q_po.js';
2
2
  export { D as DataQualityMetrics, M as ModifierState, b as SessionMetadata } from './index-Cy91q_po.js';
3
- import { WriteTrackSink } from './pipes.js';
4
- export { DatadogClient, DatadogOptions, OTelSpan, OTelTracer, OpenTelemetryOptions, SegmentClient, SegmentOptions, WebhookOptions, datadog, opentelemetry, segment, webhook } from './pipes.js';
3
+ import { W as WriteTrackSink } from './types-B8bNI9P5.js';
5
4
  import { S as SessionAnalysis, a as SessionReport, I as IndicatorOutput } from './analysis-types-Cg3hzXZX.js';
6
5
  export { C as ContentOriginAnalysis, e as PhaseTransition, P as PhysicalPlausibilityAnalysis, R as RevisionBehaviorAnalysis, b as SessionContinuityAnalysis, c as TemporalPatternsAnalysis, T as TimingAuthenticityAnalysis, f as WindowFeatures, W as WritingProcessAnalysis, d as WritingProcessSegment } from './analysis-types-Cg3hzXZX.js';
6
+ export { DatadogClient, DatadogOptions, OTelSpan, OTelTracer, OpenTelemetryOptions, SegmentClient, SegmentOptions, WebhookOptions, datadog, opentelemetry, segment, webhook } from './pipes.js';
7
7
 
8
8
  interface PersistedSessionInfo {
9
9
  contentId: string;
@@ -35,6 +35,12 @@ interface WriteTrackOptions {
35
35
  * beforeinput classification. Rich text editors (TipTap, Lexical, etc.) can use
36
36
  * this to supply definitive input source from their own transaction metadata. */
37
37
  inputSourceProvider?: () => InputSource | undefined;
38
+ /** Override the document used for selection and visibility listeners.
39
+ * Required for iframe-based editors (e.g., TinyMCE iframe mode). */
40
+ documentOverride?: Document;
41
+ /** Override the window used for focus/blur listeners.
42
+ * Required for iframe-based editors (e.g., TinyMCE iframe mode). */
43
+ windowOverride?: Window;
38
44
  }
39
45
  declare class WriteTrack {
40
46
  /** @internal */ keystrokeEvents: KeystrokeEvent[];
@@ -72,9 +78,17 @@ declare class WriteTrack {
72
78
  private _persist;
73
79
  private readonly cursorPositionProvider?;
74
80
  private readonly inputSourceProvider?;
81
+ private readonly _document;
82
+ private readonly _window;
75
83
  private pendingInputSource;
76
84
  private _sinks;
77
85
  private _listeners;
86
+ private _readyFired;
87
+ private _keydownCount;
88
+ private _analysisThrottle;
89
+ private _analysisTimer;
90
+ private _analysisDirty;
91
+ private _analysisRunning;
78
92
  /**
79
93
  * Create a WriteTrack instance
80
94
  * @param optionsOrTarget - Either an HTMLElement (localhost evaluation) or WriteTrackOptions object
@@ -156,6 +170,12 @@ declare class WriteTrack {
156
170
  isTargetDetached(): boolean;
157
171
  start(): void;
158
172
  stop(): void;
173
+ /**
174
+ * Stop tracking and wait for any pending IndexedDB save to complete.
175
+ * Use this instead of `stop()` when you need to delete persisted data afterwards.
176
+ * When persist is not enabled, behaves identically to `stop()`.
177
+ */
178
+ stopAndWait(): Promise<void>;
159
179
  /**
160
180
  * Remove any persisted session data from IndexedDB for this field.
161
181
  * No-op when persist is not enabled.
@@ -168,14 +188,43 @@ declare class WriteTrack {
168
188
  pipe(sink: WriteTrackSink): this;
169
189
  /**
170
190
  * Register an event listener.
171
- * Supported events: 'pipe:error', 'tick'
191
+ * Supported events: 'ready', 'change', 'analysis', 'tick', 'wasm:ready', 'wasm:error', 'stop', 'pipe:error'
172
192
  *
173
193
  * The `tick` event fires every ~1 second while the session is active and the
174
194
  * tab is visible. The handler receives `{ activeTime: number, totalTime: number }`
175
195
  * (both in milliseconds).
196
+ *
197
+ * @returns An unsubscribe function that removes the listener when called.
198
+ */
199
+ on(event: 'ready', handler: () => void): () => void;
200
+ on(event: 'change', handler: (payload: {
201
+ eventCount: number;
202
+ keystrokeCount: number;
203
+ }) => void): () => void;
204
+ on(event: 'analysis', handler: (analysis: SessionAnalysis) => void, opts?: {
205
+ throttle?: number;
206
+ }): () => void;
207
+ on(event: 'tick', handler: (payload: {
208
+ activeTime: number;
209
+ totalTime: number;
210
+ }) => void): () => void;
211
+ on(event: 'wasm:ready', handler: () => void): () => void;
212
+ on(event: 'wasm:error', handler: (error: Error) => void): () => void;
213
+ on(event: 'stop', handler: () => void): () => void;
214
+ on(event: 'pipe:error', handler: (error: Error, sink: WriteTrackSink) => void): () => void;
215
+ /**
216
+ * Remove a specific event listener.
176
217
  */
177
- on(event: string, handler: (...args: unknown[]) => void): this;
218
+ off(event: string, handler: (...args: unknown[]) => void): void;
219
+ /**
220
+ * Remove all listeners for a given event, or all listeners if no event is specified.
221
+ */
222
+ removeAllListeners(event?: string): void;
223
+ private _emitChange;
178
224
  private _emit;
225
+ private _triggerWasmLoad;
226
+ private _scheduleAnalysis;
227
+ private _runAnalysis;
179
228
  private _dispatchToSinks;
180
229
  private startTickInterval;
181
230
  private stopTickInterval;
@@ -224,6 +273,27 @@ declare class WriteTrack {
224
273
  static deletePersistedSession(contentId: string, fieldId?: string): Promise<void>;
225
274
  }
226
275
 
276
+ /**
277
+ * Convenience accessors for SessionAnalysis.
278
+ *
279
+ * These helpers extract commonly needed values so consumers don't have
280
+ * to navigate the nested analysis structure directly.
281
+ */
282
+
283
+ /** Extract session duration in milliseconds. */
284
+ declare function getSessionDurationMs(analysis: SessionAnalysis): number;
285
+ /** Compute characters-per-minute and words-per-minute from keydown count and session duration. */
286
+ declare function getTypingSpeed(analysis: SessionAnalysis): {
287
+ cpm: number;
288
+ wpm: number;
289
+ };
290
+ /** Extract the content origin breakdown (typed / pasted / autocompleted ratios, 0-1 each). */
291
+ declare function getContentOriginBreakdown(analysis: SessionAnalysis): {
292
+ typed: number;
293
+ pasted: number;
294
+ autocompleted: number;
295
+ };
296
+
227
297
  /**
228
298
  * Format WT-NNN indicator codes into human-readable strings.
229
299
  *
@@ -278,4 +348,4 @@ declare function createSessionReport(rawData: unknown, options?: AnalyzeEventsOp
278
348
  */
279
349
  declare function getHighResolutionTime(): number;
280
350
 
281
- export { type AnalyzeEventsOptions, ClipboardEvent, CompositionEvent, IndicatorOutput, InputSource, KeystrokeEvent, type PersistedSessionInfo, ProgrammaticInsertionEvent, SelectionEvent, SessionAnalysis, SessionReport, UndoRedoEvent, WriteTrack, WriteTrackDataSchema, type WriteTrackOptions, WriteTrackSink, analyzeEvents, createSessionReport, WriteTrack as default, formatIndicator, getHighResolutionTime };
351
+ export { type AnalyzeEventsOptions, ClipboardEvent, CompositionEvent, IndicatorOutput, InputSource, KeystrokeEvent, type PersistedSessionInfo, ProgrammaticInsertionEvent, SelectionEvent, SessionAnalysis, SessionReport, UndoRedoEvent, WriteTrack, WriteTrackDataSchema, type WriteTrackOptions, WriteTrackSink, analyzeEvents, createSessionReport, WriteTrack as default, formatIndicator, getContentOriginBreakdown, getHighResolutionTime, getSessionDurationMs, getTypingSpeed };