superdoc 2.25.0-next.2 → 2.25.0-next.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/chunks/{create-super-doc-ui-D8ss5E0J.cjs → create-super-doc-ui-C-oN_R2a.cjs} +19 -0
  2. package/dist/chunks/{create-super-doc-ui-3habU4hL.es.js → create-super-doc-ui-D5waZHl3.es.js} +19 -0
  3. package/dist/collaboration-upgrade-engine.cjs +1 -1
  4. package/dist/collaboration-upgrade-engine.es.js +1 -1
  5. package/dist/document-api/src/comments/comments.types.d.ts +2 -0
  6. package/dist/document-api/src/content-controls/content-controls.types.d.ts +4 -2
  7. package/dist/document-api/src/contract/operation-definitions.d.ts +1 -1
  8. package/dist/document-api/src/hyperlinks/hyperlinks.types.d.ts +9 -2
  9. package/dist/document-api/src/images/images.types.d.ts +3 -3
  10. package/dist/document-api/src/index.d.ts +1 -0
  11. package/dist/document-api/src/lists/lists.types.d.ts +11 -11
  12. package/dist/document-api/src/permission-ranges/permission-ranges.d.ts +9 -1
  13. package/dist/document-api/src/permission-ranges/permission-ranges.types.d.ts +17 -0
  14. package/dist/document-api/src/protection/protection.types.d.ts +2 -2
  15. package/dist/document-api/src/receipt-bridge.d.ts +3 -0
  16. package/dist/document-api/src/types/blocks.types.d.ts +2 -2
  17. package/dist/document-api/src/types/mutation-plan.types.d.ts +2 -2
  18. package/dist/document-api/src/types/receipt.d.ts +12 -0
  19. package/dist/document-api/src/types/sd-contract.d.ts +3 -0
  20. package/dist/document-api/src/types/track-changes.types.d.ts +8 -0
  21. package/dist/layout-engine/contracts/src/incremental-dependency.d.ts +2 -2
  22. package/dist/layout-engine/contracts/src/index.d.ts +4 -0
  23. package/dist/layout-engine/layout-bridge/src/font-metrics-cache.d.ts +2 -23
  24. package/dist/layout-engine/layout-bridge/src/incrementalLayout.d.ts +11 -4
  25. package/dist/layout-engine/layout-bridge/src/index.d.ts +2 -2
  26. package/dist/layout-engine/layout-bridge/src/measurement-environment.d.ts +12 -0
  27. package/dist/layout-engine/layout-bridge/src/resolveLiveCrossReferences.d.ts +1 -1
  28. package/dist/layout-engine/painters/dom/src/index.d.ts +4 -0
  29. package/dist/layout-engine/painters/dom/src/runs/text-run.d.ts +2 -17
  30. package/dist/layout-engine/painters/dom/src/runs/text-style-facts.d.ts +9 -0
  31. package/dist/layout-engine/painters/dom/src/runs/tracked-changes.d.ts +6 -9
  32. package/dist/layout-engine/painters/dom/src/styles.d.ts +21 -0
  33. package/dist/public/ui-react.cjs +1 -1
  34. package/dist/public/ui-react.es.js +1 -1
  35. package/dist/public/ui-vue.cjs +1 -1
  36. package/dist/public/ui-vue.es.js +1 -1
  37. package/dist/public/ui.cjs +1 -1
  38. package/dist/public/ui.es.js +1 -1
  39. package/dist/shared/font-system/src/registry.d.ts +5 -1
  40. package/dist/shared/font-system/src/resolver.d.ts +2 -0
  41. package/dist/style.css +27 -27
  42. package/dist/style.layered.css +27 -27
  43. package/dist/superdoc/src/core/types/index.d.ts +1 -1
  44. package/dist/superdoc/src/index.d.cts +2 -0
  45. package/dist/superdoc/src/index.d.ts +1 -0
  46. package/dist/superdoc/src/public/index.d.cts +8 -0
  47. package/dist/superdoc/src/public/index.d.ts +2 -0
  48. package/dist/superdoc/src/stores/comments-store.d.ts +7 -4
  49. package/dist/superdoc/src/stores/superdoc-store.d.ts +21 -12
  50. package/dist/superdoc.cjs +160 -14
  51. package/dist/superdoc.es.js +159 -15
  52. package/dist-cdn/style.layered.css +1 -1
  53. package/dist-cdn/superdoc.min.css +1 -1
  54. package/dist-cdn/superdoc.min.js +42 -42
  55. package/package.json +2 -2
