@select-org/select-post-builder 1.1.2 → 1.1.3

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.
@@ -2083,19 +2083,12 @@ validators$1.transitional = function transitional(validator2, version, message)
2083
2083
  }
2084
2084
  if (version && !deprecatedWarnings[opt]) {
2085
2085
  deprecatedWarnings[opt] = true;
2086
- console.warn(
2087
- formatMessage(
2088
- opt,
2089
- " has been deprecated since v" + version + " and will be removed in the near future"
2090
- )
2091
- );
2092
2086
  }
2093
2087
  return validator2 ? validator2(value, opt, opts) : true;
2094
2088
  };
2095
2089
  };
2096
2090
  validators$1.spelling = function spelling(correctSpelling) {
2097
2091
  return (value, opt) => {
2098
- console.warn(`${opt} is likely a misspelling of ${correctSpelling}`);
2099
2092
  return true;
2100
2093
  };
2101
2094
  };
@@ -3954,7 +3947,6 @@ const Toaster$1 = /* @__PURE__ */ React__namespace.default.forwardRef(function T
3954
3947
  setActualTheme("light");
3955
3948
  }
3956
3949
  } catch (e) {
3957
- console.error(e);
3958
3950
  }
3959
3951
  });
3960
3952
  }
@@ -4622,46 +4614,6 @@ const useAnalyticsLogEvent = () => {
4622
4614
  const { logEvent } = usePostBuilder();
4623
4615
  return logEvent;
4624
4616
  };
4625
- const PostBuilderProvider = ({
4626
- children,
4627
- apiBaseURL,
4628
- authToken,
4629
- toI18N,
4630
- i18nKeys,
4631
- logEvent
4632
- }) => {
4633
- const t = React.useCallback(
4634
- (key, fallback) => {
4635
- const message = toI18N(i18nKeys[key]);
4636
- if (message) return message;
4637
- return fallback || key;
4638
- },
4639
- [toI18N, i18nKeys]
4640
- );
4641
- const api = React.useMemo(() => {
4642
- const core2 = new CoreApi(apiBaseURL.core, authToken, toI18N);
4643
- const mfs = new MFSApi(apiBaseURL.mfs, authToken, toI18N);
4644
- const fileStore = new FilestoreApi(apiBaseURL.fileStore, authToken, toI18N);
4645
- core2.initApi();
4646
- mfs.initApi();
4647
- fileStore.initApi();
4648
- return {
4649
- core: core2,
4650
- mfs,
4651
- fileStore
4652
- };
4653
- }, [authToken, apiBaseURL, toI18N]);
4654
- const value = React.useMemo(() => {
4655
- return {
4656
- authToken,
4657
- t,
4658
- i18nKeys,
4659
- api,
4660
- logEvent
4661
- };
4662
- }, [authToken, t, i18nKeys, api, logEvent]);
4663
- return /* @__PURE__ */ jsxRuntime.jsx(PostBuilderContext.Provider, { value, children });
4664
- };
4665
4617
  function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
4666
4618
  return function handleEvent(event) {
4667
4619
  originalEventHandler?.(event);
@@ -5005,9 +4957,6 @@ function useControllableState({
5005
4957
  if (wasControlled !== isControlled) {
5006
4958
  const from = wasControlled ? "controlled" : "uncontrolled";
5007
4959
  const to = isControlled ? "controlled" : "uncontrolled";
5008
- console.warn(
5009
- `${caller} is changing from ${from} to ${to}. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.`
5010
- );
5011
4960
  }
5012
4961
  isControlledRef.current = isControlled;
5013
4962
  }, [isControlled, caller]);
@@ -8612,7 +8561,7 @@ const EditorTypeTabs = ({ editorTab, onSwitchEditorTab }) => {
8612
8561
  const { trackTabSwitch } = usePostBuilderAnalytics();
8613
8562
  const handleSwitchTab = (newTab) => {
8614
8563
  const oldTab = editorTab;
8615
- trackTabSwitch(oldTab, newTab);
8564
+ trackTabSwitch({ oldTab, newTab });
8616
8565
  onSwitchEditorTab(newTab);
8617
8566
  };
8618
8567
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -11334,7 +11283,6 @@ var correctTargets = function(parent2, targets) {
11334
11283
  if (correctedTarget && parent2.contains(correctedTarget)) {
11335
11284
  return correctedTarget;
11336
11285
  }
11337
- console.error("aria-hidden", target, "in not contained inside", parent2, ". Doing nothing");
11338
11286
  return null;
11339
11287
  }).filter(function(x2) {
11340
11288
  return Boolean(x2);
@@ -11383,7 +11331,6 @@ var applyAttributeToOthers = function(originalTarget, parentNode, markerName, co
11383
11331
  node.setAttribute(controlAttribute, "true");
11384
11332
  }
11385
11333
  } catch (e) {
11386
- console.error("aria-hidden: cannot operate on ", node, e);
11387
11334
  }
11388
11335
  }
11389
11336
  });
@@ -14021,15 +13968,11 @@ function requireUseSyncExternalStoreShim_development() {
14021
13968
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
14022
13969
  }
