@harbour-enterprises/superdoc 1.17.0-next.11 → 1.17.0-next.13

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 (33) hide show
  1. package/dist/chunks/{SuperConverter-D0cZ7DBR.es.js → SuperConverter-0JaBYpRa.es.js} +1 -1
  2. package/dist/chunks/{SuperConverter-DOQaFkjd.cjs → SuperConverter-BgHHB-Z2.cjs} +1 -1
  3. package/dist/chunks/{src-DQKyE7kq.cjs → src-ByCDwKn7.cjs} +458 -129
  4. package/dist/chunks/{src-bsYwK29H.es.js → src-C52EYA_H.es.js} +452 -130
  5. package/dist/super-editor/converter.cjs +1 -1
  6. package/dist/super-editor/converter.es.js +1 -1
  7. package/dist/super-editor/src/document-api-adapters/assemble-adapters.d.ts.map +1 -1
  8. package/dist/super-editor/src/document-api-adapters/capabilities-adapter.d.ts.map +1 -1
  9. package/dist/super-editor/src/document-api-adapters/errors.d.ts +1 -1
  10. package/dist/super-editor/src/document-api-adapters/errors.d.ts.map +1 -1
  11. package/dist/super-editor/src/document-api-adapters/helpers/node-address-resolver.d.ts +12 -0
  12. package/dist/super-editor/src/document-api-adapters/helpers/node-address-resolver.d.ts.map +1 -1
  13. package/dist/super-editor/src/document-api-adapters/index.d.ts.map +1 -1
  14. package/dist/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.d.ts +4 -0
  15. package/dist/super-editor/src/document-api-adapters/plan-engine/blocks-wrappers.d.ts.map +1 -0
  16. package/dist/super-editor/src/document-api-adapters/plan-engine/compiler.d.ts +14 -0
  17. package/dist/super-editor/src/document-api-adapters/plan-engine/compiler.d.ts.map +1 -1
  18. package/dist/super-editor/src/document-api-adapters/plan-engine/create-insertion.d.ts +16 -0
  19. package/dist/super-editor/src/document-api-adapters/plan-engine/create-insertion.d.ts.map +1 -0
  20. package/dist/super-editor/src/document-api-adapters/plan-engine/create-wrappers.d.ts.map +1 -1
  21. package/dist/super-editor/src/document-api-adapters/plan-engine/executor.d.ts.map +1 -1
  22. package/dist/super-editor/src/document-api-adapters/plan-engine/plan-wrappers.d.ts.map +1 -1
  23. package/dist/super-editor/src/document-api-adapters/plan-engine/preview.d.ts.map +1 -1
  24. package/dist/super-editor/src/document-api-adapters/plan-engine/query-match-adapter.d.ts.map +1 -1
  25. package/dist/super-editor/src/document-api-adapters/plan-engine/revision-tracker.d.ts.map +1 -1
  26. package/dist/super-editor/src/document-api-adapters/plan-engine/style-resolver.d.ts.map +1 -1
  27. package/dist/super-editor.cjs +2 -2
  28. package/dist/super-editor.es.js +2 -2
  29. package/dist/superdoc.cjs +3 -3
  30. package/dist/superdoc.es.js +3 -3
  31. package/dist/superdoc.umd.js +459 -137
  32. package/dist/superdoc.umd.js.map +1 -1
  33. package/package.json +1 -1
@@ -2477,7 +2477,7 @@
2477
2477
  if (last >= 0 && child.isText && child.sameMarkup(target[last])) target[last] = child.withText(target[last].text + child.text);
2478
2478
  else target.push(child);
2479
2479
  }
