memi-board 0.43.0 → 0.44.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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { A as e, C as t, D as n, E as r, O as i, S as a, T as o, _ as s, a as c, b as l, c as u, d, f, g as p, h as m, i as h, j as g, k as _, l as v, m as y, n as b, o as x, p as S, r as C, s as w, u as T, v as E, w as D, x as O, y as k } from "./slugify-Cm_pi2al.js";
2
2
  import { computed as A, onScopeDispose as j, reactive as ee, ref as M, toValue as N, watch as P } from "vue";
3
- import { deleteDoc as F, deleteField as I, doc as L, documentId as R, endBefore as te, getDoc as z, getDocs as B, increment as V, limit as H, limitToLast as ne, onSnapshot as U, orderBy as W, query as G, runTransaction as re, serverTimestamp as K, setDoc as q, startAfter as J, updateDoc as Y, where as X, writeBatch as Z } from "firebase/firestore";
4
- import { useCollection as ie, useCurrentUser as ae, useDocument as oe, useFirebaseApp as se, useFirebaseAuth as ce, useFirestore as Q } from "vuefire";
3
+ import { deleteDoc as F, deleteField as I, doc as te, documentId as L, endBefore as ne, getDoc as R, getDocs as z, increment as B, limit as V, limitToLast as re, onSnapshot as H, orderBy as U, query as W, runTransaction as ie, serverTimestamp as G, setDoc as K, startAfter as q, updateDoc as J, where as Y, writeBatch as X } from "firebase/firestore";
4
+ import { useCollection as ae, useCurrentUser as Z, useDocument as oe, useFirebaseApp as se, useFirebaseAuth as ce, useFirestore as Q } from "vuefire";
5
5
  import { GoogleAuthProvider as le, OAuthProvider as ue, createUserWithEmailAndPassword as de, signInWithEmailAndPassword as fe, signInWithPopup as pe, signOut as me, updateProfile as he } from "firebase/auth";
6
6
  import { deleteObject as ge, getStorage as _e, listAll as ve, ref as ye } from "firebase/storage";
7
7
  import { GoogleAIBackend as be, Schema as xe, getAI as Se, getGenerativeModel as Ce } from "firebase/ai";
@@ -76,7 +76,7 @@ function Ve() {
76
76
  }
