superdoc 2.20.1-next.1 → 2.20.1-next.11

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,5 +1,563 @@
1
1
  import { $ as watch, D as normalizeClass, E as nextTick, F as openBlock, H as shallowRef, L as ref, N as onMounted, R as renderList, U as toDisplayString, a as computed, c as createCommentVNode, f as createTextVNode, h as defineComponent, j as onBeforeUnmount, l as createElementBlock, n as Fragment, q as unref, rt as withModifiers, t as _plugin_vue_export_helper_default, u as createElementVNode } from "./_plugin-vue_export-helper-DHiJKCsy.es.js";
2
+ //#region src/internal/diagnostics/workflow-recording.ts
3
+ var fields$1 = /* @__PURE__ */ new Set([
4
+ "documentId",
5
+ "actionId",
6
+ "commandId",
7
+ "operation",
8
+ "source",
9
+ "origin",
10
+ "phase",
11
+ "kind",
12
+ "status",
13
+ "success",
14
+ "changed",
15
+ "reason",
16
+ "code",
17
+ "direction",
18
+ "outcome",
19
+ "receipt",
20
+ "result",
21
+ "failure",
22
+ "rejection",
23
+ "txId",
24
+ "documentEpoch",
25
+ "commitSequence",
26
+ "targetCommitSequence",
27
+ "paintedCommitSequence",
28
+ "renderInputEpoch",
29
+ "paintedRenderInputEpoch",
30
+ "health",
31
+ "selection",
32
+ "selectionBefore",
33
+ "selectionAfter",
34
+ "snapshot",
35
+ "target",
36
+ "start",
37
+ "end",
38
+ "anchor",
39
+ "focus",
40
+ "story",
41
+ "storyType",
42
+ "storyId",
43
+ "refId",
44
+ "noteId",
45
+ "textboxId",
46
+ "position",
47
+ "offset",
48
+ "unit",
49
+ "value",
50
+ "blockId",
51
+ "blockOffset",
52
+ "fragmentId",
53
+ "pageIndex",
54
+ "layoutEpoch",
55
+ "revision",
56
+ "sourceCommit",
57
+ "selectionLineageId",
58
+ "selectionIntentSequence",
59
+ "intentSequence",
60
+ "intentId",
61
+ "authoringMode",
62
+ "editableCommandKind",
63
+ "inputKind",
64
+ "visualIntent",
65
+ "preEdit",
66
+ "postEdit",
67
+ "fallback",
68
+ "selectionRevision",
69
+ "timing",
70
+ "selectionTargetMs",
71
+ "textReplaceMs",
72
+ "postEditSelectionMs",
73
+ "totalMs",
74
+ "inputAtMs",
75
+ "dispatchAtMs",
76
+ "committedAtMs",
77
+ "durationMs",
78
+ "elapsedMs",
79
+ "affectedStories",
80
+ "tableId",
81
+ "cellId",
82
+ "contentControlId",
83
+ "outsideContentControl",
84
+ "trackedBlockOffset",
85
+ "projectionBlockId",
86
+ "geometryBlockId",
87
+ "geometryBlockOffset",
88
+ "geometryTrackedBlockOffset",
89
+ "lineAffinity",
90
+ "inlineAffinity",
91
+ "stability",
92
+ "nativeId",
93
+ "paraId",
94
+ "partId",
95
+ "partRevision",
96
+ "storyRevision",
97
+ "pathFingerprint",
98
+ "path",
99
+ "index",
100
+ "name",
101
+ "id",
102
+ "range",
103
+ "hasRangeSelection",
104
+ "inputType",
105
+ "dataLength",
106
+ "isComposing",
107
+ "repeat",
108
+ "altKey",
109
+ "ctrlKey",
110
+ "metaKey",
111
+ "shiftKey",
112
+ "key",
113
+ "button",
114
+ "buttons",
115
+ "pointerType",
116
+ "clickCount",
117
+ "x",
118
+ "y",
119
+ "selector",
120
+ "domPath",
121
+ "scrollLeft",
122
+ "scrollTop",
123
+ "command",
124
+ "segments",
125
+ "nodeId",
126
+ "byteSpan",
127
+ "sdtId",
128
+ "controlId",
129
+ "scope",
130
+ "coordinateSpace",
131
+ "contentControlIds",
132
+ "scrollAncestors",
133
+ "layoutBlockRef",
134
+ "contextSource"
135
+ ]);
136
+ var contentFields$1 = /* @__PURE__ */ new Set([
137
+ "text",
138
+ "data",
139
+ "message",
140
+ "errorMessage",
141
+ "quotedText"
142
+ ]);
143
+ var inputTypes = [
144
+ "keydown",
145
+ "keyup",
146
+ "beforeinput",
147
+ "pointerdown",
148
+ "pointermove",
149
+ "pointerup",
150
+ "click",
151
+ "dblclick",
152
+ "mousedown",
153
+ "mouseup",
154
+ "scroll",
155
+ "compositionstart",
156
+ "compositionend",
157
+ "paste",
158
+ "cut",
159
+ "drop",
160
+ "dragstart"
161
+ ];
162
+ var namedKeys = /* @__PURE__ */ new Set([
163
+ "Alt",
164
+ "AltGraph",
165
+ "CapsLock",
166
+ "Control",
167
+ "Meta",
168
+ "NumLock",
169
+ "ScrollLock",
170
+ "Shift",
171
+ "Enter",
172
+ "Tab",
173
+ "ArrowLeft",
174
+ "ArrowRight",
175
+ "ArrowUp",
176
+ "ArrowDown",
177
+ "End",
178
+ "Home",
179
+ "PageDown",
180
+ "PageUp",
181
+ "Backspace",
182
+ "Delete",
183
+ "Insert",
184
+ "Escape",
185
+ "ContextMenu",
186
+ "Pause",
187
+ "Dead",
188
+ "Process",
189
+ "Unidentified"
190
+ ]);
191
+ var nextSession$1 = 0;
192
+ function own$1(value, key) {
193
+ return value && typeof value === "object" ? Object.getOwnPropertyDescriptor(value, key)?.value : void 0;
194
+ }
195
+ function budget(value, fallback, maximum) {
196
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= maximum ? value : fallback;
197
+ }
198
+ var WorkflowRecorder = class {
199
+ constructor(root, version) {
200
+ this.root = root;
201
+ this.version = version;
202
+ this.session = null;
203
+ this.events = [];
204
+ this.startMs = 0;
205
+ this.maxEvents = 2e4;
206
+ this.maxBytes = 8388608;
207
+ this.closed = false;
208
+ this.pendingIntents = /* @__PURE__ */ new Set();
209
+ this.heldKeys = /* @__PURE__ */ new Set();
210
+ this.heldButtons = /* @__PURE__ */ new Set();
211
+ this.cleanups = [];
212
+ const recorder = this;
213
+ this.api = Object.freeze({
214
+ get active() {
215
+ return recorder.active;
216
+ },
217
+ start: (options) => this.start(options),
218
+ stop: () => this.stop(),
219
+ getSnapshot: () => this.snapshot()
220
+ });
221
+ }
222
+ attachInputs() {
223
+ const view = this.root.ownerDocument.defaultView;
224
+ if (!view) throw new Error("Workflow recording requires a browser window.");
225
+ try {
226
+ for (const type of inputTypes) {
227
+ const listener = (event) => {
228
+ if (!this.active || !event.isTrusted) return;
229
+ try {
230
+ if (event.target instanceof view.Node && this.root.contains(event.target)) this.input(event);
231
+ else if (event.type === "keyup" ? this.heldKeys.delete(event.key) : event.type === "pointerup" ? this.heldButtons.delete(event.button) : false) this.unsupported("input-released-outside-mount");
232
+ } catch {
233
+ this.fail("capture-failure");
234
+ }
235
+ };
236
+ view.addEventListener(type, listener, true);
237
+ this.cleanups.push(() => view.removeEventListener(type, listener, true));
238
+ }
239
+ } catch (error) {
240
+ this.detachInputs();
241
+ throw error;
242
+ }
243
+ }
244
+ detachInputs() {
245
+ const cleanups = this.cleanups;
246
+ this.cleanups = [];
247
+ for (const cleanup of cleanups) try {
248
+ cleanup();
249
+ } catch {}
250
+ }
251
+ get active() {
252
+ return this.session?.status === "recording";
253
+ }
254
+ start(options = {}) {
255
+ if (this.closed) throw new Error("Cannot record a destroyed SuperDoc instance.");
256
+ if (this.active) throw new Error("Stop the active workflow recording first.");
257
+ this.maxEvents = budget(own$1(options, "maxEvents"), 2e4, 1e5);
258
+ this.maxBytes = budget(own$1(options, "maxBytes"), 8388608, 67108864);
259
+ const view = this.root.ownerDocument.defaultView;
260
+ this.events = [];
261
+ this.pendingIntents.clear();
262
+ this.startMs = view.performance.now();
263
+ this.session = {
264
+ schemaVersion: 1,
265
+ sessionId: `workflow-${Date.now()}-${++nextSession$1}`,
266
+ version: this.version(),
267
+ status: "recording",
268
+ startedAt: Date.now(),
269
+ durationMs: 0,
270
+ timeOrigin: view.performance.timeOrigin,
271
+ startTimeMs: this.startMs,
272
+ captureContent: own$1(options, "captureContent") === true,
273
+ viewport: {
274
+ width: view.innerWidth,
275
+ height: view.innerHeight,
276
+ devicePixelRatio: view.devicePixelRatio
277
+ },
278
+ retainedBytes: 0,
279
+ replayUnsupportedReasons: [],
280
+ pendingIntentIds: []
281
+ };
282
+ try {
283
+ this.attachInputs();
284
+ this.observe("workflow:started", () => ({
285
+ scrollTop: this.root.scrollTop,
286
+ scrollLeft: this.root.scrollLeft
287
+ }));
288
+ } catch {
289
+ this.fail("capture-failure");
290
+ }
291
+ return this.snapshot();
292
+ }
293
+ observe(type, read) {
294
+ if (!this.active) return;
295
+ try {
296
+ let remaining = 4096;
297
+ const copy = (value, depth = 0) => {
298
+ if (--remaining < 0 || depth > 14) throw new Error("payload-limit");
299
+ if (value === null || typeof value === "boolean") return value;
300
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
301
+ if (typeof value === "string") {
302
+ if (value.length > 32768) throw new Error("payload-limit");
303
+ return value;
304
+ }
305
+ if (!value || typeof value !== "object") return void 0;
306
+ if (Array.isArray(value)) {
307
+ if (value.length > 256) throw new Error("payload-limit");
308
+ return Array.from({ length: value.length }, (_, i) => copy(own$1(value, String(i)), depth + 1) ?? null);
309
+ }
310
+ const result = {};
311
+ for (const key of fields$1) {
312
+ const item = own$1(value, key);
313
+ if (key === "value" && typeof item === "string" && !this.session.captureContent) continue;
314
+ if (item !== void 0) result[key] = copy(item, depth + 1);
315
+ }
316
+ if (this.session.captureContent) for (const key of contentFields$1) {
317
+ const item = own$1(value, key);
318
+ if (item !== void 0) result[key] = copy(item, depth + 1);
319
+ }
320
+ return result;
321
+ };
322
+ const event = {
323
+ sequence: this.events.length + 1,
324
+ atMs: this.root.ownerDocument.defaultView.performance.now() - this.startMs,
325
+ type,
326
+ data: copy(read()) ?? {}
327
+ };
328
+ const serialized = JSON.stringify(event);
329
+ if (this.events.length >= this.maxEvents || this.session.retainedBytes + serialized.length * 2 > this.maxBytes) {
330
+ this.fail("capture-limit");
331
+ return;
332
+ }
333
+ this.events.push(serialized);
334
+ this.session.retainedBytes += serialized.length * 2;
335
+ if (type === "interaction:intent") {
336
+ const id = `${event.data.documentId ?? ""}/${event.data.selectionLineageId}/${event.data.intentSequence}`;
337
+ if (event.data.phase === "enqueued" || event.data.phase === "executing") this.pendingIntents.add(id);
338
+ if (event.data.phase === "settled" || event.data.phase === "failed") this.pendingIntents.delete(id);
339
+ }
340
+ } catch {
341
+ this.fail("capture-failure");
342
+ }
343
+ }
344
+ unsupported(reason) {
345
+ if (!this.session.replayUnsupportedReasons.includes(reason)) this.session.replayUnsupportedReasons.push(reason);
346
+ }
347
+ fail(reason) {
348
+ if (!this.session) return;
349
+ this.unsupported(reason);
350
+ try {
351
+ this.session.durationMs = this.root.ownerDocument.defaultView.performance.now() - this.startMs;
352
+ } catch {}
353
+ this.session.status = "incomplete";
354
+ this.clearHeldInput();
355
+ this.detachInputs();
356
+ }
357
+ input(event) {
358
+ if (!this.active || !event.isTrusted) return;
359
+ try {
360
+ const target = event.target instanceof this.root.ownerDocument.defaultView.Element ? event.target : this.root;
361
+ const pointer = event;
362
+ if (event.type === "pointermove" && pointer.buttons === 0) return;
363
+ let element = target;
364
+ let selector = null;
365
+ while (element && element !== this.root) {
366
+ for (const attribute of [
367
+ "data-layout-fragment-id",
368
+ "data-layout-block-ref",
369
+ "data-page-index",
370
+ "data-item",
371
+ "data-testid",
372
+ "aria-label"
373
+ ]) {
374
+ const value = element.getAttribute(attribute);
375
+ if (value) {
376
+ selector = `[${attribute}=${JSON.stringify(value)}]`;
377
+ break;
378
+ }
379
+ }
380
+ if (selector) break;
381
+ element = element.parentElement;
382
+ }
383
+ if (!selector && target !== this.root) {
384
+ const path = [];
385
+ element = target;
386
+ while (element && element !== this.root) {
387
+ const parent = element.parentElement;
388
+ if (!parent) break;
389
+ path.unshift(`:nth-child(${Array.prototype.indexOf.call(parent.children, element) + 1})`);
390
+ element = parent;
391
+ }
392
+ if (element === this.root) selector = `:scope > ${path.join(" > ")}`;
393
+ element = target;
394
+ }
395
+ const modifiers = event;
396
+ const paintedTarget = { selector };
397
+ if (event.type.startsWith("pointer") || [
398
+ "mousedown",
399
+ "mouseup",
400
+ "click",
401
+ "dblclick"
402
+ ].includes(event.type)) {
403
+ const path = [];
404
+ let part = element ?? this.root;
405
+ while (part && part !== this.root) {
406
+ const parent = part.parentElement;
407
+ if (!parent) break;
408
+ path.unshift(`:nth-child(${Array.prototype.indexOf.call(parent.children, part) + 1})`);
409
+ part = parent;
410
+ }
411
+ if (part === this.root && path.length) paintedTarget.domPath = `:scope > ${path.join(" > ")}`;
412
+ const controls = /* @__PURE__ */ new Set();
413
+ for (let ancestor = target; ancestor && ancestor !== this.root; ancestor = ancestor.parentElement) {
414
+ for (const [attribute, field] of [
415
+ ["data-source-node-id", "blockId"],
416
+ ["data-layout-fragment-id", "fragmentId"],
417
+ ["data-layout-block-ref", "layoutBlockRef"],
418
+ ["data-layout-story", "storyId"],
419
+ ["data-page-index", "pageIndex"]
420
+ ]) {
421
+ const value = ancestor.getAttribute(attribute);
422
+ if (value && paintedTarget[field] == null) paintedTarget[field] = field === "pageIndex" ? Number(value) : value;
423
+ }
424
+ const control = ancestor.getAttribute("data-sdt-id") ?? ancestor.getAttribute("data-sdt-container-id");
425
+ if (control) controls.add(control);
426
+ if (ancestor.classList.contains("superdoc-table-fragment") && paintedTarget.tableId == null) paintedTarget.tableId = ancestor.getAttribute("data-layout-block-ref");
427
+ }
428
+ paintedTarget.contentControlIds = [...controls];
429
+ paintedTarget.contextSource = "painted-pointer";
430
+ if (paintedTarget.fragmentId && paintedTarget.pageIndex != null) paintedTarget.selector = `[data-page-index="${paintedTarget.pageIndex}"] ${selector}`;
431
+ const scrollAncestors = [];
432
+ for (let ancestor = target; ancestor; ancestor = ancestor.parentElement) {
433
+ const style = this.root.ownerDocument.defaultView.getComputedStyle(ancestor);
434
+ const scrollable = ancestor === this.root || /auto|scroll/.test(`${style.overflowX} ${style.overflowY}`);
435
+ if (ancestor.scrollLeft || ancestor.scrollTop || scrollable && (ancestor.scrollWidth > ancestor.clientWidth || ancestor.scrollHeight > ancestor.clientHeight)) {
436
+ const path = [];
437
+ let part = ancestor;
438
+ while (part && part !== this.root) {
439
+ const parent = part.parentElement;
440
+ if (!parent) break;
441
+ path.unshift(`:nth-child(${Array.prototype.indexOf.call(parent.children, part) + 1})`);
442
+ part = parent;
443
+ }
444
+ if (part === this.root) scrollAncestors.push({
445
+ selector: ancestor === this.root ? null : `:scope > ${path.join(" > ")}`,
446
+ scrollLeft: ancestor.scrollLeft,
447
+ scrollTop: ancestor.scrollTop
448
+ });
449
+ }
450
+ if (ancestor === this.root) break;
451
+ if (scrollAncestors.length >= 32) throw new Error("scroll-ancestor-limit");
452
+ }
453
+ paintedTarget.scrollAncestors = scrollAncestors;
454
+ }
455
+ const data = {
456
+ target: paintedTarget,
457
+ inputAtMs: event.timeStamp > this.root.ownerDocument.defaultView.performance.timeOrigin ? event.timeStamp - this.root.ownerDocument.defaultView.performance.timeOrigin : event.timeStamp,
458
+ altKey: modifiers.altKey,
459
+ ctrlKey: modifiers.ctrlKey,
460
+ metaKey: modifiers.metaKey,
461
+ shiftKey: modifiers.shiftKey
462
+ };
463
+ if (event.type === "keydown" || event.type === "keyup") {
464
+ const key = modifiers.key;
465
+ if (event.type === "keydown") this.heldKeys.add(key);
466
+ else this.heldKeys.delete(key);
467
+ const named = namedKeys.has(key) || /^F(?:[1-9]|1\d|2[0-4])$/.test(key);
468
+ data.key = !named && !this.session.captureContent ? void 0 : key;
469
+ data.repeat = modifiers.repeat;
470
+ data.isComposing = modifiers.isComposing;
471
+ if (!named && !this.session.captureContent) this.unsupported("content-redacted");
472
+ if (modifiers.isComposing || key === "Dead" || key === "Process") this.unsupported("ime");
473
+ } else if (event.type.startsWith("pointer") || [
474
+ "mousedown",
475
+ "mouseup",
476
+ "click",
477
+ "dblclick"
478
+ ].includes(event.type)) {
479
+ const rect = (element ?? this.root).getBoundingClientRect();
480
+ if (event.type === "pointerdown") this.heldButtons.add(pointer.button);
481
+ if (event.type === "pointerup") this.heldButtons.delete(pointer.button);
482
+ Object.assign(data, {
483
+ button: pointer.button,
484
+ buttons: pointer.buttons,
485
+ pointerType: pointer.pointerType ?? "mouse",
486
+ clickCount: pointer.detail,
487
+ x: pointer.clientX - rect.left,
488
+ y: pointer.clientY - rect.top
489
+ });
490
+ if (pointer.pointerType && pointer.pointerType !== "mouse") this.unsupported("non-mouse-pointer");
491
+ if (!selector) this.unsupported("unresolved-pointer-target");
492
+ } else if (event.type === "scroll") {
493
+ Object.assign(data, {
494
+ scrollTop: target.scrollTop,
495
+ scrollLeft: target.scrollLeft
496
+ });
497
+ if (target !== this.root && !selector) this.unsupported("unresolved-scroll-target");
498
+ } else {
499
+ const input = event;
500
+ Object.assign(data, {
501
+ inputType: input.inputType,
502
+ dataLength: input.data?.length,
503
+ ...this.session.captureContent ? { data: input.data } : {}
504
+ });
505
+ if (input.data && !this.session.captureContent) this.unsupported("content-redacted");
506
+ if ([
507
+ "paste",
508
+ "cut",
509
+ "drop",
510
+ "dragstart",
511
+ "compositionstart",
512
+ "compositionend"
513
+ ].includes(event.type)) this.unsupported(event.type);
514
+ if (event.type === "beforeinput" && input.inputType !== "insertText" && !input.inputType?.startsWith("delete")) this.unsupported(`beforeinput:${input.inputType}`);
515
+ }
516
+ this.observe(`browser:${event.type}`, () => data);
517
+ } catch {
518
+ this.fail("capture-failure");
519
+ }
520
+ }
521
+ clearHeldInput() {
522
+ this.heldKeys.clear();
523
+ this.heldButtons.clear();
524
+ }
525
+ stop() {
526
+ if (this.active) {
527
+ if (this.heldKeys.size || this.heldButtons.size) this.unsupported("held-input-at-stop");
528
+ this.session.durationMs = this.root.ownerDocument.defaultView.performance.now() - this.startMs;
529
+ this.session.status = "stopped";
530
+ this.clearHeldInput();
531
+ }
532
+ this.detachInputs();
533
+ return this.snapshot();
534
+ }
535
+ snapshot() {
536
+ if (!this.session) return null;
537
+ return {
538
+ ...this.session,
539
+ viewport: { ...this.session.viewport },
540
+ durationMs: this.active ? this.root.ownerDocument.defaultView.performance.now() - this.startMs : this.session.durationMs,
541
+ replayUnsupportedReasons: [...this.session.replayUnsupportedReasons],
542
+ events: this.events.map((event) => JSON.parse(event)),
543
+ pendingIntentIds: [...this.pendingIntents]
544
+ };
545
+ }
546
+ close() {
547
+ if (this.active) this.fail("instance-destroyed");
548
+ this.closed = true;
549
+ this.detachInputs();
550
+ }
551
+ };
552
+ //#endregion
2
553
  //#region src/internal/diagnostics/interaction-history.ts
