@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.
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import React__default, { createContext, useContext, useCallback, useMemo, useLayoutEffect, useState, forwardRef, createElement, useEffect, useRef, Component, useImperativeHandle } from "react";
2
+ import React__default, { createContext, useContext, useLayoutEffect, useState, forwardRef, createElement, useEffect, useMemo, useRef, Component, useCallback, useImperativeHandle } from "react";
3
3
  import * as ReactDOM from "react-dom";
4
4
  import ReactDOM__default from "react-dom";
5
5
  import { jsx, Fragment as Fragment$1, jsxs } from "react/jsx-runtime";
@@ -2053,19 +2053,12 @@ validators$1.transitional = function transitional(validator2, version, message)
2053
2053
  }
2054
2054
  if (version && !deprecatedWarnings[opt]) {
2055
2055
  deprecatedWarnings[opt] = true;
2056
- console.warn(
2057
- formatMessage(
2058
- opt,
2059
- " has been deprecated since v" + version + " and will be removed in the near future"
2060
- )
2061
- );
2062
2056
  }
2063
2057
  return validator2 ? validator2(value, opt, opts) : true;
2064
2058
  };
2065
2059
  };
2066
2060
  validators$1.spelling = function spelling(correctSpelling) {
2067
2061
  return (value, opt) => {
2068
- console.warn(`${opt} is likely a misspelling of ${correctSpelling}`);
2069
2062
  return true;
2070
2063
  };
2071
2064
  };
@@ -3924,7 +3917,6 @@ const Toaster$1 = /* @__PURE__ */ React__default.forwardRef(function Toaster(pro
3924
3917
  setActualTheme("light");
3925
3918
  }
3926
3919
  } catch (e) {
3927
- console.error(e);
3928
3920
  }
3929
3921
  });
3930
3922
  }
@@ -4592,46 +4584,6 @@ const useAnalyticsLogEvent = () => {
4592
4584
  const { logEvent } = usePostBuilder();
4593
4585
  return logEvent;
4594
4586
  };