14023
13970
  function useSyncExternalStore$2(subscribe2, getSnapshot) {
14024
- didWarnOld18Alpha || void 0 === React2.startTransition || (didWarnOld18Alpha = true, console.error(
14025
- "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
14026
- ));
13971
+ didWarnOld18Alpha || void 0 === React2.startTransition || (didWarnOld18Alpha = true, void 0);
14027
13972
  var value = getSnapshot();
14028
13973
  if (!didWarnUncachedGetSnapshot) {
14029
13974
  var cachedValue = getSnapshot();
14030
- objectIs(value, cachedValue) || (console.error(
14031
- "The result of getSnapshot should be cached to avoid an infinite loop"
14032
- ), didWarnUncachedGetSnapshot = true);
13975
+ objectIs(value, cachedValue) || (void 0, didWarnUncachedGetSnapshot = true);
14033
13976
  }
14034
13977
  cachedValue = useState({
14035
13978
  inst: { value, getSnapshot }
@@ -14261,9 +14204,6 @@ const GroupSelector = ({ store }) => {
14261
14204
  setGroups(response.entries ?? []);
14262
14205
  }
14263
14206
  } catch (error) {
14264
- if (!cancelled) {
14265
- console.error("Failed to fetch groups:", error);
14266
- }
14267
14207
  } finally {
14268
14208
  if (!cancelled) {
14269
14209
  setIsLoading(false);
@@ -14912,7 +14852,7 @@ const ToolbarButton = React.forwardRef(
14912
14852
  const { trackFeature } = usePostBuilderAnalytics();
14913
14853
  const handleClick = (e) => {
14914
14854
  onClick?.(e);
14915
- if (id) trackFeature(id);
14855
+ if (id) trackFeature({ featureName: id });
14916
14856
  if (!editor) return;
14917
14857
  requestAnimationFrame(editor?.chain()?.focus);
14918
14858
  };
@@ -15216,7 +15156,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15216
15156
  React__namespace.useEffect(() => {
15217
15157
  if (titleId) {
15218
15158
  const hasTitle = document.getElementById(titleId);
15219
- if (!hasTitle) console.error(MESSAGE);
15159
+ if (!hasTitle) ;
15220
15160
  }
15221
15161
  }, [MESSAGE, titleId]);
15222
15162
  return null;
@@ -15229,7 +15169,7 @@ var DescriptionWarning = ({ contentRef, descriptionId }) => {
15229
15169
  const describedById = contentRef.current?.getAttribute("aria-describedby");
15230
15170
  if (descriptionId && describedById) {
15231
15171
  const hasDescription = document.getElementById(descriptionId);
15232
- if (!hasDescription) console.warn(MESSAGE);
15172
+ if (!hasDescription) ;
15233
15173
  }
15234
15174
  }, [MESSAGE, contentRef, descriptionId]);
15235
15175
  return null;
@@ -15615,7 +15555,6 @@ const InputGroupText = React.forwardRef(
15615
15555
  InputGroupText.displayName = "InputGroupText";
15616
15556
  const InputGroupInput = React.forwardRef(
15617
15557
  ({ className, ref: legacyRef, ...props }, ref) => {
15618
- console.log({ legacyRef });
15619
15558
  return /* @__PURE__ */ jsxRuntime.jsx(
15620
15559
  Input,
15621
15560
  {
@@ -16236,7 +16175,6 @@ const resolveUrlType = async (url) => {
16236
16175
  if (mime?.startsWith("video/")) return { type: MediaNodeTypes.Video, src: url };
16237
16176
  if (mime?.startsWith("audio/")) return { type: MediaNodeTypes.Audio, src: url };
16238
16177
  } catch (error) {
16239
- console.warn("HEAD request failed, falling back to mime detection:", error);
16240
16178
  }
16241
16179
  const ext = url.split(".").pop()?.toLowerCase();
16242
16180
  if (ext) {
@@ -16375,11 +16313,9 @@ const LinkDecoratorModal = ({
16375
16313
  setIsValid(isValid2);
16376
16314
  };
16377
16315
  const handleInsertLink = (link2, text22, uid2) => {
16378
- console.log("HANDLE INSERT LINK::", { link: link2, text: text22 });
16379
16316
  setIsLoading(true);
16380
16317
  let metadata;
16381
- core2?.resolveUrl(link2)?.then((res) => metadata = res)?.catch((err) => console.log(err))?.finally(() => {
16382
- console.log({ metadata });
16318
+ core2?.resolveUrl(link2)?.then((res) => metadata = res)?.catch((err) => void 0)?.finally(() => {
16383
16319
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
16384
16320
  setIsLoading(false);
16385
16321
  onInsertLink(link2, text22, uid2, previewPayload);
@@ -16391,12 +16327,10 @@ const LinkDecoratorModal = ({
16391
16327
  e.preventDefault();
16392
16328
  const isTextInput = textInputRef.current === e.target;
16393
16329
  if (isTextInput || hideTextInput) return handleInsertLink(link, text2, uid ?? void 0);
16394
- console.log("Enter", isTextInput);
16395
16330
  textInputRef?.current?.focus();
16396
16331
  }
16397
16332
  };
16398
16333
  React.useEffect(() => {
16399
- console.log({ defaultValues });
16400
16334
  if (!defaultValues?.link) return;
16401
16335
  const isValid2 = isValidUrl(defaultValues?.link);
16402
16336
  setIsValid(isValid2);
@@ -16405,7 +16339,6 @@ const LinkDecoratorModal = ({
16405
16339
  setLink(defaultValues?.link ?? "");
16406
16340
  setText(defaultValues?.text || "");
16407
16341
  }, [defaultValues]);
16408
- console.log("TEXT INSIDE LINK DECORATOR::", { isValid, text: text2 });
16409
16342
  return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { open, onOpenChange: handleOpenChange, children: [
16410
16343
  children ? /* @__PURE__ */ jsxRuntime.jsx(DialogTrigger, { asChild: true, children }) : null,
16411
16344
  /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { className: "-translate-1/2", children: [
@@ -16590,10 +16523,8 @@ function parseThreshold(scrollThreshold) {
16590
16523
  value: parseFloat(scrollThreshold)
16591
16524
  };
16592
16525
  }
16593
- console.warn('scrollThreshold format is invalid. Valid formats: "120px", "50%"...');
16594
16526
  return defaultThreshold;
16595
16527
  }
16596
- console.warn("scrollThreshold should be string or number");
16597
16528
  return defaultThreshold;
16598
16529
  }
16599
16530
  var InfiniteScroll = (
@@ -16615,7 +16546,6 @@ var InfiniteScroll = (
16615
16546
  return document.getElementById(_this.props.scrollableTarget);
16616
16547
  }
16617
16548
  if (_this.props.scrollableTarget === null) {
16618
- console.warn("You are trying to pass scrollableTarget but it is null. This might\n happen because the element may not have been added to DOM yet.\n See https://github.com/ankeetmaini/react-infinite-scroll-component/issues/59 for more info.\n ");
16619
16549
  }
16620
16550
  return null;
16621
16551
  };
@@ -16860,7 +16790,6 @@ function useMediaSearch(type) {
16860
16790
  setItems((prev) => reset2 ? data : [...prev, ...data]);
16861
16791
  }
16862
16792
  } catch (error) {
16863
- console.error("Error fetching images:", error);
16864
16793
  pagination.setHasMore(false);
16865
16794
  } finally {
16866
16795
  pagination.setLoading(false);
@@ -16879,7 +16808,6 @@ function useMediaSearch(type) {
16879
16808
  setItems((prev) => reset2 ? data : [...prev, ...data]);
16880
16809
  }
16881
16810
  } catch (error) {
16882
- console.error("Error fetching gifs:", error);
16883
16811
  pagination.setHasMore(false);
16884
16812
  } finally {
16885
16813
  pagination.setLoading(false);
@@ -18454,8 +18382,8 @@ function ImageSearchModal({
18454
18382
  setSearchQuery("");
18455
18383
  return;
18456
18384
  }
18457
- gifSearch.fetch(withInitialQuery).catch((err) => console.log(err));
18458
- imageSearch.fetch(withInitialQuery).catch((err) => console.log(err));
18385
+ gifSearch.fetch(withInitialQuery).catch((err) => void 0);
18386
+ imageSearch.fetch(withInitialQuery).catch((err) => void 0);
18459
18387
  };
18460
18388
  const debouncedSearch = React.useMemo(
18461
18389
  () => debounce$2(async (query) => {
@@ -18473,7 +18401,7 @@ function ImageSearchModal({
18473
18401
  const handleSearch = React.useCallback(
18474
18402
  (query) => {
18475
18403
  setSearchQuery(query);
18476
- debouncedSearch(query)?.catch((err) => console.log(err));
18404
+ debouncedSearch(query)?.catch((err) => void 0);
18477
18405
  },
18478
18406
  [debouncedSearch]
18479
18407
  );
@@ -20427,7 +20355,9 @@ const Toolbar = ({
20427
20355
  };
20428
20356
  const handleImageClick = (imageUrl, searchFrom) => {
20429
20357
  if (searchFrom) {
20430
- trackFeature(searchFrom === ImageSearchFrom.Gif ? "gif_search" : "image_search");
20358
+ trackFeature({
20359
+ featureName: searchFrom === ImageSearchFrom.Gif ? "gif_search" : "image_search"
20360
+ });
20431
20361
  }
20432
20362
  editor?.commands.insertMediaWithUpload({
20433
20363
  source: imageUrl,
@@ -20840,6 +20770,79 @@ const Toolbar = ({
20840
20770
  ] });
20841
20771
  };
20842
20772
  const VerticalSeparator = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3 w-px bg-border" });
20773
+ var PostBuilderEvents = /* @__PURE__ */ ((PostBuilderEvents2) => {
20774
+ PostBuilderEvents2["POST_PUBLISH_ATTEMPTED"] = "select:post_publish_attempted";
20775
+ PostBuilderEvents2["POST_PUBLISH_SUCCESSFUL"] = "select:post_publish_success";
20776
+ PostBuilderEvents2["POST_PUBLISH_FAILED"] = "select:post_publish_failed";
20777
+ return PostBuilderEvents2;
20778
+ })(PostBuilderEvents || {});
20779
+ const useHostAnalyticsBridge = () => {
20780
+ const analytics = usePostBuilderAnalytics();
20781
+ const sessionIdRef = React.useRef(null);
20782
+ const processedRequestIds = React.useRef(/* @__PURE__ */ new Set());
20783
+ React.useEffect(() => {
20784
+ const onPublishSuccess = (e) => {
20785
+ const { postId, postType, groupId, failureReason } = e.detail;
20786
+ if (!postId || processedRequestIds.current.has(postId)) return;
20787
+ processedRequestIds.current.add(postId);
20788
+ analytics.trackPublish({
20789
+ sessionId: sessionIdRef.current ?? analytics.currentSessionId,
20790
+ status: "success",
20791
+ postId,
20792
+ groupId,
20793
+ postType,
20794
+ failureReason
20795
+ });
20796
+ sessionIdRef.current = null;
20797
+ };
20798
+ const onPublishFailed = (e) => {
20799
+ const { postId, postType, groupId, failureReason } = e.detail;
20800
+ if (!postId || processedRequestIds.current.has(postId)) return;
20801
+ processedRequestIds.current.add(postId);
20802
+ analytics.trackPublish({
20803
+ sessionId: sessionIdRef.current ?? analytics.currentSessionId,
20804
+ status: "failed",
20805
+ postId,
20806
+ groupId,
20807
+ postType,
20808
+ failureReason
20809
+ });
20810
+ sessionIdRef.current = null;
20811
+ };
20812
+ const lockSession = () => {
20813
+ if (!sessionIdRef.current) {
20814
+ sessionIdRef.current = analytics.currentSessionId;
20815
+ }
20816
+ };
20817
+ window.addEventListener(
20818
+ PostBuilderEvents.POST_PUBLISH_SUCCESSFUL,
20819
+ onPublishSuccess
20820
+ );
20821
+ window.addEventListener(
20822
+ PostBuilderEvents.POST_PUBLISH_FAILED,
20823
+ onPublishFailed
20824
+ );
20825
+ const handlePublishAttempt = () => lockSession();
20826
+ window.addEventListener(
20827
+ PostBuilderEvents.POST_PUBLISH_ATTEMPTED,
20828
+ handlePublishAttempt
20829
+ );
20830
+ return () => {
20831
+ window.removeEventListener(
20832
+ PostBuilderEvents.POST_PUBLISH_SUCCESSFUL,
20833
+ onPublishSuccess
20834
+ );
20835
+ window.removeEventListener(
20836
+ PostBuilderEvents.POST_PUBLISH_FAILED,
20837
+ onPublishFailed
20838
+ );
20839
+ window.removeEventListener(
20840
+ PostBuilderEvents.POST_PUBLISH_ATTEMPTED,
20841
+ handlePublishAttempt
20842
+ );
20843
+ };
20844
+ }, [analytics]);
20845
+ };
20843
20846
  const usePersistence = () => {
20844
20847
  const saveCurrentTabContent = (editorType, editor) => {
20845
20848
  if (typeof window === "undefined" || typeof localStorage === "undefined" || !editor || editor.isEmpty)
@@ -21096,11 +21099,9 @@ var Progress$1 = React__namespace.forwardRef(
21096
21099
  ...progressProps
21097
21100
  } = props;
21098
21101
  if ((maxProp || maxProp === 0) && !isValidMaxNumber(maxProp)) {
21099
- console.error(getInvalidMaxError(`${maxProp}`, "Progress"));
21100
21102
  }
21101
21103
  const max2 = isValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;
21102
21104
  if (valueProp !== null && !isValidValueNumber(valueProp, max2)) {
21103
- console.error(getInvalidValueError(`${valueProp}`, "Progress"));
21104
21105
  }
21105
21106
  const value = isValidValueNumber(valueProp, max2) ? valueProp : null;
21106
21107
  const valueLabel = isNumber(value) ? getValueLabel(value, max2) : void 0;
@@ -21420,13 +21421,7 @@ const createUpdateMarkByUidCommand = (markName) => {
21420
21421
  state: state2,
21421
21422
  dispatch
21422
21423
  }) => {
21423
- console.log("=== UPDATE MARK COMMAND START ===");
21424
- console.log("markName:", markName);
21425
- console.log("uid:", uid);
21426
- console.log("attrs:", attrs);
21427
- console.log("state.doc:", state2.doc.toJSON());
21428
21424
  if (!dispatch) {
21429
- console.log("No dispatch, returning false");
21430
21425
  return false;
21431
21426
  }
21432
21427
  const { doc, schema } = state2;
@@ -21436,13 +21431,6 @@ const createUpdateMarkByUidCommand = (markName) => {
21436
21431
  doc.descendants((node, pos) => {
21437
21432
  if (node.isText && node.marks?.length) {
21438
21433
  node.marks.forEach((mark) => {
21439
- console.log("Checking mark:", {
21440
- markType: mark.type.name,
21441
- markUid: mark.attrs.uid,
21442
- targetMarkName: markName,
21443
- targetUid: uid,
21444
- matches: mark.type.name === markName && mark.attrs.uid === uid
21445
- });
21446
21434
  if (mark.type.name === markName && mark.attrs.uid === uid) {
21447
21435
  positions.push({
21448
21436
  from: pos,
@@ -21450,33 +21438,21 @@ const createUpdateMarkByUidCommand = (markName) => {
21450
21438
  mark
21451
21439
  });
21452
21440
  found2 = true;
21453
- console.log("Found matching mark at:", { from: pos, to: pos + node.nodeSize });
21454
21441
  }
21455
21442
  });
21456
21443
  }
21457
21444
  });
21458
- console.log("Total positions found:", positions.length);
21459
- console.log("Positions:", positions);
21460
21445
  if (found2) {
21461
21446
  positions.forEach(({ from, to, mark }) => {
21462
21447
  const newAttrs = { ...mark.attrs, ...attrs };
21463
21448
  const markType = schema.marks[markName];
21464
- console.log("Applying update:", { from, to, oldAttrs: mark.attrs, newAttrs });
21465
21449
  if (markType) {
21466
- console.log("Before removeMark - tr.doc:", tr.doc.toJSON());
21467
21450
  tr = tr.removeMark(from, to, markType);
21468
- console.log("After removeMark - tr.doc:", tr.doc.toJSON());
21469
21451
  tr = tr.addMark(from, to, markType.create(newAttrs));
21470
- console.log("After addMark - tr.doc:", tr.doc.toJSON());
21471
21452
  }
21472
21453
  });
21473
- console.log("About to dispatch transaction");
21474
- console.log("Final tr.doc:", tr.doc.toJSON());
21475
- console.log("Original state.doc:", state2.doc.toJSON());
21476
21454
  dispatch(tr);
21477
- console.log("Transaction dispatched successfully");
21478
21455
  }
21479
- console.log("=== UPDATE MARK COMMAND END ===");
21480
21456
  return found2;
21481
21457
  };
21482
21458
  };
@@ -22494,7 +22470,6 @@ let warnedAboutTextSelection = false;
22494
22470
  function checkTextSelection($pos) {
22495
22471
  if (!warnedAboutTextSelection && !$pos.parent.inlineContent) {
22496
22472
  warnedAboutTextSelection = true;
22497
- console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")");
22498
22473
  }
22499
22474
  }
22500
22475
  class TextSelection extends Selection {
@@ -23219,7 +23194,6 @@ const PollCreator = ({ choices, onChange }) => {
23219
23194
  const result = await fileStore.uploadImage(file);
23220
23195
  return createPollMediaOption(result, startIndex + index2);
23221
23196
  } catch (error) {
23222
- console.error("Upload failed for", file.name, error);
23223
23197
  return null;
23224
23198
  }
23225
23199
  });
@@ -23239,7 +23213,6 @@ const PollCreator = ({ choices, onChange }) => {
23239
23213
  return final;
23240
23214
  });
23241
23215
  } catch (error) {
23242
- console.error("Unexpected error during file upload:", error);
23243
23216
  setInternalChoices((current) => {
23244
23217
  const withoutPlaceholders = current.filter((c) => !isPlaceholder(c));
23245
23218
  setTimeout(() => {
@@ -23272,7 +23245,6 @@ const PollCreator = ({ choices, onChange }) => {
23272
23245
  return updated;
23273
23246
  });
23274
23247
  } catch (error) {
23275
- console.error("URL upload failed:", error);
23276
23248
  setInternalChoices((current) => {
23277
23249
  const withoutPlaceholder = current.filter((c) => !isPlaceholder(c));
23278
23250
  setTimeout(() => {
@@ -23813,7 +23785,6 @@ const LinkMarkView = ({ mark, editor }) => {
23813
23785
  };
23814
23786
  const handleUpdateLink = (link, text2, uid, previewPayload) => {
23815
23787
  if (!editor.view) return;
23816
- console.log("UPDATE LINK IN VIEW::", { text: text2 });
23817
23788
  const newText = mark?.attrs?.isLinkMode ? link : text2 || link;
23818
23789
  if (uid) {
23819
23790
  editor.commands.updateLink(uid, { href: link, text: newText, previewPayload });
@@ -23873,25 +23844,66 @@ const LinkMarkView = ({ mark, editor }) => {
23873
23844
  )
23874
23845
  ] });
23875
23846
  };
23847
+ function isValidUrlFormat(text2) {
23848
+ return isValidUrl(normalizeUrl(text2.trim()));
23849
+ }
23876
23850
  function doesPreviewExist(editor, uid) {
23877
- let exists = false;
23878
- editor.state.doc.descendants((node) => {
23879
- if (node.type.name === "linkPreview" && node.attrs.uid === uid) {
23880
- exists = true;
23881
- return false;
23882
- }
23883
- });
23884
- return exists;
23851
+ if (!editor || !uid) {
23852
+ return false;
23853
+ }
23854
+ try {
23855
+ let exists = false;
23856
+ editor.state.doc.descendants((node) => {
23857
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23858
+ exists = true;
23859
+ return false;
23860
+ }
23861
+ });
23862
+ return exists;
23863
+ } catch (err) {
23864
+ return false;
23865
+ }
23885
23866
  }
23886
23867
  function findExistingPreview(editor) {
23887
- let result = null;
23888
- editor.state.doc.descendants((node, pos) => {
23889
- if (node.type.name === "linkPreview") {
23890
- result = { node, pos };
23891
- return false;
23868
+ if (!editor) {
23869
+ return null;
23870
+ }
23871
+ try {
23872
+ let result = null;
23873
+ editor.state.doc.descendants((node, pos) => {
23874
+ if (node && node.type && node.type.name === "linkPreview") {
23875
+ result = { node, pos };
23876
+ return false;
23877
+ }
23878
+ });
23879
+ return result;
23880
+ } catch (err) {
23881
+ return null;
23882
+ }
23883
+ }
23884
+ function removePreviewByUid(editor, uid) {
23885
+ if (!editor || !uid) {
23886
+ return;
23887
+ }
23888
+ try {
23889
+ let previewPos = null;
23890
+ let previewSize = 0;
23891
+ editor.state.doc.descendants((node, pos) => {
23892
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23893
+ previewPos = pos;
23894
+ previewSize = node.nodeSize;
23895
+ return false;
23896
+ }
23897
+ });
23898
+ if (previewPos !== null && previewSize > 0) {
23899
+ const tr = editor.state.tr;
23900
+ if (tr) {
23901
+ tr.delete(previewPos, Number(previewPos) + previewSize);
23902
+ editor.view.dispatch(tr);
23903
+ }
23892
23904
  }
23893
- });
23894
- return result;
23905
+ } catch (err) {
23906
+ }
23895
23907
  }
23896
23908
  function extractBestImage(metadata) {
23897
23909
  return metadata?.image?.high_resolution ?? metadata?.image?.url ?? metadata?.image?.thumbnail ?? metadata?.image?.placeholder ?? null;
@@ -23916,6 +23928,76 @@ function collectAllLinkMarks(state2, linkMark) {
23916
23928
  });
23917
23929
  return links;
23918
23930
  }
23931
+ function syncLinkHrefWithText(newState, linkMark, editor, singlePreviewMode, pluginState) {
23932
+ if (!newState || !linkMark || !editor || !pluginState) {
23933
+ return null;
23934
+ }
23935
+ let tr = null;
23936
+ let hasChanges = false;
23937
+ try {
23938
+ newState.doc.descendants((node, pos) => {
23939
+ if (!node || !node.isText || !node.marks?.length) return;
23940
+ node.marks.forEach((mark) => {
23941
+ if (!mark || !mark.type || !mark.attrs) return;
23942
+ if (mark.type === linkMark && mark.attrs?.uid) {
23943
+ const currentText = node.text || "";
23944
+ const currentHref = mark.attrs.href || "";
23945
+ if (currentText !== currentHref) {
23946
+ const isValidUrl2 = isValidUrlFormat(currentText);
23947
+ if (!tr) {
23948
+ tr = newState.tr;
23949
+ }
23950
+ if (!tr) {
23951
+ return;
23952
+ }
23953
+ if (isValidUrl2) {
23954
+ const newMark = linkMark.create({
23955
+ ...mark.attrs,
23956
+ href: normalizeUrl(currentText)
23957
+ });
23958
+ if (!newMark) {
23959
+ return;
23960
+ }
23961
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23962
+ tr = tr.addMark(pos, pos + node.nodeSize, newMark);
23963
+ hasChanges = true;
23964
+ pluginState.processedLinks.delete(mark.attrs.uid);
23965
+ if (singlePreviewMode) {
23966
+ queueMicrotask(() => {
23967
+ try {
23968
+ const existingPreview = findExistingPreview(editor);
23969
+ if (existingPreview && mark.attrs?.uid) {
23970
+ }
23971
+ } catch (err) {
23972
+ }
23973
+ });
23974
+ } else {
23975
+ }
23976
+ } else {
23977
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23978
+ hasChanges = true;
23979
+ queueMicrotask(() => {
23980
+ try {
23981
+ if (mark.attrs?.uid) {
23982
+ removePreviewByUid(editor, mark.attrs.uid);
23983
+ }
23984
+ } catch (err) {
23985
+ }
23986
+ });
23987
+ if (mark.attrs?.uid) {
23988
+ pluginState.processedLinks.delete(mark.attrs.uid);
23989
+ pluginState.resolvingLinks.delete(mark.attrs.uid);
23990
+ }
23991
+ }
23992
+ }
23993
+ }
23994
+ });
23995
+ });
23996
+ } catch (err) {
23997
+ return null;
23998
+ }
23999
+ return hasChanges ? tr : null;
24000
+ }
23919
24001
  function assignUidsToLinks(newState, linkMark) {
23920
24002
  const newUids = /* @__PURE__ */ new Map();
23921
24003
  let tr = null;
@@ -23925,11 +24007,6 @@ function assignUidsToLinks(newState, linkMark) {
23925
24007
  node.marks.forEach((mark) => {
23926
24008
  if (mark.type === linkMark && mark.attrs?.href && !mark.attrs.uid) {
23927
24009
  const newUid = v4();
23928
- console.log("🔧 Assigning UID to autolinked URL:", {
23929
- href: mark.attrs.href,
23930
- uid: newUid,
23931
- pos
23932
- });
23933
24010
  const newMark = linkMark.create({
23934
24011
  ...mark.attrs,
23935
24012
  uid: newUid
@@ -23956,25 +24033,14 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23956
24033
  const { api, editor } = options;
23957
24034
  const mediaGroup = findByType(editor?.getJSON(), "mediaGroup");
23958
24035
  if (!api) {
23959
- console.warn("⚠️ No API provided to resolve link");
23960
24036
  return;
23961
24037
  }
23962
24038
  if (singlePreviewMode && mediaGroup.length >= 1) return;
23963
24039
  pluginState.resolvingLinks.add(link.uid);
23964
- console.log("🌐 Resolving link metadata:", {
23965
- uid: link.uid,
23966
- href: link.href,
23967
- singlePreviewMode
23968
- });
23969
24040
  api.resolveUrl(normalizeUrl(link.href)).then((metadata) => {
23970
24041
  pluginState.resolvingLinks.delete(link.uid);
23971
24042
  pluginState.processedLinks.add(link.uid);
23972
- console.log("✅ Link metadata resolved:", {
23973
- uid: link.uid,
23974
- metadata
23975
- });
23976
24043
  if (!metadata) {
23977
- console.warn("⚠️ No metadata returned for:", link.href);
23978
24044
  return;
23979
24045
  }
23980
24046
  const previewData = {
@@ -23989,13 +24055,11 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23989
24055
  if (singlePreviewMode) {
23990
24056
  const existingPreview = findExistingPreview(editor);
23991
24057
  if (existingPreview) {
23992
- console.log("🔄 Updating existing preview in single mode");
23993
24058
  const { pos } = existingPreview;
23994
24059
  const tr = editor.state.tr;
23995
24060
  tr.setNodeMarkup(pos, void 0, previewData);
23996
24061
  editor.view.dispatch(tr);
23997
24062
  } else {
23998
- console.log("➕ Creating first preview in single mode");
23999
24063
  editor.commands.setLinkPreview(previewData);
24000
24064
  }
24001
24065
  editor.commands.updateLinkByUid(link.uid, {
@@ -24003,16 +24067,12 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
24003
24067
  });
24004
24068
  } else {
24005
24069
  if (!doesPreviewExist(editor, link.uid)) {
24006
- console.log("➕ Creating new preview in multi mode");
24007
24070
  editor.chain().updateLinkByUid(link.uid, {
24008
24071
  previewPayload: convertLinkMetaToPreviewItem(metadata)
24009
24072
  }).setLinkPreview(previewData).run();
24010
- } else {
24011
- console.log("⏭️ Preview already exists, skipping");
24012
24073
  }
24013
24074
  }
24014
24075
  }).catch((err) => {
24015
- console.error("❌ Failed to resolve link:", err);
24016
24076
  pluginState.resolvingLinks.delete(link.uid);
24017
24077
  });
24018
24078
  }
@@ -24022,10 +24082,6 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24022
24082
  key: pluginKey,
24023
24083
  state: {
24024
24084
  init() {
24025
- console.log("🔌 LinkAutoResolve plugin initialized", {
24026
- singlePreviewMode,
24027
- hasApi: !!options.api
24028
- });
24029
24085
  return {
24030
24086
  resolvingLinks: /* @__PURE__ */ new Set(),
24031
24087
  processedLinks: /* @__PURE__ */ new Set()
@@ -24055,27 +24111,22 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24055
24111
  appendTransaction: (transactions, oldState, newState) => {
24056
24112
  const linkMark = newState.schema.marks["customLink"];
24057
24113
  if (!linkMark) {
24058
- console.warn("⚠️ customLink mark not found in schema");
24059
24114
  return null;
24060
24115
  }
24061
24116
  if (!transactions.some((tr) => tr.docChanged)) {
24062
24117
  return null;
24063
24118
  }
24064
- console.log("📝 Document changed, checking for new links...");
24065
24119
  const pluginState = pluginKey.getState(newState);
24120
+ if (!pluginState) {
24121
+ return null;
24122
+ }
24123
+ const syncTr = singlePreviewMode ? syncLinkHrefWithText(newState, linkMark, options.editor, singlePreviewMode, pluginState) : null;
24066
24124
  const oldLinks = collectAllLinkMarks(oldState, linkMark);
24067
24125
  const newLinks = collectAllLinkMarks(newState, linkMark);
24068
- console.log("📊 Link count:", {
24069
- old: oldLinks.size,
24070
- new: newLinks.size,
24071
- processed: pluginState.processedLinks.size,
24072
- resolving: pluginState.resolvingLinks.size
24073
- });
24074
24126
  const { tr: uidTr, newUids } = assignUidsToLinks(newState, linkMark);
24075
24127
  const linksToResolve = [];
24076
24128
  newUids.forEach((linkData) => {
24077
24129
  if (!pluginState.processedLinks.has(linkData.uid) && !pluginState.resolvingLinks.has(linkData.uid)) {
24078
- console.log("🆕 New autolinked URL detected:", linkData);
24079
24130
  linksToResolve.push(linkData);
24080
24131
  }
24081
24132
  });
@@ -24088,21 +24139,33 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24088
24139
  return;
24089
24140
  }
24090
24141
  if (!oldLinks.has(uid)) {
24091
- console.log("🆕 New link detected (with UID):", linkData);
24092
24142
  linksToResolve.push(linkData);
24093
24143
  }
24094
24144
  });
24095
24145
  if (linksToResolve.length > 0) {
24096
- console.log("🚀 Processing", linksToResolve.length, "new link(s)");
24097
24146
  queueMicrotask(() => {
24098
24147
  linksToResolve.forEach((link) => {
24099
24148
  resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginState);
24100
24149
  });
24101
24150
  });
24102
- } else {
24103
- console.log("✓ No new links to process");
24104
24151
  }
24105
- return uidTr;
24152
+ if (syncTr && uidTr) {
24153
+ try {
24154
+ uidTr.steps.forEach((step, i) => {
24155
+ if (step && syncTr) {
24156
+ syncTr.step(step);
24157
+ const map = uidTr.mapping.maps[i];
24158
+ if (map) {
24159
+ syncTr.mapping.appendMap(map);
24160
+ }
24161
+ }
24162
+ });
24163
+ return syncTr;
24164
+ } catch (err) {
24165
+ return syncTr;
24166
+ }
24167
+ }
24168
+ return syncTr ?? uidTr ?? null;
24106
24169
  }
24107
24170
  });
24108
24171
  }
@@ -24198,7 +24261,6 @@ const CustomLink = Link__default.default.extend({
24198
24261
  this?.options?.api?.resolveUrl(normalizeUrl(href))?.then((metadata) => {
24199
24262
  if (metadata) {
24200
24263
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24201
- console.log({ href, text: text2 });
24202
24264
  editor?.chain()?.updateLinkByUid(uid, { href, text: text2, previewPayload })?.updateLinkPreviewByUid(uid, {
24203
24265
  // Now using correct UID
24204
24266
  loading: false,
@@ -24257,7 +24319,6 @@ const CustomLink = Link__default.default.extend({
24257
24319
  if (attrs.href) {
24258
24320
  queueMicrotask(() => {
24259
24321
  this.options.api?.resolveUrl(normalizeUrl(attrs.href))?.then((metadata) => {
24260
- console.log({ metadata });
24261
24322
  if (metadata) {
24262
24323
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24263
24324
  let linkPreviewExists = false;
@@ -24286,7 +24347,6 @@ const CustomLink = Link__default.default.extend({
24286
24347
  editor.commands.deleteLinkPreviewByUid(uid);
24287
24348
  }
24288
24349
  }).catch((err) => {
24289
- console.log("LINK UPDATE ERR::", { err });
24290
24350
  editor.commands.deleteLinkPreviewByUid(uid);
24291
24351
  });
24292
24352
  });
@@ -24366,7 +24426,6 @@ const IframeView = ({
24366
24426
  setPreviewData(previewPayload);
24367
24427
  updateAttributes({ previewPayload });
24368
24428
  }).catch((error) => {
24369
- console.error("Failed to fetch preview:", error);
24370
24429
  }).finally(() => {
24371
24430
  });
24372
24431
  }
@@ -24611,7 +24670,6 @@ const _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTyp
24611
24670
  }
24612
24671
  });
24613
24672
  } catch (_) {
24614
- console.warn("TrustedTypes policy " + policyName + " could not be created.");
24615
24673
  return null;
24616
24674
  }
24617
24675
  };
@@ -25448,7 +25506,6 @@ const configureDOMPurify = () => {
25448
25506
  const element = node;
25449
25507
  const src = element.getAttribute("src") || "";
25450
25508
  if (!isAllowedDomain(src)) {
25451
- console.warn("🚨 Blocked iframe from non-allowed domain:", src);
25452
25509
  node.parentNode?.removeChild(node);
25453
25510
  }
25454
25511
  }
@@ -25460,7 +25517,6 @@ function sanitizeIframeHTML(html2) {
25460
25517
  const config = configureDOMPurify();
25461
25518
  const cleaned = purify.sanitize(html2, config);
25462
25519
  if (!cleaned.includes("<iframe")) {
25463
- console.warn("⚠️ No valid iframe found after sanitization");
25464
25520
  return null;
25465
25521
  }
25466
25522
  const match = cleaned.match(/<iframe[^>]*src=["']([^"']+)["']/i);
@@ -25472,7 +25528,6 @@ function sanitizeIframeHTML(html2) {
25472
25528
  }
25473
25529
  return match[1];
25474
25530
  } catch (error) {
25475
- console.error("🚨 Error sanitizing iframe:", error);
25476
25531
  return null;
25477
25532
  } finally {
25478
25533
  purify.removeAllHooks();
@@ -25510,7 +25565,6 @@ const createFinder = (regex) => {
25510
25565
  match
25511
25566
  });
25512
25567
  }
25513
- console.log({ match, matches });
25514
25568
  return matches.length > 0 ? matches : null;
25515
25569
  };
25516
25570
  };
@@ -25562,11 +25616,9 @@ const Iframe = core.Node.create({
25562
25616
  const iframeHTML = match[0];
25563
25617
  const safeSrc = sanitizeIframeHTML(iframeHTML);
25564
25618
  if (!safeSrc) {
25565
- console.warn("🚨 Blocked unsafe iframe paste");
25566
25619
  toast.error("🚨 Your pasted iframe is not safe to render");
25567
25620
  return;
25568
25621
  }
25569
- console.log("✅ Safe iframe URL validated:", safeSrc);
25570
25622
  const node = this.type.create({ src: safeSrc, previewPayload: null });
25571
25623
  state2.tr.replaceRangeWith(range.from, range.to, node);
25572
25624
  }
@@ -25577,7 +25629,6 @@ const Iframe = core.Node.create({
25577
25629
  handler: ({ state: state2, range, match }) => {
25578
25630
  const fullUrl = match[0];
25579
25631
  const embedUrl = getEmbedUrl(fullUrl);
25580
- console.log({ match, fullUrl, embedUrl });
25581
25632
  if (!embedUrl) return;
25582
25633
  const node = this.type.create({ src: embedUrl });
25583
25634
  state2.tr.replaceRangeWith(range.from, range.to, node);
@@ -25623,10 +25674,9 @@ const handleUrlWithoutSelection = (editor, url, event, autoDetectMedia) => {
25623
25674
  mediaType: MediaItemType.MEDIA_ITEM
25624
25675
  });
25625
25676
  }).catch(
25626
- (e) => console.error("[SmartLinkPaste] Media detection failed, falling back to link:", e)
25677
+ (e) => void 0
25627
25678
  );
25628
25679
  }
25629
- console.log("[SmartLinkPaste] Inserting as link node");
25630
25680
  editor.chain().focus().insertLink({ href: normalizedUrl, text: url }).run();
25631
25681
  return true;
25632
25682
  };
@@ -25648,7 +25698,6 @@ const createPasteHandler = (editor, options) => {
25648
25698
  return false;
25649
25699
  }
25650
25700
  const trimmedText = pasteText.trim();
25651
- console.log("[SmartLinkPaste] Valid URL detected:", isEmbeddableUrl(trimmedText));
25652
25701
  if (isEmbeddableUrl(trimmedText) && options?.autoEmbed) {
25653
25702
  event.preventDefault();
25654
25703
  return false;
@@ -25665,7 +25714,6 @@ const createPasteHandler = (editor, options) => {
25665
25714
  options?.autoDetectMedia ?? true
25666
25715
  );
25667
25716
  } catch (error) {
25668
- console.error("[SmartLinkPaste] Error:", error);
25669
25717
  return false;
25670
25718
  }
25671
25719
  };
@@ -25677,10 +25725,8 @@ const createTransformHandler = (editor) => {
25677
25725
  return slice;
25678
25726
  }
25679
25727
  try {
25680
- console.log("[SmartLinkPaste] Transforming inline URLs in pasted content");
25681
25728
  return transformUrlsInSlice(editor, slice);
25682
25729
  } catch (error) {
25683
- console.error("[SmartLinkPaste] Transform error:", error);
25684
25730
  return slice;
25685
25731
  }
25686
25732
  };
@@ -25787,7 +25833,6 @@ const SmartMediaUpload = core.Extension.create({
25787
25833
  const uid = v4();
25788
25834
  const options = this.options;
25789
25835
  if (!options.api) {
25790
- console.error("API instance not provided to SmartMediaUpload");
25791
25836
  return false;
25792
25837
  }
25793
25838
  if (isFileOrBlob(source)) {
@@ -25797,7 +25842,6 @@ const SmartMediaUpload = core.Extension.create({
25797
25842
  options.allowedFileTypes
25798
25843
  );
25799
25844
  if (!validation.valid) {
25800
- console.error("File validation failed:", validation.error);
25801
25845
  options.onUploadError?.(uid, new Error(validation.error));
25802
25846
  return false;
25803
25847
  }
@@ -25881,7 +25925,6 @@ const SmartMediaUpload = core.Extension.create({
25881
25925
  } else editor.commands.deleteMediaByUid(item.uid);
25882
25926
  options.onUploadComplete?.(item.uid, hostedUrl);
25883
25927
  } catch (error) {
25884
- console.error("Upload failed:", error);
25885
25928
  const blobUrl = this.storage.blobUrls.get(item.uid);
25886
25929
  if (blobUrl) {
25887
25930
  URL.revokeObjectURL(blobUrl);
@@ -25893,7 +25936,7 @@ const SmartMediaUpload = core.Extension.create({
25893
25936
  this.storage.activeUploads--;
25894
25937
  this.storage.processUploadQueue(editor);
25895
25938
  }
25896
- })().catch((err) => console.log(err));
25939
+ })().catch((err) => void 0);
25897
25940
  if (this.storage.uploadQueue.length > 0) {
25898
25941
  this.storage.processUploadQueue(editor);
25899
25942
  }
@@ -28593,7 +28636,6 @@ function getSuggestionOptions({
28593
28636
  const text2 = editor.getText();
28594
28637
  const trimmed = text2?.replace(WHITESPACE_REGEX, " ")?.trim();
28595
28638
  const matchStartPosition = trimmed?.lastIndexOf(char);
28596
- console.log({ matchStartPosition });
28597
28639
  const nodeAfter = editor.view.state.selection.$to.nodeAfter;
28598
28640
  const overrideSpace = nodeAfter?.text?.startsWith(" ");
28599
28641
  if (overrideSpace) {
@@ -28707,7 +28749,6 @@ const Mention = core.Node.create({
28707
28749
  renderHTML({ node, HTMLAttributes }) {
28708
28750
  const suggestion2 = getSuggestionFromChar(this, node.attrs.mentionSuggestionChar);
28709
28751
  if (this.options.renderLabel !== void 0) {
28710
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28711
28752
  return [
28712
28753
  "span",
28713
28754
  core.mergeAttributes({ "data-type": this.name }, this.options.HTMLAttributes, HTMLAttributes),
@@ -28747,7 +28788,6 @@ const Mention = core.Node.create({
28747
28788
  suggestion: getSuggestionFromChar(this, node.attrs.mentionSuggestionChar)
28748
28789
  };
28749
28790
  if (this.options.renderLabel !== void 0) {
28750
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28751
28791
  return this.options.renderLabel(args);
28752
28792
  }
28753
28793
  return this.options.renderText(args);
@@ -29736,11 +29776,9 @@ const mentionService = (api, mfs, store) => {
29736
29776
  const fetchMentions = async () => {
29737
29777
  const params = store.getState().getMentionParams();
29738
29778
  if (!params) {
29739
- console.error("DEBUG MENTION SERVICE::", "No group id or post id has been provided");
29740
29779
  return [];
29741
29780
  }
29742
29781
  const { groupId, postId } = params;
29743
- console.log({ groupId, postId });
29744
29782
  const response = postId ? await mfs.getRecommendationPost(groupId, postId, 0, 999) : await mfs.getRecommendationGroup(groupId, 0, 999);
29745
29783
  return response.entries?.filter((item) => Boolean(item?.user_data))?.map(
29746
29784
  (item) => ({
@@ -29759,7 +29797,6 @@ const mentionService = (api, mfs, store) => {
29759
29797
  const { selectedGroupId, groupId } = store.getState();
29760
29798
  const activeGroupId = selectedGroupId ?? groupId;
29761
29799
  if (!activeGroupId) {
29762
- console.warn("DEBUG HASHTAG SERVICE::", "No active group selected or provided");
29763
29800
  return [];
29764
29801
  }
29765
29802
  const response = await api.fetchGroupConversations(999, 0);
@@ -29961,8 +29998,8 @@ const LinkPreviewExtended = ({
29961
29998
  title,
29962
29999
  description,
29963
30000
  image,
29964
- domain
29965
- // onClickDelete,
30001
+ domain,
30002
+ onClickDelete
29966
30003
  }) => {
29967
30004
  const safeDomain = React.useMemo(() => {
29968
30005
  try {
@@ -29971,6 +30008,11 @@ const LinkPreviewExtended = ({
29971
30008
  return "unknown";
29972
30009
  }
29973
30010
  }, [href, domain]);
30011
+ const handleDelete = (e) => {
30012
+ e.preventDefault();
30013
+ e.stopPropagation();
30014
+ onClickDelete();
30015
+ };
29974
30016
  return /* @__PURE__ */ jsxRuntime.jsxs(
29975
30017
  "div",
29976
30018
  {
@@ -29979,18 +30021,32 @@ const LinkPreviewExtended = ({
29979
30021
  selected ? "ring-2 ring-blue-500 ring-offset-2 rounded-lg" : ""
29980
30022
  ),
29981
30023
  children: [
29982
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2 absolute z-50 right-3 top-3", children: /* @__PURE__ */ jsxRuntime.jsx(
29983
- ToolbarButton,
29984
- {
29985
- asChild: true,
29986
- tooltip: "Visit Link",
29987
- className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none group-hover:bg-accent/70 group-hover:text-accent-foreground text-primary-send",
29988
- children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative", children: [
29989
- /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "absolute inset-0" }),
29990
- /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, {})
29991
- ] })
29992
- }
29993
- ) }),
30024
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 absolute z-50 right-3 top-3", children: [
30025
+ /* @__PURE__ */ jsxRuntime.jsx(
30026
+ ToolbarButton,
30027
+ {
30028
+ asChild: true,
30029
+ tooltip: "Visit Link",
30030
+ className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none group-hover:bg-accent/70 group-hover:text-accent-foreground text-primary-send",
30031
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative", children: [
30032
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "absolute inset-0" }),
30033
+ /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, {})
30034
+ ] })
30035
+ }
30036
+ ),
30037
+ /* @__PURE__ */ jsxRuntime.jsx(
30038
+ ToolbarButton,
30039
+ {
30040
+ tooltip: "Remove Link Preview",
30041
+ onClick: handleDelete,
30042
+ "aria-label": "Delete link preview",
30043
+ type: "button",
30044
+ size: "icon",
30045
+ className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none bg-transparent group-hover:bg-red-50/70 hover:bg-red-50 text-destructive hover:text-destructive",
30046
+ children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, {})
30047
+ }
30048
+ )
30049
+ ] }),
29994
30050
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative z-0 w-full", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group overflow-hidden flex flex-col rounded-lg border bg-accent/30 transition-all hover:border-foreground/20 hover:shadow-sm", children: [
29995
30051
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-80 w-full shrink-0 overflow-hidden bg-muted border-b", children: /* @__PURE__ */ jsxRuntime.jsx(
29996
30052
  "img",
@@ -30111,7 +30167,6 @@ const LinkPreview = core.Node.create({
30111
30167
  },
30112
30168
  renderHTML({ node }) {
30113
30169
  const { href, uid, title, description, image, domain } = node.attrs;
30114
- console.log("INSIDE RENDER HTML::", { href, image });
30115
30170
  if (!href) return ["div", {}];
30116
30171
  const content = [
30117
30172
  // Link overlay
@@ -30246,11 +30301,6 @@ const MediaGroupView = ({ node, editor }) => {
30246
30301
  editor.commands.deleteMediaByUid(uid);
30247
30302
  };
30248
30303
  const mediaNodes = node?.content?.content || [];
30249
- console.log("MediaGroupView render:", {
30250
- contentSize: node?.content?.size,
30251
- mediaCount: mediaNodes?.length,
30252
- nodes: mediaNodes?.map((n) => ({ type: n?.type?.name, uid: n?.attrs?.uid }))
30253
- });
30254
30304
  return /* @__PURE__ */ jsxRuntime.jsx(
30255
30305
  react.NodeViewWrapper,
30256
30306
  {
@@ -30352,14 +30402,12 @@ const createMediaModePlugin = () => {
30352
30402
  child.marks.forEach((mark) => {
30353
30403
  if (mark.type.name === "customLink" && mark.attrs.previewPayload) {
30354
30404
  lastLinkPreviewData = mark.attrs.previewPayload;
30355
- console.log("Found link with previewPayload:", lastLinkPreviewData);
30356
30405
  }
30357
30406
  });
30358
30407
  }
30359
30408
  });
30360
30409
  }
30361
30410
  });
30362
- console.log("Cleanup check:", { modified, hasMediaGroup, lastLinkPreviewData });
30363
30411
  if (modified && hasMediaGroup && lastLinkPreviewData) {
30364
30412
  let hasLinkPreview = false;
30365
30413
  tr.doc.forEach((node) => {
@@ -30367,10 +30415,6 @@ const createMediaModePlugin = () => {
30367
30415
  hasLinkPreview = true;
30368
30416
  }
30369
30417
  });
30370
- console.log("Creating linkPreview:", {
30371
- hasLinkPreview,
30372
- schemaHasLinkPreview: !!newState.schema.nodes.linkPreview
30373
- });
30374
30418
  if (!hasLinkPreview && newState.schema.nodes.linkPreview) {
30375
30419
  const preview = lastLinkPreviewData;
30376
30420
  const linkPreviewNode = newState.schema.nodes.linkPreview.create({
@@ -30381,7 +30425,6 @@ const createMediaModePlugin = () => {
30381
30425
  image: preview.linkImage?.url ?? "",
30382
30426
  variant: LinkPreviewType.Extended
30383
30427
  });
30384
- console.log("Inserting linkPreview node:", { lastLinkPreviewData, linkPreviewNode });
30385
30428
  tr.insert(tr.doc.content.size, linkPreviewNode);
30386
30429
  modified = true;
30387
30430
  }
@@ -30441,7 +30484,6 @@ const createMediaModePlugin = () => {
30441
30484
  }
30442
30485
  const mediaNodes = updatedTopLevelMedia.map((m) => m.node);
30443
30486
  if (mediaNodes.some((n) => !n || n.type.name !== "media")) {
30444
- console.warn("Invalid media nodes detected, skipping group creation");
30445
30487
  return null;
30446
30488
  }
30447
30489
  const mediaGroup = newState.schema.nodes.mediaGroup.create({}, mediaNodes);
@@ -30459,7 +30501,6 @@ const createMediaModePlugin = () => {
30459
30501
  const $pos = tr.doc.resolve(endPos);
30460
30502
  tr.setSelection(state.TextSelection.near($pos));
30461
30503
  } catch (e) {
30462
- console.warn("Could not set selection:", e);
30463
30504
  }
30464
30505
  }
30465
30506
  tr.setMeta("addToHistory", false);
@@ -30467,7 +30508,6 @@ const createMediaModePlugin = () => {
30467
30508
  }
30468
30509
  return modified ? tr : null;
30469
30510
  } catch (error) {
30470
- console.error("MediaMode plugin error:", error);
30471
30511
  return null;
30472
30512
  } finally {
30473
30513
  isProcessing = false;
@@ -30609,7 +30649,7 @@ const getMediaExtensions = ({ api, store, user }) => {
30609
30649
  }),
30610
30650
  LinkPreview.configure({
30611
30651
  variant: LinkPreviewType.Extended,
30612
- selectable: false,
30652
+ // selectable: false,
30613
30653
  draggable: false
30614
30654
  }),
30615
30655
  getMentionExtension(core2, mfs, store),
@@ -30753,7 +30793,6 @@ const isLinkMarkWithPayload = (node) => isLinkMark(node) && Boolean(node?.attrs?
30753
30793
  const getLinkItemsPayload = (json) => {
30754
30794
  const links = find(json, (node) => isLinkMarkWithPayload(node));
30755
30795
  const items = links?.at(-1);
30756
- console.log("Link Items Payload::", { items });
30757
30796
  return { items };
30758
30797
  };
30759
30798
  const getPollItemsPayload = (json) => {
@@ -30767,7 +30806,7 @@ const isValidItem = (item) => {
30767
30806
  const mediaItem = item;
30768
30807
  const isValidLinkItem = linkItem?.linkUrl;
30769
30808
  const mediaItemSources = mediaItem?.sources;
30770
- const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url || mediaItemSources?.placeholder?.url;
30809
+ const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url;
30771
30810
  return Boolean(isValidLinkItem || isValidMediaItem);
30772
30811
  };
30773
30812
  const generateHtmlPostPayload = ({
@@ -30787,7 +30826,6 @@ const generateHtmlPostPayload = ({
30787
30826
  )?.at(0);
30788
30827
  const isEmbedOnly = isOnlyContentNode(json, "iframe");
30789
30828
  const body = isEmbedOnly ? previewItemEmbed?.attrs?.previewPayload?.linkTitle ?? previewItemEmbed?.attrs?.src ?? "" : secondaryText?.text ?? firstText?.text ?? "";
30790
- console.log({ firstText });
30791
30829
  const items = [
30792
30830
  previewItemMedia?.attrs?.payload,
30793
30831
  previewItemEmbed?.attrs?.previewPayload,
@@ -30814,11 +30852,14 @@ const generateMediaPostPayload = ({
30814
30852
  const { mentionData } = getMentionDataPayload(json);
30815
30853
  const { items: mediaItems } = getMediaItemsPayload(json);
30816
30854
  const { items: linkItems } = getLinkItemsPayload(json);
30855
+ const items = mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [];
30856
+ if (!body && mediaItems.length === 0)
30857
+ return { error: "Your post is empty. Add text or media to share your thoughts." };
30817
30858
  return {
30818
30859
  ...commons,
30819
30860
  type: mediaItems?.length > 0 ? NewPostType.NEW_POST_MEDIA : linkItems?.length > 0 ? NewPostType.NEW_POST_LINK : NewPostType.NEW_POST_MESSAGE,
30820
30861
  body,
30821
- items: mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [],
30862
+ items,
30822
30863
  mentionData,
30823
30864
  sendCrossMention
30824
30865
  };
@@ -30838,7 +30879,6 @@ const generatePollPostPayload = ({
30838
30879
  option_id: index2 === 0 ? item.option_id : v4(),
30839
30880
  option_color: OPTION_COLORS[index2 % OPTION_COLORS.length]
30840
30881
  })) : items;
30841
- console.log({ polls });
30842
30882
  return {
30843
30883
  ...commons,
30844
30884
  type: NewPostType.NEW_POST_POLL,
@@ -30875,6 +30915,7 @@ const PostBuilderEditorInstance = ({
30875
30915
  const [isDragging, setIsDragging] = React.useState(false);
30876
30916
  const { trackPublish } = usePostBuilderAnalytics();
30877
30917
  const { clearContent } = usePersistence();
30918
+ useHostAnalyticsBridge();
30878
30919
  const handleDragOver = (e) => {
30879
30920
  e.preventDefault();
30880
30921
  setIsDragging(true);
@@ -30894,10 +30935,24 @@ const PostBuilderEditorInstance = ({
30894
30935
  const text2 = editor?.getText();
30895
30936
  const payload = generateCreatePostPayload(editorTab, { editor, sendCrossMention });
30896
30937
  const isPollType = payload?.type === NewPostType.NEW_POST_POLL;
30897
- if (!payload) return;
30938
+ if (payload?.error) {
30939
+ toast.error(payload.error);
30940
+ return;
30941
+ }
30942
+ if (!payload?.postId) return;
30898
30943
  if (isPollType && payload.items?.length === 0)
30899
30944
  return toast.warning(`At least ${POLL_LIMITS.MIN} option is mandatory to create a poll post`);
30900
- trackPublish("attempted");
30945
+ if (typeof window !== "undefined") {
30946
+ window.dispatchEvent(
30947
+ new CustomEvent(PostBuilderEvents.POST_PUBLISH_ATTEMPTED, {
30948
+ detail: {
30949
+ postId: payload.postId,
30950
+ postType: payload.type
30951
+ }
30952
+ })
30953
+ );
30954
+ }
30955
+ trackPublish({ status: "attempted", postId: payload?.postId, postType: payload?.type });
30901
30956
  onCreatePost?.({ payload, html: html2, json, text: text2 });
30902
30957
  if (!clearOnSuccess) return;
30903
30958
  clearContent();
@@ -31071,7 +31126,6 @@ class SessionManager {
31071
31126
  }, SESSION_TIMEOUT_MS);
31072
31127
  }
31073
31128
  endSession(reason) {
31074
- console.log({ reason });
31075
31129
  if (this.inactivityTimer) {
31076
31130
  clearTimeout(this.inactivityTimer);
31077
31131
  }
@@ -31132,7 +31186,7 @@ function useAnalytics({ editorTab, config }) {
31132
31186
  const featureTracker = React.useRef(new FeatureTracker()).current;
31133
31187
  const logEvent = useAnalyticsLogEvent();
31134
31188
  const trackEvent = React.useCallback(
31135
- (name, properties = {}) => {
31189
+ ({ name, properties }) => {
31136
31190
  const fullConfig = { ...DEFAULT_CONFIG, ...config };
31137
31191
  if (!fullConfig.enabled) return;
31138
31192
  sessionManager.updateActivity();
@@ -31140,30 +31194,32 @@ function useAnalytics({ editorTab, config }) {
31140
31194
  session_id: sessionManager.getSessionId(),
31141
31195
  timestamp: Date.now(),
31142
31196
  editor_type: editorTab,
31143
- ...properties
31197
+ ...properties ?? {}
31144
31198
  };
31145
- if (logEvent) {
31146
- logEvent(name, enrichedProperties);
31147
- }
31148
- if (fullConfig.debug) {
31149
- console.log("[Analytics]", name, enrichedProperties);
31150
- }
31199
+ const cleanProps = pickBy(enrichedProperties, (value) => value != null);
31200
+ if (logEvent) logEvent(name, cleanProps);
31151
31201
  },
31152
31202
  [config, editorTab, logEvent, sessionManager]
31153
31203
  );
31154
31204
  React.useEffect(() => {
31155
31205
  const sessionId = sessionManager.startSession();
31156
- trackEvent(ANALYTICS_EVENTS.SESSION.STARTED, {
31157
- session_id: sessionId,
31158
- timestamp: Date.now(),
31159
- editor_type: editorTab
31206
+ trackEvent({
31207
+ name: ANALYTICS_EVENTS.SESSION.STARTED,
31208
+ properties: {
31209
+ session_id: sessionId,
31210
+ timestamp: Date.now(),
31211
+ editor_type: editorTab
31212
+ }
31160
31213
  });
31161
31214
  const handleUnload = () => {
31162
- trackEvent(ANALYTICS_EVENTS.SESSION.COMPLETED, {
31163
- session_id: sessionManager.getSessionId(),
31164
- timestamp: Date.now(),
31165
- editor_type: editorTab,
31166
- session_duration_ms: sessionManager.getSessionDuration()
31215
+ trackEvent({
31216
+ name: ANALYTICS_EVENTS.SESSION.COMPLETED,
31217
+ properties: {
31218
+ session_id: sessionManager.getSessionId(),
31219
+ timestamp: Date.now(),
31220
+ editor_type: editorTab,
31221
+ session_duration_ms: sessionManager.getSessionDuration()
31222
+ }
31167
31223
  });
31168
31224
  };
31169
31225
  window.addEventListener("beforeunload", handleUnload);
@@ -31173,60 +31229,88 @@ function useAnalytics({ editorTab, config }) {
31173
31229
  };
31174
31230
  }, []);
31175
31231
  const trackFeature = React.useCallback(
31176
- (featureName) => {
31232
+ ({ featureName }) => {
31177
31233
  const { isFirstUse, usageCount } = featureTracker.trackUsage(featureName);
31178
- trackEvent(isFirstUse ? ANALYTICS_EVENTS.FEATURE.DISCOVERED : ANALYTICS_EVENTS.FEATURE.USED, {
31179
- feature_name: featureName,
31180
- is_first_use: isFirstUse,
31181
- usage_count: usageCount
31234
+ trackEvent({
31235
+ name: isFirstUse ? ANALYTICS_EVENTS.FEATURE.DISCOVERED : ANALYTICS_EVENTS.FEATURE.USED,
31236
+ properties: {
31237
+ feature_name: featureName,
31238
+ is_first_use: isFirstUse,
31239
+ usage_count: usageCount
31240
+ }
31182
31241
  });
31183
31242
  },
31184
31243
  [trackEvent, featureTracker]
31185
31244
  );
31186
31245
  const trackPublish = React.useCallback(
31187
- (status, data) => {
31246
+ ({ status, data }) => {
31188
31247
  const eventMap = {
31189
31248
  attempted: ANALYTICS_EVENTS.PUBLISH.ATTEMPTED,
31190
31249
  success: ANALYTICS_EVENTS.PUBLISH.SUCCESS,
31191
31250
  failed: ANALYTICS_EVENTS.PUBLISH.FAILED
31192
31251
  };
31193
- trackEvent(eventMap[status], {
31252
+ const properties = {
31194
31253
  editor_type: editorTab,
31195
31254
  session_duration_ms: sessionManager.getSessionDuration(),
31196
31255
  ...data
31256
+ };
31257
+ trackEvent({
31258
+ name: eventMap[status],
31259
+ properties
31197
31260
  });
31198
31261
  sessionManager.endSession("completed");
31199
31262
  },
31200
31263
  [trackEvent, editorTab, sessionManager]
31201
31264
  );
31202
31265
  const trackAbandon = React.useCallback(
31203
- (contentLength, hasUnsavedChanges, abandonReason, postType) => {
31204
- trackEvent(ANALYTICS_EVENTS.SESSION.ABANDONED, {
31205
- session_duration_ms: sessionManager.getSessionDuration(),
31206
- post_type: postType,
31207
- content_length: contentLength,
31208
- has_unsaved_changes: hasUnsavedChanges,
31209
- abandon_reason: abandonReason
31266
+ ({
31267
+ contentLength,
31268
+ hasUnsavedChanges,
31269
+ abandonReason,
31270
+ postType,
31271
+ userHistoryData
31272
+ }) => {
31273
+ trackEvent({
31274
+ name: ANALYTICS_EVENTS.SESSION.ABANDONED,
31275
+ properties: {
31276
+ session_duration_ms: sessionManager.getSessionDuration(),
31277
+ post_type: postType,
31278
+ content_length: contentLength,
31279
+ has_unsaved_changes: hasUnsavedChanges,
31280
+ abandon_reason: abandonReason,
31281
+ // Include user history if provided
31282
+ ...userHistoryData && {
31283
+ previous_abandon_count: userHistoryData.previous_abandon_count,
31284
+ previous_publish_count: userHistoryData.previous_publish_count,
31285
+ time_since_last_publish_ms: userHistoryData.time_since_last_publish_ms,
31286
+ is_returning_user: userHistoryData.is_returning_user
31287
+ }
31288
+ }
31210
31289
  });
31211
31290
  sessionManager.endSession("abandoned");
31212
31291
  },
31213
31292
  [trackEvent, sessionManager]
31214
31293
  );
31215
31294
  const trackTabSwitch = React.useCallback(
31216
- (oldTab, newTab) => {
31217
- trackEvent(ANALYTICS_EVENTS.EDITOR.FOCUSED, {
31218
- from_tab: oldTab,
31219
- to_tab: newTab,
31220
- editor_type: editorTab
31295
+ ({ oldTab, newTab }) => {
31296
+ trackEvent({
31297
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31298
+ properties: {
31299
+ from_tab: oldTab,
31300
+ to_tab: newTab
31301
+ }
31221
31302
  });
31222
31303
  },
31223
- [trackEvent, editorTab]
31304
+ [trackEvent]
31224
31305
  );
31225
31306
  const trackEditorFocus = React.useCallback(
31226
- (context) => {
31227
- trackEvent(ANALYTICS_EVENTS.EDITOR.FOCUSED, {
31228
- context,
31229
- editor_type: editorTab
31307
+ ({ context }) => {
31308
+ trackEvent({
31309
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31310
+ properties: {
31311
+ context,
31312
+ editor_type: editorTab
31313
+ }
31230
31314
  });
31231
31315
  },
31232
31316
  [trackEvent, editorTab]
@@ -31260,19 +31344,91 @@ function useAnalytics({ editorTab, config }) {
31260
31344
  ]
31261
31345
  );
31262
31346
  }
31347
+ const STORAGE_KEY = "pb_user_history";
31348
+ class UserHistoryTracker {
31349
+ history;
31350
+ constructor() {
31351
+ this.history = this.loadHistory();
31352
+ }
31353
+ loadHistory() {
31354
+ try {
31355
+ const stored = localStorage.getItem(STORAGE_KEY);
31356
+ if (stored) {
31357
+ return JSON.parse(stored);
31358
+ }
31359
+ } catch (error) {
31360
+ }
31361
+ return {
31362
+ previous_abandon_count: 0,
31363
+ previous_publish_count: 0,
31364
+ last_publish_timestamp: null,
31365
+ last_abandon_timestamp: null,
31366
+ first_session_timestamp: Date.now()
31367
+ };
31368
+ }
31369
+ saveHistory() {
31370
+ try {
31371
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.history));
31372
+ } catch (error) {
31373
+ }
31374
+ }
31375
+ /**
31376
+ * Record a successful publish
31377
+ */
31378
+ recordPublish() {
31379
+ this.history.previous_publish_count += 1;
31380
+ this.history.last_publish_timestamp = Date.now();
31381
+ this.saveHistory();
31382
+ }
31383
+ /**
31384
+ * Record an abandonment
31385
+ */
31386
+ recordAbandon() {
31387
+ this.history.previous_abandon_count += 1;
31388
+ this.history.last_abandon_timestamp = Date.now();
31389
+ this.saveHistory();
31390
+ }
31391
+ /**
31392
+ * Get current user history for analytics
31393
+ */
31394
+ getHistory() {
31395
+ const now2 = Date.now();
31396
+ const daysSinceFirstSession = Math.floor(
31397
+ (now2 - this.history.first_session_timestamp) / (1e3 * 60 * 60 * 24)
31398
+ );
31399
+ return {
31400
+ previous_abandon_count: this.history.previous_abandon_count,
31401
+ previous_publish_count: this.history.previous_publish_count,
31402
+ time_since_last_publish_ms: this.history.last_publish_timestamp ? now2 - this.history.last_publish_timestamp : null,
31403
+ is_returning_user: daysSinceFirstSession > 0.5,
31404
+ days_since_first_session: daysSinceFirstSession
31405
+ };
31406
+ }
31407
+ /**
31408
+ * Clear history (for testing or user request)
31409
+ */
31410
+ clearHistory() {
31411
+ localStorage.removeItem(STORAGE_KEY);
31412
+ this.history = {
31413
+ previous_abandon_count: 0,
31414
+ previous_publish_count: 0,
31415
+ last_publish_timestamp: null,
31416
+ last_abandon_timestamp: null,
31417
+ first_session_timestamp: Date.now()
31418
+ };
31419
+ }
31420
+ }
31263
31421
  function useEditorAnalytics({
31264
31422
  editor,
31265
31423
  editorType,
31266
31424
  context,
31267
31425
  idleTimeout = 3e5,
31268
- // 5 minutes
31269
31426
  trackBlur = false
31270
- // Default: don't track every blur
31271
31427
  }) {
31272
31428
  const analytics = useAnalytics({
31273
31429
  editorTab: editorType,
31274
31430
  config: {
31275
- debug: false,
31431
+ debug: true,
31276
31432
  enabled: true
31277
31433
  }
31278
31434
  });
@@ -31280,6 +31436,7 @@ function useEditorAnalytics({
31280
31436
  const idleTimer = React.useRef();
31281
31437
  const hasFocusedOnce = React.useRef(false);
31282
31438
  const hasAbandonedSession = React.useRef(false);
31439
+ const userHistory = React.useRef(new UserHistoryTracker()).current;
31283
31440
  const getEditorMetrics = React.useCallback(() => {
31284
31441
  if (!editor) return null;
31285
31442
  const json = editor.getJSON();
@@ -31319,7 +31476,6 @@ function useEditorAnalytics({
31319
31476
  linkCount,
31320
31477
  formattingFeatures: Array.from(formattingFeatures),
31321
31478
  hasUnsavedChanges: editor.state.doc.content.size > 2,
31322
- // Has content beyond empty doc
31323
31479
  isEmpty: editor.isEmpty
31324
31480
  };
31325
31481
  }, [editor, analytics]);
@@ -31330,16 +31486,29 @@ function useEditorAnalytics({
31330
31486
  idleTimer.current = setTimeout(() => {
31331
31487
  const metrics = getEditorMetrics();
31332
31488
  if (metrics && !metrics.isEmpty) {
31333
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "idle_timeout");
31489
+ const history = userHistory.getHistory();
31490
+ analytics.trackAbandon({
31491
+ contentLength: metrics.characterCount,
31492
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31493
+ abandonReason: "idle_timeout",
31494
+ postType: void 0,
31495
+ userHistoryData: {
31496
+ previous_abandon_count: history.previous_abandon_count,
31497
+ previous_publish_count: history.previous_publish_count,
31498
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31499
+ is_returning_user: history.is_returning_user
31500
+ }
31501
+ });
31502
+ userHistory.recordAbandon();
31334
31503
  hasAbandonedSession.current = true;
31335
31504
  }
31336
31505
  }, idleTimeout);
31337
- }, [editor, idleTimeout, analytics, getEditorMetrics]);
31506
+ }, [editor, idleTimeout, analytics, getEditorMetrics, userHistory]);
31338
31507
  React.useEffect(() => {
31339
31508
  if (!editor) return;
31340
31509
  const handleFocus = () => {
31341
31510
  if (!hasFocusedOnce.current) {
31342
- analytics.trackEditorFocus(context);
31511
+ analytics.trackEditorFocus({ context });
31343
31512
  hasFocusedOnce.current = true;
31344
31513
  }
31345
31514
  resetIdleTimer();
@@ -31350,9 +31519,12 @@ function useEditorAnalytics({
31350
31519
  if (trackBlur) {
31351
31520
  const metrics = getEditorMetrics();
31352
31521
  if (metrics && !metrics.isEmpty) {
31353
- analytics.trackEvent(ANALYTICS_EVENTS.EDITOR.BLURRED, {
31354
- content_length: metrics.characterCount,
31355
- session_duration_ms: Date.now() - lastActivity.current
31522
+ analytics.trackEvent({
31523
+ name: ANALYTICS_EVENTS.EDITOR.BLURRED,
31524
+ properties: {
31525
+ content_length: metrics.characterCount,
31526
+ session_duration_ms: Date.now() - lastActivity.current
31527
+ }
31356
31528
  });
31357
31529
  }
31358
31530
  }
@@ -31371,7 +31543,20 @@ function useEditorAnalytics({
31371
31543
  if (hasAbandonedSession.current) return;
31372
31544
  const metrics = getEditorMetrics();
31373
31545
  if (metrics && !metrics.isEmpty) {
31374
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "navigation");
31546
+ const history = userHistory.getHistory();
31547
+ analytics.trackAbandon({
31548
+ contentLength: metrics.characterCount,
31549
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31550
+ abandonReason: "navigation",
31551
+ postType: void 0,
31552
+ userHistoryData: {
31553
+ previous_abandon_count: history.previous_abandon_count,
31554
+ previous_publish_count: history.previous_publish_count,
31555
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31556
+ is_returning_user: history.is_returning_user
31557
+ }
31558
+ });
31559
+ userHistory.recordAbandon();
31375
31560
  hasAbandonedSession.current = true;
31376
31561
  }
31377
31562
  };
@@ -31382,46 +31567,76 @@ function useEditorAnalytics({
31382
31567
  clearTimeout(idleTimer.current);
31383
31568
  }
31384
31569
  };
31385
- }, [editor, analytics, getEditorMetrics]);
31570
+ }, [editor, analytics, getEditorMetrics, userHistory]);
31386
31571
  const trackFeature = React.useCallback(
31387
- (featureName) => {
31388
- analytics.trackFeature(featureName);
31572
+ ({ featureName }) => {
31573
+ analytics.trackFeature({ featureName });
31389
31574
  resetIdleTimer();
31390
31575
  },
31391
31576
  [analytics, resetIdleTimer]
31392
31577
  );
31393
31578
  const trackPublish = React.useCallback(
31394
- (status, failureReason) => {
31579
+ ({ sessionId, groupId, postId, status, failureReason, postType }) => {
31395
31580
  const metrics = getEditorMetrics();
31396
31581
  if (!metrics) return;
31397
- analytics.trackPublish(status, {
31398
- word_count: metrics.wordCount,
31399
- character_count: metrics.characterCount,
31400
- media_count: metrics.mediaCount,
31401
- link_count: metrics.linkCount,
31402
- formatting_features: metrics.formattingFeatures,
31403
- failure_reason: failureReason
31582
+ const history = userHistory.getHistory();
31583
+ analytics.trackPublish({
31584
+ status,
31585
+ data: {
31586
+ ...sessionId ? { session_id: sessionId } : {},
31587
+ group_id: groupId,
31588
+ post_id: postId,
31589
+ post_type: postType,
31590
+ word_count: metrics.wordCount,
31591
+ character_count: metrics.characterCount,
31592
+ media_count: metrics.mediaCount,
31593
+ link_count: metrics.linkCount,
31594
+ formatting_features: metrics.formattingFeatures,
31595
+ failure_reason: failureReason,
31596
+ // Include user history
31597
+ previous_abandon_count: history.previous_abandon_count,
31598
+ previous_publish_count: history.previous_publish_count,
31599
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31600
+ is_returning_user: history.is_returning_user
31601
+ }
31404
31602
  });
31405
31603
  if (status === "success") {
31604
+ userHistory.recordPublish();
31406
31605
  hasAbandonedSession.current = true;
31407
31606
  }
31408
31607
  },
31409
- [analytics, getEditorMetrics]
31608
+ [analytics, getEditorMetrics, userHistory]
31410
31609
  );
31411
31610
  const trackExplicitAbandon = React.useCallback(() => {
31412
31611
  if (hasAbandonedSession.current) return;
31413
31612
  const metrics = getEditorMetrics();
31414
31613
  if (metrics && !metrics.isEmpty) {
31415
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "user_closed");
31614
+ const history = userHistory.getHistory();
31615
+ analytics.trackAbandon({
31616
+ contentLength: metrics.characterCount,
31617
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31618
+ abandonReason: "user_closed",
31619
+ postType: void 0,
31620
+ userHistoryData: {
31621
+ previous_abandon_count: history.previous_abandon_count,
31622
+ previous_publish_count: history.previous_publish_count,
31623
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31624
+ is_returning_user: history.is_returning_user
31625
+ }
31626
+ });
31627
+ userHistory.recordAbandon();
31416
31628
  hasAbandonedSession.current = true;
31417
31629
  }
31418
- }, [analytics, getEditorMetrics]);
31630
+ }, [analytics, getEditorMetrics, userHistory]);
31419
31631
  return {
31420
31632
  trackFeature,
31421
31633
  trackPublish,
31422
31634
  trackExplicitAbandon,
31423
31635
  trackTabSwitch: analytics.trackTabSwitch,
31424
- getEditorMetrics
31636
+ getEditorMetrics,
31637
+ // Expose user history for debugging
31638
+ getUserHistory: () => userHistory.getHistory(),
31639
+ currentSessionId: analytics.getSessionId()
31425
31640
  };
31426
31641
  }
31427
31642
  const PostBuilderAnalyticsProvider = ({
@@ -31487,56 +31702,66 @@ const PostBuilderEditor = ({
31487
31702
  isSubmitting,
31488
31703
  clearOnSuccess
31489
31704
  }
31490
- ) : (
31491
- // <Dialog open={openModal} onOpenChange={onModalOpenChange}>
31492
- // <DialogContent
31493
- // className="bg-transparent shadow-none border-0 p-3 lg:max-w-4xl shrink-0 max-h-[calc(100dvh-7rem)]! flex flex-col overflow-y-auto -translate-1/2"
31494
- // showCloseButton={false}
31495
- // >
31496
- // <DialogHeader>
31497
- // <DialogTitle className="sr-only">Post Builder Modal</DialogTitle>
31498
- // {!hideGroupSelector && (
31499
- // <div className="flex items-center justify-between gap-3">
31500
- // <GroupSelector user={user} store={store} />
31501
- // <DialogClose asChild>
31502
- // <Button variant="outline" size="icon">
31503
- // <X />
31504
- // </Button>
31505
- // </DialogClose>
31506
- // </div>
31507
- // )}
31508
- // </DialogHeader>
31509
- // <PostBuilderEditorInstance
31510
- // editor={editor}
31511
- // actions={actions}
31512
- // editorTab={editorTab}
31513
- // onSwitchEditor={setEditorTab}
31514
- // isSubmitting={isSubmitting}
31515
- // onCreatePost={onCreatePost}
31516
- // clearOnSuccess={clearOnSuccess}
31517
- // />
31518
- // </DialogContent>
31519
- // </Dialog>
31520
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "prose-blockquote: flex-1 flex flex-col space-y-3 max-w-full max-h-[calc(100dvh-7rem)]", children: [
31521
- !hideGroupSelector && /* @__PURE__ */ jsxRuntime.jsx(GroupSelector, { user, store }),
31522
- /* @__PURE__ */ jsxRuntime.jsx(
31523
- PostBuilderEditorInstance,
31524
- {
31525
- editor,
31526
- actions,
31527
- editorTab,
31528
- onSwitchEditor: setEditorTab,
31529
- isSubmitting,
31530
- onCreatePost,
31531
- clearOnSuccess
31532
- }
31533
- )
31534
- ] })
31535
- ) }),
31705
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "prose-blockquote: flex-1 flex flex-col space-y-3 max-w-full max-h-[calc(100dvh-7rem)]", children: [
31706
+ !hideGroupSelector && /* @__PURE__ */ jsxRuntime.jsx(GroupSelector, { user, store }),
31707
+ /* @__PURE__ */ jsxRuntime.jsx(
31708
+ PostBuilderEditorInstance,
31709
+ {
31710
+ editor,
31711
+ actions,
31712
+ editorTab,
31713
+ onSwitchEditor: setEditorTab,
31714
+ isSubmitting,
31715
+ onCreatePost,
31716
+ clearOnSuccess
31717
+ }
31718
+ )
31719
+ ] }) }),
31536
31720
  /* @__PURE__ */ jsxRuntime.jsx(Toaster2, { position: "top-center" })
31537
31721
  ] })
31538
31722
  }
31539
31723
  );
31540
31724
  };
31725
+ const PostBuilderProvider = ({
31726
+ children,
31727
+ apiBaseURL,
31728
+ authToken,
31729
+ toI18N,
31730
+ i18nKeys,
31731
+ logEvent
31732
+ }) => {
31733
+ const t = React.useCallback(
31734
+ (key, fallback) => {
31735
+ const message = toI18N(i18nKeys[key]);
31736
+ if (message) return message;
31737
+ return fallback || key;
31738
+ },
31739
+ [toI18N, i18nKeys]
31740
+ );
31741
+ const api = React.useMemo(() => {
31742
+ const core2 = new CoreApi(apiBaseURL.core, authToken, toI18N);
31743
+ const mfs = new MFSApi(apiBaseURL.mfs, authToken, toI18N);
31744
+ const fileStore = new FilestoreApi(apiBaseURL.fileStore, authToken, toI18N);
31745
+ core2.initApi();
31746
+ mfs.initApi();
31747
+ fileStore.initApi();
31748
+ return {
31749
+ core: core2,
31750
+ mfs,
31751
+ fileStore
31752
+ };
31753
+ }, [authToken, apiBaseURL, toI18N]);
31754
+ const value = React.useMemo(() => {
31755
+ return {
31756
+ authToken,
31757
+ t,
31758
+ i18nKeys,
31759
+ api,
31760
+ logEvent
31761
+ };
31762
+ }, [authToken, t, i18nKeys, api, logEvent]);
31763
+ return /* @__PURE__ */ jsxRuntime.jsx(PostBuilderContext.Provider, { value, children });
31764
+ };
31541
31765
  exports.PostBuilderEditor = PostBuilderEditor;
31766
+ exports.PostBuilderEvents = PostBuilderEvents;
31542
31767
  exports.PostBuilderProvider = PostBuilderProvider;