writetrack 0.10.3 → 0.12.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.
@@ -1,23 +1,7 @@
1
1
  import { WriteTrack } from 'writetrack';
2
+ import type { BaseBindingOptions } from 'writetrack';
2
3
 
3
- export interface WriteTrackLexicalOptions {
4
- /** WriteTrack license key */
5
- license?: string;
6
- /** User identifier for metadata */
7
- userId?: string;
8
- /** Content identifier for metadata */
9
- contentId?: string;
10
- /** Additional metadata */
11
- metadata?: Record<string, unknown>;
12
- /** Auto-start tracking when editor root is available (default: true) */
13
- autoStart?: boolean;
14
- /** URL to the WASM binary for analysis. If omitted, uses default loader path. */
15
- wasmUrl?: string;
16
- /** Enable IndexedDB session persistence and auto-resume. Requires contentId. */
17
- persist?: boolean;
18
- /** Callback fired every second with active session time. */
19
- onTick?: (data: { activeTime: number; totalTime: number }) => void;
20
- }
4
+ export type WriteTrackLexicalOptions = BaseBindingOptions;
21
5
 
22
6
  export interface WriteTrackLexicalHandle {
23
7
  /** The underlying WriteTrack instance (null until root element is available) */
@@ -1 +1 @@
1
- import{WriteTrack as d}from"writetrack";function f(n,s,r){let o=r.autoStart!==!1,a,l=n.registerUpdateListener(({tags:t})=>{t.has("paste")?a="paste":t.has("historic")?a="undo":a=void 0}),e={tracker:null,isTracking:!1,destroy(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1),l(),k()}};function u(t){e.tracker=new d({target:t,license:r.license,userId:r.userId,contentId:r.contentId,metadata:r.metadata,wasmUrl:r.wasmUrl,persist:r.persist,cursorPositionProvider:()=>{try{return n.getEditorState().read(()=>{let i=s();return i&&typeof i.anchor?.offset=="number"?i.anchor.offset:0})}catch{return 0}},inputSourceProvider:()=>a}),r.onTick&&e.tracker.on("tick",r.onTick),o&&(r.persist?e.tracker.ready.then(()=>{e.tracker&&(e.tracker.start(),e.isTracking=!0)}):(e.tracker.start(),e.isTracking=!0))}function c(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1)}let k=n.registerRootListener(t=>{t?(c(),u(t)):c()});return e}export{f as createWriteTrackLexical};
1
+ import{WriteTrack as u}from"writetrack";function f(i,s,r){let l=r.autoStart!==!1,a,o=i.registerUpdateListener(({tags:t})=>{t.has("paste")?a="paste":t.has("historic")?a="undo":a=void 0}),e={tracker:null,isTracking:!1,destroy(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1),o(),d()}};function k(t){e.tracker=new u({target:t,license:r.license,userId:r.userId,contentId:r.contentId,metadata:r.metadata,wasmUrl:r.wasmUrl,persist:r.persist,cursorPositionProvider:()=>{try{return i.getEditorState().read(()=>{let n=s();return n&&typeof n.anchor?.offset=="number"?n.anchor.offset:0})}catch{return 0}},inputSourceProvider:()=>a}),r.onTick&&e.tracker.on("tick",r.onTick),l?r.persist?e.tracker.ready.then(()=>{e.tracker&&(e.tracker.start(),e.isTracking=!0,r.onReady?.(e.tracker))}):(e.tracker.start(),e.isTracking=!0,r.onReady?.(e.tracker)):r.persist?e.tracker.ready.then(()=>{e.tracker&&r.onReady?.(e.tracker)}):r.onReady?.(e.tracker)}function c(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1)}let d=i.registerRootListener(t=>{t?(c(),k(t)):c()});return e}export{f as createWriteTrackLexical};
package/dist/pipes.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var m=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var x=(n,r)=>{for(var o in r)m(n,o,{get:r[o],enumerable:!0})},T=(n,r,o,t)=>{if(r&&typeof r=="object"||typeof r=="function")for(let e of y(r))!b.call(n,e)&&e!==o&&m(n,e,{get:()=>r[e],enumerable:!(t=h(r,e))||t.enumerable});return n};var w=n=>T(m({},"__esModule",{value:!0}),n);var S={};x(S,{datadog:()=>p,opentelemetry:()=>g,segment:()=>d,webhook:()=>f});module.exports=w(S);function f(n){let{url:r,headers:o={},retries:t=0,backoffMs:e=100,maxBackoffMs:a=3e4,keepalive:c=!1}=n;return{async send(v){let u=null;for(let s=0;s<=t;s++){if(s>0){let i=Math.min(e*Math.pow(2,s-1),a);await new Promise(k=>setTimeout(k,i))}try{let i=await fetch(r,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify(v),keepalive:c});if(i.ok)return;u=new Error(`Webhook failed: ${i.status} ${i.statusText}`)}catch(i){u=i instanceof Error?i:new Error(String(i))}}throw u}}}function l(n){return n instanceof Error?n.message:String(n)}function p(n){let{client:r,actionName:o="writetrack_session",tags:t={}}=n;return{async send(e){let a={...t,duration:e.metadata.duration,keystrokeCount:e.session.events.length,qualityLevel:e.quality.qualityLevel,targetElement:e.metadata.targetElement,schemaVersion:e.version};e.metadata.userId&&(a.userId=e.metadata.userId),e.metadata.contentId&&(a.contentId=e.metadata.contentId),e.metadata.custom&&(a.custom=e.metadata.custom);try{r.addAction(o,a)}catch(c){throw new Error(`Datadog addAction failed: ${l(c)}`)}}}}function d(n){let{client:r,eventName:o="WriteTrack Session"}=n;return{async send(t){let e={duration:t.metadata.duration,keystrokeCount:t.session.events.length,qualityLevel:t.quality.qualityLevel,targetElement:t.metadata.targetElement,schemaVersion:t.version};t.metadata.userId&&(e.userId=t.metadata.userId),t.metadata.contentId&&(e.contentId=t.metadata.contentId),t.metadata.custom&&(e.custom=t.metadata.custom),r.track(o,e)}}}function g(n){let{tracer:r,spanName:o="writetrack.session"}=n;return{async send(t){let e=r.startSpan(o);try{e.setAttribute("writetrack.duration",t.metadata.duration),e.setAttribute("writetrack.keystroke_count",t.session.events.length),e.setAttribute("writetrack.quality_level",t.quality.qualityLevel),e.setAttribute("writetrack.target_element",t.metadata.targetElement),e.setAttribute("writetrack.schema_version",t.version),t.metadata.userId&&e.setAttribute("writetrack.user_id",t.metadata.userId),t.metadata.contentId&&e.setAttribute("writetrack.content_id",t.metadata.contentId),e.setStatus({code:1})}finally{e.end()}}}}0&&(module.exports={datadog,opentelemetry,segment,webhook});
1
+ "use strict";var f=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var w=(r,n)=>{for(var o in n)f(r,o,{get:n[o],enumerable:!0})},x=(r,n,o,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let e of y(n))!b.call(r,e)&&e!==o&&f(r,e,{get:()=>n[e],enumerable:!(t=h(n,e))||t.enumerable});return r};var S=r=>x(f({},"__esModule",{value:!0}),r);var T={};w(T,{datadog:()=>p,opentelemetry:()=>g,segment:()=>d,webhook:()=>l});module.exports=S(T);function l(r){let{url:n,headers:o={},retries:t=0,backoffMs:e=100,maxBackoffMs:a=3e4,keepalive:u=!1}=r;return{async send(v){let m=null;for(let s=0;s<=t;s++){if(s>0){let i=Math.min(e*Math.pow(2,s-1),a);await new Promise(k=>setTimeout(k,i))}try{let i=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json",...o},body:JSON.stringify(v),keepalive:u});if(i.ok)return;m=new Error(`Webhook failed: ${i.status} ${i.statusText}`)}catch(i){m=i instanceof Error?i:new Error(String(i))}}throw m}}}function c(r){return r instanceof Error?r.message:String(r)}function p(r){let{client:n,actionName:o="writetrack_session",tags:t={}}=r;return{async send(e){let a={...t,duration:e.metadata.duration,keystrokeCount:e.session.events.length,qualityLevel:e.quality.qualityLevel,targetElement:e.metadata.targetElement,schemaVersion:e.version};e.metadata.userId&&(a.userId=e.metadata.userId),e.metadata.contentId&&(a.contentId=e.metadata.contentId),e.metadata.custom&&(a.custom=e.metadata.custom);try{n.addAction(o,a)}catch(u){throw new Error(`Datadog addAction failed: ${c(u)}`)}}}}function d(r){let{client:n,eventName:o="WriteTrack Session"}=r;return{async send(t){let e={duration:t.metadata.duration,keystrokeCount:t.session.events.length,qualityLevel:t.quality.qualityLevel,targetElement:t.metadata.targetElement,schemaVersion:t.version};t.metadata.userId&&(e.userId=t.metadata.userId),t.metadata.contentId&&(e.contentId=t.metadata.contentId),t.metadata.custom&&(e.custom=t.metadata.custom);try{n.track(o,e)}catch(a){throw new Error(`Segment track failed: ${c(a)}`)}}}}function g(r){let{tracer:n,spanName:o="writetrack.session"}=r;return{async send(t){let e=n.startSpan(o);try{e.setAttribute("writetrack.duration",t.metadata.duration),e.setAttribute("writetrack.keystroke_count",t.session.events.length),e.setAttribute("writetrack.quality_level",t.quality.qualityLevel),e.setAttribute("writetrack.target_element",t.metadata.targetElement),e.setAttribute("writetrack.schema_version",t.version),t.metadata.userId&&e.setAttribute("writetrack.user_id",t.metadata.userId),t.metadata.contentId&&e.setAttribute("writetrack.content_id",t.metadata.contentId),t.metadata.custom&&e.setAttribute("writetrack.custom",JSON.stringify(t.metadata.custom)),e.setStatus({code:1})}finally{e.end()}}}}0&&(module.exports={datadog,opentelemetry,segment,webhook});
@@ -1,22 +1,8 @@
1
1
  import { WriteTrack } from 'writetrack';
2
+ import type { BaseBindingOptions } from 'writetrack';
2
3
  import { Plugin, PluginKey } from 'prosemirror-state';
3
4
 
4
- export interface WriteTrackPluginOptions {
5
- /** WriteTrack license key */
6
- license?: string;
7
- /** User identifier for metadata */
8
- userId?: string;
9
- /** Content identifier for metadata */
10
- contentId?: string;
11
- /** Additional metadata */
12
- metadata?: Record<string, unknown>;
13
- /** Auto-start tracking when editor is ready (default: true) */
14
- autoStart?: boolean;
15
- /** URL to the WASM binary for analysis. If omitted, uses default loader path. */
16
- wasmUrl?: string;
17
- /** Enable IndexedDB session persistence and auto-resume. Requires contentId. */
18
- persist?: boolean;
19
- }
5
+ export type WriteTrackPluginOptions = BaseBindingOptions;
20
6
 
21
7
  export interface WriteTrackPluginState {
22
8
  tracker: WriteTrack | null;
@@ -1 +1 @@
1
- import{Plugin as u,PluginKey as c}from"prosemirror-state";import{WriteTrack as o}from"writetrack";var s=new c("writetrack");function g(e={}){let l=e.autoStart!==!1,t=null,a=!1,i;return new u({key:s,state:{init(){return{tracker:null,isTracking:!1}},apply(){return{tracker:t,isTracking:t!==null&&a}}},filterTransaction(r){let n=r.getMeta("uiEvent");return n==="paste"?i="paste":n==="drop"?i="drop":n==="cut"?i="cut":r.getMeta("composition")?i="composition":i=void 0,!0},view(r){let n=r.dom;return t=new o({target:n,license:e.license,userId:e.userId,contentId:e.contentId,metadata:e.metadata,wasmUrl:e.wasmUrl,persist:e.persist,cursorPositionProvider:()=>r.state.selection.from,inputSourceProvider:()=>i}),l&&(e.persist?t.ready.then(()=>{t&&(t.start(),a=!0)}):(t.start(),a=!0)),r.dispatch(r.state.tr),{destroy(){t&&(t.stop(),t=null,a=!1)}}}})}export{g as WriteTrackPlugin,s as WriteTrackPluginKey};
1
+ import{Plugin as s,PluginKey as c}from"prosemirror-state";import{WriteTrack as o}from"writetrack";var u=new c("writetrack");function d(t={}){let l=t.autoStart!==!1,e=null,a=!1,i;return new s({key:u,state:{init(){return{tracker:null,isTracking:!1}},apply(){return{tracker:e,isTracking:e!==null&&a}}},filterTransaction(r){let n=r.getMeta("uiEvent");return n==="paste"?i="paste":n==="drop"?i="drop":n==="cut"?i="cut":r.getMeta("composition")?i="composition":i=void 0,!0},view(r){let n=r.dom;return e=new o({target:n,license:t.license,userId:t.userId,contentId:t.contentId,metadata:t.metadata,wasmUrl:t.wasmUrl,persist:t.persist,cursorPositionProvider:()=>r.state.selection.from,inputSourceProvider:()=>i}),t.onTick&&e.on("tick",t.onTick),l?t.persist?e.ready.then(()=>{e&&(e.start(),a=!0,t.onReady?.(e))}):(e.start(),a=!0,t.onReady?.(e)):t.persist?e.ready.then(()=>{e&&t.onReady?.(e)}):t.onReady?.(e),r.dispatch(r.state.tr),{destroy(){e&&(e.stop(),e=null,a=!1)}}}})}export{d as WriteTrackPlugin,u as WriteTrackPluginKey};
@@ -1,21 +1,7 @@
1
1
  import { WriteTrack } from 'writetrack';
2
+ import type { BaseBindingOptions } from 'writetrack';
2
3
 
3
- export interface WriteTrackModuleOptions {
4
- /** WriteTrack license key */
5
- license?: string;
6
- /** User identifier for metadata */
7
- userId?: string;
8
- /** Content identifier for metadata */
9
- contentId?: string;
10
- /** Additional metadata */
11
- metadata?: Record<string, unknown>;
12
- /** Auto-start tracking when module is initialized (default: true) */
13
- autoStart?: boolean;
14
- /** URL to the WASM binary for analysis. If omitted, uses default loader path. */
15
- wasmUrl?: string;
16
- /** Enable IndexedDB session persistence and auto-resume. Requires contentId. */
17
- persist?: boolean;
18
- }
4
+ export type WriteTrackModuleOptions = BaseBindingOptions;
19
5
 
20
6
  /**
21
7
  * Quill module for WriteTrack keystroke analysis
@@ -1 +1 @@
1
- import{WriteTrack as a}from"writetrack";var e=class{constructor(t,r){this._tracker=null;this._isTracking=!1;let n=r.autoStart!==!1;t.on("text-change",(c,o,i)=>{this._currentSource=i==="api"?"api":void 0}),this._tracker=new a({target:t.root,license:r.license,userId:r.userId,contentId:r.contentId,metadata:r.metadata,wasmUrl:r.wasmUrl,persist:r.persist,cursorPositionProvider:()=>t.getSelection()?.index??0,inputSourceProvider:()=>this._currentSource}),n&&(r.persist?this._tracker.ready.then(()=>{this._tracker&&(this._tracker.start(),this._isTracking=!0)}):(this._tracker.start(),this._isTracking=!0))}get tracker(){return this._tracker}get isTracking(){return this._isTracking}destroy(){this._tracker&&(this._tracker.stop(),this._tracker=null,this._isTracking=!1)}};export{e as WriteTrackModule};
1
+ import{WriteTrack as n}from"writetrack";var t=class{constructor(e,r){this._tracker=null;this._isTracking=!1;let i=r.autoStart!==!1;e.on("text-change",(c,o,a)=>{this._currentSource=a==="api"?"api":void 0}),this._tracker=new n({target:e.root,license:r.license,userId:r.userId,contentId:r.contentId,metadata:r.metadata,wasmUrl:r.wasmUrl,persist:r.persist,cursorPositionProvider:()=>e.getSelection()?.index??0,inputSourceProvider:()=>this._currentSource}),r.onTick&&this._tracker.on("tick",r.onTick),i?r.persist?this._tracker.ready.then(()=>{this._tracker&&(this._tracker.start(),this._isTracking=!0,r.onReady?.(this._tracker))}):(this._tracker.start(),this._isTracking=!0,r.onReady?.(this._tracker)):r.persist?this._tracker.ready.then(()=>{this._tracker&&r.onReady?.(this._tracker)}):r.onReady?.(this._tracker)}get tracker(){return this._tracker}get isTracking(){return this._isTracking}destroy(){this._tracker&&(this._tracker.stop(),this._tracker=null,this._isTracking=!1)}};export{t as WriteTrackModule};
@@ -1,21 +1,10 @@
1
- import { WriteTrack } from 'writetrack';
1
+ import { WriteTrack, SessionAnalysis } from 'writetrack';
2
+ import type { BaseBindingOptions } from 'writetrack';
2
3
  import { RefObject } from 'react';
3
4
 
4
- export interface UseWriteTrackOptions {
5
- /** WriteTrack license key */
6
- license?: string;
7
- /** User identifier included in metadata */
8
- userId?: string;
9
- /** Content identifier included in metadata */
10
- contentId?: string;
11
- /** Additional metadata */
12
- metadata?: Record<string, unknown>;
13
- /** Auto-start tracking when element is available (default: true) */
14
- autoStart?: boolean;
15
- /** URL to the WASM binary for analysis. If omitted, uses default loader path. */
16
- wasmUrl?: string;
17
- /** Enable IndexedDB session persistence and auto-resume. Requires contentId. */
18
- persist?: boolean;
5
+ export interface UseWriteTrackOptions extends BaseBindingOptions {
6
+ /** Subscribe to real-time analysis events. Requires wasmUrl or default WASM loader. */
7
+ analysis?: boolean;
19
8
  }
20
9
 
21
10
  export interface UseWriteTrackReturn {
@@ -27,8 +16,18 @@ export interface UseWriteTrackReturn {
27
16
  stop: () => void;
28
17
  /** Whether the tracker is currently active */
29
18
  isTracking: boolean;
30
- /** Access to the underlying WriteTrack instance */
19
+ /**
20
+ * Access to the underlying WriteTrack instance.
21
+ * When `autoStart` is false, this is `null` on the initial render and
22
+ * becomes available after the first re-render.
23
+ */
31
24
  tracker: WriteTrack | null;
25
+ /** Whether the tracker has initialised and is ready */
26
+ isReady: boolean;
27
+ /** Latest analysis result (when `analysis: true`) */
28
+ analysis: SessionAnalysis | null;
29
+ /** Latest error from WASM or tracker initialisation */
30
+ error: Error | null;
32
31
  }
33
32
 
34
33
  /**
@@ -1 +1 @@
1
- import{useEffect as g,useRef as l,useCallback as u,useState as f}from"react";import{WriteTrack as k}from"writetrack";function m(e,p={}){let{autoStart:a=!0,...i}=p,n=l(i);n.current=i;let r=l(null),[t,s]=f(!1),[,o]=f(0);g(()=>{if(!e.current)return;let c=!1;return r.current=new k({target:e.current,...n.current}),a?n.current.persist?r.current.ready.then(()=>{c||!r.current||(r.current.start(),s(!0))}):(r.current.start(),s(!0)):o(d=>d+1),()=>{c=!0,r.current?.stop(),r.current=null,s(!1)}},[e,a]);let T=u(()=>{r.current&&!t&&(r.current.start(),s(!0))},[t]),W=u(()=>{r.current&&t&&(r.current.stop(),s(!1))},[t]);return{reset:u(()=>{e.current&&(r.current?.stop(),r.current=new k({target:e.current,...n.current}),t&&(n.current.persist?r.current.ready.then(()=>{r.current&&r.current.start()}):r.current.start()),o(c=>c+1))},[e,t]),start:T,stop:W,isTracking:t,tracker:r.current}}export{m as useWriteTrack};
1
+ import{useEffect as A,useRef as y,useCallback as p,useState as l}from"react";import{WriteTrack as x}from"writetrack";var u=class{constructor(s){this._unsubs=[];this._opts=s,this._state={tracker:null,isReady:!1,isTracking:!1,analysis:null,error:null},this._init(s.target,s.writeTrackOptions)}_init(s,i){let t=new x({...i,target:s});if(this._state.tracker=t,this._unsubs=[],this._opts.onTick){let a=t.on("tick",this._opts.onTick);this._unsubs.push(a)}if(this._opts.analysis){let a=t.on("analysis",n=>{this._state.analysis=n,this._notify()});this._unsubs.push(a);let o=t.on("wasm:error",n=>{this._state.error=n,this._notify()});this._unsubs.push(o)}this._opts.autoStart!==!1?!!i.persist?t.ready.then(()=>{t.start(),this._state.isReady=!0,this._state.isTracking=!0,this._notify(),this._opts.onReady?.(t)}).catch(o=>{this._state.error=o,this._notify()}):(t.start(),this._state.isReady=!0,this._state.isTracking=!0,this._notify(),queueMicrotask(()=>{this._opts.onReady?.(t)})):(this._state.isReady=!0,this._notify())}_notify(){this._opts.onStateChange({tracker:this._state.tracker,isReady:this._state.isReady,isTracking:this._state.isTracking,analysis:this._state.analysis,error:this._state.error})}getState(){return{tracker:this._state.tracker,isReady:this._state.isReady,isTracking:this._state.isTracking,analysis:this._state.analysis,error:this._state.error}}start(){this._state.tracker&&!this._state.isTracking&&(this._state.tracker.start(),this._state.isTracking=!0,this._notify())}stop(){this._state.tracker&&this._state.isTracking&&(this._state.tracker.stop(),this._state.isTracking=!1,this._notify())}async destroy(){this._state.tracker&&await this._state.tracker.stopAndWait();for(let s of this._unsubs)s();this._unsubs=[],this._state.tracker=null,this._state.isReady=!1,this._state.isTracking=!1,this._state.analysis=null,this._state.error=null,this._notify()}async reset(s,i){await this.destroy(),this._init(s,i??this._opts.writeTrackOptions)}};function j(e,s={}){let{autoStart:i=!0,analysis:t,onTick:k,onReady:a,...o}=s,n=y(o);n.current=o;let h=y(k);h.current=k;let _=y(a);_.current=a;let c=y(null),[d,g]=l(null),[m,R]=l(!1),[O,b]=l(!1),[S,W]=l(null),[v,w]=l(null);A(()=>{if(!e.current)return;let f=!1,T=new u({target:e.current,writeTrackOptions:n.current,autoStart:i,analysis:t,onTick:h.current?r=>h.current?.(r):void 0,onReady:r=>_.current?.(r),onStateChange:r=>{f||(g(r.tracker),R(r.isTracking),b(r.isReady),W(r.analysis),w(r.error))}});return c.current=T,()=>{f=!0,c.current=null,T.destroy()}},[e,i,t]);let C=p(()=>{c.current?.start()},[]),E=p(()=>{c.current?.stop()},[]);return{reset:p(()=>{!e.current||!c.current||c.current.reset(e.current,n.current)},[e]),start:C,stop:E,isTracking:m,tracker:d,isReady:O,analysis:S,error:v}}export{j as useWriteTrack};
@@ -1,21 +1,7 @@
1
1
  import { WriteTrack } from 'writetrack';
2
+ import type { BaseBindingOptions } from 'writetrack';
2
3
 
3
- export interface WriteTrackSlateOptions {
4
- /** WriteTrack license key */
5
- license?: string;
6
- /** User identifier for metadata */
7
- userId?: string;
8
- /** Content identifier for metadata */
9
- contentId?: string;
10
- /** Additional metadata */
11
- metadata?: Record<string, unknown>;
12
- /** Auto-start tracking when created (default: true) */
13
- autoStart?: boolean;
14
- /** URL to the WASM binary for analysis. If omitted, uses default loader path. */
15
- wasmUrl?: string;
16
- /** Enable IndexedDB session persistence and auto-resume. Requires contentId. */
17
- persist?: boolean;
18
- }
4
+ export type WriteTrackSlateOptions = BaseBindingOptions;
19
5
 
20
6
  export interface WriteTrackSlateHandle {
21
7
  /** The underlying WriteTrack instance */
@@ -1 +1 @@
1
- import{WriteTrack as o}from"writetrack";function k(t,c,r){let l=r.autoStart!==!1,a,s=t.insertText;t.insertText=n=>{a="keyboard",s.call(t,n)};let i=t.insertData;t.insertData=n=>{a="paste",i.call(t,n)};let e={tracker:null,isTracking:!1,destroy(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1),t.insertText=s,t.insertData=i}};return e.tracker=new o({target:c,license:r.license,userId:r.userId,contentId:r.contentId,metadata:r.metadata,wasmUrl:r.wasmUrl,persist:r.persist,cursorPositionProvider:()=>t.selection?.anchor.offset??0,inputSourceProvider:()=>a}),l&&(r.persist?e.tracker.ready.then(()=>{e.tracker&&(e.tracker.start(),e.isTracking=!0)}):(e.tracker.start(),e.isTracking=!0)),e}export{k as createWriteTrackSlate};
1
+ import{WriteTrack as k}from"writetrack";function o(t,s,r){let l=r.autoStart!==!1,a,c=t.insertText;t.insertText=n=>{a="keyboard",c.call(t,n)};let i=t.insertData;t.insertData=n=>{a="paste",i.call(t,n)};let e={tracker:null,isTracking:!1,destroy(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1),t.insertText=c,t.insertData=i}};return e.tracker=new k({target:s,license:r.license,userId:r.userId,contentId:r.contentId,metadata:r.metadata,wasmUrl:r.wasmUrl,persist:r.persist,cursorPositionProvider:()=>t.selection?.anchor.offset??0,inputSourceProvider:()=>a}),r.onTick&&e.tracker.on("tick",r.onTick),l?r.persist?e.tracker.ready.then(()=>{e.tracker&&(e.tracker.start(),e.isTracking=!0,r.onReady?.(e.tracker))}):(e.tracker.start(),e.isTracking=!0,r.onReady?.(e.tracker)):r.persist?e.tracker.ready.then(()=>{e.tracker&&r.onReady?.(e.tracker)}):r.onReady?.(e.tracker),e}export{o as createWriteTrackSlate};
@@ -1,71 +1,41 @@
1
- import { WriteTrack } from 'writetrack';
2
-
3
- export interface WriteTrackTinyMCEOptions {
4
- /** WriteTrack license key */
5
- license?: string;
6
- /** User identifier for metadata */
7
- userId?: string;
8
- /** Content identifier for metadata */
9
- contentId?: string;
10
- /** Additional metadata */
11
- metadata?: Record<string, unknown>;
12
- /** Auto-start tracking when editor initializes (default: true) */
13
- autoStart?: boolean;
14
- /** URL to the WASM binary for analysis. If omitted, uses default loader path. */
15
- wasmUrl?: string;
16
- /** Enable IndexedDB session persistence and auto-resume. Requires contentId. */
17
- persist?: boolean;
18
- /** Callback fired every second with active session time. */
19
- onTick?: (data: { activeTime: number; totalTime: number }) => void;
20
- }
21
-
22
- export interface WriteTrackTinyMCEHandle {
23
- /** The underlying WriteTrack instance (null until editor init fires) */
24
- tracker: WriteTrack | null;
25
- /** Whether tracking is currently active */
26
- isTracking: boolean;
27
- /** Stop tracking and clean up resources */
28
- destroy(): void;
29
- }
30
-
31
1
  /**
32
- * Attach WriteTrack to a TinyMCE editor.
2
+ * Native TinyMCE plugin for WriteTrack.
33
3
  *
34
- * Hooks into TinyMCE's `init` and `remove` lifecycle events.
35
- * Uses `editor.getBody()` as the target element.
4
+ * Importing this module registers the `writetrack` plugin with TinyMCE's
5
+ * PluginManager. No function call required — import for side effect.
36
6
  *
37
- * **Note:** Only inline mode (`inline: true`) is fully supported.
38
- * In iframe mode (default), window/document-level listeners attach to the
39
- * host page rather than the iframe, resulting in degraded tracking.
7
+ * Supports both inline and iframe editor modes. In iframe mode, focus and
8
+ * selection listeners automatically attach to the iframe's document context.
40
9
  *
41
10
  * @example
42
11
  * ```ts
43
- * import tinymce from 'tinymce';
44
- * import { createWriteTrackTinyMCE } from 'writetrack/tinymce';
12
+ * import 'writetrack/tinymce';
45
13
  *
46
14
  * tinymce.init({
47
15
  * selector: '#editor',
48
- * inline: true,
49
- * setup: (editor) => {
50
- * const handle = createWriteTrackTinyMCE(editor, {
51
- * license: 'your-license-key',
52
- * });
53
- * },
16
+ * plugins: ['writetrack'],
17
+ * writetrack_license: 'your-license-key',
18
+ * });
19
+ *
20
+ * // Access plugin API after init:
21
+ * editor.on('init', () => {
22
+ * const wt = editor.plugins.writetrack;
23
+ * const data = wt.tracker?.getData();
54
24
  * });
55
25
  * ```
56
26
  *
57
- * @param editor - A TinyMCE `Editor` instance
58
- * @param options - WriteTrack configuration options
59
- * @returns A handle with the tracker instance and a destroy method
27
+ * @module writetrack/tinymce
60
28
  */
61
- export declare function createWriteTrackTinyMCE(
62
- editor: {
63
- getBody(): HTMLElement;
64
- selection: {
65
- getRng(): { startOffset: number };
66
- };
67
- on(event: string, handler: () => void): void;
68
- off(event: string, handler: () => void): void;
69
- },
70
- options: WriteTrackTinyMCEOptions
71
- ): WriteTrackTinyMCEHandle;
29
+
30
+ import { WriteTrack } from 'writetrack';
31
+
32
+ export interface WriteTrackTinyMCEPlugin {
33
+ /** The underlying WriteTrack instance (null until editor init fires) */
34
+ tracker: WriteTrack | null;
35
+ /** Whether tracking is currently active */
36
+ isTracking: boolean;
37
+ /** Stop tracking and clean up resources */
38
+ destroy(): void;
39
+ /** TinyMCE plugin metadata for the Help plugin */
40
+ getMetadata(): { name: string; url: string };
41
+ }
@@ -1 +1 @@
1
- import{WriteTrack as k}from"writetrack";function m(t,r){let l=r.autoStart!==!1,n,a=!1,e={tracker:null,isTracking:!1,destroy(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1),t.off("init",s),t.off("remove",u),t.off("PastePreProcess",o),t.off("AutocompleterStart",c),t.off("AutocompleterEnd",i)}};function o(){n="paste"}function c(){a=!0}function i(){a&&(n="autocomplete"),a=!1}function s(){let f=t.getBody();e.tracker=new k({target:f,license:r.license,userId:r.userId,contentId:r.contentId,metadata:r.metadata,wasmUrl:r.wasmUrl,persist:r.persist,cursorPositionProvider:()=>{try{return t.selection.getRng().startOffset}catch{return 0}},inputSourceProvider:()=>n}),r.onTick&&e.tracker.on("tick",r.onTick),l&&(r.persist?e.tracker.ready.then(()=>{e.tracker&&(e.tracker.start(),e.isTracking=!0)}):(e.tracker.start(),e.isTracking=!0))}function u(){e.destroy()}return t.on("init",s),t.on("remove",u),t.on("PastePreProcess",o),t.on("AutocompleterStart",c),t.on("AutocompleterEnd",i),e}export{m as createWriteTrackTinyMCE};
1
+ import{WriteTrack as E}from"writetrack";function d(){tinymce.PluginManager.add("writetrack",(t,M)=>{t.options.register("writetrack_license",{processor:"string",default:""}),t.options.register("writetrack_userId",{processor:"string",default:""}),t.options.register("writetrack_contentId",{processor:"string",default:""}),t.options.register("writetrack_metadata",{processor:"object",default:{}}),t.options.register("writetrack_autoStart",{processor:"boolean",default:!0}),t.options.register("writetrack_wasmUrl",{processor:"string",default:""}),t.options.register("writetrack_persist",{processor:"boolean",default:!1}),t.options.register("writetrack_onTick",{processor:"function",default:void 0}),t.options.register("writetrack_onReady",{processor:"function",default:void 0});let n,o=!1,e={tracker:null,isTracking:!1,destroy(){e.tracker&&(e.tracker.stop(),e.tracker=null,e.isTracking=!1),t.off("init",g),t.off("remove",l),t.off("PastePreProcess",s),t.off("AutocompleterStart",c),t.off("AutocompleterEnd",u)},getMetadata(){return{name:"WriteTrack",url:"https://writetrack.dev"}}};function s(){n="paste"}function c(){o=!0}function u(){o&&(n="autocomplete"),o=!1}function g(){let p=t.getBody(),m=t.options.get("writetrack_license")||void 0,w=t.options.get("writetrack_userId")||void 0,T=t.options.get("writetrack_contentId")||void 0,i=t.options.get("writetrack_metadata"),y=t.options.get("writetrack_wasmUrl")||void 0,a=t.options.get("writetrack_persist"),f=t.options.get("writetrack_onTick"),r=t.options.get("writetrack_onReady"),v=t.options.get("writetrack_autoStart"),k=!!t.iframeElement,P=k?t.getDoc():void 0,_=k?t.getWin():void 0;e.tracker=new E({target:p,license:m,userId:w,contentId:T,metadata:i&&Object.keys(i).length>0?i:void 0,wasmUrl:y,persist:a,documentOverride:P,windowOverride:_,cursorPositionProvider:()=>{try{return t.selection.getRng().startOffset}catch{return 0}},inputSourceProvider:()=>n}),f&&e.tracker.on("tick",f),v?a?e.tracker.ready.then(()=>{e.tracker&&(e.tracker.start(),e.isTracking=!0,r?.(e.tracker))}):(e.tracker.start(),e.isTracking=!0,r?.(e.tracker)):a?e.tracker.ready.then(()=>{e.tracker&&r?.(e.tracker)}):r?.(e.tracker)}function l(){e.destroy()}return t.on("init",g),t.on("remove",l),t.on("PastePreProcess",s),t.on("AutocompleterStart",c),t.on("AutocompleterEnd",u),e})}d();
@@ -1,30 +1,18 @@
1
1
  import { WriteTrack } from 'writetrack';
2
+ import type { InputSource, BaseBindingOptions } from 'writetrack';
2
3
  import { Extension } from '@tiptap/core';
3
4
 
4
- export interface WriteTrackExtensionOptions {
5
- /** WriteTrack license key */
6
- license?: string;
7
- /** User identifier for metadata */
8
- userId?: string;
9
- /** Content identifier for metadata */
10
- contentId?: string;
11
- /** Additional metadata */
12
- metadata?: Record<string, unknown>;
13
- /** Auto-start tracking when editor is created (default: true) */
14
- autoStart?: boolean;
15
- /** URL to the WASM binary for analysis. If omitted, uses default loader path. */
16
- wasmUrl?: string;
17
- /** Enable IndexedDB session persistence and auto-resume. Requires contentId. */
18
- persist?: boolean;
19
- /** Callback fired every second with active session time. Wired up inside onCreate to avoid lifecycle race conditions. */
20
- onTick?: (data: { activeTime: number; totalTime: number }) => void;
21
- }
5
+ export type WriteTrackExtensionOptions = BaseBindingOptions;
22
6
 
23
7
  export interface WriteTrackExtensionStorage {
24
8
  /** The underlying WriteTrack instance */
25
9
  tracker: WriteTrack | null;
10
+ /** Whether the tracker is ready (persistence loaded if applicable) */
11
+ isReady: boolean;
26
12
  /** Whether tracking is currently active */
27
13
  isTracking: boolean;
14
+ /** Current input source classification (instance-scoped via storage) */
15
+ currentSource: InputSource | undefined;
28
16
  }
29
17
 
30
18
  /**
@@ -53,3 +41,12 @@ export declare const WriteTrackExtension: Extension<
53
41
  WriteTrackExtensionOptions,
54
42
  WriteTrackExtensionStorage
55
43
  >;
44
+
45
+ declare module '@tiptap/core' {
46
+ interface Storage {
47
+ writetrack: WriteTrackExtensionStorage;
48
+ }
49
+ interface EditorEvents {
50
+ 'writetrack:ready': { tracker: WriteTrack };
51
+ }
52
+ }
@@ -1 +1 @@
1
- import{Extension as r}from"@tiptap/core";import{WriteTrack as i}from"writetrack";var n=r.create({name:"writetrack",addOptions(){return{license:void 0,userId:void 0,contentId:void 0,metadata:void 0,autoStart:!0,wasmUrl:void 0,persist:void 0,onTick:void 0}},addStorage(){return{tracker:null,isTracking:!1,currentSource:void 0}},onTransaction({transaction:t}){let e=t.getMeta("uiEvent");e==="paste"?this.storage.currentSource="paste":e==="drop"?this.storage.currentSource="drop":e==="cut"?this.storage.currentSource="cut":this.storage.currentSource=void 0},onCreate(){let t=this.editor.view.dom;this.storage.tracker=new i({target:t,license:this.options.license,userId:this.options.userId,contentId:this.options.contentId,metadata:this.options.metadata,wasmUrl:this.options.wasmUrl,persist:this.options.persist,cursorPositionProvider:()=>this.editor.view.state.selection.from,inputSourceProvider:()=>this.storage.currentSource}),this.options.onTick&&this.storage.tracker.on("tick",this.options.onTick),this.options.autoStart&&(this.options.persist?this.storage.tracker.ready.then(()=>{this.storage.tracker&&(this.storage.tracker.start(),this.storage.isTracking=!0)}):(this.storage.tracker.start(),this.storage.isTracking=!0))},onDestroy(){this.storage.tracker&&(this.storage.tracker.stop(),this.storage.tracker=null,this.storage.isTracking=!1)}});export{n as WriteTrackExtension};
1
+ import{Extension as r}from"@tiptap/core";import{WriteTrack as i}from"writetrack";var s=r.create({name:"writetrack",addOptions(){return{license:void 0,userId:void 0,contentId:void 0,metadata:void 0,autoStart:!0,wasmUrl:void 0,persist:void 0,onTick:void 0,onReady:void 0}},addStorage(){return{tracker:null,isReady:!1,isTracking:!1,currentSource:void 0}},onTransaction({transaction:t}){let e=t.getMeta("uiEvent");e==="paste"?this.storage.currentSource="paste":e==="drop"?this.storage.currentSource="drop":e==="cut"?this.storage.currentSource="cut":this.storage.currentSource=void 0},onCreate(){let t=this.editor.view.dom;this.storage.tracker=new i({target:t,license:this.options.license,userId:this.options.userId,contentId:this.options.contentId,metadata:this.options.metadata,wasmUrl:this.options.wasmUrl,persist:this.options.persist,cursorPositionProvider:()=>this.editor.view.state.selection.from,inputSourceProvider:()=>this.storage.currentSource}),this.options.onTick&&this.storage.tracker.on("tick",this.options.onTick),this.options.autoStart?this.options.persist?this.storage.tracker.ready.then(()=>{this.storage.tracker&&(this.storage.tracker.start(),this.storage.isReady=!0,this.storage.isTracking=!0,this.editor.emit("writetrack:ready",{tracker:this.storage.tracker}),this.options.onReady?.(this.storage.tracker))}):(this.storage.tracker.start(),this.storage.isReady=!0,this.storage.isTracking=!0,this.editor.emit("writetrack:ready",{tracker:this.storage.tracker}),this.options.onReady?.(this.storage.tracker)):this.options.persist?this.storage.tracker.ready.then(()=>{this.storage.tracker&&(this.storage.isReady=!0,this.editor.emit("writetrack:ready",{tracker:this.storage.tracker}),this.options.onReady?.(this.storage.tracker))}):(this.storage.isReady=!0,this.editor.emit("writetrack:ready",{tracker:this.storage.tracker}),this.options.onReady?.(this.storage.tracker))},onDestroy(){this.storage.tracker&&(this.storage.tracker.stop(),this.storage.tracker=null,this.storage.isReady=!1,this.storage.isTracking=!1)}});export{s as WriteTrackExtension};