554
+ function isWorkflowRecordingEnabled(config) {
555
+ try {
556
+ return own(own(own(config, "diagnostics"), "recording"), "enabled") === true;
557
+ } catch {
558
+ return false;
559
+ }
560
+ }
3
561
  var recorders = /* @__PURE__ */ new WeakMap();
4
562
  var nextSession = 0;
5
563
  var fields = [
@@ -105,7 +663,7 @@ function limit(value, fallback, ceiling) {
105
663
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= ceiling ? value : fallback;
106
664
  }
107
665
  var InteractionRecorder = class {
108
- constructor(config, version) {
666
+ constructor(config, version, root) {
109
667
  this.version = version;
110
668
  this.sessionId = `interaction-${++nextSession}`;
111
669
  this.slots = [];
@@ -119,6 +677,9 @@ var InteractionRecorder = class {
119
677
  this.failures = 0;
120
678
  this.closed = false;
121
679
  this.cleanups = [];
680
+ if (isWorkflowRecordingEnabled(config)) try {
681
+ this.workflow = new WorkflowRecorder(root, version);
682
+ } catch {}
122
683
  const history = own(own(config, "diagnostics"), "history");
123
684
  this.enabled = own(history, "enabled") !== false;
124
685
  this.captureContent = own(history, "captureContent") === true;
@@ -126,6 +687,7 @@ var InteractionRecorder = class {
126
687
  this.maxBytes = limit(own(history, "maxBytes"), 1048576, 16777216);
127
688
  }
128
689
  record(type, read) {
690
+ this.workflow?.observe(type, read);
129
691
  if (!this.enabled || this.closed) return;
130
692
  try {
131
693
  let truncated = false;
@@ -202,7 +764,7 @@ var InteractionRecorder = class {
202
764
  }
203
765
  }
204
766
  action() {
205
- return this.enabled && !this.closed ? `${this.sessionId}:${++this.actions}` : void 0;
767
+ return (this.enabled || this.workflow?.active) && !this.closed ? `${this.sessionId}:${++this.actions}` : void 0;
206
768
  }
207
769
  snapshot() {
208
770
  const events = [];
@@ -286,6 +848,7 @@ var InteractionRecorder = class {
286
848
  }
287
849
  }
288
850
  close() {
851
+ this.workflow?.close();
289
852
  this.closed = true;
290
853
  for (const cleanup of this.cleanups) try {
291
854
  cleanup();
@@ -312,10 +875,11 @@ var unavailable = Object.freeze({
312
875
  });
313
876
  function createInteractionHistory(owner, config, version, root) {
314
877
  try {
315
- const recorder = new InteractionRecorder(config, version);
878
+ const recorder = new InteractionRecorder(config, version, root);
316
879
  recorders.set(owner, recorder);
317
880
  recorder.attach(root);
318
881
  const handle = Object.freeze({
882
+ ...recorder.workflow ? { recording: recorder.workflow.api } : {},
319
883
  getSnapshot: () => {
320
884
  try {
321
885
  return recorder.snapshot();
@@ -360,6 +924,9 @@ function closeInteractionHistory(owner) {
360
924
  recorders.delete(owner);
361
925
  } catch {}
362
926
  }
927
+ function getWorkflowRecording(owner) {
928
+ return recorders.get(owner)?.workflow?.api;
929
+ }
363
930
  //#endregion
364
931
  //#region ../layout-engine/dom-contract/src/class-names.ts
365
932
  /**
@@ -5683,6 +6250,7 @@ function createSuperDocUI(options) {
5683
6250
  let asyncReadFailureRetryAtMs = 0;
5684
6251
  let foregroundAsyncRetryTimer = null;
5685
6252
  let pendingSelectionSeedValidationToken = null;
6253
+ let typedCaretValidationHeld = false;
5686
6254
  let typingContentInvalidationTimer = null;
5687
6255
  const pendingAsyncReadSettlements = [];
5688
6256
  const scheduleAsyncRefresh = () => {
@@ -6120,6 +6688,16 @@ function createSuperDocUI(options) {
6120
6688
  scheduleForegroundAsyncRetry();
6121
6689
  return;
6122
6690
  }
6691
+ if (typedCaretValidationHeld && Date.now() - lastTypingMutationAtMs < HEAVY_READ_IDLE_MS) {
6692
+ const token = selectionReadToken();
6693
+ if (asyncReads.get("selection")?.token !== token) {
6694
+ refreshSelectionFromHost(void 0, true);
6695
+ if (asyncReads.get("selection")?.token === token) recompute();
6696
+ }
6697
+ scheduleForegroundAsyncRetry(HEAVY_READ_IDLE_POLL_MS);
6698
+ return;
6699
+ }
6700
+ typedCaretValidationHeld = false;
6123
6701
  const validationToken = pendingSelectionSeedValidationToken;
6124
6702
  pendingSelectionSeedValidationToken = null;
6125
6703
  if (validationToken === selectionReadToken()) issueAsyncRead("selection", validationToken, selectionCurrentRun, normalizeSelectionInfo);
@@ -6258,7 +6836,7 @@ function createSuperDocUI(options) {
6258
6836
  }
6259
6837
  if (pendingPostPaintSelectionRefresh) continue;
6260
6838
  selectionEpoch += 1;
6261
- refreshSelectionFromHost();
6839
+ refreshSelectionFromHost(void 0, true);
6262
6840
  recompute(paintCompleted ? "post-paint-selection" : "post-paint-selection-failed");
6263
6841
  }
6264
6842
  };
@@ -6269,7 +6847,11 @@ function createSuperDocUI(options) {
6269
6847
  if (typingContentInvalidationTimer) clearTimeout(typingContentInvalidationTimer);
6270
6848
  typingContentInvalidationTimer = setTimeout(() => {
6271
6849
  typingContentInvalidationTimer = null;
6272
- if (!disposed) invalidateDocumentContentAndRecompute();
6850
+ if (!disposed) {
6851
+ invalidateDocumentContent();
6852
+ if (typedCaretValidationHeld && !foregroundMutationActive()) refreshSelectionFromHost(void 0, true);
6853
+ recompute();
6854
+ }
6273
6855
  }, 500);
6274
6856
  };
6275
6857
  const issueAsyncRead = (key, token, run, normalize) => {
@@ -6363,6 +6945,13 @@ function createSuperDocUI(options) {
6363
6945
  value: entry.value,
6364
6946
  status: "ready"
6365
6947
  };
6948
+ if (key === "selection" && typedCaretValidationHeld && Date.now() - lastTypingMutationAtMs < HEAVY_READ_IDLE_MS) {
6949
+ scheduleForegroundAsyncRetry(HEAVY_READ_IDLE_POLL_MS);
6950
+ return {
6951
+ value: entry?.hasSettled ? entry.value : null,
6952
+ status: entry?.hasSettled ? "stale" : "pending"
6953
+ };
6954
+ }
6366
6955
  if (isHeavyDocReadKey(key) && !heavyReadDemandActive(key, token)) {
6367
6956
  if (hostSourceLoadPhase() === "loading") {
6368
6957
  heavyReadsHeldUntilIdle = true;
@@ -6484,6 +7073,7 @@ function createSuperDocUI(options) {
6484
7073
  heldSettledInlineValues = null;
6485
7074
  optimisticParagraphAlignment = null;
6486
7075
  pendingSelectionSeedValidationToken = null;
7076
+ typedCaretValidationHeld = false;
6487
7077
  coldAsyncReadDeferrals.clear();
6488
7078
  demandedHeavyReads.clear();
6489
7079
  incompleteTrackChangesDirectoryReadTokens.clear();
@@ -6665,9 +7255,10 @@ function createSuperDocUI(options) {
6665
7255
  * same carrier, or while an active typing dispatch advances the same caret by
6666
7256
  * one code point. Pending work alone never carries review command context.
6667
7257
  */
6668
- const refreshSelectionFromHost = (hostSelectionSnapshot) => {
7258
+ const refreshSelectionFromHost = (hostSelectionSnapshot, afterTypingPaint = false) => {
6669
7259
  const foreground = foregroundMutationState();
6670
7260
  if (isNonCollapsedHostSelection(hostSelectionSnapshot) && !(foreground && foreground.active > 0)) {
7261
+ typedCaretValidationHeld = false;
6671
7262
  pendingSelectionSeedValidationToken = null;
6672
7263
  issueAsyncRead("selection", selectionReadToken(), selectionCurrentRun, normalizeSelectionInfo);
6673
7264
  return;
@@ -6677,8 +7268,14 @@ function createSuperDocUI(options) {
6677
7268
  if (typeof read !== "function") return;
6678
7269
  const seed = normalizeSelectionInfo(safeCall(() => read.call(host), null));
6679
7270
  if (!seed || !isCollapsedCaretSnapshot(seed)) return;
7271
+ const previousCaret = collapsedTextAddressFromSelection(state.selection);
7272
+ const nextCaret = collapsedTextAddressFromTarget(seed.selectionTarget) ?? collapsedTextAddressFromTarget(seed.target);
7273
+ const previousRange = previousCaret?.range;
7274
+ const nextRange = nextCaret?.range;
7275
+ const sameSeedCaret = Boolean(previousCaret && nextCaret && previousCaret.blockId === nextCaret.blockId && storyLocatorSignature(previousCaret.story) === storyLocatorSignature(nextCaret.story) && previousRange?.start === nextRange?.start);
7276
+ typedCaretValidationHeld = Boolean(foreground && foreground.active > 0) || typedCaretValidationHeld && (afterTypingPaint || sameSeedCaret);
6680
7277
  const token = selectionReadToken();
6681
- const deferAuthoritativeRead = Boolean(foreground && (foreground.active > 0 || foreground.pending > 0));
7278
+ const deferAuthoritativeRead = Boolean(foreground && (foreground.active > 0 || foreground.pending > 0)) || typedCaretValidationHeld && Date.now() - lastTypingMutationAtMs < HEAVY_READ_IDLE_MS;
6682
7279
  if (!deferAuthoritativeRead) {
6683
7280
  pendingSelectionSeedValidationToken = null;
6684
7281
  if (issueAsyncRead("selection", token, selectionCurrentRun, normalizeSelectionInfo)) return;
@@ -6690,10 +7287,6 @@ function createSuperDocUI(options) {
6690
7287
  const seedMarks = Array.isArray(seed.activeMarks) && seed.activeMarks.length > 0 ? seed.activeMarks : Array.isArray(state.selection.activeMarks) ? state.selection.activeMarks : [];
6691
7288
  const seedCommentIds = Array.isArray(seed.activeCommentIds) ? seed.activeCommentIds : [];
6692
7289
  const paintedTrackChangeId = readCollapsedHostTrackChangeId(hostSelectionSnapshot);
6693
- const previousCaret = collapsedTextAddressFromSelection(state.selection);
6694
- const nextCaret = collapsedTextAddressFromTarget(seed.selectionTarget) ?? collapsedTextAddressFromTarget(seed.target);
6695
- const previousRange = previousCaret?.range;
6696
- const nextRange = nextCaret?.range;
6697
7290
  const sameActiveTypingCaret = Boolean(foreground && foreground.active > 0 && previousCaret && nextCaret && previousCaret.blockId === nextCaret.blockId && storyLocatorSignature(previousCaret.story) === storyLocatorSignature(nextCaret.story) && typeof previousRange?.start === "number" && typeof nextRange?.start === "number" && Math.abs(nextRange.start - previousRange.start) <= 2);
6698
7291
  const carriedChangeIds = paintedTrackChangeId != null || sameActiveTypingCaret ? state.selection.activeChangeIds.filter((id) => paintedTrackChangeId == null || buildTrackedChangeIdContext(state.trackChanges.items).aliasesFor(id).includes(paintedTrackChangeId)) : [];
6699
7292
  const seedChangeIds = Array.isArray(seed.activeChangeIds) && seed.activeChangeIds.length > 0 ? seed.activeChangeIds : carriedChangeIds;
@@ -7660,6 +8253,7 @@ function createSuperDocUI(options) {
7660
8253
  if (support && (support.status === "supported" || support.enabled === true)) return void 0;
7661
8254
  return SUPERDOC_UI_REASONS.bulkDecisionsDisabled;
7662
8255
  };
8256
+ const canStorePendingInlineFormat = (selection) => selection.empty && collapsedTextAddressFromSelection(selection) != null && typeof getHost()?.setPendingInlineFormat === "function";
7663
8257
  const computeCommandState = (id, doc, selection, projectedInlineValues, lockModesById = /* @__PURE__ */ new Map()) => {
7664
8258
  if (customCommands.has(id)) return normalizeCommandState({
7665
8259
  supported: true,
@@ -7814,7 +8408,7 @@ function createSuperDocUI(options) {
7814
8408
  value,
7815
8409
  reason: lockReason
7816
8410
  }, "builtin");
7817
- return normalizeCommandState(selectionBlockIds(selection).length > 0 && typeof getHost()?.setPendingInlineFormat === "function" ? {
8411
+ return normalizeCommandState(canStorePendingInlineFormat(selection) ? {
7818
8412
  enabled: true,
7819
8413
  active,
7820
8414
  supported: true,
@@ -10466,7 +11060,7 @@ function createSuperDocUI(options) {
10466
11060
  if (trackDecisionCommand(id)?.scope === "id") return true;
10467
11061
  if (!descriptor || descriptor.disposition !== "routed") return true;
10468
11062
  if (descriptor.inline?.kind === "clear") return selectionBlockIds(state.selection).length > 0 || resolveInlineSelectionTarget(state.selection) != null;
10469
- if (descriptor.inline) return resolveInlineSelectionTarget(state.selection) != null || selectionBlockIds(state.selection).length > 0;
11063
+ if (descriptor.inline) return resolveInlineSelectionTarget(state.selection) != null || canStorePendingInlineFormat(state.selection);
10470
11064
  if (descriptor.blockParagraph || descriptor.list) return selectionBlockIds(state.selection).length > 0;
10471
11065
  if (descriptor.link) return linkPayloadHasExplicitTarget(payload) || selectionTextAddresses(state.selection).length > 0 || collapsedTextAddressFromSelection(state.selection) != null || commandActiveState(descriptor, getDoc(), state.selection);
10472
11066
  return true;
@@ -10532,7 +11126,7 @@ function createSuperDocUI(options) {
10532
11126
  if (contentControlLockReason(lockModesById)) return false;
10533
11127
  const target = resolveInlineSelectionTarget(state.selection);
10534
11128
  if (!target) {
10535
- if (state.selection.empty === false) return settleCommandExecution(false);
11129
+ if (!canStorePendingInlineFormat(state.selection)) return settleCommandExecution(false);
10536
11130
  return settleCommandExecution(storePendingInlineFormat(descriptor, normalized));
10537
11131
  }
10538
11132
  const active = commandActiveState(descriptor, doc, state.selection);
@@ -13633,4 +14227,4 @@ function commandIsActive(descriptor, selection) {
13633
14227
  return descriptor.activeMark ? selection.activeMarks.includes(descriptor.activeMark) : false;
13634
14228
  }
13635
14229
  //#endregion
13636
- export { BUILT_IN_COMMAND_IDS as a, createImageFilePicker as c, DOM_CLASS_NAMES as d, closeInteractionHistory as f, registerFirstPartyCommandMutation as i, resolveImageSrc as l, recordInteraction as m, executeFirstPartyCommandAsync as n, applyV2CommentInvalidationFromMutation as o, createInteractionHistory as p, readFirstPartyPageNumbers as r, getV2TrackedChangeMutationImpact as s, createSuperDocUI as t, shallowEqual as u };
14230
+ export { BUILT_IN_COMMAND_IDS as a, createImageFilePicker as c, DOM_CLASS_NAMES as d, closeInteractionHistory as f, recordInteraction as g, isWorkflowRecordingEnabled as h, registerFirstPartyCommandMutation as i, resolveImageSrc as l, getWorkflowRecording as m, executeFirstPartyCommandAsync as n, applyV2CommentInvalidationFromMutation as o, createInteractionHistory as p, readFirstPartyPageNumbers as r, getV2TrackedChangeMutationImpact as s, createSuperDocUI as t, shallowEqual as u };