memi-board 0.43.0 → 0.44.0

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,8 +414,8 @@ 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
  };
@@ -461,26 +461,26 @@ async function mt(e, t) {
461
461
  }
462
462
  var ht = 450;
463
463
  async function gt(e, t) {
464
- let n = await B(t);
464
+ let n = await z(t);
465
465
  for (let t = 0; t < n.docs.length; t += ht) {
466
- let r = Z(e);
466
+ let r = X(e);
467
467
  n.docs.slice(t, t + ht).forEach((e) => r.delete(e.ref)), await r.commit();
468
468
  }
469
469
  }
470
470
  async function _t(e, t, n) {
471
- await gt(e, G(O(e, t), X("postId", "==", n)));
471
+ await gt(e, W(O(e, t), Y("postId", "==", n)));
472
472
  }
473
473
  async function vt(e, t, n) {
474
- await gt(e, G(i(e, t), X("postId", "==", n)));
474
+ await gt(e, W(i(e, t), Y("postId", "==", n)));
475
475
  }
476
476
  async function yt(e, t, n) {
477
- await gt(e, G(O(e, t), X("commentId", "==", n)));
477
+ await gt(e, W(O(e, t), Y("commentId", "==", n)));
478
478
  }
479
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)]);
480
+ let o = t(e, r, i), s = a(e, r, i), [c, l] = await Promise.all([R(o), R(s)]);
481
481
  if (!c.exists()) return;
482
482
  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);
483
+ await gt(e, W(E(e, r), Y("postId", "==", i))), await _t(e, r, i), await vt(e, r, i);
484
484
  let f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
485
485
  for (let e of u.attachments ?? []) {
486
486
  if (!e?.path) continue;
@@ -599,7 +599,7 @@ function Nt(e, t, n) {
599
599
  };
600
600
  }
601
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;
602
+ 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) => Nt(e.id, e, t))), p = f, m = A(() => f.value.filter((e) => e.visibility !== "hidden")), _ = m;
603
603
  function v(e) {
604
604
  if (e) return f.value.find((t) => t.id === e)?.label ?? e;
605
605
  }
@@ -627,9 +627,9 @@ function Pt() {
627
627
  async function M(e, t, r) {
628
628
  let i;
629
629
  for (;;) {
630
- let a = await B(G(e, X("boardId", "==", t), W("__name__"), ...i ? [J(i)] : [], H(400)));
630
+ let a = await z(W(e, Y("boardId", "==", t), U("__name__"), ...i ? [q(i)] : [], V(400)));
631
631
  if (a.empty) break;
632
- let o = Z(n), s = 0;
632
+ let o = X(n), s = 0;
633
633
  for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
634
634
  if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
635
635
  }
@@ -648,7 +648,7 @@ function Pt() {
648
648
  commentWriteRole: e.commentWriteRole ?? "user",
649
649
  allowedStaffUids: e.allowedStaffUids ?? [],
650
650
  order: t,
651
- updatedAt: K()
651
+ updatedAt: G()
652
652
  };
653
653
  }
654
654
  async function I(e, r = e.order ?? 0) {
@@ -660,12 +660,12 @@ function Pt() {
660
660
  label: o,
661
661
  visibility: s
662
662
  }, r);
663
- await q(g(n, t(), a), c, { merge: !0 }), await N(a, s !== "hidden");
663
+ await K(g(n, t(), a), c, { merge: !0 }), await N(a, s !== "hidden");
664
664
  }