77
77
  async function He(e, t) {
78
78
  try {
79
- let n = await z(g(e.db, e.paths, t));
79
+ let n = await R(g(e.db, e.paths, t));
80
80
  if (!n.exists()) return {
81
81
  label: t,
82
82
  description: "",
@@ -113,7 +113,7 @@ async function We(e, t, n) {
113
113
  let s = await He(a, r);
114
114
  if (s.hidden) return null;
115
115
  try {
116
- let e = (await B(G(o(a.db, a.paths), X("boardId", "==", r), X("slug", "==", i), X("listed", "==", !0), X("isPublished", "==", !0), H(1)))).docs[0];
116
+ let e = (await z(W(o(a.db, a.paths), Y("boardId", "==", r), Y("slug", "==", i), Y("listed", "==", !0), Y("isPublished", "==", !0), V(1)))).docs[0];
117
117
  if (!e) return null;
118
118
  let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title.trim() : "";
119
119
  return n ? {
@@ -165,7 +165,7 @@ async function Ge(e, t) {
165
165
  async function Ke(e, t) {
166
166
  let n = [], r = null;
167
167
  try {
168
- let i = await B(G(o(e.db, e.paths), X("boardId", "==", t), X("listed", "==", !0), X("isPublished", "==", !0), W("createdAt", "desc"), H(12)));
168
+ let i = await z(W(o(e.db, e.paths), Y("boardId", "==", t), Y("listed", "==", !0), Y("isPublished", "==", !0), U("createdAt", "desc"), V(12)));
169
169
  for (let e of i.docs) {
170
170
  let t = e.data() ?? {}, i = typeof t.title == "string" ? t.title.trim() : "";
171
171
  i && n.length < 5 && n.push(i), r ||= Pe(t.previewImage);
@@ -254,7 +254,7 @@ function st() {
254
254
  }), e[ot];
255
255
  }
256
256
  function ct() {
257
- let e = c(), t = st(), n = Q(), r = ce(), i = ae(), { role: a, rolePending: o, rawBlockCount: s, blockAtMs: l } = t;
257
+ let e = c(), t = st(), n = Q(), r = ce(), i = Z(), { role: a, rolePending: o, rawBlockCount: s, blockAtMs: l } = t;
258
258
  function u() {
259
259
  let t = e.moderation?.blockBanThreshold;
260
260
  return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
@@ -274,22 +274,22 @@ function ct() {
274
274
  s.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), l.value = at(e.moderationBlockAt);
275
275
  }
276
276
  async function g(e) {
277
- let t = f(e.uid), r = m(n, h(), e.uid), i = await z(t);
278
- if (!i.exists()) return await Promise.all([q(t, {
277
+ let t = f(e.uid), r = m(n, h(), e.uid), i = await R(t);
278
+ if (!i.exists()) return await Promise.all([K(t, {
279
279
  role: "user",
280
280
  displayName: e.displayName,
281
281
  photoURL: e.photoURL,
282
- joinedAt: K(),
283
- lastVisitAt: K(),
284
- updatedAt: K()
285
- }), q(r, { email: e.email })]), p({ moderationBlockCount: 0 }), "user";
282
+ joinedAt: G(),
283
+ lastVisitAt: G(),
284
+ updatedAt: G()
285
+ }), K(r, { email: e.email })]), p({ moderationBlockCount: 0 }), "user";
286
286
  let a = i.data();
287
287
  p(a);
288
288
  let o = typeof a.displayName == "string" && a.displayName.trim(), s = typeof a.photoURL == "string" && a.photoURL.trim(), c = {
289
- lastVisitAt: K(),
290
- updatedAt: K()
289
+ lastVisitAt: G(),
290
+ updatedAt: G()
291
291
  };
292
- return !o && e.displayName && (c.displayName = e.displayName), !s && e.photoURL && (c.photoURL = e.photoURL), await Promise.all([Y(t, c), q(r, { email: e.email }, { merge: !0 })]), [
292
+ return !o && e.displayName && (c.displayName = e.displayName), !s && e.photoURL && (c.photoURL = e.photoURL), await Promise.all([J(t, c), K(r, { email: e.email }, { merge: !0 })]), [
293
293
  "admin",
294
294
  "staff",
295
295
  "user"
@@ -301,7 +301,7 @@ function ct() {
301
301
  p(void 0);
302
302
  return;
303
303
  }
304
- let t = await z(f(e));
304
+ let t = await R(f(e));
305
305
  p(t.exists() ? t.data() : void 0);
306
306
  }
307
307
  t.watchStarted || (t.watchStarted = !0, P(i, async (e) => {
@@ -337,17 +337,17 @@ function ct() {
337
337
  restricted: !1,
338
338
  messageSuffix: ""
339
339
  };
340
- let n = f(e), r = await z(n);
341
- r.exists() ? await Y(n, {
342
- moderationBlockCount: V(1),
343
- moderationBlockAt: K(),
344
- updatedAt: K()
345
- }) : await q(n, {
340
+ let n = f(e), r = await R(n);
341
+ r.exists() ? await J(n, {
342
+ moderationBlockCount: B(1),
343
+ moderationBlockAt: G(),
344
+ updatedAt: G()
345
+ }) : await K(n, {
346
346
  role: "user",
347
347
  displayName: i.value?.displayName ?? null,
348
348
  moderationBlockCount: 1,
349
- moderationBlockAt: K(),
350
- updatedAt: K()
349
+ moderationBlockAt: G(),
350
+ updatedAt: G()
351
351
  });
352
352
  let a = (r.exists() ? Math.max(0, Math.floor(Number(r.data().moderationBlockCount) || 0)) : 0) + 1, o = Date.now();
353
353
  s.value = a, l.value = o;
@@ -389,10 +389,10 @@ function ct() {
389
389
  function I(e) {
390
390
  return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
391
391
  }
392
- function L(e) {
392
+ function te(e) {
393
393
  return v.value && i.value?.uid === e.authorUid;
394
394
  }
395
- function R(e) {
395
+ function L(e) {
396
396
  return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
397
397
  }
398
398
  return {
@@ -414,15 +414,36 @@ function ct() {
414
414
  signOut: N,
415
415
  canEdit: I,
416
416
  canDelete: I,
417
- canEditComment: L,
418
- canDeleteComment: R,
417
+ canEditComment: te,
418
+ canDeleteComment: L,
419
419
  recordContentModerationBlock: D,
420
420
  refreshBoardUser: _
421
421
  };
422
422
  }
423
423
  //#endregion
424
+ //#region src/utils/imeSafeSubmit.ts
425
+ var lt = /* @__PURE__ */ new WeakMap();
426
+ function ut(e) {
427
+ let t = e.currentTarget;
428
+ return t instanceof HTMLButtonElement ? t : t instanceof Element ? t.closest("button") : null;
429
+ }
430
+ function dt(e) {
431
+ if (e.pointerType !== "mouse" || e.button !== 0) return;
432
+ let t = ut(e), n = t?.form;
433
+ if (!t || !n || t.disabled) return;
434
+ lt.set(t, Date.now() + 1e3);
435
+ let r = document.activeElement;
436
+ r instanceof HTMLElement && r.blur(), setTimeout(() => n.requestSubmit(t), 0);
437
+ }
438
+ function ft(e) {
439
+ let t = ut(e);
440
+ if (!t) return;
441
+ let n = lt.get(t);
442
+ n && Date.now() < n && (e.preventDefault(), lt.delete(t));
443
+ }
444
+ //#endregion
424
445
  //#region src/utils/extractEditorImageUrls.ts
425
- function lt(e) {
446
+ function pt(e) {
426
447
  if (!e) return [];
427
448
  let t = /* @__PURE__ */ new Set();
428
449
  for (let n of e.matchAll(/!\[[^\]]*]\((https?:\/\/[^)\s]+)\)/g)) n[1] && t.add(n[1].replaceAll("&amp;", "&"));
@@ -431,7 +452,7 @@ function lt(e) {
431
452
  }
432
453
  //#endregion
433
454
  //#region src/utils/storagePath.ts
434
- function ut(e) {
455
+ function mt(e) {
435
456
  try {
436
457
  let t = new URL(e), n = t.hostname.toLowerCase();
437
458
  if (!(n === "firebasestorage.googleapis.com" || n.endsWith(".firebasestorage.app"))) return null;
@@ -441,109 +462,109 @@ function ut(e) {
441
462
  return null;
442
463
  }
443
464
  }
444
- function dt(e) {
465
+ function ht(e) {
445
466
  return e.match(/(?:^|\/)posts\/([^/]+)\//)?.[1] ?? null;
446
467
  }
447
468
  //#endregion
448
469
  //#region src/utils/deletePostCascade.ts
449
- async function ft(e) {
470
+ async function gt(e) {
450
471
  try {
451
472
  let t = await ve(e);
452
- await Promise.all([...t.items.map((e) => ge(e).catch(() => {})), ...t.prefixes.map((e) => ft(e))]);
473
+ await Promise.all([...t.items.map((e) => ge(e).catch(() => {})), ...t.prefixes.map((e) => gt(e))]);
453
474
  } catch {}
454
475
  }
455
- async function pt(e, t) {
456
- await ft(ye(e, `${t}/images`)), await ft(ye(e, `${t}/attachments`));
476
+ async function _t(e, t) {
477
+ await gt(ye(e, `${t}/images`)), await gt(ye(e, `${t}/attachments`));
457
478
  }
458
- async function mt(e, t) {
479
+ async function vt(e, t) {
459
480
  let n = [...new Set([...t].filter(Boolean))];
460
481
  await Promise.all(n.map((t) => ge(ye(e, t)).catch(() => {})));
461
482
  }
462
- var ht = 450;
463
- async function gt(e, t) {
464
- let n = await B(t);
465
- for (let t = 0; t < n.docs.length; t += ht) {
466
- let r = Z(e);
467
- n.docs.slice(t, t + ht).forEach((e) => r.delete(e.ref)), await r.commit();
483
+ var yt = 450;
484
+ async function bt(e, t) {
485
+ let n = await z(t);
486
+ for (let t = 0; t < n.docs.length; t += yt) {
487
+ let r = X(e);
488
+ n.docs.slice(t, t + yt).forEach((e) => r.delete(e.ref)), await r.commit();
468
489
  }
469
490
  }
470
- async function _t(e, t, n) {
471
- await gt(e, G(O(e, t), X("postId", "==", n)));
491
+ async function xt(e, t, n) {
492
+ await bt(e, W(O(e, t), Y("postId", "==", n)));
472
493
  }
473
- async function vt(e, t, n) {
474
- await gt(e, G(i(e, t), X("postId", "==", n)));
494
+ async function St(e, t, n) {
495
+ await bt(e, W(i(e, t), Y("postId", "==", n)));
475
496
  }
476
- async function yt(e, t, n) {
477
- await gt(e, G(O(e, t), X("commentId", "==", n)));
497
+ async function Ct(e, t, n) {
498
+ await bt(e, W(O(e, t), Y("commentId", "==", n)));
478
499
  }
479
- async function bt(e, n, r, i) {
480
- let o = t(e, r, i), s = a(e, r, i), [c, l] = await Promise.all([z(o), z(s)]);
500
+ async function wt(e, n, r, i) {
501
+ let o = t(e, r, i), s = a(e, r, i), [c, l] = await Promise.all([R(o), R(s)]);
481
502
  if (!c.exists()) return;
482
503
  let u = c.data(), d = l.exists() ? String(l.data().content ?? "") : "";
483
- await gt(e, G(E(e, r), X("postId", "==", i))), await _t(e, r, i), await vt(e, r, i);
504
+ await bt(e, W(E(e, r), Y("postId", "==", i))), await xt(e, r, i), await St(e, r, i);
484
505
  let f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
485
506
  for (let e of u.attachments ?? []) {
486
507
  if (!e?.path) continue;
487
508
  f.add(e.path);
488
- let t = dt(e.path);
509
+ let t = ht(e.path);
489
510
  t && t !== i && p.add(t);
490
511
  }
491
- for (let e of lt(d)) {
492
- let t = ut(e);
512
+ for (let e of pt(d)) {
513
+ let t = mt(e);
493
514
  if (!t) continue;
494
515
  f.add(t);
495
516
  let n = t.replace(/\/images\/([^/]+)$/, "/images/thumbnails/$1").replace(/\.[^.]+$/, ".jpg");
496
517
  n !== t && n.includes("/images/thumbnails/") && f.add(n);
497
518
  let r = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
498
519
  r && !t.includes("/thumbnails/") && f.add(`${r[1]}thumbnails/${r[2]}.jpg`);
499
- let a = dt(t);
520
+ let a = ht(t);
500
521
  a && a !== i && p.add(a);
501
522
  }
502
- await F(s), await pt(n, D(r, i));
503
- for (let e of p) await pt(n, D(r, e));
504
- await mt(n, f), await F(o);
523
+ await F(s), await _t(n, D(r, i));
524
+ for (let e of p) await _t(n, D(r, e));
525
+ await vt(n, f), await F(o);
505
526
  }
506
527
  //#endregion
507
528
  //#region src/utils/postBody.ts
508
- function xt(e) {
529
+ function Tt(e) {
509
530
  return String(e || "").replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<img\b[^>]*>/gi, " ").replace(/<iframe\b[^>]*>[\s\S]*?<\/iframe>/gi, " ").replace(/<video\b[\s\S]*?<\/video>/gi, " ").replace(/<audio\b[\s\S]*?<\/audio>/gi, " ").replace(/<[^>]+>/g, " ").replace(/&nbsp;/gi, " ").replace(/&#160;/g, " ").replace(/&[a-z]+;/gi, " ").replace(/&#\d+;/g, " ").replace(/[\u200B-\u200D\uFEFF\u00AD]/g, "").replace(/\s+/g, " ").trim();
510
531
  }
511
- function St(e, t = 40) {
512
- let n = xt(e);
532
+ function Et(e, t = 40) {
533
+ let n = Tt(e);
513
534
  if (!n) return "";
514
535
  if (n.length <= t) return n;
515
536
  let r = n.slice(0, t), i = r.lastIndexOf(" ");
516
537
  return `${(i >= Math.floor(t * .6) ? r.slice(0, i) : r).trimEnd()}…`;
517
538
  }
518
- function Ct(e) {
519
- return xt(e).length > 0;
539
+ function Dt(e) {
540
+ return Tt(e).length > 0;
520
541
  }
521
- function wt(e, t) {
542
+ function Ot(e, t) {
522
543
  return /<img\b/i.test(String(e || "")) ? !0 : (t || []).some((e) => !!e?.type?.startsWith("image/"));
523
544
  }
524
- function Tt(e) {
525
- return !Ct(e);
545
+ function kt(e) {
546
+ return !Dt(e);
526
547
  }
527
548
  //#endregion
528
549
  //#region src/utils/postPreview.ts
529
- function Et(e) {
550
+ function At(e) {
530
551
  return e.replace(/&amp;/g, "&").replace(/&quot;/g, "\"").replace(/&#39;/g, "'");
531
552
  }
532
- function Dt(e) {
553
+ function jt(e) {
533
554
  if (e) try {
534
- let t = new URL(Et(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
555
+ let t = new URL(At(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
535
556
  if (n === "youtu.be") return t.pathname.split("/").filter(Boolean)[0];
536
557
  if (n.endsWith("youtube.com") || n === "youtube-nocookie.com") return t.pathname.startsWith("/embed/") || t.pathname.startsWith("/shorts/") ? t.pathname.split("/")[2] : t.searchParams.get("v") || void 0;
537
558
  } catch {
538
559
  return;
539
560
  }
540
561
  }
541
- function Ot(e) {
542
- let t = Dt(e.videoUrl);
562
+ function Mt(e) {
563
+ let t = jt(e.videoUrl);
543
564
  return t ? `https://i.ytimg.com/vi/${t}/hqdefault.jpg` : e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
544
565
  }
545
- function kt(e, t = []) {
546
- let n = e.match(/<img\b[^>]*\bsrc=["']([^"']+)["']/i), r = e.match(/<iframe\b[^>]*\bsrc=["']([^"']+)["']/i), i = t.find((e) => e.type.startsWith("image/"))?.url, a = t.find((e) => e.type.startsWith("video/"))?.url, o = r ? Et(r[1]) : a, s = o ? Dt(o) : void 0, c = n ? Et(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
566
+ function Nt(e, t = []) {
567
+ let n = e.match(/<img\b[^>]*\bsrc=["']([^"']+)["']/i), r = e.match(/<iframe\b[^>]*\bsrc=["']([^"']+)["']/i), i = t.find((e) => e.type.startsWith("image/"))?.url, a = t.find((e) => e.type.startsWith("video/"))?.url, o = r ? At(r[1]) : a, s = o ? jt(o) : void 0, c = n ? At(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
547
568
  return {
548
569
  summary: e.replace(/<style[\s\S]*?<\/style>/gi, " ").replace(/<script[\s\S]*?<\/script>/gi, " ").replace(/<br\s*\/?>/gi, "\n").replace(/<\/(p|div|li|h[1-6]|blockquote)>/gi, "\n").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/[^\S\n]+/g, " ").replace(/ *\n */g, "\n").replace(/\n{2,}/g, "\n").trim().slice(0, 160),
549
570
  ...c ? { previewImage: c } : {},
@@ -552,7 +573,7 @@ function kt(e, t = []) {
552
573
  }
553
574
  //#endregion
554
575
  //#region src/composables/useMemiBoardSettings.ts
555
- var At = [
576
+ var Pt = [
556
577
  {
557
578
  id: "free",
558
579
  label: "자유",
@@ -580,17 +601,17 @@ var At = [
580
601
  visibility: "public",
581
602
  order: 2
582
603
  }
583
- ], jt = At;
584
- function Mt(e) {
604
+ ], Ft = Pt;
605
+ function It(e) {
585
606
  return e === "hidden" ? "hidden" : "public";
586
607
  }
587
- function Nt(e, t, n) {
608
+ function Lt(e, t, n) {
588
609
  return {
589
610
  id: e,
590
611
  label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
591
612
  order: typeof t.order == "number" ? t.order : n,
592
613
  description: (typeof t.description == "string" ? t.description : "") || "",
593
- visibility: Mt(t.visibility),
614
+ visibility: It(t.visibility),
594
615
  listView: t.listView ?? "default",
595
616
  editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
596
617
  writeRole: t.writeRole ?? "user",
@@ -598,8 +619,8 @@ function Nt(e, t, n) {
598
619
  allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : []
599
620
  };
600
621
  }
601
- function Pt() {
602
- let t = () => h(), n = Q(), r = se(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = ct(), l = A(() => G(e(n, t()), W("order", "asc"))), { data: u, pending: d } = ie(l, { ssrKey: S(t(), "boards") }), f = A(() => u.value.map((e, t) => Nt(e.id, e, t))), p = f, m = A(() => f.value.filter((e) => e.visibility !== "hidden")), _ = m;
622
+ function Rt() {
623
+ let t = () => h(), n = Q(), r = se(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = ct(), l = A(() => W(e(n, t()), U("order", "asc"))), { data: u, pending: d } = ae(l, { ssrKey: S(t(), "boards") }), f = A(() => u.value.map((e, t) => Lt(e.id, e, t))), p = f, m = A(() => f.value.filter((e) => e.visibility !== "hidden")), _ = m;
603
624
  function v(e) {
604
625
  if (e) return f.value.find((t) => t.id === e)?.label ?? e;
605
626
  }
@@ -627,9 +648,9 @@ function Pt() {
627
648
  async function M(e, t, r) {
628
649
  let i;
629
650
  for (;;) {
630
- let a = await B(G(e, X("boardId", "==", t), W("__name__"), ...i ? [J(i)] : [], H(400)));
651
+ let a = await z(W(e, Y("boardId", "==", t), U("__name__"), ...i ? [q(i)] : [], V(400)));
631
652
  if (a.empty) break;
632
- let o = Z(n), s = 0;
653
+ let o = X(n), s = 0;
633
654
  for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
634
655
  if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
635
656
  }
@@ -641,35 +662,35 @@ function Pt() {
641
662
  return {
642
663
  label: e.label.trim(),
643
664
  description: (e.description ?? "").trim(),
644
- visibility: Mt(e.visibility),
665
+ visibility: It(e.visibility),
645
666
  listView: e.listView ?? "default",
646
667
  editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
647
668
  writeRole: e.writeRole ?? "user",
648
669
  commentWriteRole: e.commentWriteRole ?? "user",
649
670
  allowedStaffUids: e.allowedStaffUids ?? [],
650
671
  order: t,
651
- updatedAt: K()
672
+ updatedAt: G()
652
673
  };
653
674
  }
654
675
  async function I(e, r = e.order ?? 0) {
655
676
  if (!i.value) throw Error("로그인이 필요합니다.");
656
677
  let a = e.id.trim(), o = e.label.trim();
657
678
  if (!a || !o) throw Error("보드 ID와 이름을 입력해 주세요.");
658
- let s = Mt(e.visibility), c = P({
679
+ let s = It(e.visibility), c = P({
659
680
  ...e,
660
681
  label: o,
661
682
  visibility: s
662
683
  }, r);
663
- await q(g(n, t(), a), c, { merge: !0 }), await N(a, s !== "hidden");
684
+ await K(g(n, t(), a), c, { merge: !0 }), await N(a, s !== "hidden");
664
685
  }
665
- let L = I;
666
- async function R(e) {
686
+ let te = I;
687
+ async function L(e) {
667
688
  if (!i.value) throw Error("로그인이 필요합니다.");
668
- let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a = Z(n), o = [];
689
+ let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a = X(n), o = [];
669
690
  e.forEach((e, i) => {
670
691
  let s = e.id.trim(), c = e.label.trim();
671
692
  if (!s || !c) throw Error("보드 ID와 이름을 입력해 주세요.");
672
- let l = Mt(e.visibility), u = P({
693
+ let l = It(e.visibility), u = P({
673
694
  ...e,
674
695
  label: c,
675
696
  visibility: l
@@ -681,23 +702,23 @@ function Pt() {
681
702
  }), await a.commit();
682
703
  for (let e of o) await N(e.id, e.listed);
683
704
  }
684
- let te = R;
685
- async function z(e) {
705
+ let ne = L;
706
+ async function R(e) {
686
707
  if (!i.value) throw Error("로그인이 필요합니다.");
687
708
  let a = e.trim();
688
709
  if (!a) throw Error("삭제할 게시판 ID가 필요합니다.");
689
710
  for (;;) {
690
- let e = await B(G(o(n, t()), X("boardId", "==", a), H(25)));
711
+ let e = await z(W(o(n, t()), Y("boardId", "==", a), V(25)));
691
712
  if (e.empty) break;
692
- for (let i of e.docs) await bt(n, _e(r), t(), i.id);
713
+ for (let i of e.docs) await wt(n, _e(r), t(), i.id);
693
714
  }
694
715
  await F(g(n, t(), e));
695
716
  }
696
- let V = z;
697
- async function ne() {
717
+ let B = R;
718
+ async function re() {
698
719
  return Promise.resolve();
699
720
  }
700
- async function U(e) {
721
+ async function H(e) {
701
722
  let t = e.trim();
702
723
  if (!t) throw Error("보드 이름을 입력해 주세요.");
703
724
  if (!i.value) throw Error("로그인이 필요합니다.");
@@ -733,33 +754,34 @@ function Pt() {
733
754
  categoryVisibility: T,
734
755
  isCategoryHidden: O,
735
756
  settingsPending: d,
736
- ensureSettings: ne,
737
- addBoard: U,
738
- addCategory: U,
757
+ ensureSettings: re,
758
+ addBoard: H,
759
+ addCategory: H,
739
760
  saveBoard: I,
740
- saveCategory: L,
741
- saveBoards: R,
742
- saveCategories: te,
743
- deleteBoard: z,
744
- deleteCategory: V,
745
- DEFAULT_BOARDS: At,
746
- DEFAULT_CATEGORIES: jt
761
+ saveCategory: te,
762
+ saveBoards: L,
763
+ saveCategories: ne,
764
+ deleteBoard: R,
765
+ deleteCategory: B,
766
+ DEFAULT_BOARDS: Pt,
767
+ DEFAULT_CATEGORIES: Ft
747
768
  };
748
769
  }
749
770
  //#endregion
750
771
  //#region src/composables/useMemiBoardPosts.ts
751
- function Ft(e) {
772
+ var zt = /* @__PURE__ */ new Map();
773
+ function Bt(e) {
752
774
  if (!e || typeof e != "object") return !1;
753
775
  let t = "code" in e ? String(e.code) : "";
754
776
  return t === "permission-denied" || t === "firestore/permission-denied";
755
777
  }
756
- function It(e) {
778
+ function Vt(e) {
757
779
  let t = N(e)?.trim();
758
780
  if (!t) throw Error("[memi-board] boardId 가 필요합니다.");
759
781
  return t;
760
782
  }
761
- function Lt(e) {
762
- let n = Q(), r = se(), { isBoardHidden: i, getBoard: s } = Pt(), c = () => h(), l = () => It(e), u = () => o(n, c()), d = (e) => t(n, c(), e), f = (e) => a(n, c(), e);
783
+ function Ht(e) {
784
+ let n = Q(), r = se(), { isBoardHidden: i, getBoard: s } = Rt(), c = () => h(), l = () => Vt(e), u = () => o(n, c()), d = (e) => t(n, c(), e), f = (e) => a(n, c(), e);
763
785
  function p() {
764
786
  return !i(l());
765
787
  }
@@ -767,7 +789,7 @@ function Lt(e) {
767
789
  return s(l())?.editorType === "image";
768
790
  }
769
791
  function g(e) {
770
- let t = m(), n = Ct(e.content), r = wt(e.content, e.attachments);
792
+ let t = m(), n = Dt(e.content), r = Ot(e.content, e.attachments);
771
793
  if (t) {
772
794
  if (!r) throw Error("사진을 올려 주세요.");
773
795
  return;
@@ -776,12 +798,12 @@ function Lt(e) {
776
798
  if (!e.title?.trim()) throw Error("제목을 입력해 주세요.");
777
799
  }
778
800
  function _() {
779
- return L(u()).id;
801
+ return te(u()).id;
780
802
  }
781
803
  async function v(e = {}) {
782
- let t = e.pageSize ?? 20, n = [X("boardId", "==", l()), X("isPublished", "==", !0)];
783
- e.publicOnly !== !1 && n.push(X("listed", "==", !0)), n.push(W("createdAt", "desc")), e.cursor && n.push(J(e.cursor)), n.push(H(t + 1));
784
- let r = await B(G(u(), ...n)), i = r.docs.slice(0, t);
804
+ let t = e.pageSize ?? 20, n = [Y("boardId", "==", l()), Y("isPublished", "==", !0)];
805
+ e.publicOnly !== !1 && n.push(Y("listed", "==", !0)), n.push(U("createdAt", "desc")), e.cursor && n.push(q(e.cursor)), n.push(V(t + 1));
806
+ let r = await z(W(u(), ...n)), i = r.docs.slice(0, t);
785
807
  return {
786
808
  posts: i.map((e) => ({
787
809
  id: e.id,
@@ -792,7 +814,7 @@ function Lt(e) {
792
814
  };
793
815
  }
794
816
  async function y(e) {
795
- let [t, n] = await Promise.all([z(d(e)), z(f(e))]);
817
+ let [t, n] = await Promise.all([R(d(e)), R(f(e))]);
796
818
  return t.exists() ? {
797
819
  id: t.id,
798
820
  ...t.data(),
@@ -801,7 +823,7 @@ function Lt(e) {
801
823
  }
802
824
  async function x(e) {
803
825
  try {
804
- let t = (await B(G(u(), X("boardId", "==", l()), X("slug", "==", e.trim()), H(1)))).docs[0];
826
+ let t = (await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", e.trim()), V(1)))).docs[0];
805
827
  if (!t) return { status: "not-found" };
806
828
  try {
807
829
  let e = await y(t.id);
@@ -810,30 +832,54 @@ function Lt(e) {
810
832
  post: e
811
833
  } : { status: "not-found" };
812
834
  } catch (e) {
813
- return Ft(e) ? { status: "permission-denied" } : {
835
+ return Bt(e) ? { status: "permission-denied" } : {
814
836
  status: "error",
815
837
  message: e instanceof Error ? e.message : String(e)
816
838
  };
817
839
  }
818
840
  } catch (e) {
819
- return Ft(e) ? { status: "permission-denied" } : {
841
+ return Bt(e) ? { status: "permission-denied" } : {
820
842
  status: "error",
821
843
  message: e instanceof Error ? e.message : String(e)
822
844
  };
823
845
  }
824
846
  }
825
847
  async function S(e) {
848
+ let t = e.trim(), n = zt.get(`${l()}/${t}`);
849
+ if (n) return {
850
+ status: "ok",
851
+ id: n
852
+ };
853
+ try {
854
+ let e = (await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", t), V(1)))).docs[0];
855
+ return e ? {
856
+ status: "ok",
857
+ id: e.id
858
+ } : { status: "not-found" };
859
+ } catch (e) {
860
+ return Bt(e) ? { status: "permission-denied" } : {
861
+ status: "error",
862
+ message: e instanceof Error ? e.message : String(e)
863
+ };
864
+ }
865
+ }
866
+ async function C(e) {
867
+ let t = b(e.trim()) || "post", n = t, r = 1;
868
+ for (; !(await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", n), V(1)))).empty;) r++, n = `${t}-${r}`;
869
+ return n;
870
+ }
871
+ async function w(e) {
826
872
  if (!e.createdAt) return {
827
873
  previous: null,
828
874
  next: null
829
875
  };
830
876
  try {
831
877
  let t = [
832
- X("boardId", "==", l()),
833
- X("isPublished", "==", !0),
834
- ...e.listed === !1 ? [] : [X("listed", "==", !0)],
835
- W("createdAt", "desc")
836
- ], [n, r] = await Promise.all([B(G(u(), ...t, J(e.createdAt), H(1))), B(G(u(), ...t, te(e.createdAt), ne(1)))]), i = (e) => {
878
+ Y("boardId", "==", l()),
879
+ Y("isPublished", "==", !0),
880
+ ...e.listed === !1 ? [] : [Y("listed", "==", !0)],
881
+ U("createdAt", "desc")
882
+ ], [n, r] = await Promise.all([z(W(u(), ...t, q(e.createdAt), V(1))), z(W(u(), ...t, ne(e.createdAt), re(1)))]), i = (e) => {
837
883
  let t = e.docs[0];
838
884
  return t ? {
839
885
  id: t.id,
@@ -851,43 +897,36 @@ function Lt(e) {
851
897
  };
852
898
  }
853
899
  }
854
- async function C(e) {
900
+ async function T(e) {
855
901
  g(e);
856
- let t = e.postId || _(), n = m(), r, i;
857
- if (n) r = t, i = St(e.content);
858
- else {
859
- i = e.title.trim();
860
- let t = b(i) || "post";
861
- r = t;
862
- let n = 1;
863
- for (; !(await B(G(u(), X("boardId", "==", l()), X("slug", "==", r), H(1)))).empty;) n++, r = `${t}-${n}`;
864
- }
865
- let a = kt(e.content, e.attachments), o = p();
866
- return await q(d(t), {
902
+ let t = e.postId || _(), r = m(), i, a;
903
+ r ? (i = t, a = Et(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await C(a));
904
+ let o = Nt(e.content, e.attachments), s = p(), c = X(n);
905
+ return c.set(d(t), {
867
906
  boardId: l(),
868
- slug: r,
869
- title: i,
870
- ...a,
907
+ slug: i,
908
+ title: a,
909
+ ...o,
871
910
  tags: e.tags ?? [],
872
911
  attachments: e.attachments ?? [],
873
912
  commentCount: 0,
874
913
  likeCount: 0,
875
914
  viewCount: 0,
876
- listed: o,
915
+ listed: s,
877
916
  isPublished: !1,
878
917
  authorUid: e.authorUid,
879
918
  authorName: e.authorName,
880
919
  authorPhoto: e.authorPhoto,
881
920
  moderationStatus: "approved",
882
921
  moderationModel: e.moderationModel ?? null,
883
- createdAt: K(),
884
- updatedAt: K()
885
- }), await q(f(t), { content: e.content }), r;
922
+ createdAt: G(),
923
+ updatedAt: G()
924
+ }), c.set(f(t), { content: e.content }), await c.commit(), zt.set(`${l()}/${i}`, t), i;
886
925
  }
887
- async function w(e, t) {
926
+ async function E(e, t) {
888
927
  g(t);
889
- let n = m() ? St(t.content) : t.title.trim(), r = kt(t.content, t.attachments), i = p();
890
- await Promise.all([Y(d(e), {
928
+ let n = m() ? Et(t.content) : t.title.trim(), r = Nt(t.content, t.attachments), i = p();
929
+ await Promise.all([J(d(e), {
891
930
  title: n,
892
931
  ...r,
893
932
  previewImage: r.previewImage ? r.previewImage : I(),
@@ -895,34 +934,37 @@ function Lt(e) {
895
934
  tags: t.tags ?? [],
896
935
  listed: i,
897
936
  attachments: t.attachments ?? [],
898
- updatedAt: K()
899
- }), q(f(e), { content: t.content }, { merge: !0 })]);
937
+ updatedAt: G()
938
+ }), K(f(e), { content: t.content }, { merge: !0 })]);
900
939
  }
901
- async function T(e) {
902
- await Y(d(e), {
940
+ async function D(e) {
941
+ await J(d(e), {
903
942
  isPublished: !0,
904
- publishedAt: K(),
905
- updatedAt: K()
943
+ publishedAt: G(),
944
+ updatedAt: G()
906
945
  });
907
946
  }
908
- async function E(e) {
909
- await bt(n, _e(r), c(), e);
947
+ async function O(e) {
948
+ await wt(n, _e(r), c(), e);
949
+ for (let [t, n] of zt) n === e && zt.delete(t);
910
950
  }
911
951
  return {
912
952
  createPostId: _,
913
953
  getPosts: v,
914
954
  getPost: y,
915
955
  getPostBySlug: x,
916
- getAdjacentPosts: S,
917
- createPost: C,
918
- updatePost: w,
919
- publishPost: T,
920
- deletePost: E
956
+ resolvePostIdBySlug: S,
957
+ resolveUniqueSlug: C,
958
+ getAdjacentPosts: w,
959
+ createPost: T,
960
+ updatePost: E,
961
+ publishPost: D,
962
+ deletePost: O
921
963
  };
922
964
  }
923
- var Rt = 10;
924
- function zt(e, t = {}) {
925
- let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = ct(), s = () => h(), c = t.pageSize ?? Rt, l = A(() => i.value?.uid ?? ""), u = A(() => It(e)), d = () => o(n, s()), f = A(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = M([]), m = M([]), g = M([]), _ = M(!0), v = M(!0), y = M(!1), b = M(""), x = null, S = null, C, w;
965
+ var Ut = 10;
966
+ function Wt(e, t = {}) {
967
+ let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = ct(), s = () => h(), c = t.pageSize ?? Ut, l = A(() => i.value?.uid ?? ""), u = A(() => Vt(e)), d = () => o(n, s()), f = A(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = M([]), m = M([]), g = M([]), _ = M(!0), v = M(!0), y = M(!1), b = M(""), x = null, S = null, C, w;
926
968
  function T(e) {
927
969
  return e.createdAt?.toMillis?.() ?? 0;
928
970
  }
@@ -936,11 +978,11 @@ function zt(e, t = {}) {
936
978
  return [...e.values()].sort((e, t) => T(t) - T(e) || String(t.id).localeCompare(String(e.id)));
937
979
  });
938
980
  function D() {
939
- let e = [X("boardId", "==", u.value), X("isPublished", "==", !0)];
940
- return f.value && e.push(X("listed", "==", !0)), e;
981
+ let e = [Y("boardId", "==", u.value), Y("isPublished", "==", !0)];
982
+ return f.value && e.push(Y("listed", "==", !0)), e;
941
983
  }
942
984
  function O() {
943
- C?.(), C = U(G(d(), ...D(), W("createdAt", "desc"), W(R(), "desc"), H(c)), (e) => {
985
+ C?.(), C = H(W(d(), ...D(), U("createdAt", "desc"), U(L(), "desc"), V(c)), (e) => {
944
986
  p.value = e.docs.map((e) => ({
945
987
  id: e.id,
946
988
  ...e.data()
@@ -956,7 +998,7 @@ function zt(e, t = {}) {
956
998
  g.value = [];
957
999
  return;
958
1000
  }
959
- w = U(G(d(), X("boardId", "==", u.value), X("authorUid", "==", e), X("isPublished", "==", !1), W("createdAt", "desc"), H(20)), (e) => {
1001
+ w = H(W(d(), Y("boardId", "==", u.value), Y("authorUid", "==", e), Y("isPublished", "==", !1), U("createdAt", "desc"), V(20)), (e) => {
960
1002
  g.value = e.docs.map((e) => ({
961
1003
  id: e.id,
962
1004
  ...e.data()
@@ -971,11 +1013,11 @@ function zt(e, t = {}) {
971
1013
  try {
972
1014
  let e = S ?? x, t = [
973
1015
  ...D(),
974
- W("createdAt", "desc"),
975
- W(R(), "desc"),
976
- ...e ? [J(e)] : [],
977
- H(c + 1)
978
- ], n = await B(G(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
1016
+ U("createdAt", "desc"),
1017
+ U(L(), "desc"),
1018
+ ...e ? [q(e)] : [],
1019
+ V(c + 1)
1020
+ ], n = await z(W(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
979
1021
  id: e.id,
980
1022
  ...e.data()
981
1023
  })), a = new Set([...m.value, ...p.value].map((e) => e.id));
@@ -1005,8 +1047,8 @@ function zt(e, t = {}) {
1005
1047
  loadMore: ee
1006
1048
  };
1007
1049
  }
1008
- function Bt(e, n) {
1009
- let r = Q(), i = () => h(), o = A(() => It(e)), s = A(() => typeof n == "string" ? n : n.value), c = A(() => t(r, i(), s.value)), l = A(() => a(r, i(), s.value)), { data: u, pending: d } = oe(c), { data: f, pending: p } = oe(l);
1050
+ function Gt(e, n) {
1051
+ let r = Q(), i = () => h(), o = A(() => Vt(e)), s = A(() => typeof n == "string" ? n : n.value), c = A(() => t(r, i(), s.value)), l = A(() => a(r, i(), s.value)), { data: u, pending: d } = oe(c), { data: f, pending: p } = oe(l);
1010
1052
  return {
1011
1053
  post: A(() => !u.value || u.value.boardId !== o.value ? null : {
1012
1054
  ...u.value,
@@ -1018,9 +1060,9 @@ function Bt(e, n) {
1018
1060
  }
1019
1061
  //#endregion
1020
1062
  //#region src/composables/useMemiBoardUserPosts.ts
1021
- var Vt = 10;
1022
- function Ht(e, t = {}) {
1023
- let n = Q(), r = () => h(), i = () => o(n, r()), a = t.pageSize ?? Vt, s = A(() => N(e)?.trim() || ""), c = M([]), l = M([]), u = M(!0), d = M(!0), f = M(!1), p = M(""), m = null, g = null, _;
1063
+ var Kt = 10;
1064
+ function qt(e, t = {}) {
1065
+ let n = Q(), r = () => h(), i = () => o(n, r()), a = t.pageSize ?? Kt, s = A(() => N(e)?.trim() || ""), c = M([]), l = M([]), u = M(!0), d = M(!0), f = M(!1), p = M(""), m = null, g = null, _;
1024
1066
  function v(e) {
1025
1067
  return {
1026
1068
  id: e.id,
@@ -1037,9 +1079,9 @@ function Ht(e, t = {}) {
1037
1079
  });
1038
1080
  function x() {
1039
1081
  return [
1040
- X("authorUid", "==", s.value),
1041
- X("isPublished", "==", !0),
1042
- X("listed", "==", !0)
1082
+ Y("authorUid", "==", s.value),
1083
+ Y("isPublished", "==", !0),
1084
+ Y("listed", "==", !0)
1043
1085
  ];
1044
1086
  }
1045
1087
  function S() {
@@ -1047,7 +1089,7 @@ function Ht(e, t = {}) {
1047
1089
  u.value = !1;
1048
1090
  return;
1049
1091
  }
1050
- _ = U(G(i(), ...x(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
1092
+ _ = H(W(i(), ...x(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1051
1093
  c.value = e.docs.map(v), m = e.docs.at(-1) ?? null, g || (d.value = e.docs.length >= a), u.value = !1;
1052
1094
  }, (e) => {
1053
1095
  console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
@@ -1059,11 +1101,11 @@ function Ht(e, t = {}) {
1059
1101
  try {
1060
1102
  let e = g ?? m, t = [
1061
1103
  ...x(),
1062
- W("createdAt", "desc"),
1063
- W(R(), "desc"),
1064
- ...e ? [J(e)] : [],
1065
- H(a + 1)
1066
- ], n = await B(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(v), s = new Set([...l.value, ...c.value].map((e) => e.id));
1104
+ U("createdAt", "desc"),
1105
+ U(L(), "desc"),
1106
+ ...e ? [q(e)] : [],
1107
+ V(a + 1)
1108
+ ], n = await z(W(i(), ...t)), r = n.docs.slice(0, a), o = r.map(v), s = new Set([...l.value, ...c.value].map((e) => e.id));
1067
1109
  l.value.push(...o.filter((e) => !s.has(e.id))), g = r.at(-1) ?? g, d.value = n.docs.length > a;
1068
1110
  } catch (e) {
1069
1111
  p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
@@ -1086,9 +1128,9 @@ function Ht(e, t = {}) {
1086
1128
  }
1087
1129
  //#endregion
1088
1130
  //#region src/composables/useMemiBoardUserComments.ts
1089
- var Ut = 10;
1090
- function Wt(e, t = {}) {
1091
- let n = Q(), r = () => h(), i = () => E(n, r()), a = t.pageSize ?? Ut, o = A(() => N(e)?.trim() || ""), s = M([]), c = M([]), l = M(!0), u = M(!0), d = M(!1), f = M(""), p = null, m = null, g;
1131
+ var Jt = 10;
1132
+ function Yt(e, t = {}) {
1133
+ let n = Q(), r = () => h(), i = () => E(n, r()), a = t.pageSize ?? Jt, o = A(() => N(e)?.trim() || ""), s = M([]), c = M([]), l = M(!0), u = M(!0), d = M(!1), f = M(""), p = null, m = null, g;
1092
1134
  function _(e) {
1093
1135
  return {
1094
1136
  id: e.id,
@@ -1104,14 +1146,14 @@ function Wt(e, t = {}) {
1104
1146
  return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
1105
1147
  });
1106
1148
  function b() {
1107
- return [X("authorUid", "==", o.value), X("listed", "==", !0)];
1149
+ return [Y("authorUid", "==", o.value), Y("listed", "==", !0)];
1108
1150
  }
1109
1151
  function x() {
1110
1152
  if (g?.(), !o.value) {
1111
1153
  l.value = !1;
1112
1154
  return;
1113
1155
  }
1114
- g = U(G(i(), ...b(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
1156
+ g = H(W(i(), ...b(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1115
1157
  s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
1116
1158
  }, (e) => {
1117
1159
  console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
@@ -1123,11 +1165,11 @@ function Wt(e, t = {}) {
1123
1165
  try {
1124
1166
  let e = m ?? p, t = [
1125
1167
  ...b(),
1126
- W("createdAt", "desc"),
1127
- W(R(), "desc"),
1128
- ...e ? [J(e)] : [],
1129
- H(a + 1)
1130
- ], n = await B(G(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
1168
+ U("createdAt", "desc"),
1169
+ U(L(), "desc"),
1170
+ ...e ? [q(e)] : [],
1171
+ V(a + 1)
1172
+ ], n = await z(W(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
1131
1173
  c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
1132
1174
  } catch (e) {
1133
1175
  f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
@@ -1150,11 +1192,11 @@ function Wt(e, t = {}) {
1150
1192
  }
1151
1193
  //#endregion
1152
1194
  //#region src/composables/useMemiBoardCommentFeed.ts
1153
- var Gt = 10;
1154
- function Kt(e = "latest", t = {}) {
1195
+ var Xt = 10;
1196
+ function Zt(e = "latest", t = {}) {
1155
1197
  let n = Q(), r = () => h(), i = () => E(n, r()), a = A(() => {
1156
1198
  let e = Math.floor(Number(N(t.pageSize)));
1157
- return Number.isFinite(e) && e > 0 ? e : Gt;
1199
+ return Number.isFinite(e) && e > 0 ? e : Xt;
1158
1200
  }), o = A(() => N(e) === "likes" ? "likes" : "latest"), s = M([]), c = M([]), l = M(!0), u = M(!0), d = M(!1), f = M(""), p = null, m = null, g;
1159
1201
  function _(e) {
1160
1202
  return {
@@ -1179,18 +1221,18 @@ function Kt(e = "latest", t = {}) {
1179
1221
  });
1180
1222
  function x() {
1181
1223
  return o.value === "likes" ? [
1182
- X("listed", "==", !0),
1183
- W("likeCount", "desc"),
1184
- W("createdAt", "desc"),
1185
- W(R(), "desc")
1224
+ Y("listed", "==", !0),
1225
+ U("likeCount", "desc"),
1226
+ U("createdAt", "desc"),
1227
+ U(L(), "desc")
1186
1228
  ] : [
1187
- X("listed", "==", !0),
1188
- W("createdAt", "desc"),
1189
- W(R(), "desc")
1229
+ Y("listed", "==", !0),
1230
+ U("createdAt", "desc"),
1231
+ U(L(), "desc")
1190
1232
  ];
1191
1233
  }
1192
1234
  function S() {
1193
- g?.(), g = U(G(i(), ...x(), H(a.value)), (e) => {
1235
+ g?.(), g = H(W(i(), ...x(), V(a.value)), (e) => {
1194
1236
  s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
1195
1237
  }, (e) => {
1196
1238
  console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
@@ -1200,7 +1242,7 @@ function Kt(e = "latest", t = {}) {
1200
1242
  if (!(d.value || !u.value || l.value)) {
1201
1243
  d.value = !0, f.value = "";
1202
1244
  try {
1203
- let e = m ?? p, t = await B(G(i(), ...x(), ...e ? [J(e)] : [], H(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(_), o = new Set([...c.value, ...s.value].map((e) => e.id));
1245
+ let e = m ?? p, t = await z(W(i(), ...x(), ...e ? [q(e)] : [], V(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(_), o = new Set([...c.value, ...s.value].map((e) => e.id));
1204
1246
  c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
1205
1247
  } catch (e) {
1206
1248
  f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
@@ -1224,9 +1266,9 @@ function Kt(e = "latest", t = {}) {
1224
1266
  }
1225
1267
  //#endregion
1226
1268
  //#region src/composables/useMemiBoardAuthorMemo.ts
1227
- var qt = 100, Jt = /* @__PURE__ */ new Map();
1269
+ var Qt = 100, $t = /* @__PURE__ */ new Map();
1228
1270
  function $(e) {
1229
- let t = Jt.get(e);
1271
+ let t = $t.get(e);
1230
1272
  return t || (t = ee({
1231
1273
  text: "",
1232
1274
  sentiment: null,
@@ -1234,9 +1276,9 @@ function $(e) {
1234
1276
  pending: !1,
1235
1277
  saving: !1,
1236
1278
  error: ""
1237
- }), Jt.set(e, t)), t;
1279
+ }), $t.set(e, t)), t;
1238
1280
  }
1239
- function Yt(e) {
1281
+ function en(e) {
1240
1282
  let t = Q(), n = () => h(), { user: r } = ct(), i = A(() => N(e)), a = A(() => `${r.value?.uid ?? ""}:${i.value}`), o = A(() => {
1241
1283
  let e = r.value?.uid, a = i.value;
1242
1284
  return !e || !a ? null : f(t, n(), e, a);
@@ -1252,7 +1294,7 @@ function Yt(e) {
1252
1294
  let t = $(a.value);
1253
1295
  t.pending = !0, t.error = "";
1254
1296
  try {
1255
- let n = (await z(e)).data();
1297
+ let n = (await R(e)).data();
1256
1298
  t.text = n ? n.text ?? "" : "", t.sentiment = n ? n.sentiment ?? null : null, t.loaded = !0;
1257
1299
  } catch (e) {
1258
1300
  t.error = e.message || String(e), console.error("[memi-board:authorMemo] load failed", e);
@@ -1268,10 +1310,10 @@ function Yt(e) {
1268
1310
  let i = $(a.value);
1269
1311
  i.saving = !0, i.error = "";
1270
1312
  try {
1271
- await q(n, {
1313
+ await K(n, {
1272
1314
  text: r,
1273
1315
  sentiment: t,
1274
- updatedAt: K()
1316
+ updatedAt: G()
1275
1317
  }), i.text = r, i.sentiment = t, i.loaded = !0;
1276
1318
  } catch (e) {
1277
1319
  throw i.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
@@ -1306,15 +1348,15 @@ function Yt(e) {
1306
1348
  }
1307
1349
  //#endregion
1308
1350
  //#region src/composables/useMemiBoardComments.ts
1309
- var Xt = 10, Zt = 5, Qt = 1e3;
1310
- function $t(e) {
1351
+ var tn = 10, nn = 5, rn = 1e3;
1352
+ function an(e) {
1311
1353
  let t = e.trim();
1312
1354
  if (!t) throw Error("댓글 내용을 입력해 주세요.");
1313
- if (t.length > 1e3) throw Error(`댓글은 ${Qt.toLocaleString()}자까지 작성할 수 있습니다.`);
1355
+ if (t.length > 1e3) throw Error(`댓글은 ${rn.toLocaleString()}자까지 작성할 수 있습니다.`);
1314
1356
  return t;
1315
1357
  }
1316
- function en(e, n, r = {}) {
1317
- let i = Q(), a = () => h(), { isBoardHidden: o } = Pt(), c = () => E(i, a()), l = A(() => N(e)), u = A(() => N(n)), d = () => !o(l.value), f = M([]), p = M([]), m = M(r.subscribe !== !1), g = M([]), _ = M(!1), v = M(r.subscribe !== !1), y = M(r.subscribe !== !1), b = null, x, S;
1358
+ function on(e, n, r = {}) {
1359
+ let i = Q(), a = () => h(), { isBoardHidden: o } = Rt(), c = () => E(i, a()), l = A(() => N(e)), u = A(() => N(n)), d = () => !o(l.value), f = M([]), p = M([]), m = M(r.subscribe !== !1), g = M([]), _ = M(!1), v = M(r.subscribe !== !1), y = M(r.subscribe !== !1), b = null, x, S;
1318
1360
  function C(e) {
1319
1361
  return e.createdAt?.toMillis?.() ?? 0;
1320
1362
  }
@@ -1331,7 +1373,7 @@ function en(e, n, r = {}) {
1331
1373
  if (g.value = [], f.value = [], p.value = [], b = null, clearTimeout(x), x = void 0, S?.(), S = void 0, v.value = r.subscribe !== !1, r.subscribe !== !1) {
1332
1374
  m.value = !0, y.value = !0;
1333
1375
  try {
1334
- let t = B(G(c(), X("postId", "==", e), W("createdAt", "desc"), W(R(), "desc")));
1376
+ let t = z(W(c(), Y("postId", "==", e), U("createdAt", "desc"), U(L(), "desc")));
1335
1377
  if (await Promise.all([t.then((t) => {
1336
1378
  if (u.value !== e) return;
1337
1379
  let n = t.docs.map((e) => ({
@@ -1346,7 +1388,7 @@ function en(e, n, r = {}) {
1346
1388
  }
1347
1389
  }, { immediate: !0 });
1348
1390
  function T() {
1349
- S?.(), S = U(G(c(), X("postId", "==", u.value), X("parentId", "==", null), W("createdAt", "desc"), W(R(), "desc"), H(1)), (e) => {
1391
+ S?.(), S = H(W(c(), Y("postId", "==", u.value), Y("parentId", "==", null), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
1350
1392
  let t = new Map(f.value.map((e) => [e.id, e]));
1351
1393
  for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
1352
1394
  id: n.doc.id,
@@ -1362,17 +1404,17 @@ function en(e, n, r = {}) {
1362
1404
  _.value = !0;
1363
1405
  try {
1364
1406
  let e = [
1365
- X("postId", "==", u.value),
1366
- X("parentId", "==", null),
1367
- W("createdAt", "asc"),
1368
- W(R(), "asc"),
1369
- ...b ? [J(b)] : [],
1370
- H(11)
1371
- ], t = await B(G(c(), ...e)), n = t.docs.slice(0, Xt), r = n.map((e) => ({
1407
+ Y("postId", "==", u.value),
1408
+ Y("parentId", "==", null),
1409
+ U("createdAt", "asc"),
1410
+ U(L(), "asc"),
1411
+ ...b ? [q(b)] : [],
1412
+ V(11)
1413
+ ], t = await z(W(c(), ...e)), n = t.docs.slice(0, tn), r = n.map((e) => ({
1372
1414
  id: e.id,
1373
1415
  ...e.data()
1374
1416
  })), i = new Set(g.value.map((e) => e.id));
1375
- g.value.push(...r.filter((e) => !i.has(e.id))), b = n.at(-1) ?? b, t.size <= Xt && (v.value = !1, x = setTimeout(() => {
1417
+ g.value.push(...r.filter((e) => !i.has(e.id))), b = n.at(-1) ?? b, t.size <= tn && (v.value = !1, x = setTimeout(() => {
1376
1418
  x = void 0, T();
1377
1419
  }, 1e3));
1378
1420
  } finally {
@@ -1384,7 +1426,7 @@ function en(e, n, r = {}) {
1384
1426
  clearTimeout(x), S?.();
1385
1427
  });
1386
1428
  async function O(e) {
1387
- let n = $t(e.body), r = Z(i), o = L(c());
1429
+ let n = an(e.body), r = X(i), o = te(c());
1388
1430
  r.set(o, {
1389
1431
  postId: u.value,
1390
1432
  boardId: l.value,
@@ -1402,14 +1444,14 @@ function en(e, n, r = {}) {
1402
1444
  replyCount: 0,
1403
1445
  likeCount: 0,
1404
1446
  isReply: !1,
1405
- createdAt: K(),
1406
- updatedAt: K()
1407
- }), r.update(t(i, a(), u.value), { commentCount: V(1) }), await r.commit();
1447
+ createdAt: G(),
1448
+ updatedAt: G()
1449
+ }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
1408
1450
  }
1409
1451
  async function k(e) {
1410
- let n = $t(e.body);
1452
+ let n = an(e.body);
1411
1453
  if (!e.parent.id) throw Error("답글 대상 댓글을 찾을 수 없습니다.");
1412
- let r = Z(i), o = L(c()), f = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
1454
+ let r = X(i), o = te(c()), f = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
1413
1455
  if (!f) throw Error("댓글 스레드를 찾을 수 없습니다.");
1414
1456
  let p = Math.min((e.parent.depth ?? 0) + 1, 2);
1415
1457
  r.set(o, {
@@ -1429,28 +1471,28 @@ function en(e, n, r = {}) {
1429
1471
  replyCount: 0,
1430
1472
  likeCount: 0,
1431
1473
  isReply: !0,
1432
- createdAt: K(),
1433
- updatedAt: K()
1434
- }), r.update(s(i, a(), f), { replyCount: V(1) }), r.update(t(i, a(), u.value), { commentCount: V(1) }), await r.commit();
1474
+ createdAt: G(),
1475
+ updatedAt: G()
1476
+ }), r.update(s(i, a(), f), { replyCount: B(1) }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
1435
1477
  }
1436
1478
  async function ee(e) {
1437
1479
  if (!e.id) return;
1438
1480
  if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error("답글이 있는 댓글은 현재 삭제할 수 없습니다.");
1439
- await yt(i, a(), e.id);
1440
- let n = Z(i);
1441
- n.delete(s(i, a(), e.id)), e.parentId && e.rootId && n.update(s(i, a(), e.rootId), { replyCount: V(-1) }), n.update(t(i, a(), u.value), { commentCount: V(-1) }), await n.commit(), g.value = g.value.filter((t) => t.id !== e.id), p.value = p.value.filter((t) => t.id !== e.id), f.value = f.value.filter((t) => t.id !== e.id);
1481
+ await Ct(i, a(), e.id);
1482
+ let n = X(i);
1483
+ n.delete(s(i, a(), e.id)), e.parentId && e.rootId && n.update(s(i, a(), e.rootId), { replyCount: B(-1) }), n.update(t(i, a(), u.value), { commentCount: B(-1) }), await n.commit(), g.value = g.value.filter((t) => t.id !== e.id), p.value = p.value.filter((t) => t.id !== e.id), f.value = f.value.filter((t) => t.id !== e.id);
1442
1484
  }
1443
1485
  async function F(e, t) {
1444
- let n = $t(t);
1445
- await Y(s(i, a(), e), {
1486
+ let n = an(t);
1487
+ await J(s(i, a(), e), {
1446
1488
  body: n,
1447
- updatedAt: K()
1489
+ updatedAt: G()
1448
1490
  });
1449
1491
  }
1450
1492
  async function I(e, t, n) {
1451
- await Y(s(i, a(), e), {
1493
+ await J(s(i, a(), e), {
1452
1494
  isBlinded: t,
1453
- moderatedAt: K(),
1495
+ moderatedAt: G(),
1454
1496
  moderatedBy: n
1455
1497
  });
1456
1498
  }
@@ -1467,13 +1509,13 @@ function en(e, n, r = {}) {
1467
1509
  deleteComment: ee
1468
1510
  };
1469
1511
  }
1470
- function tn(e, t, n) {
1512
+ function sn(e, t, n) {
1471
1513
  let r = Q(), i = () => h(), a = () => E(r, i()), o = t.trim(), s = M([]), c = M(!1), l = M(!1), u = M(!0), d = null, f;
1472
1514
  function p(e) {
1473
1515
  return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
1474
1516
  }
1475
1517
  function m() {
1476
- f ||= U(G(a(), X("postId", "==", o), X("rootId", "==", n), X("isReply", "==", !0), W("createdAt", "desc"), W(R(), "desc"), H(1)), (e) => {
1518
+ f ||= H(W(a(), Y("postId", "==", o), Y("rootId", "==", n), Y("isReply", "==", !0), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
1477
1519
  let t = new Map(s.value.map((e) => [e.id, e]));
1478
1520
  for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
1479
1521
  id: n.doc.id,
@@ -1489,18 +1531,18 @@ function tn(e, t, n) {
1489
1531
  c.value = !0;
1490
1532
  try {
1491
1533
  let e = [
1492
- X("postId", "==", o),
1493
- X("rootId", "==", n),
1494
- X("isReply", "==", !0),
1495
- W("createdAt", "asc"),
1496
- W(R(), "asc"),
1497
- ...d ? [J(d)] : [],
1498
- H(6)
1499
- ], t = await B(G(a(), ...e)), r = new Set(s.value.map((e) => e.id)), i = t.docs.slice(0, Zt), c = i.map((e) => ({
1534
+ Y("postId", "==", o),
1535
+ Y("rootId", "==", n),
1536
+ Y("isReply", "==", !0),
1537
+ U("createdAt", "asc"),
1538
+ U(L(), "asc"),
1539
+ ...d ? [q(d)] : [],
1540
+ V(6)
1541
+ ], t = await z(W(a(), ...e)), r = new Set(s.value.map((e) => e.id)), i = t.docs.slice(0, nn), c = i.map((e) => ({
1500
1542
  id: e.id,
1501
1543
  ...e.data()
1502
1544
  })).filter((e) => !r.has(e.id));
1503
- s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <= Zt && (u.value = !1, m());
1545
+ s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <= nn && (u.value = !1, m());
1504
1546
  } finally {
1505
1547
  c.value = !1;
1506
1548
  }
@@ -1523,8 +1565,8 @@ function tn(e, t, n) {
1523
1565
  }
1524
1566
  //#endregion
1525
1567
  //#region src/composables/useMemiBoardLikes.ts
1526
- function nn(e, n) {
1527
- let r = () => h(), i = Q(), a = ae(), o = M(!1), s = M(!1), c;
1568
+ function cn(e, n) {
1569
+ let r = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
1528
1570
  function l(e) {
1529
1571
  return k(i, r(), n, e);
1530
1572
  }
@@ -1533,7 +1575,7 @@ function nn(e, n) {
1533
1575
  o.value = !1;
1534
1576
  return;
1535
1577
  }
1536
- c = U(l(e.uid), (e) => {
1578
+ c = H(l(e.uid), (e) => {
1537
1579
  o.value = e.exists();
1538
1580
  }, (e) => {
1539
1581
  console.error("[memi-board:likes] onSnapshot failed", e);
@@ -1546,12 +1588,12 @@ function nn(e, n) {
1546
1588
  s.value = !0;
1547
1589
  try {
1548
1590
  let a = l(c), o = t(i, r(), n);
1549
- return await re(i, async (t) => (await t.get(a)).exists() ? (t.delete(a), t.update(o, { likeCount: V(-1) }), !1) : (t.set(a, {
1591
+ return await ie(i, async (t) => (await t.get(a)).exists() ? (t.delete(a), t.update(o, { likeCount: B(-1) }), !1) : (t.set(a, {
1550
1592
  uid: c,
1551
1593
  postId: n,
1552
1594
  boardId: e,
1553
- createdAt: K()
1554
- }), t.update(o, { likeCount: V(1) }), !0));
1595
+ createdAt: G()
1596
+ }), t.update(o, { likeCount: B(1) }), !0));
1555
1597
  } finally {
1556
1598
  s.value = !1;
1557
1599
  }
@@ -1562,11 +1604,11 @@ function nn(e, n) {
1562
1604
  toggleLike: u
1563
1605
  };
1564
1606
  }
1565
- var rn = Symbol.for("memi-board:comment-likes");
1566
- function an(e, t) {
1567
- let n = () => h(), r = Q(), i = ae(), a = A(() => N(e)), o = A(() => N(t)), c = M(/* @__PURE__ */ new Set()), l = M(null), u;
1607
+ var ln = Symbol.for("memi-board:comment-likes");
1608
+ function un(e, t) {
1609
+ let n = () => h(), r = Q(), i = Z(), a = A(() => N(e)), o = A(() => N(t)), c = M(/* @__PURE__ */ new Set()), l = M(null), u;
1568
1610
  P([i, o], ([e, t]) => {
1569
- u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u = U(G(O(r, n()), X("uid", "==", e.uid), X("postId", "==", t), X("target", "==", "comment")), (e) => {
1611
+ u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u = H(W(O(r, n()), Y("uid", "==", e.uid), Y("postId", "==", t), Y("target", "==", "comment")), (e) => {
1570
1612
  let t = /* @__PURE__ */ new Set();
1571
1613
  for (let n of e.docs) {
1572
1614
  let e = n.data().commentId;
@@ -1590,7 +1632,7 @@ function an(e, t) {
1590
1632
  if (l.value) return d(e);
1591
1633
  l.value = e;
1592
1634
  try {
1593
- let i = k(r, n(), e, t), l = s(r, n(), e), u = await re(r, async (n) => {
1635
+ let i = k(r, n(), e, t), l = s(r, n(), e), u = await ie(r, async (n) => {
1594
1636
  let r = await n.get(i), s = await n.get(l);
1595
1637
  if (!s.exists()) throw Error("댓글을 찾을 수 없습니다.");
1596
1638
  let c = Number(s.data()?.likeCount ?? 0);
@@ -1600,7 +1642,7 @@ function an(e, t) {
1600
1642
  boardId: a.value,
1601
1643
  commentId: e,
1602
1644
  target: "comment",
1603
- createdAt: K()
1645
+ createdAt: G()
1604
1646
  }), n.update(l, { likeCount: c + 1 }), !0);
1605
1647
  }), d = new Set(c.value);
1606
1648
  return u ? d.add(e) : d.delete(e), c.value = d, u;
@@ -1616,7 +1658,7 @@ function an(e, t) {
1616
1658
  }
1617
1659
  //#endregion
1618
1660
  //#region src/composables/useMemiBoardReports.ts
1619
- var on = 200, sn = [
1661
+ var dn = 200, fn = [
1620
1662
  {
1621
1663
  value: "spam",
1622
1664
  label: "스팸·광고"
@@ -1638,17 +1680,17 @@ var on = 200, sn = [
1638
1680
  label: "기타"
1639
1681
  }
1640
1682
  ];
1641
- function cn(e) {
1642
- return sn.find((t) => t.value === e)?.label || e || "신고";
1683
+ function pn(e) {
1684
+ return fn.find((t) => t.value === e)?.label || e || "신고";
1643
1685
  }
1644
- function ln(e, t) {
1645
- let n = () => h(), i = Q(), a = ae(), o = M(!1), s = M(!1), c;
1686
+ function mn(e, t) {
1687
+ let n = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
1646
1688
  P(a, (e) => {
1647
1689
  if (c?.(), c = void 0, !e) {
1648
1690
  o.value = !1;
1649
1691
  return;
1650
1692
  }
1651
- c = U(r(i, n(), t, e.uid), (e) => {
1693
+ c = H(r(i, n(), t, e.uid), (e) => {
1652
1694
  o.value = e.exists();
1653
1695
  }, (e) => {
1654
1696
  console.error("[memi-board:reports] onSnapshot failed", e);
@@ -1659,13 +1701,13 @@ function ln(e, t) {
1659
1701
  if (!l) throw Error("로그인이 필요합니다.");
1660
1702
  if (s.value) return;
1661
1703
  if (c.authorUid && c.authorUid === l) throw Error("자신의 글은 신고할 수 없습니다.");
1662
- let u = sn.some((e) => e.value === c.reason) ? c.reason : null;
1704
+ let u = fn.some((e) => e.value === c.reason) ? c.reason : null;
1663
1705
  if (!u) throw Error("신고 사유를 선택해 주세요.");
1664
1706
  let d = (c.detail || "").trim();
1665
1707
  if (d.length > 200) throw Error("자세한 내용은 200자까지입니다.");
1666
1708
  s.value = !0;
1667
1709
  try {
1668
- await q(r(i, n(), t, l), {
1710
+ await K(r(i, n(), t, l), {
1669
1711
  uid: l,
1670
1712
  target: "post",
1671
1713
  postId: t,
@@ -1676,7 +1718,7 @@ function ln(e, t) {
1676
1718
  postTitle: (c.postTitle || "").trim().slice(0, 200),
1677
1719
  authorUid: c.authorUid || "",
1678
1720
  authorName: c.authorName ?? null,
1679
- createdAt: K()
1721
+ createdAt: G()
1680
1722
  }), o.value = !0;
1681
1723
  } finally {
1682
1724
  s.value = !1;
@@ -1688,9 +1730,9 @@ function ln(e, t) {
1688
1730
  submitReport: l
1689
1731
  };
1690
1732
  }
1691
- var un = 20;
1692
- function dn(e = {}) {
1693
- let t = () => h(), n = Q(), { canManageContent: a, canManageBoard: o } = ct(), s = e.pageSize ?? un, c = A(() => N(e.boardId)?.trim() || ""), l = M([]), u = M(!0), d = M(!1), f = M(!1), p = M(""), m = null, g;
1733
+ var hn = 20;
1734
+ function gn(e = {}) {
1735
+ let t = () => h(), n = Q(), { canManageContent: a, canManageBoard: o } = ct(), s = e.pageSize ?? hn, c = A(() => N(e.boardId)?.trim() || ""), l = M([]), u = M(!0), d = M(!1), f = M(!1), p = M(""), m = null, g;
1694
1736
  function _(e) {
1695
1737
  return {
1696
1738
  id: e.id,
@@ -1703,8 +1745,8 @@ function dn(e = {}) {
1703
1745
  return;
1704
1746
  }
1705
1747
  u.value = !0;
1706
- let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")];
1707
- g = U(G(i(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), H(s)), (e) => {
1748
+ let e = c.value ? [Y("status", "==", "open"), Y("boardId", "==", c.value)] : [Y("status", "==", "open"), Y("target", "==", "post")];
1749
+ g = H(W(i(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), V(s)), (e) => {
1708
1750
  l.value = e.docs.map(_).filter((e) => o(e.boardId)), m = e.docs.at(-1) ?? null, f.value = e.docs.length >= s, u.value = !1;
1709
1751
  }, (e) => {
1710
1752
  console.error("[memi-board:report-queue] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
@@ -1715,7 +1757,7 @@ function dn(e = {}) {
1715
1757
  if (!d.value && f.value && m && a.value) {
1716
1758
  d.value = !0, p.value = "";
1717
1759
  try {
1718
- let e = c.value ? [X("status", "==", "open"), X("boardId", "==", c.value)] : [X("status", "==", "open"), X("target", "==", "post")], r = await B(G(i(n, t()), ...e, W("createdAt", "desc"), W(R(), "desc"), J(m), H(s + 1))), a = r.docs.slice(0, s), u = new Set(l.value.map((e) => e.id));
1760
+ let e = c.value ? [Y("status", "==", "open"), Y("boardId", "==", c.value)] : [Y("status", "==", "open"), Y("target", "==", "post")], r = await z(W(i(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), q(m), V(s + 1))), a = r.docs.slice(0, s), u = new Set(l.value.map((e) => e.id));
1719
1761
  l.value.push(...a.map(_).filter((e) => !u.has(e.id) && o(e.boardId))), m = a.at(-1) ?? m, f.value = r.docs.length > s;
1720
1762
  } catch (e) {
1721
1763
  p.value = e.message || String(e);
@@ -1725,10 +1767,10 @@ function dn(e = {}) {
1725
1767
  }
1726
1768
  }
1727
1769
  async function b(e, i) {
1728
- e.id && o(e.boardId) && await Y(r(n, t(), e.postId, e.uid), {
1770
+ e.id && o(e.boardId) && await J(r(n, t(), e.postId, e.uid), {
1729
1771
  status: i,
1730
- reviewedAt: K(),
1731
- reviewedBy: ae().value?.uid || ""
1772
+ reviewedAt: G(),
1773
+ reviewedBy: Z().value?.uid || ""
1732
1774
  });
1733
1775
  }
1734
1776
  return {
@@ -1744,7 +1786,7 @@ function dn(e = {}) {
1744
1786
  }
1745
1787
  //#endregion
1746
1788
  //#region src/composables/useMemiBoardViews.ts
1747
- function fn() {
1789
+ function _n() {
1748
1790
  let e = () => h(), n = Q();
1749
1791
  function r(t, n) {
1750
1792
  let { postsCollection: r } = e();
@@ -1768,7 +1810,7 @@ function fn() {
1768
1810
  if (c && l && !i(c, l)) {
1769
1811
  a(c, l);
1770
1812
  try {
1771
- await Y(t(n, e(), l), { viewCount: V(1) });
1813
+ await J(t(n, e(), l), { viewCount: B(1) });
1772
1814
  } catch (e) {
1773
1815
  try {
1774
1816
  sessionStorage.removeItem(r(c, l));
@@ -1784,7 +1826,7 @@ function fn() {
1784
1826
  }
1785
1827
  //#endregion
1786
1828
  //#region src/utils/moderation-prompt.ts
1787
- var pn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\n아래 텍스트에 욕설·비속어·성희롱·혐오·위협·스팸·도배성 광고가 있으면 반드시 거부(flagged=true)합니다.\n\nflagged=true 예:\n- 욕설/비속어: 씨발, 시발, 병신, 지랄, 좆, 개새끼, 존나, fuck, shit, bitch 등\n- 성적 모욕, 혐오 발언, 협박\n- 게시판 주제와 무관한 도배성 광고/스팸\n\nflagged=false:\n- 게시판 주제에 맞는 정상적인 글/댓글 (강한 의견이나 정당한 비판은 허용)\n\nJSON만 출력:\n{\"flagged\":boolean,\"category\":\"none\"|\"abuse\"|\"spam\"|\"adult\"|\"violence\"|\"other\",\"reason\":string}\n- flagged=true면 category를 고르고, reason은 한국어로 **무엇이 문제인지** 구체적으로 1문장\n (예: \"욕설(비속어)이 포함되어 게시할 수 없습니다.\", \"광고·스팸성 문구가 있어 게시할 수 없습니다.\")\n 욕설 단어 전체를 그대로 길게 인용하지 말고, 유형(욕설/혐오/스팸 등)을 분명히 밝힌다.\n- flagged=false면 category는 \"none\", reason은 \"\"", mn = {
1829
+ var vn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\n아래 텍스트에 욕설·비속어·성희롱·혐오·위협·스팸·도배성 광고가 있으면 반드시 거부(flagged=true)합니다.\n\nflagged=true 예:\n- 욕설/비속어: 씨발, 시발, 병신, 지랄, 좆, 개새끼, 존나, fuck, shit, bitch 등\n- 성적 모욕, 혐오 발언, 협박\n- 게시판 주제와 무관한 도배성 광고/스팸\n\nflagged=false:\n- 게시판 주제에 맞는 정상적인 글/댓글 (강한 의견이나 정당한 비판은 허용)\n\nJSON만 출력:\n{\"flagged\":boolean,\"category\":\"none\"|\"abuse\"|\"spam\"|\"adult\"|\"violence\"|\"other\",\"reason\":string}\n- flagged=true면 category를 고르고, reason은 한국어로 **무엇이 문제인지** 구체적으로 1문장\n (예: \"욕설(비속어)이 포함되어 게시할 수 없습니다.\", \"광고·스팸성 문구가 있어 게시할 수 없습니다.\")\n 욕설 단어 전체를 그대로 길게 인용하지 말고, 유형(욕설/혐오/스팸 등)을 분명히 밝힌다.\n- flagged=false면 category는 \"none\", reason은 \"\"", yn = {
1788
1830
  abuse: "욕설·비속어·모욕",
1789
1831
  spam: "스팸·광고",
1790
1832
  adult: "선정적·성인 내용",
@@ -1792,17 +1834,17 @@ var pn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
1792
1834
  other: "부적절한 내용",
1793
1835
  none: ""
1794
1836
  };
1795
- function hn(e) {
1837
+ function bn(e) {
1796
1838
  if (e.via === "local" && e.localHit) {
1797
1839
  let t = e.localHit.trim();
1798
1840
  return t.length > 0 && t.length <= 12 ? `「${t}」 같은 표현은 사용할 수 없습니다. 다른 말로 바꿔 주세요.` : "욕설·비속어가 포함되어 게시할 수 없습니다. 표현을 바꿔 주세요.";
1799
1841
  }
1800
1842
  let t = (e.reason || "").trim();
1801
1843
  if (t) return t;
1802
- let n = e.category && e.category !== "none" ? mn[e.category] || e.category : "";
1844
+ let n = e.category && e.category !== "none" ? yn[e.category] || e.category : "";
1803
1845
  return n ? `${n}이(가) 포함되어 게시할 수 없습니다. 내용을 수정해 주세요.` : "게시할 수 없는 내용이 포함되어 있습니다. 내용을 수정해 주세요.";
1804
1846
  }
1805
- var gn = [
1847
+ var xn = [
1806
1848
  "씨발",
1807
1849
  "시발",
1808
1850
  "시이발",
@@ -1828,10 +1870,10 @@ var gn = [
1828
1870
  "bitch",
1829
1871
  "asshole"
1830
1872
  ];
1831
- function _n(e) {
1873
+ function Sn(e) {
1832
1874
  return new RegExp(e.join("|"), "i");
1833
1875
  }
1834
- var vn = /* @__PURE__ */ new Set([
1876
+ var Cn = /* @__PURE__ */ new Set([
1835
1877
  "none",
1836
1878
  "abuse",
1837
1879
  "spam",
@@ -1839,7 +1881,7 @@ var vn = /* @__PURE__ */ new Set([
1839
1881
  "violence",
1840
1882
  "other"
1841
1883
  ]);
1842
- function yn(e) {
1884
+ function wn(e) {
1843
1885
  let t = e.trim();
1844
1886
  if (!t) return null;
1845
1887
  let n;
@@ -1857,7 +1899,7 @@ function yn(e) {
1857
1899
  if (typeof n != "object" || !n) return null;
1858
1900
  let r = n;
1859
1901
  if (typeof r.flagged != "boolean") return null;
1860
- let i = typeof r.category == "string" && vn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
1902
+ let i = typeof r.category == "string" && Cn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
1861
1903
  return {
1862
1904
  flagged: r.flagged,
1863
1905
  category: i,
@@ -1866,20 +1908,20 @@ function yn(e) {
1866
1908
  }
1867
1909
  //#endregion
1868
1910
  //#region src/composables/useMemiBoardModeration.ts
1869
- var bn = {
1911
+ var Tn = {
1870
1912
  flagged: !1,
1871
1913
  category: "none",
1872
1914
  reason: "",
1873
1915
  via: "empty"
1874
1916
  };
1875
- function xn() {
1876
- let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a = _n([...gn, ...e.localBlocklist ?? []]);
1917
+ function En() {
1918
+ let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a = Sn([...xn, ...e.localBlocklist ?? []]);
1877
1919
  function o(e) {
1878
1920
  let t = e.match(a);
1879
1921
  return t ? {
1880
1922
  flagged: !0,
1881
1923
  category: "abuse",
1882
- reason: hn({
1924
+ reason: bn({
1883
1925
  via: "local",
1884
1926
  localHit: t[0] || "",
1885
1927
  category: "abuse"
@@ -1894,7 +1936,7 @@ function xn() {
1894
1936
  });
1895
1937
  return Ce(i, {
1896
1938
  model: n,
1897
- systemInstruction: pn,
1939
+ systemInstruction: vn,
1898
1940
  generationConfig: {
1899
1941
  temperature: 0,
1900
1942
  maxOutputTokens: 256,
@@ -1923,7 +1965,7 @@ function xn() {
1923
1965
  };
1924
1966
  }
1925
1967
  function u(e, t = "") {
1926
- let n = hn({
1968
+ let n = bn({
1927
1969
  reason: e.reason,
1928
1970
  category: e.category,
1929
1971
  via: e.via
@@ -1951,26 +1993,26 @@ function xn() {
1951
1993
  };
1952
1994
  let a = t.trim();
1953
1995
  if (!a) return {
1954
- ...bn,
1996
+ ...Tn,
1955
1997
  via: "empty"
1956
1998
  };
1957
1999
  if (i?.skipFilter) return {
1958
- ...bn,
2000
+ ...Tn,
1959
2001
  via: "admin-override"
1960
2002
  };
1961
2003
  let c = o(a);
1962
2004
  if (c) return d(c);
1963
2005
  if (e.enabled === !1) return {
1964
- ...bn,
2006
+ ...Tn,
1965
2007
  via: "disabled"
1966
2008
  };
1967
2009
  try {
1968
- let e = yn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
2010
+ let e = wn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
1969
2011
  if (!e) return l();
1970
2012
  let t = {
1971
2013
  flagged: e.flagged,
1972
2014
  category: e.category,
1973
- reason: hn({
2015
+ reason: bn({
1974
2016
  reason: e.reason,
1975
2017
  category: e.category,
1976
2018
  via: "ai"
@@ -1990,14 +2032,14 @@ function xn() {
1990
2032
  via: "restricted"
1991
2033
  };
1992
2034
  if (e.enabled === !1 || !e.moderateImages) return {
1993
- ...bn,
2035
+ ...Tn,
1994
2036
  via: "disabled"
1995
2037
  };
1996
2038
  try {
1997
2039
  let e = await new Promise((e, n) => {
1998
2040
  let r = new FileReader();
1999
2041
  r.onload = () => e(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(t);
2000
- }), n = yn((await s().generateContent([{ inlineData: {
2042
+ }), n = wn((await s().generateContent([{ inlineData: {
2001
2043
  mimeType: t.type || "image/jpeg",
2002
2044
  data: e
2003
2045
  } }, "이 이미지를 심사해 주세요."])).response.text());
@@ -2005,7 +2047,7 @@ function xn() {
2005
2047
  let r = {
2006
2048
  flagged: n.flagged,
2007
2049
  category: n.category,
2008
- reason: hn({
2050
+ reason: bn({
2009
2051
  reason: n.reason,
2010
2052
  category: n.category,
2011
2053
  via: "ai"
@@ -2024,7 +2066,7 @@ function xn() {
2024
2066
  }
2025
2067
  //#endregion
2026
2068
  //#region src/composables/useMemiBoardUsers.ts
2027
- var Sn = [
2069
+ var Dn = [
2028
2070
  {
2029
2071
  value: "admin",
2030
2072
  label: "관리자",
@@ -2041,13 +2083,13 @@ var Sn = [
2041
2083
  description: "글과 댓글을 작성하고 본인이 작성한 콘텐츠만 수정·삭제할 수 있습니다."
2042
2084
  }
2043
2085
  ];
2044
- function Cn(e = {}) {
2045
- let t = () => h(), n = Q(), r = A(() => N(e.enabled) ?? !0 ? p(n, t()) : null), i = ie(r, { ssrKey: S(t(), "users-management") });
2086
+ function On(e = {}) {
2087
+ let t = () => h(), n = Q(), r = A(() => N(e.enabled) ?? !0 ? p(n, t()) : null), i = ae(r, { ssrKey: S(t(), "users-management") });
2046
2088
  async function a(e, r) {
2047
- if (!Sn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
2048
- await Y(y(n, t(), e), {
2089
+ if (!Dn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
2090
+ await J(y(n, t(), e), {
2049
2091
  role: r,
2050
- updatedAt: K()
2092
+ updatedAt: G()
2051
2093
  });
2052
2094
  }
2053
2095
  return {
@@ -2058,7 +2100,7 @@ function Cn(e = {}) {
2058
2100
  }
2059
2101
  //#endregion
2060
2102
  //#region src/composables/useMemiBoardUserProfile.ts
2061
- function wn(e) {
2103
+ function kn(e) {
2062
2104
  let t = Q(), n = () => h(), r = A(() => N(e)), i = A(() => {
2063
2105
  let e = r.value;
2064
2106
  return e ? y(t, n(), e) : null;
@@ -2070,7 +2112,7 @@ function wn(e) {
2070
2112
  }
2071
2113
  //#endregion
2072
2114
  //#region src/utils/section.ts
2073
- var Tn = [
2115
+ var An = [
2074
2116
  3,
2075
2117
  4,
2076
2118
  5,
@@ -2079,7 +2121,7 @@ var Tn = [
2079
2121
  8,
2080
2122
  9,
2081
2123
  12
2082
- ], En = [
2124
+ ], jn = [
2083
2125
  {
2084
2126
  value: "list",
2085
2127
  label: "게시목록"
@@ -2092,24 +2134,24 @@ var Tn = [
2092
2134
  value: "comments",
2093
2135
  label: "댓글모음"
2094
2136
  }
2095
- ], Dn = [{
2137
+ ], Mn = [{
2096
2138
  value: "latest",
2097
2139
  label: "최신순"
2098
2140
  }, {
2099
2141
  value: "likes",
2100
2142
  label: "좋아요순"
2101
2143
  }];
2102
- function On(e) {
2144
+ function Nn(e) {
2103
2145
  return e === "list" ? 5 : 4;
2104
2146
  }
2105
- function kn(e, t) {
2147
+ function Pn(e, t) {
2106
2148
  let n = Math.floor(Number(t));
2107
- return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : On(e);
2149
+ return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : Nn(e);
2108
2150
  }
2109
- function An(e) {
2151
+ function Fn(e) {
2110
2152
  return e === 12 ? null : 12 - e;
2111
2153
  }
2112
- function jn(e) {
2154
+ function In(e) {
2113
2155
  return {
2114
2156
  3: "col-span-12 md:col-span-3",
2115
2157
  4: "col-span-12 md:col-span-4",
@@ -2121,36 +2163,36 @@ function jn(e) {
2121
2163
  12: "col-span-12"
2122
2164
  }[e];
2123
2165
  }
2124
- function Mn(e) {
2166
+ function Ln(e) {
2125
2167
  return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
2126
2168
  }
2127
- function Nn(e) {
2169
+ function Rn(e) {
2128
2170
  let t = e.boardId || e.category || "free";
2129
2171
  return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
2130
2172
  }
2131
- function Pn(e) {
2173
+ function zn(e) {
2132
2174
  return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
2133
2175
  }
2134
- function Fn(e) {
2176
+ function Bn(e) {
2135
2177
  if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
2136
2178
  }
2137
- function In(e) {
2179
+ function Vn(e) {
2138
2180
  return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
2139
2181
  }
2140
- function Ln(e) {
2182
+ function Hn(e) {
2141
2183
  return e.title?.trim() || e.summary || "게시물";
2142
2184
  }
2143
- function Rn(e) {
2185
+ function Un(e) {
2144
2186
  return e === "image" || e === "video" ? "media" : "list";
2145
2187
  }
2146
- function zn(e) {
2147
- return Rn(e) === "media" ? "미디어" : "목록";
2188
+ function Wn(e) {
2189
+ return Un(e) === "media" ? "미디어" : "목록";
2148
2190
  }
2149
- function Bn(e, t) {
2191
+ function Gn(e, t) {
2150
2192
  return e ? t(e)?.listView ?? "default" : "default";
2151
2193
  }
2152
- function Vn(e, t) {
2153
- let n = e.map((e) => Bn(e.boardId, t));
2194
+ function Kn(e, t) {
2195
+ let n = e.map((e) => Gn(e.boardId, t));
2154
2196
  if (!n.length) return "default";
2155
2197
  if (n.every((e) => e === n[0])) return n[0];
2156
2198
  let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
@@ -2158,27 +2200,27 @@ function Vn(e, t) {
2158
2200
  }
2159
2201
  //#endregion
2160
2202
  //#region src/composables/useMemiBoardSections.ts
2161
- var Hn = [];
2162
- function Un(e) {
2203
+ var qn = [];
2204
+ function Jn(e) {
2163
2205
  let t = Number(e.cols);
2164
- if (Tn.includes(t)) return t;
2206
+ if (An.includes(t)) return t;
2165
2207
  let n = e.width;
2166
2208
  return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
2167
2209
  }
2168
- function Wn(e) {
2210
+ function Yn(e) {
2169
2211
  let t = e.height ?? e.size;
2170
2212
  return t === "sm" || t === "lg" ? t : "md";
2171
2213
  }
2172
- function Gn(e) {
2214
+ function Xn(e) {
2173
2215
  return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
2174
2216
  }
2175
- function Kn(e) {
2217
+ function Zn(e) {
2176
2218
  return e.sort === "likes" ? "likes" : "latest";
2177
2219
  }
2178
- function qn(e) {
2220
+ function Qn(e) {
2179
2221
  return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
2180
2222
  }
2181
- function Jn(e, t) {
2223
+ function $n(e, t) {
2182
2224
  let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
2183
2225
  for (let e of n) {
2184
2226
  let n = String(e || "").trim();
@@ -2186,44 +2228,44 @@ function Jn(e, t) {
2186
2228
  }
2187
2229
  return r;
2188
2230
  }
2189
- function Yn(e, t) {
2190
- let n = Gn(e), r = kn(n, e.count);
2231
+ function er(e, t) {
2232
+ let n = Xn(e), r = Pn(n, e.count);
2191
2233
  return {
2192
2234
  id: String(e.id || `box-${t + 1}`),
2193
2235
  title: String(e.title || `섹션 ${t + 1}`),
2194
2236
  showTitle: e.showTitle !== !1,
2195
2237
  kind: n,
2196
- boardId: qn(e),
2238
+ boardId: Qn(e),
2197
2239
  count: r,
2198
- postIds: Jn(e, r),
2199
- sort: Kn(e),
2200
- cols: Un(e),
2201
- height: Wn(e),
2240
+ postIds: $n(e, r),
2241
+ sort: Zn(e),
2242
+ cols: Jn(e),
2243
+ height: Yn(e),
2202
2244
  order: t
2203
2245
  };
2204
2246
  }
2205
- function Xn() {
2206
- let e = Q(), t = L(e, "settings", "homeLayout"), { data: n, pending: r } = oe(t), i = A(() => (Array.isArray(n.value?.blocks) ? n.value.blocks : Hn).map((e, t) => Yn(e, t)));
2247
+ function tr() {
2248
+ let e = Q(), t = te(e, "settings", "homeLayout"), { data: n, pending: r } = oe(t), i = A(() => (Array.isArray(n.value?.blocks) ? n.value.blocks : qn).map((e, t) => er(e, t)));
2207
2249
  async function a(e) {
2208
- await q(t, {
2250
+ await K(t, {
2209
2251
  columns: 12,
2210
2252
  blocks: e.map((e, t) => {
2211
- let n = e, r = Gn(n), i = kn(r, e.count);
2253
+ let n = e, r = Xn(n), i = Pn(r, e.count);
2212
2254
  return {
2213
2255
  id: e.id,
2214
2256
  title: e.title.trim() || `섹션 ${t + 1}`,
2215
2257
  showTitle: e.showTitle !== !1,
2216
2258
  kind: r,
2217
- boardId: qn(n),
2259
+ boardId: Qn(n),
2218
2260
  count: i,
2219
- postIds: Jn(n, i),
2220
- sort: Kn(n),
2221
- cols: Un(n),
2222
- height: Wn(n),
2261
+ postIds: $n(n, i),
2262
+ sort: Zn(n),
2263
+ cols: Jn(n),
2264
+ height: Yn(n),
2223
2265
  order: t
2224
2266
  };
2225
2267
  }),
2226
- updatedAt: K()
2268
+ updatedAt: G()
2227
2269
  });
2228
2270
  }
2229
2271
  return {
@@ -2238,19 +2280,19 @@ function Xn() {
2238
2280
  }
2239
2281
  //#endregion
2240
2282
  //#region src/composables/useMemiBoardMiniPosts.ts
2241
- function Zn(e, t) {
2283
+ function nr(e, t) {
2242
2284
  let n = Q(), r = () => h(), i = N(e)?.trim() || "all", a = A(() => {
2243
- let i = Math.max(1, Math.floor(Number(N(t)) || 5)), a = N(e)?.trim() || "", s = [X("isPublished", "==", !0), X("listed", "==", !0)];
2244
- return a && s.unshift(X("boardId", "==", a)), G(o(n, r()), ...s, W("createdAt", "desc"), H(i));
2245
- }), { data: s, pending: c, error: l } = ie(a, { ssrKey: S(r(), `mini-list/${i}`) });
2285
+ let i = Math.max(1, Math.floor(Number(N(t)) || 5)), a = N(e)?.trim() || "", s = [Y("isPublished", "==", !0), Y("listed", "==", !0)];
2286
+ return a && s.unshift(Y("boardId", "==", a)), W(o(n, r()), ...s, U("createdAt", "desc"), V(i));
2287
+ }), { data: s, pending: c, error: l } = ae(a, { ssrKey: S(r(), `mini-list/${i}`) });
2246
2288
  return {
2247
2289
  posts: A(() => s.value ?? []),
2248
2290
  pending: c,
2249
2291
  error: l
2250
2292
  };
2251
2293
  }
2252
- function Qn(e) {
2253
- let t = Q(), n = () => h(), r = A(() => [...new Set(N(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = A(() => r.value.length ? G(o(t, n()), X(R(), "in", r.value)) : null), { data: s, pending: c, error: l } = ie(a, { ssrKey: S(n(), `mini-picked/${i}`) });
2294
+ function rr(e) {
2295
+ let t = Q(), n = () => h(), r = A(() => [...new Set(N(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = A(() => r.value.length ? W(o(t, n()), Y(L(), "in", r.value)) : null), { data: s, pending: c, error: l } = ae(a, { ssrKey: S(n(), `mini-picked/${i}`) });
2254
2296
  return {
2255
2297
  posts: A(() => {
2256
2298
  let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
@@ -2266,7 +2308,17 @@ function Qn(e) {
2266
2308
  }
2267
2309
  //#endregion
2268
2310
  //#region src/data/versionHistory.ts
2269
- var $n = [
2311
+ var ir = [
2312
+ {
2313
+ version: "0.44.1",
2314
+ date: "2026-10-01",
2315
+ highlights: ["Mac Safari에서 한글을 입력하고 바로 등록 버튼을 누를 때 두 번 눌러야 하던 문제를 고쳤어요"]
2316
+ },
2317
+ {
2318
+ version: "0.44.0",
2319
+ date: "2026-10-01",
2320
+ highlights: ["글을 저장하고 미리보기가 뜨기까지 기다리는 시간이 줄었어요 (특히 iPhone·Mac Safari)"]
2321
+ },
2270
2322
  {
2271
2323
  version: "0.42.0",
2272
2324
  date: "2026-08-27",
@@ -2536,7 +2588,7 @@ var $n = [
2536
2588
  highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
2537
2589
  note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
2538
2590
  }
2539
- ], er = /* @__PURE__ */ Ae(((e, t) => {
2591
+ ], ar = /* @__PURE__ */ Ae(((e, t) => {
2540
2592
  (function(n, r) {
2541
2593
  typeof e == "object" && t !== void 0 ? t.exports = r() : typeof define == "function" && define.amd ? define(r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs = r();
2542
2594
  })(e, (function() {
@@ -2830,7 +2882,7 @@ var $n = [
2830
2882
  return w(1e3 * e);
2831
2883
  }, w.en = b[y], w.Ls = b, w.p = {}, w;
2832
2884
  }));
2833
- })), tr = /* @__PURE__ */ Ae(((e, t) => {
2885
+ })), or = /* @__PURE__ */ Ae(((e, t) => {
2834
2886
  (function(n, r) {
2835
2887
  typeof e == "object" && t !== void 0 ? t.exports = r() : typeof define == "function" && define.amd ? define(r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs_plugin_relativeTime = r();
2836
2888
  })(e, (function() {
@@ -2934,9 +2986,9 @@ var $n = [
2934
2986
  };
2935
2987
  };
2936
2988
  }));
2937
- })), nr = /* @__PURE__ */ Ae(((e, t) => {
2989
+ })), sr = /* @__PURE__ */ Ae(((e, t) => {
2938
2990
  (function(n, r) {
2939
- typeof e == "object" && t !== void 0 ? t.exports = r(er()) : typeof define == "function" && define.amd ? define(["dayjs"], r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs_locale_ko = r(n.dayjs);
2991
+ typeof e == "object" && t !== void 0 ? t.exports = r(ar()) : typeof define == "function" && define.amd ? define(["dayjs"], r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs_locale_ko = r(n.dayjs);
2940
2992
  })(e, (function(e) {
2941
2993
  function t(e) {
2942
2994
  return e && typeof e == "object" && "default" in e ? e : { default: e };
@@ -2984,24 +3036,24 @@ var $n = [
2984
3036
  };
2985
3037
  return n.default.locale(r, null, !0), r;
2986
3038
  }));
2987
- })), rr = /* @__PURE__ */ Me(er(), 1), ir = /* @__PURE__ */ Me(tr(), 1);
2988
- nr(), rr.default.extend(ir.default), rr.default.locale("ko");
2989
- function ar(e) {
3039
+ })), cr = /* @__PURE__ */ Me(ar(), 1), lr = /* @__PURE__ */ Me(or(), 1);
3040
+ sr(), cr.default.extend(lr.default), cr.default.locale("ko");
3041
+ function ur(e) {
2990
3042
  return e?.toDate ? e.toDate().toLocaleDateString("ko-KR") : "";
2991
3043
  }
2992
- function or(e, t = Date.now()) {
2993
- return e?.toDate ? (0, rr.default)(e.toDate()).from((0, rr.default)(t)) : "방금 전";
3044
+ function dr(e, t = Date.now()) {
3045
+ return e?.toDate ? (0, cr.default)(e.toDate()).from((0, cr.default)(t)) : "방금 전";
2994
3046
  }
2995
- function sr(e) {
2996
- return e?.toDate ? (0, rr.default)(e.toDate()).format("YYYY년 M월 D일 HH:mm:ss") : "시간 확인 중";
3047
+ function fr(e) {
3048
+ return e?.toDate ? (0, cr.default)(e.toDate()).format("YYYY년 M월 D일 HH:mm:ss") : "시간 확인 중";
2997
3049
  }
2998
- function cr(e, t) {
2999
- let n = sr(e), r = e?.toMillis?.(), i = t?.toMillis?.();
3000
- return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${sr(t)}`];
3050
+ function pr(e, t) {
3051
+ let n = fr(e), r = e?.toMillis?.(), i = t?.toMillis?.();
3052
+ return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${fr(t)}`];
3001
3053
  }
3002
3054
  //#endregion
3003
3055
  //#region src/composables/useMemiBoardWritingAssistant.ts
3004
- var lr = 10, ur = 864e5, dr = 200, fr = {
3056
+ var mr = 10, hr = 864e5, gr = 200, _r = {
3005
3057
  proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
3006
3058
  polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
3007
3059
  continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
@@ -3010,40 +3062,40 @@ var lr = 10, ur = 864e5, dr = 200, fr = {
3010
3062
  "translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
3011
3063
  title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
3012
3064
  };
3013
- function pr(e) {
3014
- if (e.action !== "custom") return fr[e.action];
3015
- let t = e.customInstruction?.trim().slice(0, dr);
3065
+ function vr(e) {
3066
+ if (e.action !== "custom") return _r[e.action];
3067
+ let t = e.customInstruction?.trim().slice(0, gr);
3016
3068
  if (!t) throw Error("어떻게 바꿀지 지시문을 입력해 주세요.");
3017
3069
  return `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${t}`;
3018
3070
  }
3019
- function mr(e) {
3071
+ function yr(e) {
3020
3072
  return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
3021
3073
  }
3022
- function hr(e) {
3074
+ function br(e) {
3023
3075
  return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
3024
3076
  }
3025
- function gr() {
3026
- let e = se(), t = Q(), n = ae(), r = c();
3077
+ function xr() {
3078
+ let e = se(), t = Q(), n = Z(), r = c();
3027
3079
  async function i() {
3028
3080
  let e = n.value?.uid;
3029
3081
  if (!e) throw Error("AI 글쓰기 도우미는 로그인 후 사용할 수 있습니다.");
3030
- await re(t, async (n) => {
3082
+ await ie(t, async (n) => {
3031
3083
  let r = y(t, h(), e), i = await n.get(r);
3032
3084
  if (!i.exists()) throw Error("사용자 정보를 확인한 뒤 다시 시도해 주세요.");
3033
- let a = i.data(), o = hr(a.aiWritingWindowAt), s = Math.max(0, Math.floor(Number(a.aiWritingCount) || 0)), c = Date.now(), l = o != null && c - o < ur;
3085
+ let a = i.data(), o = br(a.aiWritingWindowAt), s = Math.max(0, Math.floor(Number(a.aiWritingCount) || 0)), c = Date.now(), l = o != null && c - o < hr;
3034
3086
  if (l && s >= 10) {
3035
- let e = o + ur, t = Math.max(1, Math.ceil((e - c) / 36e5));
3087
+ let e = o + hr, t = Math.max(1, Math.ceil((e - c) / 36e5));
3036
3088
  throw Error(`AI 글쓰기 도우미는 하루 10회까지 사용할 수 있습니다. 약 ${t}시간 후 다시 이용해 주세요.`);
3037
3089
  }
3038
3090
  n.update(r, {
3039
3091
  aiWritingCount: l ? s + 1 : 1,
3040
- aiWritingWindowAt: l ? a.aiWritingWindowAt : K(),
3041
- updatedAt: K()
3092
+ aiWritingWindowAt: l ? a.aiWritingWindowAt : G(),
3093
+ updatedAt: G()
3042
3094
  });
3043
3095
  });
3044
3096
  }
3045
3097
  async function a(t) {
3046
- let n = pr(t);
3098
+ let n = vr(t);
3047
3099
  if (!t.content.trim()) throw Error("AI로 다듬을 내용을 먼저 입력해 주세요.");
3048
3100
  await i();
3049
3101
  let a = r.moderation ?? {}, o = Se(e, {
@@ -3064,7 +3116,7 @@ function gr() {
3064
3116
  `작업: ${n}`,
3065
3117
  t.title ? `현재 제목: ${t.title}` : "",
3066
3118
  `본문:\n${c.slice(0, 12e3)}`
3067
- ].filter(Boolean).join("\n\n"), u = mr((await s.generateContent(l)).response.text());
3119
+ ].filter(Boolean).join("\n\n"), u = yr((await s.generateContent(l)).response.text());
3068
3120
  if (!u) throw Error("AI가 결과를 만들지 못했습니다. 다시 시도해 주세요.");
3069
3121
  return u;
3070
3122
  }
@@ -3072,14 +3124,14 @@ function gr() {
3072
3124
  }
3073
3125
  //#endregion
3074
3126
  //#region src/utils/renderMarkdown.ts
3075
- function _r(e) {
3127
+ function Sr(e) {
3076
3128
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
3077
3129
  }
3078
- function vr(e) {
3130
+ function Cr(e) {
3079
3131
  let t = e;
3080
3132
  return t = t.replace(/`([^`]+)`/g, "<code>$1</code>"), t = t.replace(/!\[([^\]]*)\]\((https?:\/\/[^)\s]+)\)/g, "<img src=\"$2\" alt=\"$1\" class=\"max-w-full h-auto rounded-lg my-3\" loading=\"lazy\" />"), t = t.replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, "<a href=\"$2\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"text-primary underline\">$1</a>"), t = t.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>"), t = t.replace(/\*([^*]+)\*/g, "<em>$1</em>"), t = t.replace(/~~([^~]+)~~/g, "<del>$1</del>"), t;
3081
3133
  }
3082
- function yr(e) {
3134
+ function wr(e) {
3083
3135
  if (!e?.trim()) return "";
3084
3136
  let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
3085
3137
  function c() {
@@ -3088,7 +3140,7 @@ function yr(e) {
3088
3140
  return;
3089
3141
  }
3090
3142
  let e = o;
3091
- n.push(`<${e}>${s.map((e) => `<li>${vr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3143
+ n.push(`<${e}>${s.map((e) => `<li>${Cr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3092
3144
  }
3093
3145
  for (; r < t.length;) {
3094
3146
  let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
@@ -3097,7 +3149,7 @@ function yr(e) {
3097
3149
  continue;
3098
3150
  }
3099
3151
  if (i) {
3100
- a.push(_r(e)), r++;
3152
+ a.push(Sr(e)), r++;
3101
3153
  continue;
3102
3154
  }
3103
3155
  if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
@@ -3108,24 +3160,24 @@ function yr(e) {
3108
3160
  if (u) {
3109
3161
  c();
3110
3162
  let e = u[1].length;
3111
- n.push(`<h${e} class="font-semibold mt-4 mb-2">${vr(_r(u[2]))}</h${e}>`), r++;
3163
+ n.push(`<h${e} class="font-semibold mt-4 mb-2">${Cr(Sr(u[2]))}</h${e}>`), r++;
3112
3164
  continue;
3113
3165
  }
3114
3166
  if (e.startsWith("> ")) {
3115
3167
  c();
3116
3168
  let e = [];
3117
- for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(_r((t[r] ?? "").slice(2))), r++;
3118
- n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${vr(e.join("<br />"))}</blockquote>`);
3169
+ for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(Sr((t[r] ?? "").slice(2))), r++;
3170
+ n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${Cr(e.join("<br />"))}</blockquote>`);
3119
3171
  continue;
3120
3172
  }
3121
3173
  let d = e.match(/^[-*+]\s+(.+)$/);
3122
3174
  if (d) {
3123
- o && o !== "ul" && c(), o = "ul", s.push(_r(d[1])), r++;
3175
+ o && o !== "ul" && c(), o = "ul", s.push(Sr(d[1])), r++;
3124
3176
  continue;
3125
3177
  }
3126
3178
  let f = e.match(/^\d+\.\s+(.+)$/);
3127
3179
  if (f) {
3128
- o && o !== "ol" && c(), o = "ol", s.push(_r(f[1])), r++;
3180
+ o && o !== "ol" && c(), o = "ol", s.push(Sr(f[1])), r++;
3129
3181
  continue;
3130
3182
  }
3131
3183
  if (!e.trim()) {
@@ -3137,13 +3189,13 @@ function yr(e) {
3137
3189
  for (; r < t.length;) {
3138
3190
  let e = t[r] ?? "";
3139
3191
  if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
3140
- p.push(_r(e)), r++;
3192
+ p.push(Sr(e)), r++;
3141
3193
  }
3142
- n.push(`<p class="my-2 leading-relaxed">${vr(p.join("<br />"))}</p>`);
3194
+ n.push(`<p class="my-2 leading-relaxed">${Cr(p.join("<br />"))}</p>`);
3143
3195
  }
3144
3196
  return c(), i && a.length && n.push(`<pre class="overflow-x-auto rounded-lg bg-muted p-3 text-sm"><code>${a.join("\n")}</code></pre>`), n.join("\n");
3145
3197
  }
3146
3198
  //#endregion
3147
- export { qt as AUTHOR_MEMO_MAX_LENGTH, Tn as BOARD_SECTION_COLS, En as BOARD_SECTION_KINDS, Dn as BOARD_SECTION_SORTS, Sn as BOARD_USER_ROLES, Qt as COMMENT_BODY_MAX_LENGTH, et as DEFAULT_BLOCK_BAN_DECAY_MS, $e as DEFAULT_BLOCK_BAN_THRESHOLD, At as DEFAULT_BOARDS, jt as DEFAULT_CATEGORIES, x as DEFAULT_COMMENTS_COLLECTION, w as DEFAULT_LIKES_COLLECTION, u as DEFAULT_POSTS_COLLECTION, v as DEFAULT_REPORTS_COLLECTION, T as DEFAULT_SETTINGS_COLLECTION, d as DEFAULT_USERS_COLLECTION, on as REPORT_DETAIL_MAX_LENGTH, sn as REPORT_REASONS, lr as WRITING_ASSISTANT_DAILY_LIMIT, Ne as asHttpUrl, ze as boardListOgDescription, Re as boardListOgTitle, Le as boardPostOgDescription, Ie as boardPostOgTitle, S as boardSsrKey, y as boardUserDoc, p as boardUsersCol, kt as buildPostPreview, Je as canManageBoardByRole, Ye as canWriteCommentByRole, kn as clampSectionCount, s as commentDoc, E as commentsCol, C as configureMemiBoard, On as defaultSectionCount, tt as effectiveModerationBlockCount, lt as extractEditorImageUrls, Ge as fetchPublicListForSeo, We as fetchPublicPostForSeo, ar as formatDate, sr as formatFullDate, or as formatRelativeDate, it as formatRestrictedUntilLabel, cr as formatTimestampDetails, wt as hasBodyImage, Ct as hasBodyText, qe as isAssignedStaff, Tt as isContentEmpty, Ft as isFirestorePermissionDenied, rt as isModerationWriteRestricted, k as likeDoc, l as likeDocId, O as likesCol, rn as memiBoardCommentLikesKey, Bn as miniBoardView, Fn as miniCommentLink, Pn as miniMoreLink, In as miniPostImage, Nn as miniPostLink, Ln as miniPostTitle, Vn as miniPostsView, Rn as miniViewGroup, zn as miniViewLabel, nt as moderationWriteRestrictedUntilMs, Be as normalizeBasePath, Yn as normalizeBoardSection, An as pairSectionCols, xt as plainTextFromHtml, a as postBodyDoc, t as postDoc, dt as postNamespaceFromStoragePath, D as postStorageFolder, o as postsCol, yr as renderMarkdownToHtml, r as reportDoc, n as reportDocId, cn as reportReasonLabel, i as reportsCol, _ as resolveBoardPathConfig, Ve as resolvePublicSeoDb, jn as sectionColClass, Mn as sectionMinHeight, e as settingsCol, g as settingsDoc, b as slugify, ut as storagePathFromDownloadUrl, St as titleFromBody, Fe as toAbsoluteUrl, Pe as toBoardOgImageUrl, h as useBoardPathConfig, ct as useMemiBoardAuth, Yt as useMemiBoardAuthorMemo, Kt as useMemiBoardCommentFeed, an as useMemiBoardCommentLikes, en as useMemiBoardComments, c as useMemiBoardConfig, nn as useMemiBoardLikes, Zn as useMemiBoardMiniLatest, Qn as useMemiBoardMiniPicked, xn as useMemiBoardModeration, Bt as useMemiBoardPost, zt as useMemiBoardPostList, Lt as useMemiBoardPosts, tn as useMemiBoardReplies, dn as useMemiBoardReportQueue, ln as useMemiBoardReports, Xn as useMemiBoardSections, Pt as useMemiBoardSettings, Wt as useMemiBoardUserComments, Ht as useMemiBoardUserPosts, wn as useMemiBoardUserProfile, Cn as useMemiBoardUsers, fn as useMemiBoardViews, gr as useMemiBoardWritingAssistant, $n as versionHistory, Ot as videoListCoverUrl, Dt as youtubeId };
3199
+ export { Qt as AUTHOR_MEMO_MAX_LENGTH, An as BOARD_SECTION_COLS, jn as BOARD_SECTION_KINDS, Mn as BOARD_SECTION_SORTS, Dn as BOARD_USER_ROLES, rn as COMMENT_BODY_MAX_LENGTH, et as DEFAULT_BLOCK_BAN_DECAY_MS, $e as DEFAULT_BLOCK_BAN_THRESHOLD, Pt as DEFAULT_BOARDS, Ft as DEFAULT_CATEGORIES, x as DEFAULT_COMMENTS_COLLECTION, w as DEFAULT_LIKES_COLLECTION, u as DEFAULT_POSTS_COLLECTION, v as DEFAULT_REPORTS_COLLECTION, T as DEFAULT_SETTINGS_COLLECTION, d as DEFAULT_USERS_COLLECTION, dn as REPORT_DETAIL_MAX_LENGTH, fn as REPORT_REASONS, mr as WRITING_ASSISTANT_DAILY_LIMIT, Ne as asHttpUrl, ze as boardListOgDescription, Re as boardListOgTitle, Le as boardPostOgDescription, Ie as boardPostOgTitle, S as boardSsrKey, y as boardUserDoc, p as boardUsersCol, Nt as buildPostPreview, Je as canManageBoardByRole, Ye as canWriteCommentByRole, Pn as clampSectionCount, s as commentDoc, E as commentsCol, C as configureMemiBoard, Nn as defaultSectionCount, tt as effectiveModerationBlockCount, pt as extractEditorImageUrls, Ge as fetchPublicListForSeo, We as fetchPublicPostForSeo, ur as formatDate, fr as formatFullDate, dr as formatRelativeDate, it as formatRestrictedUntilLabel, pr as formatTimestampDetails, Ot as hasBodyImage, Dt as hasBodyText, ft as imeSafeSubmitClick, dt as imeSafeSubmitPointerDown, qe as isAssignedStaff, kt as isContentEmpty, Bt as isFirestorePermissionDenied, rt as isModerationWriteRestricted, k as likeDoc, l as likeDocId, O as likesCol, ln as memiBoardCommentLikesKey, Gn as miniBoardView, Bn as miniCommentLink, zn as miniMoreLink, Vn as miniPostImage, Rn as miniPostLink, Hn as miniPostTitle, Kn as miniPostsView, Un as miniViewGroup, Wn as miniViewLabel, nt as moderationWriteRestrictedUntilMs, Be as normalizeBasePath, er as normalizeBoardSection, Fn as pairSectionCols, Tt as plainTextFromHtml, a as postBodyDoc, t as postDoc, ht as postNamespaceFromStoragePath, D as postStorageFolder, o as postsCol, wr as renderMarkdownToHtml, r as reportDoc, n as reportDocId, pn as reportReasonLabel, i as reportsCol, _ as resolveBoardPathConfig, Ve as resolvePublicSeoDb, In as sectionColClass, Ln as sectionMinHeight, e as settingsCol, g as settingsDoc, b as slugify, mt as storagePathFromDownloadUrl, Et as titleFromBody, Fe as toAbsoluteUrl, Pe as toBoardOgImageUrl, h as useBoardPathConfig, ct as useMemiBoardAuth, en as useMemiBoardAuthorMemo, Zt as useMemiBoardCommentFeed, un as useMemiBoardCommentLikes, on as useMemiBoardComments, c as useMemiBoardConfig, cn as useMemiBoardLikes, nr as useMemiBoardMiniLatest, rr as useMemiBoardMiniPicked, En as useMemiBoardModeration, Gt as useMemiBoardPost, Wt as useMemiBoardPostList, Ht as useMemiBoardPosts, sn as useMemiBoardReplies, gn as useMemiBoardReportQueue, mn as useMemiBoardReports, tr as useMemiBoardSections, Rt as useMemiBoardSettings, Yt as useMemiBoardUserComments, qt as useMemiBoardUserPosts, kn as useMemiBoardUserProfile, On as useMemiBoardUsers, _n as useMemiBoardViews, xr as useMemiBoardWritingAssistant, ir as versionHistory, Mt as videoListCoverUrl, jt as youtubeId };
3148
3200
 
3149
3201
  //# sourceMappingURL=index.js.map