@harbour-enterprises/superdoc 0.24.0-next.6 → 0.25.0-next.1

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 (34) hide show
  1. package/dist/chunks/{PdfViewer-BiHh3x6b.es.js → PdfViewer-BEbvklge.es.js} +1 -1
  2. package/dist/chunks/{PdfViewer-qk_hITc5.cjs → PdfViewer-CvksDDwi.cjs} +1 -1
  3. package/dist/chunks/{index-aMnFs35I.es.js → index-B9Ad3j3k.es.js} +166 -76
  4. package/dist/chunks/{index-Di6nG2sc.cjs → index-Bf3lSVG2.cjs} +166 -76
  5. package/dist/chunks/{super-editor.es-Dz7y81Yr.es.js → super-editor.es--RpCOiR4.es.js} +157 -15
  6. package/dist/chunks/{super-editor.es-BKZvTraR.cjs → super-editor.es-Bh07I_ue.cjs} +157 -15
  7. package/dist/core/SuperDoc.d.ts +20 -0
  8. package/dist/core/SuperDoc.d.ts.map +1 -1
  9. package/dist/core/collaboration/permissions.d.ts +7 -1
  10. package/dist/core/collaboration/permissions.d.ts.map +1 -1
  11. package/dist/core/types/index.d.ts +23 -1
  12. package/dist/core/types/index.d.ts.map +1 -1
  13. package/dist/style.css +55 -55
  14. package/dist/super-editor/ai-writer.es.js +2 -2
  15. package/dist/super-editor/chunks/{converter-CI3WqmGV.js → converter-gSy6s2VK.js} +1 -1
  16. package/dist/super-editor/chunks/{docx-zipper-D4fk50d9.js → docx-zipper-CceGxV02.js} +1 -1
  17. package/dist/super-editor/chunks/{editor-DC6pZVp1.js → editor-CyBtLJFF.js} +116 -16
  18. package/dist/super-editor/chunks/{toolbar-DMobfM6u.js → toolbar-1Ejr8Exl.js} +2 -2
  19. package/dist/super-editor/converter.es.js +1 -1
  20. package/dist/super-editor/docx-zipper.es.js +2 -2
  21. package/dist/super-editor/editor.es.js +3 -3
  22. package/dist/super-editor/file-zipper.es.js +1 -1
  23. package/dist/super-editor/super-editor/src/components/slash-menu/tests/testHelpers.d.ts +1 -0
  24. package/dist/super-editor/super-editor/src/core/Editor.d.ts +18 -0
  25. package/dist/super-editor/super-editor/src/extensions/track-changes/permission-helpers.d.ts +110 -0
  26. package/dist/super-editor/super-editor.es.js +66 -21
  27. package/dist/super-editor/toolbar.es.js +2 -2
  28. package/dist/super-editor.cjs +1 -1
  29. package/dist/super-editor.es.js +1 -1
  30. package/dist/superdoc.cjs +2 -2
  31. package/dist/superdoc.es.js +2 -2
  32. package/dist/superdoc.umd.js +321 -89
  33. package/dist/superdoc.umd.js.map +1 -1
  34. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { m as defineComponent, B as h, O as Transition, $ as process$1, I as watchEffect, d as computed, r as ref, j as onMounted, W as onUnmounted, c as createElementBlock, o as openBlock, a as createBaseVNode, f as createCommentVNode, v as createVNode, x as unref } from "./vue-ZWZLQtoU.es.js";
