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.
@@ -1,12 +1,5 @@
1
- import { W as WriteTrackDataSchema } from './index-Cy91q_po.js';
2
-
3
- /**
4
- * A WriteTrack output sink receives session data when a session ends.
5
- */
6
- interface WriteTrackSink {
7
- /** Send session data to the destination. */
8
- send(data: WriteTrackDataSchema): Promise<void>;
9
- }
1
+ import { W as WriteTrackSink } from './types-B8bNI9P5.js';
2
+ import './index-Cy91q_po.js';
10
3
 
11
4
  interface WebhookOptions {
12
5
  /** URL to POST session data to */
@@ -110,4 +103,4 @@ interface OpenTelemetryOptions {
110
103
  */
111
104
  declare function opentelemetry(options: OpenTelemetryOptions): WriteTrackSink;
112
105
 
113
- export { type DatadogClient, type DatadogOptions, type OTelSpan, type OTelTracer, type OpenTelemetryOptions, type SegmentClient, type SegmentOptions, type WebhookOptions, type WriteTrackSink, datadog, opentelemetry, segment, webhook };
106
+ export { type DatadogClient, type DatadogOptions, type OTelSpan, type OTelTracer, type OpenTelemetryOptions, type SegmentClient, type SegmentOptions, type WebhookOptions, WriteTrackSink, datadog, opentelemetry, segment, webhook };
package/dist/esm/pipes.js CHANGED
@@ -1 +1 @@
1
- function p(n){let{url:o,headers:i={},retries:t=0,backoffMs:e=100,maxBackoffMs:a=3e4,keepalive:c=!1}=n;return{async send(f){let u=null;for(let s=0;s<=t;s++){if(s>0){let r=Math.min(e*Math.pow(2,s-1),a);await new Promise(l=>setTimeout(l,r))}try{let r=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",...i},body:JSON.stringify(f),keepalive:c});if(r.ok)return;u=new Error(`Webhook failed: ${r.status} ${r.statusText}`)}catch(r){u=r instanceof Error?r:new Error(String(r))}}throw u}}}function m(n){return n instanceof Error?n.message:String(n)}function d(n){let{client:o,actionName:i="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{o.addAction(i,a)}catch(c){throw new Error(`Datadog addAction failed: ${m(c)}`)}}}}function g(n){let{client:o,eventName:i="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),o.track(i,e)}}}function v(n){let{tracer:o,spanName:i="writetrack.session"}=n;return{async send(t){let e=o.startSpan(i);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()}}}}export{d as datadog,v as opentelemetry,g as segment,p as webhook};
1
+ function p(r){let{url:i,headers:a={},retries:t=0,backoffMs:e=100,maxBackoffMs:o=3e4,keepalive:u=!1}=r;return{async send(f){let m=null;for(let s=0;s<=t;s++){if(s>0){let n=Math.min(e*Math.pow(2,s-1),o);await new Promise(l=>setTimeout(l,n))}try{let n=await fetch(i,{method:"POST",headers:{"Content-Type":"application/json",...a},body:JSON.stringify(f),keepalive:u});if(n.ok)return;m=new Error(`Webhook failed: ${n.status} ${n.statusText}`)}catch(n){m=n instanceof Error?n:new Error(String(n))}}throw m}}}function c(r){return r instanceof Error?r.message:String(r)}function d(r){let{client:i,actionName:a="writetrack_session",tags:t={}}=r;return{async send(e){let o={...t,duration:e.metadata.duration,keystrokeCount:e.session.events.length,qualityLevel:e.quality.qualityLevel,targetElement:e.metadata.targetElement,schemaVersion:e.version};e.metadata.userId&&(o.userId=e.metadata.userId),e.metadata.contentId&&(o.contentId=e.metadata.contentId),e.metadata.custom&&(o.custom=e.metadata.custom);try{i.addAction(a,o)}catch(u){throw new Error(`Datadog addAction failed: ${c(u)}`)}}}}function g(r){let{client:i,eventName:a="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{i.track(a,e)}catch(o){throw new Error(`Segment track failed: ${c(o)}`)}}}}function v(r){let{tracer:i,spanName:a="writetrack.session"}=r;return{async send(t){let e=i.startSpan(a);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()}}}}export{d as datadog,v as opentelemetry,g as segment,p as webhook};
@@ -0,0 +1,61 @@
1
+ import { S as SessionAnalysis, a as SessionReport } from './analysis-types-Cg3hzXZX.js';
2
+ import { W as WriteTrackDataSchema } from './index-Cy91q_po.js';
3
+ import { W as WriteTrackSink } from './types-B8bNI9P5.js';
4
+
5
+ /**
6
+ * WriteTrack Test Utilities
7
+ *
8
+ * Framework-agnostic factories for creating mock WriteTrack instances
9
+ * and SessionAnalysis objects in consumer tests.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createMockAnalysis, createMockTracker } from 'writetrack/testing';
14
+ *
15
+ * const analysis = createMockAnalysis({ keydownCount: 500 });
16
+ * const tracker = createMockTracker({ analysis });
17
+ * ```
18
+ */
19
+
20
+ /** Recursively makes all properties of T optional. */
21
+ type DeepPartial<T> = T extends object ? {
22
+ [P in keyof T]?: DeepPartial<T[P]>;
23
+ } : T;
24
+ /**
25
+ * Create a complete SessionAnalysis with sensible defaults.
26
+ * Accepts deep partial overrides that are merged into the defaults.
27
+ */
28
+ declare function createMockAnalysis(overrides?: DeepPartial<SessionAnalysis>): SessionAnalysis;
29
+ /** Options for configuring the mock tracker. */
30
+ interface MockTrackerOptions {
31
+ /** Analysis returned by getAnalysis(). Defaults to a mock analysis. */
32
+ analysis?: SessionAnalysis | null;
33
+ /** Partial data merged into the default getData() return value. */
34
+ data?: DeepPartial<WriteTrackDataSchema>;
35
+ }
36
+ /** The mock tracker interface returned by createMockTracker(). */
37
+ interface MockWriteTrack {
38
+ getData(): WriteTrackDataSchema;
39
+ getAnalysis(): Promise<SessionAnalysis | null>;
40
+ getSessionReport(): Promise<SessionReport>;
41
+ getText(): string;
42
+ on(event: string, handler: (...args: unknown[]) => void): () => void;
43
+ off(event: string, handler: (...args: unknown[]) => void): void;
44
+ removeAllListeners(event?: string): void;
45
+ pipe(sink: WriteTrackSink): MockWriteTrack;
46
+ start(): void;
47
+ stop(): void;
48
+ stopAndWait(): Promise<void>;
49
+ ready: Promise<void>;
50
+ /** Test-only: fire an event to all registered handlers. */
51
+ emit(event: string, ...args: unknown[]): void;
52
+ }
53
+ /**
54
+ * Create a mock object that satisfies the WriteTrack public interface.
55
+ *
56
+ * The mock is test-framework-agnostic (no vitest/jest spies).
57
+ * Use `emit(event, data)` to fire events to registered handlers.
58
+ */
59
+ declare function createMockTracker(options?: MockTrackerOptions): MockWriteTrack;
60
+
61
+ export { type DeepPartial, type MockTrackerOptions, type MockWriteTrack, createMockAnalysis, createMockTracker };
@@ -0,0 +1 @@
1
+ function d(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function u(e,c){let a={...e},i=c;for(let o of Object.keys(i)){let t=i[o],n=a[o];d(t)&&d(n)?a[o]=u(n,t):t!==void 0&&(a[o]=t)}return a}function m(){return{version:"1.0.0",locale:"en",analyzedAt:17e11,sufficientData:!0,keydownCount:420,integrity:{algorithm:"SHA-256",checkpoints:[],finalDigest:"mock-digest-0000",eventCount:450},sessionTimeline:[],initialTextLength:0,initialTextHash:"",finalTextLength:350,finalTextHash:"mock-final-hash",contentOrigin:{indicator:{code:"WT-104",params:{}},pasteReworkIndicator:{code:"WT-104",params:{}},metrics:{charactersByOrigin:{typed:.92,pasted:.06,autocompleted:.02},pasteEvents:[],pasteClassification:{internalPasteRatio:0,externalPasteRatio:.06,unknownPasteRatio:0},pasteEditSummary:{pasteRetentionRate:0,meanModificationDelayMs:0,pasteToTypeRatio:.065,meanReworkRatio:0,pasteLengthMean:0,pasteLengthStd:0,pasteLengthMin:0,pasteLengthMax:0},contentTimeline:{timestamps:[],series:{}}}},timingAuthenticity:{indicator:{code:"WT-204",params:{}},metrics:{dwellTimeDistribution:{mean:85,cv:.35,histogram:[]},flightTimeDistribution:{mean:110,cv:.4,histogram:[]},periodicityScore:.08,entropy:3.8,timingOverTime:{timestamps:[],series:{}}}},sessionContinuity:{indicator:{code:"WT-302",params:{}},metrics:{changePoints:[],tabAwayEvents:[],segmentComparison:{timestamps:[],series:{}}}},physicalPlausibility:{indicator:{code:"WT-403",params:{}},metrics:{impossibleSequences:{count:0,timeline:{timestamps:[],values:[]},samples:[]},syntheticEventRatio:0,mouseActivityDuringTyping:{periodsWithMouseActivity:.3,longestGapWithoutMouse:12e3},zeroLatencyEventCount:0,unmatchedKeydownCount:2,bulkInsertCharCount:0,modifierEventCount:18,uncoveredCaseCount:0,modifierLateralBalance:.8,modifierCoverage:1,modifierSustainCount:4,nonStandardKeys:[]}},revisionBehavior:{indicator:{code:"WT-503",params:{}},metrics:{correctionRate:.04,correctionCount:17,navigationCount:8,undoRedoCount:2,editPatterns:[],correctionTimeline:{timestamps:[],values:[]},revisionDepth:{maxDepth:3,avgDepth:1.2,regionsRevisedMultipleTimes:2},proportionBehindFrontier:.12,substitutedWordsCount:3,jumpToEditFrequency:.4,jumpDistanceSd:25,revisionAtPriorRatio:.08,revisionAtFrontierRatio:.92,insertionDeletion:{insertionCount:12,totalInsertionChars:380,insertionLengthMean:31.7,insertionLengthMedian:18,deletionCount:8,totalDeletionChars:45,deletionLengthMean:5.6,appendToInsertionRatio:.75},productProcessRatio:.85,pauseLocation:{beforeSentence:{count:5,meanDuration:2800},beforeWord:{count:12,meanDuration:800},withinWord:{count:3,meanDuration:350},afterWord:{count:8,meanDuration:600},betweenWords:{count:15,meanDuration:450}},proportionEventsAfterLastChar:.78,proportionCharsInMultiWordInsert:.04}},temporalPatterns:{indicator:{code:"WT-603",params:{}},metrics:{sessionDurationMs:3e5,speedTimeline:{timestamps:[],values:[]},fatigueRatio:.88,warmupRatio:1.15,pauseDistribution:{histogram:[],count:14,meanDuration:1800},burstPattern:{avgBurstLength:6,avgBurstSpeed:65,burstToTotalRatio:.35,burstDurationSd:480,burstDurationCv:.45},pause200ms:{count:45,meanDuration:350,sdDuration:120,pauseRate:.15},pause2000ms:{count:8,meanDuration:3200,sdDuration:900,pauseRate:.027},shortToLongPauseRatio:5.6,fluencySd5seg:12.5,fluencySd10seg:18.3,burstClassification:{pBurstCount:22,pBurstMedianDuration:4500,rBurstCount:15,rBurstMedianDuration:1200,pToRRatio:1.47}}},writingProcess:{indicator:{code:"WT-700",params:{}},metrics:{segments:[],transitions:[],timeInPhase:{planning:.15,drafting:.7,revision:.15},phaseChangeCount:8,windowDurationMs:3e4,phaseTimeline:{timestamps:[],values:[]}}},outputSignature:"mock-signature"}}function p(e){return e?u(m(),e):m()}function l(){return{version:"2.0.0",metadata:{tool:{name:"writetrack",version:"0.0.0-mock"},targetElement:"div",timestamp:new Date().toISOString(),duration:0,sessionId:"mock-session-id"},session:{events:[],rawText:"",sessionStartTime:0,sessionEndTime:0},quality:{overallScore:1,completeness:1,sequenceValid:!0,timingValid:!0,sessionDuration:0,eventCount:0,qualityLevel:"GOOD",issues:[],validatedAt:new Date().toISOString()}}}function g(e){let c=(e==null?void 0:e.analysis)!==void 0?e.analysis:p(),a=e!=null&&e.data?u(l(),e.data):l(),i={},o={getData(){return a},getAnalysis(){return Promise.resolve(c)},async getSessionReport(){return{data:a,analysis:c}},getText(){return a.session.rawText??""},on(t,n){return i[t]||(i[t]=[]),i[t].push(n),()=>{let s=i[t];if(s){let r=s.indexOf(n);r!==-1&&s.splice(r,1)}}},off(t,n){let s=i[t];if(s){let r=s.indexOf(n);r!==-1&&s.splice(r,1)}},removeAllListeners(t){if(t)delete i[t];else for(let n of Object.keys(i))delete i[n]},pipe(t){return o},start(){},stop(){},async stopAndWait(){},ready:Promise.resolve(),emit(t,...n){let s=i[t];if(s)for(let r of[...s])r(...n)}};return o}export{p as createMockAnalysis,g as createMockTracker};
package/dist/esm/viz.d.ts CHANGED
@@ -52,7 +52,7 @@ declare abstract class BaseChart<T = unknown> extends HTMLElement {
52
52
  /** Called on container resize. Override in subclasses that shouldn't full re-render. */
53
53
  protected onResize(): void;
54
54
  /** Wrap render() in try/catch so subclasses don't need individual error handling */
55
- private safeRender;
55
+ protected safeRender(): void;
56
56
  /** Subclasses implement this to draw their visualization */
57
57
  protected abstract render(): void;
58
58
  /** Register the custom element if not already defined */
@@ -148,32 +148,6 @@ declare class PauseDistribution extends BaseChart<SessionAnalysis> {
148
148
  protected render(): void;
149
149
  }
150
150
 
151
- /**
152
- * DocumentGrowth — cumulative character count over time.
153
- *
154
- * Vertical jumps indicate paste/cut events. Slope indicates typing speed.
155
- * Consumes raw WriteTrackDataSchema (not WASM analysis output).
156
- */
157
-
158
- interface GrowthPoint {
159
- time: number;
160
- chars: number;
161
- isPaste: boolean;
162
- isCut: boolean;
163
- pasteLength?: number;
164
- cutLength?: number;
165
- }
166
- /** Extract cumulative character growth from raw events. */
167
- declare function extractGrowthData(data: WriteTrackDataSchema): GrowthPoint[];
168
- declare class DocumentGrowth extends BaseChart<WriteTrackDataSchema> {
169
- static tagName: string;
170
- /** Optional change point time (seconds) — renders as a dashed vertical rule. */
171
- private _changePointTime;
172
- /** Set a change point time (in seconds) to display as a vertical marker. */
173
- setChangePoint(timeSec: number | null): void;
174
- protected render(): void;
175
- }
176
-
177
151
  /**
178
152
  * EditBeeswarm — per-keystroke beeswarm visualization.
179
153
  *
@@ -206,7 +180,7 @@ declare class EditBeeswarm extends BaseChart<WriteTrackDataSchema> {
206
180
  /** Glyph marks: single text mark so everything dodges together.
207
181
  * Typed chars as letters, deletes as ×, pastes as 📋, cuts as ✂. */
208
182
  private buildGlyphMarks;
209
- /** Crop the SVG viewBox top to fit content, preserving the bottom (axis). */
183
+ /** Crop the SVG viewBox bottom to fit content, preserving the top (axis). */
210
184
  private cropViewBox;
211
185
  }
212
186
 
@@ -276,12 +250,54 @@ interface OriginBarColors {
276
250
  /** Extract origin proportions from analysis, filtering out 0% segments. */
277
251
  declare function extractOriginData(analysis: SessionAnalysis): OriginDatum[];
278
252
  /** Render a horizontal stacked bar showing content origin proportions. */
279
- declare function renderOriginBar(data: OriginDatum[], width: number, colors?: OriginBarColors): SVGSVGElement | null;
253
+ declare function renderOriginBar(data: OriginDatum[], width: number, colors?: OriginBarColors, textColors?: Partial<OriginBarColors>): SVGSVGElement | null;
280
254
  declare class WtOriginBar extends BaseChart<SessionAnalysis> {
281
255
  static tagName: string;
282
256
  protected render(): void;
283
257
  }
284
258
 
259
+ /**
260
+ * Session scorecard web component.
261
+ *
262
+ * Renders a full-page analysis report with header, stat badges, narrative summary,
263
+ * origin bar, 6-cell analysis grid, and detail panels with embedded charts.
264
+ *
265
+ * @element wt-scorecard
266
+ *
267
+ * @attr {string} theme - Color theme: `"light"` or `"dark"`. Overrides ancestor `data-theme` and `prefers-color-scheme`.
268
+ * @attr {boolean} share - Show share button and make QR code clickable.
269
+ * @attr {boolean} download - Show download button.
270
+ * @attr {string} data - JSON-serialized `SessionReport`. Alternative to calling `setData()`.
271
+ * @attr {boolean} compact - Compact rendering mode (inherited from BaseChart).
272
+ * @attr {string} label - Custom `aria-label` for accessibility (inherited from BaseChart).
273
+ *
274
+ * @fires wt-share - When the share button or QR code is clicked. Detail: `{ report: SessionReport }`.
275
+ * @fires wt-download - When the download button is clicked. Detail: `{ report: SessionReport }`.
276
+ * @fires wt-render - When render completes (inherited from BaseChart).
277
+ *
278
+ * @csspart page - The root container element.
279
+ *
280
+ * @cssprop [--wt-scorecard-bg] - Main background color.
281
+ * @cssprop [--wt-scorecard-bg-card] - Cell card background color.
282
+ * @cssprop [--wt-scorecard-bg-card-hover] - Card hover state color.
283
+ * @cssprop [--wt-scorecard-bg-card-flagged] - Flagged cell background color.
284
+ * @cssprop [--wt-scorecard-bg-detail] - Detail panel background color.
285
+ * @cssprop [--wt-scorecard-text] - Primary text color.
286
+ * @cssprop [--wt-scorecard-text-secondary] - Secondary text color.
287
+ * @cssprop [--wt-scorecard-text-tertiary] - Tertiary/muted text color.
288
+ * @cssprop [--wt-scorecard-border] - Border color.
289
+ * @cssprop [--wt-scorecard-border-heavy] - Heavy border color.
290
+ * @cssprop [--wt-scorecard-status-clear] - Pass/clear status color.
291
+ * @cssprop [--wt-scorecard-status-flagged] - Flagged/fail status color.
292
+ * @cssprop [--wt-scorecard-chart-line] - Chart line color.
293
+ * @cssprop [--wt-scorecard-chart-accent] - Chart accent color.
294
+ * @cssprop [--wt-scorecard-chart-flagged] - Chart flagged color.
295
+ * @cssprop [--wt-scorecard-chart-tertiary] - Chart tertiary color.
296
+ * @cssprop [--wt-scorecard-chart-cyan] - Chart cyan (paste) color.
297
+ * @cssprop [--wt-scorecard-font-display] - Display font (titles, headers).
298
+ * @cssprop [--wt-scorecard-font-body] - Body text font.
299
+ * @cssprop [--wt-scorecard-font-data] - Data/code font.
300
+ */
285
301
  declare class WtScorecard extends BaseChart<SessionReport> {
286
302
  static tagName: string;
287
303
  static get observedAttributes(): string[];
@@ -418,4 +434,82 @@ declare class WtBadge extends BaseChart<BadgeData> {
418
434
  */
419
435
  declare function generateWritingSummary(analysis: SessionAnalysis): string | null;
420
436
 
421
- export { type BadgeData, type BadgeStatus, BaseChart, type BeeswarmDatum, type BeeswarmType, type BubbleDatum, CATEGORY_NAMES, type CategoryKey, CorrectionsBubble, DocumentGrowth, EditBeeswarm, type EditType, EditWaterfall, GLOSSARY, type GlossaryEntry, type GrowthPoint, IntegrityFooter, type OriginBarColors, type OriginDatum, type PauseBin, PauseDistribution, RhythmHeatmap, type RhythmPoint, type ScorecardMetric, Sparkline, type SpeedPoint, SpeedTimeline, type StatBadge, TIER1_CATEGORIES, TIER2_CATEGORIES, type WaterfallData, type WaterfallPoint, WtBadge, WtOriginBar, WtScorecard, extractBeeswarmData, extractCorrectionBubbles, extractGrowthData, extractOriginData, extractPauseHistogram, extractRhythmPairs, extractSeries, extractSpeedData, extractStatBadges, extractWaterfallData, formatDuration, generateCaption, generateSummary, generateWritingSummary, getMetrics, getStatus, isPass, renderOriginBar, renderStatBadges, wrapTerms };
437
+ /**
438
+ * CompositionTimeline — session activity segments over time.
439
+ *
440
+ * Shows typing/paste/pause/tabAway segments as colored horizontal bars
441
+ * and paste events as dots scaled by character count.
442
+ */
443
+
444
+ declare const SEGMENT_COLORS: Record<string, string>;
445
+ interface SegmentDatum {
446
+ start: number;
447
+ end: number;
448
+ type: string;
449
+ color: string;
450
+ }
451
+ interface PasteDatum {
452
+ time: number;
453
+ chars: number;
454
+ source: string;
455
+ }
456
+ /** Extract activity segments from analysis, converting ms to seconds. */
457
+ declare function extractSegments(analysis: SessionAnalysis): SegmentDatum[];
458
+ /** Extract paste event markers from analysis. */
459
+ declare function extractPasteMarkers(analysis: SessionAnalysis): PasteDatum[];
460
+ /** Extract only tab-away segments (for mode="focus" rendering). */
461
+ declare function extractFocusSegments(analysis: SessionAnalysis): SegmentDatum[];
462
+ declare class CompositionTimeline extends BaseChart<SessionAnalysis> {
463
+ static tagName: string;
464
+ static get observedAttributes(): string[];
465
+ get mode(): string;
466
+ protected render(): void;
467
+ private _renderFocus;
468
+ }
469
+
470
+ /**
471
+ * DocumentGrowth — writing process chart.
472
+ *
473
+ * By default shows net document length (product) over time as a line + area fill.
474
+ * Opt-in attributes enable additional series:
475
+ * process — cumulative total input activity (always increasing)
476
+ * cursor — cursor position in the document over time
477
+ * pauses — orange dots sized by inter-keystroke gap duration
478
+ *
479
+ * Consumes raw WriteTrackDataSchema (not WASM analysis output).
480
+ */
481
+
482
+ interface ProcessPoint {
483
+ time: number;
484
+ process: number;
485
+ product: number;
486
+ cursor: number;
487
+ }
488
+ interface PauseDot {
489
+ time: number;
490
+ product: number;
491
+ pauseMs: number;
492
+ }
493
+ interface ProcessGraphData {
494
+ points: ProcessPoint[];
495
+ pauses: PauseDot[];
496
+ }
497
+ /** Extract process/product data from raw keystroke events. */
498
+ declare function extractProcessData(data: WriteTrackDataSchema, minPauseMs?: number): ProcessGraphData;
499
+ declare class DocumentGrowth extends BaseChart<WriteTrackDataSchema> {
500
+ static tagName: string;
501
+ private _changePointTime;
502
+ /** Set a change point time (in seconds) to display as a vertical marker. */
503
+ setChangePoint(timeSec: number | null): void;
504
+ static get observedAttributes(): string[];
505
+ attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
506
+ protected render(): void;
507
+ }
508
+ /** @deprecated Use DocumentGrowth */
509
+ declare const ProcessGraph: typeof DocumentGrowth;
510
+ /** @deprecated Use extractProcessData */
511
+ declare const extractGrowthData: typeof extractProcessData;
512
+ /** @deprecated Use ProcessPoint */
513
+ type GrowthPoint = ProcessPoint;
514
+
515
+ export { type BadgeData, type BadgeStatus, BaseChart, type BeeswarmDatum, type BeeswarmType, type BubbleDatum, CATEGORY_NAMES, type CategoryKey, CompositionTimeline, CorrectionsBubble, DocumentGrowth, EditBeeswarm, type EditType, EditWaterfall, GLOSSARY, type GlossaryEntry, type GrowthPoint, IntegrityFooter, type OriginBarColors, type OriginDatum, type PasteDatum, type PauseBin, PauseDistribution, type PauseDot, ProcessGraph, type ProcessGraphData, type ProcessPoint, RhythmHeatmap, type RhythmPoint, SEGMENT_COLORS, type ScorecardMetric, type SegmentDatum, Sparkline, type SpeedPoint, SpeedTimeline, type StatBadge, TIER1_CATEGORIES, TIER2_CATEGORIES, type WaterfallData, type WaterfallPoint, WtBadge, WtOriginBar, WtScorecard, extractBeeswarmData, extractCorrectionBubbles, extractFocusSegments, extractGrowthData, extractOriginData, extractPasteMarkers, extractPauseHistogram, extractProcessData, extractRhythmPairs, extractSegments, extractSeries, extractSpeedData, extractStatBadges, extractWaterfallData, formatDuration, generateCaption, generateSummary, generateWritingSummary, getMetrics, getStatus, isPass, renderOriginBar, renderStatBadges, wrapTerms };