4595
- const PostBuilderProvider = ({
4596
- children,
4597
- apiBaseURL,
4598
- authToken,
4599
- toI18N,
4600
- i18nKeys,
4601
- logEvent
4602
- }) => {
4603
- const t = useCallback(
4604
- (key, fallback) => {
4605
- const message = toI18N(i18nKeys[key]);
4606
- if (message) return message;
4607
- return fallback || key;
4608
- },
4609
- [toI18N, i18nKeys]
4610
- );
4611
- const api = useMemo(() => {
4612
- const core = new CoreApi(apiBaseURL.core, authToken, toI18N);
4613
- const mfs = new MFSApi(apiBaseURL.mfs, authToken, toI18N);
4614
- const fileStore = new FilestoreApi(apiBaseURL.fileStore, authToken, toI18N);
4615
- core.initApi();
4616
- mfs.initApi();
4617
- fileStore.initApi();
4618
- return {
4619
- core,
4620
- mfs,
4621
- fileStore
4622
- };
4623
- }, [authToken, apiBaseURL, toI18N]);
4624
- const value = useMemo(() => {
4625
- return {
4626
- authToken,
4627
- t,
4628
- i18nKeys,
4629
- api,
4630
- logEvent
4631
- };
4632
- }, [authToken, t, i18nKeys, api, logEvent]);
4633
- return /* @__PURE__ */ jsx(PostBuilderContext.Provider, { value, children });
4634
- };
4635
4587
  function composeEventHandlers(originalEventHandler, ourEventHandler, { checkForDefaultPrevented = true } = {}) {
4636
4588
  return function handleEvent(event) {
4637
4589
  originalEventHandler?.(event);
@@ -4975,9 +4927,6 @@ function useControllableState({
4975
4927
  if (wasControlled !== isControlled) {
4976
4928
  const from = wasControlled ? "controlled" : "uncontrolled";
4977
4929
  const to = isControlled ? "controlled" : "uncontrolled";
4978
- console.warn(
4979
- `${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.`
4980
- );
4981
4930
  }
4982
4931
  isControlledRef.current = isControlled;
4983
4932
  }, [isControlled, caller]);
@@ -8582,7 +8531,7 @@ const EditorTypeTabs = ({ editorTab, onSwitchEditorTab }) => {
8582
8531
  const { trackTabSwitch } = usePostBuilderAnalytics();
8583
8532
  const handleSwitchTab = (newTab) => {
8584
8533
  const oldTab = editorTab;
8585
- trackTabSwitch(oldTab, newTab);
8534
+ trackTabSwitch({ oldTab, newTab });
8586
8535
  onSwitchEditorTab(newTab);
8587
8536
  };
8588
8537
  return /* @__PURE__ */ jsx(
@@ -11304,7 +11253,6 @@ var correctTargets = function(parent2, targets) {
11304
11253
  if (correctedTarget && parent2.contains(correctedTarget)) {
11305
11254
  return correctedTarget;
11306
11255
  }
11307
- console.error("aria-hidden", target, "in not contained inside", parent2, ". Doing nothing");
11308
11256
  return null;
11309
11257
  }).filter(function(x2) {
11310
11258
  return Boolean(x2);
@@ -11353,7 +11301,6 @@ var applyAttributeToOthers = function(originalTarget, parentNode, markerName, co
11353
11301
  node.setAttribute(controlAttribute, "true");
11354
11302
  }
11355
11303
  } catch (e) {
11356
- console.error("aria-hidden: cannot operate on ", node, e);
11357
11304
  }
11358
11305
  }
11359
11306
  });
@@ -13991,15 +13938,11 @@ function requireUseSyncExternalStoreShim_development() {
13991
13938
  return x2 === y && (0 !== x2 || 1 / x2 === 1 / y) || x2 !== x2 && y !== y;
13992
13939
  }
13993
13940
  function useSyncExternalStore$2(subscribe2, getSnapshot) {
13994
- didWarnOld18Alpha || void 0 === React2.startTransition || (didWarnOld18Alpha = true, console.error(
13995
- "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."
13996
- ));
13941
+ didWarnOld18Alpha || void 0 === React2.startTransition || (didWarnOld18Alpha = true, void 0);
13997
13942
  var value = getSnapshot();
13998
13943
  if (!didWarnUncachedGetSnapshot) {
13999
13944
  var cachedValue = getSnapshot();
14000
- objectIs(value, cachedValue) || (console.error(
14001
- "The result of getSnapshot should be cached to avoid an infinite loop"
14002
- ), didWarnUncachedGetSnapshot = true);
13945
+ objectIs(value, cachedValue) || (void 0, didWarnUncachedGetSnapshot = true);
14003
13946
  }
14004
13947
  cachedValue = useState2({
14005
13948
  inst: { value, getSnapshot }
@@ -14231,9 +14174,6 @@ const GroupSelector = ({ store }) => {
14231
14174
  setGroups(response.entries ?? []);
14232
14175
  }
14233
14176
  } catch (error) {
14234
- if (!cancelled) {
14235
- console.error("Failed to fetch groups:", error);
14236
- }
14237
14177
  } finally {
14238
14178
  if (!cancelled) {
14239
14179
  setIsLoading(false);
@@ -14882,7 +14822,7 @@ const ToolbarButton = forwardRef(
14882
14822
  const { trackFeature } = usePostBuilderAnalytics();
14883
14823
  const handleClick = (e) => {
14884
14824
  onClick?.(e);
14885
- if (id) trackFeature(id);
14825
+ if (id) trackFeature({ featureName: id });
14886
14826
  if (!editor) return;
14887
14827
  requestAnimationFrame(editor?.chain()?.focus);
14888
14828
  };
@@ -15186,7 +15126,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
15186
15126
  React.useEffect(() => {
15187
15127
  if (titleId) {
15188
15128
  const hasTitle = document.getElementById(titleId);
15189
- if (!hasTitle) console.error(MESSAGE);
15129
+ if (!hasTitle) ;
15190
15130
  }
15191
15131
  }, [MESSAGE, titleId]);
15192
15132
  return null;
@@ -15199,7 +15139,7 @@ var DescriptionWarning = ({ contentRef, descriptionId }) => {
15199
15139
  const describedById = contentRef.current?.getAttribute("aria-describedby");
15200
15140
  if (descriptionId && describedById) {
15201
15141
  const hasDescription = document.getElementById(descriptionId);
15202
- if (!hasDescription) console.warn(MESSAGE);
15142
+ if (!hasDescription) ;
15203
15143
  }
15204
15144
  }, [MESSAGE, contentRef, descriptionId]);
15205
15145
  return null;
@@ -15585,7 +15525,6 @@ const InputGroupText = forwardRef(
15585
15525
  InputGroupText.displayName = "InputGroupText";
15586
15526
  const InputGroupInput = forwardRef(
15587
15527
  ({ className, ref: legacyRef, ...props }, ref) => {
15588
- console.log({ legacyRef });
15589
15528
  return /* @__PURE__ */ jsx(
15590
15529
  Input,
15591
15530
  {
@@ -16206,7 +16145,6 @@ const resolveUrlType = async (url) => {
16206
16145
  if (mime?.startsWith("video/")) return { type: MediaNodeTypes.Video, src: url };
16207
16146
  if (mime?.startsWith("audio/")) return { type: MediaNodeTypes.Audio, src: url };
16208
16147
  } catch (error) {
16209
- console.warn("HEAD request failed, falling back to mime detection:", error);
16210
16148
  }
16211
16149
  const ext = url.split(".").pop()?.toLowerCase();
16212
16150
  if (ext) {
@@ -16345,11 +16283,9 @@ const LinkDecoratorModal = ({
16345
16283
  setIsValid(isValid2);
16346
16284
  };
16347
16285
  const handleInsertLink = (link2, text22, uid2) => {
16348
- console.log("HANDLE INSERT LINK::", { link: link2, text: text22 });
16349
16286
  setIsLoading(true);
16350
16287
  let metadata;
16351
- core?.resolveUrl(link2)?.then((res) => metadata = res)?.catch((err) => console.log(err))?.finally(() => {
16352
- console.log({ metadata });
16288
+ core?.resolveUrl(link2)?.then((res) => metadata = res)?.catch((err) => void 0)?.finally(() => {
16353
16289
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
16354
16290
  setIsLoading(false);
16355
16291
  onInsertLink(link2, text22, uid2, previewPayload);
@@ -16361,12 +16297,10 @@ const LinkDecoratorModal = ({
16361
16297
  e.preventDefault();
16362
16298
  const isTextInput = textInputRef.current === e.target;
16363
16299
  if (isTextInput || hideTextInput) return handleInsertLink(link, text2, uid ?? void 0);
16364
- console.log("Enter", isTextInput);
16365
16300
  textInputRef?.current?.focus();
16366
16301
  }
16367
16302
  };
16368
16303
  useEffect(() => {
16369
- console.log({ defaultValues });
16370
16304
  if (!defaultValues?.link) return;
16371
16305
  const isValid2 = isValidUrl(defaultValues?.link);
16372
16306
  setIsValid(isValid2);
@@ -16375,7 +16309,6 @@ const LinkDecoratorModal = ({
16375
16309
  setLink(defaultValues?.link ?? "");
16376
16310
  setText(defaultValues?.text || "");
16377
16311
  }, [defaultValues]);
16378
- console.log("TEXT INSIDE LINK DECORATOR::", { isValid, text: text2 });
16379
16312
  return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange: handleOpenChange, children: [
16380
16313
  children ? /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children }) : null,
16381
16314
  /* @__PURE__ */ jsxs(DialogContent, { className: "-translate-1/2", children: [
@@ -16560,10 +16493,8 @@ function parseThreshold(scrollThreshold) {
16560
16493
  value: parseFloat(scrollThreshold)
16561
16494
  };
16562
16495
  }
16563
- console.warn('scrollThreshold format is invalid. Valid formats: "120px", "50%"...');
16564
16496
  return defaultThreshold;
16565
16497
  }
16566
- console.warn("scrollThreshold should be string or number");
16567
16498
  return defaultThreshold;
16568
16499
  }
16569
16500
  var InfiniteScroll = (
@@ -16585,7 +16516,6 @@ var InfiniteScroll = (
16585
16516
  return document.getElementById(_this.props.scrollableTarget);
16586
16517
  }
16587
16518
  if (_this.props.scrollableTarget === null) {
16588
- 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 ");
16589
16519
  }
16590
16520
  return null;
16591
16521
  };
@@ -16830,7 +16760,6 @@ function useMediaSearch(type) {
16830
16760
  setItems((prev) => reset2 ? data : [...prev, ...data]);
16831
16761
  }
16832
16762
  } catch (error) {
16833
- console.error("Error fetching images:", error);
16834
16763
  pagination.setHasMore(false);
16835
16764
  } finally {
16836
16765
  pagination.setLoading(false);
@@ -16849,7 +16778,6 @@ function useMediaSearch(type) {
16849
16778
  setItems((prev) => reset2 ? data : [...prev, ...data]);
16850
16779
  }
16851
16780
  } catch (error) {
16852
- console.error("Error fetching gifs:", error);
16853
16781
  pagination.setHasMore(false);
16854
16782
  } finally {
16855
16783
  pagination.setLoading(false);
@@ -18424,8 +18352,8 @@ function ImageSearchModal({
18424
18352
  setSearchQuery("");
18425
18353
  return;
18426
18354
  }
18427
- gifSearch.fetch(withInitialQuery).catch((err) => console.log(err));
18428
- imageSearch.fetch(withInitialQuery).catch((err) => console.log(err));
18355
+ gifSearch.fetch(withInitialQuery).catch((err) => void 0);
18356
+ imageSearch.fetch(withInitialQuery).catch((err) => void 0);
18429
18357
  };
18430
18358
  const debouncedSearch = useMemo(
18431
18359
  () => debounce$2(async (query) => {
@@ -18443,7 +18371,7 @@ function ImageSearchModal({
18443
18371
  const handleSearch = useCallback(
18444
18372
  (query) => {
18445
18373
  setSearchQuery(query);
18446
- debouncedSearch(query)?.catch((err) => console.log(err));
18374
+ debouncedSearch(query)?.catch((err) => void 0);
18447
18375
  },
18448
18376
  [debouncedSearch]
18449
18377
  );
@@ -20397,7 +20325,9 @@ const Toolbar = ({
20397
20325
  };
20398
20326
  const handleImageClick = (imageUrl, searchFrom) => {
20399
20327
  if (searchFrom) {
20400
- trackFeature(searchFrom === ImageSearchFrom.Gif ? "gif_search" : "image_search");
20328
+ trackFeature({
20329
+ featureName: searchFrom === ImageSearchFrom.Gif ? "gif_search" : "image_search"
20330
+ });
20401
20331
  }
20402
20332
  editor?.commands.insertMediaWithUpload({
20403
20333
  source: imageUrl,
@@ -20810,10 +20740,82 @@ const Toolbar = ({
20810
20740
  ] });
20811
20741
  };
20812
20742
  const VerticalSeparator = () => /* @__PURE__ */ jsx("div", { className: "h-3 w-px bg-border" });
20743
+ var PostBuilderEvents = /* @__PURE__ */ ((PostBuilderEvents2) => {
20744
+ PostBuilderEvents2["POST_PUBLISH_ATTEMPTED"] = "select:post_publish_attempted";
20745
+ PostBuilderEvents2["POST_PUBLISH_SUCCESSFUL"] = "select:post_publish_success";
20746
+ PostBuilderEvents2["POST_PUBLISH_FAILED"] = "select:post_publish_failed";
20747
+ return PostBuilderEvents2;
20748
+ })(PostBuilderEvents || {});
20749
+ const useHostAnalyticsBridge = () => {
20750
+ const analytics = usePostBuilderAnalytics();
20751
+ const sessionIdRef = useRef(null);
20752
+ const processedRequestIds = useRef(/* @__PURE__ */ new Set());
20753
+ useEffect(() => {
20754
+ const onPublishSuccess = (e) => {
20755
+ const { postId, postType, groupId, failureReason } = e.detail;
20756
+ if (!postId || processedRequestIds.current.has(postId)) return;
20757
+ processedRequestIds.current.add(postId);
20758
+ analytics.trackPublish({
20759
+ sessionId: sessionIdRef.current ?? analytics.currentSessionId,
20760
+ status: "success",
20761
+ postId,
20762
+ groupId,
20763
+ postType,
20764
+ failureReason
20765
+ });
20766
+ sessionIdRef.current = null;
20767
+ };
20768
+ const onPublishFailed = (e) => {
20769
+ const { postId, postType, groupId, failureReason } = e.detail;
20770
+ if (!postId || processedRequestIds.current.has(postId)) return;
20771
+ processedRequestIds.current.add(postId);
20772
+ analytics.trackPublish({
20773
+ sessionId: sessionIdRef.current ?? analytics.currentSessionId,
20774
+ status: "failed",
20775
+ postId,
20776
+ groupId,
20777
+ postType,
20778
+ failureReason
20779
+ });
20780
+ sessionIdRef.current = null;
20781
+ };
20782
+ const lockSession = () => {
20783
+ if (!sessionIdRef.current) {
20784
+ sessionIdRef.current = analytics.currentSessionId;
20785
+ }
20786
+ };
20787
+ window.addEventListener(
20788
+ PostBuilderEvents.POST_PUBLISH_SUCCESSFUL,
20789
+ onPublishSuccess
20790
+ );
20791
+ window.addEventListener(
20792
+ PostBuilderEvents.POST_PUBLISH_FAILED,
20793
+ onPublishFailed
20794
+ );
20795
+ const handlePublishAttempt = () => lockSession();
20796
+ window.addEventListener(
20797
+ PostBuilderEvents.POST_PUBLISH_ATTEMPTED,
20798
+ handlePublishAttempt
20799
+ );
20800
+ return () => {
20801
+ window.removeEventListener(
20802
+ PostBuilderEvents.POST_PUBLISH_SUCCESSFUL,
20803
+ onPublishSuccess
20804
+ );
20805
+ window.removeEventListener(
20806
+ PostBuilderEvents.POST_PUBLISH_FAILED,
20807
+ onPublishFailed
20808
+ );
20809
+ window.removeEventListener(
20810
+ PostBuilderEvents.POST_PUBLISH_ATTEMPTED,
20811
+ handlePublishAttempt
20812
+ );
20813
+ };
20814
+ }, [analytics]);
20815
+ };
20813
20816
  const usePersistence = () => {
20814
20817
  const saveCurrentTabContent = (editorType, editor) => {
20815
- if (typeof window === "undefined" || typeof localStorage === "undefined" || !editor || editor.isEmpty)
20816
- return;
20818
+ if (typeof window === "undefined" || typeof localStorage === "undefined" || !editor) return;
20817
20819
  const json = editor?.getJSON();
20818
20820
  const filteredJson = filterNodes(json, (node) => !node?.attrs?.uploading);
20819
20821
  if (filteredJson) {
@@ -21066,11 +21068,9 @@ var Progress$1 = React.forwardRef(
21066
21068
  ...progressProps
21067
21069
  } = props;
21068
21070
  if ((maxProp || maxProp === 0) && !isValidMaxNumber(maxProp)) {
21069
- console.error(getInvalidMaxError(`${maxProp}`, "Progress"));
21070
21071
  }
21071
21072
  const max2 = isValidMaxNumber(maxProp) ? maxProp : DEFAULT_MAX;
21072
21073
  if (valueProp !== null && !isValidValueNumber(valueProp, max2)) {
21073
- console.error(getInvalidValueError(`${valueProp}`, "Progress"));
21074
21074
  }
21075
21075
  const value = isValidValueNumber(valueProp, max2) ? valueProp : null;
21076
21076
  const valueLabel = isNumber(value) ? getValueLabel(value, max2) : void 0;
@@ -21390,13 +21390,7 @@ const createUpdateMarkByUidCommand = (markName) => {
21390
21390
  state,
21391
21391
  dispatch
21392
21392
  }) => {
21393
- console.log("=== UPDATE MARK COMMAND START ===");
21394
- console.log("markName:", markName);
21395
- console.log("uid:", uid);
21396
- console.log("attrs:", attrs);
21397
- console.log("state.doc:", state.doc.toJSON());
21398
21393
  if (!dispatch) {
21399
- console.log("No dispatch, returning false");
21400
21394
  return false;
21401
21395
  }
21402
21396
  const { doc, schema } = state;
@@ -21406,13 +21400,6 @@ const createUpdateMarkByUidCommand = (markName) => {
21406
21400
  doc.descendants((node, pos) => {
21407
21401
  if (node.isText && node.marks?.length) {
21408
21402
  node.marks.forEach((mark) => {
21409
- console.log("Checking mark:", {
21410
- markType: mark.type.name,
21411
- markUid: mark.attrs.uid,
21412
- targetMarkName: markName,
21413
- targetUid: uid,
21414
- matches: mark.type.name === markName && mark.attrs.uid === uid
21415
- });
21416
21403
  if (mark.type.name === markName && mark.attrs.uid === uid) {
21417
21404
  positions.push({
21418
21405
  from: pos,
@@ -21420,33 +21407,21 @@ const createUpdateMarkByUidCommand = (markName) => {
21420
21407
  mark
21421
21408
  });
21422
21409
  found2 = true;
21423
- console.log("Found matching mark at:", { from: pos, to: pos + node.nodeSize });
21424
21410
  }
21425
21411
  });
21426
21412
  }
21427
21413
  });
21428
- console.log("Total positions found:", positions.length);
21429
- console.log("Positions:", positions);
21430
21414
  if (found2) {
21431
21415
  positions.forEach(({ from, to, mark }) => {
21432
21416
  const newAttrs = { ...mark.attrs, ...attrs };
21433
21417
  const markType = schema.marks[markName];
21434
- console.log("Applying update:", { from, to, oldAttrs: mark.attrs, newAttrs });
21435
21418
  if (markType) {
21436
- console.log("Before removeMark - tr.doc:", tr.doc.toJSON());
21437
21419
  tr = tr.removeMark(from, to, markType);
21438
- console.log("After removeMark - tr.doc:", tr.doc.toJSON());
21439
21420
  tr = tr.addMark(from, to, markType.create(newAttrs));
21440
- console.log("After addMark - tr.doc:", tr.doc.toJSON());
21441
21421
  }
21442
21422
  });
21443
- console.log("About to dispatch transaction");
21444
- console.log("Final tr.doc:", tr.doc.toJSON());
21445
- console.log("Original state.doc:", state.doc.toJSON());
21446
21423
  dispatch(tr);
21447
- console.log("Transaction dispatched successfully");
21448
21424
  }
21449
- console.log("=== UPDATE MARK COMMAND END ===");
21450
21425
  return found2;
21451
21426
  };
21452
21427
  };
@@ -22464,7 +22439,6 @@ let warnedAboutTextSelection = false;
22464
22439
  function checkTextSelection($pos) {
22465
22440
  if (!warnedAboutTextSelection && !$pos.parent.inlineContent) {
22466
22441
  warnedAboutTextSelection = true;
22467
- console["warn"]("TextSelection endpoint not pointing into a node with inline content (" + $pos.parent.type.name + ")");
22468
22442
  }
22469
22443
  }
22470
22444
  class TextSelection extends Selection {
@@ -23189,7 +23163,6 @@ const PollCreator = ({ choices, onChange }) => {
23189
23163
  const result = await fileStore.uploadImage(file);
23190
23164
  return createPollMediaOption(result, startIndex + index2);
23191
23165
  } catch (error) {
23192
- console.error("Upload failed for", file.name, error);
23193
23166
  return null;
23194
23167
  }
23195
23168
  });
@@ -23209,7 +23182,6 @@ const PollCreator = ({ choices, onChange }) => {
23209
23182
  return final;
23210
23183
  });
23211
23184
  } catch (error) {
23212
- console.error("Unexpected error during file upload:", error);
23213
23185
  setInternalChoices((current) => {
23214
23186
  const withoutPlaceholders = current.filter((c) => !isPlaceholder(c));
23215
23187
  setTimeout(() => {
@@ -23242,7 +23214,6 @@ const PollCreator = ({ choices, onChange }) => {
23242
23214
  return updated;
23243
23215
  });
23244
23216
  } catch (error) {
23245
- console.error("URL upload failed:", error);
23246
23217
  setInternalChoices((current) => {
23247
23218
  const withoutPlaceholder = current.filter((c) => !isPlaceholder(c));
23248
23219
  setTimeout(() => {
@@ -23783,7 +23754,6 @@ const LinkMarkView = ({ mark, editor }) => {
23783
23754
  };
23784
23755
  const handleUpdateLink = (link, text2, uid, previewPayload) => {
23785
23756
  if (!editor.view) return;
23786
- console.log("UPDATE LINK IN VIEW::", { text: text2 });
23787
23757
  const newText = mark?.attrs?.isLinkMode ? link : text2 || link;
23788
23758
  if (uid) {
23789
23759
  editor.commands.updateLink(uid, { href: link, text: newText, previewPayload });
@@ -23843,25 +23813,66 @@ const LinkMarkView = ({ mark, editor }) => {
23843
23813
  )
23844
23814
  ] });
23845
23815
  };
23816
+ function isValidUrlFormat(text2) {
23817
+ return isValidUrl(normalizeUrl(text2.trim()));
23818
+ }
23846
23819
  function doesPreviewExist(editor, uid) {
23847
- let exists = false;
23848
- editor.state.doc.descendants((node) => {
23849
- if (node.type.name === "linkPreview" && node.attrs.uid === uid) {
23850
- exists = true;
23851
- return false;
23852
- }
23853
- });
23854
- return exists;
23820
+ if (!editor || !uid) {
23821
+ return false;
23822
+ }
23823
+ try {
23824
+ let exists = false;
23825
+ editor.state.doc.descendants((node) => {
23826
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23827
+ exists = true;
23828
+ return false;
23829
+ }
23830
+ });
23831
+ return exists;
23832
+ } catch (err) {
23833
+ return false;
23834
+ }
23855
23835
  }
23856
23836
  function findExistingPreview(editor) {
23857
- let result = null;
23858
- editor.state.doc.descendants((node, pos) => {
23859
- if (node.type.name === "linkPreview") {
23860
- result = { node, pos };
23861
- return false;
23837
+ if (!editor) {
23838
+ return null;
23839
+ }
23840
+ try {
23841
+ let result = null;
23842
+ editor.state.doc.descendants((node, pos) => {
23843
+ if (node && node.type && node.type.name === "linkPreview") {
23844
+ result = { node, pos };
23845
+ return false;
23846
+ }
23847
+ });
23848
+ return result;
23849
+ } catch (err) {
23850
+ return null;
23851
+ }
23852
+ }
23853
+ function removePreviewByUid(editor, uid) {
23854
+ if (!editor || !uid) {
23855
+ return;
23856
+ }
23857
+ try {
23858
+ let previewPos = null;
23859
+ let previewSize = 0;
23860
+ editor.state.doc.descendants((node, pos) => {
23861
+ if (node && node.type && node.type.name === "linkPreview" && node.attrs?.uid === uid) {
23862
+ previewPos = pos;
23863
+ previewSize = node.nodeSize;
23864
+ return false;
23865
+ }
23866
+ });
23867
+ if (previewPos !== null && previewSize > 0) {
23868
+ const tr = editor.state.tr;
23869
+ if (tr) {
23870
+ tr.delete(previewPos, Number(previewPos) + previewSize);
23871
+ editor.view.dispatch(tr);
23872
+ }
23862
23873
  }
23863
- });
23864
- return result;
23874
+ } catch (err) {
23875
+ }
23865
23876
  }
23866
23877
  function extractBestImage(metadata) {
23867
23878
  return metadata?.image?.high_resolution ?? metadata?.image?.url ?? metadata?.image?.thumbnail ?? metadata?.image?.placeholder ?? null;
@@ -23886,6 +23897,76 @@ function collectAllLinkMarks(state, linkMark) {
23886
23897
  });
23887
23898
  return links;
23888
23899
  }
23900
+ function syncLinkHrefWithText(newState, linkMark, editor, singlePreviewMode, pluginState) {
23901
+ if (!newState || !linkMark || !editor || !pluginState) {
23902
+ return null;
23903
+ }
23904
+ let tr = null;
23905
+ let hasChanges = false;
23906
+ try {
23907
+ newState.doc.descendants((node, pos) => {
23908
+ if (!node || !node.isText || !node.marks?.length) return;
23909
+ node.marks.forEach((mark) => {
23910
+ if (!mark || !mark.type || !mark.attrs) return;
23911
+ if (mark.type === linkMark && mark.attrs?.uid) {
23912
+ const currentText = node.text || "";
23913
+ const currentHref = mark.attrs.href || "";
23914
+ if (currentText !== currentHref) {
23915
+ const isValidUrl2 = isValidUrlFormat(currentText);
23916
+ if (!tr) {
23917
+ tr = newState.tr;
23918
+ }
23919
+ if (!tr) {
23920
+ return;
23921
+ }
23922
+ if (isValidUrl2) {
23923
+ const newMark = linkMark.create({
23924
+ ...mark.attrs,
23925
+ href: normalizeUrl(currentText)
23926
+ });
23927
+ if (!newMark) {
23928
+ return;
23929
+ }
23930
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23931
+ tr = tr.addMark(pos, pos + node.nodeSize, newMark);
23932
+ hasChanges = true;
23933
+ pluginState.processedLinks.delete(mark.attrs.uid);
23934
+ if (singlePreviewMode) {
23935
+ queueMicrotask(() => {
23936
+ try {
23937
+ const existingPreview = findExistingPreview(editor);
23938
+ if (existingPreview && mark.attrs?.uid) {
23939
+ }
23940
+ } catch (err) {
23941
+ }
23942
+ });
23943
+ } else {
23944
+ }
23945
+ } else {
23946
+ tr = tr.removeMark(pos, pos + node.nodeSize, linkMark);
23947
+ hasChanges = true;
23948
+ queueMicrotask(() => {
23949
+ try {
23950
+ if (mark.attrs?.uid) {
23951
+ removePreviewByUid(editor, mark.attrs.uid);
23952
+ }
23953
+ } catch (err) {
23954
+ }
23955
+ });
23956
+ if (mark.attrs?.uid) {
23957
+ pluginState.processedLinks.delete(mark.attrs.uid);
23958
+ pluginState.resolvingLinks.delete(mark.attrs.uid);
23959
+ }
23960
+ }
23961
+ }
23962
+ }
23963
+ });
23964
+ });
23965
+ } catch (err) {
23966
+ return null;
23967
+ }
23968
+ return hasChanges ? tr : null;
23969
+ }
23889
23970
  function assignUidsToLinks(newState, linkMark) {
23890
23971
  const newUids = /* @__PURE__ */ new Map();
23891
23972
  let tr = null;
@@ -23895,11 +23976,6 @@ function assignUidsToLinks(newState, linkMark) {
23895
23976
  node.marks.forEach((mark) => {
23896
23977
  if (mark.type === linkMark && mark.attrs?.href && !mark.attrs.uid) {
23897
23978
  const newUid = v4();
23898
- console.log("🔧 Assigning UID to autolinked URL:", {
23899
- href: mark.attrs.href,
23900
- uid: newUid,
23901
- pos
23902
- });
23903
23979
  const newMark = linkMark.create({
23904
23980
  ...mark.attrs,
23905
23981
  uid: newUid
@@ -23926,25 +24002,14 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23926
24002
  const { api, editor } = options;
23927
24003
  const mediaGroup = findByType(editor?.getJSON(), "mediaGroup");
23928
24004
  if (!api) {
23929
- console.warn("⚠️ No API provided to resolve link");
23930
24005
  return;
23931
24006
  }
23932
24007
  if (singlePreviewMode && mediaGroup.length >= 1) return;
23933
24008
  pluginState.resolvingLinks.add(link.uid);
23934
- console.log("🌐 Resolving link metadata:", {
23935
- uid: link.uid,
23936
- href: link.href,
23937
- singlePreviewMode
23938
- });
23939
24009
  api.resolveUrl(normalizeUrl(link.href)).then((metadata) => {
23940
24010
  pluginState.resolvingLinks.delete(link.uid);
23941
24011
  pluginState.processedLinks.add(link.uid);
23942
- console.log("✅ Link metadata resolved:", {
23943
- uid: link.uid,
23944
- metadata
23945
- });
23946
24012
  if (!metadata) {
23947
- console.warn("⚠️ No metadata returned for:", link.href);
23948
24013
  return;
23949
24014
  }
23950
24015
  const previewData = {
@@ -23959,13 +24024,11 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23959
24024
  if (singlePreviewMode) {
23960
24025
  const existingPreview = findExistingPreview(editor);
23961
24026
  if (existingPreview) {
23962
- console.log("🔄 Updating existing preview in single mode");
23963
24027
  const { pos } = existingPreview;
23964
24028
  const tr = editor.state.tr;
23965
24029
  tr.setNodeMarkup(pos, void 0, previewData);
23966
24030
  editor.view.dispatch(tr);
23967
24031
  } else {
23968
- console.log("➕ Creating first preview in single mode");
23969
24032
  editor.commands.setLinkPreview(previewData);
23970
24033
  }
23971
24034
  editor.commands.updateLinkByUid(link.uid, {
@@ -23973,16 +24036,12 @@ function resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginSta
23973
24036
  });
23974
24037
  } else {
23975
24038
  if (!doesPreviewExist(editor, link.uid)) {
23976
- console.log("➕ Creating new preview in multi mode");
23977
24039
  editor.chain().updateLinkByUid(link.uid, {
23978
24040
  previewPayload: convertLinkMetaToPreviewItem(metadata)
23979
24041
  }).setLinkPreview(previewData).run();
23980
- } else {
23981
- console.log("⏭️ Preview already exists, skipping");
23982
24042
  }
23983
24043
  }
23984
24044
  }).catch((err) => {
23985
- console.error("❌ Failed to resolve link:", err);
23986
24045
  pluginState.resolvingLinks.delete(link.uid);
23987
24046
  });
23988
24047
  }
@@ -23992,10 +24051,6 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
23992
24051
  key: pluginKey,
23993
24052
  state: {
23994
24053
  init() {
23995
- console.log("🔌 LinkAutoResolve plugin initialized", {
23996
- singlePreviewMode,
23997
- hasApi: !!options.api
23998
- });
23999
24054
  return {
24000
24055
  resolvingLinks: /* @__PURE__ */ new Set(),
24001
24056
  processedLinks: /* @__PURE__ */ new Set()
@@ -24025,27 +24080,22 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24025
24080
  appendTransaction: (transactions, oldState, newState) => {
24026
24081
  const linkMark = newState.schema.marks["customLink"];
24027
24082
  if (!linkMark) {
24028
- console.warn("⚠️ customLink mark not found in schema");
24029
24083
  return null;
24030
24084
  }
24031
24085
  if (!transactions.some((tr) => tr.docChanged)) {
24032
24086
  return null;
24033
24087
  }
24034
- console.log("📝 Document changed, checking for new links...");
24035
24088
  const pluginState = pluginKey.getState(newState);
24089
+ if (!pluginState) {
24090
+ return null;
24091
+ }
24092
+ const syncTr = singlePreviewMode ? syncLinkHrefWithText(newState, linkMark, options.editor, singlePreviewMode, pluginState) : null;
24036
24093
  const oldLinks = collectAllLinkMarks(oldState, linkMark);
24037
24094
  const newLinks = collectAllLinkMarks(newState, linkMark);
24038
- console.log("📊 Link count:", {
24039
- old: oldLinks.size,
24040
- new: newLinks.size,
24041
- processed: pluginState.processedLinks.size,
24042
- resolving: pluginState.resolvingLinks.size
24043
- });
24044
24095
  const { tr: uidTr, newUids } = assignUidsToLinks(newState, linkMark);
24045
24096
  const linksToResolve = [];
24046
24097
  newUids.forEach((linkData) => {
24047
24098
  if (!pluginState.processedLinks.has(linkData.uid) && !pluginState.resolvingLinks.has(linkData.uid)) {
24048
- console.log("🆕 New autolinked URL detected:", linkData);
24049
24099
  linksToResolve.push(linkData);
24050
24100
  }
24051
24101
  });
@@ -24058,21 +24108,33 @@ function createLinkAutoResolvePlugin(options, singlePreviewMode = false) {
24058
24108
  return;
24059
24109
  }
24060
24110
  if (!oldLinks.has(uid)) {
24061
- console.log("🆕 New link detected (with UID):", linkData);
24062
24111
  linksToResolve.push(linkData);
24063
24112
  }
24064
24113
  });
24065
24114
  if (linksToResolve.length > 0) {
24066
- console.log("🚀 Processing", linksToResolve.length, "new link(s)");
24067
24115
  queueMicrotask(() => {
24068
24116
  linksToResolve.forEach((link) => {
24069
24117
  resolveLinkAndHandlePreview(link, options, singlePreviewMode, pluginState);
24070
24118
  });
24071
24119
  });
24072
- } else {
24073
- console.log("✓ No new links to process");
24074
24120
  }
24075
- return uidTr;
24121
+ if (syncTr && uidTr) {
24122
+ try {
24123
+ uidTr.steps.forEach((step, i) => {
24124
+ if (step && syncTr) {
24125
+ syncTr.step(step);
24126
+ const map = uidTr.mapping.maps[i];
24127
+ if (map) {
24128
+ syncTr.mapping.appendMap(map);
24129
+ }
24130
+ }
24131
+ });
24132
+ return syncTr;
24133
+ } catch (err) {
24134
+ return syncTr;
24135
+ }
24136
+ }
24137
+ return syncTr ?? uidTr ?? null;
24076
24138
  }
24077
24139
  });
24078
24140
  }
@@ -24168,7 +24230,6 @@ const CustomLink = Link$1.extend({
24168
24230
  this?.options?.api?.resolveUrl(normalizeUrl(href))?.then((metadata) => {
24169
24231
  if (metadata) {
24170
24232
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24171
- console.log({ href, text: text2 });
24172
24233
  editor?.chain()?.updateLinkByUid(uid, { href, text: text2, previewPayload })?.updateLinkPreviewByUid(uid, {
24173
24234
  // Now using correct UID
24174
24235
  loading: false,
@@ -24227,7 +24288,6 @@ const CustomLink = Link$1.extend({
24227
24288
  if (attrs.href) {
24228
24289
  queueMicrotask(() => {
24229
24290
  this.options.api?.resolveUrl(normalizeUrl(attrs.href))?.then((metadata) => {
24230
- console.log({ metadata });
24231
24291
  if (metadata) {
24232
24292
  const previewPayload = convertLinkMetaToPreviewItem(metadata);
24233
24293
  let linkPreviewExists = false;
@@ -24256,7 +24316,6 @@ const CustomLink = Link$1.extend({
24256
24316
  editor.commands.deleteLinkPreviewByUid(uid);
24257
24317
  }
24258
24318
  }).catch((err) => {
24259
- console.log("LINK UPDATE ERR::", { err });
24260
24319
  editor.commands.deleteLinkPreviewByUid(uid);
24261
24320
  });
24262
24321
  });
@@ -24336,7 +24395,6 @@ const IframeView = ({
24336
24395
  setPreviewData(previewPayload);
24337
24396
  updateAttributes({ previewPayload });
24338
24397
  }).catch((error) => {
24339
- console.error("Failed to fetch preview:", error);
24340
24398
  }).finally(() => {
24341
24399
  });
24342
24400
  }
@@ -24581,7 +24639,6 @@ const _createTrustedTypesPolicy = function _createTrustedTypesPolicy2(trustedTyp
24581
24639
  }
24582
24640
  });
24583
24641
  } catch (_) {
24584
- console.warn("TrustedTypes policy " + policyName + " could not be created.");
24585
24642
  return null;
24586
24643
  }
24587
24644
  };
@@ -25418,7 +25475,6 @@ const configureDOMPurify = () => {
25418
25475
  const element = node;
25419
25476
  const src = element.getAttribute("src") || "";
25420
25477
  if (!isAllowedDomain(src)) {
25421
- console.warn("🚨 Blocked iframe from non-allowed domain:", src);
25422
25478
  node.parentNode?.removeChild(node);
25423
25479
  }
25424
25480
  }
@@ -25430,7 +25486,6 @@ function sanitizeIframeHTML(html2) {
25430
25486
  const config = configureDOMPurify();
25431
25487
  const cleaned = purify.sanitize(html2, config);
25432
25488
  if (!cleaned.includes("<iframe")) {
25433
- console.warn("⚠️ No valid iframe found after sanitization");
25434
25489
  return null;
25435
25490
  }
25436
25491
  const match = cleaned.match(/<iframe[^>]*src=["']([^"']+)["']/i);
@@ -25442,7 +25497,6 @@ function sanitizeIframeHTML(html2) {
25442
25497
  }
25443
25498
  return match[1];
25444
25499
  } catch (error) {
25445
- console.error("🚨 Error sanitizing iframe:", error);
25446
25500
  return null;
25447
25501
  } finally {
25448
25502
  purify.removeAllHooks();
@@ -25480,7 +25534,6 @@ const createFinder = (regex) => {
25480
25534
  match
25481
25535
  });
25482
25536
  }
25483
- console.log({ match, matches });
25484
25537
  return matches.length > 0 ? matches : null;
25485
25538
  };
25486
25539
  };
@@ -25532,11 +25585,9 @@ const Iframe = Node$1.create({
25532
25585
  const iframeHTML = match[0];
25533
25586
  const safeSrc = sanitizeIframeHTML(iframeHTML);
25534
25587
  if (!safeSrc) {
25535
- console.warn("🚨 Blocked unsafe iframe paste");
25536
25588
  toast.error("🚨 Your pasted iframe is not safe to render");
25537
25589
  return;
25538
25590
  }
25539
- console.log("✅ Safe iframe URL validated:", safeSrc);
25540
25591
  const node = this.type.create({ src: safeSrc, previewPayload: null });
25541
25592
  state.tr.replaceRangeWith(range.from, range.to, node);
25542
25593
  }
@@ -25547,7 +25598,6 @@ const Iframe = Node$1.create({
25547
25598
  handler: ({ state, range, match }) => {
25548
25599
  const fullUrl = match[0];
25549
25600
  const embedUrl = getEmbedUrl(fullUrl);
25550
- console.log({ match, fullUrl, embedUrl });
25551
25601
  if (!embedUrl) return;
25552
25602
  const node = this.type.create({ src: embedUrl });
25553
25603
  state.tr.replaceRangeWith(range.from, range.to, node);
@@ -25593,10 +25643,9 @@ const handleUrlWithoutSelection = (editor, url, event, autoDetectMedia) => {
25593
25643
  mediaType: MediaItemType.MEDIA_ITEM
25594
25644
  });
25595
25645
  }).catch(
25596
- (e) => console.error("[SmartLinkPaste] Media detection failed, falling back to link:", e)
25646
+ (e) => void 0
25597
25647
  );
25598
25648
  }
25599
- console.log("[SmartLinkPaste] Inserting as link node");
25600
25649
  editor.chain().focus().insertLink({ href: normalizedUrl, text: url }).run();
25601
25650
  return true;
25602
25651
  };
@@ -25618,7 +25667,6 @@ const createPasteHandler = (editor, options) => {
25618
25667
  return false;
25619
25668
  }
25620
25669
  const trimmedText = pasteText.trim();
25621
- console.log("[SmartLinkPaste] Valid URL detected:", isEmbeddableUrl(trimmedText));
25622
25670
  if (isEmbeddableUrl(trimmedText) && options?.autoEmbed) {
25623
25671
  event.preventDefault();
25624
25672
  return false;
@@ -25635,7 +25683,6 @@ const createPasteHandler = (editor, options) => {
25635
25683
  options?.autoDetectMedia ?? true
25636
25684
  );
25637
25685
  } catch (error) {
25638
- console.error("[SmartLinkPaste] Error:", error);
25639
25686
  return false;
25640
25687
  }
25641
25688
  };
@@ -25647,10 +25694,8 @@ const createTransformHandler = (editor) => {
25647
25694
  return slice;
25648
25695
  }
25649
25696
  try {
25650
- console.log("[SmartLinkPaste] Transforming inline URLs in pasted content");
25651
25697
  return transformUrlsInSlice(editor, slice);
25652
25698
  } catch (error) {
25653
- console.error("[SmartLinkPaste] Transform error:", error);
25654
25699
  return slice;
25655
25700
  }
25656
25701
  };
@@ -25757,7 +25802,6 @@ const SmartMediaUpload = Extension.create({
25757
25802
  const uid = v4();
25758
25803
  const options = this.options;
25759
25804
  if (!options.api) {
25760
- console.error("API instance not provided to SmartMediaUpload");
25761
25805
  return false;
25762
25806
  }
25763
25807
  if (isFileOrBlob(source)) {
@@ -25767,7 +25811,6 @@ const SmartMediaUpload = Extension.create({
25767
25811
  options.allowedFileTypes
25768
25812
  );
25769
25813
  if (!validation.valid) {
25770
- console.error("File validation failed:", validation.error);
25771
25814
  options.onUploadError?.(uid, new Error(validation.error));
25772
25815
  return false;
25773
25816
  }
@@ -25851,7 +25894,6 @@ const SmartMediaUpload = Extension.create({
25851
25894
  } else editor.commands.deleteMediaByUid(item.uid);
25852
25895
  options.onUploadComplete?.(item.uid, hostedUrl);
25853
25896
  } catch (error) {
25854
- console.error("Upload failed:", error);
25855
25897
  const blobUrl = this.storage.blobUrls.get(item.uid);
25856
25898
  if (blobUrl) {
25857
25899
  URL.revokeObjectURL(blobUrl);
@@ -25863,7 +25905,7 @@ const SmartMediaUpload = Extension.create({
25863
25905
  this.storage.activeUploads--;
25864
25906
  this.storage.processUploadQueue(editor);
25865
25907
  }
25866
- })().catch((err) => console.log(err));
25908
+ })().catch((err) => void 0);
25867
25909
  if (this.storage.uploadQueue.length > 0) {
25868
25910
  this.storage.processUploadQueue(editor);
25869
25911
  }
@@ -28563,7 +28605,6 @@ function getSuggestionOptions({
28563
28605
  const text2 = editor.getText();
28564
28606
  const trimmed = text2?.replace(WHITESPACE_REGEX, " ")?.trim();
28565
28607
  const matchStartPosition = trimmed?.lastIndexOf(char);
28566
- console.log({ matchStartPosition });
28567
28608
  const nodeAfter = editor.view.state.selection.$to.nodeAfter;
28568
28609
  const overrideSpace = nodeAfter?.text?.startsWith(" ");
28569
28610
  if (overrideSpace) {
@@ -28677,7 +28718,6 @@ const Mention = Node$1.create({
28677
28718
  renderHTML({ node, HTMLAttributes }) {
28678
28719
  const suggestion = getSuggestionFromChar(this, node.attrs.mentionSuggestionChar);
28679
28720
  if (this.options.renderLabel !== void 0) {
28680
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28681
28721
  return [
28682
28722
  "span",
28683
28723
  mergeAttributes({ "data-type": this.name }, this.options.HTMLAttributes, HTMLAttributes),
@@ -28717,7 +28757,6 @@ const Mention = Node$1.create({
28717
28757
  suggestion: getSuggestionFromChar(this, node.attrs.mentionSuggestionChar)
28718
28758
  };
28719
28759
  if (this.options.renderLabel !== void 0) {
28720
- console.warn("renderLabel is deprecated use renderText and renderHTML instead");
28721
28760
  return this.options.renderLabel(args);
28722
28761
  }
28723
28762
  return this.options.renderText(args);
@@ -29706,11 +29745,9 @@ const mentionService = (api, mfs, store) => {
29706
29745
  const fetchMentions = async () => {
29707
29746
  const params = store.getState().getMentionParams();
29708
29747
  if (!params) {
29709
- console.error("DEBUG MENTION SERVICE::", "No group id or post id has been provided");
29710
29748
  return [];
29711
29749
  }
29712
29750
  const { groupId, postId } = params;
29713
- console.log({ groupId, postId });
29714
29751
  const response = postId ? await mfs.getRecommendationPost(groupId, postId, 0, 999) : await mfs.getRecommendationGroup(groupId, 0, 999);
29715
29752
  return response.entries?.filter((item) => Boolean(item?.user_data))?.map(
29716
29753
  (item) => ({
@@ -29729,7 +29766,6 @@ const mentionService = (api, mfs, store) => {
29729
29766
  const { selectedGroupId, groupId } = store.getState();
29730
29767
  const activeGroupId = selectedGroupId ?? groupId;
29731
29768
  if (!activeGroupId) {
29732
- console.warn("DEBUG HASHTAG SERVICE::", "No active group selected or provided");
29733
29769
  return [];
29734
29770
  }
29735
29771
  const response = await api.fetchGroupConversations(999, 0);
@@ -29931,8 +29967,8 @@ const LinkPreviewExtended = ({
29931
29967
  title,
29932
29968
  description,
29933
29969
  image,
29934
- domain
29935
- // onClickDelete,
29970
+ domain,
29971
+ onClickDelete
29936
29972
  }) => {
29937
29973
  const safeDomain = useMemo(() => {
29938
29974
  try {
@@ -29941,6 +29977,11 @@ const LinkPreviewExtended = ({
29941
29977
  return "unknown";
29942
29978
  }
29943
29979
  }, [href, domain]);
29980
+ const handleDelete = (e) => {
29981
+ e.preventDefault();
29982
+ e.stopPropagation();
29983
+ onClickDelete();
29984
+ };
29944
29985
  return /* @__PURE__ */ jsxs(
29945
29986
  "div",
29946
29987
  {
@@ -29949,18 +29990,32 @@ const LinkPreviewExtended = ({
29949
29990
  selected ? "ring-2 ring-blue-500 ring-offset-2 rounded-lg" : ""
29950
29991
  ),
29951
29992
  children: [
29952
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 absolute z-50 right-3 top-3", children: /* @__PURE__ */ jsx(
29953
- ToolbarButton,
29954
- {
29955
- asChild: true,
29956
- tooltip: "Visit Link",
29957
- className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none group-hover:bg-accent/70 group-hover:text-accent-foreground text-primary-send",
29958
- children: /* @__PURE__ */ jsxs("span", { className: "relative", children: [
29959
- /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "absolute inset-0" }),
29960
- /* @__PURE__ */ jsx(ExternalLink, {})
29961
- ] })
29962
- }
29963
- ) }),
29993
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 absolute z-50 right-3 top-3", children: [
29994
+ /* @__PURE__ */ jsx(
29995
+ ToolbarButton,
29996
+ {
29997
+ asChild: true,
29998
+ tooltip: "Visit Link",
29999
+ className: "cursor-pointer backdrop-blur-2xl size-6 shadow-none group-hover:bg-accent/70 group-hover:text-accent-foreground text-primary-send",
30000
+ children: /* @__PURE__ */ jsxs("span", { className: "relative", children: [
30001
+ /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", className: "absolute inset-0" }),
30002
+ /* @__PURE__ */ jsx(ExternalLink, {})
30003
+ ] })
30004
+ }
30005
+ ),
30006
+ /* @__PURE__ */ jsx(
30007
+ ToolbarButton,
30008
+ {
30009
+ tooltip: "Remove Link Preview",
30010
+ onClick: handleDelete,
30011
+ "aria-label": "Delete link preview",
30012
+ type: "button",
30013
+ size: "icon",
30014
+ 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",
30015
+ children: /* @__PURE__ */ jsx(Trash2, {})
30016
+ }
30017
+ )
30018
+ ] }),
29964
30019
  /* @__PURE__ */ jsx("div", { className: "relative z-0 w-full", children: /* @__PURE__ */ 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: [
29965
30020
  /* @__PURE__ */ jsx("div", { className: "relative h-80 w-full shrink-0 overflow-hidden bg-muted border-b", children: /* @__PURE__ */ jsx(
29966
30021
  "img",
@@ -30081,7 +30136,6 @@ const LinkPreview = Node$1.create({
30081
30136
  },
30082
30137
  renderHTML({ node }) {
30083
30138
  const { href, uid, title, description, image, domain } = node.attrs;
30084
- console.log("INSIDE RENDER HTML::", { href, image });
30085
30139
  if (!href) return ["div", {}];
30086
30140
  const content = [
30087
30141
  // Link overlay
@@ -30216,11 +30270,6 @@ const MediaGroupView = ({ node, editor }) => {
30216
30270
  editor.commands.deleteMediaByUid(uid);
30217
30271
  };
30218
30272
  const mediaNodes = node?.content?.content || [];
30219
- console.log("MediaGroupView render:", {
30220
- contentSize: node?.content?.size,
30221
- mediaCount: mediaNodes?.length,
30222
- nodes: mediaNodes?.map((n) => ({ type: n?.type?.name, uid: n?.attrs?.uid }))
30223
- });
30224
30273
  return /* @__PURE__ */ jsx(
30225
30274
  NodeViewWrapper,
30226
30275
  {
@@ -30322,14 +30371,12 @@ const createMediaModePlugin = () => {
30322
30371
  child.marks.forEach((mark) => {
30323
30372
  if (mark.type.name === "customLink" && mark.attrs.previewPayload) {
30324
30373
  lastLinkPreviewData = mark.attrs.previewPayload;
30325
- console.log("Found link with previewPayload:", lastLinkPreviewData);
30326
30374
  }
30327
30375
  });
30328
30376
  }
30329
30377
  });
30330
30378
  }
30331
30379
  });
30332
- console.log("Cleanup check:", { modified, hasMediaGroup, lastLinkPreviewData });
30333
30380
  if (modified && hasMediaGroup && lastLinkPreviewData) {
30334
30381
  let hasLinkPreview = false;
30335
30382
  tr.doc.forEach((node) => {
@@ -30337,10 +30384,6 @@ const createMediaModePlugin = () => {
30337
30384
  hasLinkPreview = true;
30338
30385
  }
30339
30386
  });
30340
- console.log("Creating linkPreview:", {
30341
- hasLinkPreview,
30342
- schemaHasLinkPreview: !!newState.schema.nodes.linkPreview
30343
- });
30344
30387
  if (!hasLinkPreview && newState.schema.nodes.linkPreview) {
30345
30388
  const preview = lastLinkPreviewData;
30346
30389
  const linkPreviewNode = newState.schema.nodes.linkPreview.create({
@@ -30351,7 +30394,6 @@ const createMediaModePlugin = () => {
30351
30394
  image: preview.linkImage?.url ?? "",
30352
30395
  variant: LinkPreviewType.Extended
30353
30396
  });
30354
- console.log("Inserting linkPreview node:", { lastLinkPreviewData, linkPreviewNode });
30355
30397
  tr.insert(tr.doc.content.size, linkPreviewNode);
30356
30398
  modified = true;
30357
30399
  }
@@ -30411,7 +30453,6 @@ const createMediaModePlugin = () => {
30411
30453
  }
30412
30454
  const mediaNodes = updatedTopLevelMedia.map((m) => m.node);
30413
30455
  if (mediaNodes.some((n) => !n || n.type.name !== "media")) {
30414
- console.warn("Invalid media nodes detected, skipping group creation");
30415
30456
  return null;
30416
30457
  }
30417
30458
  const mediaGroup = newState.schema.nodes.mediaGroup.create({}, mediaNodes);
@@ -30429,7 +30470,6 @@ const createMediaModePlugin = () => {
30429
30470
  const $pos = tr.doc.resolve(endPos);
30430
30471
  tr.setSelection(TextSelection$1.near($pos));
30431
30472
  } catch (e) {
30432
- console.warn("Could not set selection:", e);
30433
30473
  }
30434
30474
  }
30435
30475
  tr.setMeta("addToHistory", false);
@@ -30437,7 +30477,6 @@ const createMediaModePlugin = () => {
30437
30477
  }
30438
30478
  return modified ? tr : null;
30439
30479
  } catch (error) {
30440
- console.error("MediaMode plugin error:", error);
30441
30480
  return null;
30442
30481
  } finally {
30443
30482
  isProcessing = false;
@@ -30579,7 +30618,7 @@ const getMediaExtensions = ({ api, store, user }) => {
30579
30618
  }),
30580
30619
  LinkPreview.configure({
30581
30620
  variant: LinkPreviewType.Extended,
30582
- selectable: false,
30621
+ // selectable: false,
30583
30622
  draggable: false
30584
30623
  }),
30585
30624
  getMentionExtension(core, mfs, store),
@@ -30723,7 +30762,6 @@ const isLinkMarkWithPayload = (node) => isLinkMark(node) && Boolean(node?.attrs?
30723
30762
  const getLinkItemsPayload = (json) => {
30724
30763
  const links = find(json, (node) => isLinkMarkWithPayload(node));
30725
30764
  const items = links?.at(-1);
30726
- console.log("Link Items Payload::", { items });
30727
30765
  return { items };
30728
30766
  };
30729
30767
  const getPollItemsPayload = (json) => {
@@ -30737,7 +30775,7 @@ const isValidItem = (item) => {
30737
30775
  const mediaItem = item;
30738
30776
  const isValidLinkItem = linkItem?.linkUrl;
30739
30777
  const mediaItemSources = mediaItem?.sources;
30740
- const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url || mediaItemSources?.placeholder?.url;
30778
+ const isValidMediaItem = mediaItemSources?.original?.url || mediaItemSources?.thumbnail?.url;
30741
30779
  return Boolean(isValidLinkItem || isValidMediaItem);
30742
30780
  };
30743
30781
  const generateHtmlPostPayload = ({
@@ -30757,7 +30795,6 @@ const generateHtmlPostPayload = ({
30757
30795
  )?.at(0);
30758
30796
  const isEmbedOnly = isOnlyContentNode(json, "iframe");
30759
30797
  const body = isEmbedOnly ? previewItemEmbed?.attrs?.previewPayload?.linkTitle ?? previewItemEmbed?.attrs?.src ?? "" : secondaryText?.text ?? firstText?.text ?? "";
30760
- console.log({ firstText });
30761
30798
  const items = [
30762
30799
  previewItemMedia?.attrs?.payload,
30763
30800
  previewItemEmbed?.attrs?.previewPayload,
@@ -30784,11 +30821,14 @@ const generateMediaPostPayload = ({
30784
30821
  const { mentionData } = getMentionDataPayload(json);
30785
30822
  const { items: mediaItems } = getMediaItemsPayload(json);
30786
30823
  const { items: linkItems } = getLinkItemsPayload(json);
30824
+ const items = mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [];
30825
+ if (!body && mediaItems.length === 0)
30826
+ return { error: "Your post is empty. Add text or media to share your thoughts." };
30787
30827
  return {
30788
30828
  ...commons,
30789
30829
  type: mediaItems?.length > 0 ? NewPostType.NEW_POST_MEDIA : linkItems?.length > 0 ? NewPostType.NEW_POST_LINK : NewPostType.NEW_POST_MESSAGE,
30790
30830
  body,
30791
- items: mediaItems?.length > 0 ? mediaItems : linkItems?.length > 0 ? linkItems : [],
30831
+ items,
30792
30832
  mentionData,
30793
30833
  sendCrossMention
30794
30834
  };
@@ -30808,7 +30848,6 @@ const generatePollPostPayload = ({
30808
30848
  option_id: index2 === 0 ? item.option_id : v4(),
30809
30849
  option_color: OPTION_COLORS[index2 % OPTION_COLORS.length]
30810
30850
  })) : items;
30811
- console.log({ polls });
30812
30851
  return {
30813
30852
  ...commons,
30814
30853
  type: NewPostType.NEW_POST_POLL,
@@ -30845,6 +30884,7 @@ const PostBuilderEditorInstance = ({
30845
30884
  const [isDragging, setIsDragging] = useState(false);
30846
30885
  const { trackPublish } = usePostBuilderAnalytics();
30847
30886
  const { clearContent } = usePersistence();
30887
+ useHostAnalyticsBridge();
30848
30888
  const handleDragOver = (e) => {
30849
30889
  e.preventDefault();
30850
30890
  setIsDragging(true);
@@ -30864,10 +30904,24 @@ const PostBuilderEditorInstance = ({
30864
30904
  const text2 = editor?.getText();
30865
30905
  const payload = generateCreatePostPayload(editorTab, { editor, sendCrossMention });
30866
30906
  const isPollType = payload?.type === NewPostType.NEW_POST_POLL;
30867
- if (!payload) return;
30907
+ if (payload?.error) {
30908
+ toast.error(payload.error);
30909
+ return;
30910
+ }
30911
+ if (!payload?.postId) return;
30868
30912
  if (isPollType && payload.items?.length === 0)
30869
30913
  return toast.warning(`At least ${POLL_LIMITS.MIN} option is mandatory to create a poll post`);
30870
- trackPublish("attempted");
30914
+ if (typeof window !== "undefined") {
30915
+ window.dispatchEvent(
30916
+ new CustomEvent(PostBuilderEvents.POST_PUBLISH_ATTEMPTED, {
30917
+ detail: {
30918
+ postId: payload.postId,
30919
+ postType: payload.type
30920
+ }
30921
+ })
30922
+ );
30923
+ }
30924
+ trackPublish({ status: "attempted", postId: payload?.postId, postType: payload?.type });
30871
30925
  onCreatePost?.({ payload, html: html2, json, text: text2 });
30872
30926
  if (!clearOnSuccess) return;
30873
30927
  clearContent();
@@ -31041,7 +31095,6 @@ class SessionManager {
31041
31095
  }, SESSION_TIMEOUT_MS);
31042
31096
  }
31043
31097
  endSession(reason) {
31044
- console.log({ reason });
31045
31098
  if (this.inactivityTimer) {
31046
31099
  clearTimeout(this.inactivityTimer);
31047
31100
  }
@@ -31102,7 +31155,7 @@ function useAnalytics({ editorTab, config }) {
31102
31155
  const featureTracker = useRef(new FeatureTracker()).current;
31103
31156
  const logEvent = useAnalyticsLogEvent();
31104
31157
  const trackEvent = useCallback(
31105
- (name, properties = {}) => {
31158
+ ({ name, properties }) => {
31106
31159
  const fullConfig = { ...DEFAULT_CONFIG, ...config };
31107
31160
  if (!fullConfig.enabled) return;
31108
31161
  sessionManager.updateActivity();
@@ -31110,30 +31163,32 @@ function useAnalytics({ editorTab, config }) {
31110
31163
  session_id: sessionManager.getSessionId(),
31111
31164
  timestamp: Date.now(),
31112
31165
  editor_type: editorTab,
31113
- ...properties
31166
+ ...properties ?? {}
31114
31167
  };
31115
- if (logEvent) {
31116
- logEvent(name, enrichedProperties);
31117
- }
31118
- if (fullConfig.debug) {
31119
- console.log("[Analytics]", name, enrichedProperties);
31120
- }
31168
+ const cleanProps = pickBy(enrichedProperties, (value) => value != null);
31169
+ if (logEvent) logEvent(name, cleanProps);
31121
31170
  },
31122
31171
  [config, editorTab, logEvent, sessionManager]
31123
31172
  );
31124
31173
  useEffect(() => {
31125
31174
  const sessionId = sessionManager.startSession();
31126
- trackEvent(ANALYTICS_EVENTS.SESSION.STARTED, {
31127
- session_id: sessionId,
31128
- timestamp: Date.now(),
31129
- editor_type: editorTab
31175
+ trackEvent({
31176
+ name: ANALYTICS_EVENTS.SESSION.STARTED,
31177
+ properties: {
31178
+ session_id: sessionId,
31179
+ timestamp: Date.now(),
31180
+ editor_type: editorTab
31181
+ }
31130
31182
  });
31131
31183
  const handleUnload = () => {
31132
- trackEvent(ANALYTICS_EVENTS.SESSION.COMPLETED, {
31133
- session_id: sessionManager.getSessionId(),
31134
- timestamp: Date.now(),
31135
- editor_type: editorTab,
31136
- session_duration_ms: sessionManager.getSessionDuration()
31184
+ trackEvent({
31185
+ name: ANALYTICS_EVENTS.SESSION.COMPLETED,
31186
+ properties: {
31187
+ session_id: sessionManager.getSessionId(),
31188
+ timestamp: Date.now(),
31189
+ editor_type: editorTab,
31190
+ session_duration_ms: sessionManager.getSessionDuration()
31191
+ }
31137
31192
  });
31138
31193
  };
31139
31194
  window.addEventListener("beforeunload", handleUnload);
@@ -31143,60 +31198,88 @@ function useAnalytics({ editorTab, config }) {
31143
31198
  };
31144
31199
  }, []);
31145
31200
  const trackFeature = useCallback(
31146
- (featureName) => {
31201
+ ({ featureName }) => {
31147
31202
  const { isFirstUse, usageCount } = featureTracker.trackUsage(featureName);
31148
- trackEvent(isFirstUse ? ANALYTICS_EVENTS.FEATURE.DISCOVERED : ANALYTICS_EVENTS.FEATURE.USED, {
31149
- feature_name: featureName,
31150
- is_first_use: isFirstUse,
31151
- usage_count: usageCount
31203
+ trackEvent({
31204
+ name: isFirstUse ? ANALYTICS_EVENTS.FEATURE.DISCOVERED : ANALYTICS_EVENTS.FEATURE.USED,
31205
+ properties: {
31206
+ feature_name: featureName,
31207
+ is_first_use: isFirstUse,
31208
+ usage_count: usageCount
31209
+ }
31152
31210
  });
31153
31211
  },
31154
31212
  [trackEvent, featureTracker]
31155
31213
  );
31156
31214
  const trackPublish = useCallback(
31157
- (status, data) => {
31215
+ ({ status, data }) => {
31158
31216
  const eventMap = {
31159
31217
  attempted: ANALYTICS_EVENTS.PUBLISH.ATTEMPTED,
31160
31218
  success: ANALYTICS_EVENTS.PUBLISH.SUCCESS,
31161
31219
  failed: ANALYTICS_EVENTS.PUBLISH.FAILED
31162
31220
  };
31163
- trackEvent(eventMap[status], {
31221
+ const properties = {
31164
31222
  editor_type: editorTab,
31165
31223
  session_duration_ms: sessionManager.getSessionDuration(),
31166
31224
  ...data
31225
+ };
31226
+ trackEvent({
31227
+ name: eventMap[status],
31228
+ properties
31167
31229
  });
31168
31230
  sessionManager.endSession("completed");
31169
31231
  },
31170
31232
  [trackEvent, editorTab, sessionManager]
31171
31233
  );
31172
31234
  const trackAbandon = useCallback(
31173
- (contentLength, hasUnsavedChanges, abandonReason, postType) => {
31174
- trackEvent(ANALYTICS_EVENTS.SESSION.ABANDONED, {
31175
- session_duration_ms: sessionManager.getSessionDuration(),
31176
- post_type: postType,
31177
- content_length: contentLength,
31178
- has_unsaved_changes: hasUnsavedChanges,
31179
- abandon_reason: abandonReason
31235
+ ({
31236
+ contentLength,
31237
+ hasUnsavedChanges,
31238
+ abandonReason,
31239
+ postType,
31240
+ userHistoryData
31241
+ }) => {
31242
+ trackEvent({
31243
+ name: ANALYTICS_EVENTS.SESSION.ABANDONED,
31244
+ properties: {
31245
+ session_duration_ms: sessionManager.getSessionDuration(),
31246
+ post_type: postType,
31247
+ content_length: contentLength,
31248
+ has_unsaved_changes: hasUnsavedChanges,
31249
+ abandon_reason: abandonReason,
31250
+ // Include user history if provided
31251
+ ...userHistoryData && {
31252
+ previous_abandon_count: userHistoryData.previous_abandon_count,
31253
+ previous_publish_count: userHistoryData.previous_publish_count,
31254
+ time_since_last_publish_ms: userHistoryData.time_since_last_publish_ms,
31255
+ is_returning_user: userHistoryData.is_returning_user
31256
+ }
31257
+ }
31180
31258
  });
31181
31259
  sessionManager.endSession("abandoned");
31182
31260
  },
31183
31261
  [trackEvent, sessionManager]
31184
31262
  );
31185
31263
  const trackTabSwitch = useCallback(
31186
- (oldTab, newTab) => {
31187
- trackEvent(ANALYTICS_EVENTS.EDITOR.FOCUSED, {
31188
- from_tab: oldTab,
31189
- to_tab: newTab,
31190
- editor_type: editorTab
31264
+ ({ oldTab, newTab }) => {
31265
+ trackEvent({
31266
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31267
+ properties: {
31268
+ from_tab: oldTab,
31269
+ to_tab: newTab
31270
+ }
31191
31271
  });
31192
31272
  },
31193
- [trackEvent, editorTab]
31273
+ [trackEvent]
31194
31274
  );
31195
31275
  const trackEditorFocus = useCallback(
31196
- (context) => {
31197
- trackEvent(ANALYTICS_EVENTS.EDITOR.FOCUSED, {
31198
- context,
31199
- editor_type: editorTab
31276
+ ({ context }) => {
31277
+ trackEvent({
31278
+ name: ANALYTICS_EVENTS.EDITOR.FOCUSED,
31279
+ properties: {
31280
+ context,
31281
+ editor_type: editorTab
31282
+ }
31200
31283
  });
31201
31284
  },
31202
31285
  [trackEvent, editorTab]
@@ -31230,19 +31313,91 @@ function useAnalytics({ editorTab, config }) {
31230
31313
  ]
31231
31314
  );
31232
31315
  }
31316
+ const STORAGE_KEY = "pb_user_history";
31317
+ class UserHistoryTracker {
31318
+ history;
31319
+ constructor() {
31320
+ this.history = this.loadHistory();
31321
+ }
31322
+ loadHistory() {
31323
+ try {
31324
+ const stored = localStorage.getItem(STORAGE_KEY);
31325
+ if (stored) {
31326
+ return JSON.parse(stored);
31327
+ }
31328
+ } catch (error) {
31329
+ }
31330
+ return {
31331
+ previous_abandon_count: 0,
31332
+ previous_publish_count: 0,
31333
+ last_publish_timestamp: null,
31334
+ last_abandon_timestamp: null,
31335
+ first_session_timestamp: Date.now()
31336
+ };
31337
+ }
31338
+ saveHistory() {
31339
+ try {
31340
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(this.history));
31341
+ } catch (error) {
31342
+ }
31343
+ }
31344
+ /**
31345
+ * Record a successful publish
31346
+ */
31347
+ recordPublish() {
31348
+ this.history.previous_publish_count += 1;
31349
+ this.history.last_publish_timestamp = Date.now();
31350
+ this.saveHistory();
31351
+ }
31352
+ /**
31353
+ * Record an abandonment
31354
+ */
31355
+ recordAbandon() {
31356
+ this.history.previous_abandon_count += 1;
31357
+ this.history.last_abandon_timestamp = Date.now();
31358
+ this.saveHistory();
31359
+ }
31360
+ /**
31361
+ * Get current user history for analytics
31362
+ */
31363
+ getHistory() {
31364
+ const now2 = Date.now();
31365
+ const daysSinceFirstSession = Math.floor(
31366
+ (now2 - this.history.first_session_timestamp) / (1e3 * 60 * 60 * 24)
31367
+ );
31368
+ return {
31369
+ previous_abandon_count: this.history.previous_abandon_count,
31370
+ previous_publish_count: this.history.previous_publish_count,
31371
+ time_since_last_publish_ms: this.history.last_publish_timestamp ? now2 - this.history.last_publish_timestamp : null,
31372
+ is_returning_user: daysSinceFirstSession > 0.5,
31373
+ days_since_first_session: daysSinceFirstSession
31374
+ };
31375
+ }
31376
+ /**
31377
+ * Clear history (for testing or user request)
31378
+ */
31379
+ clearHistory() {
31380
+ localStorage.removeItem(STORAGE_KEY);
31381
+ this.history = {
31382
+ previous_abandon_count: 0,
31383
+ previous_publish_count: 0,
31384
+ last_publish_timestamp: null,
31385
+ last_abandon_timestamp: null,
31386
+ first_session_timestamp: Date.now()
31387
+ };
31388
+ }
31389
+ }
31233
31390
  function useEditorAnalytics({
31234
31391
  editor,
31235
31392
  editorType,
31236
31393
  context,
31237
31394
  idleTimeout = 3e5,
31238
- // 5 minutes
31239
31395
  trackBlur = false
31240
- // Default: don't track every blur
31241
31396
  }) {
31242
31397
  const analytics = useAnalytics({
31243
31398
  editorTab: editorType,
31244
31399
  config: {
31245
- debug: false,
31400
+ debug: true,
31246
31401
  enabled: true
31247
31402
  }
31248
31403
  });
@@ -31250,6 +31405,7 @@ function useEditorAnalytics({
31250
31405
  const idleTimer = useRef();
31251
31406
  const hasFocusedOnce = useRef(false);
31252
31407
  const hasAbandonedSession = useRef(false);
31408
+ const userHistory = useRef(new UserHistoryTracker()).current;
31253
31409
  const getEditorMetrics = useCallback(() => {
31254
31410
  if (!editor) return null;
31255
31411
  const json = editor.getJSON();
@@ -31289,7 +31445,6 @@ function useEditorAnalytics({
31289
31445
  linkCount,
31290
31446
  formattingFeatures: Array.from(formattingFeatures),
31291
31447
  hasUnsavedChanges: editor.state.doc.content.size > 2,
31292
- // Has content beyond empty doc
31293
31448
  isEmpty: editor.isEmpty
31294
31449
  };
31295
31450
  }, [editor, analytics]);
@@ -31300,16 +31455,29 @@ function useEditorAnalytics({
31300
31455
  idleTimer.current = setTimeout(() => {
31301
31456
  const metrics = getEditorMetrics();
31302
31457
  if (metrics && !metrics.isEmpty) {
31303
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "idle_timeout");
31458
+ const history = userHistory.getHistory();
31459
+ analytics.trackAbandon({
31460
+ contentLength: metrics.characterCount,
31461
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31462
+ abandonReason: "idle_timeout",
31463
+ postType: void 0,
31464
+ userHistoryData: {
31465
+ previous_abandon_count: history.previous_abandon_count,
31466
+ previous_publish_count: history.previous_publish_count,
31467
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31468
+ is_returning_user: history.is_returning_user
31469
+ }
31470
+ });
31471
+ userHistory.recordAbandon();
31304
31472
  hasAbandonedSession.current = true;
31305
31473
  }
31306
31474
  }, idleTimeout);
31307
- }, [editor, idleTimeout, analytics, getEditorMetrics]);
31475
+ }, [editor, idleTimeout, analytics, getEditorMetrics, userHistory]);
31308
31476
  useEffect(() => {
31309
31477
  if (!editor) return;
31310
31478
  const handleFocus = () => {
31311
31479
  if (!hasFocusedOnce.current) {
31312
- analytics.trackEditorFocus(context);
31480
+ analytics.trackEditorFocus({ context });
31313
31481
  hasFocusedOnce.current = true;
31314
31482
  }
31315
31483
  resetIdleTimer();
@@ -31320,9 +31488,12 @@ function useEditorAnalytics({
31320
31488
  if (trackBlur) {
31321
31489
  const metrics = getEditorMetrics();
31322
31490
  if (metrics && !metrics.isEmpty) {
31323
- analytics.trackEvent(ANALYTICS_EVENTS.EDITOR.BLURRED, {
31324
- content_length: metrics.characterCount,
31325
- session_duration_ms: Date.now() - lastActivity.current
31491
+ analytics.trackEvent({
31492
+ name: ANALYTICS_EVENTS.EDITOR.BLURRED,
31493
+ properties: {
31494
+ content_length: metrics.characterCount,
31495
+ session_duration_ms: Date.now() - lastActivity.current
31496
+ }
31326
31497
  });
31327
31498
  }
31328
31499
  }
@@ -31341,7 +31512,20 @@ function useEditorAnalytics({
31341
31512
  if (hasAbandonedSession.current) return;
31342
31513
  const metrics = getEditorMetrics();
31343
31514
  if (metrics && !metrics.isEmpty) {
31344
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "navigation");
31515
+ const history = userHistory.getHistory();
31516
+ analytics.trackAbandon({
31517
+ contentLength: metrics.characterCount,
31518
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31519
+ abandonReason: "navigation",
31520
+ postType: void 0,
31521
+ userHistoryData: {
31522
+ previous_abandon_count: history.previous_abandon_count,
31523
+ previous_publish_count: history.previous_publish_count,
31524
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31525
+ is_returning_user: history.is_returning_user
31526
+ }
31527
+ });
31528
+ userHistory.recordAbandon();
31345
31529
  hasAbandonedSession.current = true;
31346
31530
  }
31347
31531
  };
@@ -31352,46 +31536,76 @@ function useEditorAnalytics({
31352
31536
  clearTimeout(idleTimer.current);
31353
31537
  }
31354
31538
  };
31355
- }, [editor, analytics, getEditorMetrics]);
31539
+ }, [editor, analytics, getEditorMetrics, userHistory]);
31356
31540
  const trackFeature = useCallback(
31357
- (featureName) => {
31358
- analytics.trackFeature(featureName);
31541
+ ({ featureName }) => {
31542
+ analytics.trackFeature({ featureName });
31359
31543
  resetIdleTimer();
31360
31544
  },
31361
31545
  [analytics, resetIdleTimer]
31362
31546
  );
31363
31547
  const trackPublish = useCallback(
31364
- (status, failureReason) => {
31548
+ ({ sessionId, groupId, postId, status, failureReason, postType }) => {
31365
31549
  const metrics = getEditorMetrics();
31366
31550
  if (!metrics) return;
31367
- analytics.trackPublish(status, {
31368
- word_count: metrics.wordCount,
31369
- character_count: metrics.characterCount,
31370
- media_count: metrics.mediaCount,
31371
- link_count: metrics.linkCount,
31372
- formatting_features: metrics.formattingFeatures,
31373
- failure_reason: failureReason
31551
+ const history = userHistory.getHistory();
31552
+ analytics.trackPublish({
31553
+ status,
31554
+ data: {
31555
+ ...sessionId ? { session_id: sessionId } : {},
31556
+ group_id: groupId,
31557
+ post_id: postId,
31558
+ post_type: postType,
31559
+ word_count: metrics.wordCount,
31560
+ character_count: metrics.characterCount,
31561
+ media_count: metrics.mediaCount,
31562
+ link_count: metrics.linkCount,
31563
+ formatting_features: metrics.formattingFeatures,
31564
+ failure_reason: failureReason,
31565
+ // Include user history
31566
+ previous_abandon_count: history.previous_abandon_count,
31567
+ previous_publish_count: history.previous_publish_count,
31568
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31569
+ is_returning_user: history.is_returning_user
31570
+ }
31374
31571
  });
31375
31572
  if (status === "success") {
31573
+ userHistory.recordPublish();
31376
31574
  hasAbandonedSession.current = true;
31377
31575
  }
31378
31576
  },
31379
- [analytics, getEditorMetrics]
31577
+ [analytics, getEditorMetrics, userHistory]
31380
31578
  );
31381
31579
  const trackExplicitAbandon = useCallback(() => {
31382
31580
  if (hasAbandonedSession.current) return;
31383
31581
  const metrics = getEditorMetrics();
31384
31582
  if (metrics && !metrics.isEmpty) {
31385
- analytics.trackAbandon(metrics.characterCount, metrics.hasUnsavedChanges, "user_closed");
31583
+ const history = userHistory.getHistory();
31584
+ analytics.trackAbandon({
31585
+ contentLength: metrics.characterCount,
31586
+ hasUnsavedChanges: metrics.hasUnsavedChanges,
31587
+ abandonReason: "user_closed",
31588
+ postType: void 0,
31589
+ userHistoryData: {
31590
+ previous_abandon_count: history.previous_abandon_count,
31591
+ previous_publish_count: history.previous_publish_count,
31592
+ time_since_last_publish_ms: history.time_since_last_publish_ms,
31593
+ is_returning_user: history.is_returning_user
31594
+ }
31595
+ });
31596
+ userHistory.recordAbandon();
31386
31597
  hasAbandonedSession.current = true;
31387
31598
  }
31388
- }, [analytics, getEditorMetrics]);
31599
+ }, [analytics, getEditorMetrics, userHistory]);
31389
31600
  return {
31390
31601
  trackFeature,
31391
31602
  trackPublish,
31392
31603
  trackExplicitAbandon,
31393
31604
  trackTabSwitch: analytics.trackTabSwitch,
31394
- getEditorMetrics
31605
+ getEditorMetrics,
31606
+ // Expose user history for debugging
31607
+ getUserHistory: () => userHistory.getHistory(),
31608
+ currentSessionId: analytics.getSessionId()
31395
31609
  };
31396
31610
  }
31397
31611
  const PostBuilderAnalyticsProvider = ({
@@ -31457,58 +31671,68 @@ const PostBuilderEditor = ({
31457
31671
  isSubmitting,
31458
31672
  clearOnSuccess
31459
31673
  }
31460
- ) : (
31461
- // <Dialog open={openModal} onOpenChange={onModalOpenChange}>
31462
- // <DialogContent
31463
- // 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"
31464
- // showCloseButton={false}
31465
- // >
31466
- // <DialogHeader>
31467
- // <DialogTitle className="sr-only">Post Builder Modal</DialogTitle>
31468
- // {!hideGroupSelector && (
31469
- // <div className="flex items-center justify-between gap-3">
31470
- // <GroupSelector user={user} store={store} />
31471
- // <DialogClose asChild>
31472
- // <Button variant="outline" size="icon">
31473
- // <X />
31474
- // </Button>
31475
- // </DialogClose>
31476
- // </div>
31477
- // )}
31478
- // </DialogHeader>
31479
- // <PostBuilderEditorInstance
31480
- // editor={editor}
31481
- // actions={actions}
31482
- // editorTab={editorTab}
31483
- // onSwitchEditor={setEditorTab}
31484
- // isSubmitting={isSubmitting}
31485
- // onCreatePost={onCreatePost}
31486
- // clearOnSuccess={clearOnSuccess}
31487
- // />
31488
- // </DialogContent>
31489
- // </Dialog>
31490
- /* @__PURE__ */ jsxs("div", { className: "prose-blockquote: flex-1 flex flex-col space-y-3 max-w-full max-h-[calc(100dvh-7rem)]", children: [
31491
- !hideGroupSelector && /* @__PURE__ */ jsx(GroupSelector, { user, store }),
31492
- /* @__PURE__ */ jsx(
31493
- PostBuilderEditorInstance,
31494
- {
31495
- editor,
31496
- actions,
31497
- editorTab,
31498
- onSwitchEditor: setEditorTab,
31499
- isSubmitting,
31500
- onCreatePost,
31501
- clearOnSuccess
31502
- }
31503
- )
31504
- ] })
31505
- ) }),
31674
+ ) : /* @__PURE__ */ jsxs("div", { className: "prose-blockquote: flex-1 flex flex-col space-y-3 max-w-full max-h-[calc(100dvh-7rem)]", children: [
31675
+ !hideGroupSelector && /* @__PURE__ */ jsx(GroupSelector, { user, store }),
31676
+ /* @__PURE__ */ jsx(
31677
+ PostBuilderEditorInstance,
31678
+ {
31679
+ editor,
31680
+ actions,
31681
+ editorTab,
31682
+ onSwitchEditor: setEditorTab,
31683
+ isSubmitting,
31684
+ onCreatePost,
31685
+ clearOnSuccess
31686
+ }
31687
+ )
31688
+ ] }) }),
31506
31689
  /* @__PURE__ */ jsx(Toaster2, { position: "top-center" })
31507
31690
  ] })
31508
31691
  }
31509
31692
  );
31510
31693
  };
31694
+ const PostBuilderProvider = ({
31695
+ children,
31696
+ apiBaseURL,
31697
+ authToken,
31698
+ toI18N,
31699
+ i18nKeys,
31700
+ logEvent
31701
+ }) => {
31702
+ const t = useCallback(
31703
+ (key, fallback) => {
31704
+ const message = toI18N(i18nKeys[key]);
31705
+ if (message) return message;
31706
+ return fallback || key;
31707
+ },
31708
+ [toI18N, i18nKeys]
31709
+ );
31710
+ const api = useMemo(() => {
31711
+ const core = new CoreApi(apiBaseURL.core, authToken, toI18N);
31712
+ const mfs = new MFSApi(apiBaseURL.mfs, authToken, toI18N);
31713
+ const fileStore = new FilestoreApi(apiBaseURL.fileStore, authToken, toI18N);
31714
+ core.initApi();
31715
+ mfs.initApi();
31716
+ fileStore.initApi();
31717
+ return {
31718
+ core,
31719
+ mfs,
31720
+ fileStore
31721
+ };
31722
+ }, [authToken, apiBaseURL, toI18N]);
31723
+ const value = useMemo(() => {
31724
+ return {
31725
+ authToken,
31726
+ t,
31727
+ i18nKeys,
31728
+ api,
31729
+ logEvent
31730
+ };
31731
+ }, [authToken, t, i18nKeys, api, logEvent]);
31732
+ return /* @__PURE__ */ jsx(PostBuilderContext.Provider, { value, children });
31733
+ };
31511
31734
  export {
31512
31735
  PostBuilderEditor,
31736
+ PostBuilderEvents,
31513
31737
  PostBuilderProvider
31514
31738
  };