memi-board 0.42.1 → 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,18 +1,30 @@
1
- import { A as e, C as t, D as n, E as r, M as i, N as a, O as o, S as s, T as c, _ as l, a as u, b as d, c as f, d as p, f as m, g as h, h as g, i as _, j as v, k as y, l as b, m as x, n as S, o as C, p as w, r as T, s as E, u as D, v as O, w as k, x as A, y as j } from "./slugify-Cyq-Gg8X.js";
2
- import { computed as M, onScopeDispose as N, reactive as ee, ref as P, toValue as F, watch as I } from "vue";
3
- import { deleteDoc as te, deleteField as ne, doc as re, documentId as L, endBefore as ie, getDoc as R, getDocs as z, increment as B, limit as V, limitToLast as ae, onSnapshot as H, orderBy as U, query as W, runTransaction as oe, 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 se, useCurrentUser as Z, useDocument as ce, useFirebaseApp as le, useFirebaseAuth as ue, useFirestore as Q } from "vuefire";
5
- import { GoogleAuthProvider as de, OAuthProvider as fe, createUserWithEmailAndPassword as pe, signInWithEmailAndPassword as me, signInWithPopup as he, signOut as ge, updateProfile as _e } from "firebase/auth";
6
- import { deleteObject as ve, getStorage as ye, listAll as be, ref as xe } from "firebase/storage";
7
- import { GoogleAIBackend as Se, Schema as Ce, getAI as we, getGenerativeModel as Te } from "firebase/ai";
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
+ 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 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
+ 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
+ import { deleteObject as ge, getStorage as _e, listAll as ve, ref as ye } from "firebase/storage";
7
+ import { GoogleAIBackend as be, Schema as xe, getAI as Se, getGenerativeModel as Ce } from "firebase/ai";
8
+ //#region \0rolldown/runtime.js
9
+ var we = Object.create, Te = Object.defineProperty, Ee = Object.getOwnPropertyDescriptor, De = Object.getOwnPropertyNames, Oe = Object.getPrototypeOf, ke = Object.prototype.hasOwnProperty, Ae = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), je = (e, t, n, r) => {
10
+ if (t && typeof t == "object" || typeof t == "function") for (var i = De(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !ke.call(e, s) && s !== n && Te(e, s, {
11
+ get: ((e) => t[e]).bind(null, s),
12
+ enumerable: !(r = Ee(t, s)) || r.enumerable
13
+ });
14
+ return e;
15
+ }, Me = (e, t, n) => (n = e == null ? {} : we(Oe(e)), je(t || !e || !e.__esModule || !ke.call(e, "default") ? Te(n, "default", {
16
+ value: e,
17
+ enumerable: !0
18
+ }) : n, e));
19
+ //#endregion
8
20
  //#region src/utils/boardSeo.ts
9
- function Ee(e) {
21
+ function Ne(e) {
10
22
  if (typeof e != "string") return null;
11
23
  let t = e.trim();
12
24
  return /^https?:\/\//i.test(t) ? t : null;
13
25
  }
14
- function De(e) {
15
- let t = Ee(e);
26
+ function Pe(e) {
27
+ let t = Ne(e);
16
28
  if (!t) return null;
17
29
  if (!/firebasestorage\.googleapis\.com/i.test(t)) return t;
18
30
  try {
@@ -29,42 +41,42 @@ function De(e) {
29
41
  return t;
30
42
  }
31
43
  }
32
- function Oe(e, t, n = "") {
44
+ function Fe(e, t, n = "") {
33
45
  let r = t.replace(/\/$/, ""), i = e.trim();
34
- return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? Oe(n, t) : r;
46
+ return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? Fe(n, t) : r;
35
47
  }
36
- function ke(e, t, n, r) {
48
+ function Ie(e, t, n, r) {
37
49
  let i = r?.trim().slice(0, 40), a = e.trim() || i || "사진", o = t?.trim(), s = n.trim() || "Board";
38
50
  return o ? `${a} · ${o} | ${s}` : `${a} | ${s}`;
39
51
  }
40
- function Ae(e) {
52
+ function Le(e) {
41
53
  let t = [];
42
54
  return e.summary?.trim() ? t.push(e.summary.trim().slice(0, 140)) : t.push("게시판 글"), e.categoryLabel?.trim() && t.push(e.categoryLabel.trim()), e.authorName?.trim() && t.push(e.authorName.trim()), t.join(" · ").slice(0, 200);
43
55
  }
44
- function je(e, t) {
56
+ function Re(e, t) {
45
57
  let n = t.trim() || "Board", r = e?.trim();
46
58
  return r && r !== "전체" ? `${r} 게시판 | ${n}` : `게시판 | ${n}`;
47
59
  }
48
- function Me(e) {
60
+ function ze(e) {
49
61
  if (e.description?.trim()) return e.description.trim().slice(0, 200);
50
62
  let t = e.categoryLabel?.trim(), n = t && t !== "전체" ? `${t} 게시판 — 소식을 확인하세요.` : "게시판 — 공지와 이야기를 확인하세요.", r = (e.recentTitles || []).filter(Boolean).slice(0, 3);
51
63
  return r.length ? `${n} ${r.map((e) => `「${e}」`).join(" ")}`.slice(0, 200) : n.slice(0, 200);
52
64
  }
53
- function Ne(e) {
65
+ function Be(e) {
54
66
  let t = (e || "/board").trim() || "/board";
55
67
  return (t.startsWith("/") ? t : `/${t}`).replace(/\/$/, "") || "/board";
56
68
  }
57
69
  //#endregion
58
70
  //#region src/composables/fetchPublicSeo.ts
59
- function Pe() {
71
+ function Ve() {
60
72
  return {
61
73
  db: Q(),
62
- paths: _()
74
+ paths: h()
63
75
  };
64
76
  }
65
- async function Fe(e, t) {
77
+ async function He(e, t) {
66
78
  try {
67
- let n = await R(v(e.db, e.paths, t));
79
+ let n = await R(g(e.db, e.paths, t));
68
80
  if (!n.exists()) return {
69
81
  label: t,
70
82
  description: "",
@@ -84,7 +96,7 @@ async function Fe(e, t) {
84
96
  };
85
97
  }
86
98
  }
87
- function Ie(e) {
99
+ function Ue(e) {
88
100
  if (e && typeof e == "object" && "toDate" in e) try {
89
101
  let t = e.toDate();
90
102
  return t instanceof Date ? t.toISOString() : null;
@@ -93,36 +105,36 @@ function Ie(e) {
93
105
  }
94
106
  return null;
95
107
  }
96
- async function Le(e, t, n) {
108
+ async function We(e, t, n) {
97
109
  let r = e.trim(), i = t.trim();
98
110
  if (!r || !i) return null;
99
- let a = n ?? Pe();
100
- a.paths = y(a.paths);
101
- let o = await Fe(a, r);
102
- if (o.hidden) return null;
111
+ let a = n ?? Ve();
112
+ a.paths = _(a.paths);
113
+ let s = await He(a, r);
114
+ if (s.hidden) return null;
103
115
  try {
104
- let e = (await z(W(c(a.db, a.paths), Y("boardId", "==", r), Y("slug", "==", i), Y("listed", "==", !0), Y("isPublished", "==", !0), V(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];
105
117
  if (!e) return null;
106
118
  let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title.trim() : "";
107
119
  return n ? {
108
120
  id: e.id,
109
121
  slug: typeof t.slug == "string" ? t.slug : i,
110
122
  category: r,
111
- categoryLabel: o.label,
123
+ categoryLabel: s.label,
112
124
  title: n,
113
125
  summary: typeof t.summary == "string" ? t.summary.trim().slice(0, 200) : "",
114
- previewImage: De(t.previewImage),
126
+ previewImage: Pe(t.previewImage),
115
127
  authorName: typeof t.authorName == "string" && t.authorName.trim() ? t.authorName.trim() : null,
116
- createdAt: Ie(t.createdAt)
128
+ createdAt: Ue(t.createdAt)
117
129
  } : null;
118
130
  } catch (e) {
119
131
  return import.meta.dev && console.warn("[memi-board] fetchPublicPostForSeo failed", e), null;
120
132
  }
121
133
  }
122
- async function Re(e, t) {
123
- let n = e?.trim() || null, r = t ?? Pe();
124
- if (r.paths = y(r.paths), n) {
125
- let e = await Fe(r, n);
134
+ async function Ge(e, t) {
135
+ let n = e?.trim() || null, r = t ?? Ve();
136
+ if (r.paths = _(r.paths), n) {
137
+ let e = await He(r, n);
126
138
  if (e.hidden) return {
127
139
  kind: "category",
128
140
  category: n,
@@ -131,7 +143,7 @@ async function Re(e, t) {
131
143
  ogImage: null,
132
144
  recentTitles: []
133
145
  };
134
- let { recentTitles: t, ogImage: i } = await ze(r, n);
146
+ let { recentTitles: t, ogImage: i } = await Ke(r, n);
135
147
  return {
136
148
  kind: "category",
137
149
  category: n,
@@ -150,13 +162,13 @@ async function Re(e, t) {
150
162
  recentTitles: []
151
163
  };
152
164
  }
153
- async function ze(e, t) {
165
+ async function Ke(e, t) {
154
166
  let n = [], r = null;
155
167
  try {
156
- let i = await z(W(c(e.db, e.paths), Y("boardId", "==", t), Y("listed", "==", !0), Y("isPublished", "==", !0), U("createdAt", "desc"), V(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)));
157
169
  for (let e of i.docs) {
158
170
  let t = e.data() ?? {}, i = typeof t.title == "string" ? t.title.trim() : "";
159
- i && n.length < 5 && n.push(i), r ||= De(t.previewImage);
171
+ i && n.length < 5 && n.push(i), r ||= Pe(t.previewImage);
160
172
  }
161
173
  } catch (e) {
162
174
  import.meta.dev && console.warn("[memi-board] loadRecentListed failed", e);
@@ -168,31 +180,31 @@ async function ze(e, t) {
168
180
  }
169
181
  //#endregion
170
182
  //#region src/utils/boardAccess.ts
171
- function Be(e, t) {
183
+ function qe(e, t) {
172
184
  return !e || !t ? !1 : (t.allowedStaffUids ?? []).includes(e);
173
185
  }
174
- function Ve(e, t, n, r) {
175
- return e ? t ? !0 : n ? Be(e, r) : !1 : !1;
186
+ function Je(e, t, n, r) {
187
+ return e ? t ? !0 : n ? qe(e, r) : !1 : !1;
176
188
  }
177
- function He(e, t, n, r) {
189
+ function Ye(e, t, n, r) {
178
190
  if (!e) return !1;
179
- if (r?.visibility === "hidden") return Ve(e, t, n, r);
191
+ if (r?.visibility === "hidden") return Je(e, t, n, r);
180
192
  let i = r?.commentWriteRole ?? "user";
181
- return i === "admin" ? t : i !== "staff" || Ve(e, t, n, r);
193
+ return i === "admin" ? t : i !== "staff" || Je(e, t, n, r);
182
194
  }
183
195
  //#endregion
184
196
  //#region src/composables/boardLookup.ts
185
- var Ue;
186
- function We(e) {
187
- Ue = e;
197
+ var Xe;
198
+ function Ze(e) {
199
+ Xe = e;
188
200
  }
189
- function Ge(e) {
190
- return Ue?.(e);
201
+ function Qe(e) {
202
+ return Xe?.(e);
191
203
  }
192
204
  //#endregion
193
205
  //#region src/utils/moderation-strike.ts
194
- var Ke = 10, qe = 864e5;
195
- function Je(e, t, n = Date.now(), r = qe) {
206
+ var $e = 10, et = 864e5;
207
+ function tt(e, t, n = Date.now(), r = et) {
196
208
  let i = Math.max(0, Math.floor(Number(e) || 0));
197
209
  if (i <= 0) return 0;
198
210
  let a = typeof t == "number" && Number.isFinite(t) ? t : null;
@@ -200,7 +212,7 @@ function Je(e, t, n = Date.now(), r = qe) {
200
212
  let o = Math.floor((n - a) / r);
201
213
  return Math.max(0, i - o);
202
214
  }
203
- function Ye(e, t, n = Date.now(), r = 10, i = qe) {
215
+ function nt(e, t, n = Date.now(), r = 10, i = et) {
204
216
  let a = Math.max(0, Math.floor(Number(e) || 0));
205
217
  if (a < r) return null;
206
218
  let o = typeof t == "number" && Number.isFinite(t) ? t : null;
@@ -208,17 +220,17 @@ function Ye(e, t, n = Date.now(), r = 10, i = qe) {
208
220
  let s = o + (a - (r - 1)) * i;
209
221
  return s > n ? s : null;
210
222
  }
211
- function Xe(e, t, n = Date.now(), r = 10, i = qe) {
212
- return Ye(e, t, n, r, i) != null;
223
+ function rt(e, t, n = Date.now(), r = 10, i = et) {
224
+ return nt(e, t, n, r, i) != null;
213
225
  }
214
- function Ze(e, t = Date.now()) {
226
+ function it(e, t = Date.now()) {
215
227
  let n = Math.max(0, e - t), r = Math.ceil(n / 36e5);
216
228
  if (r <= 0) return "곧 해제";
217
229
  if (r < 24) return `약 ${r}시간 후 해제`;
218
230
  let i = Math.floor(r / 24), a = r % 24;
219
231
  return a === 0 ? `약 ${i}일 후 해제` : `약 ${i}일 ${a}시간 후 해제`;
220
232
  }
221
- function Qe(e) {
233
+ function at(e) {
222
234
  if (e == null) return null;
223
235
  if (typeof e == "number" && Number.isFinite(e)) return e;
224
236
  if (typeof e == "object" && e && "toMillis" in e && typeof e.toMillis == "function") return e.toMillis();
@@ -230,39 +242,39 @@ function Qe(e) {
230
242
  }
231
243
  //#endregion
232
244
  //#region src/composables/useMemiBoardAuth.ts
233
- var $e = "__MEMI_BOARD_AUTH_STATE__";
234
- function et() {
245
+ var ot = "__MEMI_BOARD_AUTH_STATE__";
246
+ function st() {
235
247
  let e = globalThis;
236
- return e[$e] || (e[$e] = {
237
- role: P("user"),
238
- rolePending: P(!0),
239
- rawBlockCount: P(0),
240
- blockAtMs: P(null),
248
+ return e[ot] || (e[ot] = {
249
+ role: M("user"),
250
+ rolePending: M(!0),
251
+ rawBlockCount: M(0),
252
+ blockAtMs: M(null),
241
253
  watchStarted: !1
242
- }), e[$e];
254
+ }), e[ot];
243
255
  }
244
- function tt() {
245
- let e = u(), t = et(), n = Q(), r = ue(), i = Z(), { role: a, rolePending: o, rawBlockCount: s, blockAtMs: c } = t;
246
- function l() {
256
+ function ct() {
257
+ let e = c(), t = st(), n = Q(), r = ce(), i = Z(), { role: a, rolePending: o, rawBlockCount: s, blockAtMs: l } = t;
258
+ function u() {
247
259
  let t = e.moderation?.blockBanThreshold;
248
260
  return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
249
261
  }
250
262
  function d() {
251
263
  let t = e.moderation?.blockBanDecayMs;
252
- return typeof t == "number" && t > 0 ? t : qe;
264
+ return typeof t == "number" && t > 0 ? t : et;
253
265
  }
254
266
  function f(e) {
255
- return x(n, _(), e);
267
+ return y(n, h(), e);
256
268
  }
257
269
  function p(e) {
258
270
  if (!e) {
259
- s.value = 0, c.value = null;
271
+ s.value = 0, l.value = null;
260
272
  return;
261
273
  }
262
- s.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), c.value = Qe(e.moderationBlockAt);
274
+ s.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), l.value = at(e.moderationBlockAt);
263
275
  }
264
- async function m(e) {
265
- let t = f(e.uid), r = g(n, _(), e.uid), i = await R(t);
276
+ async function g(e) {
277
+ let t = f(e.uid), r = m(n, h(), e.uid), i = await R(t);
266
278
  if (!i.exists()) return await Promise.all([K(t, {
267
279
  role: "user",
268
280
  displayName: e.displayName,
@@ -283,7 +295,7 @@ function tt() {
283
295
  "user"
284
296
  ].includes(String(a.role)) ? a.role : "user";
285
297
  }
286
- async function h() {
298
+ async function _() {
287
299
  let e = i.value?.uid;
288
300
  if (!e) {
289
301
  p(void 0);
@@ -292,34 +304,34 @@ function tt() {
292
304
  let t = await R(f(e));
293
305
  p(t.exists() ? t.data() : void 0);
294
306
  }
295
- t.watchStarted || (t.watchStarted = !0, I(i, async (e) => {
307
+ t.watchStarted || (t.watchStarted = !0, P(i, async (e) => {
296
308
  if (o.value = !0, !e) {
297
309
  a.value = "user", p(void 0), o.value = !1;
298
310
  return;
299
311
  }
300
312
  try {
301
- a.value = await m(e);
313
+ a.value = await g(e);
302
314
  } catch (e) {
303
315
  console.error("[memi-board] ensureUserDoc failed", e), a.value = "user", p(void 0);
304
316
  } finally {
305
317
  o.value = !1;
306
318
  }
307
319
  }, { immediate: !0 }));
308
- let v = M(() => !!i.value), y = M(() => a.value === "admin"), b = M(() => a.value === "staff"), S = M(() => y.value || b.value), C = M(() => Je(s.value, c.value, Date.now(), d())), w = M(() => {
309
- let e = l();
310
- return e <= 0 ? !1 : Xe(s.value, c.value, Date.now(), e, d());
311
- }), T = M(() => {
312
- let e = l();
320
+ let v = A(() => !!i.value), b = A(() => a.value === "admin"), x = A(() => a.value === "staff"), S = A(() => b.value || x.value), C = A(() => tt(s.value, l.value, Date.now(), d())), w = A(() => {
321
+ let e = u();
322
+ return e <= 0 ? !1 : rt(s.value, l.value, Date.now(), e, d());
323
+ }), T = A(() => {
324
+ let e = u();
313
325
  if (e <= 0) return null;
314
- let t = Ye(s.value, c.value, Date.now(), e, d());
315
- return t == null ? null : Ze(t);
316
- }), E = M(() => {
326
+ let t = nt(s.value, l.value, Date.now(), e, d());
327
+ return t == null ? null : it(t);
328
+ }), E = A(() => {
317
329
  if (!w.value) return null;
318
330
  let e = T.value;
319
331
  return e ? `콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요. (${e})` : "콘텐츠 경고가 누적되어 글·댓글 작성이 잠시 제한됐어요.";
320
332
  });
321
333
  async function D() {
322
- let e = i.value?.uid, t = l();
334
+ let e = i.value?.uid, t = u();
323
335
  if (!e || t <= 0) return {
324
336
  effectiveCount: 0,
325
337
  restricted: !1,
@@ -338,14 +350,14 @@ function tt() {
338
350
  updatedAt: G()
339
351
  });
340
352
  let a = (r.exists() ? Math.max(0, Math.floor(Number(r.data().moderationBlockCount) || 0)) : 0) + 1, o = Date.now();
341
- s.value = a, c.value = o;
342
- let u = Je(a, o, o, d()), p = Xe(a, o, o, t, d()), m = ` (경고 ${u}/${t})`;
353
+ s.value = a, l.value = o;
354
+ let c = tt(a, o, o, d()), p = rt(a, o, o, t, d()), m = ` (경고 ${c}/${t})`;
343
355
  if (p) {
344
- let e = Ye(a, o, o, t, d()), n = e == null ? null : Ze(e, o);
345
- m = n ? ` 경고 ${u}회가 되어 글·댓글 작성이 제한됩니다 (${n}).` : ` 경고 ${u}회가 되어 글·댓글 작성이 제한됩니다.`;
356
+ let e = nt(a, o, o, t, d()), n = e == null ? null : it(e, o);
357
+ m = n ? ` 경고 ${c}회가 되어 글·댓글 작성이 제한됩니다 (${n}).` : ` 경고 ${c}회가 되어 글·댓글 작성이 제한됩니다.`;
346
358
  }
347
359
  return {
348
- effectiveCount: u,
360
+ effectiveCount: c,
349
361
  restricted: p,
350
362
  messageSuffix: m
351
363
  };
@@ -355,62 +367,62 @@ function tt() {
355
367
  return r;
356
368
  }
357
369
  async function k() {
358
- return he(O(), new de());
359
- }
360
- async function A() {
361
- let e = new fe("apple.com");
362
- return e.addScope("email"), e.addScope("name"), he(O(), e);
370
+ return pe(O(), new le());
363
371
  }
364
- async function j(e, t) {
365
- return me(O(), e, t);
372
+ async function j() {
373
+ let e = new ue("apple.com");
374
+ return e.addScope("email"), e.addScope("name"), pe(O(), e);
366
375
  }
367
- async function N(e, t, n) {
368
- let r = await pe(O(), e, t);
369
- return n && await _e(r.user, { displayName: n }), r;
376
+ async function ee(e, t) {
377
+ return fe(O(), e, t);
370
378
  }
371
- async function ee() {
372
- await ge(O());
379
+ async function M(e, t, n) {
380
+ let r = await de(O(), e, t);
381
+ return n && await he(r.user, { displayName: n }), r;
373
382
  }
374
- function P(e) {
375
- return Ve(i.value?.uid, y.value, b.value, e ? Ge(e) : void 0);
383
+ async function N() {
384
+ await me(O());
376
385
  }
377
386
  function F(e) {
378
- return v.value && (i.value?.uid === e.authorUid || P(e.boardId));
387
+ return Je(i.value?.uid, b.value, x.value, e ? Qe(e) : void 0);
388
+ }
389
+ function I(e) {
390
+ return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
379
391
  }
380
392
  function te(e) {
381
393
  return v.value && i.value?.uid === e.authorUid;
382
394
  }
383
- function ne(e) {
384
- return v.value && (i.value?.uid === e.authorUid || P(e.boardId));
395
+ function L(e) {
396
+ return v.value && (i.value?.uid === e.authorUid || F(e.boardId));
385
397
  }
386
398
  return {
387
399
  user: i,
388
400
  isSignedIn: v,
389
- isAdmin: y,
390
- isStaff: b,
401
+ isAdmin: b,
402
+ isStaff: x,
391
403
  canManageContent: S,
392
- canManageBoard: P,
404
+ canManageBoard: F,
393
405
  rolePending: o,
394
406
  moderationBlockCount: C,
395
407
  isWriteRestricted: w,
396
408
  restrictedUntilLabel: T,
397
409
  restrictedMessage: E,
398
410
  signInWithGoogle: k,
399
- signInWithApple: A,
400
- signInWithEmail: j,
401
- signUpWithEmail: N,
402
- signOut: ee,
403
- canEdit: F,
404
- canDelete: F,
411
+ signInWithApple: j,
412
+ signInWithEmail: ee,
413
+ signUpWithEmail: M,
414
+ signOut: N,
415
+ canEdit: I,
416
+ canDelete: I,
405
417
  canEditComment: te,
406
- canDeleteComment: ne,
418
+ canDeleteComment: L,
407
419
  recordContentModerationBlock: D,
408
- refreshBoardUser: h
420
+ refreshBoardUser: _
409
421
  };
410
422
  }
411
423
  //#endregion
412
424
  //#region src/utils/extractEditorImageUrls.ts
413
- function nt(e) {
425
+ function lt(e) {
414
426
  if (!e) return [];
415
427
  let t = /* @__PURE__ */ new Set();
416
428
  for (let n of e.matchAll(/!\[[^\]]*]\((https?:\/\/[^)\s]+)\)/g)) n[1] && t.add(n[1].replaceAll("&amp;", "&"));
@@ -419,7 +431,7 @@ function nt(e) {
419
431
  }
420
432
  //#endregion
421
433
  //#region src/utils/storagePath.ts
422
- function rt(e) {
434
+ function ut(e) {
423
435
  try {
424
436
  let t = new URL(e), n = t.hostname.toLowerCase();
425
437
  if (!(n === "firebasestorage.googleapis.com" || n.endsWith(".firebasestorage.app"))) return null;
@@ -429,109 +441,109 @@ function rt(e) {
429
441
  return null;
430
442
  }
431
443
  }
432
- function it(e) {
444
+ function dt(e) {
433
445
  return e.match(/(?:^|\/)posts\/([^/]+)\//)?.[1] ?? null;
434
446
  }
435
447
  //#endregion
436
448
  //#region src/utils/deletePostCascade.ts
437
- async function at(e) {
449
+ async function ft(e) {
438
450
  try {
439
- let t = await be(e);
440
- await Promise.all([...t.items.map((e) => ve(e).catch(() => {})), ...t.prefixes.map((e) => at(e))]);
451
+ let t = await ve(e);
452
+ await Promise.all([...t.items.map((e) => ge(e).catch(() => {})), ...t.prefixes.map((e) => ft(e))]);
441
453
  } catch {}
442
454
  }
443
- async function ot(e, t) {
444
- await at(xe(e, `${t}/images`)), await at(xe(e, `${t}/attachments`));
455
+ async function pt(e, t) {
456
+ await ft(ye(e, `${t}/images`)), await ft(ye(e, `${t}/attachments`));
445
457
  }
446
- async function st(e, t) {
458
+ async function mt(e, t) {
447
459
  let n = [...new Set([...t].filter(Boolean))];
448
- await Promise.all(n.map((t) => ve(xe(e, t)).catch(() => {})));
460
+ await Promise.all(n.map((t) => ge(ye(e, t)).catch(() => {})));
449
461
  }
450
- var ct = 450;
451
- async function lt(e, t) {
462
+ var ht = 450;
463
+ async function gt(e, t) {
452
464
  let n = await z(t);
453
- for (let t = 0; t < n.docs.length; t += ct) {
465
+ for (let t = 0; t < n.docs.length; t += ht) {
454
466
  let r = X(e);
455
- n.docs.slice(t, t + ct).forEach((e) => r.delete(e.ref)), await r.commit();
467
+ n.docs.slice(t, t + ht).forEach((e) => r.delete(e.ref)), await r.commit();
456
468
  }
457
469
  }
458
- async function ut(e, t, n) {
459
- await lt(e, W(A(e, t), Y("postId", "==", n)));
470
+ async function _t(e, t, n) {
471
+ await gt(e, W(O(e, t), Y("postId", "==", n)));
460
472
  }
461
- async function dt(e, t, n) {
462
- await lt(e, W(o(e, t), Y("postId", "==", n)));
473
+ async function vt(e, t, n) {
474
+ await gt(e, W(i(e, t), Y("postId", "==", n)));
463
475
  }
464
- async function ft(e, t, n) {
465
- await lt(e, W(A(e, t), Y("commentId", "==", n)));
476
+ async function yt(e, t, n) {
477
+ await gt(e, W(O(e, t), Y("commentId", "==", n)));
466
478
  }
467
- async function pt(e, n, r, i) {
468
- let a = t(e, r, i), o = s(e, r, i), [c, l] = await Promise.all([R(a), R(o)]);
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([R(o), R(s)]);
469
481
  if (!c.exists()) return;
470
482
  let u = c.data(), d = l.exists() ? String(l.data().content ?? "") : "";
471
- await lt(e, W(O(e, r), Y("postId", "==", i))), await ut(e, r, i), await dt(e, r, i);
483
+ await gt(e, W(E(e, r), Y("postId", "==", i))), await _t(e, r, i), await vt(e, r, i);
472
484
  let f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
473
485
  for (let e of u.attachments ?? []) {
474
486
  if (!e?.path) continue;
475
487
  f.add(e.path);
476
- let t = it(e.path);
488
+ let t = dt(e.path);
477
489
  t && t !== i && p.add(t);
478
490
  }
479
- for (let e of nt(d)) {
480
- let t = rt(e);
491
+ for (let e of lt(d)) {
492
+ let t = ut(e);
481
493
  if (!t) continue;
482
494
  f.add(t);
483
495
  let n = t.replace(/\/images\/([^/]+)$/, "/images/thumbnails/$1").replace(/\.[^.]+$/, ".jpg");
484
496
  n !== t && n.includes("/images/thumbnails/") && f.add(n);
485
497
  let r = t.match(/^(.*\/images\/)([^/]+)\.[^.]+$/);
486
498
  r && !t.includes("/thumbnails/") && f.add(`${r[1]}thumbnails/${r[2]}.jpg`);
487
- let a = it(t);
499
+ let a = dt(t);
488
500
  a && a !== i && p.add(a);
489
501
  }
490
- await te(o), await ot(n, k(r, i));
491
- for (let e of p) await ot(n, k(r, e));
492
- await st(n, f), await te(a);
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);
493
505
  }
494
506
  //#endregion
495
507
  //#region src/utils/postBody.ts
496
- function mt(e) {
508
+ function xt(e) {
497
509
  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();
498
510
  }
499
- function ht(e, t = 40) {
500
- let n = mt(e);
511
+ function St(e, t = 40) {
512
+ let n = xt(e);
501
513
  if (!n) return "";
502
514
  if (n.length <= t) return n;
503
515
  let r = n.slice(0, t), i = r.lastIndexOf(" ");
504
516
  return `${(i >= Math.floor(t * .6) ? r.slice(0, i) : r).trimEnd()}…`;
505
517
  }
506
- function gt(e) {
507
- return mt(e).length > 0;
518
+ function Ct(e) {
519
+ return xt(e).length > 0;
508
520
  }
509
- function _t(e, t) {
521
+ function wt(e, t) {
510
522
  return /<img\b/i.test(String(e || "")) ? !0 : (t || []).some((e) => !!e?.type?.startsWith("image/"));
511
523
  }
512
- function vt(e) {
513
- return !gt(e);
524
+ function Tt(e) {
525
+ return !Ct(e);
514
526
  }
515
527
  //#endregion
516
528
  //#region src/utils/postPreview.ts
517
- function yt(e) {
529
+ function Et(e) {
518
530
  return e.replace(/&amp;/g, "&").replace(/&quot;/g, "\"").replace(/&#39;/g, "'");
519
531
  }
520
- function bt(e) {
532
+ function Dt(e) {
521
533
  if (e) try {
522
- let t = new URL(yt(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
534
+ let t = new URL(Et(e)), n = t.hostname.toLowerCase().replace(/^www\./, "");
523
535
  if (n === "youtu.be") return t.pathname.split("/").filter(Boolean)[0];
524
536
  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;
525
537
  } catch {
526
538
  return;
527
539
  }
528
540
  }
529
- function xt(e) {
530
- let t = bt(e.videoUrl);
541
+ function Ot(e) {
542
+ let t = Dt(e.videoUrl);
531
543
  return t ? `https://i.ytimg.com/vi/${t}/hqdefault.jpg` : e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
532
544
  }
533
- function St(e, t = []) {
534
- 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 ? yt(r[1]) : a, s = o ? bt(o) : void 0, c = n ? yt(n[1]) : i || (s ? `https://i.ytimg.com/vi/${s}/hqdefault.jpg` : void 0);
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);
535
547
  return {
536
548
  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),
537
549
  ...c ? { previewImage: c } : {},
@@ -540,7 +552,7 @@ function St(e, t = []) {
540
552
  }
541
553
  //#endregion
542
554
  //#region src/composables/useMemiBoardSettings.ts
543
- var Ct = [
555
+ var At = [
544
556
  {
545
557
  id: "free",
546
558
  label: "자유",
@@ -568,17 +580,17 @@ var Ct = [
568
580
  visibility: "public",
569
581
  order: 2
570
582
  }
571
- ], wt = Ct;
572
- function Tt(e) {
583
+ ], jt = At;
584
+ function Mt(e) {
573
585
  return e === "hidden" ? "hidden" : "public";
574
586
  }
575
- function Et(e, t, n) {
587
+ function Nt(e, t, n) {
576
588
  return {
577
589
  id: e,
578
590
  label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
579
591
  order: typeof t.order == "number" ? t.order : n,
580
592
  description: (typeof t.description == "string" ? t.description : "") || "",
581
- visibility: Tt(t.visibility),
593
+ visibility: Mt(t.visibility),
582
594
  listView: t.listView ?? "default",
583
595
  editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
584
596
  writeRole: t.writeRole ?? "user",
@@ -586,33 +598,33 @@ function Et(e, t, n) {
586
598
  allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : []
587
599
  };
588
600
  }
589
- function Dt() {
590
- let t = () => _(), n = Q(), r = le(), { isSignedIn: i, isAdmin: a, isStaff: o, user: s } = tt(), l = M(() => W(e(n, t()), U("order", "asc"))), { data: u, pending: d } = se(l, { ssrKey: w(t(), "boards") }), f = M(() => u.value.map((e, t) => Et(e.id, e, t))), p = f, m = M(() => f.value.filter((e) => e.visibility !== "hidden")), h = m;
591
- function g(e) {
601
+ function Pt() {
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
+ function v(e) {
592
604
  if (e) return f.value.find((t) => t.id === e)?.label ?? e;
593
605
  }
594
- let y = g;
595
- function b(e) {
606
+ let y = v;
607
+ function x(e) {
596
608
  if (e) return f.value.find((t) => t.id === e)?.description?.trim() || void 0;
597
609
  }
598
- let x = b;
599
- function C(e) {
610
+ let C = x;
611
+ function w(e) {
600
612
  return e ? f.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
601
613
  }
602
- let T = C;
603
- function E(e) {
604
- return C(e) === "hidden";
614
+ let T = w;
615
+ function D(e) {
616
+ return w(e) === "hidden";
605
617
  }
606
- let D = E;
618
+ let O = D;
607
619
  function k(e) {
608
620
  if (e) return f.value.find((t) => t.id === e);
609
621
  }
610
- We((e) => k(e));
611
- function A(e) {
612
- return Ve(s.value?.uid, a.value, o.value, e ? k(e) : void 0);
622
+ Ze((e) => k(e));
623
+ function j(e) {
624
+ return Je(c.value?.uid, a.value, s.value, e ? k(e) : void 0);
613
625
  }
614
- let j = M(() => f.value.filter((e) => A(e.id)));
615
- async function N(e, t, r) {
626
+ let ee = A(() => f.value.filter((e) => j(e.id)));
627
+ async function M(e, t, r) {
616
628
  let i;
617
629
  for (;;) {
618
630
  let a = await z(W(e, Y("boardId", "==", t), U("__name__"), ...i ? [q(i)] : [], V(400)));
@@ -622,14 +634,14 @@ function Dt() {
622
634
  if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
623
635
  }
624
636
  }
625
- async function ee(e, r) {
626
- await N(c(n, t()), e, r), await N(O(n, t()), e, r);
637
+ async function N(e, r) {
638
+ await M(o(n, t()), e, r), await M(E(n, t()), e, r);
627
639
  }
628
640
  function P(e, t) {
629
641
  return {
630
642
  label: e.label.trim(),
631
643
  description: (e.description ?? "").trim(),
632
- visibility: Tt(e.visibility),
644
+ visibility: Mt(e.visibility),
633
645
  listView: e.listView ?? "default",
634
646
  editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
635
647
  writeRole: e.writeRole ?? "user",
@@ -639,61 +651,61 @@ function Dt() {
639
651
  updatedAt: G()
640
652
  };
641
653
  }
642
- async function F(e, r = e.order ?? 0) {
654
+ async function I(e, r = e.order ?? 0) {
643
655
  if (!i.value) throw Error("로그인이 필요합니다.");
644
656
  let a = e.id.trim(), o = e.label.trim();
645
657
  if (!a || !o) throw Error("보드 ID와 이름을 입력해 주세요.");
646
- let s = Tt(e.visibility), c = P({
658
+ let s = Mt(e.visibility), c = P({
647
659
  ...e,
648
660
  label: o,
649
661
  visibility: s
650
662
  }, r);
651
- await K(v(n, t(), a), c, { merge: !0 }), await ee(a, s !== "hidden");
663
+ await K(g(n, t(), a), c, { merge: !0 }), await N(a, s !== "hidden");
652
664
  }
653
- let I = F;
654
- async function ne(e) {
665
+ let te = I;
666
+ async function L(e) {
655
667
  if (!i.value) throw Error("로그인이 필요합니다.");
656
668
  let r = new Map(f.value.map((e) => [e.id, e.visibility ?? "public"])), a = X(n), o = [];
657
669
  e.forEach((e, i) => {
658
670
  let s = e.id.trim(), c = e.label.trim();
659
671
  if (!s || !c) throw Error("보드 ID와 이름을 입력해 주세요.");
660
- let l = Tt(e.visibility), u = P({
672
+ let l = Mt(e.visibility), u = P({
661
673
  ...e,
662
674
  label: c,
663
675
  visibility: l
664
676
  }, i);
665
- a.set(v(n, t(), s), u, { merge: !0 }), ((r.get(s) ?? "public") !== l || l === "hidden") && o.push({
677
+ a.set(g(n, t(), s), u, { merge: !0 }), ((r.get(s) ?? "public") !== l || l === "hidden") && o.push({
666
678
  id: s,
667
679
  listed: l !== "hidden"
668
680
  });
669
681
  }), await a.commit();
670
- for (let e of o) await ee(e.id, e.listed);
682
+ for (let e of o) await N(e.id, e.listed);
671
683
  }
672
- let re = ne;
673
- async function L(e) {
684
+ let ne = L;
685
+ async function R(e) {
674
686
  if (!i.value) throw Error("로그인이 필요합니다.");
675
687
  let a = e.trim();
676
688
  if (!a) throw Error("삭제할 게시판 ID가 필요합니다.");
677
689
  for (;;) {
678
- let e = await z(W(c(n, t()), Y("boardId", "==", a), V(25)));
690
+ let e = await z(W(o(n, t()), Y("boardId", "==", a), V(25)));
679
691
  if (e.empty) break;
680
- for (let i of e.docs) await pt(n, ye(r), t(), i.id);
692
+ for (let i of e.docs) await bt(n, _e(r), t(), i.id);
681
693
  }
682
- await te(v(n, t(), e));
694
+ await F(g(n, t(), e));
683
695
  }
684
- let ie = L;
685
- async function R() {
696
+ let B = R;
697
+ async function re() {
686
698
  return Promise.resolve();
687
699
  }
688
- async function B(e) {
700
+ async function H(e) {
689
701
  let t = e.trim();
690
702
  if (!t) throw Error("보드 이름을 입력해 주세요.");
691
703
  if (!i.value) throw Error("로그인이 필요합니다.");
692
704
  let n = f.value.find((e) => e.label === t);
693
705
  if (n) return n.id;
694
- let r = S(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(f.value.map((e) => e.id));
706
+ let r = b(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(f.value.map((e) => e.id));
695
707
  for (; s.has(a);) a = `${r}-${o++}`;
696
- return await F({
708
+ return await I({
697
709
  id: a,
698
710
  label: t,
699
711
  visibility: "public",
@@ -707,55 +719,56 @@ function Dt() {
707
719
  return {
708
720
  boards: f,
709
721
  publicBoards: m,
710
- boardLabel: g,
711
- boardDescription: b,
712
- boardVisibility: C,
713
- isBoardHidden: E,
722
+ boardLabel: v,
723
+ boardDescription: x,
724
+ boardVisibility: w,
725
+ isBoardHidden: D,
714
726
  getBoard: k,
715
- canManageBoard: A,
716
- managedBoards: j,
727
+ canManageBoard: j,
728
+ managedBoards: ee,
717
729
  categories: p,
718
- publicCategories: h,
730
+ publicCategories: _,
719
731
  categoryLabel: y,
720
- categoryDescription: x,
732
+ categoryDescription: C,
721
733
  categoryVisibility: T,
722
- isCategoryHidden: D,
734
+ isCategoryHidden: O,
723
735
  settingsPending: d,
724
- ensureSettings: R,
725
- addBoard: B,
726
- addCategory: B,
727
- saveBoard: F,
728
- saveCategory: I,
729
- saveBoards: ne,
730
- saveCategories: re,
731
- deleteBoard: L,
732
- deleteCategory: ie,
733
- DEFAULT_BOARDS: Ct,
734
- DEFAULT_CATEGORIES: wt
736
+ ensureSettings: re,
737
+ addBoard: H,
738
+ addCategory: H,
739
+ saveBoard: I,
740
+ saveCategory: te,
741
+ saveBoards: L,
742
+ saveCategories: ne,
743
+ deleteBoard: R,
744
+ deleteCategory: B,
745
+ DEFAULT_BOARDS: At,
746
+ DEFAULT_CATEGORIES: jt
735
747
  };
736
748
  }
737
749
  //#endregion
738
750
  //#region src/composables/useMemiBoardPosts.ts
739
- function Ot(e) {
751
+ var Ft = /* @__PURE__ */ new Map();
752
+ function It(e) {
740
753
  if (!e || typeof e != "object") return !1;
741
754
  let t = "code" in e ? String(e.code) : "";
742
755
  return t === "permission-denied" || t === "firestore/permission-denied";
743
756
  }
744
- function kt(e) {
745
- let t = F(e)?.trim();
757
+ function Lt(e) {
758
+ let t = N(e)?.trim();
746
759
  if (!t) throw Error("[memi-board] boardId 가 필요합니다.");
747
760
  return t;
748
761
  }
749
- function At(e) {
750
- let n = Q(), r = le(), { isBoardHidden: i, getBoard: a } = Dt(), o = () => _(), l = () => kt(e), u = () => c(n, o()), d = (e) => t(n, o(), e), f = (e) => s(n, o(), 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);
751
764
  function p() {
752
765
  return !i(l());
753
766
  }
754
767
  function m() {
755
- return a(l())?.editorType === "image";
768
+ return s(l())?.editorType === "image";
756
769
  }
757
- function h(e) {
758
- let t = m(), n = gt(e.content), r = _t(e.content, e.attachments);
770
+ function g(e) {
771
+ let t = m(), n = Ct(e.content), r = wt(e.content, e.attachments);
759
772
  if (t) {
760
773
  if (!r) throw Error("사진을 올려 주세요.");
761
774
  return;
@@ -763,8 +776,8 @@ function At(e) {
763
776
  if (!n && !r) throw Error("본문에 글자를 입력하거나 이미지를 첨부해 주세요.");
764
777
  if (!e.title?.trim()) throw Error("제목을 입력해 주세요.");
765
778
  }
766
- function g() {
767
- return re(u()).id;
779
+ function _() {
780
+ return te(u()).id;
768
781
  }
769
782
  async function v(e = {}) {
770
783
  let t = e.pageSize ?? 20, n = [Y("boardId", "==", l()), Y("isPublished", "==", !0)];
@@ -787,7 +800,7 @@ function At(e) {
787
800
  content: n.exists() ? n.data().content ?? "" : ""
788
801
  } : null;
789
802
  }
790
- async function b(e) {
803
+ async function x(e) {
791
804
  try {
792
805
  let t = (await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", e.trim()), V(1)))).docs[0];
793
806
  if (!t) return { status: "not-found" };
@@ -798,19 +811,43 @@ function At(e) {
798
811
  post: e
799
812
  } : { status: "not-found" };
800
813
  } catch (e) {
801
- return Ot(e) ? { status: "permission-denied" } : {
814
+ return It(e) ? { status: "permission-denied" } : {
802
815
  status: "error",
803
816
  message: e instanceof Error ? e.message : String(e)
804
817
  };
805
818
  }
806
819
  } catch (e) {
807
- return Ot(e) ? { status: "permission-denied" } : {
820
+ return It(e) ? { status: "permission-denied" } : {
808
821
  status: "error",
809
822
  message: e instanceof Error ? e.message : String(e)
810
823
  };
811
824
  }
812
825
  }
813
- async function x(e) {
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) {
814
851
  if (!e.createdAt) return {
815
852
  previous: null,
816
853
  next: null
@@ -821,7 +858,7 @@ function At(e) {
821
858
  Y("isPublished", "==", !0),
822
859
  ...e.listed === !1 ? [] : [Y("listed", "==", !0)],
823
860
  U("createdAt", "desc")
824
- ], [n, r] = await Promise.all([z(W(u(), ...t, q(e.createdAt), V(1))), z(W(u(), ...t, ie(e.createdAt), ae(1)))]), i = (e) => {
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) => {
825
862
  let t = e.docs[0];
826
863
  return t ? {
827
864
  id: t.id,
@@ -839,29 +876,22 @@ function At(e) {
839
876
  };
840
877
  }
841
878
  }
842
- async function C(e) {
843
- h(e);
844
- let t = e.postId || g(), n = m(), r, i;
845
- if (n) r = t, i = ht(e.content);
846
- else {
847
- i = e.title.trim();
848
- let t = S(i) || "post";
849
- r = t;
850
- let n = 1;
851
- for (; !(await z(W(u(), Y("boardId", "==", l()), Y("slug", "==", r), V(1)))).empty;) n++, r = `${t}-${n}`;
852
- }
853
- let a = St(e.content, e.attachments), o = p();
854
- return await K(d(t), {
879
+ async function T(e) {
880
+ g(e);
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), {
855
885
  boardId: l(),
856
- slug: r,
857
- title: i,
858
- ...a,
886
+ slug: i,
887
+ title: a,
888
+ ...o,
859
889
  tags: e.tags ?? [],
860
890
  attachments: e.attachments ?? [],
861
891
  commentCount: 0,
862
892
  likeCount: 0,
863
893
  viewCount: 0,
864
- listed: o,
894
+ listed: s,
865
895
  isPublished: !1,
866
896
  authorUid: e.authorUid,
867
897
  authorName: e.authorName,
@@ -870,56 +900,59 @@ function At(e) {
870
900
  moderationModel: e.moderationModel ?? null,
871
901
  createdAt: G(),
872
902
  updatedAt: G()
873
- }), await K(f(t), { content: e.content }), r;
903
+ }), c.set(f(t), { content: e.content }), await c.commit(), Ft.set(`${l()}/${i}`, t), i;
874
904
  }
875
- async function w(e, t) {
876
- h(t);
877
- let n = m() ? ht(t.content) : t.title.trim(), r = St(t.content, t.attachments), i = p();
905
+ async function E(e, t) {
906
+ g(t);
907
+ let n = m() ? St(t.content) : t.title.trim(), r = kt(t.content, t.attachments), i = p();
878
908
  await Promise.all([J(d(e), {
879
909
  title: n,
880
910
  ...r,
881
- previewImage: r.previewImage ? r.previewImage : ne(),
882
- videoUrl: r.videoUrl ? r.videoUrl : ne(),
911
+ previewImage: r.previewImage ? r.previewImage : I(),
912
+ videoUrl: r.videoUrl ? r.videoUrl : I(),
883
913
  tags: t.tags ?? [],
884
914
  listed: i,
885
915
  attachments: t.attachments ?? [],
886
916
  updatedAt: G()
887
917
  }), K(f(e), { content: t.content }, { merge: !0 })]);
888
918
  }
889
- async function T(e) {
919
+ async function D(e) {
890
920
  await J(d(e), {
891
921
  isPublished: !0,
892
922
  publishedAt: G(),
893
923
  updatedAt: G()
894
924
  });
895
925
  }
896
- async function E(e) {
897
- await pt(n, ye(r), o(), e);
926
+ async function O(e) {
927
+ await bt(n, _e(r), c(), e);
928
+ for (let [t, n] of Ft) n === e && Ft.delete(t);
898
929
  }
899
930
  return {
900
- createPostId: g,
931
+ createPostId: _,
901
932
  getPosts: v,
902
933
  getPost: y,
903
- getPostBySlug: b,
904
- getAdjacentPosts: x,
905
- createPost: C,
906
- updatePost: w,
907
- publishPost: T,
908
- deletePost: E
934
+ getPostBySlug: x,
935
+ resolvePostIdBySlug: S,
936
+ resolveUniqueSlug: C,
937
+ getAdjacentPosts: w,
938
+ createPost: T,
939
+ updatePost: E,
940
+ publishPost: D,
941
+ deletePost: O
909
942
  };
910
943
  }
911
- var jt = 10;
912
- function Mt(e, t = {}) {
913
- let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = tt(), o = () => _(), s = t.pageSize ?? jt, l = M(() => i.value?.uid ?? ""), u = M(() => kt(e)), d = () => c(n, o()), f = M(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = P([]), m = P([]), h = P([]), g = P(!0), v = P(!0), y = P(!1), b = P(""), 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;
914
947
  function T(e) {
915
948
  return e.createdAt?.toMillis?.() ?? 0;
916
949
  }
917
- let E = M(() => {
950
+ let E = A(() => {
918
951
  let e = /* @__PURE__ */ new Map();
919
952
  for (let t of [
920
953
  ...m.value,
921
954
  ...p.value,
922
- ...h.value
955
+ ...g.value
923
956
  ]) t.id && e.set(t.id, t);
924
957
  return [...e.values()].sort((e, t) => T(t) - T(e) || String(t.id).localeCompare(String(e.id)));
925
958
  });
@@ -928,24 +961,24 @@ function Mt(e, t = {}) {
928
961
  return f.value && e.push(Y("listed", "==", !0)), e;
929
962
  }
930
963
  function O() {
931
- C?.(), C = H(W(d(), ...D(), U("createdAt", "desc"), U(L(), "desc"), V(s)), (e) => {
964
+ C?.(), C = H(W(d(), ...D(), U("createdAt", "desc"), U(L(), "desc"), V(c)), (e) => {
932
965
  p.value = e.docs.map((e) => ({
933
966
  id: e.id,
934
967
  ...e.data()
935
- })), x = e.docs.at(-1) ?? null, S || (v.value = e.docs.length >= s), g.value = !1;
968
+ })), x = e.docs.at(-1) ?? null, S || (v.value = e.docs.length >= c), _.value = !1;
936
969
  }, (e) => {
937
- console.error("[memi-board:postList] onSnapshot failed", e), b.value = e.message || String(e), g.value = !1;
970
+ console.error("[memi-board:postList] onSnapshot failed", e), b.value = e.message || String(e), _.value = !1;
938
971
  });
939
972
  }
940
973
  function k() {
941
974
  w?.();
942
975
  let e = l.value;
943
976
  if (!e) {
944
- h.value = [];
977
+ g.value = [];
945
978
  return;
946
979
  }
947
980
  w = H(W(d(), Y("boardId", "==", u.value), Y("authorUid", "==", e), Y("isPublished", "==", !1), U("createdAt", "desc"), V(20)), (e) => {
948
- h.value = e.docs.map((e) => ({
981
+ g.value = e.docs.map((e) => ({
949
982
  id: e.id,
950
983
  ...e.data()
951
984
  }));
@@ -953,8 +986,8 @@ function Mt(e, t = {}) {
953
986
  console.error("[memi-board:postList] own draft onSnapshot failed", e);
954
987
  });
955
988
  }
956
- async function A() {
957
- if (!(y.value || !v.value || g.value)) {
989
+ async function ee() {
990
+ if (!(y.value || !v.value || _.value)) {
958
991
  y.value = !0, b.value = "";
959
992
  try {
960
993
  let e = S ?? x, t = [
@@ -962,12 +995,12 @@ function Mt(e, t = {}) {
962
995
  U("createdAt", "desc"),
963
996
  U(L(), "desc"),
964
997
  ...e ? [q(e)] : [],
965
- V(s + 1)
966
- ], n = await z(W(d(), ...t)), r = n.docs.slice(0, s), i = r.map((e) => ({
998
+ V(c + 1)
999
+ ], n = await z(W(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
967
1000
  id: e.id,
968
1001
  ...e.data()
969
1002
  })), a = new Set([...m.value, ...p.value].map((e) => e.id));
970
- m.value.push(...i.filter((e) => !a.has(e.id))), S = r.at(-1) ?? S, v.value = n.docs.length > s;
1003
+ m.value.push(...i.filter((e) => !a.has(e.id))), S = r.at(-1) ?? S, v.value = n.docs.length > c;
971
1004
  } catch (e) {
972
1005
  b.value = e.message || String(e), console.error("[memi-board:postList] loadMore failed", e);
973
1006
  } finally {
@@ -975,40 +1008,40 @@ function Mt(e, t = {}) {
975
1008
  }
976
1009
  }
977
1010
  }
978
- function j() {
979
- C?.(), p.value = [], m.value = [], x = null, S = null, v.value = !0, b.value = "", g.value = !0, O(), k();
1011
+ function N() {
1012
+ C?.(), p.value = [], m.value = [], x = null, S = null, v.value = !0, b.value = "", _.value = !0, O(), k();
980
1013
  }
981
- return I([
1014
+ return P([
982
1015
  u,
983
1016
  f,
984
1017
  l
985
- ], j, { immediate: !0 }), N(() => {
1018
+ ], N, { immediate: !0 }), j(() => {
986
1019
  C?.(), w?.();
987
1020
  }), {
988
1021
  posts: E,
989
- postsPending: g,
1022
+ postsPending: _,
990
1023
  hasMore: v,
991
1024
  loadingMore: y,
992
1025
  loadError: b,
993
- loadMore: A
1026
+ loadMore: ee
994
1027
  };
995
1028
  }
996
- function Nt(e, n) {
997
- let r = Q(), i = () => _(), a = M(() => kt(e)), o = M(() => typeof n == "string" ? n : n.value), c = M(() => t(r, i(), o.value)), l = M(() => s(r, i(), o.value)), { data: u, pending: d } = ce(c), { data: f, pending: p } = ce(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);
998
1031
  return {
999
- post: M(() => !u.value || u.value.boardId !== a.value ? null : {
1032
+ post: A(() => !u.value || u.value.boardId !== o.value ? null : {
1000
1033
  ...u.value,
1001
- id: o.value,
1034
+ id: s.value,
1002
1035
  content: f.value?.content ?? ""
1003
1036
  }),
1004
- pending: M(() => d.value || p.value)
1037
+ pending: A(() => d.value || p.value)
1005
1038
  };
1006
1039
  }
1007
1040
  //#endregion
1008
1041
  //#region src/composables/useMemiBoardUserPosts.ts
1009
- var Pt = 10;
1010
- function Ft(e, t = {}) {
1011
- let n = Q(), r = () => _(), i = () => c(n, r()), a = t.pageSize ?? Pt, o = M(() => F(e)?.trim() || ""), s = P([]), l = P([]), u = P(!0), d = P(!0), f = P(!1), p = P(""), m = null, h = null, g;
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, _;
1012
1045
  function v(e) {
1013
1046
  return {
1014
1047
  id: e.id,
@@ -1018,41 +1051,41 @@ function Ft(e, t = {}) {
1018
1051
  function y(e) {
1019
1052
  return e.createdAt?.toMillis?.() ?? 0;
1020
1053
  }
1021
- let b = M(() => {
1054
+ let b = A(() => {
1022
1055
  let e = /* @__PURE__ */ new Map();
1023
- for (let t of [...l.value, ...s.value]) t.id && e.set(t.id, t);
1056
+ for (let t of [...l.value, ...c.value]) t.id && e.set(t.id, t);
1024
1057
  return [...e.values()].sort((e, t) => y(t) - y(e) || String(t.id).localeCompare(String(e.id)));
1025
1058
  });
1026
1059
  function x() {
1027
1060
  return [
1028
- Y("authorUid", "==", o.value),
1061
+ Y("authorUid", "==", s.value),
1029
1062
  Y("isPublished", "==", !0),
1030
1063
  Y("listed", "==", !0)
1031
1064
  ];
1032
1065
  }
1033
1066
  function S() {
1034
- if (g?.(), !o.value) {
1067
+ if (_?.(), !s.value) {
1035
1068
  u.value = !1;
1036
1069
  return;
1037
1070
  }
1038
- g = H(W(i(), ...x(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1039
- s.value = e.docs.map(v), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= a), u.value = !1;
1071
+ _ = H(W(i(), ...x(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1072
+ c.value = e.docs.map(v), m = e.docs.at(-1) ?? null, g || (d.value = e.docs.length >= a), u.value = !1;
1040
1073
  }, (e) => {
1041
1074
  console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
1042
1075
  });
1043
1076
  }
1044
1077
  async function C() {
1045
- if (!(f.value || !d.value || u.value || !o.value)) {
1078
+ if (!f.value && d.value && !u.value && s.value) {
1046
1079
  f.value = !0, p.value = "";
1047
1080
  try {
1048
- let e = h ?? m, t = [
1081
+ let e = g ?? m, t = [
1049
1082
  ...x(),
1050
1083
  U("createdAt", "desc"),
1051
1084
  U(L(), "desc"),
1052
1085
  ...e ? [q(e)] : [],
1053
1086
  V(a + 1)
1054
- ], n = await z(W(i(), ...t)), r = n.docs.slice(0, a), o = r.map(v), c = new Set([...l.value, ...s.value].map((e) => e.id));
1055
- l.value.push(...o.filter((e) => !c.has(e.id))), h = r.at(-1) ?? h, d.value = n.docs.length > a;
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));
1088
+ l.value.push(...o.filter((e) => !s.has(e.id))), g = r.at(-1) ?? g, d.value = n.docs.length > a;
1056
1089
  } catch (e) {
1057
1090
  p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
1058
1091
  } finally {
@@ -1061,9 +1094,9 @@ function Ft(e, t = {}) {
1061
1094
  }
1062
1095
  }
1063
1096
  function w() {
1064
- g?.(), s.value = [], l.value = [], m = null, h = null, d.value = !0, p.value = "", u.value = !0, S();
1097
+ _?.(), c.value = [], l.value = [], m = null, g = null, d.value = !0, p.value = "", u.value = !0, S();
1065
1098
  }
1066
- return I(o, w, { immediate: !0 }), N(() => g?.()), {
1099
+ return P(s, w, { immediate: !0 }), j(() => _?.()), {
1067
1100
  posts: b,
1068
1101
  postsPending: u,
1069
1102
  hasMore: d,
@@ -1074,10 +1107,10 @@ function Ft(e, t = {}) {
1074
1107
  }
1075
1108
  //#endregion
1076
1109
  //#region src/composables/useMemiBoardUserComments.ts
1077
- var It = 10;
1078
- function Lt(e, t = {}) {
1079
- let n = Q(), r = () => _(), i = () => O(n, r()), a = t.pageSize ?? It, o = M(() => F(e)?.trim() || ""), s = P([]), c = P([]), l = P(!0), u = P(!0), d = P(!1), f = P(""), p = null, m = null, h;
1080
- function g(e) {
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;
1113
+ function _(e) {
1081
1114
  return {
1082
1115
  id: e.id,
1083
1116
  ...e.data()
@@ -1086,7 +1119,7 @@ function Lt(e, t = {}) {
1086
1119
  function v(e) {
1087
1120
  return e.createdAt?.toMillis?.() ?? 0;
1088
1121
  }
1089
- let y = M(() => {
1122
+ let y = A(() => {
1090
1123
  let e = /* @__PURE__ */ new Map();
1091
1124
  for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
1092
1125
  return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
@@ -1095,18 +1128,18 @@ function Lt(e, t = {}) {
1095
1128
  return [Y("authorUid", "==", o.value), Y("listed", "==", !0)];
1096
1129
  }
1097
1130
  function x() {
1098
- if (h?.(), !o.value) {
1131
+ if (g?.(), !o.value) {
1099
1132
  l.value = !1;
1100
1133
  return;
1101
1134
  }
1102
- h = H(W(i(), ...b(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1103
- s.value = e.docs.map(g), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
1135
+ g = H(W(i(), ...b(), U("createdAt", "desc"), U(L(), "desc"), V(a)), (e) => {
1136
+ s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
1104
1137
  }, (e) => {
1105
1138
  console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
1106
1139
  });
1107
1140
  }
1108
1141
  async function S() {
1109
- if (!(d.value || !u.value || l.value || !o.value)) {
1142
+ if (!d.value && u.value && !l.value && o.value) {
1110
1143
  d.value = !0, f.value = "";
1111
1144
  try {
1112
1145
  let e = m ?? p, t = [
@@ -1115,7 +1148,7 @@ function Lt(e, t = {}) {
1115
1148
  U(L(), "desc"),
1116
1149
  ...e ? [q(e)] : [],
1117
1150
  V(a + 1)
1118
- ], n = await z(W(i(), ...t)), r = n.docs.slice(0, a), o = r.map(g), l = new Set([...c.value, ...s.value].map((e) => e.id));
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));
1119
1152
  c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
1120
1153
  } catch (e) {
1121
1154
  f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
@@ -1125,9 +1158,9 @@ function Lt(e, t = {}) {
1125
1158
  }
1126
1159
  }
1127
1160
  function C() {
1128
- h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, x();
1161
+ g?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, x();
1129
1162
  }
1130
- return I(o, C, { immediate: !0 }), N(() => h?.()), {
1163
+ return P(o, C, { immediate: !0 }), j(() => g?.()), {
1131
1164
  comments: y,
1132
1165
  commentsPending: l,
1133
1166
  hasMore: u,
@@ -1138,13 +1171,13 @@ function Lt(e, t = {}) {
1138
1171
  }
1139
1172
  //#endregion
1140
1173
  //#region src/composables/useMemiBoardCommentFeed.ts
1141
- var Rt = 10;
1142
- function zt(e = "latest", t = {}) {
1143
- let n = Q(), r = () => _(), i = () => O(n, r()), a = M(() => {
1144
- let e = Math.floor(Number(F(t.pageSize)));
1145
- return Number.isFinite(e) && e > 0 ? e : Rt;
1146
- }), o = M(() => F(e) === "likes" ? "likes" : "latest"), s = P([]), c = P([]), l = P(!0), u = P(!0), d = P(!1), f = P(""), p = null, m = null, h;
1147
- function g(e) {
1174
+ var Kt = 10;
1175
+ function qt(e = "latest", t = {}) {
1176
+ let n = Q(), r = () => h(), i = () => E(n, r()), a = A(() => {
1177
+ let e = Math.floor(Number(N(t.pageSize)));
1178
+ return Number.isFinite(e) && e > 0 ? e : Kt;
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;
1180
+ function _(e) {
1148
1181
  return {
1149
1182
  id: e.id,
1150
1183
  ...e.data()
@@ -1160,7 +1193,7 @@ function zt(e = "latest", t = {}) {
1160
1193
  }
1161
1194
  return v(t) - v(e) || String(t.id).localeCompare(String(e.id));
1162
1195
  }
1163
- let b = M(() => {
1196
+ let b = A(() => {
1164
1197
  let e = /* @__PURE__ */ new Map();
1165
1198
  for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
1166
1199
  return [...e.values()].sort(y);
@@ -1178,8 +1211,8 @@ function zt(e = "latest", t = {}) {
1178
1211
  ];
1179
1212
  }
1180
1213
  function S() {
1181
- h?.(), h = H(W(i(), ...x(), V(a.value)), (e) => {
1182
- s.value = e.docs.map(g), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
1214
+ g?.(), g = H(W(i(), ...x(), V(a.value)), (e) => {
1215
+ s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
1183
1216
  }, (e) => {
1184
1217
  console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
1185
1218
  });
@@ -1188,7 +1221,7 @@ function zt(e = "latest", t = {}) {
1188
1221
  if (!(d.value || !u.value || l.value)) {
1189
1222
  d.value = !0, f.value = "";
1190
1223
  try {
1191
- 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(g), 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));
1192
1225
  c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
1193
1226
  } catch (e) {
1194
1227
  f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
@@ -1198,9 +1231,9 @@ function zt(e = "latest", t = {}) {
1198
1231
  }
1199
1232
  }
1200
1233
  function w() {
1201
- h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, S();
1234
+ g?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, S();
1202
1235
  }
1203
- return I([o, a], w, { immediate: !0 }), N(() => h?.()), {
1236
+ return P([o, a], w, { immediate: !0 }), j(() => g?.()), {
1204
1237
  comments: b,
1205
1238
  commentsPending: l,
1206
1239
  hasMore: u,
@@ -1212,9 +1245,9 @@ function zt(e = "latest", t = {}) {
1212
1245
  }
1213
1246
  //#endregion
1214
1247
  //#region src/composables/useMemiBoardAuthorMemo.ts
1215
- var Bt = 100, Vt = /* @__PURE__ */ new Map();
1248
+ var Jt = 100, Yt = /* @__PURE__ */ new Map();
1216
1249
  function $(e) {
1217
- let t = Vt.get(e);
1250
+ let t = Yt.get(e);
1218
1251
  return t || (t = ee({
1219
1252
  text: "",
1220
1253
  sentiment: null,
@@ -1222,19 +1255,19 @@ function $(e) {
1222
1255
  pending: !1,
1223
1256
  saving: !1,
1224
1257
  error: ""
1225
- }), Vt.set(e, t)), t;
1258
+ }), Yt.set(e, t)), t;
1226
1259
  }
1227
- function Ht(e) {
1228
- let t = Q(), n = () => _(), { user: r } = tt(), i = M(() => F(e)), a = M(() => `${r.value?.uid ?? ""}:${i.value}`), o = M(() => {
1260
+ function Xt(e) {
1261
+ let t = Q(), n = () => h(), { user: r } = ct(), i = A(() => N(e)), a = A(() => `${r.value?.uid ?? ""}:${i.value}`), o = A(() => {
1229
1262
  let e = r.value?.uid, a = i.value;
1230
- return !e || !a ? null : m(t, n(), e, a);
1231
- }), s = M({
1263
+ return !e || !a ? null : f(t, n(), e, a);
1264
+ }), s = A({
1232
1265
  get: () => $(a.value).text,
1233
1266
  set: (e) => {
1234
1267
  $(a.value).text = e;
1235
1268
  }
1236
- }), c = M(() => $(a.value).sentiment), l = M(() => $(a.value).loaded), u = M(() => $(a.value).pending), d = M(() => $(a.value).saving), f = M(() => $(a.value).error);
1237
- async function p() {
1269
+ }), c = A(() => $(a.value).sentiment), l = A(() => $(a.value).loaded), u = A(() => $(a.value).pending), d = A(() => $(a.value).saving), p = A(() => $(a.value).error);
1270
+ async function m() {
1238
1271
  let e = o.value;
1239
1272
  if (!e) return;
1240
1273
  let t = $(a.value);
@@ -1248,7 +1281,7 @@ function Ht(e) {
1248
1281
  t.pending = !1;
1249
1282
  }
1250
1283
  }
1251
- async function h(e, t) {
1284
+ async function g(e, t) {
1252
1285
  let n = o.value;
1253
1286
  if (!n) return;
1254
1287
  let r = e.trim();
@@ -1267,13 +1300,13 @@ function Ht(e) {
1267
1300
  i.saving = !1;
1268
1301
  }
1269
1302
  }
1270
- async function g() {
1303
+ async function _() {
1271
1304
  let e = o.value;
1272
1305
  if (!e) return;
1273
1306
  let t = $(a.value);
1274
1307
  t.saving = !0, t.error = "";
1275
1308
  try {
1276
- await te(e), t.text = "", t.sentiment = null, t.loaded = !0;
1309
+ await F(e), t.text = "", t.sentiment = null, t.loaded = !0;
1277
1310
  } catch (e) {
1278
1311
  throw t.error = e.message || String(e), console.error("[memi-board:authorMemo] remove failed", e), e;
1279
1312
  } finally {
@@ -1286,40 +1319,40 @@ function Ht(e) {
1286
1319
  loaded: l,
1287
1320
  pending: u,
1288
1321
  saving: d,
1289
- error: f,
1290
- load: p,
1291
- save: h,
1292
- remove: g
1322
+ error: p,
1323
+ load: m,
1324
+ save: g,
1325
+ remove: _
1293
1326
  };
1294
1327
  }
1295
1328
  //#endregion
1296
1329
  //#region src/composables/useMemiBoardComments.ts
1297
- var Ut = 10, Wt = 5, Gt = 1e3;
1298
- function Kt(e) {
1330
+ var Zt = 10, Qt = 5, $t = 1e3;
1331
+ function en(e) {
1299
1332
  let t = e.trim();
1300
1333
  if (!t) throw Error("댓글 내용을 입력해 주세요.");
1301
- if (t.length > 1e3) throw Error(`댓글은 ${Gt.toLocaleString()}자까지 작성할 수 있습니다.`);
1334
+ if (t.length > 1e3) throw Error(`댓글은 ${$t.toLocaleString()}자까지 작성할 수 있습니다.`);
1302
1335
  return t;
1303
1336
  }
1304
- function qt(e, n, r = {}) {
1305
- let i = Q(), a = () => _(), { isBoardHidden: o } = Dt(), s = () => O(i, a()), c = M(() => F(e)), u = M(() => F(n)), d = () => !o(c.value), f = P([]), p = P([]), m = P(r.subscribe !== !1), h = P([]), g = P(!1), v = P(r.subscribe !== !1), y = P(r.subscribe !== !1), b = null, x, S;
1337
+ function tn(e, n, r = {}) {
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;
1306
1339
  function C(e) {
1307
1340
  return e.createdAt?.toMillis?.() ?? 0;
1308
1341
  }
1309
- let w = M(() => {
1342
+ let w = A(() => {
1310
1343
  let e = /* @__PURE__ */ new Map();
1311
1344
  for (let t of [
1312
1345
  ...f.value,
1313
1346
  ...p.value,
1314
- ...h.value
1347
+ ...g.value
1315
1348
  ]) t.id && e.set(t.id, t);
1316
1349
  return [...e.values()].sort((e, t) => C(e) - C(t) || String(e.id).localeCompare(String(t.id)));
1317
1350
  });
1318
- I([u, c], async ([e]) => {
1319
- if (h.value = [], f.value = [], p.value = [], b = null, clearTimeout(x), x = void 0, S?.(), S = void 0, v.value = r.subscribe !== !1, r.subscribe !== !1) {
1351
+ P([u, l], async ([e]) => {
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) {
1320
1353
  m.value = !0, y.value = !0;
1321
1354
  try {
1322
- let t = z(W(s(), Y("postId", "==", e), U("createdAt", "desc"), U(L(), "desc")));
1355
+ let t = z(W(c(), Y("postId", "==", e), U("createdAt", "desc"), U(L(), "desc")));
1323
1356
  if (await Promise.all([t.then((t) => {
1324
1357
  if (u.value !== e) return;
1325
1358
  let n = t.docs.map((e) => ({
@@ -1327,14 +1360,14 @@ function qt(e, n, r = {}) {
1327
1360
  ...e.data()
1328
1361
  }));
1329
1362
  p.value = n.filter((e) => e.parentId === void 0);
1330
- }), E()]), u.value !== e) return;
1363
+ }), D()]), u.value !== e) return;
1331
1364
  } finally {
1332
1365
  u.value === e && (m.value = !1, y.value = !1);
1333
1366
  }
1334
1367
  }
1335
1368
  }, { immediate: !0 });
1336
1369
  function T() {
1337
- S?.(), S = H(W(s(), Y("postId", "==", u.value), Y("parentId", "==", null), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
1370
+ S?.(), S = H(W(c(), Y("postId", "==", u.value), Y("parentId", "==", null), U("createdAt", "desc"), U(L(), "desc"), V(1)), (e) => {
1338
1371
  let t = new Map(f.value.map((e) => [e.id, e]));
1339
1372
  for (let n of e.docChanges()) n.type !== "removed" && t.set(n.doc.id, {
1340
1373
  id: n.doc.id,
@@ -1345,9 +1378,9 @@ function qt(e, n, r = {}) {
1345
1378
  console.error("[memi-board:comments] onSnapshot failed", e);
1346
1379
  });
1347
1380
  }
1348
- async function E() {
1349
- if (!(g.value || !v.value)) {
1350
- g.value = !0;
1381
+ async function D() {
1382
+ if (!_.value && v.value) {
1383
+ _.value = !0;
1351
1384
  try {
1352
1385
  let e = [
1353
1386
  Y("postId", "==", u.value),
@@ -1356,26 +1389,26 @@ function qt(e, n, r = {}) {
1356
1389
  U(L(), "asc"),
1357
1390
  ...b ? [q(b)] : [],
1358
1391
  V(11)
1359
- ], t = await z(W(s(), ...e)), n = t.docs.slice(0, Ut), r = n.map((e) => ({
1392
+ ], t = await z(W(c(), ...e)), n = t.docs.slice(0, Zt), r = n.map((e) => ({
1360
1393
  id: e.id,
1361
1394
  ...e.data()
1362
- })), i = new Set(h.value.map((e) => e.id));
1363
- h.value.push(...r.filter((e) => !i.has(e.id))), b = n.at(-1) ?? b, t.size <= Ut && (v.value = !1, x = setTimeout(() => {
1395
+ })), i = new Set(g.value.map((e) => e.id));
1396
+ g.value.push(...r.filter((e) => !i.has(e.id))), b = n.at(-1) ?? b, t.size <= Zt && (v.value = !1, x = setTimeout(() => {
1364
1397
  x = void 0, T();
1365
1398
  }, 1e3));
1366
1399
  } finally {
1367
- g.value = !1;
1400
+ _.value = !1;
1368
1401
  }
1369
1402
  }
1370
1403
  }
1371
- N(() => {
1404
+ j(() => {
1372
1405
  clearTimeout(x), S?.();
1373
1406
  });
1374
- async function D(e) {
1375
- let n = Kt(e.body), r = X(i), o = re(s());
1407
+ async function O(e) {
1408
+ let n = en(e.body), r = X(i), o = te(c());
1376
1409
  r.set(o, {
1377
1410
  postId: u.value,
1378
- boardId: c.value,
1411
+ boardId: l.value,
1379
1412
  listed: d(),
1380
1413
  body: n,
1381
1414
  authorUid: e.authorUid,
@@ -1395,14 +1428,14 @@ function qt(e, n, r = {}) {
1395
1428
  }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
1396
1429
  }
1397
1430
  async function k(e) {
1398
- let n = Kt(e.body);
1431
+ let n = en(e.body);
1399
1432
  if (!e.parent.id) throw Error("답글 대상 댓글을 찾을 수 없습니다.");
1400
- let r = X(i), o = re(s()), 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;
1401
1434
  if (!f) throw Error("댓글 스레드를 찾을 수 없습니다.");
1402
1435
  let p = Math.min((e.parent.depth ?? 0) + 1, 2);
1403
1436
  r.set(o, {
1404
1437
  postId: u.value,
1405
- boardId: c.value,
1438
+ boardId: l.value,
1406
1439
  listed: d(),
1407
1440
  body: n,
1408
1441
  authorUid: e.authorUid,
@@ -1419,24 +1452,24 @@ function qt(e, n, r = {}) {
1419
1452
  isReply: !0,
1420
1453
  createdAt: G(),
1421
1454
  updatedAt: G()
1422
- }), r.update(l(i, a(), f), { replyCount: B(1) }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
1455
+ }), r.update(s(i, a(), f), { replyCount: B(1) }), r.update(t(i, a(), u.value), { commentCount: B(1) }), await r.commit();
1423
1456
  }
1424
- async function A(e) {
1457
+ async function ee(e) {
1425
1458
  if (!e.id) return;
1426
1459
  if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error("답글이 있는 댓글은 현재 삭제할 수 없습니다.");
1427
- await ft(i, a(), e.id);
1460
+ await yt(i, a(), e.id);
1428
1461
  let n = X(i);
1429
- n.delete(l(i, a(), e.id)), e.parentId && e.rootId && n.update(l(i, a(), e.rootId), { replyCount: B(-1) }), n.update(t(i, a(), u.value), { commentCount: B(-1) }), await n.commit(), h.value = h.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);
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);
1430
1463
  }
1431
- async function j(e, t) {
1432
- let n = Kt(t);
1433
- await J(l(i, a(), e), {
1464
+ async function F(e, t) {
1465
+ let n = en(t);
1466
+ await J(s(i, a(), e), {
1434
1467
  body: n,
1435
1468
  updatedAt: G()
1436
1469
  });
1437
1470
  }
1438
- async function ee(e, t, n) {
1439
- await J(l(i, a(), e), {
1471
+ async function I(e, t, n) {
1472
+ await J(s(i, a(), e), {
1440
1473
  isBlinded: t,
1441
1474
  moderatedAt: G(),
1442
1475
  moderatedBy: n
@@ -1444,19 +1477,19 @@ function qt(e, n, r = {}) {
1444
1477
  }
1445
1478
  return {
1446
1479
  comments: w,
1447
- commentsPending: M(() => y.value || m.value),
1480
+ commentsPending: A(() => y.value || m.value),
1448
1481
  hasMore: v,
1449
- loadingMore: g,
1450
- loadMore: E,
1451
- addComment: D,
1482
+ loadingMore: _,
1483
+ loadMore: D,
1484
+ addComment: O,
1452
1485
  addReply: k,
1453
- updateComment: j,
1454
- setCommentBlinded: ee,
1455
- deleteComment: A
1486
+ updateComment: F,
1487
+ setCommentBlinded: I,
1488
+ deleteComment: ee
1456
1489
  };
1457
1490
  }
1458
- function Jt(e, t, n) {
1459
- let r = Q(), i = () => _(), a = () => O(r, i()), o = t.trim(), s = P([]), c = P(!1), l = P(!1), u = P(!0), d = null, f;
1491
+ function nn(e, t, n) {
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;
1460
1493
  function p(e) {
1461
1494
  return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
1462
1495
  }
@@ -1472,8 +1505,8 @@ function Jt(e, t, n) {
1472
1505
  console.error("[memi-board:replies] onSnapshot failed", e);
1473
1506
  });
1474
1507
  }
1475
- async function h() {
1476
- if (!(c.value || !u.value)) {
1508
+ async function g() {
1509
+ if (!c.value && u.value) {
1477
1510
  c.value = !0;
1478
1511
  try {
1479
1512
  let e = [
@@ -1484,39 +1517,39 @@ function Jt(e, t, n) {
1484
1517
  U(L(), "asc"),
1485
1518
  ...d ? [q(d)] : [],
1486
1519
  V(6)
1487
- ], t = await z(W(a(), ...e)), r = new Set(s.value.map((e) => e.id)), i = t.docs.slice(0, Wt), c = i.map((e) => ({
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) => ({
1488
1521
  id: e.id,
1489
1522
  ...e.data()
1490
1523
  })).filter((e) => !r.has(e.id));
1491
- s.value = p([...s.value, ...c]), d = i.at(-1) ?? d, l.value = !0, t.size <= Wt && (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());
1492
1525
  } finally {
1493
1526
  c.value = !1;
1494
1527
  }
1495
1528
  }
1496
1529
  }
1497
- function g() {
1530
+ function _() {
1498
1531
  f?.(), f = void 0, s.value = [], d = null, l.value = !1, u.value = !0;
1499
1532
  }
1500
1533
  async function v() {
1501
- g(), await h();
1534
+ _(), await g();
1502
1535
  }
1503
- return N(() => f?.()), {
1536
+ return j(() => f?.()), {
1504
1537
  replies: s,
1505
1538
  loading: c,
1506
1539
  loaded: l,
1507
1540
  hasMore: u,
1508
- loadMore: h,
1541
+ loadMore: g,
1509
1542
  refresh: v
1510
1543
  };
1511
1544
  }
1512
1545
  //#endregion
1513
1546
  //#region src/composables/useMemiBoardLikes.ts
1514
- function Yt(e, n) {
1515
- let r = () => _(), i = Q(), a = Z(), o = P(!1), s = P(!1), c;
1547
+ function rn(e, n) {
1548
+ let r = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
1516
1549
  function l(e) {
1517
- return j(i, r(), n, e);
1550
+ return k(i, r(), n, e);
1518
1551
  }
1519
- I(a, (e) => {
1552
+ P(a, (e) => {
1520
1553
  if (c?.(), c = void 0, !e) {
1521
1554
  o.value = !1;
1522
1555
  return;
@@ -1526,7 +1559,7 @@ function Yt(e, n) {
1526
1559
  }, (e) => {
1527
1560
  console.error("[memi-board:likes] onSnapshot failed", e);
1528
1561
  });
1529
- }, { immediate: !0 }), N(() => c?.());
1562
+ }, { immediate: !0 }), j(() => c?.());
1530
1563
  async function u() {
1531
1564
  let c = a.value?.uid;
1532
1565
  if (!c) throw Error("로그인이 필요합니다.");
@@ -1534,7 +1567,7 @@ function Yt(e, n) {
1534
1567
  s.value = !0;
1535
1568
  try {
1536
1569
  let a = l(c), o = t(i, r(), n);
1537
- return await oe(i, async (t) => (await t.get(a)).exists() ? (t.delete(a), t.update(o, { likeCount: B(-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, {
1538
1571
  uid: c,
1539
1572
  postId: n,
1540
1573
  boardId: e,
@@ -1550,50 +1583,50 @@ function Yt(e, n) {
1550
1583
  toggleLike: u
1551
1584
  };
1552
1585
  }
1553
- var Xt = Symbol.for("memi-board:comment-likes");
1554
- function Zt(e, t) {
1555
- let n = () => _(), r = Q(), i = Z(), a = M(() => F(e)), o = M(() => F(t)), s = P(/* @__PURE__ */ new Set()), c = P(null), u;
1556
- I([i, o], ([e, t]) => {
1557
- u?.(), u = void 0, s.value = /* @__PURE__ */ new Set(), !(!e || !t) && (u = H(W(A(r, n()), Y("uid", "==", e.uid), Y("postId", "==", t), Y("target", "==", "comment")), (e) => {
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;
1589
+ P([i, o], ([e, t]) => {
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) => {
1558
1591
  let t = /* @__PURE__ */ new Set();
1559
1592
  for (let n of e.docs) {
1560
1593
  let e = n.data().commentId;
1561
1594
  typeof e == "string" && e && t.add(e);
1562
1595
  }
1563
- s.value = t;
1596
+ c.value = t;
1564
1597
  }, (e) => {
1565
1598
  console.error("[memi-board:comment-likes] onSnapshot failed", e);
1566
1599
  }));
1567
- }, { immediate: !0 }), N(() => u?.());
1600
+ }, { immediate: !0 }), j(() => u?.());
1568
1601
  function d(e) {
1569
- return !!e && s.value.has(e);
1602
+ return !!e && c.value.has(e);
1570
1603
  }
1571
1604
  function f(e) {
1572
- return !!e && c.value === e;
1605
+ return !!e && l.value === e;
1573
1606
  }
1574
1607
  async function p(e) {
1575
1608
  let t = i.value?.uid;
1576
1609
  if (!t) throw Error("로그인이 필요합니다.");
1577
1610
  if (!e) return !1;
1578
- if (c.value) return d(e);
1579
- c.value = e;
1611
+ if (l.value) return d(e);
1612
+ l.value = e;
1580
1613
  try {
1581
- let i = j(r, n(), e, t), c = l(r, n(), e), u = await oe(r, async (n) => {
1582
- let r = await n.get(i), s = await n.get(c);
1614
+ let i = k(r, n(), e, t), l = s(r, n(), e), u = await ie(r, async (n) => {
1615
+ let r = await n.get(i), s = await n.get(l);
1583
1616
  if (!s.exists()) throw Error("댓글을 찾을 수 없습니다.");
1584
- let l = Number(s.data()?.likeCount ?? 0);
1585
- return r.exists() ? (n.delete(i), n.update(c, { likeCount: Math.max(0, l - 1) }), !1) : (n.set(i, {
1617
+ let c = Number(s.data()?.likeCount ?? 0);
1618
+ return r.exists() ? (n.delete(i), n.update(l, { likeCount: Math.max(0, c - 1) }), !1) : (n.set(i, {
1586
1619
  uid: t,
1587
1620
  postId: o.value,
1588
1621
  boardId: a.value,
1589
1622
  commentId: e,
1590
1623
  target: "comment",
1591
1624
  createdAt: G()
1592
- }), n.update(c, { likeCount: l + 1 }), !0);
1593
- }), d = new Set(s.value);
1594
- return u ? d.add(e) : d.delete(e), s.value = d, u;
1625
+ }), n.update(l, { likeCount: c + 1 }), !0);
1626
+ }), d = new Set(c.value);
1627
+ return u ? d.add(e) : d.delete(e), c.value = d, u;
1595
1628
  } finally {
1596
- c.value = null;
1629
+ l.value = null;
1597
1630
  }
1598
1631
  }
1599
1632
  return {
@@ -1604,7 +1637,7 @@ function Zt(e, t) {
1604
1637
  }
1605
1638
  //#endregion
1606
1639
  //#region src/composables/useMemiBoardReports.ts
1607
- var Qt = 200, $t = [
1640
+ var sn = 200, cn = [
1608
1641
  {
1609
1642
  value: "spam",
1610
1643
  label: "스팸·광고"
@@ -1626,12 +1659,12 @@ var Qt = 200, $t = [
1626
1659
  label: "기타"
1627
1660
  }
1628
1661
  ];
1629
- function en(e) {
1630
- return $t.find((t) => t.value === e)?.label || e || "신고";
1662
+ function ln(e) {
1663
+ return cn.find((t) => t.value === e)?.label || e || "신고";
1631
1664
  }
1632
- function tn(e, t) {
1633
- let n = () => _(), i = Q(), a = Z(), o = P(!1), s = P(!1), c;
1634
- I(a, (e) => {
1665
+ function un(e, t) {
1666
+ let n = () => h(), i = Q(), a = Z(), o = M(!1), s = M(!1), c;
1667
+ P(a, (e) => {
1635
1668
  if (c?.(), c = void 0, !e) {
1636
1669
  o.value = !1;
1637
1670
  return;
@@ -1641,13 +1674,13 @@ function tn(e, t) {
1641
1674
  }, (e) => {
1642
1675
  console.error("[memi-board:reports] onSnapshot failed", e);
1643
1676
  });
1644
- }, { immediate: !0 }), N(() => c?.());
1677
+ }, { immediate: !0 }), j(() => c?.());
1645
1678
  async function l(c) {
1646
1679
  let l = a.value?.uid;
1647
1680
  if (!l) throw Error("로그인이 필요합니다.");
1648
1681
  if (s.value) return;
1649
1682
  if (c.authorUid && c.authorUid === l) throw Error("자신의 글은 신고할 수 없습니다.");
1650
- let u = $t.some((e) => e.value === c.reason) ? c.reason : null;
1683
+ let u = cn.some((e) => e.value === c.reason) ? c.reason : null;
1651
1684
  if (!u) throw Error("신고 사유를 선택해 주세요.");
1652
1685
  let d = (c.detail || "").trim();
1653
1686
  if (d.length > 200) throw Error("자세한 내용은 200자까지입니다.");
@@ -1676,35 +1709,35 @@ function tn(e, t) {
1676
1709
  submitReport: l
1677
1710
  };
1678
1711
  }
1679
- var nn = 20;
1680
- function rn(e = {}) {
1681
- let t = () => _(), n = Q(), { canManageContent: i, canManageBoard: a } = tt(), s = e.pageSize ?? nn, c = M(() => F(e.boardId)?.trim() || ""), l = P([]), u = P(!0), d = P(!1), f = P(!1), p = P(""), m = null, h;
1682
- function g(e) {
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;
1715
+ function _(e) {
1683
1716
  return {
1684
1717
  id: e.id,
1685
1718
  ...e.data()
1686
1719
  };
1687
1720
  }
1688
1721
  function v() {
1689
- if (h?.(), !i.value) {
1722
+ if (g?.(), !a.value) {
1690
1723
  l.value = [], u.value = !1;
1691
1724
  return;
1692
1725
  }
1693
1726
  u.value = !0;
1694
1727
  let e = c.value ? [Y("status", "==", "open"), Y("boardId", "==", c.value)] : [Y("status", "==", "open"), Y("target", "==", "post")];
1695
- h = H(W(o(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), V(s)), (e) => {
1696
- l.value = e.docs.map(g).filter((e) => a(e.boardId)), m = e.docs.at(-1) ?? null, f.value = e.docs.length >= s, u.value = !1;
1728
+ g = H(W(i(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), V(s)), (e) => {
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;
1697
1730
  }, (e) => {
1698
1731
  console.error("[memi-board:report-queue] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
1699
1732
  });
1700
1733
  }
1701
- I([i, c], v, { immediate: !0 }), N(() => h?.());
1734
+ P([a, c], v, { immediate: !0 }), j(() => g?.());
1702
1735
  async function y() {
1703
- if (!(d.value || !f.value || !m || !i.value)) {
1736
+ if (!d.value && f.value && m && a.value) {
1704
1737
  d.value = !0, p.value = "";
1705
1738
  try {
1706
- let e = c.value ? [Y("status", "==", "open"), Y("boardId", "==", c.value)] : [Y("status", "==", "open"), Y("target", "==", "post")], r = await z(W(o(n, t()), ...e, U("createdAt", "desc"), U(L(), "desc"), q(m), V(s + 1))), i = r.docs.slice(0, s), u = new Set(l.value.map((e) => e.id));
1707
- l.value.push(...i.map(g).filter((e) => !u.has(e.id) && a(e.boardId))), m = i.at(-1) ?? m, f.value = r.docs.length > s;
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));
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;
1708
1741
  } catch (e) {
1709
1742
  p.value = e.message || String(e);
1710
1743
  } finally {
@@ -1713,7 +1746,7 @@ function rn(e = {}) {
1713
1746
  }
1714
1747
  }
1715
1748
  async function b(e, i) {
1716
- !e.id || !a(e.boardId) || await J(r(n, t(), e.postId, e.uid), {
1749
+ e.id && o(e.boardId) && await J(r(n, t(), e.postId, e.uid), {
1717
1750
  status: i,
1718
1751
  reviewedAt: G(),
1719
1752
  reviewedBy: Z().value?.uid || ""
@@ -1732,8 +1765,8 @@ function rn(e = {}) {
1732
1765
  }
1733
1766
  //#endregion
1734
1767
  //#region src/composables/useMemiBoardViews.ts
1735
- function an() {
1736
- let e = () => _(), n = Q();
1768
+ function pn() {
1769
+ let e = () => h(), n = Q();
1737
1770
  function r(t, n) {
1738
1771
  let { postsCollection: r } = e();
1739
1772
  return `memi-board:viewed:${r}:${t}:${n}`;
@@ -1747,13 +1780,13 @@ function an() {
1747
1780
  }
1748
1781
  }
1749
1782
  function a(e, t) {
1750
- if (!(typeof sessionStorage > "u")) try {
1783
+ if (typeof sessionStorage < "u") try {
1751
1784
  sessionStorage.setItem(r(e, t), "1");
1752
1785
  } catch {}
1753
1786
  }
1754
1787
  async function o(o, s) {
1755
1788
  let c = o?.trim(), l = s?.trim();
1756
- if (!(!c || !l) && !i(c, l)) {
1789
+ if (c && l && !i(c, l)) {
1757
1790
  a(c, l);
1758
1791
  try {
1759
1792
  await J(t(n, e(), l), { viewCount: B(1) });
@@ -1772,7 +1805,7 @@ function an() {
1772
1805
  }
1773
1806
  //#endregion
1774
1807
  //#region src/utils/moderation-prompt.ts
1775
- var on = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", sn = {
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 = {
1776
1809
  abuse: "욕설·비속어·모욕",
1777
1810
  spam: "스팸·광고",
1778
1811
  adult: "선정적·성인 내용",
@@ -1780,17 +1813,17 @@ var on = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
1780
1813
  other: "부적절한 내용",
1781
1814
  none: ""
1782
1815
  };
1783
- function cn(e) {
1816
+ function gn(e) {
1784
1817
  if (e.via === "local" && e.localHit) {
1785
1818
  let t = e.localHit.trim();
1786
1819
  return t.length > 0 && t.length <= 12 ? `「${t}」 같은 표현은 사용할 수 없습니다. 다른 말로 바꿔 주세요.` : "욕설·비속어가 포함되어 게시할 수 없습니다. 표현을 바꿔 주세요.";
1787
1820
  }
1788
1821
  let t = (e.reason || "").trim();
1789
1822
  if (t) return t;
1790
- let n = e.category && e.category !== "none" ? sn[e.category] || e.category : "";
1823
+ let n = e.category && e.category !== "none" ? hn[e.category] || e.category : "";
1791
1824
  return n ? `${n}이(가) 포함되어 게시할 수 없습니다. 내용을 수정해 주세요.` : "게시할 수 없는 내용이 포함되어 있습니다. 내용을 수정해 주세요.";
1792
1825
  }
1793
- var ln = [
1826
+ var _n = [
1794
1827
  "씨발",
1795
1828
  "시발",
1796
1829
  "시이발",
@@ -1816,10 +1849,10 @@ var ln = [
1816
1849
  "bitch",
1817
1850
  "asshole"
1818
1851
  ];
1819
- function un(e) {
1852
+ function vn(e) {
1820
1853
  return new RegExp(e.join("|"), "i");
1821
1854
  }
1822
- var dn = /* @__PURE__ */ new Set([
1855
+ var yn = /* @__PURE__ */ new Set([
1823
1856
  "none",
1824
1857
  "abuse",
1825
1858
  "spam",
@@ -1827,7 +1860,7 @@ var dn = /* @__PURE__ */ new Set([
1827
1860
  "violence",
1828
1861
  "other"
1829
1862
  ]);
1830
- function fn(e) {
1863
+ function bn(e) {
1831
1864
  let t = e.trim();
1832
1865
  if (!t) return null;
1833
1866
  let n;
@@ -1845,7 +1878,7 @@ function fn(e) {
1845
1878
  if (typeof n != "object" || !n) return null;
1846
1879
  let r = n;
1847
1880
  if (typeof r.flagged != "boolean") return null;
1848
- let i = typeof r.category == "string" && dn.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 : "";
1849
1882
  return {
1850
1883
  flagged: r.flagged,
1851
1884
  category: i,
@@ -1854,20 +1887,20 @@ function fn(e) {
1854
1887
  }
1855
1888
  //#endregion
1856
1889
  //#region src/composables/useMemiBoardModeration.ts
1857
- var pn = {
1890
+ var xn = {
1858
1891
  flagged: !1,
1859
1892
  category: "none",
1860
1893
  reason: "",
1861
1894
  via: "empty"
1862
1895
  };
1863
- function mn() {
1864
- let e = u().moderation ?? {}, t = le(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = tt(), a = un([...ln, ...e.localBlocklist ?? []]);
1896
+ function Sn() {
1897
+ let e = c().moderation ?? {}, t = se(), { isWriteRestricted: n, restrictedMessage: r, recordContentModerationBlock: i } = ct(), a = vn([..._n, ...e.localBlocklist ?? []]);
1865
1898
  function o(e) {
1866
1899
  let t = e.match(a);
1867
1900
  return t ? {
1868
1901
  flagged: !0,
1869
1902
  category: "abuse",
1870
- reason: cn({
1903
+ reason: gn({
1871
1904
  via: "local",
1872
1905
  localHit: t[0] || "",
1873
1906
  category: "abuse"
@@ -1876,26 +1909,26 @@ function mn() {
1876
1909
  } : null;
1877
1910
  }
1878
1911
  function s() {
1879
- let n = e.model ?? "gemini-3.5-flash-lite", r = e.useLimitedUseAppCheckTokens !== !1, i = we(t, {
1880
- backend: new Se(),
1912
+ let n = e.model ?? "gemini-3.5-flash-lite", r = e.useLimitedUseAppCheckTokens !== !1, i = Se(t, {
1913
+ backend: new be(),
1881
1914
  useLimitedUseAppCheckTokens: r
1882
1915
  });
1883
- return Te(i, {
1916
+ return Ce(i, {
1884
1917
  model: n,
1885
- systemInstruction: on,
1918
+ systemInstruction: mn,
1886
1919
  generationConfig: {
1887
1920
  temperature: 0,
1888
1921
  maxOutputTokens: 256,
1889
1922
  responseMimeType: "application/json",
1890
- responseSchema: Ce.object({ properties: {
1891
- flagged: Ce.boolean(),
1892
- category: Ce.string(),
1893
- reason: Ce.string()
1923
+ responseSchema: xe.object({ properties: {
1924
+ flagged: xe.boolean(),
1925
+ category: xe.string(),
1926
+ reason: xe.string()
1894
1927
  } })
1895
1928
  }
1896
1929
  });
1897
1930
  }
1898
- function c() {
1931
+ function l() {
1899
1932
  return e.onError === "block" ? {
1900
1933
  flagged: !0,
1901
1934
  category: "other",
@@ -1910,8 +1943,8 @@ function mn() {
1910
1943
  via: "ai-error-allow"
1911
1944
  };
1912
1945
  }
1913
- function l(e, t = "") {
1914
- let n = cn({
1946
+ function u(e, t = "") {
1947
+ let n = gn({
1915
1948
  reason: e.reason,
1916
1949
  category: e.category,
1917
1950
  via: e.via
@@ -1925,9 +1958,9 @@ function mn() {
1925
1958
  if (!e.flagged || e.error || e.via !== "local" && e.via !== "ai") return e;
1926
1959
  try {
1927
1960
  let { messageSuffix: t } = await i();
1928
- return l(e, t);
1961
+ return u(e, t);
1929
1962
  } catch (t) {
1930
- return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t), l(e);
1963
+ return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t), u(e);
1931
1964
  }
1932
1965
  }
1933
1966
  async function f(t, i) {
@@ -1939,26 +1972,26 @@ function mn() {
1939
1972
  };
1940
1973
  let a = t.trim();
1941
1974
  if (!a) return {
1942
- ...pn,
1975
+ ...xn,
1943
1976
  via: "empty"
1944
1977
  };
1945
1978
  if (i?.skipFilter) return {
1946
- ...pn,
1979
+ ...xn,
1947
1980
  via: "admin-override"
1948
1981
  };
1949
- let l = o(a);
1950
- if (l) return d(l);
1982
+ let c = o(a);
1983
+ if (c) return d(c);
1951
1984
  if (e.enabled === !1) return {
1952
- ...pn,
1985
+ ...xn,
1953
1986
  via: "disabled"
1954
1987
  };
1955
1988
  try {
1956
- let e = fn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
1957
- if (!e) return c();
1989
+ let e = bn((await s().generateContent(`심사할 텍스트:\n"""${a.slice(0, 4e3)}"""`)).response.text());
1990
+ if (!e) return l();
1958
1991
  let t = {
1959
1992
  flagged: e.flagged,
1960
1993
  category: e.category,
1961
- reason: cn({
1994
+ reason: gn({
1962
1995
  reason: e.reason,
1963
1996
  category: e.category,
1964
1997
  via: "ai"
@@ -1967,7 +2000,7 @@ function mn() {
1967
2000
  };
1968
2001
  return t.flagged ? d(t) : t;
1969
2002
  } catch (e) {
1970
- return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e), c();
2003
+ return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e), l();
1971
2004
  }
1972
2005
  }
1973
2006
  async function p(t) {
@@ -1978,22 +2011,22 @@ function mn() {
1978
2011
  via: "restricted"
1979
2012
  };
1980
2013
  if (e.enabled === !1 || !e.moderateImages) return {
1981
- ...pn,
2014
+ ...xn,
1982
2015
  via: "disabled"
1983
2016
  };
1984
2017
  try {
1985
2018
  let e = await new Promise((e, n) => {
1986
2019
  let r = new FileReader();
1987
2020
  r.onload = () => e(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(t);
1988
- }), n = fn((await s().generateContent([{ inlineData: {
2021
+ }), n = bn((await s().generateContent([{ inlineData: {
1989
2022
  mimeType: t.type || "image/jpeg",
1990
2023
  data: e
1991
2024
  } }, "이 이미지를 심사해 주세요."])).response.text());
1992
- if (!n) return c();
2025
+ if (!n) return l();
1993
2026
  let r = {
1994
2027
  flagged: n.flagged,
1995
2028
  category: n.category,
1996
- reason: cn({
2029
+ reason: gn({
1997
2030
  reason: n.reason,
1998
2031
  category: n.category,
1999
2032
  via: "ai"
@@ -2002,7 +2035,7 @@ function mn() {
2002
2035
  };
2003
2036
  return r.flagged ? d(r) : r;
2004
2037
  } catch (e) {
2005
- return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e), c();
2038
+ return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e), l();
2006
2039
  }
2007
2040
  }
2008
2041
  return {
@@ -2012,7 +2045,7 @@ function mn() {
2012
2045
  }
2013
2046
  //#endregion
2014
2047
  //#region src/composables/useMemiBoardUsers.ts
2015
- var hn = [
2048
+ var Cn = [
2016
2049
  {
2017
2050
  value: "admin",
2018
2051
  label: "관리자",
@@ -2029,11 +2062,11 @@ var hn = [
2029
2062
  description: "글과 댓글을 작성하고 본인이 작성한 콘텐츠만 수정·삭제할 수 있습니다."
2030
2063
  }
2031
2064
  ];
2032
- function gn(e = {}) {
2033
- let t = () => _(), n = Q(), r = M(() => F(e.enabled) ?? !0 ? h(n, t()) : null), i = se(r, { ssrKey: w(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") });
2034
2067
  async function a(e, r) {
2035
- if (!hn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
2036
- await J(x(n, t(), e), {
2068
+ if (!Cn.some((e) => e.value === r)) throw Error("지원하지 않는 역할입니다.");
2069
+ await J(y(n, t(), e), {
2037
2070
  role: r,
2038
2071
  updatedAt: G()
2039
2072
  });
@@ -2046,11 +2079,11 @@ function gn(e = {}) {
2046
2079
  }
2047
2080
  //#endregion
2048
2081
  //#region src/composables/useMemiBoardUserProfile.ts
2049
- function _n(e) {
2050
- let t = Q(), n = () => _(), r = M(() => F(e)), i = M(() => {
2082
+ function Tn(e) {
2083
+ let t = Q(), n = () => h(), r = A(() => N(e)), i = A(() => {
2051
2084
  let e = r.value;
2052
- return e ? x(t, n(), e) : null;
2053
- }), { data: a, pending: o } = ce(i);
2085
+ return e ? y(t, n(), e) : null;
2086
+ }), { data: a, pending: o } = oe(i);
2054
2087
  return {
2055
2088
  profile: a,
2056
2089
  profilePending: o
@@ -2058,7 +2091,7 @@ function _n(e) {
2058
2091
  }
2059
2092
  //#endregion
2060
2093
  //#region src/utils/section.ts
2061
- var vn = [
2094
+ var En = [
2062
2095
  3,
2063
2096
  4,
2064
2097
  5,
@@ -2067,7 +2100,7 @@ var vn = [
2067
2100
  8,
2068
2101
  9,
2069
2102
  12
2070
- ], yn = [
2103
+ ], Dn = [
2071
2104
  {
2072
2105
  value: "list",
2073
2106
  label: "게시목록"
@@ -2080,24 +2113,24 @@ var vn = [
2080
2113
  value: "comments",
2081
2114
  label: "댓글모음"
2082
2115
  }
2083
- ], bn = [{
2116
+ ], On = [{
2084
2117
  value: "latest",
2085
2118
  label: "최신순"
2086
2119
  }, {
2087
2120
  value: "likes",
2088
2121
  label: "좋아요순"
2089
2122
  }];
2090
- function xn(e) {
2123
+ function kn(e) {
2091
2124
  return e === "list" ? 5 : 4;
2092
2125
  }
2093
- function Sn(e, t) {
2126
+ function An(e, t) {
2094
2127
  let n = Math.floor(Number(t));
2095
- return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : xn(e);
2128
+ return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : kn(e);
2096
2129
  }
2097
- function Cn(e) {
2130
+ function jn(e) {
2098
2131
  return e === 12 ? null : 12 - e;
2099
2132
  }
2100
- function wn(e) {
2133
+ function Mn(e) {
2101
2134
  return {
2102
2135
  3: "col-span-12 md:col-span-3",
2103
2136
  4: "col-span-12 md:col-span-4",
@@ -2109,36 +2142,36 @@ function wn(e) {
2109
2142
  12: "col-span-12"
2110
2143
  }[e];
2111
2144
  }
2112
- function Tn(e) {
2145
+ function Nn(e) {
2113
2146
  return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
2114
2147
  }
2115
- function En(e) {
2148
+ function Pn(e) {
2116
2149
  let t = e.boardId || e.category || "free";
2117
2150
  return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
2118
2151
  }
2119
- function Dn(e) {
2152
+ function Fn(e) {
2120
2153
  return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
2121
2154
  }
2122
- function On(e) {
2123
- if (!(!e.boardId || !e.postId)) return `/board/${e.boardId}/post/${e.postId}`;
2155
+ function In(e) {
2156
+ if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
2124
2157
  }
2125
- function kn(e) {
2158
+ function Ln(e) {
2126
2159
  return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
2127
2160
  }
2128
- function An(e) {
2161
+ function Rn(e) {
2129
2162
  return e.title?.trim() || e.summary || "게시물";
2130
2163
  }
2131
- function jn(e) {
2164
+ function zn(e) {
2132
2165
  return e === "image" || e === "video" ? "media" : "list";
2133
2166
  }
2134
- function Mn(e) {
2135
- return jn(e) === "media" ? "미디어" : "목록";
2167
+ function Bn(e) {
2168
+ return zn(e) === "media" ? "미디어" : "목록";
2136
2169
  }
2137
- function Nn(e, t) {
2170
+ function Vn(e, t) {
2138
2171
  return e ? t(e)?.listView ?? "default" : "default";
2139
2172
  }
2140
- function Pn(e, t) {
2141
- let n = e.map((e) => Nn(e.boardId, t));
2173
+ function Hn(e, t) {
2174
+ let n = e.map((e) => Vn(e.boardId, t));
2142
2175
  if (!n.length) return "default";
2143
2176
  if (n.every((e) => e === n[0])) return n[0];
2144
2177
  let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
@@ -2146,68 +2179,68 @@ function Pn(e, t) {
2146
2179
  }
2147
2180
  //#endregion
2148
2181
  //#region src/composables/useMemiBoardSections.ts
2149
- var Fn = [];
2150
- function In(e) {
2182
+ var Un = [];
2183
+ function Wn(e) {
2151
2184
  let t = Number(e.cols);
2152
- if (vn.includes(t)) return t;
2185
+ if (En.includes(t)) return t;
2153
2186
  let n = e.width;
2154
2187
  return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
2155
2188
  }
2156
- function Ln(e) {
2189
+ function Gn(e) {
2157
2190
  let t = e.height ?? e.size;
2158
2191
  return t === "sm" || t === "lg" ? t : "md";
2159
2192
  }
2160
- function Rn(e) {
2193
+ function Kn(e) {
2161
2194
  return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
2162
2195
  }
2163
- function zn(e) {
2196
+ function qn(e) {
2164
2197
  return e.sort === "likes" ? "likes" : "latest";
2165
2198
  }
2166
- function Bn(e) {
2199
+ function Jn(e) {
2167
2200
  return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
2168
2201
  }
2169
- function Vn(e, t) {
2202
+ function Yn(e, t) {
2170
2203
  let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
2171
2204
  for (let e of n) {
2172
2205
  let n = String(e || "").trim();
2173
- if (!(!n || r.includes(n)) && (r.push(n), r.length >= t)) break;
2206
+ if (n && !r.includes(n) && (r.push(n), r.length >= t)) break;
2174
2207
  }
2175
2208
  return r;
2176
2209
  }
2177
- function Hn(e, t) {
2178
- let n = Rn(e), r = Sn(n, e.count);
2210
+ function Xn(e, t) {
2211
+ let n = Kn(e), r = An(n, e.count);
2179
2212
  return {
2180
2213
  id: String(e.id || `box-${t + 1}`),
2181
2214
  title: String(e.title || `섹션 ${t + 1}`),
2182
2215
  showTitle: e.showTitle !== !1,
2183
2216
  kind: n,
2184
- boardId: Bn(e),
2217
+ boardId: Jn(e),
2185
2218
  count: r,
2186
- postIds: Vn(e, r),
2187
- sort: zn(e),
2188
- cols: In(e),
2189
- height: Ln(e),
2219
+ postIds: Yn(e, r),
2220
+ sort: qn(e),
2221
+ cols: Wn(e),
2222
+ height: Gn(e),
2190
2223
  order: t
2191
2224
  };
2192
2225
  }
2193
- function Un() {
2194
- let e = Q(), t = re(e, "settings", "homeLayout"), { data: n, pending: r } = ce(t), i = M(() => (Array.isArray(n.value?.blocks) ? n.value.blocks : Fn).map((e, t) => Hn(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)));
2195
2228
  async function a(e) {
2196
2229
  await K(t, {
2197
2230
  columns: 12,
2198
2231
  blocks: e.map((e, t) => {
2199
- let n = e, r = Rn(n), i = Sn(r, e.count);
2232
+ let n = e, r = Kn(n), i = An(r, e.count);
2200
2233
  return {
2201
2234
  id: e.id,
2202
2235
  title: e.title.trim() || `섹션 ${t + 1}`,
2203
2236
  showTitle: e.showTitle !== !1,
2204
2237
  kind: r,
2205
- boardId: Bn(n),
2238
+ boardId: Jn(n),
2206
2239
  count: i,
2207
- postIds: Vn(n, i),
2208
- sort: zn(n),
2209
- cols: In(n),
2210
- height: Ln(n),
2240
+ postIds: Yn(n, i),
2241
+ sort: qn(n),
2242
+ cols: Wn(n),
2243
+ height: Gn(n),
2211
2244
  order: t
2212
2245
  };
2213
2246
  }),
@@ -2219,42 +2252,47 @@ function Un() {
2219
2252
  pending: r,
2220
2253
  sections: i,
2221
2254
  blocks: i,
2222
- hasSavedLayout: M(() => Array.isArray(n.value?.blocks)),
2255
+ hasSavedLayout: A(() => Array.isArray(n.value?.blocks)),
2223
2256
  saveSections: a,
2224
2257
  saveBlocks: a
2225
2258
  };
2226
2259
  }
2227
2260
  //#endregion
2228
2261
  //#region src/composables/useMemiBoardMiniPosts.ts
2229
- function Wn(e, t) {
2230
- let n = Q(), r = () => _(), i = F(e)?.trim() || "all", a = M(() => {
2231
- let i = Math.max(1, Math.floor(Number(F(t)) || 5)), a = F(e)?.trim() || "", o = [Y("isPublished", "==", !0), Y("listed", "==", !0)];
2232
- return a && o.unshift(Y("boardId", "==", a)), W(c(n, r()), ...o, U("createdAt", "desc"), V(i));
2233
- }), { data: o, pending: s, error: l } = se(a, { ssrKey: w(r(), `mini-list/${i}`) });
2262
+ function Qn(e, t) {
2263
+ let n = Q(), r = () => h(), i = N(e)?.trim() || "all", a = A(() => {
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}`) });
2234
2267
  return {
2235
- posts: M(() => o.value ?? []),
2236
- pending: s,
2268
+ posts: A(() => s.value ?? []),
2269
+ pending: c,
2237
2270
  error: l
2238
2271
  };
2239
2272
  }
2240
- function Gn(e) {
2241
- let t = Q(), n = () => _(), r = M(() => [...new Set(F(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = M(() => r.value.length ? W(c(t, n()), Y(L(), "in", r.value)) : null), { data: o, pending: s, error: l } = se(a, { ssrKey: w(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}`) });
2242
2275
  return {
2243
- posts: M(() => {
2244
- let e = new Map((o.value ?? []).map((e) => [e.id, e])), t = [];
2276
+ posts: A(() => {
2277
+ let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
2245
2278
  for (let n of r.value) {
2246
2279
  let r = e.get(n);
2247
2280
  r && r.isPublished !== !1 && t.push(r);
2248
2281
  }
2249
2282
  return t;
2250
2283
  }),
2251
- pending: s,
2284
+ pending: c,
2252
2285
  error: l
2253
2286
  };
2254
2287
  }
2255
2288
  //#endregion
2256
2289
  //#region src/data/versionHistory.ts
2257
- var Kn = [
2290
+ var er = [
2291
+ {
2292
+ version: "0.44.0",
2293
+ date: "2026-10-01",
2294
+ highlights: ["글을 저장하고 미리보기가 뜨기까지 기다리는 시간이 줄었어요 (특히 iPhone·Mac Safari)"]
2295
+ },
2258
2296
  {
2259
2297
  version: "0.42.0",
2260
2298
  date: "2026-08-27",
@@ -2524,7 +2562,7 @@ var Kn = [
2524
2562
  highlights: ["글쓰기·댓글·첨부·로그인 권한으로 게시판을 바로 시작할 수 있어요", "부적절한 글·댓글은 AI 검열로 막을 수 있어요"],
2525
2563
  note: "실제 보안은 호스트 Firebase 규칙 등록이 필요합니다."
2526
2564
  }
2527
- ], qn = /* @__PURE__ */ i(((e, t) => {
2565
+ ], tr = /* @__PURE__ */ Ae(((e, t) => {
2528
2566
  (function(n, r) {
2529
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();
2530
2568
  })(e, (function() {
@@ -2818,7 +2856,7 @@ var Kn = [
2818
2856
  return w(1e3 * e);
2819
2857
  }, w.en = b[y], w.Ls = b, w.p = {}, w;
2820
2858
  }));
2821
- })), Jn = /* @__PURE__ */ i(((e, t) => {
2859
+ })), nr = /* @__PURE__ */ Ae(((e, t) => {
2822
2860
  (function(n, r) {
2823
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();
2824
2862
  })(e, (function() {
@@ -2922,9 +2960,9 @@ var Kn = [
2922
2960
  };
2923
2961
  };
2924
2962
  }));
2925
- })), Yn = /* @__PURE__ */ i(((e, t) => {
2963
+ })), rr = /* @__PURE__ */ Ae(((e, t) => {
2926
2964
  (function(n, r) {
2927
- typeof e == "object" && t !== void 0 ? t.exports = r(qn()) : 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);
2928
2966
  })(e, (function(e) {
2929
2967
  function t(e) {
2930
2968
  return e && typeof e == "object" && "default" in e ? e : { default: e };
@@ -2972,24 +3010,24 @@ var Kn = [
2972
3010
  };
2973
3011
  return n.default.locale(r, null, !0), r;
2974
3012
  }));
2975
- })), Xn = /* @__PURE__ */ a(qn(), 1), Zn = /* @__PURE__ */ a(Jn(), 1);
2976
- Yn(), Xn.default.extend(Zn.default), Xn.default.locale("ko");
2977
- function Qn(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) {
2978
3016
  return e?.toDate ? e.toDate().toLocaleDateString("ko-KR") : "";
2979
3017
  }
2980
- function $n(e, t = Date.now()) {
2981
- return e?.toDate ? (0, Xn.default)(e.toDate()).from((0, Xn.default)(t)) : "방금 전";
3018
+ function sr(e, t = Date.now()) {
3019
+ return e?.toDate ? (0, ir.default)(e.toDate()).from((0, ir.default)(t)) : "방금 전";
2982
3020
  }
2983
- function er(e) {
2984
- return e?.toDate ? (0, Xn.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") : "시간 확인 중";
2985
3023
  }
2986
- function tr(e, t) {
2987
- let n = er(e), r = e?.toMillis?.(), i = t?.toMillis?.();
2988
- return i == null || r == null || r === i ? [n] : [`생성시간: ${n}`, `수정시간: ${er(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)}`];
2989
3027
  }
2990
3028
  //#endregion
2991
3029
  //#region src/composables/useMemiBoardWritingAssistant.ts
2992
- var nr = 10, rr = 864e5, ir = 200, ar = {
3030
+ var ur = 10, dr = 864e5, fr = 200, pr = {
2993
3031
  proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
2994
3032
  polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
2995
3033
  continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
@@ -2998,29 +3036,29 @@ var nr = 10, rr = 864e5, ir = 200, ar = {
2998
3036
  "translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
2999
3037
  title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
3000
3038
  };
3001
- function or(e) {
3002
- if (e.action !== "custom") return ar[e.action];
3003
- let t = e.customInstruction?.trim().slice(0, ir);
3039
+ function mr(e) {
3040
+ if (e.action !== "custom") return pr[e.action];
3041
+ let t = e.customInstruction?.trim().slice(0, fr);
3004
3042
  if (!t) throw Error("어떻게 바꿀지 지시문을 입력해 주세요.");
3005
3043
  return `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${t}`;
3006
3044
  }
3007
- function sr(e) {
3045
+ function hr(e) {
3008
3046
  return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
3009
3047
  }
3010
- function cr(e) {
3048
+ function gr(e) {
3011
3049
  return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
3012
3050
  }
3013
- function lr() {
3014
- let e = le(), t = Q(), n = Z(), r = u();
3051
+ function _r() {
3052
+ let e = se(), t = Q(), n = Z(), r = c();
3015
3053
  async function i() {
3016
3054
  let e = n.value?.uid;
3017
3055
  if (!e) throw Error("AI 글쓰기 도우미는 로그인 후 사용할 수 있습니다.");
3018
- await oe(t, async (n) => {
3019
- let r = x(t, _(), e), i = await n.get(r);
3056
+ await ie(t, async (n) => {
3057
+ let r = y(t, h(), e), i = await n.get(r);
3020
3058
  if (!i.exists()) throw Error("사용자 정보를 확인한 뒤 다시 시도해 주세요.");
3021
- let a = i.data(), o = cr(a.aiWritingWindowAt), s = Math.max(0, Math.floor(Number(a.aiWritingCount) || 0)), c = Date.now(), l = o != null && c - o < rr;
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;
3022
3060
  if (l && s >= 10) {
3023
- let e = o + rr, t = Math.max(1, Math.ceil((e - c) / 36e5));
3061
+ let e = o + dr, t = Math.max(1, Math.ceil((e - c) / 36e5));
3024
3062
  throw Error(`AI 글쓰기 도우미는 하루 10회까지 사용할 수 있습니다. 약 ${t}시간 후 다시 이용해 주세요.`);
3025
3063
  }
3026
3064
  n.update(r, {
@@ -3031,13 +3069,13 @@ function lr() {
3031
3069
  });
3032
3070
  }
3033
3071
  async function a(t) {
3034
- let n = or(t);
3072
+ let n = mr(t);
3035
3073
  if (!t.content.trim()) throw Error("AI로 다듬을 내용을 먼저 입력해 주세요.");
3036
3074
  await i();
3037
- let a = r.moderation ?? {}, o = we(e, {
3038
- backend: new Se(),
3075
+ let a = r.moderation ?? {}, o = Se(e, {
3076
+ backend: new be(),
3039
3077
  useLimitedUseAppCheckTokens: a.useLimitedUseAppCheckTokens !== !1
3040
- }), s = Te(o, {
3078
+ }), s = Ce(o, {
3041
3079
  model: a.model ?? "gemini-3.5-flash-lite",
3042
3080
  systemInstruction: [
3043
3081
  "너는 게시판 글쓰기 편집 도우미다.",
@@ -3052,7 +3090,7 @@ function lr() {
3052
3090
  `작업: ${n}`,
3053
3091
  t.title ? `현재 제목: ${t.title}` : "",
3054
3092
  `본문:\n${c.slice(0, 12e3)}`
3055
- ].filter(Boolean).join("\n\n"), u = sr((await s.generateContent(l)).response.text());
3093
+ ].filter(Boolean).join("\n\n"), u = hr((await s.generateContent(l)).response.text());
3056
3094
  if (!u) throw Error("AI가 결과를 만들지 못했습니다. 다시 시도해 주세요.");
3057
3095
  return u;
3058
3096
  }
@@ -3060,14 +3098,14 @@ function lr() {
3060
3098
  }
3061
3099
  //#endregion
3062
3100
  //#region src/utils/renderMarkdown.ts
3063
- function ur(e) {
3101
+ function vr(e) {
3064
3102
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
3065
3103
  }
3066
- function dr(e) {
3104
+ function yr(e) {
3067
3105
  let t = e;
3068
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;
3069
3107
  }
3070
- function fr(e) {
3108
+ function br(e) {
3071
3109
  if (!e?.trim()) return "";
3072
3110
  let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
3073
3111
  function c() {
@@ -3076,7 +3114,7 @@ function fr(e) {
3076
3114
  return;
3077
3115
  }
3078
3116
  let e = o;
3079
- n.push(`<${e}>${s.map((e) => `<li>${dr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3117
+ n.push(`<${e}>${s.map((e) => `<li>${yr(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3080
3118
  }
3081
3119
  for (; r < t.length;) {
3082
3120
  let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
@@ -3085,7 +3123,7 @@ function fr(e) {
3085
3123
  continue;
3086
3124
  }
3087
3125
  if (i) {
3088
- a.push(ur(e)), r++;
3126
+ a.push(vr(e)), r++;
3089
3127
  continue;
3090
3128
  }
3091
3129
  if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
@@ -3096,24 +3134,24 @@ function fr(e) {
3096
3134
  if (u) {
3097
3135
  c();
3098
3136
  let e = u[1].length;
3099
- n.push(`<h${e} class="font-semibold mt-4 mb-2">${dr(ur(u[2]))}</h${e}>`), r++;
3137
+ n.push(`<h${e} class="font-semibold mt-4 mb-2">${yr(vr(u[2]))}</h${e}>`), r++;
3100
3138
  continue;
3101
3139
  }
3102
3140
  if (e.startsWith("> ")) {
3103
3141
  c();
3104
3142
  let e = [];
3105
- for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(ur((t[r] ?? "").slice(2))), r++;
3106
- n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${dr(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>`);
3107
3145
  continue;
3108
3146
  }
3109
3147
  let d = e.match(/^[-*+]\s+(.+)$/);
3110
3148
  if (d) {
3111
- o && o !== "ul" && c(), o = "ul", s.push(ur(d[1])), r++;
3149
+ o && o !== "ul" && c(), o = "ul", s.push(vr(d[1])), r++;
3112
3150
  continue;
3113
3151
  }
3114
3152
  let f = e.match(/^\d+\.\s+(.+)$/);
3115
3153
  if (f) {
3116
- o && o !== "ol" && c(), o = "ol", s.push(ur(f[1])), r++;
3154
+ o && o !== "ol" && c(), o = "ol", s.push(vr(f[1])), r++;
3117
3155
  continue;
3118
3156
  }
3119
3157
  if (!e.trim()) {
@@ -3125,13 +3163,13 @@ function fr(e) {
3125
3163
  for (; r < t.length;) {
3126
3164
  let e = t[r] ?? "";
3127
3165
  if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
3128
- p.push(ur(e)), r++;
3166
+ p.push(vr(e)), r++;
3129
3167
  }
3130
- n.push(`<p class="my-2 leading-relaxed">${dr(p.join("<br />"))}</p>`);
3168
+ n.push(`<p class="my-2 leading-relaxed">${yr(p.join("<br />"))}</p>`);
3131
3169
  }
3132
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");
3133
3171
  }
3134
3172
  //#endregion
3135
- export { Bt as AUTHOR_MEMO_MAX_LENGTH, vn as BOARD_SECTION_COLS, yn as BOARD_SECTION_KINDS, bn as BOARD_SECTION_SORTS, hn as BOARD_USER_ROLES, Gt as COMMENT_BODY_MAX_LENGTH, qe as DEFAULT_BLOCK_BAN_DECAY_MS, Ke as DEFAULT_BLOCK_BAN_THRESHOLD, Ct as DEFAULT_BOARDS, wt as DEFAULT_CATEGORIES, C as DEFAULT_COMMENTS_COLLECTION, E as DEFAULT_LIKES_COLLECTION, f as DEFAULT_POSTS_COLLECTION, b as DEFAULT_REPORTS_COLLECTION, D as DEFAULT_SETTINGS_COLLECTION, p as DEFAULT_USERS_COLLECTION, Qt as REPORT_DETAIL_MAX_LENGTH, $t as REPORT_REASONS, nr as WRITING_ASSISTANT_DAILY_LIMIT, Ee as asHttpUrl, Me as boardListOgDescription, je as boardListOgTitle, Ae as boardPostOgDescription, ke as boardPostOgTitle, w as boardSsrKey, x as boardUserDoc, h as boardUsersCol, St as buildPostPreview, Ve as canManageBoardByRole, He as canWriteCommentByRole, Sn as clampSectionCount, l as commentDoc, O as commentsCol, T as configureMemiBoard, xn as defaultSectionCount, Je as effectiveModerationBlockCount, nt as extractEditorImageUrls, Re as fetchPublicListForSeo, Le as fetchPublicPostForSeo, Qn as formatDate, er as formatFullDate, $n as formatRelativeDate, Ze as formatRestrictedUntilLabel, tr as formatTimestampDetails, _t as hasBodyImage, gt as hasBodyText, Be as isAssignedStaff, vt as isContentEmpty, Ot as isFirestorePermissionDenied, Xe as isModerationWriteRestricted, j as likeDoc, d as likeDocId, A as likesCol, Xt as memiBoardCommentLikesKey, Nn as miniBoardView, On as miniCommentLink, Dn as miniMoreLink, kn as miniPostImage, En as miniPostLink, An as miniPostTitle, Pn as miniPostsView, jn as miniViewGroup, Mn as miniViewLabel, Ye as moderationWriteRestrictedUntilMs, Ne as normalizeBasePath, Hn as normalizeBoardSection, Cn as pairSectionCols, mt as plainTextFromHtml, s as postBodyDoc, t as postDoc, it as postNamespaceFromStoragePath, k as postStorageFolder, c as postsCol, fr as renderMarkdownToHtml, r as reportDoc, n as reportDocId, en as reportReasonLabel, o as reportsCol, y as resolveBoardPathConfig, Pe as resolvePublicSeoDb, wn as sectionColClass, Tn as sectionMinHeight, e as settingsCol, v as settingsDoc, S as slugify, rt as storagePathFromDownloadUrl, ht as titleFromBody, Oe as toAbsoluteUrl, De as toBoardOgImageUrl, _ as useBoardPathConfig, tt as useMemiBoardAuth, Ht as useMemiBoardAuthorMemo, zt as useMemiBoardCommentFeed, Zt as useMemiBoardCommentLikes, qt as useMemiBoardComments, u as useMemiBoardConfig, Yt as useMemiBoardLikes, Wn as useMemiBoardMiniLatest, Gn as useMemiBoardMiniPicked, mn as useMemiBoardModeration, Nt as useMemiBoardPost, Mt as useMemiBoardPostList, At as useMemiBoardPosts, Jt as useMemiBoardReplies, rn as useMemiBoardReportQueue, tn as useMemiBoardReports, Un as useMemiBoardSections, Dt as useMemiBoardSettings, Lt as useMemiBoardUserComments, Ft as useMemiBoardUserPosts, _n as useMemiBoardUserProfile, gn as useMemiBoardUsers, an as useMemiBoardViews, lr as useMemiBoardWritingAssistant, Kn as versionHistory, xt as videoListCoverUrl, bt 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 };
3136
3174
 
3137
3175
  //# sourceMappingURL=index.js.map