665
- let L = I;
666
- async function R(e) {
665
+ let te = I;
666
+ async function L(e) {
667
667
  if (!i.value) throw Error("로그인이 필요합니다.");
668
- let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a = Z(n), o = [];
668
+ let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a = X(n), o = [];
669
669
  e.forEach((e, i) => {
670
670
  let s = e.id.trim(), c = e.label.trim();
671
671
  if (!s || !c) throw Error("보드 ID와 이름을 입력해 주세요.");
@@ -681,23 +681,23 @@ function Pt() {
681
681
  }), await a.commit();
682
682
  for (let e of o) await N(e.id, e.listed);
683
683
  }
684
- let te = R;
685
- async function z(e) {
684
+ let ne = L;
685
+ async function R(e) {
686
686
  if (!i.value) throw Error("로그인이 필요합니다.");
687
687
  let a = e.trim();
688
688
  if (!a) throw Error("삭제할 게시판 ID가 필요합니다.");
689
689
  for (;;) {
690
- let e = await B(G(o(n, t()), X("boardId", "==", a), H(25)));
690
+ let e = await z(W(o(n, t()), Y("boardId", "==", a), V(25)));
691
691
  if (e.empty) break;
692
692
  for (let i of e.docs) await bt(n, _e(r), t(), i.id);
693
693
  }
694
694
  await F(g(n, t(), e));
695
695
  }
696
- let V = z;
697
- async function ne() {
696
+ let B = R;
697
+ async function re() {
698
698
  return Promise.resolve();
699
699
  }
700
- async function U(e) {
700
+ async function H(e) {
701
701
  let t = e.trim();
702
702
  if (!t) throw Error("보드 이름을 입력해 주세요.");
703
703
  if (!i.value) throw Error("로그인이 필요합니다.");
@@ -733,33 +733,34 @@ function Pt() {
733
733
  categoryVisibility: T,
734
734
  isCategoryHidden: O,
735
735
  settingsPending: d,
736
- ensureSettings: ne,
737
- addBoard: U,
738
- addCategory: U,
736
+ ensureSettings: re,
737
+ addBoard: H,
738
+ addCategory: H,
739
739
  saveBoard: I,
740
- saveCategory: L,
741
- saveBoards: R,
742
- saveCategories: te,
743
- deleteBoard: z,
744
- deleteCategory: V,
740
+ saveCategory: te,
741
+ saveBoards: L,
742
+ saveCategories: ne,
743
+ deleteBoard: R,
744
+ deleteCategory: B,
745
745
  DEFAULT_BOARDS: At,
746
746
  DEFAULT_CATEGORIES: jt
747
747
  };
748
748
  }
749
749
  //#endregion
750
750
  //#region src/composables/useMemiBoardPosts.ts
751
- function Ft(e) {
751
+ var Ft = /* @__PURE__ */ new Map();
752
+ function It(e) {
752
753
  if (!e || typeof e != "object") return !1;
753
754
  let t = "code" in e ? String(e.code) : "";
754
755
  return t === "permission-denied" || t === "firestore/permission-denied";
755
756
  }
756
- function It(e) {
757
+ function Lt(e) {
757
758
  let t = N(e)?.trim();
758
759
  if (!t) throw Error("[memi-board] boardId 가 필요합니다.");
759
760
  return t;
760
761
  }
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);
762
+ function Rt(e) {
763
+ let n = Q(), r = se(), { isBoardHidden: i, getBoard: s } = Pt(), c = () => h(), l = () => Lt(e), u = () => o(n, c()), d = (e) => t(n, c(), e), f = (e) => a(n, c(), e);
763
764
  function p() {
764
765
  return !i(l());
765
766
  }
@@ -776,12 +777,12 @@ function Lt(e) {
776
777
  if (!e.title?.trim()) throw Error("제목을 입력해 주세요.");
777
778
  }
778
779
  function _() {
779
- return L(u()).id;
780
+ return te(u()).id;
780
781
  }
781
782
  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);
783
+ let t = e.pageSize ?? 20, n = [Y("boardId", "==", l()), Y("isPublished", "==", !0)];
784
+ 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));
785
+ let r = await z(W(u(), ...n)), i = r.docs.slice(0, t);
785
786
  return {
786
787
  posts: i.map((e) => ({
787
788
  id: e.id,
@@ -792,7 +793,7 @@ function Lt(e) {
792
793
  };
793
794
  }
794
795
  async function y(e) {
795
- let [t, n] = await Promise.all([z(d(e)), z(f(e))]);
796
+ let [t, n] = await Promise.all([R(d(e)), R(f(e))]);
796
797
  return t.exists() ? {
797
798
  id: t.id,
798
799
  ...t.data(),
@@ -801,7 +802,7 @@ function Lt(e) {
801
802
  }
802
803
  async function x(e) {
803
804
  try {
804
- let t = (await B(G(u(), X("boardId", "==", l()), X("slug", "==", e.trim()), H(1)))).docs[0];
805
+ let t = (await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", e.trim()), V(1)))).docs[0];
805
806
  if (!t) return { status: "not-found" };
806
807
  try {
807
808
  let e = await y(t.id);
@@ -810,30 +811,54 @@ function Lt(e) {
810
811
  post: e
811
812
  } : { status: "not-found" };
812
813
  } catch (e) {
813
- return Ft(e) ? { status: "permission-denied" } : {
814
+ return It(e) ? { status: "permission-denied" } : {
814
815
  status: "error",
815
816
  message: e instanceof Error ? e.message : String(e)
816
817
  };
817
818
  }
818
819
  } catch (e) {
819
- return Ft(e) ? { status: "permission-denied" } : {
820
+ return It(e) ? { status: "permission-denied" } : {
820
821
  status: "error",
821
822
  message: e instanceof Error ? e.message : String(e)
822
823
  };
823
824
  }
824
825
  }
825
826
  async function S(e) {
827
+ let t = e.trim(), n = Ft.get(`${l()}/${t}`);
828
+ if (n) return {
829
+ status: "ok",
830
+ id: n
831
+ };
832
+ try {
833
+ let e = (await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", t), V(1)))).docs[0];
834
+ return e ? {
835
+ status: "ok",
836
+ id: e.id
837
+ } : { status: "not-found" };
838
+ } catch (e) {
839
+ return It(e) ? { status: "permission-denied" } : {
840
+ status: "error",
841
+ message: e instanceof Error ? e.message : String(e)
842
+ };
843
+ }
844
+ }
845
+ async function C(e) {
846
+ let t = b(e.trim()) || "post", n = t, r = 1;
847
+ for (; !(await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", n), V(1)))).empty;) r++, n = `${t}-${r}`;
848
+ return n;
849
+ }
850
+ async function w(e) {
826
851
  if (!e.createdAt) return {
827
852
  previous: null,
828
853
  next: null
829
854
  };
830
855
  try {
831
856
  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) => {
857
+ Y("boardId", "==", l()),
858
+ Y("isPublished", "==", !0),
859
+ ...e.listed === !1 ? [] : [Y("listed", "==", !0)],
860
+ U("createdAt", "desc")
861
+ ], [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
862
  let t = e.docs[0];
838
863
  return t ? {
839
864
  id: t.id,
@@ -851,43 +876,36 @@ function Lt(e) {
851
876
  };
852
877
  }
853
878
  }
854
- async function C(e) {
879
+ async function T(e) {
855
880
  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), {
881
+ let t = e.postId || _(), r = m(), i, a;
882
+ r ? (i = t, a = St(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await C(a));
883
+ let o = kt(e.content, e.attachments), s = p(), c = X(n);
884
+ return c.set(d(t), {
867
885
  boardId: l(),
868
- slug: r,
869
- title: i,
870
- ...a,
886
+ slug: i,
887
+ title: a,
888
+ ...o,
871
889
  tags: e.tags ?? [],
872
890
  attachments: e.attachments ?? [],
873
891
  commentCount: 0,
874
892
  likeCount: 0,
875
893
  viewCount: 0,
876
- listed: o,
894
+ listed: s,
877
895
  isPublished: !1,
878
896
  authorUid: e.authorUid,
879
897
  authorName: e.authorName,
880
898
  authorPhoto: e.authorPhoto,
881
899
  moderationStatus: "approved",
882
900
  moderationModel: e.moderationModel ?? null,
883
- createdAt: K(),
884
- updatedAt: K()
885
- }), await q(f(t), { content: e.content }), r;
901
+ createdAt: G(),
902
+ updatedAt: G()
903
+ }), c.set(f(t), { content: e.content }), await c.commit(), Ft.set(`${l()}/${i}`, t), i;
886
904
  }
887
- async function w(e, t) {
905
+ async function E(e, t) {
888
906
  g(t);
889
907
  let n = m() ? St(t.content) : t.title.trim(), r = kt(t.content, t.attachments), i = p();
890
- await Promise.all([Y(d(e), {
908
+ await Promise.all([J(d(e), {
891
909
  title: n,
892
910
  ...r,
893
911
  previewImage: r.previewImage ? r.previewImage : I(),
@@ -895,34 +913,37 @@ function Lt(e) {
895
913
  tags: t.tags ?? [],
896
914
  listed: i,
897
915
  attachments: t.attachments ?? [],
898
- updatedAt: K()
899
- }), q(f(e), { content: t.content }, { merge: !0 })]);
916
+ updatedAt: G()
917
+ }), K(f(e), { content: t.content }, { merge: !0 })]);
900
918
  }
901
- async function T(e) {
902
- await Y(d(e), {
919
+ async function D(e) {
920
+ await J(d(e), {
903
921
  isPublished: !0,
904
- publishedAt: K(),
905
- updatedAt: K()
922
+ publishedAt: G(),
923
+ updatedAt: G()
906
924
  });
907
925
  }
908
- async function E(e) {
926
+ async function O(e) {
909
927
  await bt(n, _e(r), c(), e);
928
+ for (let [t, n] of Ft) n === e && Ft.delete(t);
910
929
  }
911
930
  return {
912
931
  createPostId: _,
913
932
  getPosts: v,
914
933
  getPost: y,
915
934
  getPostBySlug: x,
916
- getAdjacentPosts: S,
917
- createPost: C,
918
- updatePost: w,
919
- publishPost: T,
920
- deletePost: E
935
+ resolvePostIdBySlug: S,
936
+ resolveUniqueSlug: C,
937
+ getAdjacentPosts: w,
938
+ createPost: T,
939
+ updatePost: E,
940
+ publishPost: D,
941
+ deletePost: O
921
942
  };
922
943
  }
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;
944
+ var zt = 10;
945
+ function Bt(e, t = {}) {
946
+ let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = ct(), s = () => h(), c = t.pageSize ?? zt, l = A(() => i.value?.uid ?? ""), u = A(() => Lt(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
947
  function T(e) {
927
948
  return e.createdAt?.toMillis?.() ?? 0;
928
949
  }
@@ -936,11 +957,11 @@ function zt(e, t = {}) {
936
957
  return [...e.values()].sort((e, t) => T(t) - T(e) || String(t.id).localeCompare(String(e.id)));
937
958
  });
938
959
  function D() {
939
- let e = [X("boardId", "==", u.value), X("isPublished", "==", !0)];
940
- return f.value && e.push(X("listed", "==", !0)), e;
960
+ let e = [Y("boardId", "==", u.value), Y("isPublished", "==", !0)];
961
+ return f.value && e.push(Y("listed", "==", !0)), e;
941
962
  }
942
963
  function O() {
943
- C?.(), C = U(G(d(), ...D(), W("createdAt", "desc"), W(R(), "desc"), H(c)), (e) => {
964
+ C?.(), C = H(W(d(), ...D(), U("createdAt", "desc"), U(L(), "desc"), V(c)), (e) => {
944
965
  p.value = e.docs.map((e) => ({
945
966
  id: e.id,
946
967
  ...e.data()
@@ -956,7 +977,7 @@ function zt(e, t = {}) {
956
977
  g.value = [];
957
978
  return;
958
979
  }
959
- w = U(G(d(), X("boardId", "==", u.value), X("authorUid", "==", e), X("isPublished", "==", !1), W("createdAt", "desc"), H(20)), (e) => {
980
+ w = H(W(d(), Y("boardId", "==", u.value), Y("authorUid", "==", e), Y("isPublished", "==", !1), U("createdAt", "desc"), V(20)), (e) => {
960
981
  g.value = e.docs.map((e) => ({
961
982
  id: e.id,
962
983
  ...e.data()
@@ -971,11 +992,11 @@ function zt(e, t = {}) {
971
992
  try {
972
993
  let e = S ?? x, t = [
973
994
  ...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) => ({
995
+ U("createdAt", "desc"),
996
+ U(L(), "desc"),
997
+ ...e ? [q(e)] : [],
998
+ V(c + 1)
999
+ ], n = await z(W(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
979
1000
  id: e.id,
980
1001
  ...e.data()
981
1002
  })), a = new Set([...m.value, ...p.value].map((e) => e.id));
@@ -1005,8 +1026,8 @@ function zt(e, t = {}) {
1005
1026
  loadMore: ee
1006
1027
  };
1007
1028
  }
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);
1029
+ function Vt(e, n) {
1030
+ let r = Q(), i = () => h(), o = A(() => Lt(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
1031
  return {
1011
1032
  post: A(() => !u.value || u.value.boardId !== o.value ? null : {
1012
1033
  ...u.value,
@@ -1018,9 +1039,9 @@ function Bt(e, n) {
1018
1039
  }
1019
1040
  //#endregion
1020
1041
  //#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, _;
1042
+ var Ht = 10;
1043
+ function Ut(e, t = {}) {
1044
+ let n = Q(), r = () => h(), i = () => o(n, r()), a = t.pageSize ?? Ht, 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
1045
  function v(e) {
1025
1046
  return {
1026
1047
  id: e.id,
@@ -1037,9 +1058,9 @@ function Ht(e, t = {}) {
1037
1058
  });
1038
1059
  function x() {
1039
1060
  return [
1040
- X("authorUid", "==", s.value),
1041
- X("isPublished", "==", !0),
1042
- X("listed", "==", !0)
1061
+ Y("authorUid", "==", s.value),
1062
+ Y("isPublished", "==", !0),
1063
+ Y("listed", "==", !0)
1043
1064
  ];
1044
1065
  }
1045
1066
  function S() {
@@ -1047,7 +1068,7 @@ function Ht(e, t = {}) {
1047
1068
  u.value = !1;
1048
1069
  return;
1049
1070
  }
1050
- _ = U(G(i(), ...x(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
1071
+ _ = H(W(i(), ...x(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1051
1072
  c.value = e.docs.map(v), m = e.docs.at(-1) ?? null, g || (d.value = e.docs.length >= a), u.value = !1;
1052
1073
  }, (e) => {
1053
1074
  console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
@@ -1059,11 +1080,11 @@ function Ht(e, t = {}) {
1059
1080
  try {
1060
1081
  let e = g ?? m, t = [
1061
1082
  ...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));
1083
+ U("createdAt", "desc"),
1084
+ U(L(), "desc"),
1085
+ ...e ? [q(e)] : [],
1086
+ V(a + 1)
1087
+ ], 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
1088
  l.value.push(...o.filter((e) => !s.has(e.id))), g = r.at(-1) ?? g, d.value = n.docs.length > a;
1068
1089
  } catch (e) {
1069
1090
  p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
@@ -1086,9 +1107,9 @@ function Ht(e, t = {}) {
1086
1107
  }
1087
1108
  //#endregion
1088
1109
  //#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;
1110
+ var Wt = 10;
1111
+ function Gt(e, t = {}) {
1112
+ let n = Q(), r = () => h(), i = () => E(n, r()), a = t.pageSize ?? Wt, 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
1113
  function _(e) {
1093
1114
  return {
1094
1115
  id: e.id,
@@ -1104,14 +1125,14 @@ function Wt(e, t = {}) {
1104
1125
  return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
1105
1126
  });
1106
1127
  function b() {
1107
- return [X("authorUid", "==", o.value), X("listed", "==", !0)];
1128
+ return [Y("authorUid", "==", o.value), Y("listed", "==", !0)];
1108
1129
  }
1109
1130
  function x() {
1110
1131
  if (g?.(), !o.value) {
1111
1132
  l.value = !1;
1112
1133
  return;
1113
1134
  }
1114
- g = U(G(i(), ...b(), W("createdAt", "desc"), W(R(), "desc"), H(a)), (e) => {
1135
+ g = H(W(i(), ...b(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1115
1136
  s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
1116
1137
  }, (e) => {
1117
1138
  console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
@@ -1123,11 +1144,11 @@ function Wt(e, t = {}) {
1123
1144
  try {
1124
1145
  let e = m ?? p, t = [
1125
1146
  ...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));
1147
+ U("createdAt", "desc"),
1148
+ U(L(), "desc"),
1149
+ ...e ? [q(e)] : [],
1150
+ V(a + 1)
1151
+ ], 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
1152
  c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
1132
1153
  } catch (e) {
1133
1154
  f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
@@ -1150,11 +1171,11 @@ function Wt(e, t = {}) {
1150
1171
  }
1151
1172
  //#endregion
1152
1173
  //#region src/composables/useMemiBoardCommentFeed.ts
1153
- var Gt = 10;
1154
- function Kt(e = "latest", t = {}) {
1174
+ var Kt = 10;
1175
+ function qt(e = "latest", t = {}) {
1155
1176
  let n = Q(), r = () => h(), i = () => E(n, r()), a = A(() => {
1156
1177
  let e = Math.floor(Number(N(t.pageSize)));
1157
- return Number.isFinite(e) && e > 0 ? e : Gt;
1178
+ return Number.isFinite(e) && e > 0 ? e : Kt;
1158
1179
  }), 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
1180
  function _(e) {
1160
1181
  return {
@@ -1179,18 +1200,18 @@ function Kt(e = "latest", t = {}) {
1179
1200
  });
1180
1201
  function x() {
1181
1202
  return o.value === "likes" ? [
1182
- X("listed", "==", !0),
1183
- W("likeCount", "desc"),
1184
- W("createdAt", "desc"),
1185
- W(R(), "desc")
1203
+ Y("listed", "==", !0),
1204
+ U("likeCount", "desc"),
1205
+ U("createdAt", "desc"),
1206
+ U(L(), "desc")
1186
1207
  ] : [
1187
- X("listed", "==", !0),
1188
- W("createdAt", "desc"),
1189
- W(R(), "desc")
1208
+ Y("listed", "==", !0),
1209
+ U("createdAt", "desc"),
1210
+ U(L(), "desc")
1190
1211
  ];
1191
1212
  }
1192
1213
  function S() {
1193
- g?.(), g = U(G(i(), ...x(), H(a.value)), (e) => {
1214
+ g?.(), g = H(W(i(), ...x(), V(a.value)), (e) => {
1194
1215
  s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
1195
1216
  }, (e) => {
1196
1217
  console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
@@ -1200,7 +1221,7 @@ function Kt(e = "latest", t = {}) {
1200
1221
  if (!(d.value || !u.value || l.value)) {
1201
1222
  d.value = !0, f.value = "";
1202
1223
  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));
1224
+ 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
1225
  c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
1205
1226
  } catch (e) {
1206
1227
  f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
@@ -1224,9 +1245,9 @@ function Kt(e = "latest", t = {}) {
1224
1245
  }
1225
1246
  //#endregion
1226
1247
  //#region src/composables/useMemiBoardAuthorMemo.ts
1227
- var qt = 100, Jt = /* @__PURE__ */ new Map();
1248
+ var Jt = 100, Yt = /* @__PURE__ */ new Map();
1228
1249
  function $(e) {
1229
- let t = Jt.get(e);
1250
+ let t = Yt.get(e);
1230
1251
  return t || (t = ee({
1231
1252
  text: "",
1232
1253
  sentiment: null,
@@ -1234,9 +1255,9 @@ function $(e) {
1234
1255
  pending: !1,
1235
1256
  saving: !1,
1236
1257
  error: ""
1237
- }), Jt.set(e, t)), t;
1258
+ }), Yt.set(e, t)), t;
1238
1259
  }
1239
- function Yt(e) {
1260
+ function Xt(e) {
1240
1261
  let t = Q(), n = () => h(), { user: r } = ct(), i = A(() => N(e)), a = A(() => `${r.value?.uid ?? ""}:${i.value}`), o = A(() => {
1241
1262
  let e = r.value?.uid, a = i.value;
1242
1263
  return !e || !a ? null : f(t, n(), e, a);
@@ -1252,7 +1273,7 @@ function Yt(e) {
1252
1273
  let t = $(a.value);
1253
1274
  t.pending = !0, t.error = "";
1254
1275
  try {
1255
- let n = (await z(e)).data();
1276
+ let n = (await R(e)).data();
1256
1277
  t.text = n ? n.text ?? "" : "", t.sentiment = n ? n.sentiment ?? null : null, t.loaded = !0;
1257
1278
  } catch (e) {
1258
1279
  t.error = e.message || String(e), console.error("[memi-board:authorMemo] load failed", e);
@@ -1268,10 +1289,10 @@ function Yt(e) {
1268
1289
  let i = $(a.value);
1269
1290
  i.saving = !0, i.error = "";
1270
1291
  try {
1271
- await q(n, {
1292
+ await K(n, {
1272
1293
  text: r,
1273
1294
  sentiment: t,
1274
- updatedAt: K()
1295
+ updatedAt: G()
1275
1296
  }), i.text = r, i.sentiment = t, i.loaded = !0;
1276
1297
  } catch (e) {
1277
1298
  throw i.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
@@ -1306,14 +1327,14 @@ function Yt(e) {
1306
1327
  }
1307
1328
  //#endregion
1308
1329
  //#region src/composables/useMemiBoardComments.ts
1309
- var Xt = 10, Zt = 5, Qt = 1e3;
1310
- function $t(e) {
1330
+ var Zt = 10, Qt = 5, $t = 1e3;
1331
+ function en(e) {
1311
1332
  let t = e.trim();
1312
1333
  if (!t) throw Error("댓글 내용을 입력해 주세요.");
1313
- if (t.length > 1e3) throw Error(`댓글은 ${Qt.toLocaleString()}자까지 작성할 수 있습니다.`);
1334
+ if (t.length > 1e3) throw Error(`댓글은 ${$t.toLocaleString()}자까지 작성할 수 있습니다.`);
1314
1335
  return t;
1315
1336
  }
1316
- function en(e, n, r = {}) {
1337
+ function tn(e, n, r = {}) {
1317
1338
  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;
1318
1339
  function C(e) {
1319
1340
  return e.createdAt?.toMillis?.() ?? 0;
@@ -1331,7 +1352,7 @@ function en(e, n, r = {}) {
1331
1352
  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
1353
  m.value = !0, y.value = !0;
1333
1354
  try {
1334
- let t = B(G(c(), X("postId", "==", e), W("createdAt", "desc"), W(R(), "desc")));
1355
+ let t = z(W(c(), Y("postId", "==", e), U("createdAt", "desc"), U(L(), "desc")));
1335
1356
  if (await Promise.all([t.then((t) => {
1336
1357
  if (u.value !== e) return;
1337
1358
  let n = t.docs.map((e) => ({
@@ -1346,7 +1367,7 @@ function en(e, n, r = {}) {
1346
1367
  }
1347
1368
  }, { immediate: !0 });
1348
1369
  function T() {
1349
- S?.(), S = U(G(c(), X("postId", "==", u.value), X("parentId", "==", null), W("createdAt", "desc"), W(R(), "desc"), H(1)), (e) => {
1370
+ S?.(), S = H(W(c(), Y("postId", "==", u.value), Y("parentId", "==", null), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
1350
1371
  let t = new Map(f.value.map((e) => [e.id, e]));
1351
1372
  for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
1352
1373
  id: n.doc.id,
@@ -1362,17 +1383,17 @@ function en(e, n, r = {}) {
1362
1383
  _.value = !0;
1363
1384
  try {
1364
1385
  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) => ({
1386
+ Y("postId", "==", u.value),
1387
+ Y("parentId", "==", null),
1388
+ U("createdAt", "asc"),
1389
+ U(L(), "asc"),
1390
+ ...b ? [q(b)] : [],
1391
+ V(11)
1392
+ ], t = await z(W(c(), ...e)), n = t.docs.slice(0, Zt), r = n.map((e) => ({
1372
1393
  id: e.id,
1373
1394
  ...e.data()
1374
1395
  })), 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(() => {
1396
+ g.value.push(...r.filter((e) => !i.has(e.id))), b = n.at(-1) ?? b, t.size <= Zt && (v.value = !1, x = setTimeout(() => {
1376
1397
  x = void 0, T();
1377
1398
  }, 1e3));
1378
1399
  } finally {
@@ -1384,7 +1405,7 @@ function en(e, n, r = {}) {
1384
1405
  clearTimeout(x), S?.();
1385
1406
  });
1386
1407
  async function O(e) {
1387
- let n = $t(e.body), r = Z(i), o = L(c());
1408
+ let n = en(e.body), r = X(i), o = te(c());
1388
1409
  r.set(o, {
1389
1410
  postId: u.value,
1390
1411
  boardId: l.value,
@@ -1402,14 +1423,14 @@ function en(e, n, r = {}) {
1402
1423
  replyCount: 0,
1403
1424
  likeCount: 0,
1404
1425
  isReply: !1,
1405
- createdAt: K(),
1406
- updatedAt: K()
1407
- }), r.update(t(i, a(), u.value), { commentCount: V(1) }), await r.commit();
1426
+ createdAt: G(),
1427
+ updatedAt: G()
1428
+ }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
1408
1429
  }
1409
1430
  async function k(e) {
1410
- let n = $t(e.body);
1431
+ let n = en(e.body);
1411
1432
  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;
1433
+ let r = X(i), o = te(c()), f = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
1413
1434
  if (!f) throw Error("댓글 스레드를 찾을 수 없습니다.");
1414
1435
  let p = Math.min((e.parent.depth ?? 0) + 1, 2);
1415
1436
  r.set(o, {
@@ -1429,28 +1450,28 @@ function en(e, n, r = {}) {
1429
1450
  replyCount: 0,
1430
1451
  likeCount: 0,
1431
1452
  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();
1453
+ createdAt: G(),
1454
+ updatedAt: G()
1455
+ }), r.update(s(i, a(), f), { replyCount: B(1) }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
1435
1456
  }
1436
1457
  async function ee(e) {
1437
1458
  if (!e.id) return;
1438
1459
  if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error("답글이 있는 댓글은 현재 삭제할 수 없습니다.");
1439
1460
  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);
1461
+ let n = X(i);
1462
+ 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
1463
  }
1443
1464
  async function F(e, t) {
1444
- let n = $t(t);
1445
- await Y(s(i, a(), e), {
1465
+ let n = en(t);
1466
+ await J(s(i, a(), e), {
1446
1467
  body: n,
1447
- updatedAt: K()
1468
+ updatedAt: G()
1448
1469
  });
1449
1470
  }
1450
1471
  async function I(e, t, n) {
1451
- await Y(s(i, a(), e), {
1472
+ await J(s(i, a(), e), {
1452
1473
  isBlinded: t,
1453
- moderatedAt: K(),
1474
+ moderatedAt: G(),
1454
1475
  moderatedBy: n
1455
1476
  });
1456
1477
  }
@@ -1467,13 +1488,13 @@ function en(e, n, r = {}) {
1467
1488
  deleteComment: ee
1468
1489
  };
1469
1490
  }
1470
- function tn(e, t, n) {
1491
+ function nn(e, t, n) {
1471
1492
  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
1493
  function p(e) {
1473
1494
  return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
1474
1495
  }
1475
1496
  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) => {
1497
+ f ||= H(W(a(), Y("postId", "==", o), Y("rootId", "==", n), Y("isReply", "==", !0), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
1477
1498
  let t = new Map(s.value.map((e) => [e.id, e]));
1478
1499
  for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
1479
1500
  id: n.doc.id,
@@ -1489,18 +1510,18 @@ function tn(e, t, n) {
1489
1510
  c.value = !0;
1490
1511
  try {
1491
1512
  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) => ({
1513
+ Y("postId", "==", o),
1514
+ Y("rootId", "==", n),
1515
+ Y("isReply", "==", !0),
1516
+ U("createdAt", "asc"),
1517
+ U(L(), "asc"),
1518
+ ...d ? [q(d)] : [],
1519
+ V(6)
1520
+ ], t = await z(W(a(), ...e)), r = new Set(s.value.map((e) => e.id)), i = t.docs.slice(0, Qt), c = i.map((e) => ({
1500
1521
  id: e.id,
1501
1522
  ...e.data()
1502
1523
  })).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());
1524
+ s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <= Qt && (u.value = !1, m());
1504
1525
  } finally {
1505
1526
  c.value = !1;
1506
1527
  }
@@ -1523,8 +1544,8 @@ function tn(e, t, n) {
1523
1544
  }
1524
1545
  //#endregion
1525
1546
  //#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;
1547
+ function rn(e, n) {
1548
+ let r = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
1528
1549
  function l(e) {
1529
1550
  return k(i, r(), n, e);
1530
1551
  }
@@ -1533,7 +1554,7 @@ function nn(e, n) {
1533
1554
  o.value = !1;
1534
1555
  return;
1535
1556
  }
1536
- c = U(l(e.uid), (e) => {
1557
+ c = H(l(e.uid), (e) => {
1537
1558
  o.value = e.exists();
1538
1559
  }, (e) => {
1539
1560
  console.error("[memi-board:likes] onSnapshot failed", e);
@@ -1546,12 +1567,12 @@ function nn(e, n) {
1546
1567
  s.value = !0;
1547
1568
  try {
1548
1569
  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, {
1570
+ 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
1571
  uid: c,
1551
1572
  postId: n,
1552
1573
  boardId: e,
1553
- createdAt: K()
1554
- }), t.update(o, { likeCount: V(1) }), !0));
1574
+ createdAt: G()
1575
+ }), t.update(o, { likeCount: B(1) }), !0));
1555
1576
  } finally {
1556
1577
  s.value = !1;
1557
1578
  }
@@ -1562,11 +1583,11 @@ function nn(e, n) {
1562
1583
  toggleLike: u
1563
1584
  };
1564
1585
  }
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;
1586
+ var an = Symbol.for("memi-board:comment-likes");
1587
+ function on(e, t) {
1588
+ 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
1589
  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) => {
1590
+ 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
1591
  let t = /* @__PURE__ */ new Set();
1571
1592
  for (let n of e.docs) {
1572
1593
  let e = n.data().commentId;
@@ -1590,7 +1611,7 @@ function an(e, t) {
1590
1611
  if (l.value) return d(e);
1591
1612
  l.value = e;
1592
1613
  try {
1593
- let i = k(r, n(), e, t), l = s(r, n(), e), u = await re(r, async (n) => {
1614
+ let i = k(r, n(), e, t), l = s(r, n(), e), u = await ie(r, async (n) => {
1594
1615
  let r = await n.get(i), s = await n.get(l);
1595
1616
  if (!s.exists()) throw Error("댓글을 찾을 수 없습니다.");
1596
1617
  let c = Number(s.data()?.likeCount ?? 0);
@@ -1600,7 +1621,7 @@ function an(e, t) {
1600
1621
  boardId: a.value,
1601
1622
  commentId: e,
1602
1623
  target: "comment",
1603
- createdAt: K()
1624
+ createdAt: G()
1604
1625
  }), n.update(l, { likeCount: c + 1 }), !0);
1605
1626
  }), d = new Set(c.value);
1606
1627
  return u ? d.add(e) : d.delete(e), c.value = d, u;
@@ -1616,7 +1637,7 @@ function an(e, t) {
1616
1637
  }
1617
1638
  //#endregion
1618
1639
  //#region src/composables/useMemiBoardReports.ts
1619
- var on = 200, sn = [
1640
+ var sn = 200, cn = [
1620
1641
  {
1621
1642
  value: "spam",
1622
1643
  label: "스팸·광고"
@@ -1638,17 +1659,17 @@ var on = 200, sn = [
1638
1659
  label: "기타"
1639
1660
  }
1640
1661
  ];
1641
- function cn(e) {
1642
- return sn.find((t) => t.value === e)?.label || e || "신고";
1662
+ function ln(e) {
1663
+ return cn.find((t) => t.value === e)?.label || e || "신고";
1643
1664
  }
1644
- function ln(e, t) {
1645
- let n = () => h(), i = Q(), a = ae(), o = M(!1), s = M(!1), c;
1665
+ function un(e, t) {
1666
+ let n = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
1646
1667
  P(a, (e) => {
1647
1668
  if (c?.(), c = void 0, !e) {
1648
1669
  o.value = !1;
1649
1670
  return;
1650
1671
  }
1651
- c = U(r(i, n(), t, e.uid), (e) => {
1672
+ c = H(r(i, n(), t, e.uid), (e) => {
1652
1673
  o.value = e.exists();
1653
1674
  }, (e) => {
1654
1675
  console.error("[memi-board:reports] onSnapshot failed", e);
@@ -1659,13 +1680,13 @@ function ln(e, t) {
1659
1680
  if (!l) throw Error("로그인이 필요합니다.");
1660
1681
  if (s.value) return;
1661
1682
  if (c.authorUid && c.authorUid === l) throw Error("자신의 글은 신고할 수 없습니다.");
1662
- let u = sn.some((e) => e.value === c.reason) ? c.reason : null;
1683
+ let u = cn.some((e) => e.value === c.reason) ? c.reason : null;
1663
1684
  if (!u) throw Error("신고 사유를 선택해 주세요.");
1664
1685
  let d = (c.detail || "").trim();
1665
1686
  if (d.length > 200) throw Error("자세한 내용은 200자까지입니다.");
1666
1687
  s.value = !0;
1667
1688
  try {
1668
- await q(r(i, n(), t, l), {
1689
+ await K(r(i, n(), t, l), {
1669
1690
  uid: l,
1670
1691
  target: "post",
1671
1692
  postId: t,
@@ -1676,7 +1697,7 @@ function ln(e, t) {
1676
1697
  postTitle: (c.postTitle || "").trim().slice(0, 200),
1677
1698
  authorUid: c.authorUid || "",
1678
1699
  authorName: c.authorName ?? null,
1679
- createdAt: K()
1700
+ createdAt: G()
1680
1701
  }), o.value = !0;
1681
1702
  } finally {
1682
1703
  s.value = !1;
@@ -1688,9 +1709,9 @@ function ln(e, t) {
1688
1709
  submitReport: l
1689
1710
  };
1690
1711
  }
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;
1712
+ var dn = 20;
1713
+ function fn(e = {}) {
1714
+ let t = () => h(), n = Q(), { canManageContent: a, canManageBoard: o } = ct(), s = e.pageSize ?? dn, c = A(() => N(e.boardId)?.trim() || ""), l = M([]), u = M(!0), d = M(!1), f = M(!1), p = M(""), m = null, g;
1694
1715
  function _(e) {
1695
1716
  return {
1696
1717
  id: e.id,
@@ -1703,8 +1724,8 @@ function dn(e = {}) {
1703
1724
  return;
1704
1725
  }
1705
1726
  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) => {
1727
+ let e = c.value ? [Y("status", "==", "open"), Y("boardId", "==", c.value)] : [Y("status", "==", "open"), Y("target", "==", "post")];
1728
+ g = H(W(i(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), V(s)), (e) => {
1708
1729
  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
1730
  }, (e) => {
1710
1731
  console.error("[memi-board:report-queue] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
@@ -1715,7 +1736,7 @@ function dn(e = {}) {
1715
1736
  if (!d.value && f.value && m && a.value) {
1716
1737
  d.value = !0, p.value = "";
1717
1738
  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));
1739
+ 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
1740
  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
1741
  } catch (e) {
1721
1742
  p.value = e.message || String(e);
@@ -1725,10 +1746,10 @@ function dn(e = {}) {
1725
1746
  }
1726
1747
  }
1727
1748
  async function b(e, i) {
1728
- e.id && o(e.boardId) && await Y(r(n, t(), e.postId, e.uid), {
1749
+ e.id && o(e.boardId) && await J(r(n, t(), e.postId, e.uid), {
1729
1750
  status: i,
1730
- reviewedAt: K(),
1731
- reviewedBy: ae().value?.uid || ""
1751
+ reviewedAt: G(),
1752
+ reviewedBy: Z().value?.uid || ""
1732
1753
  });
1733
1754
  }
1734
1755
  return {
@@ -1744,7 +1765,7 @@ function dn(e = {}) {
1744
1765
  }
1745
1766
  //#endregion
1746
1767
  //#region src/composables/useMemiBoardViews.ts
1747
- function fn() {
1768
+ function pn() {
1748
1769
  let e = () => h(), n = Q();
1749
1770
  function r(t, n) {
1750
1771
  let { postsCollection: r } = e();
@@ -1768,7 +1789,7 @@ function fn() {
1768
1789
  if (c && l && !i(c, l)) {
1769
1790
  a(c, l);
1770
1791
  try {
1771
- await Y(t(n, e(), l), { viewCount: V(1) });
1792
+ await J(t(n, e(), l), { viewCount: B(1) });
1772
1793
  } catch (e) {
1773
1794
  try {
1774
1795
  sessionStorage.removeItem(r(c, l));
@@ -1784,7 +1805,7 @@ function fn() {
1784
1805
  }
1785
1806
  //#endregion
1786
1807
  //#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 = {
1808
+ var mn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", hn = {
1788
1809
  abuse: "욕설·비속어·모욕",
1789
1810
  spam: "스팸·광고",
1790
1811
  adult: "선정적·성인 내용",
@@ -1792,17 +1813,17 @@ var pn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
1792
1813
  other: "부적절한 내용",
1793
1814
  none: ""
1794
1815
  };
1795
- function hn(e) {
1816
+ function gn(e) {
1796
1817
  if (e.via === "local" && e.localHit) {
1797
1818
  let t = e.localHit.trim();
1798
1819
  return t.length > 0 && t.length <= 12 ? `「${t}」 같은 표현은 사용할 수 없습니다. 다른 말로 바꿔 주세요.` : "욕설·비속어가 포함되어 게시할 수 없습니다. 표현을 바꿔 주세요.";
1799
1820
  }
1800
1821
  let t = (e.reason || "").trim();
1801
1822
  if (t) return t;
1802
- let n = e.category && e.category !== "none" ? mn[e.category] || e.category : "";
1823
+ let n = e.category && e.category !== "none" ? hn[e.category] || e.category : "";
1803
1824
  return n ? `${n}이(가) 포함되어 게시할 수 없습니다. 내용을 수정해 주세요.` : "게시할 수 없는 내용이 포함되어 있습니다. 내용을 수정해 주세요.";
1804
1825
  }
1805
- var gn = [
1826
+ var _n = [
1806
1827
  "씨발",
1807
1828
  "시발",
1808
1829
  "시이발",
@@ -1828,10 +1849,10 @@ var gn = [
1828
1849
  "bitch",
1829
1850
  "asshole"
1830
1851
  ];
1831
- function _n(e) {
1852
+ function vn(e) {
1832
1853
  return new RegExp(e.join("|"), "i");
1833
1854
  }
1834
- var vn = /* @__PURE__ */ new Set([
1855
+ var yn = /* @__PURE__ */ new Set([
1835
1856
  "none",
1836
1857
  "abuse",
1837
1858
  "spam",
@@ -1839,7 +1860,7 @@ var vn = /* @__PURE__ */ new Set([
1839
1860
  "violence",
1840
1861
  "other"
1841
1862
  ]);
1842
- function yn(e) {
1863
+ function bn(e) {
1843
1864
  let t = e.trim();
1844
1865
  if (!t) return null;
1845
1866
  let n;
@@ -1857,7 +1878,7 @@ function yn(e) {
1857
1878
  if (typeof n != "object" || !n) return null;
1858
1879
  let r = n;
1859
1880
  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 : "";
1881
+ let i = typeof r.category == "string" && yn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
1861
1882
  return {
1862
1883
  flagged: r.flagged,
1863
1884
  category: i,
@@ -1866,20 +1887,20 @@ function yn(e) {
1866
1887
  }
1867
1888
  //#endregion
1868
1889
  //#region src/composables/useMemiBoardModeration.ts
1869
- var bn = {
1890
+ var xn = {
1870
1891
  flagged: !1,
1871
1892
  category: "none",
1872
1893
  reason: "",
1873
1894
  via: "empty"
1874
1895
  };
1875
- function xn() {
1876
- let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a = _n([...gn, ...e.localBlocklist ?? []]);
1896
+ function Sn() {
1897
+ let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a = vn([..._n, ...e.localBlocklist ?? []]);
1877
1898
  function o(e) {
1878
1899
  let t = e.match(a);
1879
1900
  return t ? {
1880
1901
  flagged: !0,
1881
1902
  category: "abuse",
1882
- reason: hn({
1903
+ reason: gn({
1883
1904
  via: "local",
1884
1905
  localHit: t[0] || "",
1885
1906
  category: "abuse"
@@ -1894,7 +1915,7 @@ function xn() {
1894
1915
  });
1895
1916
  return Ce(i, {
1896
1917
  model: n,
1897
- systemInstruction: pn,
1918
+ systemInstruction: mn,
1898
1919
  generationConfig: {
1899
1920
  temperature: 0,
1900
1921
  maxOutputTokens: 256,
@@ -1923,7 +1944,7 @@ function xn() {
1923
1944
  };
1924
1945
  }
1925
1946
  function u(e, t = "") {
1926
- let n = hn({
1947
+ let n = gn({
1927
1948
  reason: e.reason,
1928
1949
  category: e.category,
1929
1950
  via: e.via
@@ -1951,26 +1972,26 @@ function xn() {
1951
1972
  };
1952
1973
  let a = t.trim();
1953
1974
  if (!a) return {
1954
- ...bn,
1975
+ ...xn,
1955
1976
  via: "empty"
1956
1977
  };
1957
1978
  if (i?.skipFilter) return {
1958
- ...bn,
1979
+ ...xn,
1959
1980
  via: "admin-override"
1960
1981
  };
1961
1982
  let c = o(a);
1962
1983
  if (c) return d(c);
1963
1984
  if (e.enabled === !1) return {
1964
- ...bn,
1985
+ ...xn,
1965
1986
  via: "disabled"
1966
1987
  };
1967
1988
  try {
1968
- let e = yn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
1989
+ let e = bn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
1969
1990
  if (!e) return l();
1970
1991
  let t = {
1971
1992
  flagged: e.flagged,
1972
1993
  category: e.category,
1973
- reason: hn({
1994
+ reason: gn({
1974
1995
  reason: e.reason,
1975
1996
  category: e.category,
1976
1997
  via: "ai"
@@ -1990,14 +2011,14 @@ function xn() {
1990
2011
  via: "restricted"
1991
2012
  };
1992
2013
  if (e.enabled === !1 || !e.moderateImages) return {
1993
- ...bn,
2014
+ ...xn,
1994
2015
  via: "disabled"
1995
2016
  };
1996
2017
  try {
1997
2018
  let e = await new Promise((e, n) => {
1998
2019
  let r = new FileReader();
1999
2020
  r.onload = () => e(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(t);
2000
- }), n = yn((await s().generateContent([{ inlineData: {
2021
+ }), n = bn((await s().generateContent([{ inlineData: {
2001
2022
  mimeType: t.type || "image/jpeg",
2002
2023
  data: e
2003
2024
  } }, "이 이미지를 심사해 주세요."])).response.text());
@@ -2005,7 +2026,7 @@ function xn() {
2005
2026
  let r = {
2006
2027
  flagged: n.flagged,
2007
2028
  category: n.category,
2008
- reason: hn({
2029
+ reason: gn({
2009
2030
  reason: n.reason,
2010
2031
  category: n.category,
2011
2032
  via: "ai"
@@ -2024,7 +2045,7 @@ function xn() {
2024
2045
  }
2025
2046
  //#endregion
2026
2047
  //#region src/composables/useMemiBoardUsers.ts
2027
- var Sn = [
2048
+ var Cn = [
2028
2049
  {
2029
2050
  value: "admin",
2030
2051
  label: "관리자",
@@ -2041,13 +2062,13 @@ var Sn = [
2041
2062
  description: "글과 댓글을 작성하고 본인이 작성한 콘텐츠만 수정·삭제할 수 있습니다."
2042
2063
  }
2043
2064
  ];
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") });
2065
+ function wn(e = {}) {
2066
+ let t = () => h(), n = Q(), r = A(() => N(e.enabled) ?? !0 ? p(n, t()) : null), i = ae(r, { ssrKey: S(t(), "users-management") });
2046
2067
  async function a(e, r) {
2047
- if (!Sn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
2048
- await Y(y(n, t(), e), {
2068
+ if (!Cn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
2069
+ await J(y(n, t(), e), {
2049
2070
  role: r,
2050
- updatedAt: K()
2071
+ updatedAt: G()
2051
2072
  });
2052
2073
  }
2053
2074
  return {
@@ -2058,7 +2079,7 @@ function Cn(e = {}) {
2058
2079
  }
2059
2080
  //#endregion
2060
2081
  //#region src/composables/useMemiBoardUserProfile.ts
2061
- function wn(e) {
2082
+ function Tn(e) {
2062
2083
  let t = Q(), n = () => h(), r = A(() => N(e)), i = A(() => {
2063
2084
  let e = r.value;
2064
2085
  return e ? y(t, n(), e) : null;
@@ -2070,7 +2091,7 @@ function wn(e) {
2070
2091
  }
2071
2092
  //#endregion
2072
2093
  //#region src/utils/section.ts
2073
- var Tn = [
2094
+ var En = [
2074
2095
  3,
2075
2096
  4,
2076
2097
  5,
@@ -2079,7 +2100,7 @@ var Tn = [
2079
2100
  8,
2080
2101
  9,
2081
2102
  12
2082
- ], En = [
2103
+ ], Dn = [
2083
2104
  {
2084
2105
  value: "list",
2085
2106
  label: "게시목록"
@@ -2092,24 +2113,24 @@ var Tn = [
2092
2113
  value: "comments",
2093
2114
  label: "댓글모음"
2094
2115
  }
2095
- ], Dn = [{
2116
+ ], On = [{
2096
2117
  value: "latest",
2097
2118
  label: "최신순"
2098
2119
  }, {
2099
2120
  value: "likes",
2100
2121
  label: "좋아요순"
2101
2122
  }];
2102
- function On(e) {
2123
+ function kn(e) {
2103
2124
  return e === "list" ? 5 : 4;
2104
2125
  }
2105
- function kn(e, t) {
2126
+ function An(e, t) {
2106
2127
  let n = Math.floor(Number(t));
2107
- return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : On(e);
2128
+ return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : kn(e);
2108
2129
  }
2109
- function An(e) {
2130
+ function jn(e) {
2110
2131
  return e === 12 ? null : 12 - e;
2111
2132
  }
2112
- function jn(e) {
2133
+ function Mn(e) {
2113
2134
  return {
2114
2135
  3: "col-span-12 md:col-span-3",
2115
2136
  4: "col-span-12 md:col-span-4",
@@ -2121,36 +2142,36 @@ function jn(e) {
2121
2142
  12: "col-span-12"
2122
2143
  }[e];
2123
2144
  }
2124
- function Mn(e) {
2145
+ function Nn(e) {
2125
2146
  return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
2126
2147
  }
2127
- function Nn(e) {
2148
+ function Pn(e) {
2128
2149
  let t = e.boardId || e.category || "free";
2129
2150
  return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
2130
2151
  }
2131
- function Pn(e) {
2152
+ function Fn(e) {
2132
2153
  return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
2133
2154
  }
2134
- function Fn(e) {
2155
+ function In(e) {
2135
2156
  if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
2136
2157
  }
2137
- function In(e) {
2158
+ function Ln(e) {
2138
2159
  return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
2139
2160
  }
2140
- function Ln(e) {
2161
+ function Rn(e) {
2141
2162
  return e.title?.trim() || e.summary || "게시물";
2142
2163
  }
2143
- function Rn(e) {
2164
+ function zn(e) {
2144
2165
  return e === "image" || e === "video" ? "media" : "list";
2145
2166
  }
2146
- function zn(e) {
2147
- return Rn(e) === "media" ? "미디어" : "목록";
2167
+ function Bn(e) {
2168
+ return zn(e) === "media" ? "미디어" : "목록";
2148
2169
  }
2149
- function Bn(e, t) {
2170
+ function Vn(e, t) {
2150
2171
  return e ? t(e)?.listView ?? "default" : "default";
2151
2172
  }
2152
- function Vn(e, t) {
2153
- let n = e.map((e) => Bn(e.boardId, t));
2173
+ function Hn(e, t) {
2174
+ let n = e.map((e) => Vn(e.boardId, t));
2154
2175
  if (!n.length) return "default";
2155
2176
  if (n.every((e) => e === n[0])) return n[0];
2156
2177
  let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
@@ -2158,27 +2179,27 @@ function Vn(e, t) {
2158
2179
  }
2159
2180
  //#endregion
2160
2181
  //#region src/composables/useMemiBoardSections.ts
2161
- var Hn = [];
2162
- function Un(e) {
2182
+ var Un = [];
2183
+ function Wn(e) {
2163
2184
  let t = Number(e.cols);
2164
- if (Tn.includes(t)) return t;
2185
+ if (En.includes(t)) return t;
2165
2186
  let n = e.width;
2166
2187
  return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
2167
2188
  }
2168
- function Wn(e) {
2189
+ function Gn(e) {
2169
2190
  let t = e.height ?? e.size;
2170
2191
  return t === "sm" || t === "lg" ? t : "md";
2171
2192
  }
2172
- function Gn(e) {
2193
+ function Kn(e) {
2173
2194
  return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
2174
2195
  }
2175
- function Kn(e) {
2196
+ function qn(e) {
2176
2197
  return e.sort === "likes" ? "likes" : "latest";
2177
2198
  }
2178
- function qn(e) {
2199
+ function Jn(e) {
2179
2200
  return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
2180
2201
  }
2181
- function Jn(e, t) {
2202
+ function Yn(e, t) {
2182
2203
  let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
2183
2204
  for (let e of n) {
2184
2205
  let n = String(e || "").trim();
@@ -2186,44 +2207,44 @@ function Jn(e, t) {
2186
2207
  }
2187
2208
  return r;
2188
2209
  }
2189
- function Yn(e, t) {
2190
- let n = Gn(e), r = kn(n, e.count);
2210
+ function Xn(e, t) {
2211
+ let n = Kn(e), r = An(n, e.count);
2191
2212
  return {
2192
2213
  id: String(e.id || `box-${t + 1}`),
2193
2214
  title: String(e.title || `섹션 ${t + 1}`),
2194
2215
  showTitle: e.showTitle !== !1,
2195
2216
  kind: n,
2196
- boardId: qn(e),
2217
+ boardId: Jn(e),
2197
2218
  count: r,
2198
- postIds: Jn(e, r),
2199
- sort: Kn(e),
2200
- cols: Un(e),
2201
- height: Wn(e),
2219
+ postIds: Yn(e, r),
2220
+ sort: qn(e),
2221
+ cols: Wn(e),
2222
+ height: Gn(e),
2202
2223
  order: t
2203
2224
  };
2204
2225
  }
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)));
2226
+ function Zn() {
2227
+ let e = Q(), t = te(e, "settings", "homeLayout"), { data: n, pending: r } = oe(t), i = A(() => (Array.isArray(n.value?.blocks) ? n.value.blocks : Un).map((e, t) => Xn(e, t)));
2207
2228
  async function a(e) {
2208
- await q(t, {
2229
+ await K(t, {
2209
2230
  columns: 12,
2210
2231
  blocks: e.map((e, t) => {
2211
- let n = e, r = Gn(n), i = kn(r, e.count);
2232
+ let n = e, r = Kn(n), i = An(r, e.count);
2212
2233
  return {
2213
2234
  id: e.id,
2214
2235
  title: e.title.trim() || `섹션 ${t + 1}`,
2215
2236
  showTitle: e.showTitle !== !1,
2216
2237
  kind: r,
2217
- boardId: qn(n),
2238
+ boardId: Jn(n),
2218
2239
  count: i,
2219
- postIds: Jn(n, i),
2220
- sort: Kn(n),
2221
- cols: Un(n),
2222
- height: Wn(n),
2240
+ postIds: Yn(n, i),
2241
+ sort: qn(n),
2242
+ cols: Wn(n),
2243
+ height: Gn(n),
2223
2244
  order: t
2224
2245
  };
2225
2246
  }),
2226
- updatedAt: K()
2247
+ updatedAt: G()
2227
2248
  });
2228
2249
  }
2229
2250
  return {
@@ -2238,19 +2259,19 @@ function Xn() {
2238
2259
  }
2239
2260
  //#endregion
2240
2261
  //#region src/composables/useMemiBoardMiniPosts.ts
2241
- function Zn(e, t) {
2262
+ function Qn(e, t) {
2242
2263
  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}`) });
2264
+ let i = Math.max(1, Math.floor(Number(N(t)) || 5)), a = N(e)?.trim() || "", s = [Y("isPublished", "==", !0), Y("listed", "==", !0)];
2265
+ return a && s.unshift(Y("boardId", "==", a)), W(o(n, r()), ...s, U("createdAt", "desc"), V(i));
2266
+ }), { data: s, pending: c, error: l } = ae(a, { ssrKey: S(r(), `mini-list/${i}`) });
2246
2267
  return {
2247
2268
  posts: A(() => s.value ?? []),
2248
2269
  pending: c,
2249
2270
  error: l
2250
2271
  };
2251
2272
  }
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}`) });
2273
+ function $n(e) {
2274
+ 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
2275
  return {
2255
2276
  posts: A(() => {
2256
2277
  let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
@@ -2266,7 +2287,12 @@ function Qn(e) {
2266
2287
  }
2267
2288
  //#endregion
2268
2289
  //#region src/data/versionHistory.ts
2269
- var $n = [
2290
+ var er = [
2291
+ {
2292
+ version: "0.44.0",
2293
+ date: "2026-10-01",
2294
+ highlights: ["글을 저장하고 미리보기가 뜨기까지 기다리는 시간이 줄었어요 (특히 iPhone·Mac Safari)"]
2295
+ },
2270
2296
  {
2271
2297
  version: "0.42.0",
2272
2298
  date: "2026-08-27",
@@ -2536,7 +2562,7 @@ var $n = [
2536
2562
  highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
2537
2563
  note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
2538
2564
  }
2539
- ], er = /* @__PURE__ */ Ae(((e, t) => {
2565
+ ], tr = /* @__PURE__ */ Ae(((e, t) => {
2540
2566
  (function(n, r) {
2541
2567
  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
2568
  })(e, (function() {
@@ -2830,7 +2856,7 @@ var $n = [
2830
2856
  return w(1e3 * e);
2831
2857
  }, w.en = b[y], w.Ls = b, w.p = {}, w;
2832
2858
  }));
2833
- })), tr = /* @__PURE__ */ Ae(((e, t) => {
2859
+ })), nr = /* @__PURE__ */ Ae(((e, t) => {
2834
2860
  (function(n, r) {
2835
2861
  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
2862
  })(e, (function() {
@@ -2934,9 +2960,9 @@ var $n = [
2934
2960
  };
2935
2961
  };
2936
2962
  }));
2937
- })), nr = /* @__PURE__ */ Ae(((e, t) => {
2963
+ })), rr = /* @__PURE__ */ Ae(((e, t) => {
2938
2964
  (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);
2965
+ typeof e == "object" && t !== void 0 ? t.exports = r(tr()) : typeof define == "function" && define.amd ? define(["dayjs"], r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs_locale_ko = r(n.dayjs);
2940
2966
  })(e, (function(e) {
2941
2967
  function t(e) {
2942
2968
  return e && typeof e == "object" && "default" in e ? e : { default: e };
@@ -2984,24 +3010,24 @@ var $n = [
2984
3010
  };
2985
3011
  return n.default.locale(r, null, !0), r;
2986
3012
  }));
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) {
3013
+ })), ir = /* @__PURE__ */ Me(tr(), 1), ar = /* @__PURE__ */ Me(nr(), 1);
3014
+ rr(), ir.default.extend(ar.default), ir.default.locale("ko");
3015
+ function or(e) {
2990
3016
  return e?.toDate ? e.toDate().toLocaleDateString("ko-KR") : "";
2991
3017
  }
2992
- function or(e, t = Date.now()) {
2993
- return e?.toDate ? (0, rr.default)(e.toDate()).from((0, rr.default)(t)) : "방금 전";
3018
+ function sr(e, t = Date.now()) {
3019
+ return e?.toDate ? (0, ir.default)(e.toDate()).from((0, ir.default)(t)) : "방금 전";
2994
3020
  }
2995
- function sr(e) {
2996
- return e?.toDate ? (0, rr.default)(e.toDate()).format("YYYY년 M월 D일 HH:mm:ss") : "시간 확인 중";
3021
+ function cr(e) {
3022
+ return e?.toDate ? (0, ir.default)(e.toDate()).format("YYYY년 M월 D일 HH:mm:ss") : "시간 확인 중";
2997
3023
  }
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)}`];
3024
+ function lr(e, t) {
3025
+ let n = cr(e), r = e?.toMillis?.(), i = t?.toMillis?.();
3026
+ return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${cr(t)}`];
3001
3027
  }
3002
3028
  //#endregion
3003
3029
  //#region src/composables/useMemiBoardWritingAssistant.ts
3004
- var lr = 10, ur = 864e5, dr = 200, fr = {
3030
+ var ur = 10, dr = 864e5, fr = 200, pr = {
3005
3031
  proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
3006
3032
  polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
3007
3033
  continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
@@ -3010,40 +3036,40 @@ var lr = 10, ur = 864e5, dr = 200, fr = {
3010
3036
  "translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
3011
3037
  title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
3012
3038
  };
3013
- function pr(e) {
3014
- if (e.action !== "custom") return fr[e.action];
3015
- let t = e.customInstruction?.trim().slice(0, dr);
3039
+ function mr(e) {
3040
+ if (e.action !== "custom") return pr[e.action];
3041
+ let t = e.customInstruction?.trim().slice(0, fr);
3016
3042
  if (!t) throw Error("어떻게 바꿀지 지시문을 입력해 주세요.");
3017
3043
  return `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${t}`;
3018
3044
  }
3019
- function mr(e) {
3045
+ function hr(e) {
3020
3046
  return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
3021
3047
  }
3022
- function hr(e) {
3048
+ function gr(e) {
3023
3049
  return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
3024
3050
  }
3025
- function gr() {
3026
- let e = se(), t = Q(), n = ae(), r = c();
3051
+ function _r() {
3052
+ let e = se(), t = Q(), n = Z(), r = c();
3027
3053
  async function i() {
3028
3054
  let e = n.value?.uid;
3029
3055
  if (!e) throw Error("AI 글쓰기 도우미는 로그인 후 사용할 수 있습니다.");
3030
- await re(t, async (n) => {
3056
+ await ie(t, async (n) => {
3031
3057
  let r = y(t, h(), e), i = await n.get(r);
3032
3058
  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;
3059
+ let a = i.data(), o = gr(a.aiWritingWindowAt), s = Math.max(0, Math.floor(Number(a.aiWritingCount) || 0)), c = Date.now(), l = o != null && c - o < dr;
3034
3060
  if (l && s >= 10) {
3035
- let e = o + ur, t = Math.max(1, Math.ceil((e - c) / 36e5));
3061
+ let e = o + dr, t = Math.max(1, Math.ceil((e - c) / 36e5));
3036
3062
  throw Error(`AI 글쓰기 도우미는 하루 10회까지 사용할 수 있습니다. 약 ${t}시간 후 다시 이용해 주세요.`);
3037
3063
  }
3038
3064
  n.update(r, {
3039
3065
  aiWritingCount: l ? s + 1 : 1,
3040
- aiWritingWindowAt: l ? a.aiWritingWindowAt : K(),
3041
- updatedAt: K()
3066
+ aiWritingWindowAt: l ? a.aiWritingWindowAt : G(),
3067
+ updatedAt: G()
3042
3068
  });
3043
3069
  });
3044
3070
  }
3045
3071
  async function a(t) {
3046
- let n = pr(t);
3072
+ let n = mr(t);
3047
3073
  if (!t.content.trim()) throw Error("AI로 다듬을 내용을 먼저 입력해 주세요.");
3048
3074
  await i();
3049
3075
  let a = r.moderation ?? {}, o = Se(e, {
@@ -3064,7 +3090,7 @@ function gr() {
3064
3090
  `작업: ${n}`,
3065
3091
  t.title ? `현재 제목: ${t.title}` : "",
3066
3092
  `본문:\n${c.slice(0, 12e3)}`
3067
- ].filter(Boolean).join("\n\n"), u = mr((await s.generateContent(l)).response.text());
3093
+ ].filter(Boolean).join("\n\n"), u = hr((await s.generateContent(l)).response.text());
3068
3094
  if (!u) throw Error("AI가 결과를 만들지 못했습니다. 다시 시도해 주세요.");
3069
3095
  return u;
3070
3096
  }
@@ -3072,14 +3098,14 @@ function gr() {
3072
3098
  }
3073
3099
  //#endregion
3074
3100
  //#region src/utils/renderMarkdown.ts
3075
- function _r(e) {
3101
+ function vr(e) {
3076
3102
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
3077
3103
  }
3078
- function vr(e) {
3104
+ function yr(e) {
3079
3105
  let t = e;
3080
3106
  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
3107
  }
3082
- function yr(e) {
3108
+ function br(e) {
3083
3109
  if (!e?.trim()) return "";
3084
3110
  let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
3085
3111
  function c() {
@@ -3088,7 +3114,7 @@ function yr(e) {
3088
3114
  return;
3089
3115
  }
3090
3116
  let e = o;
3091
- n.push(`<${e}>${s.map((e) => `<li>${vr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3117
+ n.push(`<${e}>${s.map((e) => `<li>${yr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3092
3118
  }
3093
3119
  for (; r < t.length;) {
3094
3120
  let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
@@ -3097,7 +3123,7 @@ function yr(e) {
3097
3123
  continue;
3098
3124
  }
3099
3125
  if (i) {
3100
- a.push(_r(e)), r++;
3126
+ a.push(vr(e)), r++;
3101
3127
  continue;
3102
3128
  }
3103
3129
  if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
@@ -3108,24 +3134,24 @@ function yr(e) {
3108
3134
  if (u) {
3109
3135
  c();
3110
3136
  let e = u[1].length;
3111
- n.push(`<h${e} class="font-semibold mt-4 mb-2">${vr(_r(u[2]))}</h${e}>`), r++;
3137
+ n.push(`<h${e} class="font-semibold mt-4 mb-2">${yr(vr(u[2]))}</h${e}>`), r++;
3112
3138
  continue;
3113
3139
  }
3114
3140
  if (e.startsWith("> ")) {
3115
3141
  c();
3116
3142
  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>`);
3143
+ for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(vr((t[r] ?? "").slice(2))), r++;
3144
+ n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${yr(e.join("<br />"))}</blockquote>`);
3119
3145
  continue;
3120
3146
  }
3121
3147
  let d = e.match(/^[-*+]\s+(.+)$/);
3122
3148
  if (d) {
3123
- o && o !== "ul" && c(), o = "ul", s.push(_r(d[1])), r++;
3149
+ o && o !== "ul" && c(), o = "ul", s.push(vr(d[1])), r++;
3124
3150
  continue;
3125
3151
  }
3126
3152
  let f = e.match(/^\d+\.\s+(.+)$/);
3127
3153
  if (f) {
3128
- o && o !== "ol" && c(), o = "ol", s.push(_r(f[1])), r++;
3154
+ o && o !== "ol" && c(), o = "ol", s.push(vr(f[1])), r++;
3129
3155
  continue;
3130
3156
  }
3131
3157
  if (!e.trim()) {
@@ -3137,13 +3163,13 @@ function yr(e) {
3137
3163
  for (; r < t.length;) {
3138
3164
  let e = t[r] ?? "";
3139
3165
  if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
3140
- p.push(_r(e)), r++;
3166
+ p.push(vr(e)), r++;
3141
3167
  }
3142
- n.push(`<p class="my-2 leading-relaxed">${vr(p.join("<br />"))}</p>`);
3168
+ n.push(`<p class="my-2 leading-relaxed">${yr(p.join("<br />"))}</p>`);
3143
3169
  }
3144
3170
  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
3171
  }
3146
3172
  //#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 };
3173
+ export { Jt as AUTHOR_MEMO_MAX_LENGTH, En as BOARD_SECTION_COLS, Dn as BOARD_SECTION_KINDS, On as BOARD_SECTION_SORTS, Cn as BOARD_USER_ROLES, $t 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, sn as REPORT_DETAIL_MAX_LENGTH, cn as REPORT_REASONS, ur 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, An as clampSectionCount, s as commentDoc, E as commentsCol, C as configureMemiBoard, kn as defaultSectionCount, tt as effectiveModerationBlockCount, lt as extractEditorImageUrls, Ge as fetchPublicListForSeo, We as fetchPublicPostForSeo, or as formatDate, cr as formatFullDate, sr as formatRelativeDate, it as formatRestrictedUntilLabel, lr as formatTimestampDetails, wt as hasBodyImage, Ct as hasBodyText, qe as isAssignedStaff, Tt as isContentEmpty, It as isFirestorePermissionDenied, rt as isModerationWriteRestricted, k as likeDoc, l as likeDocId, O as likesCol, an as memiBoardCommentLikesKey, Vn as miniBoardView, In as miniCommentLink, Fn as miniMoreLink, Ln as miniPostImage, Pn as miniPostLink, Rn as miniPostTitle, Hn as miniPostsView, zn as miniViewGroup, Bn as miniViewLabel, nt as moderationWriteRestrictedUntilMs, Be as normalizeBasePath, Xn as normalizeBoardSection, jn as pairSectionCols, xt as plainTextFromHtml, a as postBodyDoc, t as postDoc, dt as postNamespaceFromStoragePath, D as postStorageFolder, o as postsCol, br as renderMarkdownToHtml, r as reportDoc, n as reportDocId, ln as reportReasonLabel, i as reportsCol, _ as resolveBoardPathConfig, Ve as resolvePublicSeoDb, Mn as sectionColClass, Nn 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, Xt as useMemiBoardAuthorMemo, qt as useMemiBoardCommentFeed, on as useMemiBoardCommentLikes, tn as useMemiBoardComments, c as useMemiBoardConfig, rn as useMemiBoardLikes, Qn as useMemiBoardMiniLatest, $n as useMemiBoardMiniPicked, Sn as useMemiBoardModeration, Vt as useMemiBoardPost, Bt as useMemiBoardPostList, Rt as useMemiBoardPosts, nn as useMemiBoardReplies, fn as useMemiBoardReportQueue, un as useMemiBoardReports, Zn as useMemiBoardSections, Pt as useMemiBoardSettings, Gt as useMemiBoardUserComments, Ut as useMemiBoardUserPosts, Tn as useMemiBoardUserProfile, wn as useMemiBoardUsers, pn as useMemiBoardViews, _r as useMemiBoardWritingAssistant, er as versionHistory, Ot as videoListCoverUrl, Dt as youtubeId };
3148
3174
 
3149
3175
  //# sourceMappingURL=index.js.map