2480
- function addRange$1($start, $end, depth, target) {
2480
+ function addRange($start, $end, depth, target) {
2481
2481
  let node$1 = ($end || $start).node(depth);
2482
2482
  let startIndex = 0, endIndex = $end ? $end.index(depth) : node$1.childCount;
2483
2483
  if ($start) {
@@ -2499,23 +2499,23 @@
2499
2499
  let openStart = $from.depth > depth && joinable$1($from, $start, depth + 1);
2500
2500
  let openEnd = $to.depth > depth && joinable$1($end, $to, depth + 1);
2501
2501
  let content$2 = [];
2502
- addRange$1(null, $from, depth, content$2);
2502
+ addRange(null, $from, depth, content$2);
2503
2503
  if (openStart && openEnd && $start.index(depth) == $end.index(depth)) {
2504
2504
  checkJoin(openStart, openEnd);
2505
2505
  addNode(close(openStart, replaceThreeWay($from, $start, $end, $to, depth + 1)), content$2);
2506
2506
  } else {
2507
2507
  if (openStart) addNode(close(openStart, replaceTwoWay($from, $start, depth + 1)), content$2);
2508
- addRange$1($start, $end, depth, content$2);
2508
+ addRange($start, $end, depth, content$2);
2509
2509
  if (openEnd) addNode(close(openEnd, replaceTwoWay($end, $to, depth + 1)), content$2);
2510
2510
  }
2511
- addRange$1($to, null, depth, content$2);
2511
+ addRange($to, null, depth, content$2);
2512
2512
  return new Fragment$1(content$2);
2513
2513
  }
2514
2514
  function replaceTwoWay($from, $to, depth) {
2515
2515
  let content$2 = [];
2516
- addRange$1(null, $from, depth, content$2);
2516
+ addRange(null, $from, depth, content$2);
2517
2517
  if ($from.depth > depth) addNode(close(joinable$1($from, $to, depth + 1), replaceTwoWay($from, $to, depth + 1)), content$2);
2518
- addRange$1($to, null, depth, content$2);
2518
+ addRange($to, null, depth, content$2);
2519
2519
  return new Fragment$1(content$2);
2520
2520
  }
2521
2521
  function prepareSliceForReplace(slice, $along) {
@@ -33326,7 +33326,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
33326
33326
  var DEFAULT_ENDPOINT = "https://ingest.superdoc.dev/v1/collect";
33327
33327
  function getSuperdocVersion() {
33328
33328
  try {
33329
- return "1.17.0-next.11";
33329
+ return "1.17.0-next.13";
33330
33330
  } catch {
33331
33331
  return "unknown";
33332
33332
  }
@@ -36378,7 +36378,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36378
36378
  static getStoredSuperdocVersion(docx) {
36379
36379
  return SuperConverter.getStoredCustomProperty(docx, "SuperdocVersion");
36380
36380
  }
36381
- static setStoredSuperdocVersion(docx = this.convertedXml, version$2 = "1.17.0-next.11") {
36381
+ static setStoredSuperdocVersion(docx = this.convertedXml, version$2 = "1.17.0-next.13") {
36382
36382
  return SuperConverter.setStoredCustomProperty(docx, "SuperdocVersion", version$2, false);
36383
36383
  }
36384
36384
  static generateWordTimestamp() {
@@ -65760,7 +65760,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
65760
65760
  return false;
65761
65761
  }
65762
65762
  };
65763
- var summaryVersion = "1.17.0-next.11";
65763
+ var summaryVersion = "1.17.0-next.13";
65764
65764
  var nodeKeys = [
65765
65765
  "group",
65766
65766
  "content",
@@ -66138,6 +66138,13 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
66138
66138
  "image",
66139
66139
  "sdt"
66140
66140
  ];
66141
+ const DELETABLE_BLOCK_NODE_TYPES = [
66142
+ "paragraph",
66143
+ "heading",
66144
+ "listItem",
66145
+ "table",
66146
+ "sdt"
66147
+ ];
66141
66148
  const INLINE_NODE_TYPES = [
66142
66149
  "run",
66143
66150
  "bookmark",
@@ -66225,6 +66232,9 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
66225
66232
  "TARGET_MOVED",
66226
66233
  "PLAN_CONFLICT_OVERLAP",
66227
66234
  "INVALID_STEP_COMBINATION",
66235
+ "REVISION_CHANGED_SINCE_COMPILE",
66236
+ "INVALID_INSERTION_CONTEXT",
66237
+ "DOCUMENT_IDENTITY_CONFLICT",
66228
66238
  "CAPABILITY_UNAVAILABLE"
66229
66239
  ];
66230
66240
  var T_QUERY_MATCH = [
@@ -66326,6 +66336,27 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
66326
66336
  referenceDocPath: "delete.mdx",
66327
66337
  referenceGroup: "core"
66328
66338
  },
66339
+ "blocks.delete": {
66340
+ memberPath: "blocks.delete",
66341
+ description: "Delete an entire block node (paragraph, heading, list item, table, image, or sdt) deterministically.",
66342
+ requiresDocumentContext: true,
66343
+ metadata: mutationOperation({
66344
+ idempotency: "conditional",
66345
+ supportsDryRun: true,
66346
+ supportsTrackedMode: false,
66347
+ possibleFailureCodes: NONE_FAILURES,
66348
+ throws: [
66349
+ "TARGET_NOT_FOUND",
66350
+ "AMBIGUOUS_TARGET",
66351
+ "CAPABILITY_UNAVAILABLE",
66352
+ "INVALID_TARGET",
66353
+ "INVALID_INPUT",
66354
+ "INTERNAL_ERROR"
66355
+ ]
66356
+ }),
66357
+ referenceDocPath: "blocks/delete.mdx",
66358
+ referenceGroup: "blocks"
66359
+ },
66329
66360
  "format.apply": {
66330
66361
  memberPath: "format.apply",
66331
66362
  description: "Apply explicit inline style changes (bold, italic, underline, strike) to the target range using boolean patch semantics.",
@@ -66900,6 +66931,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
66900
66931
  }
66901
66932
  var nodeTypeValues = NODE_TYPES;
66902
66933
  var blockNodeTypeValues = BLOCK_NODE_TYPES;
66934
+ var deletableBlockNodeTypeValues = DELETABLE_BLOCK_NODE_TYPES;
66903
66935
  var inlineNodeTypeValues = INLINE_NODE_TYPES;
66904
66936
  objectSchema({
66905
66937
  start: { type: "integer" },
@@ -66936,6 +66968,14 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
66936
66968
  "kind",
66937
66969
  "nodeType",
66938
66970
  "nodeId"
66971
+ ]), objectSchema({
66972
+ kind: { const: "block" },
66973
+ nodeType: { enum: [...deletableBlockNodeTypeValues] },
66974
+ nodeId: { type: "string" }
66975
+ }, [
66976
+ "kind",
66977
+ "nodeType",
66978
+ "nodeId"
66939
66979
  ]), objectSchema({
66940
66980
  kind: { const: "block" },
66941
66981
  nodeType: { const: "paragraph" },
@@ -67087,6 +67127,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
67087
67127
  var textAddressSchema = ref$1("TextAddress");
67088
67128
  var textTargetSchema = ref$1("TextTarget");
67089
67129
  var blockNodeAddressSchema = ref$1("BlockNodeAddress");
67130
+ var deletableBlockNodeAddressSchema = ref$1("DeletableBlockNodeAddress");
67090
67131
  var paragraphAddressSchema = ref$1("ParagraphAddress");
67091
67132
  var headingAddressSchema = ref$1("HeadingAddress");
67092
67133
  var listItemAddressSchema = ref$1("ListItemAddress");
@@ -67457,6 +67498,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
67457
67498
  }, ["address", "type"]));
67458
67499
  var capabilityReasonsSchema = arraySchema({ enum: [
67459
67500
  "COMMAND_UNAVAILABLE",
67501
+ "HELPER_UNAVAILABLE",
67460
67502
  "OPERATION_UNAVAILABLE",
67461
67503
  "TRACKED_MODE_UNAVAILABLE",
67462
67504
  "DRY_RUN_UNAVAILABLE",
@@ -67546,7 +67588,13 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
67546
67588
  }, ["target", "value"]), textMutationResultSchemaFor("format.color"), textMutationFailureSchemaFor("format.color"), objectSchema({
67547
67589
  target: textAddressSchema,
67548
67590
  alignment: { oneOf: [{ enum: [...ALIGNMENTS] }, { type: "null" }] }
67549
- }, ["target", "alignment"]), textMutationResultSchemaFor("format.align"), textMutationFailureSchemaFor("format.align"), objectSchema({
67591
+ }, ["target", "alignment"]), textMutationResultSchemaFor("format.align"), textMutationFailureSchemaFor("format.align"), objectSchema({ target: deletableBlockNodeAddressSchema }, ["target"]), objectSchema({
67592
+ success: { const: true },
67593
+ deleted: deletableBlockNodeAddressSchema
67594
+ }, ["success", "deleted"]), objectSchema({
67595
+ success: { const: true },
67596
+ deleted: deletableBlockNodeAddressSchema
67597
+ }, ["success", "deleted"]), preApplyFailureResultSchemaFor("blocks.delete"), objectSchema({
67550
67598
  at: { oneOf: [
67551
67599
  objectSchema({ kind: { const: "documentStart" } }, ["kind"]),
67552
67600
  objectSchema({ kind: { const: "documentEnd" } }, ["kind"]),
@@ -67724,6 +67772,11 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
67724
67772
  description: "Primary read and write operations.",
67725
67773
  pagePath: "core/index.mdx"
67726
67774
  },
67775
+ blocks: {
67776
+ title: "Blocks",
67777
+ description: "Block-level structural operations.",
67778
+ pagePath: "blocks/index.mdx"
67779
+ },
67727
67780
  capabilities: {
67728
67781
  title: "Capabilities",
67729
67782
  description: "Runtime support discovery for capability-aware branching.",
@@ -67772,6 +67825,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
67772
67825
  }));
67773
67826
  const CAPABILITY_REASON_CODES = [
67774
67827
  "COMMAND_UNAVAILABLE",
67828
+ "HELPER_UNAVAILABLE",
67775
67829
  "OPERATION_UNAVAILABLE",
67776
67830
  "TRACKED_MODE_UNAVAILABLE",
67777
67831
  "DRY_RUN_UNAVAILABLE",
@@ -68069,6 +68123,27 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68069
68123
  validateCreateLocation(normalized.at, "create.heading");
68070
68124
  return adapter.heading(normalized, normalizeMutationOptions(options$1));
68071
68125
  }
68126
+ var SUPPORTED_DELETE_NODE_TYPES = new Set(DELETABLE_BLOCK_NODE_TYPES);
68127
+ var REJECTED_DELETE_NODE_TYPES = new Set(["tableRow", "tableCell"]);
68128
+ function validateBlocksDeleteInput(input$1) {
68129
+ if (!input$1 || typeof input$1 !== "object") throw new DocumentApiValidationError("INVALID_INPUT", "blocks.delete requires an input object.", { fields: ["input"] });
68130
+ if (!input$1.target) throw new DocumentApiValidationError("INVALID_INPUT", "blocks.delete requires a target.", { fields: ["target"] });
68131
+ if (input$1.target.kind !== "block") throw new DocumentApiValidationError("INVALID_INPUT", "blocks.delete target must have kind \"block\".", { fields: ["target.kind"] });
68132
+ if (!input$1.target.nodeId || typeof input$1.target.nodeId !== "string") throw new DocumentApiValidationError("INVALID_INPUT", "blocks.delete target requires a nodeId string.", { fields: ["target.nodeId"] });
68133
+ const { nodeType } = input$1.target;
68134
+ if (REJECTED_DELETE_NODE_TYPES.has(nodeType)) throw new DocumentApiValidationError("INVALID_TARGET", `blocks.delete does not support "${nodeType}" targets. Table row/column operations are out of scope.`, {
68135
+ fields: ["target.nodeType"],
68136
+ nodeType
68137
+ });
68138
+ if (!SUPPORTED_DELETE_NODE_TYPES.has(nodeType)) throw new DocumentApiValidationError("INVALID_TARGET", `blocks.delete does not support "${nodeType}" targets.`, {
68139
+ fields: ["target.nodeType"],
68140
+ nodeType
68141
+ });
68142
+ }
68143
+ function executeBlocksDelete(adapter, input$1, options$1) {
68144
+ validateBlocksDeleteInput(input$1);
68145
+ return adapter.delete(input$1, normalizeMutationOptions(options$1));
68146
+ }
68072
68147
  function executeTrackChangesList(adapter, input$1) {
68073
68148
  return adapter.list(input$1);
68074
68149
  }
@@ -68112,6 +68187,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68112
68187
  insert: (input$1, options$1) => api.insert(input$1, options$1),
68113
68188
  replace: (input$1, options$1) => api.replace(input$1, options$1),
68114
68189
  delete: (input$1, options$1) => api.delete(input$1, options$1),
68190
+ "blocks.delete": (input$1, options$1) => api.blocks.delete(input$1, options$1),
68115
68191
  "format.apply": (input$1, options$1) => api.format.apply(input$1, options$1),
68116
68192
  "format.fontSize": (input$1, options$1) => api.format.fontSize(input$1, options$1),
68117
68193
  "format.fontFamily": (input$1, options$1) => api.format.fontFamily(input$1, options$1),
@@ -68237,6 +68313,9 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68237
68313
  return executeTrackChangesDecide(adapters.trackChanges, input$1, options$1);
68238
68314
  }
68239
68315
  },
68316
+ blocks: { delete(input$1, options$1) {
68317
+ return executeBlocksDelete(adapters.blocks, input$1, options$1);
68318
+ } },
68240
68319
  create: {
68241
68320
  paragraph(input$1, options$1) {
68242
68321
  return executeCreateParagraph(adapters.create, input$1, options$1);
@@ -68321,6 +68400,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68321
68400
  "lists.outdent": ["setTextSelection", "decreaseListIndent"],
68322
68401
  "lists.restart": ["setTextSelection", "restartNumbering"],
68323
68402
  "lists.exit": ["exitListItemAt"],
68403
+ "blocks.delete": ["deleteBlockNodeById"],
68324
68404
  "comments.create": [
68325
68405
  "addComment",
68326
68406
  "setTextSelection",
@@ -68349,6 +68429,12 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68349
68429
  if (!required || required.length === 0) return true;
68350
68430
  return required.every((command$1) => hasCommand(editor, command$1));
68351
68431
  }
68432
+ var REQUIRED_HELPERS = { "blocks.delete": (editor) => typeof editor.helpers?.blockNode?.getBlockNodeById === "function" };
68433
+ function hasRequiredHelpers(editor, operationId) {
68434
+ const check = REQUIRED_HELPERS[operationId];
68435
+ if (!check) return true;
68436
+ return check(editor);
68437
+ }
68352
68438
  function hasMarkCapability(editor, markName) {
68353
68439
  return Boolean(editor.schema?.marks?.[markName]);
68354
68440
  }
@@ -68394,7 +68480,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68394
68480
  function isOperationAvailable(editor, operationId) {
68395
68481
  if (operationId === "format.apply") return MARK_KEYS.some((key$1) => hasMarkCapability(editor, STYLE_MARK_SCHEMA_NAMES[key$1] ?? key$1));
68396
68482
  if (INLINE_FORMAT_OPERATIONS.has(operationId)) return hasAllCommands(editor, operationId) && hasMarkCapability(editor, "textStyle");
68397
- return hasAllCommands(editor, operationId);
68483
+ return hasAllCommands(editor, operationId) && hasRequiredHelpers(editor, operationId);
68398
68484
  }
68399
68485
  function isCommandBackedAvailability(operationId) {
68400
68486
  return !isMarkBackedOperation(operationId) && !INLINE_FORMAT_OPERATIONS.has(operationId);
@@ -68408,7 +68494,10 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68408
68494
  const dryRun = metadata.supportsDryRun && available;
68409
68495
  const reasons = [];
68410
68496
  if (!available) {
68411
- if (isCommandBackedAvailability(operationId)) pushReason(reasons, "COMMAND_UNAVAILABLE");
68497
+ if (isCommandBackedAvailability(operationId)) {
68498
+ if (!hasAllCommands(editor, operationId)) pushReason(reasons, "COMMAND_UNAVAILABLE");
68499
+ if (!hasRequiredHelpers(editor, operationId)) pushReason(reasons, "HELPER_UNAVAILABLE");
68500
+ }
68412
68501
  pushReason(reasons, "OPERATION_UNAVAILABLE");
68413
68502
  }
68414
68503
  if (metadata.supportsTrackedMode && !tracked) pushReason(reasons, "TRACKED_MODE_UNAVAILABLE");
@@ -68898,13 +68987,21 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68898
68987
  });
68899
68988
  return {
68900
68989
  candidates,
68901
- byId
68990
+ byId,
68991
+ ambiguous
68902
68992
  };
68903
68993
  }
68904
68994
  function findBlockById(index$1, address) {
68905
68995
  if (address.kind !== "block") return void 0;
68906
68996
  return index$1.byId.get(`${address.nodeType}:${address.nodeId}`);
68907
68997
  }
68998
+ function findBlockByIdStrict(index$1, address) {
68999
+ const key$1 = `${address.nodeType}:${address.nodeId}`;
69000
+ if (index$1.ambiguous.has(key$1)) throw new DocumentApiAdapterError("AMBIGUOUS_TARGET", `Multiple blocks share key "${key$1}".`, { target: address });
69001
+ const candidate = index$1.byId.get(key$1);
69002
+ if (!candidate) throw new DocumentApiAdapterError("TARGET_NOT_FOUND", `Block "${key$1}" was not found.`, { target: address });
69003
+ return candidate;
69004
+ }
68908
69005
  function isTextBlockCandidate(candidate) {
68909
69006
  const node$1 = candidate.node;
68910
69007
  return Boolean(node$1?.inlineContent || node$1?.isTextblock);
@@ -68990,9 +69087,11 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
68990
69087
  function checkRevision(editor, expectedRevision) {
68991
69088
  if (expectedRevision === void 0) return;
68992
69089
  const current = getRevision(editor);
68993
- if (expectedRevision !== current) throw new PlanError("REVISION_MISMATCH", `REVISION_MISMATCH — expected revision "${expectedRevision}" but document is at "${current}"`, void 0, {
69090
+ if (expectedRevision !== current) throw new PlanError("REVISION_MISMATCH", `REVISION_MISMATCH — expected revision "${expectedRevision}" but document is at "${current}". Re-run query.match to obtain a fresh ref.`, void 0, {
68994
69091
  expectedRevision,
68995
- currentRevision: current
69092
+ currentRevision: current,
69093
+ refStability: "ephemeral",
69094
+ remediation: "Re-run query.match() to obtain a fresh ref valid for the current revision."
68996
69095
  });
68997
69096
  }
68998
69097
  function resolveSegmentPosition(targetOffset, segmentStart, segmentLength, docFrom, docTo) {
@@ -69242,7 +69341,9 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
69242
69341
  return;
69243
69342
  }
69244
69343
  if (node$1.isLeaf) {
69344
+ const start$1 = offset$1;
69245
69345
  offset$1 += 1;
69346
+ maybePushRun(start$1, offset$1, []);
69246
69347
  return;
69247
69348
  }
69248
69349
  let isFirstChild = true;
@@ -69642,12 +69743,62 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
69642
69743
  function isAssertStep(step) {
69643
69744
  return step.op === "assert";
69644
69745
  }
69746
+ function isCreateOp(op) {
69747
+ return op === "create.heading" || op === "create.paragraph";
69748
+ }
69749
+ var VALID_CREATE_POSITIONS = ["before", "after"];
69645
69750
  function isSelectWhere(where) {
69646
69751
  return where.by === "select";
69647
69752
  }
69648
69753
  function isRefWhere(where) {
69649
69754
  return where.by === "ref";
69650
69755
  }
69756
+ function validateCreateStepPosition(step) {
69757
+ const args$1 = step.args;
69758
+ if (args$1.position === void 0 || args$1.position === null) {
69759
+ args$1.position = "after";
69760
+ return;
69761
+ }
69762
+ if (!VALID_CREATE_POSITIONS.includes(args$1.position)) throw planError("INVALID_INPUT", `create step requires args.position to be 'before' or 'after'`, step.id, {
69763
+ receivedPosition: args$1.position,
69764
+ allowedValues: [...VALID_CREATE_POSITIONS],
69765
+ default: "after"
69766
+ });
69767
+ }
69768
+ function resolveCreateAnchorFromTargets(targets, position$3, stepId) {
69769
+ const target = targets[0];
69770
+ if (!target) throw planError("INVALID_INPUT", "create step has no resolved targets", stepId);
69771
+ if (target.kind === "range") return target.blockId;
69772
+ const segments = target.segments;
69773
+ if (!segments.length) throw planError("INVALID_INPUT", "span target has no segments", stepId);
69774
+ return position$3 === "before" ? segments[0].blockId : segments[segments.length - 1].blockId;
69775
+ }
69776
+ function validateInsertionContext(editor, index$1, step, stepIndex, anchorBlockId, position$3) {
69777
+ const candidate = index$1.candidates.find((c$3) => c$3.nodeId === anchorBlockId);
69778
+ if (!candidate) return;
69779
+ const paragraphType = editor.state.schema?.nodes?.paragraph;
69780
+ if (!paragraphType) return;
69781
+ const resolvedPos = editor.state.doc.resolve(candidate.pos);
69782
+ const parent = resolvedPos.parent;
69783
+ const anchorIndex = resolvedPos.index();
69784
+ const insertionIndex = position$3 === "before" ? anchorIndex : anchorIndex + 1;
69785
+ if (!(typeof parent.canReplaceWith === "function" ? parent.canReplaceWith(insertionIndex, insertionIndex, paragraphType) : parent.type.contentMatch.matchType(paragraphType))) {
69786
+ const allowedChildTypes = [];
69787
+ const match$1 = parent.type.contentMatch;
69788
+ for (const nodeType of Object.values(editor.state.schema.nodes)) if (match$1.matchType(nodeType)) allowedChildTypes.push(nodeType.name);
69789
+ throw planError("INVALID_INSERTION_CONTEXT", `Cannot create ${step.op} inside ${parent.type.name}`, step.id, {
69790
+ stepIndex,
69791
+ stepId: step.id,
69792
+ operation: step.op,
69793
+ anchorBlockId,
69794
+ parentType: parent.type.name,
69795
+ allowedChildTypes,
69796
+ insertionIndex,
69797
+ requestedChildType: "paragraph",
69798
+ requestedSemanticType: step.op === "create.heading" ? "heading" : "paragraph"
69799
+ });
69800
+ }
69801
+ }
69651
69802
  function isV3Ref(payload) {
69652
69803
  return typeof payload === "object" && payload !== null && "v" in payload && payload.v === 3;
69653
69804
  }
@@ -69860,9 +70011,13 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
69860
70011
  }
69861
70012
  function resolveV3TextRef(editor, index$1, step, refData) {
69862
70013
  const currentRevision = getRevision(editor);
69863
- if (refData.rev !== currentRevision) throw planError("REVISION_MISMATCH", `text ref was created at revision "${refData.rev}" but document is at "${currentRevision}"`, step.id, {
70014
+ if (refData.rev !== currentRevision) throw planError("REVISION_MISMATCH", `Text ref is ephemeral and revision-scoped. Re-run query.match to obtain a fresh handle.ref for revision ${currentRevision}.`, step.id, {
69864
70015
  refRevision: refData.rev,
69865
- currentRevision
70016
+ currentRevision,
70017
+ refStability: "ephemeral",
70018
+ refScope: refData.scope,
70019
+ blockId: refData.segments?.[0]?.blockId,
70020
+ remediation: `Re-run query.match() to obtain a fresh ref valid for the current revision.`
69866
70021
  });
69867
70022
  if (!refData.segments?.length) return [];
69868
70023
  const segments = refData.segments.map((s$1) => ({
@@ -69961,7 +70116,11 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
69961
70116
  return t.blockId !== prev.blockId || t.from !== prev.from || t.to !== prev.to;
69962
70117
  });
69963
70118
  if (refWhere) {
69964
- if (targets.length === 0) throw planError("MATCH_NOT_FOUND", `ref "${refWhere.ref}" did not resolve to any targets`, step.id);
70119
+ if (targets.length === 0) throw planError("MATCH_NOT_FOUND", `ref "${refWhere.ref}" did not resolve to any targets`, step.id, {
70120
+ selectorType: "ref",
70121
+ selectorPattern: refWhere.ref,
70122
+ candidateCount: 0
70123
+ });
69965
70124
  if (targets.length > 1) throw planError("AMBIGUOUS_MATCH", `ref "${refWhere.ref}" resolved to ${targets.length} targets`, step.id, { matchCount: targets.length });
69966
70125
  return targets;
69967
70126
  }
@@ -69970,57 +70129,157 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
69970
70129
  if (selectWhere.require === "first" && targets.length > 1) targets = [targets[0]];
69971
70130
  return targets;
69972
70131
  }
70132
+ function buildMatchNotFoundDetails(step) {
70133
+ const where = step.where;
70134
+ const select$1 = "select" in where ? where.select : void 0;
70135
+ const within$1 = "within" in where ? where.within : void 0;
70136
+ return {
70137
+ selectorType: select$1?.type ?? "unknown",
70138
+ selectorPattern: select$1?.pattern ?? "",
70139
+ selectorMode: select$1?.mode ?? "contains",
70140
+ searchScope: within$1?.blockId ?? "document",
70141
+ candidateCount: 0
70142
+ };
70143
+ }
69973
70144
  function applyCardinalityCheck(step, targets) {
69974
70145
  const where = step.where;
69975
70146
  if (!("require" in where) || where.require === void 0) return;
69976
70147
  const require$1 = where.require;
69977
70148
  if (require$1 === "first") {
69978
- if (targets.length === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges", step.id);
70149
+ if (targets.length === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges", step.id, buildMatchNotFoundDetails(step));
69979
70150
  } else if (require$1 === "exactlyOne") {
69980
- if (targets.length === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges", step.id);
70151
+ if (targets.length === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges", step.id, buildMatchNotFoundDetails(step));
69981
70152
  if (targets.length > 1) throw planError("AMBIGUOUS_MATCH", `selector matched ${targets.length} ranges, expected exactly one`, step.id, { matchCount: targets.length });
69982
70153
  } else if (require$1 === "all") {
69983
- if (targets.length === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges", step.id);
69984
- }
69985
- }
69986
- function detectOverlaps(steps) {
69987
- const rangesByBlock = /* @__PURE__ */ new Map();
69988
- for (const compiled of steps) for (const target of compiled.targets) if (target.kind === "range") addRange(rangesByBlock, target.blockId, target.stepId, target.from, target.to);
69989
- else for (const seg of target.segments) addRange(rangesByBlock, seg.blockId, target.stepId, seg.from, seg.to);
69990
- for (const [blockId, ranges] of rangesByBlock) {
69991
- ranges.sort((a$1, b$2) => a$1.from - b$2.from);
69992
- for (let i$1 = 1; i$1 < ranges.length; i$1++) {
69993
- const prev = ranges[i$1 - 1];
69994
- const curr = ranges[i$1];
69995
- if (prev.stepId !== curr.stepId && prev.to > curr.from) throw planError("PLAN_CONFLICT_OVERLAP", `steps "${prev.stepId}" and "${curr.stepId}" target overlapping ranges in block "${blockId}"`, curr.stepId, {
70154
+ if (targets.length === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges", step.id, buildMatchNotFoundDetails(step));
70155
+ }
70156
+ }
70157
+ const STEP_INTERACTION_MATRIX = new Map([
70158
+ ["text.rewrite::format.apply::same_target", "allow"],
70159
+ ["text.rewrite::text.rewrite::same_target", "reject"],
70160
+ ["text.rewrite::text.delete::overlapping", "reject"],
70161
+ ["text.rewrite::create.*::same_block", "allow"],
70162
+ ["text.rewrite::text.insert::same_target", "reject"],
70163
+ ["format.apply::format.apply::same_target", "allow"],
70164
+ ["format.apply::text.rewrite::same_target", "reject"],
70165
+ ["format.apply::text.delete::overlapping", "reject"],
70166
+ ["format.apply::create.*::same_block", "allow"],
70167
+ ["format.apply::text.insert::same_target", "allow"],
70168
+ ["text.delete::text.rewrite::overlapping", "reject"],
70169
+ ["text.delete::text.delete::overlapping", "reject"],
70170
+ ["text.delete::format.apply::overlapping", "reject"],
70171
+ ["text.delete::create.*::same_block", "allow"],
70172
+ ["text.delete::text.insert::overlapping", "reject"],
70173
+ ["create.*::text.rewrite::same_block", "allow"],
70174
+ ["create.*::format.apply::same_block", "allow"],
70175
+ ["create.*::text.delete::same_block", "allow"],
70176
+ ["create.*::create.*::same_block", "allow"],
70177
+ ["create.*::text.insert::same_block", "allow"],
70178
+ ["text.insert::format.apply::same_target", "allow"],
70179
+ ["text.insert::text.rewrite::same_target", "reject"],
70180
+ ["text.insert::text.delete::overlapping", "reject"],
70181
+ ["text.insert::create.*::same_block", "allow"],
70182
+ ["text.insert::text.insert::same_target", "reject"]
70183
+ ]);
70184
+ const MATRIX_EXEMPT_OPS = new Set(["assert"]);
70185
+ function normalizeOpForMatrix(op) {
70186
+ return op.startsWith("create.") ? "create.*" : op;
70187
+ }
70188
+ function classifyOverlap(stepA, stepB) {
70189
+ const rangesA = extractBlockRanges(stepA);
70190
+ const rangesB = extractBlockRanges(stepB);
70191
+ const opA = normalizeOpForMatrix(stepA.step.op);
70192
+ const opB = normalizeOpForMatrix(stepB.step.op);
70193
+ const isCreateA = opA === "create.*";
70194
+ const isCreateB = opB === "create.*";
70195
+ for (const [blockId, aEntries] of rangesA) {
70196
+ const bEntries = rangesB.get(blockId);
70197
+ if (!bEntries) continue;
70198
+ for (const a$1 of aEntries) for (const b$2 of bEntries) {
70199
+ if (isCreateA || isCreateB) return {
70200
+ overlapClass: "same_block",
69996
70201
  blockId,
69997
- rangeA: {
69998
- from: prev.from,
69999
- to: prev.to
70000
- },
70001
- rangeB: {
70002
- from: curr.from,
70003
- to: curr.to
70004
- }
70005
- });
70202
+ rangeA: a$1,
70203
+ rangeB: b$2
70204
+ };
70205
+ if (a$1.to <= b$2.from || b$2.to <= a$1.from) continue;
70206
+ if (a$1.from === b$2.from && a$1.to === b$2.to) return {
70207
+ overlapClass: "same_target",
70208
+ blockId,
70209
+ rangeA: a$1,
70210
+ rangeB: b$2
70211
+ };
70212
+ return {
70213
+ overlapClass: "overlapping",
70214
+ blockId,
70215
+ rangeA: a$1,
70216
+ rangeB: b$2
70217
+ };
70006
70218
  }
70007
70219
  }
70008
70220
  }
70009
- function addRange(map$5, blockId, stepId, from$1, to) {
70010
- let blockRanges = map$5.get(blockId);
70011
- if (!blockRanges) {
70012
- blockRanges = [];
70013
- map$5.set(blockId, blockRanges);
70221
+ function extractBlockRanges(compiled) {
70222
+ const result = /* @__PURE__ */ new Map();
70223
+ for (const target of compiled.targets) if (target.kind === "range") pushBlockRange(result, target.blockId, target.from, target.to);
70224
+ else for (const seg of target.segments) pushBlockRange(result, seg.blockId, seg.from, seg.to);
70225
+ return result;
70226
+ }
70227
+ function pushBlockRange(map$5, blockId, from$1, to) {
70228
+ let entries = map$5.get(blockId);
70229
+ if (!entries) {
70230
+ entries = [];
70231
+ map$5.set(blockId, entries);
70014
70232
  }
70015
- blockRanges.push({
70016
- stepId,
70233
+ entries.push({
70017
70234
  from: from$1,
70018
70235
  to
70019
70236
  });
70020
70237
  }
70238
+ function validateStepInteractions(steps) {
70239
+ for (let i$1 = 0; i$1 < steps.length; i$1++) for (let j$1 = i$1 + 1; j$1 < steps.length; j$1++) {
70240
+ const stepA = steps[i$1];
70241
+ const stepB = steps[j$1];
70242
+ if (MATRIX_EXEMPT_OPS.has(stepA.step.op) || MATRIX_EXEMPT_OPS.has(stepB.step.op)) continue;
70243
+ const overlap = classifyOverlap(stepA, stepB);
70244
+ if (!overlap) continue;
70245
+ const matrixKey = `${normalizeOpForMatrix(stepA.step.op)}::${normalizeOpForMatrix(stepB.step.op)}::${overlap.overlapClass}`;
70246
+ const verdict = STEP_INTERACTION_MATRIX.get(matrixKey) ?? "reject";
70247
+ if (verdict === "reject") throw planError("PLAN_CONFLICT_OVERLAP", `steps "${stepA.step.id}" and "${stepB.step.id}" target overlapping ranges in block "${overlap.blockId}"`, stepB.step.id, {
70248
+ blockId: overlap.blockId,
70249
+ stepIdA: stepA.step.id,
70250
+ stepIdB: stepB.step.id,
70251
+ opKeyA: stepA.step.op,
70252
+ opKeyB: stepB.step.op,
70253
+ rangeA: overlap.rangeA,
70254
+ rangeB: overlap.rangeB,
70255
+ overlapRegion: {
70256
+ from: Math.max(overlap.rangeA.from, overlap.rangeB.from),
70257
+ to: Math.min(overlap.rangeA.to, overlap.rangeB.to)
70258
+ },
70259
+ matrixVerdict: verdict,
70260
+ matrixKey
70261
+ });
70262
+ }
70263
+ }
70264
+ function assertNoDuplicateBlockIds(index$1) {
70265
+ const seen = /* @__PURE__ */ new Map();
70266
+ const duplicates = [];
70267
+ for (const candidate of index$1.candidates) {
70268
+ const count = seen.get(candidate.nodeId) ?? 0;
70269
+ seen.set(candidate.nodeId, count + 1);
70270
+ if (count === 1) duplicates.push(candidate.nodeId);
70271
+ }
70272
+ if (duplicates.length > 0) throw planError("DOCUMENT_IDENTITY_CONFLICT", "Document contains blocks with duplicate identities. This must be resolved before mutations can be applied.", void 0, {
70273
+ duplicateBlockIds: duplicates,
70274
+ blockCount: duplicates.length,
70275
+ remediation: "Re-import the document or call document.repair() to assign unique identities."
70276
+ });
70277
+ }
70021
70278
  function compilePlan(editor, steps) {
70022
70279
  if (steps.length > 200) throw planError("INVALID_INPUT", `plan contains ${steps.length} steps, maximum is 200`);
70280
+ const compiledRevision = getRevision(editor);
70023
70281
  const index$1 = getBlockIndex(editor);
70282
+ assertNoDuplicateBlockIds(index$1);
70024
70283
  const mutationSteps = [];
70025
70284
  const assertSteps = [];
70026
70285
  const seenIds = /* @__PURE__ */ new Set();
@@ -70030,26 +70289,41 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70030
70289
  seenIds.add(step.id);
70031
70290
  }
70032
70291
  let totalTargets = 0;
70292
+ let stepIndex = 0;
70033
70293
  for (const step of steps) {
70034
70294
  if (isAssertStep(step)) {
70035
70295
  assertSteps.push(step);
70296
+ stepIndex++;
70036
70297
  continue;
70037
70298
  }
70038
70299
  if (!hasStepExecutor(step.op)) throw planError("INVALID_INPUT", `unknown step op "${step.op}"`, step.id);
70300
+ if (isCreateOp(step.op)) validateCreateStepPosition(step);
70039
70301
  const targets = resolveStepTargets(editor, index$1, step);
70302
+ if (isCreateOp(step.op) && targets.length > 0) {
70303
+ const position$3 = step.args.position ?? "after";
70304
+ const anchorBlockId = resolveCreateAnchorFromTargets(targets, position$3, step.id);
70305
+ validateInsertionContext(editor, index$1, step, stepIndex, anchorBlockId, position$3);
70306
+ }
70040
70307
  totalTargets += targets.length;
70041
70308
  mutationSteps.push({
70042
70309
  step,
70043
70310
  targets
70044
70311
  });
70312
+ stepIndex++;
70045
70313
  }
70046
70314
  if (totalTargets > 500) throw planError("INVALID_INPUT", `plan resolved ${totalTargets} total targets, maximum is 500`);
70047
- detectOverlaps(mutationSteps);
70315
+ validateStepInteractions(mutationSteps);
70048
70316
  return {
70049
70317
  mutationSteps,
70050
- assertSteps
70318
+ assertSteps,
70319
+ compiledRevision
70051
70320
  };
70052
70321
  }
70322
+ function resolveBlockInsertionPos(editor, anchorBlockId, position$3, stepId) {
70323
+ const candidate = getBlockIndex(editor).candidates.find((c$3) => c$3.nodeId === anchorBlockId);
70324
+ if (!candidate) throw planError("TARGET_NOT_FOUND", `block "${anchorBlockId}" not found`, stepId);
70325
+ return position$3 === "before" ? candidate.pos : candidate.end;
70326
+ }
70053
70327
  function applyDirectMutationMeta(tr) {
70054
70328
  tr.setMeta("inputType", "programmatic");
70055
70329
  tr.setMeta("skipTrackChanges", true);
@@ -70094,10 +70368,28 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70094
70368
  if (setMarks.strike && schema.marks.strike) marks.push(schema.marks.strike.create());
70095
70369
  return marks;
70096
70370
  }
70097
- function toAbsoluteBlockInsertPos(editor, blockId, offset$1, stepId) {
70098
- const candidate = getBlockIndex(editor).candidates.find((c$3) => c$3.nodeId === blockId);
70099
- if (!candidate) throw planError("TARGET_NOT_FOUND", `block "${blockId}" not found`, stepId);
70100
- return candidate.pos + offset$1;
70371
+ function applyInlineMarkPatches(editor, tr, absFrom, absTo, inline) {
70372
+ const { schema } = editor.state;
70373
+ let changed = false;
70374
+ const markEntries = [
70375
+ [inline.bold, schema.marks.bold],
70376
+ [inline.italic, schema.marks.italic],
70377
+ [inline.underline, schema.marks.underline],
70378
+ [inline.strike, schema.marks.strike]
70379
+ ];
70380
+ for (const [value, markType] of markEntries) {
70381
+ if (value === void 0 || !markType) continue;
70382
+ if (value) tr.addMark(absFrom, absTo, markType.create());
70383
+ else tr.removeMark(absFrom, absTo, markType);
70384
+ changed = true;
70385
+ }
70386
+ return changed;
70387
+ }
70388
+ function resolveCreateAnchorBlockId(target, position$3, stepId) {
70389
+ if (target.kind === "range") return target.blockId;
70390
+ const segments = target.segments;
70391
+ if (!segments.length) throw planError("INVALID_INPUT", "span target has no segments", stepId);
70392
+ return position$3 === "before" ? segments[0].blockId : segments[segments.length - 1].blockId;
70101
70393
  }
70102
70394
  function executeTextRewrite(editor, tr, target, step, mapping) {
70103
70395
  const absFrom = mapping.map(target.absFrom);
@@ -70131,39 +70423,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70131
70423
  return { changed: true };
70132
70424
  }
70133
70425
  function executeStyleApply(editor, tr, target, step, mapping) {
70134
- const absFrom = mapping.map(target.absFrom);
70135
- const absTo = mapping.map(target.absTo);
70136
- const { schema } = editor.state;
70137
- let changed = false;
70138
- const markEntries = [
70139
- [
70140
- "bold",
70141
- step.args.inline.bold,
70142
- schema.marks.bold
70143
- ],
70144
- [
70145
- "italic",
70146
- step.args.inline.italic,
70147
- schema.marks.italic
70148
- ],
70149
- [
70150
- "underline",
70151
- step.args.inline.underline,
70152
- schema.marks.underline
70153
- ],
70154
- [
70155
- "strike",
70156
- step.args.inline.strike,
70157
- schema.marks.strike
70158
- ]
70159
- ];
70160
- for (const [, value, markType] of markEntries) {
70161
- if (value === void 0 || !markType) continue;
70162
- if (value) tr.addMark(absFrom, absTo, markType.create());
70163
- else tr.removeMark(absFrom, absTo, markType);
70164
- changed = true;
70165
- }
70166
- return { changed };
70426
+ return { changed: applyInlineMarkPatches(editor, tr, mapping.map(target.absFrom), mapping.map(target.absTo), step.args.inline) };
70167
70427
  }
70168
70428
  function validateMappedSpanContiguity(target, mapping, stepId) {
70169
70429
  let lastMappedEnd = -1;
@@ -70224,41 +70484,9 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70224
70484
  }
70225
70485
  function executeSpanStyleApply(editor, tr, target, step, mapping) {
70226
70486
  validateMappedSpanContiguity(target, mapping, step.id);
70227
- const { schema } = editor.state;
70228
- let changed = false;
70229
70487
  const firstSeg = target.segments[0];
70230
70488
  const lastSeg = target.segments[target.segments.length - 1];
70231
- const absFrom = mapping.map(firstSeg.absFrom, 1);
70232
- const absTo = mapping.map(lastSeg.absTo, -1);
70233
- const markEntries = [
70234
- [
70235
- "bold",
70236
- step.args.inline.bold,
70237
- schema.marks.bold
70238
- ],
70239
- [
70240
- "italic",
70241
- step.args.inline.italic,
70242
- schema.marks.italic
70243
- ],
70244
- [
70245
- "underline",
70246
- step.args.inline.underline,
70247
- schema.marks.underline
70248
- ],
70249
- [
70250
- "strike",
70251
- step.args.inline.strike,
70252
- schema.marks.strike
70253
- ]
70254
- ];
70255
- for (const [, value, markType] of markEntries) {
70256
- if (value === void 0 || !markType) continue;
70257
- if (value) tr.addMark(absFrom, absTo, markType.create());
70258
- else tr.removeMark(absFrom, absTo, markType);
70259
- changed = true;
70260
- }
70261
- return { changed };
70489
+ return { changed: applyInlineMarkPatches(editor, tr, mapping.map(firstSeg.absFrom, 1), mapping.map(lastSeg.absTo, -1), step.args.inline) };
70262
70490
  }
70263
70491
  function getReplacementText(replacement) {
70264
70492
  if (replacement.blocks !== void 0) return replacement.blocks.map((b$2) => b$2.text).join("\n\n");
@@ -70370,7 +70598,8 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70370
70598
  });
70371
70599
  return {
70372
70600
  candidates,
70373
- byId
70601
+ byId,
70602
+ ambiguous
70374
70603
  };
70375
70604
  }
70376
70605
  function resolveAssertScope(index$1, select$1, within$1) {
@@ -70428,9 +70657,11 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70428
70657
  }
70429
70658
  function executeCreateStep(editor, tr, step, targets, mapping) {
70430
70659
  const target = targets[0];
70431
- if (!target || target.kind !== "range") throw planError("INVALID_INPUT", `${step.op} step requires exactly one range target`, step.id);
70660
+ if (!target) throw planError("INVALID_INPUT", `${step.op} step requires at least one target`, step.id);
70432
70661
  const args$1 = step.args;
70433
- const pos = mapping.map(toAbsoluteBlockInsertPos(editor, target.blockId, target.from, step.id));
70662
+ const position$3 = args$1.position ?? "after";
70663
+ const anchorPos = resolveBlockInsertionPos(editor, resolveCreateAnchorBlockId(target, position$3, step.id), position$3, step.id);
70664
+ const pos = mapping.map(anchorPos);
70434
70665
  const paragraphType = editor.state.schema?.nodes?.paragraph;
70435
70666
  if (!paragraphType) throw planError("INVALID_INPUT", "paragraph node type not in schema", step.id);
70436
70667
  const sdBlockId = args$1.sdBlockId;
@@ -70447,6 +70678,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70447
70678
  const node$1 = paragraphType.createAndFill(attrs, textNode ?? void 0) ?? paragraphType.create(attrs, textNode ? [textNode] : void 0);
70448
70679
  if (!node$1) throw planError("INVALID_INPUT", `could not create ${step.op} node`, step.id);
70449
70680
  tr.insert(pos, node$1);
70681
+ assertNoPostInsertDuplicateIds(tr.doc, step.id);
70450
70682
  return {
70451
70683
  stepId: step.id,
70452
70684
  op: step.op,
@@ -70458,6 +70690,27 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70458
70690
  }
70459
70691
  };
70460
70692
  }
70693
+ function assertNoPostInsertDuplicateIds(doc$4, stepId) {
70694
+ const seen = /* @__PURE__ */ new Set();
70695
+ const duplicateSet = /* @__PURE__ */ new Set();
70696
+ doc$4.descendants((node$1) => {
70697
+ if (!node$1.isTextblock) return true;
70698
+ const attrs = node$1.attrs ?? {};
70699
+ const id = typeof attrs.paraId === "string" && attrs.paraId || typeof attrs.sdBlockId === "string" && attrs.sdBlockId || typeof attrs.nodeId === "string" && attrs.nodeId;
70700
+ if (!id) return true;
70701
+ if (seen.has(id)) duplicateSet.add(id);
70702
+ else seen.add(id);
70703
+ return true;
70704
+ });
70705
+ if (duplicateSet.size > 0) {
70706
+ const duplicates = [...duplicateSet];
70707
+ throw planError("INTERNAL_ERROR", `create step produced duplicate block identities: [${duplicates.join(", ")}]`, stepId, {
70708
+ source: "executor:checkPostInsertIdentityUniqueness",
70709
+ invariant: "post-insert block IDs must be unique",
70710
+ duplicateBlockIds: duplicates
70711
+ });
70712
+ }
70713
+ }
70461
70714
  function runMutationsOnTransaction(editor, tr, compiled, options$1) {
70462
70715
  const mapping = tr.mapping;
70463
70716
  const stepOutcomes = [];
@@ -70513,6 +70766,13 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70513
70766
  const startTime = performance.now();
70514
70767
  const revisionBefore = getRevision(editor);
70515
70768
  checkRevision(editor, options$1.expectedRevision);
70769
+ if (compiled.compiledRevision !== revisionBefore) throw planError("REVISION_CHANGED_SINCE_COMPILE", `Document revision changed between compile and execute. Compiled at "${compiled.compiledRevision}", now at "${revisionBefore}".`, void 0, {
70770
+ compiledRevision: compiled.compiledRevision,
70771
+ currentRevision: revisionBefore,
70772
+ stepCount: compiled.mutationSteps.length,
70773
+ failedAtStep: "pre-execution",
70774
+ remediation: "Re-compile the plan against the current document state."
70775
+ });
70516
70776
  const tr = editor.state.tr;
70517
70777
  if ((options$1.changeMode ?? "direct") === "tracked") applyTrackedMutationMeta(tr);
70518
70778
  else applyDirectMutationMeta(tr);
@@ -70721,7 +70981,8 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70721
70981
  },
70722
70982
  targets: []
70723
70983
  }],
70724
- assertSteps: []
70984
+ assertSteps: [],
70985
+ compiledRevision: getRevision(editor)
70725
70986
  }, { expectedRevision: options$1?.expectedRevision });
70726
70987
  }
70727
70988
  function validateWriteRequest(request, resolved) {
@@ -70808,7 +71069,8 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70808
71069
  step: stepDef,
70809
71070
  targets: [toCompiledTarget(stepId, op, resolved)]
70810
71071
  }],
70811
- assertSteps: []
71072
+ assertSteps: [],
71073
+ compiledRevision: getRevision(editor)
70812
71074
  }, {
70813
71075
  changeMode: mode,
70814
71076
  expectedRevision: options$1?.expectedRevision
@@ -70874,7 +71136,8 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
70874
71136
  marks: []
70875
71137
  }]
70876
71138
  }],
70877
- assertSteps: []
71139
+ assertSteps: [],
71140
+ compiledRevision: getRevision(editor)
70878
71141
  }, {
70879
71142
  changeMode: mode,
70880
71143
  expectedRevision: options$1?.expectedRevision
@@ -71640,6 +71903,51 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
71640
71903
  list: (query) => listCommentsHandler(editor, query)
71641
71904
  };
71642
71905
  }
71906
+ var SUPPORTED_NODE_TYPES = new Set(DELETABLE_BLOCK_NODE_TYPES);
71907
+ var REJECTED_NODE_TYPES = new Set(["tableRow", "tableCell"]);
71908
+ function validateTargetNodeType(nodeType) {
71909
+ if (REJECTED_NODE_TYPES.has(nodeType)) throw new DocumentApiAdapterError("INVALID_TARGET", `blocks.delete does not support "${nodeType}" targets. Table row/column operations are out of scope.`, { nodeType });
71910
+ if (!SUPPORTED_NODE_TYPES.has(nodeType)) throw new DocumentApiAdapterError("INVALID_TARGET", `blocks.delete does not support "${nodeType}" targets.`, { nodeType });
71911
+ }
71912
+ function resolveSdBlockId(candidate) {
71913
+ const sdBlockId = candidate.node.attrs?.sdBlockId;
71914
+ if (typeof sdBlockId === "string" && sdBlockId.length > 0) return sdBlockId;
71915
+ throw new DocumentApiAdapterError("INTERNAL_ERROR", "Resolved block candidate is missing sdBlockId attribute. This indicates a schema/extension invariant violation.", { attrs: candidate.node.attrs });
71916
+ }
71917
+ function validateCommandLayerUniqueness(editor, sdBlockId) {
71918
+ const getBlockNodeById = editor.helpers?.blockNode?.getBlockNodeById;
71919
+ if (typeof getBlockNodeById !== "function") throw new DocumentApiAdapterError("CAPABILITY_UNAVAILABLE", "blocks.delete requires the blockNode helper to be registered.", { reason: "missing_helper" });
71920
+ const matches$1 = getBlockNodeById(sdBlockId);
71921
+ if (!matches$1 || Array.isArray(matches$1) && matches$1.length === 0) throw new DocumentApiAdapterError("TARGET_NOT_FOUND", `Block with sdBlockId "${sdBlockId}" was not found at the command layer.`, { sdBlockId });
71922
+ if (Array.isArray(matches$1) && matches$1.length > 1) throw new DocumentApiAdapterError("AMBIGUOUS_TARGET", `Multiple blocks share sdBlockId "${sdBlockId}" at the command layer.`, {
71923
+ sdBlockId,
71924
+ count: matches$1.length
71925
+ });
71926
+ }
71927
+ function blocksDeleteWrapper(editor, input$1, options$1) {
71928
+ rejectTrackedMode("blocks.delete", options$1);
71929
+ const candidate = findBlockByIdStrict(getBlockIndex(editor), input$1.target);
71930
+ validateTargetNodeType(candidate.nodeType);
71931
+ const sdBlockId = resolveSdBlockId(candidate);
71932
+ const deleteBlockNodeById = requireEditorCommand(editor.commands?.deleteBlockNodeById, "blocks.delete");
71933
+ validateCommandLayerUniqueness(editor, sdBlockId);
71934
+ if (options$1?.dryRun) return {
71935
+ success: true,
71936
+ deleted: input$1.target
71937
+ };
71938
+ if (executeDomainCommand(editor, () => {
71939
+ const didApply = deleteBlockNodeById(sdBlockId);
71940
+ if (didApply) clearIndexCache(editor);
71941
+ return didApply;
71942
+ }, { expectedRevision: options$1?.expectedRevision }).steps[0]?.effect !== "changed") throw new DocumentApiAdapterError("INTERNAL_ERROR", "blocks.delete command returned false despite passing all pre-apply checks. This is an internal invariant violation.", {
71943
+ sdBlockId,
71944
+ target: input$1.target
71945
+ });
71946
+ return {
71947
+ success: true,
71948
+ deleted: input$1.target
71949
+ };
71950
+ }
71643
71951
  var DERIVED_ID_LENGTH = 24;
71644
71952
  function getRawTrackedMarks(editor) {
71645
71953
  try {
@@ -71763,9 +72071,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
71763
72071
  const location$2 = at ?? { kind: "documentEnd" };
71764
72072
  if (location$2.kind === "documentStart") return 0;
71765
72073
  if (location$2.kind === "documentEnd") return editor.state.doc.content.size;
71766
- const target = findBlockById(getBlockIndex(editor), location$2.target);
71767
- if (!target) throw new DocumentApiAdapterError("TARGET_NOT_FOUND", `Create ${operationLabel} target block was not found.`, { target: location$2.target });
71768
- return location$2.kind === "before" ? target.pos : target.end;
72074
+ return resolveBlockInsertionPos(editor, location$2.target.nodeId, location$2.kind);
71769
72075
  }
71770
72076
  function resolveCreatedBlock(editor, nodeType, blockId) {
71771
72077
  const index$1 = getBlockIndex(editor);
@@ -71867,7 +72173,9 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
71867
72173
  try {
71868
72174
  const paragraph$1 = resolveCreatedBlock(editor, "paragraph", paragraphId);
71869
72175
  if (mode === "tracked") trackedChangeRefs = collectTrackInsertRefsInRange(editor, paragraph$1.pos, paragraph$1.end);
71870
- } catch {}
72176
+ } catch (e) {
72177
+ if (!(e instanceof DocumentApiAdapterError)) throw e;
72178
+ }
71871
72179
  }
71872
72180
  return didApply;
71873
72181
  }, { expectedRevision: options$1?.expectedRevision }).steps[0]?.effect !== "changed") return {
@@ -71929,7 +72237,9 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
71929
72237
  try {
71930
72238
  const heading$2 = resolveCreatedBlock(editor, "heading", headingId);
71931
72239
  if (mode === "tracked") trackedChangeRefs = collectTrackInsertRefsInRange(editor, heading$2.pos, heading$2.end);
71932
- } catch {}
72240
+ } catch (e) {
72241
+ if (!(e instanceof DocumentApiAdapterError)) throw e;
72242
+ }
71933
72243
  }
