@mieweb/ui 0.6.1-dev.148 → 0.6.1-dev.150
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/brands/index.cjs +22 -22
- package/dist/brands/index.js +5 -5
- package/dist/chunk-2T4JU5RH.cjs +1156 -0
- package/dist/chunk-2T4JU5RH.cjs.map +1 -0
- package/dist/chunk-3SSXDWD7.js +363 -0
- package/dist/chunk-3SSXDWD7.js.map +1 -0
- package/dist/{chunk-MARLXJQO.cjs → chunk-6R2ZPDN7.cjs} +7 -7
- package/dist/{chunk-MARLXJQO.cjs.map → chunk-6R2ZPDN7.cjs.map} +1 -1
- package/dist/{chunk-WHUD3XHR.cjs → chunk-7PA26KBF.cjs} +15 -3
- package/dist/chunk-7PA26KBF.cjs.map +1 -0
- package/dist/chunk-ASLZUFH4.js +1967 -0
- package/dist/chunk-ASLZUFH4.js.map +1 -0
- package/dist/chunk-FADQVM4M.cjs +2017 -0
- package/dist/chunk-FADQVM4M.cjs.map +1 -0
- package/dist/{chunk-DFT7TYKL.cjs → chunk-H4T5T65N.cjs} +6 -3
- package/dist/chunk-H4T5T65N.cjs.map +1 -0
- package/dist/chunk-I6CY5C6A.js +12 -0
- package/dist/chunk-I6CY5C6A.js.map +1 -0
- package/dist/chunk-JFLC7SHM.cjs +35 -0
- package/dist/chunk-JFLC7SHM.cjs.map +1 -0
- package/dist/chunk-LZPPH5BW.cjs +368 -0
- package/dist/chunk-LZPPH5BW.cjs.map +1 -0
- package/dist/{chunk-3OHVUXDG.js → chunk-M7BLVBL4.js} +6 -3
- package/dist/chunk-M7BLVBL4.js.map +1 -0
- package/dist/chunk-PM2I3QKM.cjs +1419 -0
- package/dist/chunk-PM2I3QKM.cjs.map +1 -0
- package/dist/{chunk-TW6DXMSD.js → chunk-R6PBBPU3.js} +2 -2
- package/dist/{chunk-TW6DXMSD.js.map → chunk-R6PBBPU3.js.map} +1 -1
- package/dist/{chunk-33PO3J4O.js → chunk-RXY5SD3O.js} +15 -3
- package/dist/chunk-RXY5SD3O.js.map +1 -0
- package/dist/{chunk-AEGYWRSL.js → chunk-TXYTMU3K.js} +3 -3
- package/dist/{chunk-AEGYWRSL.js.map → chunk-TXYTMU3K.js.map} +1 -1
- package/dist/chunk-UHPQYBXQ.js +1124 -0
- package/dist/chunk-UHPQYBXQ.js.map +1 -0
- package/dist/chunk-XQE26F3G.js +1383 -0
- package/dist/chunk-XQE26F3G.js.map +1 -0
- package/dist/{chunk-26YNFCOC.cjs → chunk-Z6NRP4Z5.cjs} +2 -2
- package/dist/{chunk-26YNFCOC.cjs.map → chunk-Z6NRP4Z5.cjs.map} +1 -1
- package/dist/components/Dropdown/index.cjs +7 -7
- package/dist/components/Dropdown/index.d.cts +1 -1
- package/dist/components/Dropdown/index.d.ts +1 -1
- package/dist/components/Dropdown/index.js +1 -1
- package/dist/components/RichTextEditor/index.cjs +5 -5
- package/dist/components/RichTextEditor/index.js +2 -2
- package/dist/components/SuperChat/index.cjs +1319 -0
- package/dist/components/SuperChat/index.cjs.map +1 -0
- package/dist/components/SuperChat/index.d.cts +189 -0
- package/dist/components/SuperChat/index.d.ts +189 -0
- package/dist/components/SuperChat/index.js +1282 -0
- package/dist/components/SuperChat/index.js.map +1 -0
- package/dist/components/SuperChat/plugins/index.cjs +1221 -0
- package/dist/components/SuperChat/plugins/index.cjs.map +1 -0
- package/dist/components/SuperChat/plugins/index.d.cts +253 -0
- package/dist/components/SuperChat/plugins/index.d.ts +253 -0
- package/dist/components/SuperChat/plugins/index.js +1181 -0
- package/dist/components/SuperChat/plugins/index.js.map +1 -0
- package/dist/datavis.cjs +18 -362
- package/dist/datavis.cjs.map +1 -1
- package/dist/datavis.js +1 -361
- package/dist/datavis.js.map +1 -1
- package/dist/index.cjs +1297 -5412
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -240
- package/dist/index.d.ts +44 -240
- package/dist/index.js +759 -5037
- package/dist/index.js.map +1 -1
- package/dist/nitroTableGrid-FWRCDE4N.js +22 -0
- package/dist/nitroTableGrid-FWRCDE4N.js.map +1 -0
- package/dist/nitroTableGrid-IY75TQJ2.cjs +44 -0
- package/dist/nitroTableGrid-IY75TQJ2.cjs.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/tailwind-preset.cjs +4 -4
- package/dist/tailwind-preset.js +1 -1
- package/dist/types-BFFgW6qy.d.ts +240 -0
- package/dist/types-BzeY_kYO.d.cts +242 -0
- package/dist/types-BzeY_kYO.d.ts +242 -0
- package/dist/types-CRt5IPNL.d.cts +240 -0
- package/package.json +41 -4
- package/dist/chunk-33PO3J4O.js.map +0 -1
- package/dist/chunk-3OHVUXDG.js.map +0 -1
- package/dist/chunk-DFT7TYKL.cjs.map +0 -1
- package/dist/chunk-WHUD3XHR.cjs.map +0 -1
|
@@ -0,0 +1,1221 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkJFLC7SHM_cjs = require('../../../chunk-JFLC7SHM.cjs');
|
|
4
|
+
var chunkFADQVM4M_cjs = require('../../../chunk-FADQVM4M.cjs');
|
|
5
|
+
require('../../../chunk-2T4JU5RH.cjs');
|
|
6
|
+
var chunkOR5DRJCW_cjs = require('../../../chunk-OR5DRJCW.cjs');
|
|
7
|
+
var React2 = require('react');
|
|
8
|
+
var rehypeHighlight = require('rehype-highlight');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
|
+
var rehypeKatex = require('rehype-katex');
|
|
11
|
+
var remarkMath = require('remark-math');
|
|
12
|
+
var reactDom = require('react-dom');
|
|
13
|
+
|
|
14
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
+
|
|
16
|
+
function _interopNamespace(e) {
|
|
17
|
+
if (e && e.__esModule) return e;
|
|
18
|
+
var n = Object.create(null);
|
|
19
|
+
if (e) {
|
|
20
|
+
Object.keys(e).forEach(function (k) {
|
|
21
|
+
if (k !== 'default') {
|
|
22
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
23
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return e[k]; }
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
n.default = e;
|
|
31
|
+
return Object.freeze(n);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var React2__namespace = /*#__PURE__*/_interopNamespace(React2);
|
|
35
|
+
var rehypeHighlight__default = /*#__PURE__*/_interopDefault(rehypeHighlight);
|
|
36
|
+
var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
|
|
37
|
+
var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
|
|
38
|
+
|
|
39
|
+
function CopyablePre({
|
|
40
|
+
node: _node,
|
|
41
|
+
...props
|
|
42
|
+
}) {
|
|
43
|
+
const ref = React2__namespace.useRef(null);
|
|
44
|
+
const [copied, setCopied] = React2__namespace.useState(false);
|
|
45
|
+
const onCopy = React2__namespace.useCallback(() => {
|
|
46
|
+
const text = ref.current?.innerText ?? "";
|
|
47
|
+
if (!text) return;
|
|
48
|
+
const copy = navigator.clipboard?.writeText(text);
|
|
49
|
+
if (!copy) return;
|
|
50
|
+
void copy.then(
|
|
51
|
+
() => {
|
|
52
|
+
setCopied(true);
|
|
53
|
+
window.setTimeout(() => setCopied(false), 1500);
|
|
54
|
+
},
|
|
55
|
+
() => {
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
}, []);
|
|
59
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "superchat-code", className: "group relative my-2", children: [
|
|
60
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
61
|
+
"button",
|
|
62
|
+
{
|
|
63
|
+
type: "button",
|
|
64
|
+
onClick: onCopy,
|
|
65
|
+
"aria-label": copied ? "Copied" : "Copy code",
|
|
66
|
+
className: "absolute top-2 right-2 rounded-md bg-neutral-700/80 px-2 py-1 text-xs text-neutral-100 opacity-0 transition-opacity group-hover:opacity-100 hover:bg-neutral-600 focus-visible:opacity-100",
|
|
67
|
+
children: copied ? "Copied" : "Copy"
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
71
|
+
"pre",
|
|
72
|
+
{
|
|
73
|
+
...props,
|
|
74
|
+
ref,
|
|
75
|
+
className: chunkOR5DRJCW_cjs.cn(
|
|
76
|
+
"overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
|
|
77
|
+
props.className
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
function createCodePlugin() {
|
|
84
|
+
return {
|
|
85
|
+
name: "code",
|
|
86
|
+
// `detect: false` + ignoreMissing keeps it predictable for streamed output.
|
|
87
|
+
rehypePlugins: [[rehypeHighlight__default.default, { detect: false, ignoreMissing: true }]],
|
|
88
|
+
components: {
|
|
89
|
+
pre: CopyablePre
|
|
90
|
+
},
|
|
91
|
+
// `.hljs-*` token classes are already permitted by the base schema's
|
|
92
|
+
// broadened `className` allow-list on code/pre/span.
|
|
93
|
+
sanitizeSchema: {
|
|
94
|
+
attributes: {
|
|
95
|
+
code: ["className"],
|
|
96
|
+
span: ["className"]
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
var KATEX_TAGS = [
|
|
102
|
+
"span",
|
|
103
|
+
"svg",
|
|
104
|
+
"path",
|
|
105
|
+
"line",
|
|
106
|
+
"math",
|
|
107
|
+
"semantics",
|
|
108
|
+
"annotation",
|
|
109
|
+
"mrow",
|
|
110
|
+
"mi",
|
|
111
|
+
"mo",
|
|
112
|
+
"mn",
|
|
113
|
+
"ms",
|
|
114
|
+
"mtext",
|
|
115
|
+
"msup",
|
|
116
|
+
"msub",
|
|
117
|
+
"msubsup",
|
|
118
|
+
"mfrac",
|
|
119
|
+
"msqrt",
|
|
120
|
+
"mroot",
|
|
121
|
+
"mover",
|
|
122
|
+
"munder",
|
|
123
|
+
"munderover",
|
|
124
|
+
"mtable",
|
|
125
|
+
"mtr",
|
|
126
|
+
"mtd",
|
|
127
|
+
"mspace",
|
|
128
|
+
"mpadded",
|
|
129
|
+
"mphantom",
|
|
130
|
+
"menclose",
|
|
131
|
+
"mstyle"
|
|
132
|
+
];
|
|
133
|
+
function createMathPlugin() {
|
|
134
|
+
return {
|
|
135
|
+
name: "math",
|
|
136
|
+
remarkPlugins: [remarkMath__default.default],
|
|
137
|
+
// `output: 'htmlAndMathml'` (KaTeX default) gives accessible MathML too.
|
|
138
|
+
rehypePlugins: [[rehypeKatex__default.default, { throwOnError: false }]],
|
|
139
|
+
sanitizeSchema: {
|
|
140
|
+
tagNames: KATEX_TAGS,
|
|
141
|
+
attributes: {
|
|
142
|
+
"*": ["className"],
|
|
143
|
+
span: ["className", "style", "ariaHidden"],
|
|
144
|
+
svg: [
|
|
145
|
+
"xmlns",
|
|
146
|
+
"width",
|
|
147
|
+
"height",
|
|
148
|
+
"viewBox",
|
|
149
|
+
"preserveAspectRatio",
|
|
150
|
+
"style"
|
|
151
|
+
],
|
|
152
|
+
path: ["d"],
|
|
153
|
+
line: ["x1", "y1", "x2", "y2", "stroke", "strokeWidth"],
|
|
154
|
+
math: ["xmlns", "display"],
|
|
155
|
+
annotation: ["encoding"]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
var GENUI_TAG = "genui-widget";
|
|
161
|
+
function textOf(node) {
|
|
162
|
+
if (node.type === "text") return node.value ?? "";
|
|
163
|
+
return (node.children ?? []).map(textOf).join("");
|
|
164
|
+
}
|
|
165
|
+
function isGenuiPre(node) {
|
|
166
|
+
if (node.tagName !== "pre") return false;
|
|
167
|
+
const code = node.children?.find((c) => c.tagName === "code");
|
|
168
|
+
const className = code?.properties?.className;
|
|
169
|
+
const classes = Array.isArray(className) ? className : [className];
|
|
170
|
+
return classes.some(
|
|
171
|
+
(c) => typeof c === "string" && (c === "language-genui" || c === "genui")
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
function rehypeGenui() {
|
|
175
|
+
return (tree) => {
|
|
176
|
+
const walk = (node) => {
|
|
177
|
+
if (!node.children) return;
|
|
178
|
+
node.children = node.children.map((child) => {
|
|
179
|
+
if (isGenuiPre(child)) {
|
|
180
|
+
const code = child.children?.find((c) => c.tagName === "code");
|
|
181
|
+
const raw = code ? textOf(code) : "";
|
|
182
|
+
return {
|
|
183
|
+
type: "element",
|
|
184
|
+
tagName: GENUI_TAG,
|
|
185
|
+
properties: {},
|
|
186
|
+
children: [{ type: "text", value: raw }]
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
walk(child);
|
|
190
|
+
return child;
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
walk(tree);
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function PendingCard({ label }) {
|
|
197
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
198
|
+
"div",
|
|
199
|
+
{
|
|
200
|
+
"data-slot": "superchat-genui-pending",
|
|
201
|
+
className: "my-2 flex items-center gap-2 rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm text-neutral-600 dark:border-neutral-700 dark:bg-neutral-800/50 dark:text-neutral-300",
|
|
202
|
+
children: [
|
|
203
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
204
|
+
"span",
|
|
205
|
+
{
|
|
206
|
+
className: "h-3 w-3 animate-spin rounded-full border-2 border-neutral-400 border-t-transparent",
|
|
207
|
+
"aria-hidden": "true"
|
|
208
|
+
}
|
|
209
|
+
),
|
|
210
|
+
label
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
function InertFallback({ raw }) {
|
|
216
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
217
|
+
"pre",
|
|
218
|
+
{
|
|
219
|
+
"data-slot": "superchat-genui-fallback",
|
|
220
|
+
className: "my-2 overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
|
|
221
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: raw })
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
function ErrorCard({ message }) {
|
|
226
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
227
|
+
"div",
|
|
228
|
+
{
|
|
229
|
+
"data-slot": "superchat-genui-error",
|
|
230
|
+
role: "alert",
|
|
231
|
+
className: "my-2 rounded-lg border border-red-300 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-700 dark:bg-red-900/30 dark:text-red-300",
|
|
232
|
+
children: message
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
function parsePayload(raw) {
|
|
237
|
+
const trimmed = raw.trim();
|
|
238
|
+
if (!trimmed) return { ok: false };
|
|
239
|
+
try {
|
|
240
|
+
const value = JSON.parse(trimmed);
|
|
241
|
+
if (!value || typeof value.widget !== "string") return { ok: false };
|
|
242
|
+
return { ok: true, value };
|
|
243
|
+
} catch {
|
|
244
|
+
return { ok: false };
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async function validate(schema, data) {
|
|
248
|
+
if (!schema) return { ok: true, value: data };
|
|
249
|
+
const result = await schema["~standard"].validate(data);
|
|
250
|
+
if ("issues" in result && result.issues) {
|
|
251
|
+
return {
|
|
252
|
+
ok: false,
|
|
253
|
+
message: result.issues.map((i) => i.message).join("; ") || "Invalid widget payload"
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
return { ok: true, value: result.value };
|
|
257
|
+
}
|
|
258
|
+
function usePrefetchTrigger(policy, ref) {
|
|
259
|
+
const [ready, setReady] = React2__namespace.useState(policy === "eager");
|
|
260
|
+
React2__namespace.useEffect(() => {
|
|
261
|
+
if (ready) return;
|
|
262
|
+
if (policy === "idle") {
|
|
263
|
+
const requestIdle = window.requestIdleCallback;
|
|
264
|
+
const cancelIdle = window.cancelIdleCallback;
|
|
265
|
+
let idleId = null;
|
|
266
|
+
let timeoutId = null;
|
|
267
|
+
if (requestIdle) {
|
|
268
|
+
idleId = requestIdle(() => setReady(true));
|
|
269
|
+
} else {
|
|
270
|
+
timeoutId = window.setTimeout(() => setReady(true), 200);
|
|
271
|
+
}
|
|
272
|
+
return () => {
|
|
273
|
+
if (idleId !== null && cancelIdle) cancelIdle(idleId);
|
|
274
|
+
if (timeoutId !== null) window.clearTimeout(timeoutId);
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
const el = ref.current;
|
|
278
|
+
if (!el || typeof IntersectionObserver === "undefined") {
|
|
279
|
+
setReady(true);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const obs = new IntersectionObserver((entries) => {
|
|
283
|
+
if (entries.some((e) => e.isIntersecting)) {
|
|
284
|
+
setReady(true);
|
|
285
|
+
obs.disconnect();
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
obs.observe(el);
|
|
289
|
+
return () => obs.disconnect();
|
|
290
|
+
}, [policy, ready, ref]);
|
|
291
|
+
return ready;
|
|
292
|
+
}
|
|
293
|
+
function GenUIBlock({ raw, registry }) {
|
|
294
|
+
const { messageId, streaming } = chunkJFLC7SHM_cjs.useTextRenderContext();
|
|
295
|
+
const placeholderRef = React2__namespace.useRef(null);
|
|
296
|
+
const parsed = React2__namespace.useMemo(() => parsePayload(raw), [raw]);
|
|
297
|
+
const entry = parsed.ok ? registry[parsed.value.widget] : void 0;
|
|
298
|
+
const policy = entry?.prefetch ?? (parsed.ok ? parsed.value.prefetch : void 0) ?? "visible";
|
|
299
|
+
const codeReady = usePrefetchTrigger(policy, placeholderRef);
|
|
300
|
+
const [Loaded, setLoaded] = React2__namespace.useState(null);
|
|
301
|
+
const [validated, setValidated] = React2__namespace.useState(null);
|
|
302
|
+
React2__namespace.useEffect(() => {
|
|
303
|
+
if (!entry || !codeReady) return;
|
|
304
|
+
let active = true;
|
|
305
|
+
void entry.component().then((m) => {
|
|
306
|
+
if (active) setLoaded(() => m.default);
|
|
307
|
+
}).catch(() => {
|
|
308
|
+
if (active)
|
|
309
|
+
setValidated({ ok: false, message: "Failed to load widget" });
|
|
310
|
+
});
|
|
311
|
+
return () => {
|
|
312
|
+
active = false;
|
|
313
|
+
};
|
|
314
|
+
}, [entry, codeReady]);
|
|
315
|
+
React2__namespace.useEffect(() => {
|
|
316
|
+
if (!entry || !parsed.ok || streaming) return;
|
|
317
|
+
let active = true;
|
|
318
|
+
const props = parsed.value.props;
|
|
319
|
+
void (async () => {
|
|
320
|
+
const result = await validate(entry.schema, props);
|
|
321
|
+
if (!active) return;
|
|
322
|
+
if (result.ok && entry.prefetchData) {
|
|
323
|
+
try {
|
|
324
|
+
await entry.prefetchData(result.value);
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (active) setValidated(result);
|
|
329
|
+
})();
|
|
330
|
+
return () => {
|
|
331
|
+
active = false;
|
|
332
|
+
};
|
|
333
|
+
}, [entry, parsed, streaming]);
|
|
334
|
+
if (!parsed.ok) {
|
|
335
|
+
if (streaming) {
|
|
336
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: placeholderRef, children: /* @__PURE__ */ jsxRuntime.jsx(PendingCard, { label: "Preparing widget\u2026" }) });
|
|
337
|
+
}
|
|
338
|
+
return /* @__PURE__ */ jsxRuntime.jsx(InertFallback, { raw });
|
|
339
|
+
}
|
|
340
|
+
if (parsed.ok && !entry) return /* @__PURE__ */ jsxRuntime.jsx(InertFallback, { raw });
|
|
341
|
+
if (streaming || !Loaded || !validated) {
|
|
342
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: placeholderRef, children: /* @__PURE__ */ jsxRuntime.jsx(PendingCard, { label: "Preparing widget\u2026" }) });
|
|
343
|
+
}
|
|
344
|
+
if (!validated.ok) return /* @__PURE__ */ jsxRuntime.jsx(ErrorCard, { message: validated.message });
|
|
345
|
+
const meta = {
|
|
346
|
+
name: parsed.value.widget,
|
|
347
|
+
version: parsed.value.version,
|
|
348
|
+
messageId,
|
|
349
|
+
streaming
|
|
350
|
+
};
|
|
351
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Loaded, { data: validated.value, meta });
|
|
352
|
+
}
|
|
353
|
+
function createGenUIPlugin(registry) {
|
|
354
|
+
const GenUIWidgetComponent = (props) => {
|
|
355
|
+
const raw = React2__namespace.Children.toArray(props.children).filter((c) => typeof c === "string").join("");
|
|
356
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GenUIBlock, { raw, registry });
|
|
357
|
+
};
|
|
358
|
+
return {
|
|
359
|
+
name: "genui",
|
|
360
|
+
rehypePlugins: [rehypeGenui],
|
|
361
|
+
components: {
|
|
362
|
+
[GENUI_TAG]: GenUIWidgetComponent
|
|
363
|
+
},
|
|
364
|
+
sanitizeSchema: {
|
|
365
|
+
tagNames: [GENUI_TAG]
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
var MERMAID_TAG = "mermaid-diagram";
|
|
370
|
+
function textOf2(node) {
|
|
371
|
+
if (node.type === "text") return node.value ?? "";
|
|
372
|
+
return (node.children ?? []).map(textOf2).join("");
|
|
373
|
+
}
|
|
374
|
+
function isMermaidPre(node) {
|
|
375
|
+
if (node.tagName !== "pre") return false;
|
|
376
|
+
const code = node.children?.find((c) => c.tagName === "code");
|
|
377
|
+
const className = code?.properties?.className;
|
|
378
|
+
const classes = Array.isArray(className) ? className : [className];
|
|
379
|
+
return classes.some(
|
|
380
|
+
(c) => typeof c === "string" && (c === "language-mermaid" || c === "mermaid")
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
function rehypeMermaid() {
|
|
384
|
+
return (tree) => {
|
|
385
|
+
const walk = (node) => {
|
|
386
|
+
if (!node.children) return;
|
|
387
|
+
node.children = node.children.map((child) => {
|
|
388
|
+
if (isMermaidPre(child)) {
|
|
389
|
+
const code = child.children?.find((c) => c.tagName === "code");
|
|
390
|
+
const raw = code ? textOf2(code) : "";
|
|
391
|
+
return {
|
|
392
|
+
type: "element",
|
|
393
|
+
tagName: MERMAID_TAG,
|
|
394
|
+
properties: {},
|
|
395
|
+
children: [{ type: "text", value: raw }]
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
walk(child);
|
|
399
|
+
return child;
|
|
400
|
+
});
|
|
401
|
+
};
|
|
402
|
+
walk(tree);
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
function PendingCard2({ label }) {
|
|
406
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
407
|
+
"div",
|
|
408
|
+
{
|
|
409
|
+
"data-slot": "superchat-mermaid-pending",
|
|
410
|
+
className: "my-2 flex items-center gap-2 rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2 text-sm text-neutral-600 dark:border-neutral-700 dark:bg-neutral-800/50 dark:text-neutral-300",
|
|
411
|
+
children: [
|
|
412
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
413
|
+
"span",
|
|
414
|
+
{
|
|
415
|
+
className: "h-3 w-3 animate-spin rounded-full border-2 border-neutral-400 border-t-transparent",
|
|
416
|
+
"aria-hidden": "true"
|
|
417
|
+
}
|
|
418
|
+
),
|
|
419
|
+
label
|
|
420
|
+
]
|
|
421
|
+
}
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
function InertFallback2({ raw }) {
|
|
425
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
426
|
+
"pre",
|
|
427
|
+
{
|
|
428
|
+
"data-slot": "superchat-mermaid-fallback",
|
|
429
|
+
className: "my-2 overflow-x-auto rounded-lg bg-neutral-900 p-3 text-sm text-neutral-100 dark:bg-neutral-950",
|
|
430
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: raw })
|
|
431
|
+
}
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
var mermaidReady = null;
|
|
435
|
+
var mermaidTheme = null;
|
|
436
|
+
function loadMermaid(dark) {
|
|
437
|
+
const theme = dark ? "dark" : "default";
|
|
438
|
+
if (!mermaidReady || mermaidTheme !== theme) {
|
|
439
|
+
mermaidReady = (mermaidReady ?? import('mermaid').then(({ default: mermaid }) => mermaid)).then((mermaid) => {
|
|
440
|
+
mermaidTheme = theme;
|
|
441
|
+
mermaid.initialize({
|
|
442
|
+
startOnLoad: false,
|
|
443
|
+
securityLevel: "strict",
|
|
444
|
+
theme
|
|
445
|
+
});
|
|
446
|
+
return mermaid;
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return mermaidReady;
|
|
450
|
+
}
|
|
451
|
+
var mermaidSeq = 0;
|
|
452
|
+
function MermaidDiagram({ code }) {
|
|
453
|
+
const { streaming } = chunkJFLC7SHM_cjs.useTextRenderContext();
|
|
454
|
+
const [svg, setSvg] = React2__namespace.useState(null);
|
|
455
|
+
const [failed, setFailed] = React2__namespace.useState(false);
|
|
456
|
+
const idRef = React2__namespace.useRef(`superchat-mermaid-${mermaidSeq += 1}`);
|
|
457
|
+
const source = code.trim();
|
|
458
|
+
React2__namespace.useEffect(() => {
|
|
459
|
+
if (streaming || !source) return;
|
|
460
|
+
let active = true;
|
|
461
|
+
setSvg(null);
|
|
462
|
+
setFailed(false);
|
|
463
|
+
const dark = typeof document !== "undefined" && document.documentElement.classList.contains("dark");
|
|
464
|
+
void loadMermaid(dark).then((mermaid) => mermaid.render(idRef.current, source)).then(({ svg: rendered }) => {
|
|
465
|
+
if (active) setSvg(rendered);
|
|
466
|
+
}).catch(() => {
|
|
467
|
+
if (active) setFailed(true);
|
|
468
|
+
});
|
|
469
|
+
return () => {
|
|
470
|
+
active = false;
|
|
471
|
+
};
|
|
472
|
+
}, [source, streaming]);
|
|
473
|
+
if (!source && !streaming) return /* @__PURE__ */ jsxRuntime.jsx(InertFallback2, { raw: code });
|
|
474
|
+
if (failed) return /* @__PURE__ */ jsxRuntime.jsx(InertFallback2, { raw: code });
|
|
475
|
+
if (streaming || svg === null) {
|
|
476
|
+
return /* @__PURE__ */ jsxRuntime.jsx(PendingCard2, { label: "Rendering diagram\u2026" });
|
|
477
|
+
}
|
|
478
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
479
|
+
"div",
|
|
480
|
+
{
|
|
481
|
+
"data-slot": "superchat-mermaid",
|
|
482
|
+
className: "my-2 overflow-x-auto",
|
|
483
|
+
dangerouslySetInnerHTML: { __html: svg }
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
function createMermaidPlugin() {
|
|
488
|
+
const MermaidComponent = (props) => {
|
|
489
|
+
const raw = React2__namespace.Children.toArray(props.children).filter((c) => typeof c === "string").join("");
|
|
490
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MermaidDiagram, { code: raw });
|
|
491
|
+
};
|
|
492
|
+
return {
|
|
493
|
+
name: "mermaid",
|
|
494
|
+
rehypePlugins: [rehypeMermaid],
|
|
495
|
+
components: {
|
|
496
|
+
[MERMAID_TAG]: MermaidComponent
|
|
497
|
+
},
|
|
498
|
+
sanitizeSchema: {
|
|
499
|
+
tagNames: [MERMAID_TAG]
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
function filenameFromUrl(url, alt) {
|
|
504
|
+
if (alt && alt.trim()) return alt.trim();
|
|
505
|
+
try {
|
|
506
|
+
const path = new URL(url, "http://localhost").pathname;
|
|
507
|
+
const last = path.split("/").filter(Boolean).pop();
|
|
508
|
+
return last || "image";
|
|
509
|
+
} catch {
|
|
510
|
+
return "image";
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function ZoomableImage({
|
|
514
|
+
node: _node,
|
|
515
|
+
...props
|
|
516
|
+
}) {
|
|
517
|
+
const [open, setOpen] = React2__namespace.useState(false);
|
|
518
|
+
const src = typeof props.src === "string" ? props.src : "";
|
|
519
|
+
const alt = typeof props.alt === "string" ? props.alt : "";
|
|
520
|
+
const attachment = React2__namespace.useMemo(() => {
|
|
521
|
+
if (!src) return null;
|
|
522
|
+
return {
|
|
523
|
+
id: src,
|
|
524
|
+
type: "image",
|
|
525
|
+
url: src,
|
|
526
|
+
filename: filenameFromUrl(src, alt),
|
|
527
|
+
size: 0,
|
|
528
|
+
mimeType: "image/*",
|
|
529
|
+
state: "uploaded",
|
|
530
|
+
alt
|
|
531
|
+
};
|
|
532
|
+
}, [src, alt]);
|
|
533
|
+
if (!src) return null;
|
|
534
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
535
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
536
|
+
"button",
|
|
537
|
+
{
|
|
538
|
+
type: "button",
|
|
539
|
+
onClick: () => setOpen(true),
|
|
540
|
+
"aria-label": alt ? `View image: ${alt}` : "View image",
|
|
541
|
+
className: "focus-visible:ring-primary-500 my-2 inline-block cursor-zoom-in rounded-lg focus-visible:ring-2 focus-visible:outline-none",
|
|
542
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
543
|
+
"img",
|
|
544
|
+
{
|
|
545
|
+
...props,
|
|
546
|
+
alt,
|
|
547
|
+
className: chunkOR5DRJCW_cjs.cn(
|
|
548
|
+
"max-h-80 max-w-full rounded-lg object-contain",
|
|
549
|
+
props.className
|
|
550
|
+
)
|
|
551
|
+
}
|
|
552
|
+
)
|
|
553
|
+
}
|
|
554
|
+
),
|
|
555
|
+
open && typeof document !== "undefined" && reactDom.createPortal(
|
|
556
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
557
|
+
chunkFADQVM4M_cjs.LightboxModal,
|
|
558
|
+
{
|
|
559
|
+
attachment,
|
|
560
|
+
onClose: () => setOpen(false)
|
|
561
|
+
}
|
|
562
|
+
),
|
|
563
|
+
document.body
|
|
564
|
+
)
|
|
565
|
+
] });
|
|
566
|
+
}
|
|
567
|
+
function createImagePlugin() {
|
|
568
|
+
return {
|
|
569
|
+
name: "image",
|
|
570
|
+
components: {
|
|
571
|
+
img: ZoomableImage
|
|
572
|
+
},
|
|
573
|
+
// Allow inline (`data:`) and object-URL (`blob:`) image sources in addition
|
|
574
|
+
// to the default http/https, so pasted/attached images render. These are
|
|
575
|
+
// safe for `<img>` (scripts in SVG loaded via `src` do not execute).
|
|
576
|
+
sanitizeSchema: {
|
|
577
|
+
protocols: { src: ["data", "blob"] }
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
var NitroTableGrid = React2__namespace.lazy(() => import('../../../nitroTableGrid-IY75TQJ2.cjs'));
|
|
582
|
+
function textOf3(node) {
|
|
583
|
+
if (node.type === "text") return node.value ?? "";
|
|
584
|
+
return (node.children ?? []).map(textOf3).join("");
|
|
585
|
+
}
|
|
586
|
+
function rowsOf(parent) {
|
|
587
|
+
return (parent?.children ?? []).filter((c) => c.tagName === "tr");
|
|
588
|
+
}
|
|
589
|
+
function cellsOf(row, tag) {
|
|
590
|
+
return (row.children ?? []).filter((c) => c.tagName === tag);
|
|
591
|
+
}
|
|
592
|
+
function parseTable(node) {
|
|
593
|
+
if (!node || node.tagName !== "table") return null;
|
|
594
|
+
const thead = node.children?.find((c) => c.tagName === "thead");
|
|
595
|
+
const tbody = node.children?.find((c) => c.tagName === "tbody");
|
|
596
|
+
const headerRow = rowsOf(thead)[0];
|
|
597
|
+
if (!headerRow) return null;
|
|
598
|
+
const headers = cellsOf(headerRow, "th").map((c) => textOf3(c).trim());
|
|
599
|
+
if (headers.length === 0) return null;
|
|
600
|
+
const seen = /* @__PURE__ */ new Map();
|
|
601
|
+
const keys = headers.map((h) => {
|
|
602
|
+
const base = h || "column";
|
|
603
|
+
const count = seen.get(base) ?? 0;
|
|
604
|
+
seen.set(base, count + 1);
|
|
605
|
+
return count === 0 ? base : `${base} (${count + 1})`;
|
|
606
|
+
});
|
|
607
|
+
const rows = rowsOf(tbody).map((tr) => {
|
|
608
|
+
const cells = cellsOf(tr, "td");
|
|
609
|
+
const row = {};
|
|
610
|
+
keys.forEach((key, i) => {
|
|
611
|
+
row[key] = cells[i] ? textOf3(cells[i]).trim() : "";
|
|
612
|
+
});
|
|
613
|
+
return row;
|
|
614
|
+
});
|
|
615
|
+
return { headers: keys, rows };
|
|
616
|
+
}
|
|
617
|
+
function HtmlTable({
|
|
618
|
+
node: _node,
|
|
619
|
+
...props
|
|
620
|
+
}) {
|
|
621
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "my-2 overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
622
|
+
"table",
|
|
623
|
+
{
|
|
624
|
+
...props,
|
|
625
|
+
className: chunkOR5DRJCW_cjs.cn(
|
|
626
|
+
"w-full border-collapse text-sm [&_td]:border [&_td]:border-neutral-200 [&_td]:px-2 [&_td]:py-1 dark:[&_td]:border-neutral-700 [&_th]:border [&_th]:border-neutral-200 [&_th]:px-2 [&_th]:py-1 [&_th]:text-left dark:[&_th]:border-neutral-700",
|
|
627
|
+
props.className
|
|
628
|
+
)
|
|
629
|
+
}
|
|
630
|
+
) });
|
|
631
|
+
}
|
|
632
|
+
var GridErrorBoundary = class extends React2__namespace.Component {
|
|
633
|
+
state = { failed: false };
|
|
634
|
+
static getDerivedStateFromError() {
|
|
635
|
+
return { failed: true };
|
|
636
|
+
}
|
|
637
|
+
render() {
|
|
638
|
+
if (this.state.failed) return this.props.fallback;
|
|
639
|
+
return this.props.children;
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
function createNitroTablePlugin() {
|
|
643
|
+
const NitroTable = (props) => {
|
|
644
|
+
const node = props.node;
|
|
645
|
+
const fallback = /* @__PURE__ */ jsxRuntime.jsx(
|
|
646
|
+
HtmlTable,
|
|
647
|
+
{
|
|
648
|
+
...props
|
|
649
|
+
}
|
|
650
|
+
);
|
|
651
|
+
const parsed = React2__namespace.useMemo(() => parseTable(node), [node]);
|
|
652
|
+
if (!parsed) return fallback;
|
|
653
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GridErrorBoundary, { fallback, children: /* @__PURE__ */ jsxRuntime.jsx(React2__namespace.Suspense, { fallback, children: /* @__PURE__ */ jsxRuntime.jsx(NitroTableGrid, { headers: parsed.headers, rows: parsed.rows }) }) });
|
|
654
|
+
};
|
|
655
|
+
return {
|
|
656
|
+
name: "nitro-table",
|
|
657
|
+
components: {
|
|
658
|
+
table: NitroTable
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/components/SuperChat/render/attachmentCache.ts
|
|
664
|
+
var DB_NAME = "mieweb-superchat";
|
|
665
|
+
var STORE = "attachments";
|
|
666
|
+
var META_STORE = "attachments_meta";
|
|
667
|
+
var DB_VERSION = 2;
|
|
668
|
+
var DEFAULT_MAX_BYTES = 100 * 1024 * 1024;
|
|
669
|
+
var maxBytes = DEFAULT_MAX_BYTES;
|
|
670
|
+
function hasIndexedDB() {
|
|
671
|
+
return typeof window !== "undefined" && !!window.indexedDB;
|
|
672
|
+
}
|
|
673
|
+
function openDB() {
|
|
674
|
+
if (!hasIndexedDB()) return Promise.resolve(null);
|
|
675
|
+
return new Promise((resolve) => {
|
|
676
|
+
let req;
|
|
677
|
+
try {
|
|
678
|
+
req = window.indexedDB.open(DB_NAME, DB_VERSION);
|
|
679
|
+
} catch {
|
|
680
|
+
resolve(null);
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
req.onupgradeneeded = () => {
|
|
684
|
+
const db = req.result;
|
|
685
|
+
if (!db.objectStoreNames.contains(STORE)) {
|
|
686
|
+
db.createObjectStore(STORE, { keyPath: "id" });
|
|
687
|
+
}
|
|
688
|
+
if (!db.objectStoreNames.contains(META_STORE)) {
|
|
689
|
+
db.createObjectStore(META_STORE, { keyPath: "id" });
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
req.onsuccess = () => resolve(req.result);
|
|
693
|
+
req.onerror = () => resolve(null);
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
function tx(db, mode) {
|
|
697
|
+
return db.transaction(STORE, mode).objectStore(STORE);
|
|
698
|
+
}
|
|
699
|
+
function readAllMeta(db) {
|
|
700
|
+
return new Promise((resolve) => {
|
|
701
|
+
try {
|
|
702
|
+
const req = db.transaction(META_STORE, "readonly").objectStore(META_STORE).getAll();
|
|
703
|
+
req.onsuccess = () => resolve(req.result ?? []);
|
|
704
|
+
req.onerror = () => resolve([]);
|
|
705
|
+
} catch {
|
|
706
|
+
resolve([]);
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
async function touch(id) {
|
|
711
|
+
const db = await openDB();
|
|
712
|
+
if (!db) return;
|
|
713
|
+
await new Promise((resolve) => {
|
|
714
|
+
try {
|
|
715
|
+
const store = db.transaction(META_STORE, "readwrite").objectStore(META_STORE);
|
|
716
|
+
const getReq = store.get(id);
|
|
717
|
+
getReq.onsuccess = () => {
|
|
718
|
+
const meta = getReq.result;
|
|
719
|
+
if (meta) {
|
|
720
|
+
meta.lastAccessed = Date.now();
|
|
721
|
+
store.put(meta);
|
|
722
|
+
}
|
|
723
|
+
resolve();
|
|
724
|
+
};
|
|
725
|
+
getReq.onerror = () => resolve();
|
|
726
|
+
} catch {
|
|
727
|
+
resolve();
|
|
728
|
+
} finally {
|
|
729
|
+
db.close();
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
async function prune() {
|
|
734
|
+
const db = await openDB();
|
|
735
|
+
if (!db) return;
|
|
736
|
+
try {
|
|
737
|
+
const metas = await readAllMeta(db);
|
|
738
|
+
let total = metas.reduce((sum, m) => sum + (m.size || 0), 0);
|
|
739
|
+
if (total <= maxBytes) return;
|
|
740
|
+
const byAge = metas.slice().sort((a, b) => (a.lastAccessed || 0) - (b.lastAccessed || 0));
|
|
741
|
+
const victims = [];
|
|
742
|
+
for (const meta of byAge) {
|
|
743
|
+
if (total <= maxBytes) break;
|
|
744
|
+
if (metas.length - victims.length <= 1) break;
|
|
745
|
+
victims.push(meta.id);
|
|
746
|
+
total -= meta.size || 0;
|
|
747
|
+
}
|
|
748
|
+
if (!victims.length) return;
|
|
749
|
+
await new Promise((resolve) => {
|
|
750
|
+
try {
|
|
751
|
+
const t = db.transaction([STORE, META_STORE], "readwrite");
|
|
752
|
+
const blobs = t.objectStore(STORE);
|
|
753
|
+
const meta = t.objectStore(META_STORE);
|
|
754
|
+
for (const id of victims) {
|
|
755
|
+
blobs.delete(id);
|
|
756
|
+
meta.delete(id);
|
|
757
|
+
}
|
|
758
|
+
t.oncomplete = () => resolve();
|
|
759
|
+
t.onerror = () => resolve();
|
|
760
|
+
} catch {
|
|
761
|
+
resolve();
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
} finally {
|
|
765
|
+
db.close();
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
function dataUrlToBlob(dataUrl) {
|
|
769
|
+
const match = /^data:([^;,]*)(;base64)?,([\s\S]*)$/.exec(dataUrl);
|
|
770
|
+
if (!match) return null;
|
|
771
|
+
const mime = match[1] || "application/octet-stream";
|
|
772
|
+
const isBase64 = Boolean(match[2]);
|
|
773
|
+
const data = match[3];
|
|
774
|
+
try {
|
|
775
|
+
if (isBase64) {
|
|
776
|
+
const binary = window.atob(data);
|
|
777
|
+
const bytes = new Uint8Array(binary.length);
|
|
778
|
+
for (let i = 0; i < binary.length; i += 1) {
|
|
779
|
+
bytes[i] = binary.charCodeAt(i);
|
|
780
|
+
}
|
|
781
|
+
return new window.Blob([bytes], { type: mime });
|
|
782
|
+
}
|
|
783
|
+
return new window.Blob([decodeURIComponent(data)], { type: mime });
|
|
784
|
+
} catch {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
var attachmentCache = {
|
|
789
|
+
/** Whether a persistent IndexedDB store is available in this environment. */
|
|
790
|
+
isAvailable: hasIndexedDB,
|
|
791
|
+
/**
|
|
792
|
+
* Tune the cache. `maxBytes` is the eviction budget (default 100 MB); when a
|
|
793
|
+
* `put` pushes the total past it, least-recently-used entries are dropped
|
|
794
|
+
* until it fits. Set `Infinity` to disable eviction.
|
|
795
|
+
*/
|
|
796
|
+
configure(options) {
|
|
797
|
+
if (typeof options.maxBytes === "number" && options.maxBytes >= 0) {
|
|
798
|
+
maxBytes = options.maxBytes;
|
|
799
|
+
}
|
|
800
|
+
},
|
|
801
|
+
/** Total bytes currently held by the cache (0 when unavailable). */
|
|
802
|
+
async usage() {
|
|
803
|
+
const db = await openDB();
|
|
804
|
+
if (!db) return 0;
|
|
805
|
+
try {
|
|
806
|
+
const metas = await readAllMeta(db);
|
|
807
|
+
return metas.reduce((sum, m) => sum + (m.size || 0), 0);
|
|
808
|
+
} finally {
|
|
809
|
+
db.close();
|
|
810
|
+
}
|
|
811
|
+
},
|
|
812
|
+
/**
|
|
813
|
+
* Persist an attachment's bytes by id. Pass a `blob` or a `dataUrl`. Resolves
|
|
814
|
+
* to `true` when stored, `false` if unavailable or the input was unusable.
|
|
815
|
+
* Writing past the configured `maxBytes` evicts least-recently-used entries.
|
|
816
|
+
*/
|
|
817
|
+
async put(input) {
|
|
818
|
+
const db = await openDB();
|
|
819
|
+
if (!db) return false;
|
|
820
|
+
const blob = input.blob ?? (input.dataUrl ? dataUrlToBlob(input.dataUrl) : null);
|
|
821
|
+
if (!blob) {
|
|
822
|
+
db.close();
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
const now = Date.now();
|
|
826
|
+
const entry = {
|
|
827
|
+
id: input.id,
|
|
828
|
+
name: input.name,
|
|
829
|
+
type: input.type || blob.type || "application/octet-stream",
|
|
830
|
+
blob,
|
|
831
|
+
size: blob.size,
|
|
832
|
+
cachedAt: now,
|
|
833
|
+
lastAccessed: now
|
|
834
|
+
};
|
|
835
|
+
const stored = await new Promise((resolve) => {
|
|
836
|
+
try {
|
|
837
|
+
const t = db.transaction([STORE, META_STORE], "readwrite");
|
|
838
|
+
t.objectStore(STORE).put(entry);
|
|
839
|
+
t.objectStore(META_STORE).put({
|
|
840
|
+
id: entry.id,
|
|
841
|
+
size: entry.size,
|
|
842
|
+
lastAccessed: now
|
|
843
|
+
});
|
|
844
|
+
t.oncomplete = () => resolve(true);
|
|
845
|
+
t.onerror = () => resolve(false);
|
|
846
|
+
} catch {
|
|
847
|
+
resolve(false);
|
|
848
|
+
} finally {
|
|
849
|
+
db.close();
|
|
850
|
+
}
|
|
851
|
+
});
|
|
852
|
+
if (stored) await prune();
|
|
853
|
+
return stored;
|
|
854
|
+
},
|
|
855
|
+
/** Read a cached attachment (blob + metadata) by id, or `undefined`. */
|
|
856
|
+
async get(id) {
|
|
857
|
+
const db = await openDB();
|
|
858
|
+
if (!db) return void 0;
|
|
859
|
+
const entry = await new Promise((resolve) => {
|
|
860
|
+
try {
|
|
861
|
+
const req = tx(db, "readonly").get(id);
|
|
862
|
+
req.onsuccess = () => resolve(req.result ?? void 0);
|
|
863
|
+
req.onerror = () => resolve(void 0);
|
|
864
|
+
} catch {
|
|
865
|
+
resolve(void 0);
|
|
866
|
+
} finally {
|
|
867
|
+
db.close();
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
if (entry) void touch(id);
|
|
871
|
+
return entry;
|
|
872
|
+
},
|
|
873
|
+
/**
|
|
874
|
+
* Resolve a fresh `blob:` object URL for a cached attachment, or `undefined`
|
|
875
|
+
* if it isn't cached. **The caller owns the URL** and must
|
|
876
|
+
* `URL.revokeObjectURL` it when done (the {@link useAttachmentUrl} hook does
|
|
877
|
+
* this automatically).
|
|
878
|
+
*/
|
|
879
|
+
async getObjectURL(id) {
|
|
880
|
+
const entry = await attachmentCache.get(id);
|
|
881
|
+
if (!entry) return void 0;
|
|
882
|
+
try {
|
|
883
|
+
return window.URL.createObjectURL(entry.blob);
|
|
884
|
+
} catch {
|
|
885
|
+
return void 0;
|
|
886
|
+
}
|
|
887
|
+
},
|
|
888
|
+
/** Remove a cached attachment by id. */
|
|
889
|
+
async delete(id) {
|
|
890
|
+
const db = await openDB();
|
|
891
|
+
if (!db) return;
|
|
892
|
+
await new Promise((resolve) => {
|
|
893
|
+
try {
|
|
894
|
+
const t = db.transaction([STORE, META_STORE], "readwrite");
|
|
895
|
+
t.objectStore(STORE).delete(id);
|
|
896
|
+
t.objectStore(META_STORE).delete(id);
|
|
897
|
+
t.oncomplete = () => resolve();
|
|
898
|
+
t.onerror = () => resolve();
|
|
899
|
+
} catch {
|
|
900
|
+
resolve();
|
|
901
|
+
} finally {
|
|
902
|
+
db.close();
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
},
|
|
906
|
+
/** Drop every cached attachment. */
|
|
907
|
+
async clear() {
|
|
908
|
+
const db = await openDB();
|
|
909
|
+
if (!db) return;
|
|
910
|
+
await new Promise((resolve) => {
|
|
911
|
+
try {
|
|
912
|
+
const t = db.transaction([STORE, META_STORE], "readwrite");
|
|
913
|
+
t.objectStore(STORE).clear();
|
|
914
|
+
t.objectStore(META_STORE).clear();
|
|
915
|
+
t.oncomplete = () => resolve();
|
|
916
|
+
t.onerror = () => resolve();
|
|
917
|
+
} catch {
|
|
918
|
+
resolve();
|
|
919
|
+
} finally {
|
|
920
|
+
db.close();
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
var ATTACHMENT_TAG = "superchat-attachment";
|
|
926
|
+
var ATTACHMENT_FENCE = "superchat-attachment";
|
|
927
|
+
function attachmentMarkdown(payload) {
|
|
928
|
+
return ["```superchat-attachment", JSON.stringify(payload), "```"].join("\n");
|
|
929
|
+
}
|
|
930
|
+
function useAttachmentUrl(id, fallbackSrc) {
|
|
931
|
+
const [url, setUrl] = React2__namespace.useState(void 0);
|
|
932
|
+
const [status, setStatus] = React2__namespace.useState("idle");
|
|
933
|
+
React2__namespace.useEffect(() => {
|
|
934
|
+
let active = true;
|
|
935
|
+
let created;
|
|
936
|
+
if (!id && !fallbackSrc) {
|
|
937
|
+
setUrl(void 0);
|
|
938
|
+
setStatus("idle");
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
setStatus("loading");
|
|
942
|
+
void (async () => {
|
|
943
|
+
if (id) {
|
|
944
|
+
const cached = await attachmentCache.getObjectURL(id);
|
|
945
|
+
if (!active) {
|
|
946
|
+
if (cached) window.URL.revokeObjectURL(cached);
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (cached) {
|
|
950
|
+
created = cached;
|
|
951
|
+
setUrl(cached);
|
|
952
|
+
setStatus("ready");
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
if (!active) return;
|
|
957
|
+
setUrl(fallbackSrc);
|
|
958
|
+
setStatus(fallbackSrc ? "ready" : "missing");
|
|
959
|
+
})();
|
|
960
|
+
return () => {
|
|
961
|
+
active = false;
|
|
962
|
+
if (created) window.URL.revokeObjectURL(created);
|
|
963
|
+
};
|
|
964
|
+
}, [id, fallbackSrc]);
|
|
965
|
+
return { url, status };
|
|
966
|
+
}
|
|
967
|
+
var ICON_PROPS = {
|
|
968
|
+
width: 20,
|
|
969
|
+
height: 20,
|
|
970
|
+
viewBox: "0 0 24 24",
|
|
971
|
+
fill: "none",
|
|
972
|
+
stroke: "currentColor",
|
|
973
|
+
strokeWidth: 1.75,
|
|
974
|
+
strokeLinecap: "round",
|
|
975
|
+
strokeLinejoin: "round",
|
|
976
|
+
"aria-hidden": true
|
|
977
|
+
};
|
|
978
|
+
function FileGlyph() {
|
|
979
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...ICON_PROPS, children: [
|
|
980
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 3v4a1 1 0 0 0 1 1h4" }),
|
|
981
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 21H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h7l5 5v11a2 2 0 0 1-2 2Z" })
|
|
982
|
+
] });
|
|
983
|
+
}
|
|
984
|
+
function DownloadGlyph() {
|
|
985
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...ICON_PROPS, width: 16, height: 16, children: [
|
|
986
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3v12" }),
|
|
987
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "m7 12 5 5 5-5" }),
|
|
988
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 21h14" })
|
|
989
|
+
] });
|
|
990
|
+
}
|
|
991
|
+
function kindOf(type) {
|
|
992
|
+
if (type.startsWith("image/")) return "image";
|
|
993
|
+
if (type.startsWith("video/")) return "video";
|
|
994
|
+
if (type.startsWith("audio/")) return "audio";
|
|
995
|
+
if (type === "application/pdf") return "pdf";
|
|
996
|
+
return "file";
|
|
997
|
+
}
|
|
998
|
+
function FileChip({
|
|
999
|
+
name,
|
|
1000
|
+
url,
|
|
1001
|
+
unavailable
|
|
1002
|
+
}) {
|
|
1003
|
+
const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1004
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral-500 dark:text-neutral-400", children: /* @__PURE__ */ jsxRuntime.jsx(FileGlyph, {}) }),
|
|
1005
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate text-sm", children: name }),
|
|
1006
|
+
url && !unavailable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-neutral-400", children: /* @__PURE__ */ jsxRuntime.jsx(DownloadGlyph, {}) }) : null
|
|
1007
|
+
] });
|
|
1008
|
+
const className = chunkOR5DRJCW_cjs.cn(
|
|
1009
|
+
"my-2 flex max-w-sm items-center gap-2 rounded-lg border border-neutral-200 bg-neutral-50 px-3 py-2 dark:border-neutral-700 dark:bg-neutral-800",
|
|
1010
|
+
unavailable && "opacity-60"
|
|
1011
|
+
);
|
|
1012
|
+
if (url && !unavailable) {
|
|
1013
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1014
|
+
"a",
|
|
1015
|
+
{
|
|
1016
|
+
href: url,
|
|
1017
|
+
download: name,
|
|
1018
|
+
target: "_blank",
|
|
1019
|
+
rel: "noopener noreferrer",
|
|
1020
|
+
title: name,
|
|
1021
|
+
className: chunkOR5DRJCW_cjs.cn(
|
|
1022
|
+
className,
|
|
1023
|
+
"hover:border-neutral-300 hover:bg-neutral-100 dark:hover:border-neutral-600 dark:hover:bg-neutral-700"
|
|
1024
|
+
),
|
|
1025
|
+
children: content
|
|
1026
|
+
}
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
1029
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, title: name, children: [
|
|
1030
|
+
content,
|
|
1031
|
+
unavailable ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs whitespace-nowrap text-neutral-400", children: "unavailable offline" }) : null
|
|
1032
|
+
] });
|
|
1033
|
+
}
|
|
1034
|
+
function AttachmentBlock({ payload }) {
|
|
1035
|
+
const { id, type, name, src } = payload;
|
|
1036
|
+
const { url, status } = useAttachmentUrl(id || void 0, src);
|
|
1037
|
+
const kind = kindOf(type);
|
|
1038
|
+
React2__namespace.useEffect(() => {
|
|
1039
|
+
if (!id || !src || !attachmentCache.isAvailable()) return;
|
|
1040
|
+
let active = true;
|
|
1041
|
+
void attachmentCache.get(id).then((existing) => {
|
|
1042
|
+
if (active && !existing) {
|
|
1043
|
+
void attachmentCache.put({ id, name, type, dataUrl: src });
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
return () => {
|
|
1047
|
+
active = false;
|
|
1048
|
+
};
|
|
1049
|
+
}, [id, src, name, type]);
|
|
1050
|
+
if (status === "loading") {
|
|
1051
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1052
|
+
"div",
|
|
1053
|
+
{
|
|
1054
|
+
"data-slot": "superchat-attachment",
|
|
1055
|
+
className: "my-2 h-10 max-w-sm animate-pulse rounded-lg bg-neutral-100 dark:bg-neutral-800",
|
|
1056
|
+
"aria-label": `Loading ${name}`
|
|
1057
|
+
}
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
if (!url) {
|
|
1061
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "superchat-attachment", children: /* @__PURE__ */ jsxRuntime.jsx(FileChip, { name, unavailable: true }) });
|
|
1062
|
+
}
|
|
1063
|
+
let body;
|
|
1064
|
+
switch (kind) {
|
|
1065
|
+
case "image":
|
|
1066
|
+
body = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1067
|
+
"img",
|
|
1068
|
+
{
|
|
1069
|
+
src: url,
|
|
1070
|
+
alt: name,
|
|
1071
|
+
className: "max-h-80 max-w-full rounded-lg object-contain"
|
|
1072
|
+
}
|
|
1073
|
+
);
|
|
1074
|
+
break;
|
|
1075
|
+
case "video":
|
|
1076
|
+
body = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1077
|
+
"video",
|
|
1078
|
+
{
|
|
1079
|
+
src: url,
|
|
1080
|
+
controls: true,
|
|
1081
|
+
className: "max-h-80 max-w-full rounded-lg bg-black",
|
|
1082
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("track", { kind: "captions" })
|
|
1083
|
+
}
|
|
1084
|
+
);
|
|
1085
|
+
break;
|
|
1086
|
+
case "audio":
|
|
1087
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-sm", children: [
|
|
1088
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-1 truncate text-xs text-neutral-500 dark:text-neutral-400", children: name }),
|
|
1089
|
+
/* @__PURE__ */ jsxRuntime.jsx("audio", { src: url, controls: true, className: "w-full", children: /* @__PURE__ */ jsxRuntime.jsx("track", { kind: "captions" }) })
|
|
1090
|
+
] });
|
|
1091
|
+
break;
|
|
1092
|
+
case "pdf":
|
|
1093
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-2xl overflow-hidden rounded-lg border border-neutral-200 dark:border-neutral-700", children: [
|
|
1094
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-neutral-200 bg-neutral-50 px-3 py-1.5 dark:border-neutral-700 dark:bg-neutral-800", children: [
|
|
1095
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm", title: name, children: name }),
|
|
1096
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1097
|
+
"a",
|
|
1098
|
+
{
|
|
1099
|
+
href: url,
|
|
1100
|
+
download: name,
|
|
1101
|
+
target: "_blank",
|
|
1102
|
+
rel: "noopener noreferrer",
|
|
1103
|
+
className: "text-primary-700 hover:text-primary-800 dark:text-primary-300 inline-flex items-center gap-1 text-xs whitespace-nowrap",
|
|
1104
|
+
children: [
|
|
1105
|
+
/* @__PURE__ */ jsxRuntime.jsx(DownloadGlyph, {}),
|
|
1106
|
+
"Open"
|
|
1107
|
+
]
|
|
1108
|
+
}
|
|
1109
|
+
)
|
|
1110
|
+
] }),
|
|
1111
|
+
/* @__PURE__ */ jsxRuntime.jsx("iframe", { src: url, title: name, className: "h-96 w-full bg-white" })
|
|
1112
|
+
] });
|
|
1113
|
+
break;
|
|
1114
|
+
default:
|
|
1115
|
+
body = /* @__PURE__ */ jsxRuntime.jsx(FileChip, { name, url });
|
|
1116
|
+
}
|
|
1117
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-slot": "superchat-attachment", children: body });
|
|
1118
|
+
}
|
|
1119
|
+
function textOf4(node) {
|
|
1120
|
+
if (node.type === "text") return node.value ?? "";
|
|
1121
|
+
return (node.children ?? []).map(textOf4).join("");
|
|
1122
|
+
}
|
|
1123
|
+
function isAttachmentPre(node) {
|
|
1124
|
+
if (node.tagName !== "pre") return false;
|
|
1125
|
+
const code = node.children?.find((c) => c.tagName === "code");
|
|
1126
|
+
const className = code?.properties?.className;
|
|
1127
|
+
const classes = Array.isArray(className) ? className : [className];
|
|
1128
|
+
return classes.some(
|
|
1129
|
+
(c) => typeof c === "string" && (c === `language-${ATTACHMENT_FENCE}` || c === ATTACHMENT_FENCE)
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
function rehypeAttachment() {
|
|
1133
|
+
return (tree) => {
|
|
1134
|
+
const walk = (node) => {
|
|
1135
|
+
if (!node.children) return;
|
|
1136
|
+
node.children = node.children.map((child) => {
|
|
1137
|
+
if (isAttachmentPre(child)) {
|
|
1138
|
+
const code = child.children?.find((c) => c.tagName === "code");
|
|
1139
|
+
const raw = code ? textOf4(code) : "";
|
|
1140
|
+
return {
|
|
1141
|
+
type: "element",
|
|
1142
|
+
tagName: ATTACHMENT_TAG,
|
|
1143
|
+
properties: {},
|
|
1144
|
+
children: [{ type: "text", value: raw }]
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
walk(child);
|
|
1148
|
+
return child;
|
|
1149
|
+
});
|
|
1150
|
+
};
|
|
1151
|
+
walk(tree);
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
function childText(children) {
|
|
1155
|
+
return React2__namespace.Children.toArray(children).map((c) => typeof c === "string" ? c : "").join("");
|
|
1156
|
+
}
|
|
1157
|
+
function sanitizeSrc(src) {
|
|
1158
|
+
if (!src) return void 0;
|
|
1159
|
+
if (/^(?:blob:|https?:\/\/)/i.test(src)) return src;
|
|
1160
|
+
const dataMatch = /^data:([\w.+-]+\/[\w.+-]+)?[;,]/i.exec(src);
|
|
1161
|
+
if (dataMatch) {
|
|
1162
|
+
const mime = (dataMatch[1] ?? "text/plain").toLowerCase();
|
|
1163
|
+
const EXECUTABLE_MIME = /^(?:text\/html|application\/xhtml\+xml|image\/svg\+xml|text\/xml|application\/xml)$/;
|
|
1164
|
+
return EXECUTABLE_MIME.test(mime) ? void 0 : src;
|
|
1165
|
+
}
|
|
1166
|
+
return void 0;
|
|
1167
|
+
}
|
|
1168
|
+
function parsePayload2(raw) {
|
|
1169
|
+
try {
|
|
1170
|
+
const parsed = JSON.parse(raw);
|
|
1171
|
+
if (!parsed || typeof parsed.type !== "string") return null;
|
|
1172
|
+
const src = typeof parsed.src === "string" ? sanitizeSrc(parsed.src) : void 0;
|
|
1173
|
+
if (!parsed.id && !src) return null;
|
|
1174
|
+
return {
|
|
1175
|
+
id: typeof parsed.id === "string" ? parsed.id : void 0,
|
|
1176
|
+
type: parsed.type,
|
|
1177
|
+
name: typeof parsed.name === "string" ? parsed.name : "attachment",
|
|
1178
|
+
src
|
|
1179
|
+
};
|
|
1180
|
+
} catch {
|
|
1181
|
+
return null;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
function AttachmentElement({
|
|
1185
|
+
node: _node,
|
|
1186
|
+
children
|
|
1187
|
+
}) {
|
|
1188
|
+
const payload = parsePayload2(childText(children));
|
|
1189
|
+
if (!payload) return null;
|
|
1190
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AttachmentBlock, { payload });
|
|
1191
|
+
}
|
|
1192
|
+
function createAttachmentPlugin() {
|
|
1193
|
+
return {
|
|
1194
|
+
name: "attachment",
|
|
1195
|
+
rehypePlugins: [rehypeAttachment],
|
|
1196
|
+
components: {
|
|
1197
|
+
[ATTACHMENT_TAG]: AttachmentElement
|
|
1198
|
+
},
|
|
1199
|
+
// The payload rides as a text child; only the custom tag needs allow-listing.
|
|
1200
|
+
sanitizeSchema: {
|
|
1201
|
+
tagNames: [ATTACHMENT_TAG]
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
exports.ATTACHMENT_FENCE = ATTACHMENT_FENCE;
|
|
1207
|
+
exports.ATTACHMENT_TAG = ATTACHMENT_TAG;
|
|
1208
|
+
exports.GENUI_TAG = GENUI_TAG;
|
|
1209
|
+
exports.MERMAID_TAG = MERMAID_TAG;
|
|
1210
|
+
exports.attachmentCache = attachmentCache;
|
|
1211
|
+
exports.attachmentMarkdown = attachmentMarkdown;
|
|
1212
|
+
exports.createAttachmentPlugin = createAttachmentPlugin;
|
|
1213
|
+
exports.createCodePlugin = createCodePlugin;
|
|
1214
|
+
exports.createGenUIPlugin = createGenUIPlugin;
|
|
1215
|
+
exports.createImagePlugin = createImagePlugin;
|
|
1216
|
+
exports.createMathPlugin = createMathPlugin;
|
|
1217
|
+
exports.createMermaidPlugin = createMermaidPlugin;
|
|
1218
|
+
exports.createNitroTablePlugin = createNitroTablePlugin;
|
|
1219
|
+
exports.useAttachmentUrl = useAttachmentUrl;
|
|
1220
|
+
//# sourceMappingURL=index.cjs.map
|
|
1221
|
+
//# sourceMappingURL=index.cjs.map
|