@flamingo-stack/openframe-frontend-core 0.0.533 → 0.0.535-1762.4618.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NAV4FRNL.cjs → chunk-2AMYXNQ2.cjs} +26 -26
- package/dist/{chunk-NAV4FRNL.cjs.map → chunk-2AMYXNQ2.cjs.map} +1 -1
- package/dist/{chunk-2XGHEJZK.js → chunk-5OPVJBHQ.js} +4 -4
- package/dist/{chunk-4QKXNWH5.js → chunk-6OZWDOP5.js} +2 -2
- package/dist/{chunk-6YXN5RHW.js → chunk-7TQDW3PE.js} +2 -2
- package/dist/{chunk-U555TMPC.js → chunk-A5EA3YO7.js} +5 -5
- package/dist/{chunk-DFQLUK75.cjs → chunk-CMIHA6TT.cjs} +3 -3
- package/dist/{chunk-DFQLUK75.cjs.map → chunk-CMIHA6TT.cjs.map} +1 -1
- package/dist/{chunk-QZ2NAPLF.cjs → chunk-DK6IYFLD.cjs} +9 -9
- package/dist/{chunk-QZ2NAPLF.cjs.map → chunk-DK6IYFLD.cjs.map} +1 -1
- package/dist/{chunk-LE3BJ5H2.js → chunk-DRJC7TTW.js} +2 -2
- package/dist/{chunk-ENPGPZIB.cjs → chunk-ENOER2QA.cjs} +61 -61
- package/dist/{chunk-ENPGPZIB.cjs.map → chunk-ENOER2QA.cjs.map} +1 -1
- package/dist/{chunk-LIUARTOZ.js → chunk-GBWS62LR.js} +106 -285
- package/dist/chunk-GBWS62LR.js.map +1 -0
- package/dist/{chunk-2MYDGLJS.cjs → chunk-GF5A23J3.cjs} +87 -87
- package/dist/{chunk-2MYDGLJS.cjs.map → chunk-GF5A23J3.cjs.map} +1 -1
- package/dist/{chunk-4ZRHVOEB.cjs → chunk-GRGFMXNO.cjs} +31 -31
- package/dist/{chunk-4ZRHVOEB.cjs.map → chunk-GRGFMXNO.cjs.map} +1 -1
- package/dist/{chunk-46FKXLNE.js → chunk-GS4R5UQ7.js} +2 -2
- package/dist/{chunk-2TUOBFPK.js → chunk-HNZDQ4SH.js} +2 -2
- package/dist/{chunk-KMB66NYX.cjs → chunk-HSRHPF32.cjs} +7 -7
- package/dist/{chunk-KMB66NYX.cjs.map → chunk-HSRHPF32.cjs.map} +1 -1
- package/dist/{chunk-RKITTO5V.cjs → chunk-JW4BTXVH.cjs} +14 -14
- package/dist/{chunk-RKITTO5V.cjs.map → chunk-JW4BTXVH.cjs.map} +1 -1
- package/dist/{chunk-MVGL5NNJ.js → chunk-JWJQHURJ.js} +2 -2
- package/dist/{chunk-5U67WTAS.js → chunk-JWWZFEFI.js} +2 -2
- package/dist/{chunk-JDW2IL7A.cjs → chunk-JZMQQBUC.cjs} +11 -11
- package/dist/{chunk-JDW2IL7A.cjs.map → chunk-JZMQQBUC.cjs.map} +1 -1
- package/dist/{chunk-XN4JKIJY.js → chunk-QHOVACZK.js} +2 -2
- package/dist/{chunk-UPHN2VRZ.cjs → chunk-T4GNFVT3.cjs} +800 -979
- package/dist/chunk-T4GNFVT3.cjs.map +1 -0
- package/dist/{chunk-GNOK5J34.cjs → chunk-T743Z3KN.cjs} +37 -37
- package/dist/{chunk-GNOK5J34.cjs.map → chunk-T743Z3KN.cjs.map} +1 -1
- package/dist/{chunk-J4BE4FIR.cjs → chunk-TOWXHZF5.cjs} +4 -4
- package/dist/{chunk-J4BE4FIR.cjs.map → chunk-TOWXHZF5.cjs.map} +1 -1
- package/dist/{chunk-6SMLYZLH.js → chunk-URBYMQ4Z.js} +4 -4
- package/dist/{chunk-Z3NOI7X7.cjs → chunk-WL3PP4D6.cjs} +26 -26
- package/dist/{chunk-Z3NOI7X7.cjs.map → chunk-WL3PP4D6.cjs.map} +1 -1
- package/dist/{chunk-YLB6XXO6.js → chunk-WXRQYGE5.js} +2 -2
- package/dist/{chunk-6W3ULZ4X.js → chunk-XPKCOZQE.js} +6 -6
- package/dist/{chunk-OLOKQQAP.cjs → chunk-ZUVBTDLG.cjs} +5 -5
- package/dist/{chunk-OLOKQQAP.cjs.map → chunk-ZUVBTDLG.cjs.map} +1 -1
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/help-center-pages/index.cjs +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +132 -132
- package/dist/components/index.js +11 -11
- package/dist/components/meeting-scheduler/index.cjs +34 -34
- package/dist/components/meeting-scheduler/index.js +3 -3
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/file-upload.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/components/ui/markdown/rich/embed-overrides.d.ts.map +1 -1
- package/dist/components/ui/markdown/rich/shortcodes.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/utils/social-embed-cache.d.ts +16 -16
- package/dist/utils/social-embed-cache.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/chat-input.tsx +84 -32
- package/src/components/ui/__tests__/__snapshots__/markdown-parity.test.tsx.snap +1 -5
- package/src/components/ui/file-upload.tsx +5 -1
- package/src/components/ui/markdown/rich/__tests__/shortcodes.test.ts +58 -0
- package/src/components/ui/markdown/rich/embed-overrides.tsx +13 -7
- package/src/components/ui/markdown/rich/shortcodes.ts +15 -0
- package/src/utils/social-embed-cache.ts +63 -336
- package/dist/chunk-LIUARTOZ.js.map +0 -1
- package/dist/chunk-UPHN2VRZ.cjs.map +0 -1
- /package/dist/{chunk-2XGHEJZK.js.map → chunk-5OPVJBHQ.js.map} +0 -0
- /package/dist/{chunk-4QKXNWH5.js.map → chunk-6OZWDOP5.js.map} +0 -0
- /package/dist/{chunk-6YXN5RHW.js.map → chunk-7TQDW3PE.js.map} +0 -0
- /package/dist/{chunk-U555TMPC.js.map → chunk-A5EA3YO7.js.map} +0 -0
- /package/dist/{chunk-LE3BJ5H2.js.map → chunk-DRJC7TTW.js.map} +0 -0
- /package/dist/{chunk-46FKXLNE.js.map → chunk-GS4R5UQ7.js.map} +0 -0
- /package/dist/{chunk-2TUOBFPK.js.map → chunk-HNZDQ4SH.js.map} +0 -0
- /package/dist/{chunk-MVGL5NNJ.js.map → chunk-JWJQHURJ.js.map} +0 -0
- /package/dist/{chunk-5U67WTAS.js.map → chunk-JWWZFEFI.js.map} +0 -0
- /package/dist/{chunk-XN4JKIJY.js.map → chunk-QHOVACZK.js.map} +0 -0
- /package/dist/{chunk-6SMLYZLH.js.map → chunk-URBYMQ4Z.js.map} +0 -0
- /package/dist/{chunk-YLB6XXO6.js.map → chunk-WXRQYGE5.js.map} +0 -0
- /package/dist/{chunk-6W3ULZ4X.js.map → chunk-XPKCOZQE.js.map} +0 -0
|
@@ -6530,6 +6530,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6530
6530
|
// contenteditable div, not a <textarea>, so spreading them would warn.
|
|
6531
6531
|
} = rest;
|
|
6532
6532
|
const [value, setValue] = useState10("");
|
|
6533
|
+
const [hasChips, setHasChips] = useState10(false);
|
|
6533
6534
|
const [focused, setFocused] = useState10(false);
|
|
6534
6535
|
const [isStopping, setIsStopping] = useState10(false);
|
|
6535
6536
|
const [previewDismissed, setPreviewDismissed] = useState10(false);
|
|
@@ -6565,26 +6566,32 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6565
6566
|
if (typeof caret === "number") placeCaretAtOffset(el, caret);
|
|
6566
6567
|
else placeCaretAtEnd(el);
|
|
6567
6568
|
}
|
|
6569
|
+
setHasChips(el.querySelector("[data-token]") !== null);
|
|
6568
6570
|
}
|
|
6571
|
+
valueRef.current = next;
|
|
6569
6572
|
setValue(next);
|
|
6570
6573
|
}, []);
|
|
6571
6574
|
const fire = useCallback3(
|
|
6572
6575
|
(message2) => {
|
|
6573
6576
|
const can = (message2.length > 0 || allowEmptySend) && !sending && !disabled;
|
|
6574
6577
|
if (!can || !onSend) return;
|
|
6575
|
-
const
|
|
6576
|
-
|
|
6577
|
-
|
|
6578
|
-
|
|
6579
|
-
|
|
6580
|
-
|
|
6578
|
+
const sentMeta = metaRef.current;
|
|
6579
|
+
metaRef.current = /* @__PURE__ */ new Map();
|
|
6580
|
+
applyValue("");
|
|
6581
|
+
shouldRefocusRef.current = true;
|
|
6582
|
+
focusEditor();
|
|
6583
|
+
const restore = () => {
|
|
6584
|
+
if (valueRef.current.length > 0) return;
|
|
6585
|
+
metaRef.current = sentMeta;
|
|
6586
|
+
applyValue(message2);
|
|
6581
6587
|
};
|
|
6588
|
+
const result = onSend(message2);
|
|
6582
6589
|
if (result instanceof Promise) {
|
|
6583
6590
|
void result.then((ok) => {
|
|
6584
|
-
if (ok
|
|
6591
|
+
if (ok === false) restore();
|
|
6585
6592
|
});
|
|
6586
|
-
} else if (result
|
|
6587
|
-
|
|
6593
|
+
} else if (result === false) {
|
|
6594
|
+
restore();
|
|
6588
6595
|
}
|
|
6589
6596
|
},
|
|
6590
6597
|
[allowEmptySend, sending, disabled, onSend, focusEditor, applyValue]
|
|
@@ -6673,6 +6680,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6673
6680
|
const syncFromDom = useCallback3(() => {
|
|
6674
6681
|
const el = editorRef.current;
|
|
6675
6682
|
if (!el) return;
|
|
6683
|
+
setHasChips(el.querySelector("[data-token]") !== null);
|
|
6676
6684
|
setValue(serialize(el));
|
|
6677
6685
|
}, []);
|
|
6678
6686
|
const handleInput = useCallback3(() => {
|
|
@@ -6778,8 +6786,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6778
6786
|
const hasContent2 = value.trim().length > 0 || allowEmptySend;
|
|
6779
6787
|
const sendDisabled = sending || disabled || !hasContent2;
|
|
6780
6788
|
const isEmpty = value.length === 0;
|
|
6781
|
-
const
|
|
6782
|
-
const showPreview = !isDisabled && !!previewText && !previewDismissed;
|
|
6789
|
+
const showPreview = !sending && !disabled && !!previewText && !previewDismissed;
|
|
6783
6790
|
return /* @__PURE__ */ jsx30(
|
|
6784
6791
|
"div",
|
|
6785
6792
|
{
|
|
@@ -6813,23 +6820,24 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6813
6820
|
},
|
|
6814
6821
|
className: cn(
|
|
6815
6822
|
// `items-center` keeps the empty single-line text AND a mention chip
|
|
6816
|
-
// vertically centered the same way. `py-1.5`
|
|
6817
|
-
// editor's `leading-9` (36px) →
|
|
6818
|
-
//
|
|
6819
|
-
// (incl. its ~3.5px vertical-align overhead), so there's almost
|
|
6820
|
-
// slack for the chip to drift in → it reads as centered
|
|
6821
|
-
//
|
|
6823
|
+
// vertically centered the same way. With a chip in the box, `py-1.5`
|
|
6824
|
+
// (6px) pairs with the editor's `leading-9` (36px) → that row is
|
|
6825
|
+
// 36 + 2*6 = 48px. The 36px line box is just barely above the 32px
|
|
6826
|
+
// chip (incl. its ~3.5px vertical-align overhead), so there's almost
|
|
6827
|
+
// no slack for the chip to drift in → it reads as centered.
|
|
6828
|
+
// A chipless row is shorter than its content box and the `min-h-*`
|
|
6829
|
+
// here is what sets its height: 48px from `md` up, 44px below.
|
|
6822
6830
|
"flex w-full items-center gap-2 px-3 py-1.5 min-h-11 md:min-h-12 cursor-text group transition-colors duration-200",
|
|
6823
6831
|
!hideBorder && "rounded-[6px] border bg-ods-card border-ods-border",
|
|
6824
|
-
!hideBorder && (focused ? "border-ods-accent" : !
|
|
6825
|
-
!hideBorder &&
|
|
6832
|
+
!hideBorder && (focused ? "border-ods-accent" : !disabled && "hover:bg-ods-bg-hover hover:border-ods-border-hover"),
|
|
6833
|
+
!hideBorder && disabled && "!cursor-not-allowed bg-ods-bg",
|
|
6826
6834
|
hideBorder && "bg-transparent"
|
|
6827
6835
|
),
|
|
6828
6836
|
children: [
|
|
6829
6837
|
startIcon && /* @__PURE__ */ jsx30("span", { className: "flex h-6 shrink-0 items-center", children: startIcon }),
|
|
6830
6838
|
/* @__PURE__ */ jsxs23("div", { className: "relative flex-1 min-w-0", children: [
|
|
6831
|
-
isEmpty && !showPreview && /* @__PURE__ */ jsx30("span", { className: "pointer-events-none absolute left-0 top-0 select-none text-h4
|
|
6832
|
-
showPreview && /* @__PURE__ */ jsx30("p", { className: "pointer-events-none absolute inset-x-0 top-0 m-0 select-none truncate text-h4
|
|
6839
|
+
isEmpty && !showPreview && /* @__PURE__ */ jsx30("span", { className: "pointer-events-none absolute left-0 top-0 select-none text-h4 text-ods-text-secondary", children: disabled ? "Connection lost. Waiting to reconnect..." : placeholder }),
|
|
6840
|
+
showPreview && /* @__PURE__ */ jsx30("p", { className: cn("pointer-events-none absolute inset-x-0 top-0 m-0 select-none truncate text-h4 text-ods-text-secondary", hasChips && "!leading-9"), children: previewText }),
|
|
6833
6841
|
/* @__PURE__ */ jsx30(
|
|
6834
6842
|
"div",
|
|
6835
6843
|
{
|
|
@@ -6838,7 +6846,7 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6838
6846
|
role: "textbox",
|
|
6839
6847
|
"aria-multiline": "true",
|
|
6840
6848
|
"aria-label": typeof placeholder === "string" ? placeholder : "Message",
|
|
6841
|
-
contentEditable: !
|
|
6849
|
+
contentEditable: !disabled,
|
|
6842
6850
|
suppressContentEditableWarning: true,
|
|
6843
6851
|
spellCheck: true,
|
|
6844
6852
|
onInput: handleInput,
|
|
@@ -6861,17 +6869,25 @@ var ChatInput = forwardRef13((allProps, ref) => {
|
|
|
6861
6869
|
// see the preview comment above) and is only made transparent;
|
|
6862
6870
|
// the absolutely-positioned single-line preview paints over it.
|
|
6863
6871
|
showPreview && "opacity-0",
|
|
6864
|
-
// `leading-9` (36px) sits just above the 32px chip's
|
|
6865
|
-
// (~35.5px incl. vertical-align overhead): the LINE
|
|
6866
|
-
// height (deterministic 48px, no overflow) AND the
|
|
6867
|
-
// keeps the chip centered
|
|
6868
|
-
// `
|
|
6869
|
-
//
|
|
6870
|
-
//
|
|
6871
|
-
//
|
|
6872
|
-
|
|
6872
|
+
// WITH chips, `leading-9` (36px) sits just above the 32px chip's
|
|
6873
|
+
// line-box need (~35.5px incl. vertical-align overhead): the LINE
|
|
6874
|
+
// drives row height (deterministic 48px, no overflow) AND the
|
|
6875
|
+
// near-zero slack keeps the chip centered against the `align-top`
|
|
6876
|
+
// `h-9` wrapper `buildChipEl` gives it. ~4px gap between wrapped
|
|
6877
|
+
// chip rows.
|
|
6878
|
+
// WITHOUT chips there is nothing tall to center, and forcing the
|
|
6879
|
+
// same 36px box on 14px phone text (`text-h4`) put a blank line's
|
|
6880
|
+
// worth of air between every wrapped row — so plain drafts keep
|
|
6881
|
+
// `text-h4`'s own responsive line-height (20px / 24px at md).
|
|
6882
|
+
// `min-h-*` pins the single-line box even when EMPTY: a
|
|
6883
|
+
// non-editable (`contentEditable=false`, i.e. `disabled`) empty div
|
|
6884
|
+
// would otherwise collapse to 0px, and `items-center` would
|
|
6885
|
+
// re-center the shorter wrapper in the row — dropping the `top-0`
|
|
6886
|
+
// placeholder down.
|
|
6887
|
+
"text-h4 text-ods-text-primary",
|
|
6888
|
+
hasChips ? "min-h-9 !leading-9" : "min-h-[var(--font-line-space-h4-body)]",
|
|
6873
6889
|
"scrollbar-thin scrollbar-track-transparent scrollbar-thumb-ods-border/30 hover:scrollbar-thumb-ods-text-secondary/30",
|
|
6874
|
-
|
|
6890
|
+
disabled && "cursor-not-allowed"
|
|
6875
6891
|
)
|
|
6876
6892
|
}
|
|
6877
6893
|
)
|
|
@@ -23109,9 +23125,8 @@ function useRichMarkdownRuntime() {
|
|
|
23109
23125
|
import { useState as useState50, useEffect as useEffect41, useRef as useRef33 } from "react";
|
|
23110
23126
|
|
|
23111
23127
|
// src/utils/social-embed-cache.ts
|
|
23112
|
-
var cachingRequests = /* @__PURE__ */ new Map();
|
|
23113
23128
|
var dataCache = /* @__PURE__ */ new Map();
|
|
23114
|
-
var
|
|
23129
|
+
var inflightRequests = /* @__PURE__ */ new Map();
|
|
23115
23130
|
var SocialEmbedCache = class _SocialEmbedCache {
|
|
23116
23131
|
static getInstance() {
|
|
23117
23132
|
if (!_SocialEmbedCache.instance) {
|
|
@@ -23119,269 +23134,64 @@ var SocialEmbedCache = class _SocialEmbedCache {
|
|
|
23119
23134
|
}
|
|
23120
23135
|
return _SocialEmbedCache.instance;
|
|
23121
23136
|
}
|
|
23122
|
-
// Check if data exists in memory cache
|
|
23123
23137
|
getFromMemory(url) {
|
|
23124
23138
|
return dataCache.get(url) || null;
|
|
23125
23139
|
}
|
|
23126
|
-
// Store data in memory cache
|
|
23127
23140
|
setInMemory(url, data) {
|
|
23128
23141
|
dataCache.set(url, data);
|
|
23129
23142
|
}
|
|
23130
|
-
|
|
23131
|
-
|
|
23132
|
-
|
|
23133
|
-
|
|
23134
|
-
const response = await fetch(`${options.apiEndpoint}?url=${encodeURIComponent(options.url)}&cache-only=true`);
|
|
23135
|
-
if (response.ok) {
|
|
23136
|
-
const data = await response.json();
|
|
23137
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache hit: ${options.url}`);
|
|
23138
|
-
return data;
|
|
23139
|
-
} else if (response.status === 404) {
|
|
23140
|
-
console.log(`\u{1F4A8} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] No server cache available for: ${options.url}`);
|
|
23141
|
-
return null;
|
|
23142
|
-
}
|
|
23143
|
-
} catch (error) {
|
|
23144
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache check failed for: ${options.url}`, error);
|
|
23145
|
-
}
|
|
23146
|
-
return null;
|
|
23147
|
-
}
|
|
23148
|
-
// Helper method to update server cache asynchronously
|
|
23149
|
-
async updateServerCache(apiEndpoint, url, data) {
|
|
23150
|
-
try {
|
|
23151
|
-
console.log(`\u{1F4BE} [Cache] Updating server cache for: ${url}`);
|
|
23152
|
-
await fetch(`${apiEndpoint}?url=${encodeURIComponent(url)}`, {
|
|
23153
|
-
method: "POST",
|
|
23154
|
-
headers: { "Content-Type": "application/json" },
|
|
23155
|
-
body: JSON.stringify(data)
|
|
23156
|
-
});
|
|
23157
|
-
console.log(`\u2705 [Cache] Server cache updated for: ${url}`);
|
|
23158
|
-
} catch (error) {
|
|
23159
|
-
console.log(`\u274C [Cache] Server cache update failed for: ${url}`, error);
|
|
23160
|
-
}
|
|
23161
|
-
}
|
|
23162
|
-
// Store data in server cache (with deduplication)
|
|
23163
|
-
async setInServer(options, data) {
|
|
23164
|
-
const cacheKey = `${options.platform}-${options.url}`;
|
|
23165
|
-
if (cachingRequests.has(cacheKey)) {
|
|
23166
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache update skipped (already in progress): ${options.url}`);
|
|
23167
|
-
return;
|
|
23168
|
-
}
|
|
23169
|
-
console.log(`\u{1F4BE} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Updating server cache for: ${options.url}`);
|
|
23170
|
-
const cachePromise = fetch(`${options.apiEndpoint}?url=${encodeURIComponent(options.url)}`, {
|
|
23171
|
-
method: "POST",
|
|
23172
|
-
headers: { "Content-Type": "application/json" },
|
|
23173
|
-
body: JSON.stringify(data)
|
|
23174
|
-
}).then(() => {
|
|
23175
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache updated successfully: ${options.url}`);
|
|
23176
|
-
cachingRequests.delete(cacheKey);
|
|
23177
|
-
}).catch((error) => {
|
|
23178
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Cache] Server cache update failed: ${options.url}`, error);
|
|
23179
|
-
cachingRequests.delete(cacheKey);
|
|
23180
|
-
});
|
|
23181
|
-
cachingRequests.set(cacheKey, cachePromise);
|
|
23182
|
-
await cachePromise;
|
|
23183
|
-
}
|
|
23184
|
-
// Direct fetch with platform-specific logic
|
|
23185
|
-
async fetchDirect(options) {
|
|
23186
|
-
try {
|
|
23187
|
-
console.log(`\u{1F504} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Direct] Fetching content: ${options.url}`);
|
|
23188
|
-
const result = await options.directFetcher();
|
|
23189
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Direct] Fetch successful: ${options.url}`);
|
|
23190
|
-
return result;
|
|
23191
|
-
} catch (error) {
|
|
23192
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Direct] Fetch failed: ${options.url}`, error);
|
|
23193
|
-
return null;
|
|
23194
|
-
}
|
|
23195
|
-
}
|
|
23196
|
-
// Unified cache hierarchy: Memory → Server → Direct
|
|
23143
|
+
/**
|
|
23144
|
+
* Memory → proxy. Kept the historical name so the embed clients'
|
|
23145
|
+
* call sites are unchanged.
|
|
23146
|
+
*/
|
|
23197
23147
|
async fetchWithHierarchy(options) {
|
|
23198
|
-
const { url, platform, onDataUpdate, onError, onLoading
|
|
23199
|
-
const platformName = platform.charAt(0).toUpperCase() + platform.slice(1);
|
|
23200
|
-
this.scheduleAsyncRefresh(platform, url, dataValidator, options.apiEndpoint);
|
|
23201
|
-
console.log(`\u{1F50D} [${platformName} Cache] Checking memory cache for: ${url}`);
|
|
23148
|
+
const { url, platform, apiEndpoint, dataValidator, onDataUpdate, onError, onLoading } = options;
|
|
23202
23149
|
const memoryData = this.getFromMemory(url);
|
|
23203
23150
|
if (memoryData && dataValidator(memoryData)) {
|
|
23204
|
-
console.log(`\u{1F48E} [${platformName} Cache] Memory cache hit for: ${url}`);
|
|
23205
23151
|
onDataUpdate(memoryData);
|
|
23206
23152
|
onLoading(false);
|
|
23207
23153
|
return;
|
|
23208
23154
|
}
|
|
23209
|
-
console.log(`\u{1F50D} [${platformName} Cache] No memory cache, checking server cache for: ${url}`);
|
|
23210
|
-
const serverCacheData = await this.getFromServer(options);
|
|
23211
|
-
if (serverCacheData && dataValidator(serverCacheData)) {
|
|
23212
|
-
console.log(`\u{1F3AF} [${platformName} Cache] Server cache hit (cached data) for: ${url}`);
|
|
23213
|
-
onDataUpdate(serverCacheData);
|
|
23214
|
-
this.setInMemory(url, serverCacheData);
|
|
23215
|
-
onLoading(false);
|
|
23216
|
-
return;
|
|
23217
|
-
}
|
|
23218
|
-
console.log(`\u{1F50D} [${platformName} Cache] No server cache, attempting direct fetch for: ${url}`);
|
|
23219
|
-
if (platform === "reddit") {
|
|
23220
|
-
try {
|
|
23221
|
-
const directResponse = await fetch(url, {
|
|
23222
|
-
method: "GET",
|
|
23223
|
-
headers: {
|
|
23224
|
-
"Accept": "application/json"
|
|
23225
|
-
},
|
|
23226
|
-
signal: AbortSignal.timeout(1e4)
|
|
23227
|
-
});
|
|
23228
|
-
if (directResponse.ok) {
|
|
23229
|
-
const directData = await directResponse.json();
|
|
23230
|
-
if (directData && dataValidator(directData)) {
|
|
23231
|
-
console.log(`\u2705 [${platformName} Direct] Browser direct fetch successful for: ${url}`);
|
|
23232
|
-
onDataUpdate(directData);
|
|
23233
|
-
this.setInMemory(url, directData);
|
|
23234
|
-
onLoading(false);
|
|
23235
|
-
setTimeout(() => {
|
|
23236
|
-
this.updateServerCache(options.apiEndpoint, url, directData);
|
|
23237
|
-
}, 0);
|
|
23238
|
-
return;
|
|
23239
|
-
}
|
|
23240
|
-
}
|
|
23241
|
-
console.log(`\u{1F4A8} [${platformName} Direct] Browser direct fetch failed (${directResponse.status}), trying server proxy...`);
|
|
23242
|
-
} catch (directError) {
|
|
23243
|
-
console.log(`\u{1F4A8} [${platformName} Direct] Browser direct fetch failed, trying server proxy...`, directError);
|
|
23244
|
-
}
|
|
23245
|
-
}
|
|
23246
|
-
console.log(`\u{1F50D} [${platformName} Cache] Trying server proxy for: ${url}`);
|
|
23247
23155
|
try {
|
|
23248
|
-
const
|
|
23249
|
-
if (
|
|
23250
|
-
|
|
23251
|
-
|
|
23252
|
-
|
|
23253
|
-
|
|
23254
|
-
console.log(`\u{1F3AF} [${platformName} Proxy] Server cache hit (cached data) for: ${url}`);
|
|
23255
|
-
} else if (cacheStatus === "MISS-FETCHED") {
|
|
23256
|
-
console.log(`\u{1F504} [${platformName} Proxy] Server processed fresh fetch (now cached) for: ${url}`);
|
|
23257
|
-
} else {
|
|
23258
|
-
console.log(`\u2705 [${platformName} Proxy] Server returned data (${cacheStatus}) for: ${url}`);
|
|
23259
|
-
}
|
|
23260
|
-
onDataUpdate(serverData);
|
|
23261
|
-
this.setInMemory(url, serverData);
|
|
23262
|
-
onLoading(false);
|
|
23263
|
-
return;
|
|
23264
|
-
} else {
|
|
23265
|
-
console.log(`\u26A0\uFE0F [${platformName} Proxy] Server returned data but validation failed for: ${url}`);
|
|
23266
|
-
throw new Error("Server proxy returned invalid data shape");
|
|
23267
|
-
}
|
|
23268
|
-
} else {
|
|
23269
|
-
let errorData = null;
|
|
23270
|
-
try {
|
|
23271
|
-
errorData = await response.json();
|
|
23272
|
-
} catch {
|
|
23273
|
-
}
|
|
23274
|
-
if (response.status === 404 && errorData?.error && errorData?.message) {
|
|
23275
|
-
console.log(`\u{1F6AB} [${platformName} Proxy] Content unavailable: ${errorData.message}`);
|
|
23276
|
-
onError(errorData.message);
|
|
23277
|
-
onLoading(false);
|
|
23278
|
-
return;
|
|
23279
|
-
}
|
|
23280
|
-
if (errorData?.error) {
|
|
23281
|
-
throw new Error(`Server error: ${errorData.error}`);
|
|
23282
|
-
}
|
|
23283
|
-
throw new Error(`Server proxy failed: ${response.status}`);
|
|
23156
|
+
const data = await this.fetchFromProxy(url, apiEndpoint, dataValidator);
|
|
23157
|
+
if (data) {
|
|
23158
|
+
this.setInMemory(url, data);
|
|
23159
|
+
onDataUpdate(data);
|
|
23160
|
+
onLoading(false);
|
|
23161
|
+
return;
|
|
23284
23162
|
}
|
|
23163
|
+
onError(`This ${platform === "reddit" ? "Reddit post" : "tweet"} could not be loaded.`);
|
|
23285
23164
|
} catch (error) {
|
|
23286
|
-
console.log(`\u274C [${
|
|
23165
|
+
console.log(`\u274C [${platform} embed] Proxy fetch failed for: ${url}`, error);
|
|
23287
23166
|
onError(`Unable to load ${platform} content`);
|
|
23288
|
-
onLoading(false);
|
|
23289
23167
|
}
|
|
23168
|
+
onLoading(false);
|
|
23290
23169
|
}
|
|
23291
|
-
|
|
23292
|
-
|
|
23293
|
-
|
|
23294
|
-
|
|
23295
|
-
|
|
23296
|
-
|
|
23297
|
-
|
|
23298
|
-
|
|
23299
|
-
|
|
23300
|
-
fetch(`${apiEndpoint}?url=${encodeURIComponent(url)}
|
|
23301
|
-
|
|
23302
|
-
|
|
23303
|
-
|
|
23304
|
-
|
|
23305
|
-
|
|
23306
|
-
|
|
23307
|
-
}).then((data) => {
|
|
23308
|
-
if (data && dataValidator(data)) {
|
|
23309
|
-
this.setInMemory(url, data);
|
|
23310
|
-
console.log(`\u2705 [${platformName} Async] Background refresh completed for: ${url}`);
|
|
23311
|
-
} else if (data) {
|
|
23312
|
-
console.log(`\u274C [${platformName} Async] Background refresh failed (invalid data) for: ${url}`);
|
|
23313
|
-
}
|
|
23314
|
-
}).catch((error) => console.log(`\u274C [${platformName} Async] Background refresh failed for: ${url}`, error));
|
|
23315
|
-
}, 1e3);
|
|
23316
|
-
}
|
|
23317
|
-
// Background refresh to keep cache fresh (with request deduplication)
|
|
23318
|
-
async backgroundRefresh(options, currentData) {
|
|
23319
|
-
const refreshKey = `refresh-${options.platform}-${options.url}`;
|
|
23320
|
-
const now = Date.now();
|
|
23321
|
-
const lastRefresh = refreshTimestamps.get(refreshKey);
|
|
23322
|
-
if (lastRefresh && now - lastRefresh < 3e4) {
|
|
23323
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Refresh skipped (recent refresh): ${options.url}`);
|
|
23324
|
-
return;
|
|
23325
|
-
}
|
|
23326
|
-
if (cachingRequests.has(refreshKey)) {
|
|
23327
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Refresh skipped (already in progress): ${options.url}`);
|
|
23328
|
-
return;
|
|
23329
|
-
}
|
|
23330
|
-
const refreshPromise = (async () => {
|
|
23331
|
-
try {
|
|
23332
|
-
console.log(`\u{1F504} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Starting background refresh for: ${options.url}`);
|
|
23333
|
-
refreshTimestamps.set(refreshKey, now);
|
|
23334
|
-
const freshData = await this.fetchDirect(options);
|
|
23335
|
-
if (freshData && options.dataValidator(freshData)) {
|
|
23336
|
-
this.setInMemory(options.url, freshData);
|
|
23337
|
-
await this.setInServer(options, freshData);
|
|
23338
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Background refresh completed for: ${options.url}`);
|
|
23339
|
-
} else {
|
|
23340
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Background refresh failed (invalid data) for: ${options.url}`);
|
|
23341
|
-
}
|
|
23342
|
-
} catch (error) {
|
|
23343
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Background] Background refresh failed for: ${options.url}`, error);
|
|
23344
|
-
} finally {
|
|
23345
|
-
cachingRequests.delete(refreshKey);
|
|
23170
|
+
/**
|
|
23171
|
+
* Returns the validated payload, `null` for a structured "content
|
|
23172
|
+
* unavailable" 404, and throws for everything else. Concurrent calls for
|
|
23173
|
+
* the same URL share one request.
|
|
23174
|
+
*/
|
|
23175
|
+
fetchFromProxy(url, apiEndpoint, dataValidator) {
|
|
23176
|
+
const inflight = inflightRequests.get(url);
|
|
23177
|
+
if (inflight) return inflight;
|
|
23178
|
+
const request = (async () => {
|
|
23179
|
+
const response = await fetch(`${apiEndpoint}?url=${encodeURIComponent(url)}`, {
|
|
23180
|
+
signal: AbortSignal.timeout(15e3)
|
|
23181
|
+
});
|
|
23182
|
+
if (response.ok) {
|
|
23183
|
+
const data = await response.json();
|
|
23184
|
+
if (data && dataValidator(data)) return data;
|
|
23185
|
+
throw new Error("Server proxy returned invalid data shape");
|
|
23346
23186
|
}
|
|
23187
|
+
if (response.status === 404) return null;
|
|
23188
|
+
throw new Error(`Server proxy failed: ${response.status}`);
|
|
23347
23189
|
})();
|
|
23348
|
-
|
|
23349
|
-
|
|
23350
|
-
|
|
23351
|
-
|
|
23352
|
-
|
|
23353
|
-
const refreshKey = `silent-refresh-${options.platform}-${options.url}`;
|
|
23354
|
-
const now = Date.now();
|
|
23355
|
-
const lastRefresh = refreshTimestamps.get(refreshKey);
|
|
23356
|
-
if (lastRefresh && now - lastRefresh < 3e5) {
|
|
23357
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh skipped (recent refresh): ${options.url}`);
|
|
23358
|
-
return;
|
|
23359
|
-
}
|
|
23360
|
-
if (cachingRequests.has(refreshKey)) {
|
|
23361
|
-
console.log(`\u23ED\uFE0F [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh skipped (already in progress): ${options.url}`);
|
|
23362
|
-
return;
|
|
23363
|
-
}
|
|
23364
|
-
setTimeout(() => {
|
|
23365
|
-
const refreshPromise = (async () => {
|
|
23366
|
-
try {
|
|
23367
|
-
console.log(`\u{1F504} [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Starting silent background refresh for: ${options.url}`);
|
|
23368
|
-
refreshTimestamps.set(refreshKey, now);
|
|
23369
|
-
const freshData = await this.fetchDirect(options);
|
|
23370
|
-
if (freshData && options.dataValidator(freshData)) {
|
|
23371
|
-
this.setInMemory(options.url, freshData);
|
|
23372
|
-
await this.setInServer(options, freshData);
|
|
23373
|
-
console.log(`\u2705 [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh completed for: ${options.url}`);
|
|
23374
|
-
} else {
|
|
23375
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh failed (invalid data) for: ${options.url}`);
|
|
23376
|
-
}
|
|
23377
|
-
} catch (error) {
|
|
23378
|
-
console.log(`\u274C [${options.platform.charAt(0).toUpperCase() + options.platform.slice(1)} Silent] Silent refresh failed for: ${options.url}`, error);
|
|
23379
|
-
} finally {
|
|
23380
|
-
cachingRequests.delete(refreshKey);
|
|
23381
|
-
}
|
|
23382
|
-
})();
|
|
23383
|
-
cachingRequests.set(refreshKey, refreshPromise);
|
|
23384
|
-
}, 0);
|
|
23190
|
+
inflightRequests.set(
|
|
23191
|
+
url,
|
|
23192
|
+
request.finally(() => inflightRequests.delete(url))
|
|
23193
|
+
);
|
|
23194
|
+
return inflightRequests.get(url);
|
|
23385
23195
|
}
|
|
23386
23196
|
};
|
|
23387
23197
|
var socialCache = SocialEmbedCache.getInstance();
|
|
@@ -25019,13 +24829,15 @@ function buildRichEmbedOverrides({
|
|
|
25019
24829
|
}
|
|
25020
24830
|
return standard.div(divProps);
|
|
25021
24831
|
},
|
|
25022
|
-
//
|
|
25023
|
-
// `<blockquote class="reddit-embed-bq">…<a href="post-url">`
|
|
25024
|
-
//
|
|
25025
|
-
//
|
|
25026
|
-
//
|
|
25027
|
-
//
|
|
25028
|
-
//
|
|
24832
|
+
// Pasted-from-the-platform embed markup lives in published blog posts as
|
|
24833
|
+
// `<blockquote class="reddit-embed-bq">…<a href="post-url">` (58 blocks
|
|
24834
|
+
// across 9 posts) — and Twitter's equivalent is
|
|
24835
|
+
// `<blockquote class="twitter-tweet">…<a href="status-url">`. Each pair
|
|
24836
|
+
// ships a `widgets.js` loader script, which `processShortcodes` strips
|
|
24837
|
+
// from the source text (Step 1.5). The composition rehydrates the
|
|
24838
|
+
// blockquote itself: extract the post URL from the first matching link
|
|
24839
|
+
// and render the platform's embed-client SSOT. Other blockquotes fall
|
|
24840
|
+
// through to the engine's base blockquote.
|
|
25029
24841
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
25030
24842
|
blockquote: (bqProps) => {
|
|
25031
24843
|
const { node, className } = bqProps;
|
|
@@ -25034,6 +24846,10 @@ function buildRichEmbedOverrides({
|
|
|
25034
24846
|
const postUrl = findFirstHref(node, /reddit\.com/);
|
|
25035
24847
|
if (postUrl) return /* @__PURE__ */ jsx169(RedditEmbedClient, { url: postUrl });
|
|
25036
24848
|
}
|
|
24849
|
+
if (classNames.includes("twitter-tweet")) {
|
|
24850
|
+
const tweetUrl = findFirstHref(node, /(?:twitter\.com|x\.com)\/[^/]+\/status\//);
|
|
24851
|
+
if (tweetUrl) return /* @__PURE__ */ jsx169(TwitterEmbedClient, { url: tweetUrl });
|
|
24852
|
+
}
|
|
25037
24853
|
return standard.blockquote(bqProps);
|
|
25038
24854
|
},
|
|
25039
24855
|
// In-article images: MarkdownImage reads `transformImageSrc` from the
|
|
@@ -25120,6 +24936,10 @@ var processShortcodes = (content) => {
|
|
|
25120
24936
|
codeBlocks.push(match2);
|
|
25121
24937
|
return placeholder;
|
|
25122
24938
|
});
|
|
24939
|
+
processedContent = processedContent.replace(
|
|
24940
|
+
/<script\b[^>]{0,2000}>[\s\S]{0,20000}?<\/script\s{0,10}>/gi,
|
|
24941
|
+
""
|
|
24942
|
+
);
|
|
25123
24943
|
const markdownLinks = [];
|
|
25124
24944
|
processedContent = processedContent.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match2) => {
|
|
25125
24945
|
const placeholder = `__MARKDOWN_LINK_${markdownLinks.length}__`;
|
|
@@ -47303,7 +47123,8 @@ function FileUpload({
|
|
|
47303
47123
|
return;
|
|
47304
47124
|
}
|
|
47305
47125
|
try {
|
|
47306
|
-
|
|
47126
|
+
const picked = await pickFiles();
|
|
47127
|
+
if (picked.length > 0) handleFiles(picked);
|
|
47307
47128
|
} catch (err) {
|
|
47308
47129
|
setValidationError(err instanceof Error ? err.message : "Could not open the file picker");
|
|
47309
47130
|
}
|
|
@@ -62267,4 +62088,4 @@ export {
|
|
|
62267
62088
|
LogsList,
|
|
62268
62089
|
assets
|
|
62269
62090
|
};
|
|
62270
|
-
//# sourceMappingURL=chunk-
|
|
62091
|
+
//# sourceMappingURL=chunk-GBWS62LR.js.map
|