71934
72244
  return didApply;
71935
72245
  }, { expectedRevision: options$1?.expectedRevision }).steps[0]?.effect !== "changed") return {
@@ -73141,14 +73451,15 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
73141
73451
  return { success: true };
73142
73452
  }
73143
73453
  function previewPlan(editor, input$1) {
73144
- const evaluatedRevision = getRevision(editor);
73145
73454
  checkRevision(editor, input$1.expectedRevision);
73146
73455
  if (!input$1.steps?.length) throw planError("INVALID_INPUT", "plan must contain at least one step");
73147
73456
  const failures = [];
73148
73457
  const stepPreviews = [];
73149
73458
  let currentPhase = "compile";
73459
+ let evaluatedRevision = getRevision(editor);
73150
73460
  try {
73151
73461
  const compiled = compilePlan(editor, input$1.steps);
73462
+ evaluatedRevision = compiled.compiledRevision;
73152
73463
  currentPhase = "execute";
73153
73464
  const tr = editor.state.tr;
73154
73465
  const { stepOutcomes, assertFailures } = runMutationsOnTransaction(editor, tr, compiled, { throwOnAssertFailure: false });
@@ -73651,14 +73962,24 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
73651
73962
  const userOffset = input$1.offset ?? 0;
73652
73963
  const paginatedMatches = isTextSelector ? applyPagination(rawMatches, userOffset, input$1.limit) : rawMatches;
73653
73964
  if (require$1 === "first" || require$1 === "exactlyOne" || require$1 === "all") {
73654
- if (totalMatches === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges");
73965
+ if (totalMatches === 0) throw planError("MATCH_NOT_FOUND", "selector matched zero ranges", void 0, {
73966
+ selectorType: input$1.select?.type ?? "unknown",
73967
+ selectorPattern: input$1.select?.pattern ?? "",
73968
+ selectorMode: input$1.select?.mode ?? "contains",
73969
+ searchScope: (input$1.within?.kind === "block" ? input$1.within.nodeId : void 0) ?? "document",
73970
+ candidateCount: 0
73971
+ });
73655
73972
  }
73656
73973
  if (require$1 === "exactlyOne" && totalMatches > 1) throw planError("AMBIGUOUS_MATCH", `selector matched ${totalMatches} ranges, expected exactly one`, void 0, { matchCount: totalMatches });
73657
73974
  const matchItems = paginatedMatches.map((raw, pageIdx) => {
73658
73975
  const id = `m:${userOffset + pageIdx}`;
73659
73976
  if (isTextSelector && raw.textRanges?.length) {
73660
73977
  const blocks$1 = buildMatchBlocks(editor, raw.textRanges, evaluatedRevision, id);
73661
- if (blocks$1.length === 0) throw planError("INTERNAL_ERROR", `text match produced no blocks for ${id}`);
73978
+ if (blocks$1.length === 0) throw planError("INTERNAL_ERROR", `text match produced no blocks for ${id}`, void 0, {
73979
+ source: "query-match-adapter:buildMatchEntries",
73980
+ invariant: "text match must have at least one block after zero-width filtering",
73981
+ context: { matchId: id }
73982
+ });
73662
73983
  const snippetResult = buildBlocksSnippet(editor, blocks$1);
73663
73984
  return {
73664
73985
  id,
@@ -73871,6 +74192,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
73871
74192
  acceptAll: (input$1, options$1) => trackChangesAcceptAllWrapper(editor, input$1, options$1),
73872
74193
  rejectAll: (input$1, options$1) => trackChangesRejectAllWrapper(editor, input$1, options$1)
73873
74194
  },
74195
+ blocks: { delete: (input$1, options$1) => blocksDeleteWrapper(editor, input$1, options$1) },
73874
74196
  create: {
73875
74197
  paragraph: (input$1, options$1) => createParagraphWrapper(editor, input$1, options$1),
73876
74198
  heading: (input$1, options$1) => createHeadingWrapper(editor, input$1, options$1)
@@ -92641,7 +92963,7 @@ while (n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 === a$3[++i$3] && n$2 ===
92641
92963
  return migrations.length > 0;
92642
92964
  }
92643
92965
  processCollaborationMigrations() {
92644
- console.debug("[checkVersionMigrations] Current editor version", "1.17.0-next.11");
92966
+ console.debug("[checkVersionMigrations] Current editor version", "1.17.0-next.13");
92645
92967
  if (!this.options.ydoc) return;
92646
92968
  let docVersion = this.options.ydoc.getMap("meta").get("version");
92647
92969
  if (!docVersion) docVersion = "initial";
@@ -177869,7 +178191,7 @@ js: import "konva/skia-backend";
177869
178191
  this.config.colors = shuffleArray(this.config.colors);
177870
178192
  this.userColorMap = /* @__PURE__ */ new Map();
177871
178193
  this.colorIndex = 0;
177872
- this.version = "1.17.0-next.11";
178194
+ this.version = "1.17.0-next.13";
177873
178195
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
177874
178196
  this.superdocId = config$31.superdocId || v4_default();
177875
178197
  this.colors = this.config.colors;