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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,10 +20770,82 @@ 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
- if (typeof window === "undefined" || typeof localStorage === "undefined" || !editor || editor.isEmpty)
20846
- return;
20848
+ if (typeof window === "undefined" || typeof localStorage === "undefined" || !editor) return;
20847
20849
  const json = editor?.getJSON();
20848
20850
  const filteredJson = filterNodes(json, (node) => !node?.attrs?.uploading);
20849
20851
  if (filteredJson) {
@@ -21096,11 +21098,9 @@ var Progress$1 = React__namespace.forwardRef(
21096
21098
  ...progressProps
21097
21099
  } = props;
21098
21100
  if ((maxProp || maxProp === 0) && !isValidMaxNumber(maxProp)) {
21099
- console.error(getInvalidMaxError(`${maxProp}`, "Progress"));
21100
21101
  }
21101
21102
  const max2 = isValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;
21102
21103
  if (valueProp !== null && !isValidValueNumber(valueProp, max2)) {
21103
- console.error(getInvalidValueError(`${valueProp}`, "Progress"));
21104
21104
  }
21105
21105
  const value = isValidValueNumber(valueProp, max2) ? valueProp : null;
21106
21106
  const valueLabel = isNumber(value) ? getValueLabel(value, max2) : void 0;
@@ -21420,13 +21420,7 @@ const createUpdateMarkByUidCommand = (markName) => {
21420
21420
  state: state2,
21421
21421
  dispatch
21422
21422
  }) => {
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
21423
  if (!dispatch) {
21429
- console.log("No dispatch, returning false");
21430
21424
  return false;
21431
21425
  }
21432
21426
  const { doc, schema } = state2;
@@ -21436,13 +21430,6 @@ const createUpdateMarkByUidCommand = (markName) => {
21436
21430
  doc.descendants((node, pos) => {
21437
21431
  if (node.isText && node.marks?.length) {
21438
21432
  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
21433
  if (mark.type.name === markName && mark.attrs.uid === uid) {
21447
21434
  positions.push({
21448
21435
  from: pos,
@@ -21450,33 +21437,21 @@ const createUpdateMarkByUidCommand = (markName) => {
21450
21437
  mark
21451
21438
  });
21452
21439
  found2 = true;
21453
- console.log("Found matching mark at:", { from: pos, to: pos + node.nodeSize });
21454
21440
  }
21455
21441
  });
21456
21442
  }
21457
21443
  });
21458
- console.log("Total positions found:", positions.length);
21459
- console.log("Positions:", positions);
21460
21444
  if (found2) {
21461
21445
  positions.forEach(({ from, to, mark }) => {
21462
21446
  const newAttrs = { ...mark.attrs, ...attrs };
21463
21447
  const markType = schema.marks[markName];
21464
- console.log("Applying update:", { from, to, oldAttrs: mark.attrs, newAttrs });
21465
21448
  if (markType) {
21466
- console.log("Before removeMark - tr.doc:", tr.doc.toJSON());
21467
21449
  tr = tr.removeMark(from, to, markType);
21468
- console.log("After removeMark - tr.doc:", tr.doc.toJSON());
21469
21450
  tr = tr.addMark(from, to, markType.create(newAttrs));
21470
- console.log("After addMark - tr.doc:", tr.doc.toJSON());
21471
21451
  }
21472
21452
  });
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
21453
  dispatch(tr);
21477
- console.log("Transaction dispatched successfully");
21478
21454
  }
21479
- console.log("=== UPDATE MARK COMMAND END ===");
21480
21455
  return found2;
21481
21456
  };
21482
21457
  };
@@ -22494,7 +22469,6 @@ let warnedAboutTextSelection = false;
22494
22469
  function checkTextSelection($pos) {
22495
22470
  if (!warnedAboutTextSelection && !$pos.parent.inlineContent) {
22496
22471
  warnedAboutTextSelection = true;
22497
- console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")");
22498
22472
  }
22499
22473
  }
22500
22474
  class TextSelection extends Selection {
@@ -23219,7 +23193,6 @@ const PollCreator = ({ choices, onChange }) => {
23219
23193
  const result = await fileStore.uploadImage(file);
23220
23194
  return createPollMediaOption(result, startIndex + index2);
23221
23195
  } catch (error) {
23222
- console.error("Upload failed for", file.name, error);
23223
23196
  return null;
23224
23197
  }
23225
23198
  });
@@ -23239,7 +23212,6 @@ const PollCreator = ({ choices, onChange }) => {
23239
23212
  return final;
23240
23213
  });
23241
23214
  } catch (error) {
23242
- console.error("Unexpected error during file upload:", error);
23243
23215
  setInternalChoices((current) => {
23244
23216
  const withoutPlaceholders = current.filter((c) => !isPlaceholder(c));
23245
23217
  setTimeout(() => {
@@ -23272,7 +23244,6 @@ const PollCreator = ({ choices, onChange }) => {
23272
23244
  return updated;
23273
23245
  });
23274
23246
  } catch (error) {
23275
- console.error("URL upload failed:", error);
23276
23247
  setInternalChoices((current) => {
23277
23248
  const withoutPlaceholder = current.filter((c) => !isPlaceholder(c));
23278
23249
  setTimeout(() => {
@@ -23813,7 +23784,6 @@ const LinkMarkView = ({ mark, editor }) => {
23813
23784
  };
23814
23785
  const handleUpdateLink = (link, text2, uid, previewPayload) => {
23815
23786
  if (!editor.view) return;
23816
- console.log("UPDATE LINK IN VIEW::", { text: text2 });
23817
23787
  const newText = mark?.attrs?.isLinkMode ? link : text2 || link;
23818
23788
  if (uid) {
23819
23789
  editor.commands.updateLink(uid, { href: link, text: newText, previewPayload });
@@ -23873,25 +23843,66 @@ const LinkMarkView = ({ mark, editor }) => {
23873
23843
  )
23874
23844
  ] });
23875
23845
  };
23846
+ function isValidUrlFormat(text2) {
23847
+ return isValidUrl(normalizeUrl(text2.trim()));
23848
+ }
23876
23849
  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;
23850
+ if (!editor || !uid) {
23851
+ return false;
23852
+ }
23853
+ try {
23854
+ let exists = false;
23855
+ editor.state.doc.descendants((node) => {
23856
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23857
+ exists = true;
23858
+ return false;
23859
+ }
23860
+ });
23861
+ return exists;
23862
+ } catch (err) {
23863
+ return false;
23864
+ }
23885
23865
  }
23886
23866
  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;
23867
+ if (!editor) {
23868
+ return null;
23869
+ }
23870
+ try {
23871
+ let result = null;
23872
+ editor.state.doc.descendants((node, pos) => {
23873
+ if (node && node.type && node.type.name === "linkPreview") {
23874
+ result = { node, pos };
23875
+ return false;
23876
+ }
23877
+ });
23878
+ return result;
23879
+ } catch (err) {
23880
+ return null;
23881
+ }
23882
+ }
23883
+ function removePreviewByUid(editor, uid) {
23884
+ if (!editor || !uid) {
23885
+ return;
23886
+ }
23887
+ try {
23888
+ let previewPos = null;
23889
+ let previewSize = 0;
23890
+ editor.state.doc.descendants((node, pos) => {
23891
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23892
+ previewPos = pos;
23893
+ previewSize = node.nodeSize;
23894
+ return false;
23895
+ }
23896
+ });
23897
+ if (previewPos !== null && previewSize > 0) {
23898
+ const tr = editor.state.tr;
23899
+ if (tr) {
23900
+ tr.delete(previewPos, Number(previewPos) + previewSize);
23901
+ editor.view.dispatch(tr);
23902
+ }
23892
23903
  }
23893
- });
23894
- return result;
23904
+ } catch (err) {
23905
+ }
23895
23906
  }