@@ -3970,6 +3970,7 @@ Object.keys(DRAWING_SUPPORT_TAXONOMY);
3970
3970
  Object.freeze([
3971
3971
  "multiple-sections",
3972
3972
  "furniture-page-tokens",
3973
+ "body-page-number-tokens",
3973
3974
  "non-balanceable-multi-column-sections",
3974
3975
  "body-anchored-objects",
3975
3976
  "non-flowing-page-relative-body-anchors",
@@ -7833,7 +7834,16 @@ function createSuperDocUI(options) {
7833
7834
  * query surfaces only DIRECT run properties, so inherited fonts have no
7834
7835
  * projected value; the layout has already resolved them for painting.
7835
7836
  */
7837
+ const appliedSelectionPresentation = (selection) => {
7838
+ const host = getHost(), read = host?.readAppliedSelectionPresentation;
7839
+ if (typeof read !== "function") return null;
7840
+ const value = safeCall(() => read.call(host), null);
7841
+ const info = normalizeSelectionInfo(value?.selection);
7842
+ return value && info && selectionSignature(selectionSliceFromInfo(info, "ready")) === selectionSignature(selection) ? value : null;
7843
+ };
7836
7844
  const resolveEffectiveInlineValuesFromLayout = (selection) => {
7845
+ const applied = appliedSelectionPresentation(selection);
7846
+ if (applied) return applied.inlineStyle ?? {};
7837
7847
  const host = getHost();
7838
7848
  const blockIds = new Set(selectionBlockIds(selection));
7839
7849
  if (blockIds.size === 0) return {};
@@ -7951,6 +7961,8 @@ function createSuperDocUI(options) {
7951
7961
  * `{ style: 'single' }`) when active, never a bare `true` — check presence.
7952
7962
  */
7953
7963
  const resolveEffectiveMarkValuesFromLayout = (selection) => {
7964
+ const applied = appliedSelectionPresentation(selection);
7965
+ if (applied) return applied.inlineStyle ?? {};
7954
7966
  const host = getHost();
7955
7967
  const blockIds = new Set(selectionBlockIds(selection));
7956
7968
  if (blockIds.size === 0) return {};
@@ -8786,6 +8798,11 @@ function createSuperDocUI(options) {
8786
8798
  };
8787
8799
  /** Read effective paragraph alignments from the mounted, style-resolved layout. */
8788
8800
  const readEffectiveParagraphAlignments = (selection, blockIds) => {
8801
+ const applied = appliedSelectionPresentation(selection);
8802
+ if (applied) return new Map(blockIds.flatMap((id) => {
8803
+ const alignment = normalizeParagraphAlignment(applied.paragraphAlignments?.[id]);
8804
+ return alignment ? [[id, alignment]] : [];
8805
+ }));
8789
8806
  const host = getHost();
8790
8807
  const readByIds = host?.readMountedProjectionBlocksByIds;
8791
8808
  if (typeof readByIds !== "function") return null;
@@ -11284,6 +11301,8 @@ function createSuperDocUI(options) {
11284
11301
  return Boolean(readLinkPayloadTarget(payload) || isLooseObject(record.hyperlinkTarget) || isLooseObject(record.textTarget));
11285
11302
  };
11286
11303
  const commandSelectionIsReady = (id, descriptor, payload) => {
11304
+ const foreground = foregroundMutationState();
11305
+ if (foreground && (foreground.active > 0 || foreground.pending > 0)) return false;
11287
11306
  if (state.selection.status !== "ready") return false;
11288
11307
  if (trackDecisionCommand(id)?.scope === "id") return true;
11289
11308
  if (!descriptor || descriptor.disposition !== "routed") return true;
@@ -3969,6 +3969,7 @@ Object.keys(DRAWING_SUPPORT_TAXONOMY);
3969
3969
  Object.freeze([
3970
3970
  "multiple-sections",
3971
3971
  "furniture-page-tokens",
3972
+ "body-page-number-tokens",
3972
3973
  "non-balanceable-multi-column-sections",
3973
3974
  "body-anchored-objects",
3974
3975
  "non-flowing-page-relative-body-anchors",
@@ -7832,7 +7833,16 @@ function createSuperDocUI(options) {
7832
7833
  * query surfaces only DIRECT run properties, so inherited fonts have no
7833
7834
  * projected value; the layout has already resolved them for painting.
7834
7835
  */
7836
+ const appliedSelectionPresentation = (selection) => {
7837
+ const host = getHost(), read = host?.readAppliedSelectionPresentation;
7838
+ if (typeof read !== "function") return null;
7839
+ const value = safeCall(() => read.call(host), null);
7840
+ const info = normalizeSelectionInfo(value?.selection);
7841
+ return value && info && selectionSignature(selectionSliceFromInfo(info, "ready")) === selectionSignature(selection) ? value : null;
7842
+ };
7835
7843
  const resolveEffectiveInlineValuesFromLayout = (selection) => {
7844
+ const applied = appliedSelectionPresentation(selection);
7845
+ if (applied) return applied.inlineStyle ?? {};
7836
7846
  const host = getHost();
7837
7847
  const blockIds = new Set(selectionBlockIds(selection));
7838
7848
  if (blockIds.size === 0) return {};
@@ -7950,6 +7960,8 @@ function createSuperDocUI(options) {
7950
7960
  * `{ style: 'single' }`) when active, never a bare `true` — check presence.
7951
7961
  */
7952
7962
  const resolveEffectiveMarkValuesFromLayout = (selection) => {
7963
+ const applied = appliedSelectionPresentation(selection);
7964
+ if (applied) return applied.inlineStyle ?? {};
7953
7965
  const host = getHost();
7954
7966
  const blockIds = new Set(selectionBlockIds(selection));
7955
7967
  if (blockIds.size === 0) return {};
@@ -8785,6 +8797,11 @@ function createSuperDocUI(options) {
8785
8797
  };
8786
8798
  /** Read effective paragraph alignments from the mounted, style-resolved layout. */
8787
8799
  const readEffectiveParagraphAlignments = (selection, blockIds) => {
8800
+ const applied = appliedSelectionPresentation(selection);
8801
+ if (applied) return new Map(blockIds.flatMap((id) => {
8802
+ const alignment = normalizeParagraphAlignment(applied.paragraphAlignments?.[id]);
8803
+ return alignment ? [[id, alignment]] : [];
8804
+ }));
8788
8805
  const host = getHost();
8789
8806
  const readByIds = host?.readMountedProjectionBlocksByIds;
8790
8807
  if (typeof readByIds !== "function") return null;
@@ -11283,6 +11300,8 @@ function createSuperDocUI(options) {
11283
11300
  return Boolean(readLinkPayloadTarget(payload) || isLooseObject(record.hyperlinkTarget) || isLooseObject(record.textTarget));
11284
11301
  };
11285
11302
  const commandSelectionIsReady = (id, descriptor, payload) => {
11303
+ const foreground = foregroundMutationState();
11304
+ if (foreground && (foreground.active > 0 || foreground.pending > 0)) return false;
11286
11305
  if (state.selection.status !== "ready") return false;
11287
11306
  if (trackDecisionCommand(id)?.scope === "id") return true;
11288
11307
  if (!descriptor || descriptor.disposition !== "routed") return true;
@@ -19,7 +19,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
19
19
  var PRIVATE_ENGINE_INFO = (0, _superdoc_docx_engine_collaboration_upgrade_engine.getCollaborationUpgradeEngineInfo)();
20
20
  var ENGINE_INFO = Object.freeze({
21
21
  ...PRIVATE_ENGINE_INFO,
22
- superdocVersion: "2.25.0-next.2",
22
+ superdocVersion: "2.25.0-next.4",
23
23
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
24
24
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
25
25
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -18,7 +18,7 @@ var COLLABORATION_UPGRADE_ENGINE_MINIMUM_NODE_MAJOR = 20;
18
18
  var PRIVATE_ENGINE_INFO = getCollaborationUpgradeEngineInfo$1();
19
19
  var ENGINE_INFO = Object.freeze({
20
20
  ...PRIVATE_ENGINE_INFO,
21
- superdocVersion: "2.25.0-next.2",
21
+ superdocVersion: "2.25.0-next.4",
22
22
  roomSchemaVersion: Object.freeze({ ...PRIVATE_ENGINE_INFO.roomSchemaVersion }),
23
23
  supportedBundleVersions: SUPPORTED_COLLABORATION_UPGRADE_BUNDLE_VERSIONS,
24
24
  supportedV1ReaderContractVersions: SUPPORTED_V1_READER_CONTRACT_VERSIONS
@@ -216,6 +216,8 @@ export interface CommentsListQuery {
216
216
  */
217
217
  export interface CommentDomain {
218
218
  address: CommentAddress;
219
+ /** Canonical comment id alias returned by native runtimes. */
220
+ commentId?: string;
219
221
  /** See {@link CommentInfo.externalId}. */
220
222
  externalId?: string;
221
223
  /** See {@link CommentInfo.metadata}. */
@@ -1,7 +1,7 @@
1
1
  import { BlockNodeAddress, NodeKind } from '../types/base.js';
2
2
  import { SelectionTarget } from '../types/address.js';
3
3
  import { SDFragment } from '../types/fragment.js';
4
- import { ReceiptFailure, ReceiptInsert } from '../types/receipt.js';
4
+ import { ReceiptFailure, ReceiptInsert, ReceiptSuccess } from '../types/receipt.js';
5
5
  import { StoryLocator } from '../types/story.types.js';
6
6
  /**
7
7
  * Semantic SDT subtype derived from `w:sdtPr` children.
@@ -154,11 +154,13 @@ export interface ContentControlInfo {
154
154
  /** Authoritative structural emptiness when the adapter can determine it. */
155
155
  isEmpty?: boolean;
156
156
  }
157
- export interface ContentControlMutationSuccess {
157
+ export interface ContentControlMutationSuccess extends ReceiptSuccess {
158
158
  success: true;
159
159
  appliedChangeMode?: 'direct' | 'tracked';
160
160
  contentControl: ContentControlTarget;
161
161
  updatedRef?: ContentControlTarget;
162
+ /** Identity of the block created by an adjacent-content insertion. */
163
+ createdBlockId?: string;
162
164
  affectedStories?: StoryLocator[];
163
165
  trackedChangeRefs?: ReceiptInsert[];
164
166
  }
@@ -3369,7 +3369,7 @@ export declare const OPERATION_DEFINITIONS: {
3369
3369
  };
3370
3370
  readonly 'protection.setEditingRestriction': {
3371
3371
  readonly memberPath: "protection.setEditingRestriction";
3372
- readonly description: "Enable Word-style editing restriction on the document. Only readOnly mode is supported in v1.";
3372
+ readonly description: "Author a Word readOnly, comments, trackedChanges, or forms restriction. Inspect runtimeEnforced in the returned state: V2 currently enforces readOnly; the other modes are saved for Word and are not enforced in SuperDoc.";
3373
3373
  readonly expectedResult: "Returns a ProtectionMutationResult with the updated protection state on success.";
3374
3374
  readonly requiresDocumentContext: true;
3375
3375
  readonly metadata: CommandStaticMetadata;
@@ -1,7 +1,7 @@
1
1
  import { BlockNodeAddress, InlineNodeAddress } from '../types/base.js';
2
2
  import { TextAddress } from '../types/address.js';
3
3
  import { DiscoveryOutput } from '../types/discovery.js';
4
- import { ReceiptFailure } from '../types/receipt.js';
4
+ import { ReceiptFailure, ReceiptSuccess } from '../types/receipt.js';
5
5
  /** Narrowed inline address for hyperlink targets. */
6
6
  export type HyperlinkTarget = InlineNodeAddress & {
7
7
  nodeType: 'hyperlink';
@@ -74,10 +74,17 @@ export interface HyperlinkInfo {
74
74
  properties: HyperlinkReadProperties;
75
75
  text?: string;
76
76
  }
77
- export interface HyperlinkMutationSuccess {
77
+ export interface HyperlinkMutationSuccess extends ReceiptSuccess {
78
78
  success: true;
79
79
  appliedChangeMode?: 'direct' | 'tracked';
80
80
  hyperlink: HyperlinkTarget;
81
+ /** Legacy native identifier for the mutated hyperlink, null after removal. */
82
+ hyperlinkNodeId?: string | null;
83
+ /** Package parts created or modified by the mutation. */
84
+ partsCreated?: readonly string[];
85
+ partsModified?: readonly string[];
86
+ /** Relationship identity created for an external destination, when present. */
87
+ createdRId?: string;
81
88
  }
82
89
  export interface HyperlinkMutationFailure {
83
90
  success: false;
@@ -1,5 +1,5 @@
1
1
  import { BlockNodeAddress } from '../types/index.js';
2
- import { ReceiptInsert } from '../types/receipt.js';
2
+ import { ReceiptInsert, ReceiptSuccess } from '../types/receipt.js';
3
3
  import { StoryLocator } from '../types/story.types.js';
4
4
  import { ContentControlTarget } from '../content-controls/content-controls.types.js';
5
5
  import { ImageProperties, ImageWrapType, ImageWrapSide, ImageMarginOffset, ImageSize, ImageCropInfo } from '../types/media.types.js';
@@ -186,7 +186,7 @@ export interface SetZOrderInput {
186
186
  imageId: string;
187
187
  zOrder: ImageZOrderInput;
188
188
  }
189
- export interface CreateImageSuccessResult {
189
+ export interface CreateImageSuccessResult extends ReceiptSuccess {
190
190
  success: true;
191
191
  appliedChangeMode?: 'direct' | 'tracked';
192
192
  image: ImageAddress;
@@ -206,7 +206,7 @@ export interface ImagesListResult {
206
206
  total: number;
207
207
  items: ImageSummary[];
208
208
  }
209
- export interface ImagesMutationSuccessResult {
209
+ export interface ImagesMutationSuccessResult extends ReceiptSuccess {
210
210
  success: true;
211
211
  appliedChangeMode?: 'direct' | 'tracked';
212
212
  image: ImageAddress;
@@ -132,6 +132,7 @@ export type { AnchoredMetadataApi, AnchoredMetadataAdapter } from './metadata/an
132
132
  export type { ProtectionApi, ProtectionAdapter } from './protection/protection.js';
133
133
  export * from './protection/protection.types.js';
134
134
  export type { PermissionRangesApi, PermissionRangesAdapter } from './permission-ranges/permission-ranges.js';
135
+ export { listPermissionRangeEditors, resolvePermissionRangeEditor } from './permission-ranges/permission-ranges.js';
135
136
  export type * from './permission-ranges/permission-ranges.types.js';
136
137
  export type { FootnotesApi, FootnotesAdapter } from './footnotes/footnotes.js';
137
138
  export type { ClipboardApi, ClipboardAdapter } from './clipboard/clipboard.js';
@@ -1,4 +1,4 @@
1
- import { AffectedRefRemapping, BlockNodeType, ReceiptFailure, ReceiptInsert, StoryLocator, TextAddress, TextRangeShift } from '../types/index.js';
1
+ import { AffectedRefRemapping, BlockNodeType, ReceiptFailure, ReceiptInsert, ReceiptSuccess, StoryLocator, TextAddress, TextRangeShift } from '../types/index.js';
2
2
  import { DiscoveryOutput } from '../types/discovery.js';
3
3
  export type ListItemAddress = {
4
4
  kind: 'block';
@@ -356,14 +356,14 @@ export interface ListsCaptureTemplateSuccessResult {
356
356
  template: ListTemplate;
357
357
  }
358
358
  export type ListsCaptureTemplateResult = ListsCaptureTemplateSuccessResult | ListsFailureResult;
359
- export interface ListsInsertSuccessResult {
359
+ export interface ListsInsertSuccessResult extends ReceiptSuccess {
360
360
  success: true;
361
361
  appliedChangeMode?: 'direct' | 'tracked';
362
362
  item: ListItemAddress;
363
363
  insertionPoint: TextAddress;
364
364
  trackedChangeRefs?: ReceiptInsert[];
365
365
  }
366
- export interface ListsMutateItemSuccessResult {
366
+ export interface ListsMutateItemSuccessResult extends ReceiptSuccess {
367
367
  success: true;
368
368
  appliedChangeMode?: 'direct' | 'tracked';
369
369
  item: ListItemAddress;
@@ -375,38 +375,38 @@ export interface ListsMutateItemSuccessResult {
375
375
  txId?: string;
376
376
  changed?: boolean;
377
377
  }
378
- export interface ListsCreateSuccessResult {
378
+ export interface ListsCreateSuccessResult extends ReceiptSuccess {
379
379
  success: true;
380
380
  appliedChangeMode?: 'direct' | 'tracked';
381
381
  listId: string;
382
382
  item: ListItemAddress;
383
383
  }
384
- export interface ListsJoinSuccessResult {
384
+ export interface ListsJoinSuccessResult extends ReceiptSuccess {
385
385
  success: true;
386
386
  appliedChangeMode?: 'direct' | 'tracked';
387
387
  listId: string;
388
388
  }
389
- export interface ListsSeparateSuccessResult {
389
+ export interface ListsSeparateSuccessResult extends ReceiptSuccess {
390
390
  success: true;
391
391
  appliedChangeMode?: 'direct' | 'tracked';
392
392
  listId: string;
393
393
  numId: number;
394
394
  }
395
- export interface ListsMergeSuccessResult {
395
+ export interface ListsMergeSuccessResult extends ReceiptSuccess {
396
396
  success: true;
397
397
  appliedChangeMode?: 'direct' | 'tracked';
398
398
  listId: string;
399
399
  absorbedCount: number;
400
400
  removedEmptyBlocks: number;
401
401
  }
402
- export interface ListsSplitSuccessResult {
402
+ export interface ListsSplitSuccessResult extends ReceiptSuccess {
403
403
  success: true;
404
404
  appliedChangeMode?: 'direct' | 'tracked';
405
405
  listId: string;
406
406
  numId: number;
407
407
  restartedAt: number | null;
408
408
  }
409
- export interface ListsDetachSuccessResult {
409
+ export interface ListsDetachSuccessResult extends ReceiptSuccess {
410
410
  success: true;
411
411
  appliedChangeMode?: 'direct' | 'tracked';
412
412
  paragraph: {
@@ -415,7 +415,7 @@ export interface ListsDetachSuccessResult {
415
415
  nodeId: string;
416
416
  };
417
417
  }
418
- export interface ListsConvertToTextSuccessResult {
418
+ export interface ListsConvertToTextSuccessResult extends ReceiptSuccess {
419
419
  success: true;
420
420
  appliedChangeMode?: 'direct' | 'tracked';
421
421
  paragraph: {
@@ -447,7 +447,7 @@ export type ListsMergeResult = ListsMergeSuccessResult | ListsFailureResult;
447
447
  export type ListsSplitResult = ListsSplitSuccessResult | ListsFailureResult;
448
448
  export type ListsDetachResult = ListsDetachSuccessResult | ListsFailureResult;
449
449
  export type ListsConvertToTextResult = ListsConvertToTextSuccessResult | ListsFailureResult;
450
- export interface ListsDeleteSuccessResult {
450
+ export interface ListsDeleteSuccessResult extends ReceiptSuccess {
451
451
  success: true;
452
452
  appliedChangeMode?: 'direct' | 'tracked';
453
453
  /** Number of list items removed. */
@@ -1,5 +1,13 @@
1
1
  import { MutationOptions } from '../write/write.js';
2
- import { PermissionRangesListInput, PermissionRangesListResult, PermissionRangesGetInput, PermissionRangeInfo, PermissionRangesCreateInput, PermissionRangesRemoveInput, PermissionRangesUpdatePrincipalInput, PermissionRangeMutationResult, PermissionRangeRemoveResult } from './permission-ranges.types.js';
2
+ import { PermissionRangesListInput, PermissionRangesListResult, PermissionRangesGetInput, PermissionRangeInfo, PermissionRangesCreateInput, PermissionRangesRemoveInput, PermissionRangesUpdatePrincipalInput, PermissionRangeMutationResult, PermissionRangeRemoveResult, PermissionRangeEditor, PermissionRangeEditorResolution } from './permission-ranges.types.js';
3
+ /**
4
+ * Resolve a host ID or imported Word email against an explicitly supplied roster.
5
+ * Word receives the email when available; opaque IDs remain host-specific.
6
+ * Duplicate IDs/emails are ambiguous. This does not authenticate a user.
7
+ */
8
+ export declare function resolvePermissionRangeEditor(editors: readonly PermissionRangeEditor[], id: string): PermissionRangeEditorResolution;
9
+ /** Enumerate the host roster for an editor picker, including ambiguous entries. */
10
+ export declare function listPermissionRangeEditors(editors: readonly PermissionRangeEditor[]): PermissionRangeEditorResolution[];
3
11
  export interface PermissionRangesApi {
4
12
  list(input?: PermissionRangesListInput): PermissionRangesListResult;
5
13
  get(input: PermissionRangesGetInput): PermissionRangeInfo;
@@ -9,6 +9,23 @@ export type PermissionRangePrincipal = {
9
9
  kind: 'editor';
10
10
  id: string;
11
11
  };
12
+ /** Trusted host roster entry. Names are display labels, never permission identities. */
13
+ export interface PermissionRangeEditor {
14
+ id?: string | null;
15
+ email?: string | null;
16
+ name?: string | null;
17
+ }
18
+ export type PermissionRangeEditorResolution = {
19
+ status: 'resolved';
20
+ id: string;
21
+ editor: PermissionRangeEditor;
22
+ principal: Extract<PermissionRangePrincipal, {
23
+ kind: 'editor';
24
+ }>;
25
+ } | {
26
+ status: 'unknown' | 'ambiguous';
27
+ id: string;
28
+ };
12
29
  export type PermissionRangeKind = 'inline' | 'block';
13
30
  export interface PermissionRangeInfo {
14
31
  id: string;
@@ -33,8 +33,8 @@ export declare const DEFAULT_PROTECTION_STATE: DocumentProtectionState;
33
33
  export type ProtectionGetInput = Record<string, never> | undefined;
34
34
  /** Input for `protection.setEditingRestriction`. */
35
35
  export interface SetEditingRestrictionInput {
36
- /** Only `'readOnly'` is accepted in v1. */
37
- mode: 'readOnly';
36
+ /** Word restriction to author. Inspect `runtimeEnforced` before relying on engine enforcement. */
37
+ mode: Exclude<EditingRestrictionMode, 'none'>;
38
38
  /** Whether to restrict formatting changes. Defaults to false. */
39
39
  formattingRestricted?: boolean;
40
40
  }
@@ -8,6 +8,9 @@ export interface MutationReceiptBridgeContext {
8
8
  }
9
9
  interface CanonicalSuccessMetadata {
10
10
  appliedChangeMode?: ReceiptSuccess['appliedChangeMode'];
11
+ changed?: ReceiptSuccess['changed'];
12
+ trackedChangeRefs?: ReceiptSuccess['trackedChangeRefs'];
13
+ trackedChangeCount?: ReceiptSuccess['trackedChangeCount'];
11
14
  id?: ReceiptSuccess['id'];
12
15
  inserted?: ReceiptSuccess['inserted'];
13
16
  updated?: ReceiptSuccess['updated'];
@@ -144,7 +144,7 @@ export interface BlocksSplitInput {
144
144
  /** Include deleted tracked text in the offset ruler. Defaults to `visible`. */
145
145
  coordinateSpace?: 'visible' | 'tracked';
146
146
  }
147
- export interface BlocksSplitSuccessResult {
147
+ export interface BlocksSplitSuccessResult extends Omit<ReceiptSuccess, 'inserted'> {
148
148
  success: true;
149
149
  appliedChangeMode?: ReceiptSuccess['appliedChangeMode'];
150
150
  /** Address of the new paragraph created by the split (the tail). */
@@ -173,7 +173,7 @@ export interface BlocksMergeInput {
173
173
  /** Paragraph immediately after `first` in the same story. */
174
174
  second: BlockNodeAddress;
175
175
  }
176
- export interface BlocksMergeSuccessResult {
176
+ export interface BlocksMergeSuccessResult extends Omit<ReceiptSuccess, 'removed'> {
177
177
  success: true;
178
178
  appliedChangeMode?: ReceiptSuccess['appliedChangeMode'];
179
179
  /** Address of the paragraph that was removed (the second paragraph). */
@@ -5,7 +5,7 @@ import { InsertStylePolicy, StylePolicy } from './style-policy.types.js';
5
5
  import { InlineRunPatch } from '../format/inline-run-patch.js';
6
6
  import { SDFragment } from './fragment.js';
7
7
  import { Placement, NestingPolicy } from './placement.js';
8
- import { AffectedRef } from './receipt.js';
8
+ import { AffectedRef, ReceiptSuccess } from './receipt.js';
9
9
  import { ChangeMode } from '../write/write.js';
10
10
  import { StoryLocator } from './story.types.js';
11
11
  export type SelectWhere = {
@@ -241,7 +241,7 @@ export type StepOutcome = {
241
241
  trackedChangeIds?: string[];
242
242
  data: StepOutcomeData;
243
243
  };
244
- export type PlanReceipt = {
244
+ export type PlanReceipt = ReceiptSuccess & {
245
245
  success: true;
246
246
  /** Effective mode when every committed step used the same mode. */
247
247
  appliedChangeMode?: ChangeMode;
@@ -110,6 +110,12 @@ export interface ReceiptEffects {
110
110
  }
111
111
  export type ReceiptSuccess = {
112
112
  success: true;
113
+ /** Whether a successful request changed the document; false represents a no-op commit. */
114
+ changed?: boolean;
115
+ /** Tracked changes authored by this mutation. */
116
+ trackedChangeRefs?: ReceiptInsert[];
117
+ /** Number of tracked changes authored by this mutation. */
118
+ trackedChangeCount?: number;
113
119
  /**
114
120
  * Mode in which this call's document content was committed. An edit folded
115
121
  * into the author's existing insertion is tracked; auxiliary style and
@@ -202,6 +208,12 @@ export type TextMutationResolution = {
202
208
  };
203
209
  export type TextMutationReceipt = (ReceiptSuccess & {
204
210
  resolution: TextMutationResolution;
211
+ /** Per-edit tracked-change results for atomic multi-edit mutations. */
212
+ trackedChangeOutcomes?: {
213
+ editIndex: number;
214
+ trackedChangeCount: number;
215
+ trackedChangeRefs: ReceiptInsert[];
216
+ }[];
205
217
  }) | (ReceiptFailureResult & {
206
218
  resolution: TextMutationResolution;
207
219
  });
@@ -32,6 +32,9 @@ export interface SDMutationReceipt {
32
32
  before: string;
33
33
  after: string;
34
34
  };
35
+ changed?: ReceiptSuccess['changed'];
36
+ trackedChangeRefs?: ReceiptSuccess['trackedChangeRefs'];
37
+ trackedChangeCount?: ReceiptSuccess['trackedChangeCount'];
35
38
  id?: ReceiptSuccess['id'];
36
39
  inserted?: ReceiptSuccess['inserted'];
37
40
  updated?: ReceiptSuccess['updated'];
@@ -351,9 +351,17 @@ export interface TrackChangeStructuralDescriptor {
351
351
  export type TrackChangeTarget = {
352
352
  kind: 'text';
353
353
  address: TrackedChangeAddress;
354
+ /** Resolved text geometry when available. */
355
+ segments?: TextTarget['segments'];
356
+ /** Story containing the resolved geometry. */
357
+ story?: TextTarget['story'];
354
358
  } | {
355
359
  kind: 'replacement';
356
360
  address: TrackedChangeAddress;
361
+ /** Resolved text geometry when available. */
362
+ segments?: TextTarget['segments'];
363
+ /** Story containing the resolved geometry. */
364
+ story?: TextTarget['story'];
357
365
  } | {
358
366
  kind: 'formatting';
359
367
  address: TrackedChangeAddress;
@@ -5,8 +5,8 @@
5
5
  * every retained dependency that required the checkpoint; consumers reject
6
6
  * empty, duplicate, or unknown lists instead of trusting a generic boolean.
7
7
  */
8
- export type PageCheckpointDependencyClass = 'multiple-sections' | 'furniture-page-tokens' | 'non-balanceable-multi-column-sections' | 'body-anchored-objects' | 'non-flowing-page-relative-body-anchors' | 'footnotes' | 'page-references' | 'cross-references' | 'keep-constraints' | 'tables' | 'furniture-anchored-objects';
9
- export declare const PAGE_CHECKPOINT_DEPENDENCY_CLASSES: readonly ["multiple-sections", "furniture-page-tokens", "non-balanceable-multi-column-sections", "body-anchored-objects", "non-flowing-page-relative-body-anchors", "footnotes", "page-references", "cross-references", "keep-constraints", "tables", "furniture-anchored-objects"];
8
+ export type PageCheckpointDependencyClass = 'multiple-sections' | 'furniture-page-tokens' | 'body-page-number-tokens' | 'non-balanceable-multi-column-sections' | 'body-anchored-objects' | 'non-flowing-page-relative-body-anchors' | 'footnotes' | 'page-references' | 'cross-references' | 'keep-constraints' | 'tables' | 'furniture-anchored-objects';
9
+ export declare const PAGE_CHECKPOINT_DEPENDENCY_CLASSES: readonly ["multiple-sections", "furniture-page-tokens", "body-page-number-tokens", "non-balanceable-multi-column-sections", "body-anchored-objects", "non-flowing-page-relative-body-anchors", "footnotes", "page-references", "cross-references", "keep-constraints", "tables", "furniture-anchored-objects"];
10
10
  /**
11
11
  * Exact retained-generation proof for page/margin-relative body anchors that
12
12
  * cannot influence paragraph flow (`wrap=None`). The host builds this once
@@ -2899,6 +2899,8 @@ export type LayoutBlockResumeCheckpoint = {
2899
2899
  columns: ColumnLayout;
2900
2900
  }[];
2901
2901
  activeConstraintIndex: number;
2902
+ /** Exact active configuration, including single-column state omitted from Page.columns. */
2903
+ activeColumns?: ColumnLayout;
2902
2904
  footnoteDemandThisPage: number;
2903
2905
  footnoteRefsThisPage: number;
2904
2906
  footnoteAnchorsThisPage: readonly {
@@ -2935,6 +2937,8 @@ export type Layout = {
2935
2937
  layoutEpoch?: number;
2936
2938
  /** Exact paragraph-boundary resume sidecar; never inferred from painted geometry. */
2937
2939
  blockResumeCheckpoints?: ReadonlyMap<BlockId, LayoutBlockResumeCheckpoint>;
2940
+ /** Engine-authored column state at physical page creation, including count=1 configurations. */
2941
+ pageStartColumns?: ReadonlyMap<number, ColumnLayout>;
2938
2942
  };
2939
2943
  export type WrapTextMode = 'bothSides' | 'left' | 'right' | 'largest';
2940
2944
  export type WrapExclusion = {
@@ -44,36 +44,15 @@ export interface FontMetricsCacheConfig {
44
44
  */
45
45
  export declare class FontMetricsCache {
46
46
  private cache;
47
- private canvas;
48
47
  private ctx;
48
+ private fontGeneration;
49
49
  /**
50
50
  * Creates a new FontMetricsCache instance.
51
51
  * Initializes the canvas context for measurements.
52
52
  */
53
53
  constructor();
54
- /**
55
- * Initializes the canvas and context for font measurements.
56
- *
57
- * Creates an offscreen 1x1 canvas with 2D rendering context optimized for
58
- * text measurement. The canvas is never attached to the DOM and is purely
59
- * used for the canvas.measureText() API.
60
- *
61
- * Performance considerations:
62
- * - Canvas is created once and reused for all measurements
63
- * - Size is minimal (1x1) as we only need measureText(), not rendering
64
- * - willReadFrequently hint optimizes for frequent measureText() calls
65
- *
66
- * Failure modes:
67
- * - Not in browser environment (SSR): Sets ctx to null, cache will be disabled
68
- * - Canvas creation fails: Catches error, sets ctx to null, measurements fall back to defaults
69
- *
70
- * Side effects:
71
- * - Creates this.canvas and this.ctx properties
72
- * - On failure, cache becomes read-only (getMetrics returns undefined for unmeasured fonts)
73
- *
74
- * @private
75
- */
76
54
  private initializeCanvas;
55
+ private ensureFontGeneration;
77
56
  /**
78
57
  * Pre-warms the cache by measuring all characters for the specified fonts.
79
58
  *
@@ -378,13 +378,14 @@ export type IncrementalPaginationProof = IncrementalPaginationProofBase & ({
378
378
  * mid-section checkpoint cannot seed. False is admissible only
379
379
  * together with `balanceableSectionsBoundaryBlockId`, the last
380
380
  * page-bearing block at or before the final balanceable section end.
381
- * The bridge requires a document-start replay, includes that section
382
- * finalizer, and refuses convergence until a stable page strictly
383
- * after the retained boundary. Anything else takes the canonical full
384
- * layout.
381
+ * The bridge replays from document start unless the separately proved
382
+ * unchanged balanced prefix precedes a complete single-column seed
383
+ * strictly after the boundary. Convergence remains fenced after it.
385
384
  */
386
385
  multiColumnSectionsProvedNonBalanceable: boolean;
387
386
  balanceableSectionsBoundaryBlockId?: string;
387
+ /** The unchanged balanced sections precede every dirty owner; the bridge re-verifies the seeded checkpoint. */
388
+ balanceableSectionsRetainedPrefix?: true;
388
389
  /** Last vertically aligned section page; validated before reuse. */
389
390
  vAlignSectionsBoundaryBlockId?: string;
390
391
  /** Replay page zero through the aligned boundary before convergence. */
@@ -617,6 +618,12 @@ export declare function __test_only_splicedCheckpointStats(map: ReadonlyMap<stri
617
618
  sourceCount: number;
618
619
  maximumTransformTreeDepth: number;
619
620
  } | null;
621
+ export type LayoutPageGeometry = Pick<Page, 'size' | 'margins' | 'sectionIndex'>;
622
+ /** Internal live identity readback; every fragment remains visible to ownership validation. */
623
+ export declare function readLayoutPageFragmentBlockIds(pages: Page[], pageIndex: number): IterableIterator<string>;
624
+ /** Read canonical page boxes without materializing retained PM or fragment transforms. */
625
+ export declare function readLayoutPageGeometry(pages: Page[], pageIndex: number): LayoutPageGeometry;
626
+ export declare function __test_only_pageSequenceMaterializationCount(pages: Page[]): number;
620
627
  export declare function __test_only_lazyPageTransformStats(pages: Page[]): {
621
628
  segmentCount: number;
622
629
  maximumLedgerCount: number;
@@ -12,9 +12,9 @@ export { findWordBoundaries, findParagraphBoundaries } from './text-boundaries.j
12
12
  export type { BoundaryRange } from './text-boundaries.js';
13
13
  export { buildSectionAwareHeaderFooterLayoutKey, buildSectionContentWidth, buildEffectiveHeaderFooterRefsBySection, collectReferencedHeaderFooterRIds, buildSectionAwareHeaderFooterMeasurementGroups, } from './sectionAwareHeaderFooter.js';
14
14
  export type { HeaderFooterSectionKind, HeaderFooterRefs, SectionAwareHeaderFooterMeasurementGroup, } from './sectionAwareHeaderFooter.js';
15
- export { clearIncrementalModuleState, incrementalLayout, measureCache, normalizeMargin } from './incrementalLayout.js';
15
+ export { clearIncrementalModuleState, incrementalLayout, measureCache, normalizeMargin, readLayoutPageGeometry, readLayoutPageFragmentBlockIds, } from './incrementalLayout.js';
16
16
  export { hashMeasureContent } from './cache.js';
17
- export type { HeaderFooterLayoutResult, HeaderFooterGeometrySeed, IncrementalLayoutBridgeTiming, IncrementalLayoutResult, IncrementalLayoutExecutionControl, IncrementalLayoutContinuation, IncrementalMeasureReuseProof, IncrementalLayoutReuseOptions, IncrementalLayoutReuseSummary, IncrementalSectionPageNumberTransform, IncrementalLayoutTailAdoption, IncrementalLayoutTailDisposition, IncrementalPaginationProof, LayoutPositionTransform, FootnoteReserveSeed, } from './incrementalLayout.js';
17
+ export type { HeaderFooterLayoutResult, HeaderFooterGeometrySeed, IncrementalLayoutBridgeTiming, IncrementalLayoutResult, IncrementalLayoutExecutionControl, IncrementalLayoutContinuation, IncrementalMeasureReuseProof, IncrementalLayoutReuseOptions, IncrementalLayoutReuseSummary, IncrementalSectionPageNumberTransform, IncrementalLayoutTailAdoption, IncrementalLayoutTailDisposition, IncrementalPaginationProof, LayoutPositionTransform, LayoutPageGeometry, FootnoteReserveSeed, } from './incrementalLayout.js';
18
18
  export { collectFootnoteLedgers, getPreferredReserveCandidates, getPreferredReserveTrialTargets, isMandatoryOnlyFootnotePage, scoreFootnoteWindow, summarizeFootnoteWindow, } from './footnote-scorer.js';
19
19
  export type { FootnotePreferredReserveCandidate, FootnoteWindowScoreInput, FootnoteWindowScoreReason, FootnoteWindowScoreResult, FootnoteWindowStats, } from './footnote-scorer.js';
20
20
  export { computeDisplayPageNumber } from '../../layout-engine/src/index.js';
@@ -0,0 +1,12 @@
1
+ /** Native Canvas2D allocation shared by the secondary layout measurers. */
2
+ export type LayoutMeasurementContext = CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
3
+ type UnavailablePolicy = 'require-native' | 'headless-approximation';
4
+ export declare function getLayoutMeasurementFontGeneration(): number;
5
+ /** Invalidates secondary caches when a face changes behind an unchanged CSS font string. */
6
+ export declare function invalidateLayoutMeasurementFonts(): void;
7
+ export declare function createLayoutMeasurementContext(options?: {
8
+ context?: LayoutMeasurementContext;
9
+ ownerDocument?: Document;
10
+ unavailable?: UnavailablePolicy;
11
+ }): LayoutMeasurementContext | null;
12
+ export {};
@@ -18,6 +18,6 @@ export declare function cloneLiveCrossReferenceFieldBlocks<T extends FlowBlock>(
18
18
  * graph. This happens before measurement, so changed result text participates
19
19
  * in line wrapping and pagination without creating a second document mutation.
20
20
  */
21
- export declare function resolveLiveCrossReferences(bodyBlocks: FlowBlock[]): void;
21
+ export declare function resolveLiveCrossReferences(bodyBlocks: FlowBlock[]): boolean;
22
22
  /** Build the page-aware STYLEREF resolver used by repeated headers/footers. */
23
23
  export declare function buildPageStyleReferenceResolver(bodyBlocks: readonly FlowBlock[], layout: Layout): PageStyleReferenceResolver;
@@ -133,3 +133,7 @@ export type DomPainterHandle = {
133
133
  * `mode-ownership.test.ts` battery pins the surface deleted.
134
134
  */
135
135
  export declare const createDomPainter: (options: DomPainterOptions) => DomPainterHandle;
136
+ export { resolveRunTypographyStyles, resolveRunDecorationStyles } from './runs/text-style-facts.js';
137
+ export { resolveTrackedChangeDecorationFacts, getTrackedChangeLayers, resolveTrackedChangesConfig, } from './runs/tracked-changes.js';
138
+ export { buildLinkRenderData } from './runs/links.js';
139
+ export { INLINE_TRACKED_CHANGE_DEFAULTS } from './styles.js';