2
- import { d as derived, c, a as cB, f as fadeInTransition, b as cM, N as NBaseLoading, w as warnOnce, u as useConfig, e as useTheme, p as pxfy, g as createKey, h as useThemeClass, i as useCompitable, _ as _export_sfc, j as useSuperdocStore, s as storeToRefs, k as useSelection } from "./index-aMnFs35I.es.js";
2
+ import { d as derived, c, a as cB, f as fadeInTransition, b as cM, N as NBaseLoading, w as warnOnce, u as useConfig, e as useTheme, p as pxfy, g as createKey, h as useThemeClass, i as useCompitable, _ as _export_sfc, j as useSuperdocStore, s as storeToRefs, k as useSelection } from "./index-B9Ad3j3k.es.js";
3
3
  function self(vars) {
4
4
  const {
5
5
  opacityDisabled,
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const vue = require("./vue-DKMj1I9B.cjs");
4
- const superdoc = require("./index-Di6nG2sc.cjs");
4
+ const superdoc = require("./index-Bf3lSVG2.cjs");
5
5
  function self(vars) {
6
6
  const {
7
7
  opacityDisabled,
@@ -1,4 +1,4 @@
1
- import { q as index, C as CommentsPluginKey, h as TrackChangesBasePluginKey, E as Editor, n as getRichTextExtensions, f as SuperInput, e as SuperEditor, A as AIWriter, g as SuperToolbar, i as createZip } from "./super-editor.es-Dz7y81Yr.es.js";
1
+ import { q as index, C as CommentsPluginKey, h as TrackChangesBasePluginKey, E as Editor, n as getRichTextExtensions, f as SuperInput, e as SuperEditor, A as AIWriter, g as SuperToolbar, i as createZip } from "./super-editor.es--RpCOiR4.es.js";
2
2
  import { a0 as effectScope, r as ref, _ as markRaw, $ as process$1, a1 as toRaw, d as computed, a2 as isRef, a3 as isReactive, C as toRef, i as inject, p as getCurrentInstance, l as watch, x as unref, a4 as hasInjectionContext, M as reactive, s as nextTick, a5 as getCurrentScope, a6 as onScopeDispose, a7 as toRefs, g as global$1, J as shallowRef, N as readonly, j as onMounted, k as onBeforeUnmount, h as onBeforeMount, S as onActivated, q as onDeactivated, z as createTextVNode, F as Fragment, Q as Comment, m as defineComponent, D as provide, H as withDirectives, B as h, U as Teleport, R as renderSlot, V as isVNode, I as watchEffect, O as Transition, a8 as TransitionGroup, E as mergeProps, P as vShow, G as cloneVNode, T as Text, c as createElementBlock, o as openBlock, t as toDisplayString, v as createVNode, y as withCtx, a as createBaseVNode, A as normalizeStyle, f as createCommentVNode, u as createBlock, w as withModifiers, n as normalizeClass, a9 as resolveDirective, e as renderList, b as createApp, X as resolveDynamicComponent, aa as defineAsyncComponent } from "./vue-ZWZLQtoU.es.js";
3
3
  import { B as BlankDOCX } from "./blank-docx-ABm6XYAA.es.js";
4
4
  import { E as EventEmitter } from "./eventemitter3-BWEnUdTY.es.js";
@@ -15319,69 +15319,6 @@ const superdocIcons = {
15319
15319
  rejectChange: xmarkIconSvg,
15320
15320
  overflow: ellipsisVerticalSvg
15321
15321
  };
15322
- const PERMISSIONS = Object.freeze({
15323
- RESOLVE_OWN: "RESOLVE_OWN",
15324
- RESOLVE_OTHER: "RESOLVE_OTHER",
15325
- REJECT_OWN: "REJECT_OWN",
15326
- REJECT_OTHER: "REJECT_OTHER",
15327
- COMMENTS_OVERFLOW_OWN: "COMMENTS_OVERFLOW",
15328
- COMMENTS_OVERFLOW_OTHER: "COMMENTS_OVERFLOW_OTHER",
15329
- COMMENTS_DELETE_OWN: "COMMENTS_DELETE_OWN",
15330
- COMMENTS_DELETE_OTHER: "COMMENTS_DELETE_OTHER",
15331
- UPLOAD_VERSION: "UPLOAD_VERSION",
15332
- VERSION_HISTORY: "VERSION_HISTORY"
15333
- });
15334
- const ROLES = Object.freeze({
15335
- EDITOR: "editor",
15336
- SUGGESTER: "suggester",
15337
- VIEWER: "viewer"
15338
- });
15339
- const permissions = Object.freeze({
15340
- [PERMISSIONS.RESOLVE_OWN]: {
15341
- internal: [ROLES.EDITOR],
15342
- external: [ROLES.EDITOR]
15343
- },
15344
- [PERMISSIONS.RESOLVE_OTHER]: {
15345
- internal: [ROLES.EDITOR],
15346
- external: []
15347
- },
15348
- [PERMISSIONS.REJECT_OWN]: {
15349
- internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15350
- external: [ROLES.EDITOR, ROLES.SUGGESTER]
15351
- },
15352
- [PERMISSIONS.REJECT_OTHER]: {
15353
- internal: [ROLES.EDITOR],
15354
- external: []
15355
- },
15356
- [PERMISSIONS.COMMENTS_OVERFLOW_OWN]: {
15357
- internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15358
- external: [ROLES.EDITOR, ROLES.SUGGESTER]
15359
- },
15360
- [PERMISSIONS.COMMENTS_OVERFLOW_OTHER]: {
15361
- internal: [ROLES.EDITOR],
15362
- external: []
15363
- },
15364
- [PERMISSIONS.COMMENTS_DELETE_OWN]: {
15365
- internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15366
- external: [ROLES.EDITOR, ROLES.SUGGESTER]
15367
- },
15368
- [PERMISSIONS.COMMENTS_DELETE_OTHER]: {
15369
- internal: [ROLES.EDITOR],
15370
- external: []
15371
- },
15372
- [PERMISSIONS.UPLOAD_VERSION]: {
15373
- internal: [ROLES.EDITOR],
15374
- external: []
15375
- },
15376
- [PERMISSIONS.VERSION_HISTORY]: {
15377
- internal: [ROLES.EDITOR],
15378
- external: []
15379
- }
15380
- });
15381
- const isAllowed = (permission, role, isInternal) => {
15382
- const internalExternal = isInternal ? "internal" : "external";
15383
- return permissions[permission]?.[internalExternal]?.includes(role);
15384
- };
15385
15322
  const _export_sfc = (sfc, props) => {
15386
15323
  const target = sfc.__vccOpts || sfc;
15387
15324
  for (const [key, val] of props) {
@@ -15537,6 +15474,96 @@ function formatDate(timestamp) {
15537
15474
  const formattedDate = `${formattedTime} ${month} ${day}`;
15538
15475
  return formattedDate;
15539
15476
  }
15477
+ const PERMISSIONS = Object.freeze({
15478
+ RESOLVE_OWN: "RESOLVE_OWN",
15479
+ RESOLVE_OTHER: "RESOLVE_OTHER",
15480
+ REJECT_OWN: "REJECT_OWN",
15481
+ REJECT_OTHER: "REJECT_OTHER",
15482
+ COMMENTS_OVERFLOW_OWN: "COMMENTS_OVERFLOW",
15483
+ COMMENTS_OVERFLOW_OTHER: "COMMENTS_OVERFLOW_OTHER",
15484
+ COMMENTS_DELETE_OWN: "COMMENTS_DELETE_OWN",
15485
+ COMMENTS_DELETE_OTHER: "COMMENTS_DELETE_OTHER",
15486
+ UPLOAD_VERSION: "UPLOAD_VERSION",
15487
+ VERSION_HISTORY: "VERSION_HISTORY"
15488
+ });
15489
+ const ROLES = Object.freeze({
15490
+ EDITOR: "editor",
15491
+ SUGGESTER: "suggester",
15492
+ VIEWER: "viewer"
15493
+ });
15494
+ const PERMISSION_MATRIX = Object.freeze({
15495
+ [PERMISSIONS.RESOLVE_OWN]: {
15496
+ internal: [ROLES.EDITOR],
15497
+ external: [ROLES.EDITOR]
15498
+ },
15499
+ [PERMISSIONS.RESOLVE_OTHER]: {
15500
+ internal: [ROLES.EDITOR],
15501
+ external: []
15502
+ },
15503
+ [PERMISSIONS.REJECT_OWN]: {
15504
+ internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15505
+ external: [ROLES.EDITOR, ROLES.SUGGESTER]
15506
+ },
15507
+ [PERMISSIONS.REJECT_OTHER]: {
15508
+ internal: [ROLES.EDITOR],
15509
+ external: []
15510
+ },
15511
+ [PERMISSIONS.COMMENTS_OVERFLOW_OWN]: {
15512
+ internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15513
+ external: [ROLES.EDITOR, ROLES.SUGGESTER]
15514
+ },
15515
+ [PERMISSIONS.COMMENTS_OVERFLOW_OTHER]: {
15516
+ internal: [ROLES.EDITOR],
15517
+ external: []
15518
+ },
15519
+ [PERMISSIONS.COMMENTS_DELETE_OWN]: {
15520
+ internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15521
+ external: [ROLES.EDITOR, ROLES.SUGGESTER]
15522
+ },
15523
+ [PERMISSIONS.COMMENTS_DELETE_OTHER]: {
15524
+ internal: [ROLES.EDITOR],
15525
+ external: []
15526
+ },
15527
+ [PERMISSIONS.UPLOAD_VERSION]: {
15528
+ internal: [ROLES.EDITOR],
15529
+ external: []
15530
+ },
15531
+ [PERMISSIONS.VERSION_HISTORY]: {
15532
+ internal: [ROLES.EDITOR],
15533
+ external: []
15534
+ }
15535
+ });
15536
+ const pickResolver = (context = {}) => {
15537
+ if (typeof context.permissionResolver === "function") return context.permissionResolver;
15538
+ if (context.superdoc?.config?.modules?.comments?.permissionResolver) {
15539
+ const resolver = context.superdoc.config.modules.comments.permissionResolver;
15540
+ if (typeof resolver === "function") return resolver;
15541
+ }
15542
+ if (typeof context.superdoc?.config?.permissionResolver === "function") {
15543
+ return context.superdoc.config.permissionResolver;
15544
+ }
15545
+ return null;
15546
+ };
15547
+ const defaultDecisionFor = (permission, role, isInternal) => {
15548
+ const internalExternal = isInternal ? "internal" : "external";
15549
+ return PERMISSION_MATRIX[permission]?.[internalExternal]?.includes(role) ?? false;
15550
+ };
15551
+ const isAllowed = (permission, role, isInternal, context = {}) => {
15552
+ const defaultDecision = defaultDecisionFor(permission, role, isInternal);
15553
+ const resolver = pickResolver(context);
15554
+ if (typeof resolver !== "function") return defaultDecision;
15555
+ const decision = resolver({
15556
+ permission,
15557
+ role,
15558
+ isInternal,
15559
+ defaultDecision,
15560
+ comment: context.comment ?? null,
15561
+ currentUser: context.currentUser ?? context.superdoc?.config?.user ?? null,
15562
+ superdoc: context.superdoc ?? null,
15563
+ trackedChange: context.trackedChange ?? null
15564
+ });
15565
+ return typeof decision === "boolean" ? decision : defaultDecision;
15566
+ };
15540
15567
  const _hoisted_1$d = { class: "card-section comment-header" };
15541
15568
  const _hoisted_2$7 = { class: "comment-header-left" };
15542
15569
  const _hoisted_3$5 = { class: "user-info" };
@@ -15593,14 +15620,30 @@ const _sfc_main$e = {
15593
15620
  const allowResolve = computed(() => {
15594
15621
  if (!generallyAllowed.value) return false;
15595
15622
  if (props.comment.parentCommentId) return false;
15596
- if (isOwnComment || props.comment.trackedChange) return isAllowed(PERMISSIONS.RESOLVE_OWN, role, isInternal);
15597
- else return isAllowed(PERMISSIONS.RESOLVE_OTHER, role, isInternal);
15623
+ const context = {
15624
+ comment: props.comment,
15625
+ currentUser: proxy.$superdoc.config.user,
15626
+ superdoc: proxy.$superdoc
15627
+ };
15628
+ if (isOwnComment || props.comment.trackedChange) {
15629
+ return isAllowed(PERMISSIONS.RESOLVE_OWN, role, isInternal, context);
15630
+ } else {
15631
+ return isAllowed(PERMISSIONS.RESOLVE_OTHER, role, isInternal, context);
15632
+ }
15598
15633
  });
15599
15634
  const allowReject = computed(() => {
15600
15635
  if (!generallyAllowed.value) return false;
15601
15636
  if (!props.comment.trackedChange) return false;
15602
- if (isOwnComment || props.comment.trackedChange) return isAllowed(PERMISSIONS.REJECT_OWN, role, isInternal);
15603
- else return isAllowed(PERMISSIONS.REJECT_OTHER, role, isInternal);
15637
+ const context = {
15638
+ comment: props.comment,
15639
+ currentUser: proxy.$superdoc.config.user,
15640
+ superdoc: proxy.$superdoc
15641
+ };
15642
+ if (isOwnComment || props.comment.trackedChange) {
15643
+ return isAllowed(PERMISSIONS.REJECT_OWN, role, isInternal, context);
15644
+ } else {
15645
+ return isAllowed(PERMISSIONS.REJECT_OTHER, role, isInternal, context);
15646
+ }
15604
15647
  });
15605
15648
  const allowOverflow = computed(() => {
15606
15649
  if (!generallyAllowed.value) return false;
@@ -15617,9 +15660,14 @@ const _sfc_main$e = {
15617
15660
  options.add("edit");
15618
15661
  }
15619
15662
  const isOwnComment2 = props.comment.creatorEmail === proxy.$superdoc.config.user.email;
15620
- if (isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OWN, role, isInternal)) {
15663
+ const context = {
15664
+ comment: props.comment,
15665
+ currentUser: proxy.$superdoc.config.user,
15666
+ superdoc: proxy.$superdoc
15667
+ };
15668
+ if (isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OWN, role, isInternal, context)) {
15621
15669
  options.add("delete");
15622
- } else if (!isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OTHER, role, isInternal)) {
15670
+ } else if (!isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OTHER, role, isInternal, context)) {
15623
15671
  options.add("delete");
15624
15672
  }
15625
15673
  options.forEach((option) => allowedOptions.push(OVERFLOW_OPTIONS[option]));
@@ -15682,7 +15730,7 @@ const _sfc_main$e = {
15682
15730
  };
15683
15731
  }
15684
15732
  };
15685
- const CommentHeader = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-27b7739c"]]);
15733
+ const CommentHeader = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-0f4f53ef"]]);
15686
15734
  const _hoisted_1$c = { class: "input-section" };
15687
15735
  const _sfc_main$d = {
15688
15736
  __name: "CommentInput",
@@ -16102,7 +16150,7 @@ const _sfc_main$c = {
16102
16150
  };
16103
16151
  }
16104
16152
  };
16105
- const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-e07f3426"]]);
16153
+ const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-36e5f63e"]]);
16106
16154
  const _hoisted_1$a = { class: "comments-list" };
16107
16155
  const _hoisted_2$5 = { key: 0 };
16108
16156
  const _hoisted_3$3 = { class: "comment-item" };
@@ -17099,7 +17147,7 @@ const _sfc_main = {
17099
17147
  __name: "SuperDoc",
17100
17148
  emits: ["selection-update"],
17101
17149
  setup(__props, { emit: __emit }) {
17102
- const PdfViewer = defineAsyncComponent(() => import("./PdfViewer-BiHh3x6b.es.js"));
17150
+ const PdfViewer = defineAsyncComponent(() => import("./PdfViewer-BEbvklge.es.js"));
17103
17151
  const superdocStore = useSuperdocStore();
17104
17152
  const commentsStore = useCommentsStore();
17105
17153
  const {
@@ -17321,7 +17369,12 @@ const _sfc_main = {
17321
17369
  externalExtensions: proxy.$superdoc.config.editorExtensions || [],
17322
17370
  suppressDefaultDocxStyles: proxy.$superdoc.config.suppressDefaultDocxStyles,
17323
17371
  disableContextMenu: proxy.$superdoc.config.disableContextMenu,
17324
- jsonOverride: proxy.$superdoc.config.jsonOverride
17372
+ jsonOverride: proxy.$superdoc.config.jsonOverride,
17373
+ permissionResolver: (payload = {}) => proxy.$superdoc.canPerformPermission({
17374
+ role: proxy.$superdoc.config.role,
17375
+ isInternal: proxy.$superdoc.config.isInternal,
17376
+ ...payload
17377
+ })
17325
17378
  };
17326
17379
  return options;
17327
17380
  };
@@ -17690,7 +17743,7 @@ const _sfc_main = {
17690
17743
  };
17691
17744
  }
17692
17745
  };
17693
- const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6de7ff3a"]]);
17746
+ const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ac4ea6eb"]]);
17694
17747
  const createSuperdocVueApp = () => {
17695
17748
  const app = createApp(App);
17696
17749
  const pinia = createPinia();
@@ -17785,6 +17838,8 @@ class SuperDoc extends EventEmitter {
17785
17838
  users: [],
17786
17839
  modules: {},
17787
17840
  // Optional: Modules to load. Use modules.ai.{your_key} to pass in your key
17841
+ permissionResolver: null,
17842
+ // Optional: Override for permission checks
17788
17843
  title: "SuperDoc",
17789
17844
  conversations: [],
17790
17845
  pagination: false,
@@ -17842,7 +17897,7 @@ class SuperDoc extends EventEmitter {
17842
17897
  this.config.colors = shuffleArray(this.config.colors);
17843
17898
  this.userColorMap = /* @__PURE__ */ new Map();
17844
17899
  this.colorIndex = 0;
17845
- this.version = "0.23.0";
17900
+ this.version = "0.24.0";
17846
17901
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
17847
17902
  this.superdocId = config.superdocId || v4();
17848
17903
  this.colors = this.config.colors;
@@ -18148,6 +18203,41 @@ class SuperDoc extends EventEmitter {
18148
18203
  }
18149
18204
  });
18150
18205
  }
18206
+ /**
18207
+ * Determine whether the current configuration allows a given permission.
18208
+ * Used by downstream consumers (toolbar, context menu, commands) to keep
18209
+ * tracked-change affordances consistent with customer overrides.
18210
+ *
18211
+ * @param {Object} params
18212
+ * @param {string} params.permission Permission key to evaluate
18213
+ * @param {string} [params.role=this.config.role] Role to evaluate against
18214
+ * @param {boolean} [params.isInternal=this.config.isInternal] Internal/external flag
18215
+ * @param {Object|null} [params.comment] Comment object (if already resolved)
18216
+ * @param {Object|null} [params.trackedChange] Tracked change metadata (id, attrs, etc.)
18217
+ * @returns {boolean}
18218
+ */
18219
+ canPerformPermission({
18220
+ permission,
18221
+ role = this.config.role,
18222
+ isInternal = this.config.isInternal,
18223
+ comment = null,
18224
+ trackedChange = null
18225
+ } = {}) {
18226
+ if (!permission) return false;
18227
+ let resolvedComment = comment ?? trackedChange?.comment ?? null;
18228
+ const commentId = trackedChange?.commentId || trackedChange?.id;
18229
+ if (!resolvedComment && commentId && this.commentsStore?.getComment) {
18230
+ const storeComment = this.commentsStore.getComment(commentId);
18231
+ resolvedComment = storeComment?.getValues ? storeComment.getValues() : storeComment;
18232
+ }
18233
+ const context = {
18234
+ superdoc: this,
18235
+ currentUser: this.config.user,
18236
+ comment: resolvedComment ?? null,
18237
+ trackedChange: trackedChange ?? null
18238
+ };
18239
+ return isAllowed(permission, role, isInternal, context);
18240
+ }
18151
18241
  #addToolbar() {
18152
18242
  const moduleConfig = this.config.modules?.toolbar || {};
18153
18243
  this.toolbarElement = this.config.modules?.toolbar?.selector || this.config.toolbar;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- const superEditor_es = require("./super-editor.es-BKZvTraR.cjs");
2
+ const superEditor_es = require("./super-editor.es-Bh07I_ue.cjs");
3
3
  const vue = require("./vue-DKMj1I9B.cjs");
4
4
  const blankDocx = require("./blank-docx-DfW3Eeh2.cjs");
5
5
  const eventemitter3 = require("./eventemitter3-DkXkH2rT.cjs");
@@ -15336,69 +15336,6 @@ const superdocIcons = {
15336
15336
  rejectChange: xmarkIconSvg,
15337
15337
  overflow: ellipsisVerticalSvg
15338
15338
  };
15339
- const PERMISSIONS = Object.freeze({
15340
- RESOLVE_OWN: "RESOLVE_OWN",
15341
- RESOLVE_OTHER: "RESOLVE_OTHER",
15342
- REJECT_OWN: "REJECT_OWN",
15343
- REJECT_OTHER: "REJECT_OTHER",
15344
- COMMENTS_OVERFLOW_OWN: "COMMENTS_OVERFLOW",
15345
- COMMENTS_OVERFLOW_OTHER: "COMMENTS_OVERFLOW_OTHER",
15346
- COMMENTS_DELETE_OWN: "COMMENTS_DELETE_OWN",
15347
- COMMENTS_DELETE_OTHER: "COMMENTS_DELETE_OTHER",
15348
- UPLOAD_VERSION: "UPLOAD_VERSION",
15349
- VERSION_HISTORY: "VERSION_HISTORY"
15350
- });
15351
- const ROLES = Object.freeze({
15352
- EDITOR: "editor",
15353
- SUGGESTER: "suggester",
15354
- VIEWER: "viewer"
15355
- });
15356
- const permissions = Object.freeze({
15357
- [PERMISSIONS.RESOLVE_OWN]: {
15358
- internal: [ROLES.EDITOR],
15359
- external: [ROLES.EDITOR]
15360
- },
15361
- [PERMISSIONS.RESOLVE_OTHER]: {
15362
- internal: [ROLES.EDITOR],
15363
- external: []
15364
- },
15365
- [PERMISSIONS.REJECT_OWN]: {
15366
- internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15367
- external: [ROLES.EDITOR, ROLES.SUGGESTER]
15368
- },
15369
- [PERMISSIONS.REJECT_OTHER]: {
15370
- internal: [ROLES.EDITOR],
15371
- external: []
15372
- },
15373
- [PERMISSIONS.COMMENTS_OVERFLOW_OWN]: {
15374
- internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15375
- external: [ROLES.EDITOR, ROLES.SUGGESTER]
15376
- },
15377
- [PERMISSIONS.COMMENTS_OVERFLOW_OTHER]: {
15378
- internal: [ROLES.EDITOR],
15379
- external: []
15380
- },
15381
- [PERMISSIONS.COMMENTS_DELETE_OWN]: {
15382
- internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15383
- external: [ROLES.EDITOR, ROLES.SUGGESTER]
15384
- },
15385
- [PERMISSIONS.COMMENTS_DELETE_OTHER]: {
15386
- internal: [ROLES.EDITOR],
15387
- external: []
15388
- },
15389
- [PERMISSIONS.UPLOAD_VERSION]: {
15390
- internal: [ROLES.EDITOR],
15391
- external: []
15392
- },
15393
- [PERMISSIONS.VERSION_HISTORY]: {
15394
- internal: [ROLES.EDITOR],
15395
- external: []
15396
- }
15397
- });
15398
- const isAllowed = (permission, role, isInternal) => {
15399
- const internalExternal = isInternal ? "internal" : "external";
15400
- return permissions[permission]?.[internalExternal]?.includes(role);
15401
- };
15402
15339
  const _export_sfc = (sfc, props) => {
15403
15340
  const target = sfc.__vccOpts || sfc;
15404
15341
  for (const [key, val] of props) {
@@ -15554,6 +15491,96 @@ function formatDate(timestamp) {
15554
15491
  const formattedDate = `${formattedTime} ${month} ${day}`;
15555
15492
  return formattedDate;
15556
15493
  }
15494
+ const PERMISSIONS = Object.freeze({
15495
+ RESOLVE_OWN: "RESOLVE_OWN",
15496
+ RESOLVE_OTHER: "RESOLVE_OTHER",
15497
+ REJECT_OWN: "REJECT_OWN",
15498
+ REJECT_OTHER: "REJECT_OTHER",
15499
+ COMMENTS_OVERFLOW_OWN: "COMMENTS_OVERFLOW",
15500
+ COMMENTS_OVERFLOW_OTHER: "COMMENTS_OVERFLOW_OTHER",
15501
+ COMMENTS_DELETE_OWN: "COMMENTS_DELETE_OWN",
15502
+ COMMENTS_DELETE_OTHER: "COMMENTS_DELETE_OTHER",
15503
+ UPLOAD_VERSION: "UPLOAD_VERSION",
15504
+ VERSION_HISTORY: "VERSION_HISTORY"
15505
+ });
15506
+ const ROLES = Object.freeze({
15507
+ EDITOR: "editor",
15508
+ SUGGESTER: "suggester",
15509
+ VIEWER: "viewer"
15510
+ });
15511
+ const PERMISSION_MATRIX = Object.freeze({
15512
+ [PERMISSIONS.RESOLVE_OWN]: {
15513
+ internal: [ROLES.EDITOR],
15514
+ external: [ROLES.EDITOR]
15515
+ },
15516
+ [PERMISSIONS.RESOLVE_OTHER]: {
15517
+ internal: [ROLES.EDITOR],
15518
+ external: []
15519
+ },
15520
+ [PERMISSIONS.REJECT_OWN]: {
15521
+ internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15522
+ external: [ROLES.EDITOR, ROLES.SUGGESTER]
15523
+ },
15524
+ [PERMISSIONS.REJECT_OTHER]: {
15525
+ internal: [ROLES.EDITOR],
15526
+ external: []
15527
+ },
15528
+ [PERMISSIONS.COMMENTS_OVERFLOW_OWN]: {
15529
+ internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15530
+ external: [ROLES.EDITOR, ROLES.SUGGESTER]
15531
+ },
15532
+ [PERMISSIONS.COMMENTS_OVERFLOW_OTHER]: {
15533
+ internal: [ROLES.EDITOR],
15534
+ external: []
15535
+ },
15536
+ [PERMISSIONS.COMMENTS_DELETE_OWN]: {
15537
+ internal: [ROLES.EDITOR, ROLES.SUGGESTER],
15538
+ external: [ROLES.EDITOR, ROLES.SUGGESTER]
15539
+ },
15540
+ [PERMISSIONS.COMMENTS_DELETE_OTHER]: {
15541
+ internal: [ROLES.EDITOR],
15542
+ external: []
15543
+ },
15544
+ [PERMISSIONS.UPLOAD_VERSION]: {
15545
+ internal: [ROLES.EDITOR],
15546
+ external: []
15547
+ },
15548
+ [PERMISSIONS.VERSION_HISTORY]: {
15549
+ internal: [ROLES.EDITOR],
15550
+ external: []
15551
+ }
15552
+ });
15553
+ const pickResolver = (context = {}) => {
15554
+ if (typeof context.permissionResolver === "function") return context.permissionResolver;
15555
+ if (context.superdoc?.config?.modules?.comments?.permissionResolver) {
15556
+ const resolver = context.superdoc.config.modules.comments.permissionResolver;
15557
+ if (typeof resolver === "function") return resolver;
15558
+ }
15559
+ if (typeof context.superdoc?.config?.permissionResolver === "function") {
15560
+ return context.superdoc.config.permissionResolver;
15561
+ }
15562
+ return null;
15563
+ };
15564
+ const defaultDecisionFor = (permission, role, isInternal) => {
15565
+ const internalExternal = isInternal ? "internal" : "external";
15566
+ return PERMISSION_MATRIX[permission]?.[internalExternal]?.includes(role) ?? false;
15567
+ };
15568
+ const isAllowed = (permission, role, isInternal, context = {}) => {
15569
+ const defaultDecision = defaultDecisionFor(permission, role, isInternal);
15570
+ const resolver = pickResolver(context);
15571
+ if (typeof resolver !== "function") return defaultDecision;
15572
+ const decision = resolver({
15573
+ permission,
15574
+ role,
15575
+ isInternal,
15576
+ defaultDecision,
15577
+ comment: context.comment ?? null,
15578
+ currentUser: context.currentUser ?? context.superdoc?.config?.user ?? null,
15579
+ superdoc: context.superdoc ?? null,
15580
+ trackedChange: context.trackedChange ?? null
15581
+ });
15582
+ return typeof decision === "boolean" ? decision : defaultDecision;
15583
+ };
15557
15584
  const _hoisted_1$d = { class: "card-section comment-header" };
15558
15585
  const _hoisted_2$7 = { class: "comment-header-left" };
15559
15586
  const _hoisted_3$5 = { class: "user-info" };
@@ -15610,14 +15637,30 @@ const _sfc_main$e = {
15610
15637
  const allowResolve = vue.computed(() => {
15611
15638
  if (!generallyAllowed.value) return false;
15612
15639
  if (props.comment.parentCommentId) return false;
15613
- if (isOwnComment || props.comment.trackedChange) return isAllowed(PERMISSIONS.RESOLVE_OWN, role, isInternal);
15614
- else return isAllowed(PERMISSIONS.RESOLVE_OTHER, role, isInternal);
15640
+ const context = {
15641
+ comment: props.comment,
15642
+ currentUser: proxy.$superdoc.config.user,
15643
+ superdoc: proxy.$superdoc
15644
+ };
15645
+ if (isOwnComment || props.comment.trackedChange) {
15646
+ return isAllowed(PERMISSIONS.RESOLVE_OWN, role, isInternal, context);
15647
+ } else {
15648
+ return isAllowed(PERMISSIONS.RESOLVE_OTHER, role, isInternal, context);
15649
+ }
15615
15650
  });
15616
15651
  const allowReject = vue.computed(() => {
15617
15652
  if (!generallyAllowed.value) return false;
15618
15653
  if (!props.comment.trackedChange) return false;
15619
- if (isOwnComment || props.comment.trackedChange) return isAllowed(PERMISSIONS.REJECT_OWN, role, isInternal);
15620
- else return isAllowed(PERMISSIONS.REJECT_OTHER, role, isInternal);
15654
+ const context = {
15655
+ comment: props.comment,
15656
+ currentUser: proxy.$superdoc.config.user,
15657
+ superdoc: proxy.$superdoc
15658
+ };
15659
+ if (isOwnComment || props.comment.trackedChange) {
15660
+ return isAllowed(PERMISSIONS.REJECT_OWN, role, isInternal, context);
15661
+ } else {
15662
+ return isAllowed(PERMISSIONS.REJECT_OTHER, role, isInternal, context);
15663
+ }
15621
15664
  });
15622
15665
  const allowOverflow = vue.computed(() => {
15623
15666
  if (!generallyAllowed.value) return false;
@@ -15634,9 +15677,14 @@ const _sfc_main$e = {
15634
15677
  options.add("edit");
15635
15678
  }
15636
15679
  const isOwnComment2 = props.comment.creatorEmail === proxy.$superdoc.config.user.email;
15637
- if (isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OWN, role, isInternal)) {
15680
+ const context = {
15681
+ comment: props.comment,
15682
+ currentUser: proxy.$superdoc.config.user,
15683
+ superdoc: proxy.$superdoc
15684
+ };
15685
+ if (isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OWN, role, isInternal, context)) {
15638
15686
  options.add("delete");
15639
- } else if (!isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OTHER, role, isInternal)) {
15687
+ } else if (!isOwnComment2 && isAllowed(PERMISSIONS.COMMENTS_DELETE_OTHER, role, isInternal, context)) {
15640
15688
  options.add("delete");
15641
15689
  }
15642
15690
  options.forEach((option) => allowedOptions.push(OVERFLOW_OPTIONS[option]));
@@ -15699,7 +15747,7 @@ const _sfc_main$e = {
15699
15747
  };
15700
15748
  }
15701
15749
  };
15702
- const CommentHeader = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-27b7739c"]]);
15750
+ const CommentHeader = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-0f4f53ef"]]);
15703
15751
  const _hoisted_1$c = { class: "input-section" };
15704
15752
  const _sfc_main$d = {
15705
15753
  __name: "CommentInput",
@@ -16119,7 +16167,7 @@ const _sfc_main$c = {
16119
16167
  };
16120
16168
  }
16121
16169
  };
16122
- const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-e07f3426"]]);
16170
+ const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["__scopeId", "data-v-36e5f63e"]]);
16123
16171
  const _hoisted_1$a = { class: "comments-list" };
16124
16172
  const _hoisted_2$5 = { key: 0 };
16125
16173
  const _hoisted_3$3 = { class: "comment-item" };
@@ -17116,7 +17164,7 @@ const _sfc_main = {
17116
17164
  __name: "SuperDoc",
17117
17165
  emits: ["selection-update"],
17118
17166
  setup(__props, { emit: __emit }) {
17119
- const PdfViewer = vue.defineAsyncComponent(() => Promise.resolve().then(() => require("./PdfViewer-qk_hITc5.cjs")));
17167
+ const PdfViewer = vue.defineAsyncComponent(() => Promise.resolve().then(() => require("./PdfViewer-CvksDDwi.cjs")));
17120
17168
  const superdocStore = useSuperdocStore();
17121
17169
  const commentsStore = useCommentsStore();
17122
17170
  const {
@@ -17338,7 +17386,12 @@ const _sfc_main = {
17338
17386
  externalExtensions: proxy.$superdoc.config.editorExtensions || [],
17339
17387
  suppressDefaultDocxStyles: proxy.$superdoc.config.suppressDefaultDocxStyles,
17340
17388
  disableContextMenu: proxy.$superdoc.config.disableContextMenu,
17341
- jsonOverride: proxy.$superdoc.config.jsonOverride
17389
+ jsonOverride: proxy.$superdoc.config.jsonOverride,
17390
+ permissionResolver: (payload = {}) => proxy.$superdoc.canPerformPermission({
17391
+ role: proxy.$superdoc.config.role,
17392
+ isInternal: proxy.$superdoc.config.isInternal,
17393
+ ...payload
17394
+ })
17342
17395
  };
17343
17396
  return options;
17344
17397
  };
@@ -17707,7 +17760,7 @@ const _sfc_main = {
17707
17760
  };
17708
17761
  }
17709
17762
  };
17710
- const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6de7ff3a"]]);
17763
+ const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ac4ea6eb"]]);
17711
17764
  const createSuperdocVueApp = () => {
17712
17765
  const app = vue.createApp(App);
17713
17766
  const pinia = createPinia();
@@ -17802,6 +17855,8 @@ class SuperDoc extends eventemitter3.EventEmitter {
17802
17855
  users: [],
17803
17856
  modules: {},
17804
17857
  // Optional: Modules to load. Use modules.ai.{your_key} to pass in your key
17858
+ permissionResolver: null,
17859
+ // Optional: Override for permission checks
17805
17860
  title: "SuperDoc",
17806
17861
  conversations: [],
17807
17862
  pagination: false,
@@ -17859,7 +17914,7 @@ class SuperDoc extends eventemitter3.EventEmitter {
17859
17914
  this.config.colors = shuffleArray(this.config.colors);
17860
17915
  this.userColorMap = /* @__PURE__ */ new Map();
17861
17916
  this.colorIndex = 0;
17862
- this.version = "0.23.0";
17917
+ this.version = "0.24.0";
17863
17918
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
17864
17919
  this.superdocId = config.superdocId || uuid.v4();
17865
17920
  this.colors = this.config.colors;
@@ -18165,6 +18220,41 @@ class SuperDoc extends eventemitter3.EventEmitter {
18165
18220
  }
18166
18221
  });
18167
18222
  }
18223
+ /**
18224
+ * Determine whether the current configuration allows a given permission.
18225
+ * Used by downstream consumers (toolbar, context menu, commands) to keep
18226
+ * tracked-change affordances consistent with customer overrides.
18227
+ *
18228
+ * @param {Object} params
18229
+ * @param {string} params.permission Permission key to evaluate
18230
+ * @param {string} [params.role=this.config.role] Role to evaluate against
18231
+ * @param {boolean} [params.isInternal=this.config.isInternal] Internal/external flag
18232
+ * @param {Object|null} [params.comment] Comment object (if already resolved)
18233
+ * @param {Object|null} [params.trackedChange] Tracked change metadata (id, attrs, etc.)
18234
+ * @returns {boolean}
18235
+ */
18236
+ canPerformPermission({
18237
+ permission,
18238
+ role = this.config.role,
18239
+ isInternal = this.config.isInternal,
18240
+ comment = null,
18241
+ trackedChange = null
18242
+ } = {}) {
18243
+ if (!permission) return false;
18244
+ let resolvedComment = comment ?? trackedChange?.comment ?? null;
18245
+ const commentId = trackedChange?.commentId || trackedChange?.id;
18246
+ if (!resolvedComment && commentId && this.commentsStore?.getComment) {
18247
+ const storeComment = this.commentsStore.getComment(commentId);
18248
+ resolvedComment = storeComment?.getValues ? storeComment.getValues() : storeComment;
18249
+ }
18250
+ const context = {
18251
+ superdoc: this,
18252
+ currentUser: this.config.user,
18253
+ comment: resolvedComment ?? null,
18254
+ trackedChange: trackedChange ?? null
18255
+ };
18256
+ return isAllowed(permission, role, isInternal, context);
18257
+ }
18168
18258
  #addToolbar() {
18169
18259
  const moduleConfig = this.config.modules?.toolbar || {};
18170
18260
  this.toolbarElement = this.config.modules?.toolbar?.selector || this.config.toolbar;