23896
23907
  function extractBestImage(metadata) {
23897
23908
  return metadata?.image?.high_resolution ?? metadata?.image?.url ?? metadata?.image?.thumbnail ?? metadata?.image?.placeholder ?? null;
@@ -23916,6 +23927,76 @@ function collectAllLinkMarks(state2, linkMark) {
23916
23927
  });
23917
23928
  return links;
23918
23929
  }
23930
+ function syncLinkHrefWithText(newState, linkMark, editor, singlePreviewMode, pluginState) {
23931
+ if (!newState || !linkMark || !editor || !pluginState) {
23932
+ return null;
23933
+ }
23934
+ let tr = null;
23935
+ let hasChanges = false;
23936
+ try {
23937
+ newState.doc.descendants((node, pos) => {
23938
+ if (!node || !node.isText || !node.marks?.length) return;
23939
+ node.marks.forEach((mark) => {
23940
+ if (!mark || !mark.type || !mark.attrs) return;
23941
+ if (mark.type === linkMark && mark.attrs?.uid) {
23942
+ const currentText = node.text || "";
23943
+ const currentHref = mark.attrs.href || "";
23944
+ if (currentText !== currentHref) {
23945
+ const isValidUrl2 = isValidUrlFormat(currentText);
23946
+ if (!tr) {
23947
+ tr = newState.tr;
23948
+ }
23949
+ if (!tr) {
23950
+ return;
23951
+ }
23952
+ if (isValidUrl2) {
23953
+ const newMark = linkMark.create({
23954
+ ...mark.attrs,
23955
+ href: normalizeUrl(currentText)
23956
+ });
23957
+ if (!newMark) {
23958
+ return;
23959
+ }
23960
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23961
+ tr = tr.addMark(pos, pos + node.nodeSize, newMark);
23962
+ hasChanges = true;
23963
+ pluginState.processedLinks.delete(mark.attrs.uid);
23964
+ if (singlePreviewMode) {
23965
+ queueMicrotask(() => {
23966
+ try {
23967
+ const existingPreview = findExistingPreview(editor);
23968
+ if (existingPreview && mark.attrs?.uid) {
23969
+ }
23970
+ } catch (err) {
23971
+ }
23972
+ });
23973
+ } else {
23974
+ }
23975
+ } else {
23976
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23977
+ hasChanges = true;
23978
+ queueMicrotask(() => {
23979
+ try {
23980
+ if (mark.attrs?.uid) {
23981
+ removePreviewByUid(editor, mark.attrs.uid);
23982
+ }
23983
+ } catch (err) {
23984
+ }
23985
+ });
23986
+ if (mark.attrs?.uid) {
23987
+ pluginState.processedLinks.delete(mark.attrs.uid);
23988
+ pluginState.resolvingLinks.delete(mark.attrs.uid);
23989
+ }
23990
+ }
23991
+ }
23992
+ }
23993
+ });
23994
+ });
23995
+ } catch (err) {
23996
+ return null;
23997
+ }
23998
+ return hasChanges ? tr : null;
23999
+ }
23919
24000
  function assignUidsToLinks(newState, linkMark) {
23920
24001
  const newUids = /* @__PURE__ */ new Map();
23921
24002
  let tr = null;
@@ -23925,11 +24006,6 @@ function assignUidsToLinks(newState, linkMark) {
23925
24006
  node.marks.forEach((mark) => {
23926
24007
  if (mark.type === linkMark && mark.attrs?.href && !mark.attrs.uid) {
23927
24008
  const newUid = v4();
23928
- console.log("🔧 Assigning UID to autolinked URL:", {
23929
- href: mark.attrs.href,
23930
- uid: newUid,
23931
- pos
23932
- });
23933
24009
  const newMark = linkMark.create({
23934
24010
  ...mark.attrs,
23935
24011
  uid: newUid
@@ -23956,25 +24032,14 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23956
24032
  const { api, editor } = options;
23957
24033
  const mediaGroup = findByType(editor?.getJSON(), "mediaGroup");
23958
24034
  if (!api) {
23959
- console.warn("⚠️ No API provided to resolve link");
23960
24035
  return;
23961
24036
  }
23962
24037
  if (singlePreviewMode && mediaGroup.length >= 1) return;
23963
24038
  pluginState.resolvingLinks.add(link.uid);
23964
- console.log("🌐 Resolving link metadata:", {
23965
- uid: link.uid,
23966
- href: link.href,
23967
- singlePreviewMode
23968
- });
23969
24039
  api.resolveUrl(normalizeUrl(link.href)).then((metadata) => {
23970
24040
  pluginState.resolvingLinks.delete(link.uid);
23971
24041
  pluginState.processedLinks.add(link.uid);
23972
- console.log("✅ Link metadata resolved:", {
23973
- uid: link.uid,
23974
- metadata
23975
- });
23976
24042
  if (!metadata) {
23977
- console.warn("⚠️ No metadata returned for:", link.href);
23978
24043
  return;
23979
24044
  }
23980
24045
  const previewData = {
@@ -23989,13 +24054,11 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23989
24054
  if (singlePreviewMode) {
23990
24055
  const existingPreview = findExistingPreview(editor);
23991
24056
  if (existingPreview) {
23992
- console.log("🔄 Updating existing preview in single mode");
23993
24057
  const { pos } = existingPreview;
23994
24058
  const tr = editor.state.tr;
23995
24059
  tr.setNodeMarkup(pos, void 0, previewData);
23996
24060
  editor.view.dispatch(tr);
23997
24061
  } else {
23998
- console.log("➕ Creating first preview in single mode");
23999
24062
  editor.commands.setLinkPreview(previewData);
24000
24063
  }
24001
24064
  editor.commands.updateLinkByUid(link.uid, {
@@ -24003,16 +24066,12 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
24003
24066
  });
24004
24067
  } else {
24005
24068
  if (!doesPreviewExist(editor, link.uid)) {
24006
- console.log("➕ Creating new preview in multi mode");
24007
24069
  editor.chain().updateLinkByUid(link.uid, {
24008
24070
  previewPayload: convertLinkMetaToPreviewItem(metadata)
24009
24071
  }).setLinkPreview(previewData).run();
24010
- } else {
24011
- console.log("⏭️ Preview already exists, skipping");
24012
24072
  }
24013
24073
  }
24014
24074
  }).catch((err) => {
24015
- console.error("❌ Failed to resolve link:", err);
24016
24075
  pluginState.resolvingLinks.delete(link.uid);
24017
24076
  });
24018
24077
  }
@@ -24022,10 +24081,6 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24022
24081
  key: pluginKey,
24023
24082
  state: {
24024
24083
  init() {
24025
- console.log("🔌 LinkAutoResolve plugin initialized", {
24026
- singlePreviewMode,
24027
- hasApi: !!options.api
24028
- });
24029
24084
  return {
24030
24085
  resolvingLinks: /* @__PURE__ */ new Set(),
24031
24086
  processedLinks: /* @__PURE__ */ new Set()
@@ -24055,27 +24110,22 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24055
24110
  appendTransaction: (transactions, oldState, newState) => {
24056
24111
  const linkMark = newState.schema.marks["customLink"];
24057
24112
  if (!linkMark) {
24058
- console.warn("⚠️ customLink mark not found in schema");
24059
24113
  return null;
24060
24114
  }
24061
24115
  if (!transactions.some((tr) => tr.docChanged)) {
24062
24116
  return null;
24063
24117
  }
24064
- console.log("📝 Document changed, checking for new links...");
24065
24118
  const pluginState = pluginKey.getState(newState);
24119
+ if (!pluginState) {
24120
+ return null;
24121
+ }
24122
+ const syncTr = singlePreviewMode ? syncLinkHrefWithText(newState, linkMark, options.editor, singlePreviewMode, pluginState) : null;
24066
24123
  const oldLinks = collectAllLinkMarks(oldState, linkMark);
24067
24124
  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
24125
  const { tr: uidTr, newUids } = assignUidsToLinks(newState, linkMark);
24075
24126
  const linksToResolve = [];
24076
24127
  newUids.forEach((linkData) => {
24077
24128
  if (!pluginState.processedLinks.has(linkData.uid) && !pluginState.resolvingLinks.has(linkData.uid)) {
24078
- console.log("🆕 New autolinked URL detected:", linkData);
24079
24129
  linksToResolve.push(linkData);
24080
24130
  }
24081
24131
  });
@@ -24088,21 +24138,33 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24088
24138
  return;
24089
24139
  }
24090
24140
  if (!oldLinks.has(uid)) {
24091
- console.log("🆕 New link detected (with UID):", linkData);
24092
24141
  linksToResolve.push(linkData);
24093
24142
  }
24094
24143
  });
24095
24144
  if (linksToResolve.length > 0) {
24096
- console.log("🚀 Processing", linksToResolve.length, "new link(s)");
24097
24145
  queueMicrotask(() => {
24098
24146
  linksToResolve.forEach((link) => {
24099
24147
  resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginState);
24100
24148
  });
24101
24149
  });
24102
- } else {
24103
- console.log("✓ No new links to process");
24104
24150
  }
24105
- return uidTr;
24151
+ if (syncTr && uidTr) {
24152
+ try {
24153
+ uidTr.steps.forEach((step, i) => {
24154
+ if (step && syncTr) {
24155
+ syncTr.step(step);
24156
+ const map = uidTr.mapping.maps[i];
24157
+ if (map) {
24158
+ syncTr.mapping.appendMap(map);
24159
+ }
24160
+ }
24161
+ });
24162
+ return syncTr;
24163
+ } catch (err) {
24164
+ return syncTr;
24165
+ }
24166
+ }
24167
+ return syncTr ?? uidTr ?? null;
24106
24168
  }
24107
24169
  });
24108
24170
  }
@@ -24198,7 +24260,6 @@ const CustomLink = Link__default.default.extend({
24198
24260
  this?.options?.api?.resolveUrl(normalizeUrl(href))?.then((metadata) => {
24199
24261
  if (metadata) {
24200
24262
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24201
- console.log({ href, text: text2 });
24202
24263
  editor?.chain()?.updateLinkByUid(uid, { href, text: text2, previewPayload })?.updateLinkPreviewByUid(uid, {
24203
24264
  // Now using correct UID
24204
24265
  loading: false,
@@ -24257,7 +24318,6 @@ const CustomLink = Link__default.default.extend({
24257
24318
  if (attrs.href) {
24258
24319
  queueMicrotask(() => {
24259
24320
  this.options.api?.resolveUrl(normalizeUrl(attrs.href))?.then((metadata) => {
24260
- console.log({ metadata });
24261
24321
  if (metadata) {
24262
24322
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24263
24323
  let linkPreviewExists = false;
@@ -24286,7 +24346,6 @@ const CustomLink = Link__default.default.extend({
24286
24346
  editor.commands.deleteLinkPreviewByUid(uid);
24287
24347
  }
24288
24348
  }).catch((err) => {
24289
- console.log("LINK UPDATE ERR::", { err });
24290
24349
  editor.commands.deleteLinkPreviewByUid(uid);
24291
24350
  });
24292
24351
  });
@@ -24366,7 +24425,6 @@ const IframeView = ({
24366
24425
  setPreviewData(previewPayload);
24367
24426
  updateAttributes({ previewPayload });
24368
24427
  }).catch((error) => {
24369
- console.error("Failed to fetch preview:", error);
24370
24428
  }).finally(() => {
24371
24429
  });
24372
24430
  }
@@ -24611,7 +24669,6 @@ const _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTyp
24611
24669
  }
24612
24670
  });
24613
24671
  } catch (_) {
24614
- console.warn("TrustedTypes policy " + policyName + " could not be created.");
24615
24672
  return null;
24616
24673
  }
24617
24674
  };
@@ -25448,7 +25505,6 @@ const configureDOMPurify = () => {
25448
25505
  const element = node;
25449
25506
  const src = element.getAttribute("src") || "";
25450
25507
  if (!isAllowedDomain(src)) {
25451
- console.warn("🚨 Blocked iframe from non-allowed domain:", src);
25452
25508
  node.parentNode?.removeChild(node);
25453
25509
  }
25454
25510
  }
@@ -25460,7 +25516,6 @@ function sanitizeIframeHTML(html2) {
25460
25516
  const config = configureDOMPurify();
25461
25517
  const cleaned = purify.sanitize(html2, config);
25462
25518
  if (!cleaned.includes("<iframe")) {
25463
- console.warn("⚠️ No valid iframe found after sanitization");
25464
25519
  return null;
25465
25520
  }
25466
25521
  const match = cleaned.match(/<iframe[^>]*src=["']([^"']+)["']/i);
@@ -25472,7 +25527,6 @@ function sanitizeIframeHTML(html2) {
25472
25527
  }
25473
25528
  return match[1];
25474
25529
  } catch (error) {
25475
- console.error("🚨 Error sanitizing iframe:", error);
25476
25530
  return null;
25477
25531
  } finally {
25478
25532
  purify.removeAllHooks();
@@ -25510,7 +25564,6 @@ const createFinder = (regex) => {
25510
25564
  match
25511
25565
  });
25512
25566
  }
25513
- console.log({ match, matches });
25514
25567
  return matches.length > 0 ? matches : null;
25515
25568
  };
25516
25569
  };
@@ -25562,11 +25615,9 @@ const Iframe = core.Node.create({
25562
25615
  const iframeHTML = match[0];
25563
25616
  const safeSrc = sanitizeIframeHTML(iframeHTML);
25564
25617
  if (!safeSrc) {
25565
- console.warn("🚨 Blocked unsafe iframe paste");
25566
25618
  toast.error("🚨 Your pasted iframe is not safe to render");
25567
25619
  return;
25568
25620
  }
25569
- console.log("✅ Safe iframe URL validated:", safeSrc);
25570
25621
  const node = this.type.create({ src: safeSrc, previewPayload: null });
25571
25622
  state2.tr.replaceRangeWith(range.from, range.to, node);
25572
25623
  }
@@ -25577,7 +25628,6 @@ const Iframe = core.Node.create({
25577
25628
  handler: ({ state: state2, range, match }) => {
25578
25629
  const fullUrl = match[0];
25579
25630
  const embedUrl = getEmbedUrl(fullUrl);
25580
- console.log({ match, fullUrl, embedUrl });
25581
25631
  if (!embedUrl) return;
25582
25632
  const node = this.type.create({ src: embedUrl });
25583
25633
  state2.tr.replaceRangeWith(range.from, range.to, node);
@@ -25623,10 +25673,9 @@ const handleUrlWithoutSelection = (editor, url, event, autoDetectMedia) => {
25623
25673
  mediaType: MediaItemType.MEDIA_ITEM
25624
25674
  });
25625
25675
  }).catch(
25626
- (e) => console.error("[SmartLinkPaste] Media detection failed, falling back to link:", e)
25676
+ (e) => void 0
25627
25677
  );
25628
25678
  }
25629
- console.log("[SmartLinkPaste] Inserting as link node");
25630
25679
  editor.chain().focus().insertLink({ href: normalizedUrl, text: url }).run();
25631
25680
  return true;
25632
25681
  };
@@ -25648,7 +25697,6 @@ const createPasteHandler = (editor, options) => {
25648
25697
  return false;
25649
25698
  }
25650
25699
  const trimmedText = pasteText.trim();
25651
- console.log("[SmartLinkPaste] Valid URL detected:", isEmbeddableUrl(trimmedText));
25652
25700
  if (isEmbeddableUrl(trimmedText) && options?.autoEmbed) {
25653
25701
  event.preventDefault();
25654
25702
  return false;
@@ -25665,7 +25713,6 @@ const createPasteHandler = (editor, options) => {
25665
25713
  options?.autoDetectMedia ?? true
25666
25714
  );
25667
25715
  } catch (error) {
25668
- console.error("[SmartLinkPaste] Error:", error);
25669
25716
  return false;
25670
25717
  }
25671
25718
  };
@@ -25677,10 +25724,8 @@ const createTransformHandler = (editor) => {
25677
25724
  return slice;
25678
25725
  }
25679
25726
  try {
25680
- console.log("[SmartLinkPaste] Transforming inline URLs in pasted content");
25681
25727
  return transformUrlsInSlice(editor, slice);
25682
25728
  } catch (error) {
25683
- console.error("[SmartLinkPaste] Transform error:", error);
25684
25729
  return slice;
25685
25730
  }
25686
25731
  };
@@ -25787,7 +25832,6 @@ const SmartMediaUpload = core.Extension.create({
25787
25832
  const uid = v4();
25788
25833
  const options = this.options;
25789
25834
  if (!options.api) {
25790
- console.error("API instance not provided to SmartMediaUpload");
25791
25835
  return false;
25792
25836
  }
25793
25837
  if (isFileOrBlob(source)) {
@@ -25797,7 +25841,6 @@ const SmartMediaUpload = core.Extension.create({
25797
25841
  options.allowedFileTypes
25798
25842
  );
25799
25843
  if (!validation.valid) {
25800
- console.error("File validation failed:", validation.error);
25801
25844
  options.onUploadError?.(uid, new Error(validation.error));
25802
25845
  return false;
25803
25846
  }
@@ -25881,7 +25924,6 @@ const SmartMediaUpload = core.Extension.create({
25881
25924
  } else editor.commands.deleteMediaByUid(item.uid);
25882
25925
  options.onUploadComplete?.(item.uid, hostedUrl);
25883
25926
  } catch (error) {
25884
- console.error("Upload failed:", error);
25885
25927
  const blobUrl = this.storage.blobUrls.get(item.uid);
25886
25928
  if (blobUrl) {
25887
25929
  URL.revokeObjectURL(blobUrl);
@@ -25893,7 +25935,7 @@ const SmartMediaUpload = core.Extension.create({
25893
25935
  this.storage.activeUploads--;
25894
25936
  this.storage.processUploadQueue(editor);
25895
25937
  }
25896
- })().catch((err) => console.log(err));
25938
+ })().catch((err) => void 0);
25897
25939
  if (this.storage.uploadQueue.length > 0) {
25898
25940
  this.storage.processUploadQueue(editor);
25899
25941
  }
@@ -28593,7 +28635,6 @@ function getSuggestionOptions({
28593
28635
  const text2 = editor.getText();
28594
28636
  const trimmed = text2?.replace(WHITESPACE_REGEX, " ")?.trim();
28595
28637
  const matchStartPosition = trimmed?.lastIndexOf(char);
28596
- console.log({ matchStartPosition });
28597
28638
  const nodeAfter = editor.view.state.selection.$to.nodeAfter;
28598
28639
  const overrideSpace = nodeAfter?.text?.startsWith(" ");
28599
28640
  if (overrideSpace) {
@@ -28707,7 +28748,6 @@ const Mention = core.Node.create({
28707
28748
  renderHTML({ node, HTMLAttributes }) {
28708
28749
  const suggestion2 = getSuggestionFromChar(this, node.attrs.mentionSuggestionChar);
28709
28750
  if (this.options.renderLabel !== void 0) {
28710
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28711
28751
  return [
28712
28752
  "span",
28713
28753
  core.mergeAttributes({ "data-type": this.name }, this.options.HTMLAttributes, HTMLAttributes),
@@ -28747,7 +28787,6 @@ const Mention = core.Node.create({
28747
28787
  suggestion: getSuggestionFromChar(this, node.attrs.mentionSuggestionChar)
28748
28788
  };
28749
28789
  if (this.options.renderLabel !== void 0) {
28750
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28751
28790
  return this.options.renderLabel(args);
28752
28791
  }
28753
28792
  return this.options.renderText(args);
@@ -29736,11 +29775,9 @@ const mentionService = (api, mfs, store) => {
29736
29775
  const fetchMentions = async () => {
29737
29776
  const params = store.getState().getMentionParams();
29738
29777
  if (!params) {
29739
- console.error("DEBUG MENTION SERVICE::", "No group id or post id has been provided");
29740
29778
  return [];
29741
29779
  }
29742
29780
  const { groupId, postId } = params;
29743
- console.log({ groupId, postId });
29744
29781
  const response = postId ? await mfs.getRecommendationPost(groupId, postId, 0, 999) : await mfs.getRecommendationGroup(groupId, 0, 999);
29745
29782
  return response.entries?.filter((item) => Boolean(item?.user_data))?.map(
29746
29783
  (item) => ({
@@ -29759,7 +29796,6 @@ const mentionService = (api, mfs, store) => {
29759
29796
  const { selectedGroupId, groupId } = store.getState();
29760
29797
  const activeGroupId = selectedGroupId ?? groupId;
29761
29798
  if (!activeGroupId) {
29762
- console.warn("DEBUG HASHTAG SERVICE::", "No active group selected or provided");
29763
29799
  return [];
29764
29800
  }
29765
29801
  const response = await api.fetchGroupConversations(999, 0);
@@ -29961,8 +29997,8 @@ const LinkPreviewExtended = ({
29961
29997
  title,
29962
29998
  description,
29963
29999
  image,
29964
- domain
29965
- // onClickDelete,
30000
+ domain,
30001
+ onClickDelete
29966
30002
  }) => {
29967
30003
  const safeDomain = React.useMemo(() => {
29968
30004
  try {
@@ -29971,6 +30007,11 @@ const LinkPreviewExtended = ({
29971
30007
  return "unknown";
29972
30008
  }
29973
30009
  }, [href, domain]);
30010
+ const handleDelete = (e) => {
30011
+ e.preventDefault();
30012
+ e.stopPropagation();
30013
+ onClickDelete();
30014
+ };
29974
30015
  return /* @__PURE__ */ jsxRuntime.jsxs(
29975
30016
  "div",
29976
30017
  {
@@ -29979,18 +30020,32 @@ const LinkPreviewExtended = ({
29979
30020
  selected ? "ring-2 ring-blue-500 ring-offset-2 rounded-lg" : ""
29980
30021
  ),
29981
30022
  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
- ) }),
30023
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 absolute z-50 right-3 top-3", children: [
30024
+ /* @__PURE__ */ jsxRuntime.jsx(
30025
+ ToolbarButton,
30026
+ {
30027
+ asChild: true,
30028
+ tooltip: "Visit Link",
30029
+ className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none group-hover:bg-accent/70 group-hover:text-accent-foreground text-primary-send",
30030
+ children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative", children: [
30031
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "absolute inset-0" }),
30032
+ /* @__PURE__ */ jsxRuntime.jsx(ExternalLink, {})
30033
+ ] })
30034
+ }
30035
+ ),
30036
+ /* @__PURE__ */ jsxRuntime.jsx(
30037
+ ToolbarButton,
30038
+ {
30039
+ tooltip: "Remove Link Preview",
30040
+ onClick: handleDelete,
30041
+ "aria-label": "Delete link preview",
30042
+ type: "button",
30043
+ size: "icon",
30044
+ 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",
30045
+ children: /* @__PURE__ */ jsxRuntime.jsx(Trash2, {})
30046
+ }
30047
+ )
30048
+ ] }),
29994
30049
  /* @__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
30050
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-80 w-full shrink-0 overflow-hidden bg-muted border-b", children: /* @__PURE__ */ jsxRuntime.jsx(
29996
30051
  "img",
@@ -30111,7 +30166,6 @@ const LinkPreview = core.Node.create({
30111
30166
  },
30112
30167
  renderHTML({ node }) {
30113
30168
  const { href, uid, title, description, image, domain } = node.attrs;
30114
- console.log("INSIDE RENDER HTML::", { href, image });
30115
30169
  if (!href) return ["div", {}];
30116
30170
  const content = [
30117
30171
  // Link overlay
@@ -30246,11 +30300,6 @@ const MediaGroupView = ({ node, editor }) => {
30246
30300
  editor.commands.deleteMediaByUid(uid);
30247
30301
  };
30248
30302
  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
30303
  return /* @__PURE__ */ jsxRuntime.jsx(
30255
30304
  react.NodeViewWrapper,
30256
30305
  {
@@ -30352,14 +30401,12 @@ const createMediaModePlugin = () => {
30352
30401
  child.marks.forEach((mark) => {
30353
30402
  if (mark.type.name === "customLink" && mark.attrs.previewPayload) {
30354
30403
  lastLinkPreviewData = mark.attrs.previewPayload;
30355
- console.log("Found link with previewPayload:", lastLinkPreviewData);
30356
30404
  }
30357
30405
  });
30358
30406
  }
30359
30407
  });
30360
30408
  }
30361
30409
  });
30362
- console.log("Cleanup check:", { modified, hasMediaGroup, lastLinkPreviewData });
30363
30410
  if (modified && hasMediaGroup && lastLinkPreviewData) {
30364
30411
  let hasLinkPreview = false;
30365
30412
  tr.doc.forEach((node) => {
@@ -30367,10 +30414,6 @@ const createMediaModePlugin = () => {
30367
30414
  hasLinkPreview = true;
30368
30415
  }
30369
30416
  });
30370
- console.log("Creating linkPreview:", {
30371
- hasLinkPreview,
30372
- schemaHasLinkPreview: !!newState.schema.nodes.linkPreview
30373
- });
30374
30417
  if (!hasLinkPreview && newState.schema.nodes.linkPreview) {
30375
30418
  const preview = lastLinkPreviewData;
30376
30419
  const linkPreviewNode = newState.schema.nodes.linkPreview.create({
@@ -30381,7 +30424,6 @@ const createMediaModePlugin = () => {
30381
30424
  image: preview.linkImage?.url ?? "",
30382
30425
  variant: LinkPreviewType.Extended
30383
30426
  });
30384
- console.log("Inserting linkPreview node:", { lastLinkPreviewData, linkPreviewNode });
30385
30427
  tr.insert(tr.doc.content.size, linkPreviewNode);
30386
30428
  modified = true;
30387
30429
  }
@@ -30441,7 +30483,6 @@ const createMediaModePlugin = () => {
30441
30483
  }
30442
30484
  const mediaNodes = updatedTopLevelMedia.map((m) => m.node);
30443
30485
  if (mediaNodes.some((n) => !n || n.type.name !== "media")) {
30444
- console.warn("Invalid media nodes detected, skipping group creation");
30445
30486
  return null;
30446
30487
  }
30447
30488
  const mediaGroup = newState.schema.nodes.mediaGroup.create({}, mediaNodes);
@@ -30459,7 +30500,6 @@ const createMediaModePlugin = () => {
30459
30500
  const $pos = tr.doc.resolve(endPos);
30460
30501
  tr.setSelection(state.TextSelection.near($pos));
30461
30502
  } catch (e) {
30462
- console.warn("Could not set selection:", e);
30463
30503
  }
30464
30504
  }
30465
30505
  tr.setMeta("addToHistory", false);
@@ -30467,7 +30507,6 @@ const createMediaModePlugin = () => {
30467
30507
  }
30468
30508
  return modified ? tr : null;
30469
30509
  } catch (error) {
30470
- console.error("MediaMode plugin error:", error);
30471
30510
  return null;
30472
30511
  } finally {
30473
30512
  isProcessing = false;
@@ -30609,7 +30648,7 @@ const getMediaExtensions = ({ api, store, user }) => {
30609
30648
  }),
30610
30649
  LinkPreview.configure({
30611
30650
  variant: LinkPreviewType.Extended,
30612
- selectable: false,
30651
+ // selectable: false,
30613
30652
  draggable: false
30614
30653
  }),
30615
30654
  getMentionExtension(core2, mfs, store),
@@ -30753,7 +30792,6 @@ const isLinkMarkWithPayload = (node) => isLinkMark(node) && Boolean(node?.attrs?
30753
30792
  const getLinkItemsPayload = (json) => {
30754
30793
  const links = find(json, (node) => isLinkMarkWithPayload(node));
30755
30794
  const items = links?.at(-1);
30756
- console.log("Link Items Payload::", { items });
30757
30795
  return { items };
30758
30796
  };
30759
30797
  const getPollItemsPayload = (json) => {
@@ -30767,7 +30805,7 @@ const isValidItem = (item) => {
30767
30805
  const mediaItem = item;
30768
30806
  const isValidLinkItem = linkItem?.linkUrl;
30769
30807
  const mediaItemSources = mediaItem?.sources;
30770
- const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url || mediaItemSources?.placeholder?.url;
30808
+ const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url;
30771
30809
  return Boolean(isValidLinkItem || isValidMediaItem);
30772
30810
  };
30773
30811
  const generateHtmlPostPayload = ({
@@ -30787,7 +30825,6 @@ const generateHtmlPostPayload = ({
30787
30825
  )?.at(0);
30788
30826
  const isEmbedOnly = isOnlyContentNode(json, "iframe");
30789
30827
  const body = isEmbedOnly ? previewItemEmbed?.attrs?.previewPayload?.linkTitle ?? previewItemEmbed?.attrs?.src ?? "" : secondaryText?.text ?? firstText?.text ?? "";
30790
- console.log({ firstText });
30791
30828
  const items = [
30792
30829
  previewItemMedia?.attrs?.payload,
30793
30830
  previewItemEmbed?.attrs?.previewPayload,
@@ -30814,11 +30851,14 @@ const generateMediaPostPayload = ({
30814
30851
  const { mentionData } = getMentionDataPayload(json);
30815
30852
  const { items: mediaItems } = getMediaItemsPayload(json);
30816
30853
  const { items: linkItems } = getLinkItemsPayload(json);
30854
+ const items = mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [];
30855
+ if (!body && mediaItems.length === 0)
30856
+ return { error: "Your post is empty. Add text or media to share your thoughts." };
30817
30857
  return {
30818
30858
  ...commons,
30819
30859
  type: mediaItems?.length > 0 ? NewPostType.NEW_POST_MEDIA : linkItems?.length > 0 ? NewPostType.NEW_POST_LINK : NewPostType.NEW_POST_MESSAGE,
30820
30860
  body,
30821
- items: mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [],
30861
+ items,
30822
30862
  mentionData,
30823
30863
  sendCrossMention
30824
30864
  };
@@ -30838,7 +30878,6 @@ const generatePollPostPayload = ({
30838
30878
  option_id: index2 === 0 ? item.option_id : v4(),
30839
30879
  option_color: OPTION_COLORS[index2 % OPTION_COLORS.length]
30840
30880
  })) : items;
30841
- console.log({ polls });
30842
30881
  return {
30843
30882
  ...commons,
30844
30883
  type: NewPostType.NEW_POST_POLL,
@@ -30875,6 +30914,7 @@ const PostBuilderEditorInstance = ({
30875
30914
  const [isDragging, setIsDragging] = React.useState(false);
30876
30915
  const { trackPublish } = usePostBuilderAnalytics();
30877
30916
  const { clearContent } = usePersistence();
30917
+ useHostAnalyticsBridge();
30878
30918
  const handleDragOver = (e) => {
30879
30919
  e.preventDefault();
30880
30920
  setIsDragging(true);
@@ -30894,10 +30934,24 @@ const PostBuilderEditorInstance = ({
30894
30934
  const text2 = editor?.getText();
30895
30935
  const payload = generateCreatePostPayload(editorTab, { editor, sendCrossMention });
30896
30936
  const isPollType = payload?.type === NewPostType.NEW_POST_POLL;
30897
- if (!payload) return;
30937
+ if (payload?.error) {
30938
+ toast.error(payload.error);
30939
+ return;
30940
+ }
30941
+ if (!payload?.postId) return;
30898
30942
  if (isPollType && payload.items?.length === 0)
30899
30943
  return toast.warning(`At least ${POLL_LIMITS.MIN} option is mandatory to create a poll post`);
30900
- trackPublish("attempted");
30944
+ if (typeof window !== "undefined") {
30945
+ window.dispatchEvent(
30946
+ new CustomEvent(PostBuilderEvents.POST_PUBLISH_ATTEMPTED, {
30947
+ detail: {
30948
+ postId: payload.postId,
30949
+ postType: payload.type
30950
+ }
30951
+ })
30952
+ );
30953
+ }
30954
+ trackPublish({ status: "attempted", postId: payload?.postId, postType: payload?.type });
30901
30955
  onCreatePost?.({ payload, html: html2, json, text: text2 });
30902
30956
  if (!clearOnSuccess) return;
30903
30957
  clearContent();
@@ -31071,7 +31125,6 @@ class SessionManager {
31071
31125
  }, SESSION_TIMEOUT_MS);
31072
31126
  }
31073
31127
  endSession(reason) {
31074
- console.log({ reason });
31075
31128
  if (this.inactivityTimer) {
31076
31129
  clearTimeout(this.inactivityTimer);
31077
31130
  }
@@ -31132,7 +31185,7 @@ function useAnalytics({ editorTab, config }) {
31132
31185
  const featureTracker = React.useRef(new FeatureTracker()).current;
31133
31186
  const logEvent = useAnalyticsLogEvent();
31134
31187
  const trackEvent = React.useCallback(
31135
- (name, properties = {}) => {
31188
+ ({ name, properties }) => {
31136
31189
  const fullConfig = { ...DEFAULT_CONFIG, ...config };
31137
31190
  if (!fullConfig.enabled) return;
31138
31191
  sessionManager.updateActivity();
@@ -31140,30 +31193,32 @@ function useAnalytics({ editorTab, config }) {
31140
31193
  session_id: sessionManager.getSessionId(),
31141
31194
  timestamp: Date.now(),
31142
31195
  editor_type: editorTab,
31143
- ...properties
31196
+ ...properties ?? {}
31144
31197
  };
31145
- if (logEvent) {
31146
- logEvent(name, enrichedProperties);
31147
- }
31148
- if (fullConfig.debug) {
31149
- console.log("[Analytics]", name, enrichedProperties);
31150
- }
31198
+ const cleanProps = pickBy(enrichedProperties, (value) => value != null);
31199
+ if (logEvent) logEvent(name, cleanProps);
31151
31200
  },
31152
31201
  [config, editorTab, logEvent, sessionManager]
31153
31202
  );
31154
31203
  React.useEffect(() => {
31155
31204
  const sessionId = sessionManager.startSession();
31156
- trackEvent(ANALYTICS_EVENTS.SESSION.STARTED, {
31157
- session_id: sessionId,
31158
- timestamp: Date.now(),
31159
- editor_type: editorTab
31205
+ trackEvent({
31206
+ name: ANALYTICS_EVENTS.SESSION.STARTED,
31207
+ properties: {
31208
+ session_id: sessionId,
31209
+ timestamp: Date.now(),
31210
+ editor_type: editorTab
31211
+ }
31160
31212
  });
31161
31213
  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()
31214
+ trackEvent({
31215
+ name: ANALYTICS_EVENTS.SESSION.COMPLETED,
31216
+ properties: {
31217
+ session_id: sessionManager.getSessionId(),
31218
+ timestamp: Date.now(),
31219
+ editor_type: editorTab,
31220
+ session_duration_ms: sessionManager.getSessionDuration()
31221
+ }
31167
31222
  });
31168
31223
  };
31169
31224
  window.addEventListener("beforeunload", handleUnload);
@@ -31173,60 +31228,88 @@ function useAnalytics({ editorTab, config }) {
31173
31228
  };
31174
31229
  }, []);
31175
31230
  const trackFeature = React.useCallback(
31176
- (featureName) => {
31231
+ ({ featureName }) => {
31177
31232
  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
31233
+ trackEvent({
31234
+ name: isFirstUse ? ANALYTICS_EVENTS.FEATURE.DISCOVERED : ANALYTICS_EVENTS.FEATURE.USED,
31235
+ properties: {
31236
+ feature_name: featureName,
31237
+ is_first_use: isFirstUse,
31238
+ usage_count: usageCount
31239
+ }
31182
31240
  });
31183
31241
  },
31184
31242
  [trackEvent, featureTracker]
31185
31243
  );
31186
31244
  const trackPublish = React.useCallback(
31187
- (status, data) => {
31245
+ ({ status, data }) => {
31188
31246
  const eventMap = {
31189
31247
  attempted: ANALYTICS_EVENTS.PUBLISH.ATTEMPTED,
31190
31248
  success: ANALYTICS_EVENTS.PUBLISH.SUCCESS,
31191
31249
  failed: ANALYTICS_EVENTS.PUBLISH.FAILED
31192
31250
  };
31193
- trackEvent(eventMap[status], {
31251
+ const properties = {
31194
31252
  editor_type: editorTab,
31195
31253
  session_duration_ms: sessionManager.getSessionDuration(),
31196
31254
  ...data
31255
+ };
31256
+ trackEvent({
31257
+ name: eventMap[status],
31258
+ properties
31197
31259
  });
31198
31260
  sessionManager.endSession("completed");
31199
31261
  },
31200
31262
  [trackEvent, editorTab, sessionManager]
31201
31263
  );
31202
31264
  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
31265
+ ({
31266
+ contentLength,
31267
+ hasUnsavedChanges,
31268
+ abandonReason,
31269
+ postType,
31270
+ userHistoryData
31271
+ }) => {
31272
+ trackEvent({
31273
+ name: ANALYTICS_EVENTS.SESSION.ABANDONED,
31274
+ properties: {
31275
+ session_duration_ms: sessionManager.getSessionDuration(),
31276
+ post_type: postType,
31277
+ content_length: contentLength,
31278
+ has_unsaved_changes: hasUnsavedChanges,
31279
+ abandon_reason: abandonReason,
31280
+ // Include user history if provided
31281
+ ...userHistoryData && {
31282
+ previous_abandon_count: userHistoryData.previous_abandon_count,
31283
+ previous_publish_count: userHistoryData.previous_publish_count,
31284
+ time_since_last_publish_ms: userHistoryData.time_since_last_publish_ms,
31285
+ is_returning_user: userHistoryData.is_returning_user
31286
+ }
31287
+ }
31210
31288
  });
31211
31289
  sessionManager.endSession("abandoned");
31212
31290
  },
31213
31291
  [trackEvent, sessionManager]
31214
31292
  );
31215
31293
  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
31294
+ ({ oldTab, newTab }) => {
31295
+ trackEvent({
31296
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31297
+ properties: {
31298
+ from_tab: oldTab,
31299
+ to_tab: newTab
31300
+ }
31221
31301
  });
31222
31302
  },
31223
- [trackEvent, editorTab]
31303
+ [trackEvent]
31224
31304
  );
31225
31305
  const trackEditorFocus = React.useCallback(
31226
- (context) => {
31227
- trackEvent(ANALYTICS_EVENTS.EDITOR.FOCUSED, {
31228
- context,
31229
- editor_type: editorTab
31306
+ ({ context }) => {
31307
+ trackEvent({
31308
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31309
+ properties: {
31310
+ context,
31311
+ editor_type: editorTab
31312
+ }
31230
31313
  });
31231
31314
  },
31232
31315
  [trackEvent, editorTab]
@@ -31260,19 +31343,91 @@ function useAnalytics({ editorTab, config }) {
31260
31343
  ]
31261
31344
  );
31262
31345
  }
31346
+ const STORAGE_KEY = "pb_user_history";
31347
+ class UserHistoryTracker {
31348
+ history;
31349
+ constructor() {
31350
+ this.history = this.loadHistory();
31351
+ }
31352
+ loadHistory() {
31353
+ try {
31354
+ const stored = localStorage.getItem(STORAGE_KEY);
31355
+ if (stored) {
31356
+ return JSON.parse(stored);
31357
+ }
31358
+ } catch (error) {
31359
+ }
31360
+ return {
31361
+ previous_abandon_count: 0,
31362
+ previous_publish_count: 0,
31363
+ last_publish_timestamp: null,
31364
+ last_abandon_timestamp: null,
31365
+ first_session_timestamp: Date.now()
31366
+ };
31367
+ }
31368
+ saveHistory() {
31369
+ try {
31370
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.history));
31371
+ } catch (error) {
31372
+ }
31373
+ }
31374
+ /**
31375
+ * Record a successful publish
31376
+ */
31377
+ recordPublish() {
31378
+ this.history.previous_publish_count += 1;
31379
+ this.history.last_publish_timestamp = Date.now();
31380
+ this.saveHistory();
31381
+ }
31382
+ /**
31383
+ * Record an abandonment
31384
+ */
31385
+ recordAbandon() {
31386
+ this.history.previous_abandon_count += 1;
31387
+ this.history.last_abandon_timestamp = Date.now();
31388
+ this.saveHistory();
31389
+ }
31390
+ /**
31391
+ * Get current user history for analytics
31392
+ */
31393
+ getHistory() {
31394
+ const now2 = Date.now();
31395
+ const daysSinceFirstSession = Math.floor(
31396
+ (now2 - this.history.first_session_timestamp) / (1e3 * 60 * 60 * 24)
31397
+ );
31398
+ return {
31399
+ previous_abandon_count: this.history.previous_abandon_count,
31400
+ previous_publish_count: this.history.previous_publish_count,
31401
+ time_since_last_publish_ms: this.history.last_publish_timestamp ? now2 - this.history.last_publish_timestamp : null,
31402
+ is_returning_user: daysSinceFirstSession > 0.5,
31403
+ days_since_first_session: daysSinceFirstSession
31404
+ };
31405
+ }
31406
+ /**
31407
+ * Clear history (for testing or user request)
31408
+ */
31409
+ clearHistory() {
31410
+ localStorage.removeItem(STORAGE_KEY);
31411
+ this.history = {
31412
+ previous_abandon_count: 0,
31413
+ previous_publish_count: 0,
31414
+ last_publish_timestamp: null,
31415
+ last_abandon_timestamp: null,
31416
+ first_session_timestamp: Date.now()
31417
+ };
31418
+ }
31419
+ }
31263
31420
  function useEditorAnalytics({
31264
31421
  editor,
31265
31422
  editorType,
31266
31423
  context,
31267
31424
  idleTimeout = 3e5,
31268
- // 5 minutes
31269
31425
  trackBlur = false
31270
- // Default: don't track every blur
31271
31426
  }) {
31272
31427
  const analytics = useAnalytics({
31273
31428
  editorTab: editorType,
31274
31429
  config: {
31275
- debug: false,
31430
+ debug: true,
31276
31431
  enabled: true
31277
31432
  }
31278
31433
  });
@@ -31280,6 +31435,7 @@ function useEditorAnalytics({
31280
31435
  const idleTimer = React.useRef();
31281
31436
  const hasFocusedOnce = React.useRef(false);
31282
31437
  const hasAbandonedSession = React.useRef(false);
31438
+ const userHistory = React.useRef(new UserHistoryTracker()).current;
31283
31439
  const getEditorMetrics = React.useCallback(() => {
31284
31440
  if (!editor) return null;
31285
31441
  const json = editor.getJSON();
@@ -31319,7 +31475,6 @@ function useEditorAnalytics({
31319
31475
  linkCount,
31320
31476
  formattingFeatures: Array.from(formattingFeatures),
31321
31477
  hasUnsavedChanges: editor.state.doc.content.size > 2,
31322
- // Has content beyond empty doc
31323
31478
  isEmpty: editor.isEmpty
31324
31479
  };
31325
31480
  }, [editor, analytics]);
@@ -31330,16 +31485,29 @@ function useEditorAnalytics({
31330
31485
  idleTimer.current = setTimeout(() => {
31331
31486
  const metrics = getEditorMetrics();
31332
31487
  if (metrics && !metrics.isEmpty) {
31333
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "idle_timeout");
31488
+ const history = userHistory.getHistory();
31489
+ analytics.trackAbandon({
31490
+ contentLength: metrics.characterCount,
31491
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31492
+ abandonReason: "idle_timeout",
31493
+ postType: void 0,
31494
+ userHistoryData: {
31495
+ previous_abandon_count: history.previous_abandon_count,
31496
+ previous_publish_count: history.previous_publish_count,
31497
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31498
+ is_returning_user: history.is_returning_user
31499
+ }
31500
+ });
31501
+ userHistory.recordAbandon();
31334
31502
  hasAbandonedSession.current = true;
31335
31503
  }
31336
31504
  }, idleTimeout);
31337
- }, [editor, idleTimeout, analytics, getEditorMetrics]);
31505
+ }, [editor, idleTimeout, analytics, getEditorMetrics, userHistory]);
31338
31506
  React.useEffect(() => {
31339
31507
  if (!editor) return;
31340
31508
  const handleFocus = () => {
31341
31509
  if (!hasFocusedOnce.current) {
31342
- analytics.trackEditorFocus(context);
31510
+ analytics.trackEditorFocus({ context });
31343
31511
  hasFocusedOnce.current = true;
31344
31512
  }
31345
31513
  resetIdleTimer();
@@ -31350,9 +31518,12 @@ function useEditorAnalytics({
31350
31518
  if (trackBlur) {
31351
31519
  const metrics = getEditorMetrics();
31352
31520
  if (metrics && !metrics.isEmpty) {
31353
- analytics.trackEvent(ANALYTICS_EVENTS.EDITOR.BLURRED, {
31354
- content_length: metrics.characterCount,
31355
- session_duration_ms: Date.now() - lastActivity.current
31521
+ analytics.trackEvent({
31522
+ name: ANALYTICS_EVENTS.EDITOR.BLURRED,
31523
+ properties: {
31524
+ content_length: metrics.characterCount,
31525
+ session_duration_ms: Date.now() - lastActivity.current
31526
+ }
31356
31527
  });
31357
31528
  }
31358
31529
  }
@@ -31371,7 +31542,20 @@ function useEditorAnalytics({
31371
31542
  if (hasAbandonedSession.current) return;
31372
31543
  const metrics = getEditorMetrics();
31373
31544
  if (metrics && !metrics.isEmpty) {
31374
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "navigation");
31545
+ const history = userHistory.getHistory();
31546
+ analytics.trackAbandon({
31547
+ contentLength: metrics.characterCount,
31548
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31549
+ abandonReason: "navigation",
31550
+ postType: void 0,
31551
+ userHistoryData: {
31552
+ previous_abandon_count: history.previous_abandon_count,
31553
+ previous_publish_count: history.previous_publish_count,
31554
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31555
+ is_returning_user: history.is_returning_user
31556
+ }
31557
+ });
31558
+ userHistory.recordAbandon();
31375
31559
  hasAbandonedSession.current = true;
31376
31560
  }
31377
31561
  };
@@ -31382,46 +31566,76 @@ function useEditorAnalytics({
31382
31566
  clearTimeout(idleTimer.current);
31383
31567
  }
31384
31568
  };
31385
- }, [editor, analytics, getEditorMetrics]);
31569
+ }, [editor, analytics, getEditorMetrics, userHistory]);
31386
31570
  const trackFeature = React.useCallback(
31387
- (featureName) => {
31388
- analytics.trackFeature(featureName);
31571
+ ({ featureName }) => {
31572
+ analytics.trackFeature({ featureName });
31389
31573
  resetIdleTimer();
31390
31574
  },
31391
31575
  [analytics, resetIdleTimer]
31392
31576
  );
31393
31577
  const trackPublish = React.useCallback(
31394
- (status, failureReason) => {
31578
+ ({ sessionId, groupId, postId, status, failureReason, postType }) => {
31395
31579
  const metrics = getEditorMetrics();
31396
31580
  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
31581
+ const history = userHistory.getHistory();
31582
+ analytics.trackPublish({
31583
+ status,
31584
+ data: {
31585
+ ...sessionId ? { session_id: sessionId } : {},
31586
+ group_id: groupId,
31587
+ post_id: postId,
31588
+ post_type: postType,
31589
+ word_count: metrics.wordCount,
31590
+ character_count: metrics.characterCount,
31591
+ media_count: metrics.mediaCount,
31592
+ link_count: metrics.linkCount,
31593
+ formatting_features: metrics.formattingFeatures,
31594
+ failure_reason: failureReason,
31595
+ // Include user history
31596
+ previous_abandon_count: history.previous_abandon_count,
31597
+ previous_publish_count: history.previous_publish_count,
31598
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31599
+ is_returning_user: history.is_returning_user
31600
+ }
31404
31601
  });
31405
31602
  if (status === "success") {
31603
+ userHistory.recordPublish();
31406
31604
  hasAbandonedSession.current = true;
31407
31605
  }
31408
31606
  },
31409
- [analytics, getEditorMetrics]
31607
+ [analytics, getEditorMetrics, userHistory]
31410
31608
  );
31411
31609
  const trackExplicitAbandon = React.useCallback(() => {
31412
31610
  if (hasAbandonedSession.current) return;
31413
31611
  const metrics = getEditorMetrics();
31414
31612
  if (metrics && !metrics.isEmpty) {
31415
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "user_closed");
31613
+ const history = userHistory.getHistory();
31614
+ analytics.trackAbandon({
31615
+ contentLength: metrics.characterCount,
31616
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31617
+ abandonReason: "user_closed",
31618
+ postType: void 0,
31619
+ userHistoryData: {
31620
+ previous_abandon_count: history.previous_abandon_count,
31621
+ previous_publish_count: history.previous_publish_count,
31622
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31623
+ is_returning_user: history.is_returning_user
31624
+ }
31625
+ });
31626
+ userHistory.recordAbandon();
31416
31627
  hasAbandonedSession.current = true;
31417
31628
  }
31418
- }, [analytics, getEditorMetrics]);
31629
+ }, [analytics, getEditorMetrics, userHistory]);
31419
31630
  return {
31420
31631
  trackFeature,
31421
31632
  trackPublish,
31422
31633
  trackExplicitAbandon,
31423
31634
  trackTabSwitch: analytics.trackTabSwitch,
31424
- getEditorMetrics
31635
+ getEditorMetrics,
31636
+ // Expose user history for debugging
31637
+ getUserHistory: () => userHistory.getHistory(),
31638
+ currentSessionId: analytics.getSessionId()
31425
31639
  };
31426
31640
  }
31427
31641
  const PostBuilderAnalyticsProvider = ({
@@ -31487,56 +31701,66 @@ const PostBuilderEditor = ({
31487
31701
  isSubmitting,
31488
31702
  clearOnSuccess
31489
31703
  }
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
- ) }),
31704
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "prose-blockquote: flex-1 flex flex-col space-y-3 max-w-full max-h-[calc(100dvh-7rem)]", children: [
31705
+ !hideGroupSelector && /* @__PURE__ */ jsxRuntime.jsx(GroupSelector, { user, store }),
31706
+ /* @__PURE__ */ jsxRuntime.jsx(
31707
+ PostBuilderEditorInstance,
31708
+ {
31709
+ editor,
31710
+ actions,
31711
+ editorTab,
31712
+ onSwitchEditor: setEditorTab,
31713
+ isSubmitting,
31714
+ onCreatePost,
31715
+ clearOnSuccess
31716
+ }
31717
+ )
31718
+ ] }) }),
31536
31719
  /* @__PURE__ */ jsxRuntime.jsx(Toaster2, { position: "top-center" })
31537
31720
  ] })
31538
31721
  }
31539
31722
  );
31540
31723
  };
31724
+ const PostBuilderProvider = ({
31725
+ children,
31726
+ apiBaseURL,
31727
+ authToken,
31728
+ toI18N,
31729
+ i18nKeys,
31730
+ logEvent
31731
+ }) => {
31732
+ const t = React.useCallback(
31733
+ (key, fallback) => {
31734
+ const message = toI18N(i18nKeys[key]);
31735
+ if (message) return message;
31736
+ return fallback || key;
31737
+ },
31738
+ [toI18N, i18nKeys]
31739
+ );
31740
+ const api = React.useMemo(() => {
31741
+ const core2 = new CoreApi(apiBaseURL.core, authToken, toI18N);
31742
+ const mfs = new MFSApi(apiBaseURL.mfs, authToken, toI18N);
31743
+ const fileStore = new FilestoreApi(apiBaseURL.fileStore, authToken, toI18N);
31744
+ core2.initApi();
31745
+ mfs.initApi();
31746
+ fileStore.initApi();
31747
+ return {
31748
+ core: core2,
31749
+ mfs,
31750
+ fileStore
31751
+ };
31752
+ }, [authToken, apiBaseURL, toI18N]);
31753
+ const value = React.useMemo(() => {
31754
+ return {
31755
+ authToken,
31756
+ t,
31757
+ i18nKeys,
31758
+ api,
31759
+ logEvent
31760
+ };
31761
+ }, [authToken, t, i18nKeys, api, logEvent]);
31762
+ return /* @__PURE__ */ jsxRuntime.jsx(PostBuilderContext.Provider, { value, children });
31763
+ };
31541
31764
  exports.PostBuilderEditor = PostBuilderEditor;
31765
+ exports.PostBuilderEvents = PostBuilderEvents;
31542
31766
  exports.PostBuilderProvider = PostBuilderProvider;