memi-board 0.52.4 → 0.53.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.
Files changed (49) hide show
  1. package/README.md +4 -6
  2. package/dist/{ar-3hd6xh6U.js → ar-DBv_xFzj.js} +3 -2
  3. package/dist/ar-DBv_xFzj.js.map +1 -0
  4. package/dist/{commentImages-4IOk2u0O.js → commentImages-t4lu_hxD.js} +130 -99
  5. package/dist/commentImages-t4lu_hxD.js.map +1 -0
  6. package/dist/composables/useMemiBoardModeration.d.ts +1 -3
  7. package/dist/composables/useMemiBoardPosts.d.ts +6 -0
  8. package/dist/{de-DXtmk-4H.js → de-DiqhMTJO.js} +3 -2
  9. package/dist/de-DiqhMTJO.js.map +1 -0
  10. package/dist/{en-CyZH4Ct1.js → en-hMF_prdm.js} +33 -3
  11. package/dist/en-hMF_prdm.js.map +1 -0
  12. package/dist/{es-BtRbHicT.js → es-RfbaViQj.js} +3 -2
  13. package/dist/es-RfbaViQj.js.map +1 -0
  14. package/dist/{fr-vnizG3rD.js → fr-BlRWQtSh.js} +3 -2
  15. package/dist/fr-BlRWQtSh.js.map +1 -0
  16. package/dist/{id-Cf8yw8n_.js → id-C0-e3Gwc.js} +3 -2
  17. package/dist/id-C0-e3Gwc.js.map +1 -0
  18. package/dist/index.d.ts +3 -2
  19. package/dist/index.js +1172 -1059
  20. package/dist/index.js.map +1 -1
  21. package/dist/{ja-D-Nrtjk-.js → ja-q1DilxZV.js} +3 -2
  22. package/dist/ja-q1DilxZV.js.map +1 -0
  23. package/dist/{pt-CSsshr7u.js → pt-sB9letRc.js} +3 -2
  24. package/dist/pt-sB9letRc.js.map +1 -0
  25. package/dist/runtime/components/Attachments.vue +82 -22
  26. package/dist/runtime/components/CategorySettings.vue +4 -0
  27. package/dist/runtime/components/CustomFieldEditor.vue +86 -0
  28. package/dist/runtime/components/Detail.vue +15 -1
  29. package/dist/runtime/components/Editor.vue +49 -12
  30. package/dist/runtime/components/Settings.vue +190 -13
  31. package/dist/storage.js +36 -36
  32. package/dist/types.d.ts +23 -1
  33. package/dist/utils/customFields.d.ts +33 -0
  34. package/dist/utils/slugify.d.ts +2 -0
  35. package/dist/{zh-BzrsqVN2.js → zh-Dag8WCjt.js} +3 -2
  36. package/dist/zh-Dag8WCjt.js.map +1 -0
  37. package/docs/firebase-setup.md +64 -0
  38. package/docs/host-integration.md +4 -0
  39. package/package.json +1 -1
  40. package/dist/ar-3hd6xh6U.js.map +0 -1
  41. package/dist/commentImages-4IOk2u0O.js.map +0 -1
  42. package/dist/de-DXtmk-4H.js.map +0 -1
  43. package/dist/en-CyZH4Ct1.js.map +0 -1
  44. package/dist/es-BtRbHicT.js.map +0 -1
  45. package/dist/fr-vnizG3rD.js.map +0 -1
  46. package/dist/id-Cf8yw8n_.js.map +0 -1
  47. package/dist/ja-D-Nrtjk-.js.map +0 -1
  48. package/dist/pt-CSsshr7u.js.map +0 -1
  49. package/dist/zh-BzrsqVN2.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
- import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as m, P as h, R as g, S as _, T as v, U as y, V as b, W as x, X as S, Y as C, Z as w, _ as T, a as E, b as D, c as ee, d as O, f as k, g as A, h as j, j as te, k as ne, l as re, m as M, o as ie, p as ae, q as oe, r as se, s as N, t as ce, u as le, v as ue, w as P, x as de, y as F, z as fe } from "./commentImages-4IOk2u0O.js";
2
- import { computed as I, onScopeDispose as L, reactive as pe, readonly as me, ref as R, toValue as z, watch as B } from "vue";
3
- import { collection as he, deleteDoc as ge, deleteField as _e, doc as ve, documentId as V, endAt as ye, endBefore as be, getDoc as xe, getDocFromServer as Se, getDocs as H, getDocsFromServer as Ce, increment as we, limit as U, limitToLast as Te, onSnapshot as W, orderBy as G, query as K, runTransaction as Ee, serverTimestamp as q, setDoc as De, startAfter as J, updateDoc as Y, where as X, writeBatch as Oe } from "firebase/firestore";
4
- import { useCollection as ke, useCurrentUser as Ae, useDocument as je, useFirebaseApp as Me, useFirebaseAuth as Ne, useFirestore as Z } from "vuefire";
1
+ import { A as e, B as t, C as n, D as r, E as i, F as a, G as o, H as s, I as c, J as l, K as u, L as d, M as f, N as p, O as m, P as h, Q as g, R as _, S as v, T as y, U as b, V as x, W as S, X as C, Y as w, Z as T, _ as E, b as D, c as O, d as k, f as A, g as ee, h as j, i as M, j as te, k as ne, l as re, m as ie, o as ae, p as N, q as oe, r as se, s as ce, t as le, u as ue, v as P, w as de, x as F, y as fe, z as pe } from "./commentImages-t4lu_hxD.js";
2
+ import { computed as I, onScopeDispose as L, reactive as me, readonly as he, ref as R, toValue as z, watch as B } from "vue";
3
+ import { collection as ge, deleteDoc as _e, deleteField as V, doc as ve, documentId as H, endAt as ye, endBefore as be, getDoc as xe, getDocFromServer as Se, getDocs as U, getDocsFromServer as Ce, increment as we, limit as W, limitToLast as Te, onSnapshot as G, orderBy as K, query as q, runTransaction as Ee, serverTimestamp as J, setDoc as De, startAfter as Y, updateDoc as X, where as Z, writeBatch as Oe } from "firebase/firestore";
4
+ import { useCollection as ke, useCurrentUser as Ae, useDocument as je, useFirebaseApp as Me, useFirebaseAuth as Ne, useFirestore as Q } from "vuefire";
5
5
  import { GoogleAuthProvider as Pe, OAuthProvider as Fe, createUserWithEmailAndPassword as Ie, getAuth as Le, signInWithEmailAndPassword as Re, signInWithPopup as ze, signOut as Be, updateProfile as Ve } from "firebase/auth";
6
6
  import { deleteObject as He, getMetadata as Ue, getStorage as We, list as Ge, listAll as Ke, ref as qe } from "firebase/storage";
7
7
  import { GoogleAIBackend as Je, Schema as Ye, getAI as Xe, getGenerativeModel as Ze } from "firebase/ai";
8
8
  //#region src/utils/boardSeo.ts
9
9
  function Qe(e, t) {
10
- return !e || e === "전체" || e === M(t, "seo.allCategory");
10
+ return !e || e === "전체" || e === j(t, "seo.allCategory");
11
11
  }
12
12
  function $e(e) {
13
13
  if (typeof e != "string") return null;
@@ -37,23 +37,23 @@ function tt(e, t, n = "") {
37
37
  return i ? /^https?:\/\//i.test(i) ? i : `${r}${i.startsWith("/") ? i : `/${i}`}` : n ? tt(n, t) : r;
38
38
  }
39
39
  function nt(e, t, n, r, i) {
40
- let a = r?.trim().slice(0, 40), o = e.trim() || a || M(i, "seo.photo"), s = t?.trim(), c = n.trim() || "Board";
40
+ let a = r?.trim().slice(0, 40), o = e.trim() || a || j(i, "seo.photo"), s = t?.trim(), c = n.trim() || "Board";
41
41
  return s ? `${o} · ${s} | ${c}` : `${o} | ${c}`;
42
42
  }
43
43
  function rt(e, t) {
44
44
  let n = [];
45
- return e.summary?.trim() ? n.push(e.summary.trim().slice(0, 140)) : n.push(M(t, "seo.postDescriptionFallback")), e.categoryLabel?.trim() && n.push(e.categoryLabel.trim()), e.authorName?.trim() && n.push(e.authorName.trim()), n.join(" · ").slice(0, 200);
45
+ return e.summary?.trim() ? n.push(e.summary.trim().slice(0, 140)) : n.push(j(t, "seo.postDescriptionFallback")), e.categoryLabel?.trim() && n.push(e.categoryLabel.trim()), e.authorName?.trim() && n.push(e.authorName.trim()), n.join(" · ").slice(0, 200);
46
46
  }
47
47
  function it(e, t, n) {
48
48
  let r = t.trim() || "Board", i = e?.trim();
49
- return Qe(i, n) ? M(n, "seo.listTitleAll", { site: r }) : M(n, "seo.listTitle", {
49
+ return Qe(i, n) ? j(n, "seo.listTitleAll", { site: r }) : j(n, "seo.listTitle", {
50
50
  name: i,
51
51
  site: r
52
52
  });
53
53
  }
54
54
  function at(e, t) {
55
55
  if (e.description?.trim()) return e.description.trim().slice(0, 200);
56
- let n = e.categoryLabel?.trim(), r = Qe(n, t) ? M(t, "seo.listDescriptionAll") : M(t, "seo.listDescription", { name: n }), i = (e.recentTitles || []).filter(Boolean).slice(0, 3);
56
+ let n = e.categoryLabel?.trim(), r = Qe(n, t) ? j(t, "seo.listDescriptionAll") : j(t, "seo.listDescription", { name: n }), i = (e.recentTitles || []).filter(Boolean).slice(0, 3);
57
57
  return i.length ? `${r} ${i.map((e) => `「${e}」`).join(" ")}`.slice(0, 200) : r.slice(0, 200);
58
58
  }
59
59
  function ot(e) {
@@ -78,11 +78,11 @@ function lt(e, t) {
78
78
  let n = e?.[t];
79
79
  return typeof n == "string" ? n.trim() : "";
80
80
  }
81
- function Q(e) {
81
+ function $(e) {
82
82
  if (!e || typeof e != "object") return;
83
83
  let t = {};
84
84
  for (let [n, r] of Object.entries(e)) {
85
- let e = F(n);
85
+ let e = D(n);
86
86
  if (!e || !r || typeof r != "object") continue;
87
87
  let i = {};
88
88
  for (let [e, t] of Object.entries(r)) typeof t == "string" && t.trim() && (i[e] = t.trim());
@@ -92,19 +92,19 @@ function Q(e) {
92
92
  }
93
93
  function ut(e) {
94
94
  if (!e || typeof e != "object") return;
95
- let t = e, n = {}, r = F(t.locale);
95
+ let t = e, n = {}, r = D(t.locale);
96
96
  r && (n.locale = r);
97
97
  for (let e of st) typeof t[e] == "string" && (n[e] = t[e]);
98
98
  return Object.keys(n).length ? n : void 0;
99
99
  }
100
100
  function dt(e) {
101
101
  if (!e || typeof e != "object") return;
102
- let t = e, n = {}, r = F(t.locale);
102
+ let t = e, n = {}, r = D(t.locale);
103
103
  return r && (n.locale = r), typeof t.hash == "string" && t.hash && (n.hash = t.hash), n.locale || n.hash ? n : void 0;
104
104
  }
105
105
  function ft(e, t, n) {
106
106
  let r = {};
107
- if (n) for (let e of T) {
107
+ if (n) for (let e of P) {
108
108
  let t = n[e.code];
109
109
  if (!t) continue;
110
110
  let i = {};
@@ -122,28 +122,28 @@ function ft(e, t, n) {
122
122
  }), r;
123
123
  }
124
124
  function pt(e) {
125
- let t = new Set((e?.translationLocales ?? []).map((e) => F(e)).filter((e) => !!e)), n = T.map((e) => e.code);
125
+ let t = new Set((e?.translationLocales ?? []).map((e) => D(e)).filter((e) => !!e)), n = P.map((e) => e.code);
126
126
  return t.size ? n.filter((e) => t.has(e)) : n;
127
127
  }
128
128
  function mt(e) {
129
129
  if (!Array.isArray(e)) return [];
130
130
  let t = pt({ translationLocales: e.filter((e) => typeof e == "string") });
131
- return t.length === T.length ? [] : t;
131
+ return t.length === P.length ? [] : t;
132
132
  }
133
- function ht(e, t, n = T.map((e) => e.code)) {
133
+ function ht(e, t, n = P.map((e) => e.code)) {
134
134
  return !e || !t.length ? !1 : n.every((n) => t.every((t) => !!lt(e[n], t)));
135
135
  }
136
- function gt(e, t, r, i, a) {
137
- if (!n()) return i;
138
- let o = F(t), s = F(a);
139
- if (!o || s && o === s) return i;
140
- let c = lt(e?.[o], r);
141
- if (c) return c;
142
- if (o !== "en" && s !== "en") {
143
- let t = lt(e?.en, r);
136
+ function gt(e, t, n, r, i) {
137
+ if (!de()) return r;
138
+ let a = D(t), o = D(i);
139
+ if (!a || o && a === o) return r;
140
+ let s = lt(e?.[a], n);
141
+ if (s) return s;
142
+ if (a !== "en" && o !== "en") {
143
+ let t = lt(e?.en, n);
144
144
  if (t) return t;
145
145
  }
146
- return i;
146
+ return r;
147
147
  }
148
148
  function _t(e, t, n, r, i) {
149
149
  return r ? !t || t[n] !== r ? r : gt(e, i, n, r, t.locale) : "";
@@ -169,19 +169,19 @@ function St(e, t) {
169
169
  //#region src/composables/fetchPublicSeo.ts
170
170
  function Ct() {
171
171
  return {
172
- db: Z(),
173
- paths: P()
172
+ db: Q(),
173
+ paths: y()
174
174
  };
175
175
  }
176
176
  async function wt(e, t, n) {
177
177
  try {
178
- let r = await xe(w(e.db, e.paths, t));
178
+ let r = await xe(g(e.db, e.paths, t));
179
179
  if (!r.exists()) return {
180
180
  label: t,
181
181
  description: "",
182
182
  hidden: !1
183
183
  };
184
- let i = r.data() ?? {}, a = typeof i.label == "string" && i.label.trim() ? i.label.trim() : t, o = typeof i.description == "string" ? i.description.trim() : "", s = Q(i.i18n), c = ut(i.i18nSource);
184
+ let i = r.data() ?? {}, a = typeof i.label == "string" && i.label.trim() ? i.label.trim() : t, o = typeof i.description == "string" ? i.description.trim() : "", s = $(i.i18n), c = ut(i.i18nSource);
185
185
  return {
186
186
  label: _t(s, c, "label", a, n) || a,
187
187
  description: _t(s, c, "description", o, n),
@@ -207,27 +207,27 @@ function Tt(e) {
207
207
  async function Et(e, t, n, r) {
208
208
  let i = e.trim(), a = t.trim();
209
209
  if (!i || !a) return null;
210
- let s = n ?? Ct();
211
- s.paths = C(s.paths), r && await ae(r);
212
- let c = await wt(s, i, r);
213
- if (c.hidden) return null;
210
+ let o = n ?? Ct();
211
+ o.paths = C(o.paths), r && await ie(r);
212
+ let s = await wt(o, i, r);
213
+ if (s.hidden) return null;
214
214
  try {
215
- let e = (await H(K(o(s.db, s.paths), X("boardId", "==", i), X("slug", "==", a), X("listed", "==", !0), X("isPublished", "==", !0), U(1)))).docs[0];
215
+ let e = (await U(q(u(o.db, o.paths), Z("boardId", "==", i), Z("slug", "==", a), Z("listed", "==", !0), Z("isPublished", "==", !0), W(1)))).docs[0];
216
216
  if (!e) return null;
217
- let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title : "", l = typeof t.summary == "string" ? t.summary : "", u = Q(t.i18n), d = ut(t.i18nSource), f = vt({
217
+ let t = e.data() ?? {}, n = typeof t.title == "string" ? t.title : "", c = typeof t.summary == "string" ? t.summary : "", l = $(t.i18n), d = ut(t.i18nSource), f = vt({
218
218
  title: n,
219
- i18n: u,
219
+ i18n: l,
220
220
  i18nSource: d
221
221
  }, r).trim();
222
222
  return f ? {
223
223
  id: e.id,
224
224
  slug: typeof t.slug == "string" ? t.slug : a,
225
225
  category: i,
226
- categoryLabel: c.label,
226
+ categoryLabel: s.label,
227
227
  title: f,
228
228
  summary: yt({
229
- summary: l,
230
- i18n: u,
229
+ summary: c,
230
+ i18n: l,
231
231
  i18nSource: d
232
232
  }, r).trim().slice(0, 200),
233
233
  previewImage: et(t.previewImage),
@@ -239,7 +239,7 @@ async function Et(e, t, n, r) {
239
239
  }
240
240
  }
241
241
  async function Dt(e, t, n) {
242
- n && await ae(n);
242
+ n && await ie(n);
243
243
  let r = e?.trim() || null, i = t ?? Ct();
244
244
  if (i.paths = C(i.paths), r) {
245
245
  let e = await wt(i, r, n);
@@ -256,7 +256,7 @@ async function Dt(e, t, n) {
256
256
  kind: "category",
257
257
  category: r,
258
258
  categoryLabel: e.label,
259
- description: e.description || M(n, "seo.boardDescription", { name: e.label }),
259
+ description: e.description || j(n, "seo.boardDescription", { name: e.label }),
260
260
  ogImage: a,
261
261
  recentTitles: t
262
262
  };
@@ -264,8 +264,8 @@ async function Dt(e, t, n) {
264
264
  return {
265
265
  kind: "all",
266
266
  category: null,
267
- categoryLabel: M(n, "seo.allCategory"),
268
- description: M(n, "seo.allDescription"),
267
+ categoryLabel: j(n, "seo.allCategory"),
268
+ description: j(n, "seo.allDescription"),
269
269
  ogImage: null,
270
270
  recentTitles: []
271
271
  };
@@ -273,11 +273,11 @@ async function Dt(e, t, n) {
273
273
  async function Ot(e, t, n) {
274
274
  let r = [], i = null;
275
275
  try {
276
- let a = await H(K(o(e.db, e.paths), X("boardId", "==", t), X("listed", "==", !0), X("isPublished", "==", !0), G("createdAt", "desc"), U(12)));
276
+ let a = await U(q(u(e.db, e.paths), Z("boardId", "==", t), Z("listed", "==", !0), Z("isPublished", "==", !0), K("createdAt", "desc"), W(12)));
277
277
  for (let e of a.docs) {
278
278
  let t = e.data() ?? {}, a = vt({
279
279
  title: typeof t.title == "string" ? t.title : "",
280
- i18n: Q(t.i18n),
280
+ i18n: $(t.i18n),
281
281
  i18nSource: ut(t.i18nSource)
282
282
  }, n).trim();
283
283
  a && r.length < 5 && r.push(a), i ||= et(t.previewImage);
@@ -337,10 +337,10 @@ function zt(e, t, n = Date.now(), r = 10, i = It) {
337
337
  }
338
338
  function Bt(e, t = Date.now(), n) {
339
339
  let r = Math.max(0, e - t), i = Math.ceil(r / 36e5);
340
- if (i <= 0) return M(n, "moderationStrike.liftSoon");
341
- if (i < 24) return M(n, "moderationStrike.liftInHours", { hours: i });
340
+ if (i <= 0) return j(n, "moderationStrike.liftSoon");
341
+ if (i < 24) return j(n, "moderationStrike.liftInHours", { hours: i });
342
342
  let a = Math.floor(i / 24), o = i % 24;
343
- return o === 0 ? M(n, "moderationStrike.liftInDays", { days: a }) : M(n, "moderationStrike.liftInDaysHours", {
343
+ return o === 0 ? j(n, "moderationStrike.liftInDays", { days: a }) : j(n, "moderationStrike.liftInDaysHours", {
344
344
  days: a,
345
345
  hours: o
346
346
  });
@@ -369,191 +369,191 @@ function Ut() {
369
369
  }), e[Ht];
370
370
  }
371
371
  function Wt() {
372
- let e = v(), { t, locale: n } = N(), r = Ut(), i = Z(), o = Ne(), s = Ae(), { role: c, rolePending: l, rawBlockCount: u, blockAtMs: d } = r;
373
- function f() {
372
+ let e = i(), { t, locale: n } = O(), r = Ut(), o = Q(), s = Ne(), l = Ae(), { role: u, rolePending: d, rawBlockCount: f, blockAtMs: p } = r;
373
+ function m() {
374
374
  let t = e.moderation?.blockBanThreshold;
375
375
  return t === 0 ? 0 : typeof t == "number" && t > 0 ? Math.floor(t) : 10;
376
376
  }
377
- function p() {
377
+ function h() {
378
378
  let t = e.moderation?.blockBanDecayMs;
379
379
  return typeof t == "number" && t > 0 ? t : It;
380
380
  }
381
- function m(e) {
382
- return h(i, P(), e);
383
- }
384
381
  function g(e) {
385
- if (c.value = [
382
+ return a(o, y(), e);
383
+ }
384
+ function _(e) {
385
+ if (u.value = [
386
386
  "owner",
387
387
  "admin",
388
388
  "manager",
389
389
  "staff",
390
390
  "user"
391
391
  ].includes(String(e?.role)) ? e?.role : "user", !e) {
392
- u.value = 0, d.value = null;
392
+ f.value = 0, p.value = null;
393
393
  return;
394
394
  }
395
- u.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), d.value = Vt(e.moderationBlockAt);
395
+ f.value = Math.max(0, Math.floor(Number(e.moderationBlockCount) || 0)), p.value = Vt(e.moderationBlockAt);
396
396
  }
397
- async function _(e) {
398
- let t = m(e.uid), n = a(i, P(), e.uid), r = await xe(t);
397
+ async function v(e) {
398
+ let t = g(e.uid), n = c(o, y(), e.uid), r = await xe(t);
399
399
  if (!r.exists()) return await Promise.all([De(t, {
400
400
  role: "user",
401
401
  displayName: e.displayName,
402
402
  photoURL: e.photoURL,
403
- joinedAt: q(),
404
- lastVisitAt: q(),
405
- updatedAt: q()
406
- }), De(n, { email: e.email })]), g({ moderationBlockCount: 0 }), "user";
407
- let o = r.data();
408
- g(o);
409
- let s = typeof o.displayName == "string" && o.displayName.trim(), c = typeof o.photoURL == "string" && o.photoURL.trim(), l = {
410
- lastVisitAt: q(),
411
- updatedAt: q()
403
+ joinedAt: J(),
404
+ lastVisitAt: J(),
405
+ updatedAt: J()
406
+ }), De(n, { email: e.email })]), _({ moderationBlockCount: 0 }), "user";
407
+ let i = r.data();
408
+ _(i);
409
+ let a = typeof i.displayName == "string" && i.displayName.trim(), s = typeof i.photoURL == "string" && i.photoURL.trim(), l = {
410
+ lastVisitAt: J(),
411
+ updatedAt: J()
412
412
  };
413
- return !s && e.displayName && (l.displayName = e.displayName), !c && e.photoURL && (l.photoURL = e.photoURL), await Promise.all([Y(t, l), De(n, { email: e.email }, { merge: !0 })]), [
413
+ return !a && e.displayName && (l.displayName = e.displayName), !s && e.photoURL && (l.photoURL = e.photoURL), await Promise.all([X(t, l), De(n, { email: e.email }, { merge: !0 })]), [
414
414
  "owner",
415
415
  "admin",
416
416
  "manager",
417
417
  "staff",
418
418
  "user"
419
- ].includes(String(o.role)) ? o.role : "user";
419
+ ].includes(String(i.role)) ? i.role : "user";
420
420
  }
421
- async function y() {
422
- let e = s.value?.uid;
421
+ async function b() {
422
+ let e = l.value?.uid;
423
423
  if (!e) {
424
- g(void 0);
424
+ _(void 0);
425
425
  return;
426
426
  }
427
- let t = await xe(m(e));
428
- g(t.exists() ? t.data() : void 0);
427
+ let t = await xe(g(e));
428
+ _(t.exists() ? t.data() : void 0);
429
429
  }
430
- r.watchStarted || (r.watchStarted = !0, B(s, async (e) => {
431
- if (l.value = !0, !e) {
432
- c.value = "user", g(void 0), l.value = !1;
430
+ r.watchStarted || (r.watchStarted = !0, B(l, async (e) => {
431
+ if (d.value = !0, !e) {
432
+ u.value = "user", _(void 0), d.value = !1;
433
433
  return;
434
434
  }
435
435
  try {
436
- c.value = await _(e);
436
+ u.value = await v(e);
437
437
  } catch (e) {
438
- console.error("[memi-board] ensureUserDoc failed", e), c.value = "user", g(void 0);
438
+ console.error("[memi-board] ensureUserDoc failed", e), u.value = "user", _(void 0);
439
439
  } finally {
440
- l.value = !1;
440
+ d.value = !1;
441
441
  }
442
442
  }, { immediate: !0 }));
443
- let b = I(() => !!s.value), x = I(() => c.value === "owner"), S = I(() => c.value === "manager"), C = I(() => x.value || c.value === "admin"), w = I(() => S.value || c.value === "staff"), T = I(() => C.value || w.value), E = I(() => Lt(u.value, d.value, Date.now(), p())), D = I(() => {
444
- let e = f();
445
- return e <= 0 ? !1 : zt(u.value, d.value, Date.now(), e, p());
446
- }), ee = I(() => {
447
- let e = f();
443
+ let x = I(() => !!l.value), S = I(() => u.value === "owner"), C = I(() => u.value === "manager"), w = I(() => S.value || u.value === "admin"), T = I(() => C.value || u.value === "staff"), E = I(() => w.value || T.value), D = I(() => Lt(f.value, p.value, Date.now(), h())), k = I(() => {
444
+ let e = m();
445
+ return e <= 0 ? !1 : zt(f.value, p.value, Date.now(), e, h());
446
+ }), A = I(() => {
447
+ let e = m();
448
448
  if (e <= 0) return null;
449
- let t = Rt(u.value, d.value, Date.now(), e, p());
449
+ let t = Rt(f.value, p.value, Date.now(), e, h());
450
450
  return t == null ? null : Bt(t, Date.now(), n.value);
451
- }), O = I(() => {
452
- if (!D.value) return null;
453
- let e = ee.value;
451
+ }), ee = I(() => {
452
+ if (!k.value) return null;
453
+ let e = A.value;
454
454
  return e ? t("auth.writeRestrictedUntil", { until: e }) : t("auth.writeRestricted");
455
455
  });
456
- async function k() {
457
- let e = s.value?.uid, r = f();
456
+ async function j() {
457
+ let e = l.value?.uid, r = m();
458
458
  if (!e || r <= 0) return {
459
459
  effectiveCount: 0,
460
460
  restricted: !1,
461
461
  messageSuffix: ""
462
462
  };
463
- let i = m(e), a = await xe(i);
464
- a.exists() ? await Y(i, {
463
+ let i = g(e), a = await xe(i);
464
+ a.exists() ? await X(i, {
465
465
  moderationBlockCount: we(1),
466
- moderationBlockAt: q(),
467
- updatedAt: q()
466
+ moderationBlockAt: J(),
467
+ updatedAt: J()
468
468
  }) : await De(i, {
469
469
  role: "user",
470
- displayName: s.value?.displayName ?? null,
470
+ displayName: l.value?.displayName ?? null,
471
471
  moderationBlockCount: 1,
472
- moderationBlockAt: q(),
473
- updatedAt: q()
472
+ moderationBlockAt: J(),
473
+ updatedAt: J()
474
474
  });
475
- let o = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1, c = Date.now();
476
- u.value = o, d.value = c;
477
- let l = Lt(o, c, c, p()), h = zt(o, c, c, r, p()), g = t("auth.strikeSuffix", {
478
- count: l,
475
+ let o = (a.exists() ? Math.max(0, Math.floor(Number(a.data().moderationBlockCount) || 0)) : 0) + 1, s = Date.now();
476
+ f.value = o, p.value = s;
477
+ let c = Lt(o, s, s, h()), u = zt(o, s, s, r, h()), d = t("auth.strikeSuffix", {
478
+ count: c,
479
479
  threshold: r
480
480
  });
481
- if (h) {
482
- let e = Rt(o, c, c, r, p()), i = e == null ? null : Bt(e, c, n.value);
483
- g = i ? t("auth.strikeRestrictedUntil", {
484
- count: l,
481
+ if (u) {
482
+ let e = Rt(o, s, s, r, h()), i = e == null ? null : Bt(e, s, n.value);
483
+ d = i ? t("auth.strikeRestrictedUntil", {
484
+ count: c,
485
485
  until: i
486
- }) : t("auth.strikeRestricted", { count: l });
486
+ }) : t("auth.strikeRestricted", { count: c });
487
487
  }
488
488
  return {
489
- effectiveCount: l,
490
- restricted: h,
491
- messageSuffix: g
489
+ effectiveCount: c,
490
+ restricted: u,
491
+ messageSuffix: d
492
492
  };
493
493
  }
494
- function A() {
495
- if (!o) throw Error(t("auth.notInitialized"));
496
- return o;
497
- }
498
- async function j() {
499
- return ze(A(), new Pe());
494
+ function M() {
495
+ if (!s) throw Error(t("auth.notInitialized"));
496
+ return s;
500
497
  }
501
498
  async function te() {
499
+ return ze(M(), new Pe());
500
+ }
501
+ async function ne() {
502
502
  let e = new Fe("apple.com");
503
- return e.addScope("email"), e.addScope("name"), ze(A(), e);
503
+ return e.addScope("email"), e.addScope("name"), ze(M(), e);
504
504
  }
505
- async function ne(e, t) {
506
- return Re(A(), e, t);
505
+ async function re(e, t) {
506
+ return Re(M(), e, t);
507
507
  }
508
- async function re(e, t, n) {
509
- let r = await Ie(A(), e, t);
508
+ async function ie(e, t, n) {
509
+ let r = await Ie(M(), e, t);
510
510
  return n && await Ve(r.user, { displayName: n }), r;
511
511
  }
512
- async function M() {
513
- await Be(A());
512
+ async function ae() {
513
+ await Be(M());
514
514
  }
515
- function ie(e) {
516
- return At(s.value?.uid, C.value, w.value, e ? Pt(e) : void 0);
517
- }
518
- function ae(e) {
519
- return s.value ? C.value ? !0 : S.value && !!e && (Pt(e)?.allowedManagerUids ?? []).includes(s.value.uid) : !1;
515
+ function N(e) {
516
+ return At(l.value?.uid, w.value, T.value, e ? Pt(e) : void 0);
520
517
  }
521
518
  function oe(e) {
522
- return b.value && (s.value?.uid === e.authorUid || ie(e.boardId));
519
+ return l.value ? w.value ? !0 : C.value && !!e && (Pt(e)?.allowedManagerUids ?? []).includes(l.value.uid) : !1;
523
520
  }
524
521
  function se(e) {
525
- return b.value && s.value?.uid === e.authorUid;
522
+ return x.value && (l.value?.uid === e.authorUid || N(e.boardId));
526
523
  }
527
524
  function ce(e) {
528
- return b.value && (s.value?.uid === e.authorUid || ie(e.boardId));
525
+ return x.value && l.value?.uid === e.authorUid;
526
+ }
527
+ function le(e) {
528
+ return x.value && (l.value?.uid === e.authorUid || N(e.boardId));
529
529
  }
530
530
  return {
531
- user: s,
532
- role: c,
533
- isOwner: x,
534
- isManager: S,
535
- canConfigureBoard: ae,
536
- isSignedIn: b,
537
- isAdmin: C,
538
- isStaff: w,
539
- canManageContent: T,
540
- canManageBoard: ie,
541
- rolePending: l,
542
- moderationBlockCount: E,
543
- isWriteRestricted: D,
544
- restrictedUntilLabel: ee,
545
- restrictedMessage: O,
546
- signInWithGoogle: j,
547
- signInWithApple: te,
548
- signInWithEmail: ne,
549
- signUpWithEmail: re,
550
- signOut: M,
551
- canEdit: oe,
552
- canDelete: oe,
553
- canEditComment: se,
554
- canDeleteComment: ce,
555
- recordContentModerationBlock: k,
556
- refreshBoardUser: y
531
+ user: l,
532
+ role: u,
533
+ isOwner: S,
534
+ isManager: C,
535
+ canConfigureBoard: oe,
536
+ isSignedIn: x,
537
+ isAdmin: w,
538
+ isStaff: T,
539
+ canManageContent: E,
540
+ canManageBoard: N,
541
+ rolePending: d,
542
+ moderationBlockCount: D,
543
+ isWriteRestricted: k,
544
+ restrictedUntilLabel: A,
545
+ restrictedMessage: ee,
546
+ signInWithGoogle: te,
547
+ signInWithApple: ne,
548
+ signInWithEmail: re,
549
+ signUpWithEmail: ie,
550
+ signOut: ae,
551
+ canEdit: se,
552
+ canDelete: se,
553
+ canEditComment: ce,
554
+ canDeleteComment: le,
555
+ recordContentModerationBlock: j,
556
+ refreshBoardUser: b
557
557
  };
558
558
  }
559
559
  //#endregion
@@ -580,8 +580,8 @@ function Jt(e) {
580
580
  //#endregion
581
581
  //#region src/utils/findReadablePost.ts
582
582
  async function Yt(e, t, n, r, i, a) {
583
- let s = [X("boardId", "==", n), X("slug", "==", r)];
584
- return a ? (await H(K(o(e, t), ...s, U(1)))).docs[0] : (await Promise.all([H(K(o(e, t), ...s, X("listed", "==", !0), X("isPublished", "==", !0), U(1))), ...i ? [H(K(o(e, t), ...s, X("authorUid", "==", i), U(1)))] : []])).flatMap((e) => e.docs)[0];
583
+ let o = [Z("boardId", "==", n), Z("slug", "==", r)];
584
+ return a ? (await U(q(u(e, t), ...o, W(1)))).docs[0] : (await Promise.all([U(q(u(e, t), ...o, Z("listed", "==", !0), Z("isPublished", "==", !0), W(1))), ...i ? [U(q(u(e, t), ...o, Z("authorUid", "==", i), W(1)))] : []])).flatMap((e) => e.docs)[0];
585
585
  }
586
586
  //#endregion
587
587
  //#region src/utils/extractEditorImageUrls.ts
@@ -620,29 +620,29 @@ async function en(e, t) {
620
620
  }
621
621
  var tn = 450;
622
622
  async function nn(e, t, n) {
623
- return (await H(K(g(e, t), X("postId", "==", n)))).docs.flatMap((e) => ce(e.data().images, `${x(t, n)}/comment-images/`));
623
+ return (await U(q(pe(e, t), Z("postId", "==", n)))).docs.flatMap((e) => le(e.data().images, `${o(t, n)}/comment-images/`));
624
624
  }
625
625
  async function rn(e, t) {
626
626
  let n = [...new Set([...t].filter(Boolean))];
627
627
  await Promise.all(n.map((t) => He(qe(e, t)).catch(() => {})));
628
628
  }
629
629
  async function an(e, t) {
630
- let n = await H(t);
630
+ let n = await U(t);
631
631
  for (let t = 0; t < n.docs.length; t += tn) {
632
632
  let r = Oe(e);
633
633
  n.docs.slice(t, t + tn).forEach((e) => r.delete(e.ref)), await r.commit();
634
634
  }
635
635
  }
636
636
  async function on(e, t, n) {
637
- await an(e, K(b(e, t), X("postId", "==", n)));
637
+ await an(e, q(s(e, t), Z("postId", "==", n)));
638
638
  }
639
639
  async function sn(e, t, n) {
640
- await an(e, K(b(e, t), X("commentId", "==", n), X("target", "==", "comment")));
640
+ await an(e, q(s(e, t), Z("commentId", "==", n), Z("target", "==", "comment")));
641
641
  }
642
642
  async function cn(e, t, n, r) {
643
- let i = y(e, n, r), a = s(e, n, r), [o, c] = await Promise.all([xe(i), xe(a)]);
644
- if (!o.exists()) return;
645
- let l = o.data(), u = c.exists() ? String(c.data().content ?? "") : "", d = await nn(e, n, r), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
643
+ let i = S(e, n, r), a = b(e, n, r), [s, c] = await Promise.all([xe(i), xe(a)]);
644
+ if (!s.exists()) return;
645
+ let l = s.data(), u = c.exists() ? String(c.data().content ?? "") : "", d = await nn(e, n, r), f = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Set();
646
646
  for (let e of l.attachments ?? []) {
647
647
  if (!e?.path) continue;
648
648
  f.add(e.path);
@@ -660,9 +660,9 @@ async function cn(e, t, n, r) {
660
660
  let a = Qt(t);
661
661
  a && a !== r && p.add(a);
662
662
  }
663
- await en(t, x(n, r));
664
- for (let e of p) await en(t, x(n, e));
665
- await rn(t, d), await rn(t, f), await an(e, K(g(e, n), X("postId", "==", r))), await on(e, n, r), await ge(a), await ge(i);
663
+ await en(t, o(n, r));
664
+ for (let e of p) await en(t, o(n, e));
665
+ await rn(t, d), await rn(t, f), await an(e, q(pe(e, n), Z("postId", "==", r))), await on(e, n, r), await _e(a), await _e(i);
666
666
  }
667
667
  //#endregion
668
668
  //#region src/utils/postBody.ts
@@ -712,45 +712,129 @@ function _n(e, t = []) {
712
712
  };
713
713
  }
714
714
  //#endregion
715
+ //#region src/utils/customFields.ts
716
+ var vn = 8, yn = 40, bn = 80, xn = 200, Sn = /^[a-z][A-Za-z0-9_]{0,31}$/;
717
+ function Cn(e) {
718
+ return typeof e == "string" ? e.trim() : "";
719
+ }
720
+ function wn(e) {
721
+ return (typeof e == "string" ? e.trim() : "").slice(0, 40);
722
+ }
723
+ function Tn(e) {
724
+ return (typeof e == "string" ? e.trim() : "").slice(0, 80);
725
+ }
726
+ function En(e, t, n) {
727
+ return n ? {
728
+ key: e,
729
+ label: t,
730
+ placeholder: n
731
+ } : {
732
+ key: e,
733
+ label: t
734
+ };
735
+ }
736
+ function Dn(e) {
737
+ if (!Array.isArray(e)) return [];
738
+ let t = /* @__PURE__ */ new Set(), n = [];
739
+ for (let r of e) {
740
+ if (!r || typeof r != "object") continue;
741
+ let e = r, i = Cn(e.key), a = wn(e.label);
742
+ if (Sn.test(i) && a && !t.has(i) && (t.add(i), n.push(En(i, a, Tn(e.placeholder))), n.length >= 8)) break;
743
+ }
744
+ return n;
745
+ }
746
+ function On(e) {
747
+ let t = (e ?? []).filter((e) => Cn(e?.key) || wn(e?.label) || Tn(e?.placeholder));
748
+ if (t.length > 8) return {
749
+ fields: [],
750
+ issue: { code: "tooMany" }
751
+ };
752
+ let n = /* @__PURE__ */ new Set(), r = [];
753
+ for (let e of t) {
754
+ let t = Cn(e.key), i = wn(e.label), a = Tn(e.placeholder);
755
+ if (!Sn.test(t)) return {
756
+ fields: [],
757
+ issue: { code: "invalidKey" }
758
+ };
759
+ if (n.has(t)) return {
760
+ fields: [],
761
+ issue: {
762
+ code: "duplicateKey",
763
+ key: t
764
+ }
765
+ };
766
+ if (!i) return {
767
+ fields: [],
768
+ issue: {
769
+ code: "labelRequired",
770
+ key: t
771
+ }
772
+ };
773
+ n.add(t), r.push(En(t, i, a));
774
+ }
775
+ return {
776
+ fields: r,
777
+ issue: null
778
+ };
779
+ }
780
+ function kn(e) {
781
+ if (!e || typeof e != "object" || Array.isArray(e)) return {};
782
+ let t = {};
783
+ for (let [n, r] of Object.entries(e)) {
784
+ if (!Sn.test(n) || typeof r != "string") continue;
785
+ let e = r.trim().slice(0, 200);
786
+ e && (t[n] = e);
787
+ }
788
+ return t;
789
+ }
790
+ function An(e, t) {
791
+ let n = {};
792
+ for (let r of t) {
793
+ let t = (e[r.key] ?? "").trim().slice(0, 200);
794
+ t && (n[r.key] = t);
795
+ }
796
+ return n;
797
+ }
798
+ //#endregion
715
799
  //#region src/utils/saveBoardVisibility.ts
716
- function vn(e) {
800
+ function jn(e) {
717
801
  return e === "hidden" ? "hidden" : "public";
718
802
  }
719
- async function yn(e, t, n, r) {
803
+ async function Mn(e, t, n, r) {
720
804
  let i;
721
805
  for (;;) {
722
- let a = await H(K(t, X("boardId", "==", n), G("__name__"), ...i ? [J(i)] : [], U(400)));
806
+ let a = await U(q(t, Z("boardId", "==", n), K("__name__"), ...i ? [Y(i)] : [], W(400)));
723
807
  if (a.empty) break;
724
808
  let o = Oe(e), s = 0;
725
809
  for (let e of a.docs) e.data().listed !== r && (o.update(e.ref, { listed: r }), s++);
726
810
  if (s && await o.commit(), i = a.docs[a.docs.length - 1], a.docs.length < 400) break;
727
811
  }
728
812
  }
729
- async function bn(e, t, n, r) {
730
- await yn(e, o(e, t), n, r), await yn(e, g(e, t), n, r);
813
+ async function Nn(e, t, n, r) {
814
+ await Mn(e, u(e, t), n, r), await Mn(e, pe(e, t), n, r);
731
815
  }
732
- async function xn(e, t, n, r) {
733
- let i = w(e, t, n), a = vn(r.visibility);
816
+ async function Pn(e, t, n, r) {
817
+ let i = g(e, t, n), a = jn(r.visibility);
734
818
  await Ee(e, async (e) => {
735
819
  let t = await e.get(i), n = t.data(), o = n?.visibilityTransition || "";
736
820
  if (o && o !== a) throw Error("Finish the pending visibility change before changing it again.");
737
- return !t.exists() || !o && vn(n?.visibility) === a ? (e.set(i, r, { merge: !0 }), !1) : (e.set(i, {
821
+ return !t.exists() || !o && jn(n?.visibility) === a ? (e.set(i, r, { merge: !0 }), !1) : (e.set(i, {
738
822
  ...r,
739
- visibility: a === "public" ? "public" : vn(n?.visibility),
823
+ visibility: a === "public" ? "public" : jn(n?.visibility),
740
824
  visibilityTransition: a
741
825
  }, { merge: !0 }), !0);
742
- }) && (await bn(e, t, n, a !== "hidden"), await Ee(e, async (e) => {
826
+ }) && (await Nn(e, t, n, a !== "hidden"), await Ee(e, async (e) => {
743
827
  if ((await e.get(i)).data()?.visibilityTransition !== a) throw Error("The visibility transition changed. Reload and retry.");
744
828
  e.update(i, {
745
829
  visibility: a,
746
830
  visibilityTransition: "",
747
- updatedAt: q()
831
+ updatedAt: J()
748
832
  });
749
833
  }));
750
834
  }
751
835
  //#endregion
752
836
  //#region src/utils/moderation-prompt.ts
753
- var Sn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", Cn = {
837
+ var Fn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이터입니다.\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은 \"\"", In = {
754
838
  ko: "Korean",
755
839
  en: "English",
756
840
  ja: "Japanese",
@@ -762,12 +846,12 @@ var Sn = "당신은 게시판 콘텐츠를 심사하는 엄격한 모더레이
762
846
  ar: "Arabic",
763
847
  id: "Indonesian"
764
848
  };
765
- function wn(e) {
766
- let t = Cn[e] ?? "English", n = ue(e).name;
849
+ function Ln(e) {
850
+ let t = In[e] ?? "English", n = fe(e).name;
767
851
  return t === n ? t : `${t} (${n})`;
768
852
  }
769
- function Tn(e) {
770
- let t = wn(e);
853
+ function Rn(e) {
854
+ let t = Ln(e);
771
855
  return `You are a strict moderator reviewing content for a message board.
772
856
  If the text below contains profanity, vulgar slang, sexual harassment, hate speech, threats, spam, or repetitive/flooding advertisements, you MUST reject it (flagged=true).
773
857
 
@@ -794,17 +878,17 @@ Output JSON only:
794
878
  Do not quote the offensive words at length; clearly state the type (profanity/hate/spam, etc.).
795
879
  - If flagged=false, category is "none" and reason is ""`;
796
880
  }
797
- function En(e = "ko") {
798
- return e === "ko" ? Sn : Tn(e);
881
+ function zn(e = "ko") {
882
+ return e === "ko" ? Fn : Rn(e);
799
883
  }
800
- function Dn(e, t = "ko") {
884
+ function Bn(e, t = "ko") {
801
885
  let n = `"""${e.slice(0, 4e3)}"""`;
802
886
  return t === "ko" ? `심사할 텍스트:\n${n}` : `Text to review:\n${n}`;
803
887
  }
804
- function On(e = "ko") {
888
+ function Vn(e = "ko") {
805
889
  return e === "ko" ? "이 이미지를 심사해 주세요." : "Please review this image.";
806
890
  }
807
- var kn = {
891
+ var Hn = {
808
892
  abuse: "욕설·비속어·모욕",
809
893
  spam: "스팸·광고",
810
894
  adult: "선정적·성인 내용",
@@ -812,21 +896,21 @@ var kn = {
812
896
  other: "부적절한 내용",
813
897
  none: ""
814
898
  };
815
- function An(e, t = "ko") {
816
- return !e || e === "none" ? "" : e in kn ? M(t, `moderationPrompt.categories.${e}`) : e;
899
+ function Un(e, t = "ko") {
900
+ return !e || e === "none" ? "" : e in Hn ? j(t, `moderationPrompt.categories.${e}`) : e;
817
901
  }
818
- function jn(e) {
902
+ function Wn(e) {
819
903
  let t = e.locale ?? "ko";
820
904
  if (e.via === "local" && e.localHit) {
821
905
  let n = e.localHit.trim();
822
- return n.length > 0 && n.length <= 12 ? M(t, "moderationPrompt.localHit", { hit: n }) : M(t, "moderationPrompt.localGeneric");
906
+ return n.length > 0 && n.length <= 12 ? j(t, "moderationPrompt.localHit", { hit: n }) : j(t, "moderationPrompt.localGeneric");
823
907
  }
824
908
  let n = (e.reason || "").trim();
825
909
  if (n) return n;
826
- let r = e.category ? An(e.category, t) : "";
827
- return r ? M(t, "moderationPrompt.categoryBlocked", { category: r }) : M(t, "moderationPrompt.genericBlocked");
910
+ let r = e.category ? Un(e.category, t) : "";
911
+ return r ? j(t, "moderationPrompt.categoryBlocked", { category: r }) : j(t, "moderationPrompt.genericBlocked");
828
912
  }
829
- var Mn = [
913
+ var Gn = [
830
914
  "씨발",
831
915
  "시발",
832
916
  "시이발",
@@ -852,10 +936,10 @@ var Mn = [
852
936
  "bitch",
853
937
  "asshole"
854
938
  ];
855
- function Nn(e) {
939
+ function Kn(e) {
856
940
  return new RegExp(e.join("|"), "i");
857
941
  }
858
- var Pn = /* @__PURE__ */ new Set([
942
+ var qn = /* @__PURE__ */ new Set([
859
943
  "none",
860
944
  "abuse",
861
945
  "spam",
@@ -863,7 +947,7 @@ var Pn = /* @__PURE__ */ new Set([
863
947
  "violence",
864
948
  "other"
865
949
  ]);
866
- function Fn(e) {
950
+ function Jn(e) {
867
951
  let t = e.trim();
868
952
  if (!t) return null;
869
953
  let n;
@@ -881,7 +965,7 @@ function Fn(e) {
881
965
  if (typeof n != "object" || !n) return null;
882
966
  let r = n;
883
967
  if (typeof r.flagged != "boolean") return null;
884
- let i = typeof r.category == "string" && Pn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
968
+ let i = typeof r.category == "string" && qn.has(r.category) ? r.category : r.flagged ? "other" : "none", a = typeof r.reason == "string" ? r.reason : "";
885
969
  return {
886
970
  flagged: r.flagged,
887
971
  category: i,
@@ -890,11 +974,11 @@ function Fn(e) {
890
974
  }
891
975
  //#endregion
892
976
  //#region src/composables/useMemiBoardAutoTranslate.ts
893
- var In = 3e4, Ln = 45e3, Rn = 12e3, zn = 3;
894
- function Bn(e) {
977
+ var Yn = 3e4, Xn = 45e3, Zn = 12e3, Qn = 3;
978
+ function $n(e) {
895
979
  return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
896
980
  }
897
- async function Vn(e, t, n) {
981
+ async function er(e, t, n) {
898
982
  let r = Array(e.length), i = 0;
899
983
  async function a() {
900
984
  for (; i < e.length;) {
@@ -904,7 +988,7 @@ async function Vn(e, t, n) {
904
988
  }
905
989
  return await Promise.all(Array.from({ length: Math.min(t, e.length) }, () => a())), r;
906
990
  }
907
- function Hn(e, t) {
991
+ function tr(e, t) {
908
992
  return new Promise((n, r) => {
909
993
  let i = setTimeout(() => r(/* @__PURE__ */ Error(`translation timed out after ${t / 1e3}s`)), t);
910
994
  e.then((e) => {
@@ -914,14 +998,14 @@ function Hn(e, t) {
914
998
  });
915
999
  });
916
1000
  }
917
- function Un() {
918
- let e = Me(), { moderation: t } = v();
1001
+ function nr() {
1002
+ let e = Me(), { moderation: t } = i();
919
1003
  async function n(n) {
920
- D();
1004
+ F();
921
1005
  let r = Xe(e, {
922
1006
  backend: new Je(),
923
1007
  useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
924
- }), i = await Hn(Ze(r, {
1008
+ }), i = await tr(Ze(r, {
925
1009
  model: t.model ?? "gemini-3.5-flash-lite",
926
1010
  systemInstruction: [
927
1011
  "Identify the predominant language of the supplied message-board text.",
@@ -932,9 +1016,9 @@ function Un() {
932
1016
  temperature: 0,
933
1017
  maxOutputTokens: 128,
934
1018
  responseMimeType: "application/json",
935
- responseSchema: Ye.object({ properties: { locale: Ye.enumString({ enum: T.map((e) => e.code) }) } })
1019
+ responseSchema: Ye.object({ properties: { locale: Ye.enumString({ enum: P.map((e) => e.code) }) } })
936
1020
  }
937
- }).generateContent(JSON.stringify({ text: n.slice(0, Rn) })), In), a = F(JSON.parse(i.response.text())?.locale);
1021
+ }).generateContent(JSON.stringify({ text: n.slice(0, Zn) })), Yn), a = D(JSON.parse(i.response.text())?.locale);
938
1022
  if (!a) throw Error("Could not identify the original language. Please try translating again.");
939
1023
  return a;
940
1024
  }
@@ -959,15 +1043,15 @@ function Un() {
959
1043
  }
960
1044
  });
961
1045
  }
962
- async function i(e, t, n, i) {
1046
+ async function a(e, t, n, i) {
963
1047
  let a = Object.keys(e.fields), o = [
964
1048
  `Purpose: ${i}`,
965
- `Source language: ${wn(t)} (${t})`,
966
- `Translate into: ${n.map((e) => `${e} = ${wn(e)}`).join(", ")}`,
1049
+ `Source language: ${Ln(t)} (${t})`,
1050
+ `Translate into: ${n.map((e) => `${e} = ${Ln(e)}`).join(", ")}`,
967
1051
  e.context ? `Context (do not translate): ${e.context}` : "",
968
1052
  "Text (JSON):",
969
1053
  JSON.stringify(e.fields)
970
- ].filter(Boolean).join("\n"), s = await Hn(r(n, a).generateContent(o), In), c = JSON.parse(s.response.text()), l = {};
1054
+ ].filter(Boolean).join("\n"), s = await tr(r(n, a).generateContent(o), Yn), c = JSON.parse(s.response.text()), l = {};
971
1055
  for (let e of n) {
972
1056
  let t = c?.[e];
973
1057
  if (!t) continue;
@@ -980,17 +1064,17 @@ function Un() {
980
1064
  }
981
1065
  return l;
982
1066
  }
983
- async function a(e, t = {}) {
984
- D();
985
- let n = t.source ?? "ko", r = (t.targets ?? T.map((e) => e.code)).filter((e) => e !== n), a = t.purpose ?? "website UI labels", o = e.map((e) => ({
1067
+ async function o(e, t = {}) {
1068
+ F();
1069
+ let n = t.source ?? "ko", r = (t.targets ?? P.map((e) => e.code)).filter((e) => e !== n), i = t.purpose ?? "website UI labels", o = e.map((e) => ({
986
1070
  ...e,
987
1071
  fields: Object.fromEntries(Object.entries(e.fields).map(([e, t]) => [e, t.trim()]).filter(([, e]) => e))
988
1072
  })).filter((e) => Object.keys(e.fields).length);
989
1073
  if (!o.length || !r.length) return {};
990
- let s = await Promise.all(o.map((e) => i(e, n, r, a)));
1074
+ let s = await Promise.all(o.map((e) => a(e, n, r, i)));
991
1075
  return Object.fromEntries(o.map((e, t) => [e.id, s[t]]));
992
1076
  }
993
- function o() {
1077
+ function s() {
994
1078
  let n = Xe(e, {
995
1079
  backend: new Je(),
996
1080
  useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
@@ -1009,32 +1093,32 @@ function Un() {
1009
1093
  }
1010
1094
  });
1011
1095
  }
1012
- async function s(e, t = {}) {
1013
- D();
1014
- let n = t.source ?? "ko", r = (t.targets ?? T.map((e) => e.code)).filter((e) => e !== n), i = e.trim();
1096
+ async function c(e, t = {}) {
1097
+ F();
1098
+ let n = t.source ?? "ko", r = (t.targets ?? P.map((e) => e.code)).filter((e) => e !== n), i = e.trim();
1015
1099
  if (!i || !r.length) return {};
1016
- if (i.length > 12e3) throw Error(`translation is limited to ${Rn} characters`);
1017
- let a = await Vn(r, zn, async (e) => {
1100
+ if (i.length > 12e3) throw Error(`translation is limited to ${Zn} characters`);
1101
+ let a = await er(r, Qn, async (e) => {
1018
1102
  let t = [
1019
- `Source language: ${wn(n)} (${n})`,
1020
- `Translate into: ${e} = ${wn(e)}`,
1103
+ `Source language: ${Ln(n)} (${n})`,
1104
+ `Translate into: ${e} = ${Ln(e)}`,
1021
1105
  "HTML:",
1022
1106
  i
1023
- ].join("\n"), r = Bn((await Hn(o().generateContent(t), Ln)).response.text());
1107
+ ].join("\n"), r = $n((await tr(s().generateContent(t), Xn)).response.text());
1024
1108
  if (!r) throw Error(`empty translation for ${e}`);
1025
1109
  return [e, r];
1026
1110
  });
1027
1111
  return Object.fromEntries(a);
1028
1112
  }
1029
1113
  return {
1030
- translateEntries: a,
1031
- translateHtml: s,
1114
+ translateEntries: o,
1115
+ translateHtml: c,
1032
1116
  detectSourceLocale: n
1033
1117
  };
1034
1118
  }
1035
1119
  //#endregion
1036
1120
  //#region src/composables/useMemiBoardSettings.ts
1037
- var Wn = [
1121
+ var rr = [
1038
1122
  {
1039
1123
  id: "free",
1040
1124
  label: "자유",
@@ -1062,17 +1146,17 @@ var Wn = [
1062
1146
  visibility: "public",
1063
1147
  order: 2
1064
1148
  }
1065
- ], Gn = Wn;
1066
- function Kn(e) {
1149
+ ], ir = rr;
1150
+ function ar(e) {
1067
1151
  return e === "hidden" ? "hidden" : "public";
1068
1152
  }
1069
- function qn(e, t, n) {
1153
+ function or(e, t, n) {
1070
1154
  return {
1071
1155
  id: e,
1072
1156
  label: typeof t.label == "string" && t.label.trim() ? t.label.trim() : e,
1073
1157
  order: typeof t.order == "number" ? t.order : n,
1074
1158
  description: (typeof t.description == "string" ? t.description : "") || "",
1075
- visibility: Kn(t.visibility),
1159
+ visibility: ar(t.visibility),
1076
1160
  visibilityTransition: t.visibilityTransition === "hidden" || t.visibilityTransition === "public" ? t.visibilityTransition : void 0,
1077
1161
  listView: t.listView ?? "default",
1078
1162
  editorType: t.editorType ?? (t.listView === "image" ? "image" : "default"),
@@ -1080,144 +1164,151 @@ function qn(e, t, n) {
1080
1164
  commentWriteRole: t.commentWriteRole ?? "user",
1081
1165
  allowedStaffUids: Array.isArray(t.allowedStaffUids) ? t.allowedStaffUids : [],
1082
1166
  allowedManagerUids: Array.isArray(t.allowedManagerUids) ? t.allowedManagerUids : [],
1083
- locale: F(t.locale) ?? "",
1167
+ locale: D(t.locale) ?? "",
1084
1168
  autoTranslate: t.autoTranslate === !0,
1085
1169
  autoTranslatePosts: t.autoTranslatePosts === !0,
1086
1170
  translationLocales: mt(t.translationLocales),
1087
- i18n: Q(t.i18n),
1171
+ customFields: Dn(t.customFields),
1172
+ i18n: $(t.i18n),
1088
1173
  i18nSource: ut(t.i18nSource)
1089
1174
  };
1090
1175
  }
1091
- function Jn() {
1092
- let e = () => P(), t = Z(), r = Me(), { isSignedIn: i, isAdmin: a, isStaff: s, user: c } = Wt(), { t: l, locale: u } = N(), { translateEntries: d } = Un(), f = I(() => K(S(t, e()), G("order", "asc"))), { data: m, pending: h } = ke(f, { ssrKey: p(e(), "boards") }), g = I(() => m.value.map((e, t) => qn(e.id, e, t))), _ = g, v = I(() => g.value.filter((e) => e.visibility !== "hidden")), y = v;
1093
- function b(e, t) {
1176
+ function sr() {
1177
+ let e = () => y(), t = Q(), n = Me(), { isSignedIn: r, isAdmin: i, isStaff: a, user: o } = Wt(), { t: s, locale: c } = O(), { translateEntries: l } = nr(), d = I(() => q(T(t, e()), K("order", "asc"))), { data: f, pending: p } = ke(d, { ssrKey: h(e(), "boards") }), m = I(() => f.value.map((e, t) => or(e.id, e, t))), _ = m, v = I(() => m.value.filter((e) => e.visibility !== "hidden")), b = v;
1178
+ function x(e, t) {
1094
1179
  if (!e) return;
1095
- let n = g.value.find((t) => t.id === e);
1096
- return n ? _t(n.i18n, n.i18nSource, "label", n.label, t ?? u.value) || n.label : e;
1180
+ let n = m.value.find((t) => t.id === e);
1181
+ return n ? _t(n.i18n, n.i18nSource, "label", n.label, t ?? c.value) || n.label : e;
1097
1182
  }
1098
- let x = b;
1183
+ let S = x;
1099
1184
  function C(e, t) {
1100
1185
  if (!e) return;
1101
- let n = g.value.find((t) => t.id === e), r = n?.description?.trim();
1102
- if (n && r) return _t(n.i18n, n.i18nSource, "description", r, t ?? u.value) || void 0;
1186
+ let n = m.value.find((t) => t.id === e), r = n?.description?.trim();
1187
+ if (n && r) return _t(n.i18n, n.i18nSource, "description", r, t ?? c.value) || void 0;
1103
1188
  }
1104
- let T = C;
1105
- function D(e) {
1106
- return e ? g.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
1189
+ let w = C;
1190
+ function E(e) {
1191
+ return e ? m.value.find((t) => t.id === e)?.visibility ?? "public" : "public";
1107
1192
  }
1108
- let ee = D;
1109
- function O(e) {
1110
- return D(e) === "hidden";
1111
- }
1112
- let k = O;
1193
+ let k = E;
1113
1194
  function A(e) {
1114
- if (e) return g.value.find((t) => t.id === e);
1195
+ return E(e) === "hidden";
1115
1196
  }
1116
- Nt((e) => A(e));
1197
+ let ee = A;
1117
1198
  function j(e) {
1118
- return At(c.value?.uid, a.value, s.value, e ? A(e) : void 0);
1199
+ if (e) return m.value.find((t) => t.id === e);
1200
+ }
1201
+ Nt((e) => j(e));
1202
+ function M(e) {
1203
+ return At(o.value?.uid, i.value, a.value, e ? j(e) : void 0);
1119
1204
  }
1120
- let te = I(() => g.value.filter((e) => j(e.id)));
1121
- function ne(e, t) {
1205
+ let te = I(() => m.value.filter((e) => M(e.id)));
1206
+ function ne(e) {
1207
+ return e.code === "duplicateKey" ? s("settings.customFields.duplicateKey", { key: e.key }) : e.code === "labelRequired" ? s("settings.customFields.labelRequired", { key: e.key }) : e.code === "tooMany" ? s("settings.customFields.limit") : s("settings.customFields.invalidKey");
1208
+ }
1209
+ function re(e, t) {
1210
+ let n = On(e.customFields);
1211
+ if (n.issue) throw Error(ne(n.issue));
1122
1212
  return {
1123
1213
  label: e.label.trim(),
1124
1214
  description: (e.description ?? "").trim(),
1125
- visibility: Kn(e.visibility),
1215
+ visibility: ar(e.visibility),
1126
1216
  listView: e.listView ?? "default",
1127
1217
  editorType: e.editorType ?? (e.listView === "image" ? "image" : "default"),
1128
1218
  writeRole: e.writeRole ?? "user",
1129
1219
  commentWriteRole: e.commentWriteRole ?? "user",
1130
1220
  allowedStaffUids: e.allowedStaffUids ?? [],
1131
1221
  allowedManagerUids: e.allowedManagerUids ?? [],
1132
- locale: F(e.locale) ?? "",
1222
+ locale: D(e.locale) ?? "",
1133
1223
  autoTranslate: e.autoTranslate === !0,
1134
1224
  autoTranslatePosts: e.autoTranslatePosts === !0,
1135
1225
  translationLocales: mt(e.translationLocales),
1226
+ customFields: n.fields,
1136
1227
  ...e.i18n ? { i18n: e.i18n } : {},
1137
1228
  ...e.i18nSource ? { i18nSource: e.i18nSource } : {},
1138
1229
  order: t,
1139
- updatedAt: q()
1230
+ updatedAt: J()
1140
1231
  };
1141
1232
  }
1142
- async function re(e) {
1143
- if (!n()) return e;
1144
- let t = e.label.trim(), r = (e.description ?? "").trim();
1233
+ async function ie(e) {
1234
+ if (!de()) return e;
1235
+ let t = e.label.trim(), n = (e.description ?? "").trim();
1145
1236
  if (!t) return e;
1146
1237
  if (xt({
1147
1238
  ...e,
1148
1239
  label: t,
1149
- description: r
1240
+ description: n
1150
1241
  })) return {
1151
1242
  ...e,
1152
1243
  label: t,
1153
- description: r
1244
+ description: n
1154
1245
  };
1155
- let i = u.value, a = pt(e), o = { label: t };
1156
- r && (o.description = r);
1157
- let s = ft(i, o, (await d([{
1246
+ let r = c.value, i = pt(e), a = { label: t };
1247
+ n && (a.description = n);
1248
+ let o = ft(r, a, (await l([{
1158
1249
  id: e.id || "board",
1159
- fields: o,
1250
+ fields: a,
1160
1251
  context: e.id
1161
1252
  }], {
1162
- source: i,
1163
- targets: a,
1253
+ source: r,
1254
+ targets: i,
1164
1255
  purpose: "board name and short description shown in navigation and page headers"
1165
1256
  }))[e.id || "board"]);
1166
- if (!ht(s, Object.keys(o), [...a, i])) throw Error(l("settings.autoTranslate.failed", { count: a.length }));
1257
+ if (!ht(o, Object.keys(a), [...i, r])) throw Error(s("settings.autoTranslate.failed", { count: i.length }));
1167
1258
  return {
1168
1259
  ...e,
1169
1260
  label: t,
1170
- description: r,
1171
- i18n: s,
1261
+ description: n,
1262
+ i18n: o,
1172
1263
  i18nSource: {
1173
- locale: i,
1264
+ locale: r,
1174
1265
  label: t,
1175
- description: r
1266
+ description: n
1176
1267
  }
1177
1268
  };
1178
1269
  }
1179
- async function M(n, r = n.order ?? 0) {
1180
- if (!i.value) throw Error(l("boardSettings.signInRequired"));
1270
+ async function N(n, i = n.order ?? 0) {
1271
+ if (!r.value) throw Error(s("boardSettings.signInRequired"));
1181
1272
  let a = n.id.trim(), o = n.label.trim();
1182
- if (!a || !o) throw Error(l("boardSettings.idAndNameRequired"));
1183
- let s = Kn(n.visibility), c = ne({
1273
+ if (!a || !o) throw Error(s("boardSettings.idAndNameRequired"));
1274
+ let c = ar(n.visibility), l = re({
1184
1275
  ...n,
1185
1276
  label: o,
1186
- visibility: s
1187
- }, r);
1188
- await xn(t, e(), a, c);
1189
- }
1190
- let ie = M;
1191
- async function ae(e) {
1192
- if (!i.value) throw Error(l("boardSettings.signInRequired"));
1193
- for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(l("boardSettings.idAndNameRequired"));
1194
- for (let [t, n] of e.entries()) await M(n, t);
1195
- }
1196
- let oe = ae;
1197
- async function se(n) {
1198
- if (!i.value) throw Error(l("boardSettings.signInRequired"));
1199
- let a = n.trim();
1200
- if (!a) throw Error(l("boardSettings.deleteIdRequired"));
1277
+ visibility: c
1278
+ }, i);
1279
+ await Pn(t, e(), a, l);
1280
+ }
1281
+ let oe = N;
1282
+ async function se(e) {
1283
+ if (!r.value) throw Error(s("boardSettings.signInRequired"));
1284
+ for (let t of e) if (!t.id.trim() || !t.label.trim()) throw Error(s("boardSettings.idAndNameRequired"));
1285
+ for (let [t, n] of e.entries()) await N(n, t);
1286
+ }
1287
+ let ce = se;
1288
+ async function le(i) {
1289
+ if (!r.value) throw Error(s("boardSettings.signInRequired"));
1290
+ let a = i.trim();
1291
+ if (!a) throw Error(s("boardSettings.deleteIdRequired"));
1201
1292
  for (;;) {
1202
- let n = await H(K(o(t, e()), X("boardId", "==", a), U(25)));
1203
- if (n.empty) break;
1204
- for (let i of n.docs) await cn(t, We(r), e(), i.id);
1293
+ let r = await U(q(u(t, e()), Z("boardId", "==", a), W(25)));
1294
+ if (r.empty) break;
1295
+ for (let i of r.docs) await cn(t, We(n), e(), i.id);
1205
1296
  }
1206
- await ge(w(t, e(), n));
1297
+ await _e(g(t, e(), i));
1207
1298
  }
1208
- let ce = se;
1209
- async function le() {
1299
+ let ue = le;
1300
+ async function P() {
1210
1301
  return Promise.resolve();
1211
1302
  }
1212
- async function ue(e) {
1213
- let t = e.trim();
1214
- if (!t) throw Error(l("boardSettings.nameRequired"));
1215
- if (!i.value) throw Error(l("boardSettings.signInRequired"));
1216
- let n = g.value.find((e) => e.label === t);
1303
+ async function F(e) {
1304
+ let t = e.trim().slice(0, 40);
1305
+ if (!t) throw Error(s("boardSettings.nameRequired"));
1306
+ if (!r.value) throw Error(s("boardSettings.signInRequired"));
1307
+ let n = m.value.find((e) => e.label === t);
1217
1308
  if (n) return n.id;
1218
- let r = E(t) || `board-${Date.now()}`, a = r, o = 2, s = new Set(g.value.map((e) => e.id));
1219
- for (; s.has(a);) a = `${r}-${o++}`;
1220
- return await M({
1309
+ let i = ae(t) || `board-${Date.now()}`, a = i, o = 2, c = new Set(m.value.map((e) => e.id));
1310
+ for (; c.has(a);) a = `${i}-${o++}`;
1311
+ return await N({
1221
1312
  id: a,
1222
1313
  label: t,
1223
1314
  visibility: "public",
@@ -1225,91 +1316,91 @@ function Jn() {
1225
1316
  editorType: "default",
1226
1317
  writeRole: "user",
1227
1318
  commentWriteRole: "user",
1228
- order: g.value.length
1319
+ order: m.value.length
1229
1320
  }), a;
1230
1321
  }
1231
1322
  return {
1232
- boards: g,
1323
+ boards: m,
1233
1324
  publicBoards: v,
1234
- boardLabel: b,
1325
+ boardLabel: x,
1235
1326
  boardDescription: C,
1236
- boardVisibility: D,
1237
- isBoardHidden: O,
1238
- getBoard: A,
1239
- canManageBoard: j,
1327
+ boardVisibility: E,
1328
+ isBoardHidden: A,
1329
+ getBoard: j,
1330
+ canManageBoard: M,
1240
1331
  managedBoards: te,
1241
1332
  categories: _,
1242
- publicCategories: y,
1243
- categoryLabel: x,
1244
- categoryDescription: T,
1245
- categoryVisibility: ee,
1246
- isCategoryHidden: k,
1247
- settingsPending: h,
1248
- ensureSettings: le,
1249
- addBoard: ue,
1250
- addCategory: ue,
1251
- saveBoard: M,
1252
- saveCategory: ie,
1253
- translateBoard: re,
1254
- saveBoards: ae,
1255
- saveCategories: oe,
1256
- deleteBoard: se,
1257
- deleteCategory: ce,
1258
- DEFAULT_BOARDS: Wn,
1259
- DEFAULT_CATEGORIES: Gn
1333
+ publicCategories: b,
1334
+ categoryLabel: S,
1335
+ categoryDescription: w,
1336
+ categoryVisibility: k,
1337
+ isCategoryHidden: ee,
1338
+ settingsPending: p,
1339
+ ensureSettings: P,
1340
+ addBoard: F,
1341
+ addCategory: F,
1342
+ saveBoard: N,
1343
+ saveCategory: oe,
1344
+ translateBoard: ie,
1345
+ saveBoards: se,
1346
+ saveCategories: ce,
1347
+ deleteBoard: le,
1348
+ deleteCategory: ue,
1349
+ DEFAULT_BOARDS: rr,
1350
+ DEFAULT_CATEGORIES: ir
1260
1351
  };
1261
1352
  }
1262
1353
  //#endregion
1263
1354
  //#region src/composables/useMemiBoardPosts.ts
1264
- var Yn = /* @__PURE__ */ new Map();
1265
- function Xn(e) {
1355
+ var cr = /* @__PURE__ */ new Map();
1356
+ function lr(e) {
1266
1357
  if (!e || typeof e != "object") return !1;
1267
1358
  let t = "code" in e ? String(e.code) : "";
1268
1359
  return t === "permission-denied" || t === "firestore/permission-denied";
1269
1360
  }
1270
- function Zn(e, t) {
1361
+ function ur(e, t) {
1271
1362
  let n = z(e)?.trim();
1272
- if (!n) throw Error(M(t, "posts.boardIdRequired"));
1363
+ if (!n) throw Error(j(t, "posts.boardIdRequired"));
1273
1364
  return n;
1274
1365
  }
1275
- function Qn(e) {
1276
- let t = Z(), n = Me(), { isBoardHidden: r, getBoard: i } = Jn(), { user: a, canManageBoard: c } = Wt(), { t: l, locale: u } = N(), d = () => P(), f = () => Zn(e, u.value), p = () => o(t, d()), m = (e) => y(t, d(), e), h = (e) => s(t, d(), e);
1277
- function g(e, t, n) {
1366
+ function dr(e) {
1367
+ let t = Q(), n = Me(), { isBoardHidden: r, getBoard: i } = sr(), { user: a, canManageBoard: o } = Wt(), { t: s, locale: c } = O(), l = () => y(), d = () => ur(e, c.value), f = () => u(t, l()), p = (e) => S(t, l(), e), m = (e) => b(t, l(), e);
1368
+ function h(e, t, n) {
1278
1369
  return {
1279
1370
  id: e,
1280
1371
  ...t,
1281
- i18n: Q(t.i18n),
1372
+ i18n: $(t.i18n),
1282
1373
  i18nSource: ut(t.i18nSource),
1283
1374
  content: typeof n?.content == "string" ? n.content : "",
1284
- contentI18n: Q(n?.i18n),
1375
+ contentI18n: $(n?.i18n),
1285
1376
  contentI18nSource: dt(n?.i18nSource)
1286
1377
  };
1287
1378
  }
1288
- function _() {
1289
- return !r(f());
1379
+ function g() {
1380
+ return !r(d());
1290
1381
  }
1291
- function v() {
1292
- return i(f())?.editorType === "image";
1382
+ function _() {
1383
+ return i(d())?.editorType === "image";
1293
1384
  }
1294
- function b(e) {
1295
- let t = v(), n = dn(e.content), r = fn(e.content, e.attachments);
1385
+ function v(e) {
1386
+ let t = _(), n = dn(e.content), r = fn(e.content, e.attachments);
1296
1387
  if (t) {
1297
- if (!r) throw Error(l("posts.photoRequired"));
1388
+ if (!r) throw Error(s("posts.photoRequired"));
1298
1389
  return;
1299
1390
  }
1300
- if (!n && !r) throw Error(l("posts.bodyRequired"));
1301
- if (!e.title?.trim()) throw Error(l("posts.titleRequired"));
1391
+ if (!n && !r) throw Error(s("posts.bodyRequired"));
1392
+ if (!e.title?.trim()) throw Error(s("posts.titleRequired"));
1302
1393
  }
1303
1394
  function x() {
1304
- return ve(p()).id;
1395
+ return ve(f()).id;
1305
1396
  }
1306
- function S(e) {
1307
- return Yt(t, d(), f(), e, a.value?.uid, c(f()));
1397
+ function C(e) {
1398
+ return Yt(t, l(), d(), e, a.value?.uid, o(d()));
1308
1399
  }
1309
- async function C(e = {}) {
1310
- let t = e.pageSize ?? 20, n = [X("boardId", "==", f()), X("isPublished", "==", !0)];
1311
- e.publicOnly !== !1 && n.push(X("listed", "==", !0)), n.push(G("createdAt", "desc")), e.cursor && n.push(J(e.cursor)), n.push(U(t + 1));
1312
- let r = await H(K(p(), ...n)), i = r.docs.slice(0, t);
1400
+ async function w(e = {}) {
1401
+ let t = e.pageSize ?? 20, n = [Z("boardId", "==", d()), Z("isPublished", "==", !0)];
1402
+ e.publicOnly !== !1 && n.push(Z("listed", "==", !0)), n.push(K("createdAt", "desc")), e.cursor && n.push(Y(e.cursor)), n.push(W(t + 1));
1403
+ let r = await U(q(f(), ...n)), i = r.docs.slice(0, t);
1313
1404
  return {
1314
1405
  posts: i.map((e) => ({
1315
1406
  id: e.id,
@@ -1319,67 +1410,67 @@ function Qn(e) {
1319
1410
  hasMore: r.docs.length > t
1320
1411
  };
1321
1412
  }
1322
- async function w(e) {
1323
- let [t, n] = await Promise.all([xe(m(e)), xe(h(e))]);
1324
- return t.exists() ? g(t.id, t.data(), n.exists() ? n.data() : void 0) : null;
1325
- }
1326
1413
  async function T(e) {
1414
+ let [t, n] = await Promise.all([xe(p(e)), xe(m(e))]);
1415
+ return t.exists() ? h(t.id, t.data(), n.exists() ? n.data() : void 0) : null;
1416
+ }
1417
+ async function E(e) {
1327
1418
  try {
1328
- let t = await S(e.trim());
1419
+ let t = await C(e.trim());
1329
1420
  if (!t) return { status: "not-found" };
1330
1421
  try {
1331
- let e = await w(t.id);
1422
+ let e = await T(t.id);
1332
1423
  return e ? {
1333
1424
  status: "ok",
1334
1425
  post: e
1335
1426
  } : { status: "not-found" };
1336
1427
  } catch (e) {
1337
- return Xn(e) ? { status: "permission-denied" } : {
1428
+ return lr(e) ? { status: "permission-denied" } : {
1338
1429
  status: "error",
1339
1430
  message: e instanceof Error ? e.message : String(e)
1340
1431
  };
1341
1432
  }
1342
1433
  } catch (e) {
1343
- return Xn(e) ? { status: "permission-denied" } : {
1434
+ return lr(e) ? { status: "permission-denied" } : {
1344
1435
  status: "error",
1345
1436
  message: e instanceof Error ? e.message : String(e)
1346
1437
  };
1347
1438
  }
1348
1439
  }
1349
- async function ee(e) {
1350
- let t = e.trim(), n = Yn.get(`${f()}/${t}`);
1440
+ async function D(e) {
1441
+ let t = e.trim(), n = cr.get(`${d()}/${t}`);
1351
1442
  if (n) return {
1352
1443
  status: "ok",
1353
1444
  id: n
1354
1445
  };
1355
1446
  try {
1356
- let e = await S(t);
1447
+ let e = await C(t);
1357
1448
  return e ? {
1358
1449
  status: "ok",
1359
1450
  id: e.id
1360
- } : { status: r(f()) ? "permission-denied" : "not-found" };
1451
+ } : { status: r(d()) ? "permission-denied" : "not-found" };
1361
1452
  } catch (e) {
1362
- return Xn(e) ? { status: "permission-denied" } : {
1453
+ return lr(e) ? { status: "permission-denied" } : {
1363
1454
  status: "error",
1364
1455
  message: e instanceof Error ? e.message : String(e)
1365
1456
  };
1366
1457
  }
1367
1458
  }
1368
- async function O(e) {
1369
- return `${E(e.trim()) || "post"}-${x()}`;
1370
- }
1371
1459
  async function k(e) {
1460
+ return `${ae(e.trim()) || "post"}-${x()}`;
1461
+ }
1462
+ async function A(e) {
1372
1463
  if (!e.createdAt) return {
1373
1464
  previous: null,
1374
1465
  next: null
1375
1466
  };
1376
1467
  try {
1377
1468
  let t = [
1378
- X("boardId", "==", f()),
1379
- X("isPublished", "==", !0),
1380
- ...e.listed === !1 ? [] : [X("listed", "==", !0)],
1381
- G("createdAt", "desc")
1382
- ], [n, r] = await Promise.all([H(K(p(), ...t, J(e.createdAt), U(1))), H(K(p(), ...t, be(e.createdAt), Te(1)))]), i = (e) => {
1469
+ Z("boardId", "==", d()),
1470
+ Z("isPublished", "==", !0),
1471
+ ...e.listed === !1 ? [] : [Z("listed", "==", !0)],
1472
+ K("createdAt", "desc")
1473
+ ], [n, r] = await Promise.all([U(q(f(), ...t, Y(e.createdAt), W(1))), U(q(f(), ...t, be(e.createdAt), Te(1)))]), i = (e) => {
1383
1474
  let t = e.docs[0];
1384
1475
  return t ? {
1385
1476
  id: t.id,
@@ -1397,13 +1488,13 @@ function Qn(e) {
1397
1488
  };
1398
1489
  }
1399
1490
  }
1400
- async function A(e) {
1401
- b(e);
1402
- let n = e.postId || x(), r = v(), i, a;
1403
- r ? (i = n, a = un(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await O(a));
1404
- let o = _n(e.content, e.attachments), s = _(), c = Oe(t);
1405
- return c.set(m(n), {
1406
- boardId: f(),
1491
+ async function ee(e) {
1492
+ v(e);
1493
+ let n = e.postId || x(), r = _(), i, a;
1494
+ r ? (i = n, a = un(e.content)) : (a = e.title.trim(), i = e.slug?.trim() || await k(a));
1495
+ let o = _n(e.content, e.attachments), s = g(), c = Oe(t);
1496
+ return c.set(p(n), {
1497
+ boardId: d(),
1407
1498
  slug: i,
1408
1499
  title: a,
1409
1500
  ...o,
@@ -1419,127 +1510,129 @@ function Qn(e) {
1419
1510
  authorPhoto: e.authorPhoto,
1420
1511
  moderationStatus: "approved",
1421
1512
  moderationModel: e.moderationModel ?? null,
1422
- createdAt: q(),
1423
- updatedAt: q(),
1513
+ createdAt: J(),
1514
+ updatedAt: J(),
1424
1515
  ...e.translations ? {
1425
1516
  i18n: e.translations.i18n,
1426
1517
  i18nSource: e.translations.i18nSource
1427
- } : {}
1428
- }), c.set(h(n), {
1518
+ } : {},
1519
+ ...e.extend && Object.keys(e.extend).length ? { extend: kn(e.extend) } : {}
1520
+ }), c.set(m(n), {
1429
1521
  content: e.content,
1430
1522
  ...e.translations?.contentI18n ? {
1431
1523
  i18n: e.translations.contentI18n,
1432
1524
  i18nSource: e.translations.contentI18nSource
1433
1525
  } : {}
1434
- }), await c.commit(), Yn.set(`${f()}/${i}`, n), i;
1526
+ }), await c.commit(), cr.set(`${d()}/${i}`, n), i;
1435
1527
  }
1436
1528
  async function j(e, t) {
1437
- b(t);
1438
- let n = v() ? un(t.content) : t.title.trim(), r = _n(t.content, t.attachments), i = _();
1439
- await Promise.all([Y(m(e), {
1529
+ v(t);
1530
+ let n = _() ? un(t.content) : t.title.trim(), r = _n(t.content, t.attachments), i = g(), a = t.extend ? kn(t.extend) : void 0;
1531
+ await Promise.all([X(p(e), {
1440
1532
  title: n,
1441
1533
  ...r,
1442
- previewImage: r.previewImage ? r.previewImage : _e(),
1443
- videoUrl: r.videoUrl ? r.videoUrl : _e(),
1534
+ previewImage: r.previewImage ? r.previewImage : V(),
1535
+ videoUrl: r.videoUrl ? r.videoUrl : V(),
1444
1536
  tags: t.tags ?? [],
1445
1537
  listed: i,
1446
1538
  attachments: t.attachments ?? [],
1447
- updatedAt: q(),
1539
+ updatedAt: J(),
1448
1540
  ...t.translations ? {
1449
1541
  i18n: t.translations.i18n,
1450
1542
  i18nSource: t.translations.i18nSource
1451
- } : {}
1452
- }), De(h(e), {
1543
+ } : {},
1544
+ ...a ? { extend: Object.keys(a).length ? a : V() } : {}
1545
+ }), De(m(e), {
1453
1546
  content: t.content,
1454
1547
  ...t.translations ? t.translations.contentI18n ? {
1455
1548
  i18n: t.translations.contentI18n,
1456
1549
  i18nSource: t.translations.contentI18nSource
1457
1550
  } : {
1458
- i18n: _e(),
1459
- i18nSource: _e()
1551
+ i18n: V(),
1552
+ i18nSource: V()
1460
1553
  } : {}
1461
1554
  }, { merge: !0 })]);
1462
1555
  }
1463
- async function te(e, t) {
1464
- D(), await Promise.all([Y(m(e), {
1556
+ async function M(e, t) {
1557
+ F(), await Promise.all([X(p(e), {
1465
1558
  i18n: t.i18n,
1466
1559
  i18nSource: t.i18nSource,
1467
- updatedAt: q()
1468
- }), De(h(e), t.contentI18n ? {
1560
+ updatedAt: J()
1561
+ }), De(m(e), t.contentI18n ? {
1469
1562
  i18n: t.contentI18n,
1470
1563
  i18nSource: t.contentI18nSource
1471
1564
  } : {
1472
- i18n: _e(),
1473
- i18nSource: _e()
1565
+ i18n: V(),
1566
+ i18nSource: V()
1474
1567
  }, { merge: !0 })]);
1475
1568
  }
1476
- async function ne(e) {
1477
- await Y(m(e), {
1569
+ async function te(e) {
1570
+ await X(p(e), {
1478
1571
  isPublished: !0,
1479
- publishedAt: q(),
1480
- updatedAt: q()
1572
+ publishedAt: J(),
1573
+ updatedAt: J()
1481
1574
  });
1482
1575
  }
1483
- async function re(e, t) {
1484
- await Y(m(e), t ? {
1576
+ async function ne(e, t) {
1577
+ await X(p(e), t ? {
1485
1578
  pinned: !0,
1486
- pinnedAt: q()
1579
+ pinnedAt: J()
1487
1580
  } : {
1488
- pinned: _e(),
1489
- pinnedAt: _e()
1581
+ pinned: V(),
1582
+ pinnedAt: V()
1490
1583
  });
1491
1584
  }
1492
- async function M(e) {
1493
- await cn(t, We(n), d(), e);
1494
- for (let [t, n] of Yn) n === e && Yn.delete(t);
1585
+ async function re(e) {
1586
+ await cn(t, We(n), l(), e);
1587
+ for (let [t, n] of cr) n === e && cr.delete(t);
1495
1588
  }
1496
1589
  return {
1497
1590
  createPostId: x,
1498
- getPosts: C,
1499
- getPost: w,
1500
- getPostBySlug: T,
1501
- resolvePostIdBySlug: ee,
1502
- resolveUniqueSlug: O,
1503
- getAdjacentPosts: k,
1504
- createPost: A,
1591
+ getPosts: w,
1592
+ getPost: T,
1593
+ getPostBySlug: E,
1594
+ resolvePostIdBySlug: D,
1595
+ resolveUniqueSlug: k,
1596
+ getAdjacentPosts: A,
1597
+ createPost: ee,
1505
1598
  updatePost: j,
1506
- savePostTranslations: te,
1507
- publishPost: ne,
1508
- setPostPinned: re,
1509
- deletePost: M
1599
+ savePostTranslations: M,
1600
+ publishPost: te,
1601
+ setPostPinned: ne,
1602
+ deletePost: re
1510
1603
  };
1511
1604
  }
1512
- var $n = 10, er = 10;
1513
- function tr(e, t = {}) {
1514
- let n = Z(), { isAdmin: r, user: i, canManageBoard: a } = Wt(), s = () => P(), c = t.pageSize ?? $n, l = I(() => i.value?.uid ?? ""), u = I(() => Zn(e)), d = () => o(n, s()), f = I(() => t.publicOnly === void 0 ? !(r.value || a(u.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = R([]), m = R([]), h = R([]), g = R([]), _ = R(!0), v = R(!0), y = R(!0), b = R(!1), x = R(""), S = null, C = null, w, T, E;
1515
- function D(e) {
1605
+ var fr = 10, pr = 10;
1606
+ function mr(e, t = {}) {
1607
+ let n = Q(), { isAdmin: r, user: i, canManageBoard: a } = Wt(), o = () => y(), s = t.pageSize ?? fr, c = I(() => i.value?.uid ?? ""), l = I(() => ur(e)), d = () => u(n, o()), f = I(() => t.publicOnly === void 0 ? !(r.value || a(l.value)) : typeof t.publicOnly == "boolean" ? t.publicOnly : t.publicOnly.value), p = R([]), m = R([]), h = R([]), g = R([]), _ = R(!0), v = R(!0), b = R(!0), x = R(!1), S = R(""), C = null, w = null, T, E, D;
1608
+ function O(e) {
1516
1609
  return e.createdAt?.toMillis?.() ?? 0;
1517
1610
  }
1518
- let ee = I(() => {
1611
+ let k = I(() => {
1519
1612
  let e = new Set(g.value.map((e) => e.id)), t = /* @__PURE__ */ new Map();
1520
1613
  for (let n of [
1521
1614
  ...m.value,
1522
1615
  ...p.value,
1523
1616
  ...h.value
1524
1617
  ]) n.id && !e.has(n.id) && t.set(n.id, n);
1525
- return [...t.values()].sort((e, t) => D(t) - D(e) || String(t.id).localeCompare(String(e.id)));
1618
+ return [...t.values()].sort((e, t) => O(t) - O(e) || String(t.id).localeCompare(String(e.id)));
1526
1619
  });
1527
- function O() {
1528
- let e = [X("boardId", "==", u.value), X("isPublished", "==", !0)];
1529
- return f.value && e.push(X("listed", "==", !0)), e;
1620
+ function A() {
1621
+ let e = [Z("boardId", "==", l.value), Z("isPublished", "==", !0)];
1622
+ return f.value && e.push(Z("listed", "==", !0)), e;
1530
1623
  }
1531
- function k() {
1532
- w?.(), w = W(K(d(), ...O(), G("createdAt", "desc"), G(V(), "desc"), U(c)), (e) => {
1624
+ function ee() {
1625
+ T?.(), T = G(q(d(), ...A(), K("createdAt", "desc"), K(H(), "desc"), W(s)), (e) => {
1533
1626
  p.value = e.docs.map((e) => ({
1534
1627
  id: e.id,
1535
1628
  ...e.data()
1536
- })), S = e.docs.at(-1) ?? null, C || (y.value = e.docs.length >= c), v.value = !1;
1629
+ })), C = e.docs.at(-1) ?? null, w || (b.value = e.docs.length >= s), v.value = !1;
1537
1630
  }, (e) => {
1538
- console.error("[memi-board:postList] onSnapshot failed", e), x.value = e.message || String(e), v.value = !1;
1631
+ console.error("[memi-board:postList] onSnapshot failed", e), S.value = e.message || String(e), v.value = !1;
1539
1632
  });
1540
1633
  }
1541
- function A() {
1542
- E?.(), E = W(K(d(), ...O(), X("pinned", "==", !0), G("pinnedAt", "desc"), U(er)), (e) => {
1634
+ function j() {
1635
+ D?.(), D = G(q(d(), ...A(), Z("pinned", "==", !0), K("pinnedAt", "desc"), W(pr)), (e) => {
1543
1636
  g.value = e.docs.map((e) => ({
1544
1637
  id: e.id,
1545
1638
  ...e.data()
@@ -1548,14 +1641,14 @@ function tr(e, t = {}) {
1548
1641
  console.error("[memi-board:postList] notice onSnapshot failed", e), g.value = [], _.value = !1;
1549
1642
  });
1550
1643
  }
1551
- function j() {
1552
- T?.();
1553
- let e = l.value;
1644
+ function M() {
1645
+ E?.();
1646
+ let e = c.value;
1554
1647
  if (!e) {
1555
1648
  h.value = [];
1556
1649
  return;
1557
1650
  }
1558
- T = W(K(d(), X("boardId", "==", u.value), X("authorUid", "==", e), X("isPublished", "==", !1), G("createdAt", "desc"), U(20)), (e) => {
1651
+ E = G(q(d(), Z("boardId", "==", l.value), Z("authorUid", "==", e), Z("isPublished", "==", !1), K("createdAt", "desc"), W(20)), (e) => {
1559
1652
  h.value = e.docs.map((e) => ({
1560
1653
  id: e.id,
1561
1654
  ...e.data()
@@ -1565,70 +1658,70 @@ function tr(e, t = {}) {
1565
1658
  });
1566
1659
  }
1567
1660
  async function te() {
1568
- if (!(b.value || !y.value || v.value)) {
1569
- b.value = !0, x.value = "";
1661
+ if (!(x.value || !b.value || v.value)) {
1662
+ x.value = !0, S.value = "";
1570
1663
  try {
1571
- let e = C ?? S, t = [
1572
- ...O(),
1573
- G("createdAt", "desc"),
1574
- G(V(), "desc"),
1575
- ...e ? [J(e)] : [],
1576
- U(c + 1)
1577
- ], n = await H(K(d(), ...t)), r = n.docs.slice(0, c), i = r.map((e) => ({
1664
+ let e = w ?? C, t = [
1665
+ ...A(),
1666
+ K("createdAt", "desc"),
1667
+ K(H(), "desc"),
1668
+ ...e ? [Y(e)] : [],
1669
+ W(s + 1)
1670
+ ], n = await U(q(d(), ...t)), r = n.docs.slice(0, s), i = r.map((e) => ({
1578
1671
  id: e.id,
1579
1672
  ...e.data()
1580
1673
  })), a = new Set([...m.value, ...p.value].map((e) => e.id));
1581
- m.value.push(...i.filter((e) => !a.has(e.id))), C = r.at(-1) ?? C, y.value = n.docs.length > c;
1674
+ m.value.push(...i.filter((e) => !a.has(e.id))), w = r.at(-1) ?? w, b.value = n.docs.length > s;
1582
1675
  } catch (e) {
1583
- x.value = e.message || String(e), console.error("[memi-board:postList] loadMore failed", e);
1676
+ S.value = e.message || String(e), console.error("[memi-board:postList] loadMore failed", e);
1584
1677
  } finally {
1585
- b.value = !1;
1678
+ x.value = !1;
1586
1679
  }
1587
1680
  }
1588
1681
  }
1589
1682
  function ne() {
1590
- w?.(), p.value = [], m.value = [], S = null, C = null, y.value = !0, x.value = "", v.value = !0, g.value = [], _.value = !0, k(), A(), j();
1683
+ T?.(), p.value = [], m.value = [], C = null, w = null, b.value = !0, S.value = "", v.value = !0, g.value = [], _.value = !0, ee(), j(), M();
1591
1684
  }
1592
1685
  return B([
1593
- u,
1686
+ l,
1594
1687
  f,
1595
- l
1688
+ c
1596
1689
  ], ne, { immediate: !0 }), L(() => {
1597
- w?.(), E?.(), T?.();
1690
+ T?.(), D?.(), E?.();
1598
1691
  }), {
1599
- posts: ee,
1692
+ posts: k,
1600
1693
  notices: g,
1601
1694
  postsPending: I(() => v.value || _.value),
1602
- hasMore: y,
1603
- loadingMore: b,
1604
- loadError: x,
1695
+ hasMore: b,
1696
+ loadingMore: x,
1697
+ loadError: S,
1605
1698
  loadMore: te
1606
1699
  };
1607
1700
  }
1608
- function nr(e, t) {
1609
- let n = Z(), r = () => P(), i = I(() => Zn(e)), a = I(() => typeof t == "string" ? t : t.value), o = I(() => y(n, r(), a.value)), c = I(() => s(n, r(), a.value)), { data: l, pending: u } = je(o), { data: d, pending: f } = je(c);
1701
+ function hr(e, t) {
1702
+ let n = Q(), r = () => y(), i = I(() => ur(e)), a = I(() => typeof t == "string" ? t : t.value), o = I(() => S(n, r(), a.value)), s = I(() => b(n, r(), a.value)), { data: c, pending: l } = je(o), { data: u, pending: d } = je(s);
1610
1703
  return {
1611
1704
  post: I(() => {
1612
- if (!l.value || l.value.boardId !== i.value) return null;
1613
- let e = d.value;
1705
+ if (!c.value || c.value.boardId !== i.value) return null;
1706
+ let e = u.value;
1614
1707
  return {
1615
- ...l.value,
1708
+ ...c.value,
1616
1709
  id: a.value,
1617
- i18n: Q(l.value.i18n),
1618
- i18nSource: ut(l.value.i18nSource),
1619
- content: d.value?.content ?? "",
1620
- contentI18n: Q(e?.i18n),
1710
+ i18n: $(c.value.i18n),
1711
+ i18nSource: ut(c.value.i18nSource),
1712
+ content: u.value?.content ?? "",
1713
+ contentI18n: $(e?.i18n),
1621
1714
  contentI18nSource: dt(e?.i18nSource)
1622
1715
  };
1623
1716
  }),
1624
- pending: I(() => u.value || f.value)
1717
+ pending: I(() => l.value || d.value)
1625
1718
  };
1626
1719
  }
1627
1720
  //#endregion
1628
1721
  //#region src/composables/useMemiBoardUserPosts.ts
1629
- var rr = 10;
1630
- function ir(e, t = {}) {
1631
- let n = Z(), r = () => P(), i = () => o(n, r()), a = t.pageSize ?? rr, s = I(() => z(e)?.trim() || ""), c = R([]), l = R([]), u = R(!0), d = R(!0), f = R(!1), p = R(""), m = null, h = null, g;
1722
+ var gr = 10;
1723
+ function _r(e, t = {}) {
1724
+ let n = Q(), r = () => y(), i = () => u(n, r()), a = t.pageSize ?? gr, o = I(() => z(e)?.trim() || ""), s = R([]), c = R([]), l = R(!0), d = R(!0), f = R(!1), p = R(""), m = null, h = null, g;
1632
1725
  function _(e) {
1633
1726
  return {
1634
1727
  id: e.id,
@@ -1638,41 +1731,41 @@ function ir(e, t = {}) {
1638
1731
  function v(e) {
1639
1732
  return e.createdAt?.toMillis?.() ?? 0;
1640
1733
  }
1641
- let y = I(() => {
1734
+ let b = I(() => {
1642
1735
  let e = /* @__PURE__ */ new Map();
1643
- for (let t of [...l.value, ...c.value]) t.id && e.set(t.id, t);
1736
+ for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
1644
1737
  return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
1645
1738
  });
1646
- function b() {
1739
+ function x() {
1647
1740
  return [
1648
- X("authorUid", "==", s.value),
1649
- X("isPublished", "==", !0),
1650
- X("listed", "==", !0)
1741
+ Z("authorUid", "==", o.value),
1742
+ Z("isPublished", "==", !0),
1743
+ Z("listed", "==", !0)
1651
1744
  ];
1652
1745
  }
1653
- function x() {
1654
- if (g?.(), !s.value) {
1655
- u.value = !1;
1746
+ function S() {
1747
+ if (g?.(), !o.value) {
1748
+ l.value = !1;
1656
1749
  return;
1657
1750
  }
1658
- g = W(K(i(), ...b(), G("createdAt", "desc"), G(V(), "desc"), U(a)), (e) => {
1659
- c.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= a), u.value = !1;
1751
+ g = G(q(i(), ...x(), K("createdAt", "desc"), K(H(), "desc"), W(a)), (e) => {
1752
+ s.value = e.docs.map(_), m = e.docs.at(-1) ?? null, h || (d.value = e.docs.length >= a), l.value = !1;
1660
1753
  }, (e) => {
1661
- console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), u.value = !1;
1754
+ console.error("[memi-board:userPosts] onSnapshot failed", e), p.value = e.message || String(e), l.value = !1;
1662
1755
  });
1663
1756
  }
1664
- async function S() {
1665
- if (!f.value && d.value && !u.value && s.value) {
1757
+ async function C() {
1758
+ if (!f.value && d.value && !l.value && o.value) {
1666
1759
  f.value = !0, p.value = "";
1667
1760
  try {
1668
1761
  let e = h ?? m, t = [
1669
- ...b(),
1670
- G("createdAt", "desc"),
1671
- G(V(), "desc"),
1672
- ...e ? [J(e)] : [],
1673
- U(a + 1)
1674
- ], n = await H(K(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), s = new Set([...l.value, ...c.value].map((e) => e.id));
1675
- l.value.push(...o.filter((e) => !s.has(e.id))), h = r.at(-1) ?? h, d.value = n.docs.length > a;
1762
+ ...x(),
1763
+ K("createdAt", "desc"),
1764
+ K(H(), "desc"),
1765
+ ...e ? [Y(e)] : [],
1766
+ W(a + 1)
1767
+ ], n = await U(q(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
1768
+ c.value.push(...o.filter((e) => !l.has(e.id))), h = r.at(-1) ?? h, d.value = n.docs.length > a;
1676
1769
  } catch (e) {
1677
1770
  p.value = e.message || String(e), console.error("[memi-board:userPosts] loadMore failed", e);
1678
1771
  } finally {
@@ -1680,47 +1773,47 @@ function ir(e, t = {}) {
1680
1773
  }
1681
1774
  }
1682
1775
  }
1683
- function C() {
1684
- g?.(), c.value = [], l.value = [], m = null, h = null, d.value = !0, p.value = "", u.value = !0, x();
1776
+ function w() {
1777
+ g?.(), s.value = [], c.value = [], m = null, h = null, d.value = !0, p.value = "", l.value = !0, S();
1685
1778
  }
1686
- return B(s, C, { immediate: !0 }), L(() => g?.()), {
1687
- posts: y,
1688
- postsPending: u,
1779
+ return B(o, w, { immediate: !0 }), L(() => g?.()), {
1780
+ posts: b,
1781
+ postsPending: l,
1689
1782
  hasMore: d,
1690
1783
  loadingMore: f,
1691
1784
  loadError: p,
1692
- loadMore: S
1785
+ loadMore: C
1693
1786
  };
1694
1787
  }
1695
1788
  //#endregion
1696
1789
  //#region src/composables/useMemiBoardUserComments.ts
1697
- var ar = 10;
1698
- function or(e, t = {}) {
1699
- let n = Z(), r = () => P(), i = () => g(n, r()), a = t.pageSize ?? ar, o = I(() => z(e)?.trim() || ""), s = R([]), c = R([]), l = R(!0), u = R(!0), d = R(!1), f = R(""), p = null, m = null, h;
1700
- function _(e) {
1790
+ var vr = 10;
1791
+ function yr(e, t = {}) {
1792
+ let n = Q(), r = () => y(), i = () => pe(n, r()), a = t.pageSize ?? vr, o = I(() => z(e)?.trim() || ""), s = R([]), c = R([]), l = R(!0), u = R(!0), d = R(!1), f = R(""), p = null, m = null, h;
1793
+ function g(e) {
1701
1794
  return {
1702
1795
  id: e.id,
1703
1796
  ...e.data()
1704
1797
  };
1705
1798
  }
1706
- function v(e) {
1799
+ function _(e) {
1707
1800
  return e.createdAt?.toMillis?.() ?? 0;
1708
1801
  }
1709
- let y = I(() => {
1802
+ let v = I(() => {
1710
1803
  let e = /* @__PURE__ */ new Map();
1711
1804
  for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
1712
- return [...e.values()].sort((e, t) => v(t) - v(e) || String(t.id).localeCompare(String(e.id)));
1805
+ return [...e.values()].sort((e, t) => _(t) - _(e) || String(t.id).localeCompare(String(e.id)));
1713
1806
  });
1714
1807
  function b() {
1715
- return [X("authorUid", "==", o.value), X("listed", "==", !0)];
1808
+ return [Z("authorUid", "==", o.value), Z("listed", "==", !0)];
1716
1809
  }
1717
1810
  function x() {
1718
1811
  if (h?.(), !o.value) {
1719
1812
  l.value = !1;
1720
1813
  return;
1721
1814
  }
1722
- h = W(K(i(), ...b(), G("createdAt", "desc"), G(V(), "desc"), U(a)), (e) => {
1723
- s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
1815
+ h = G(q(i(), ...b(), K("createdAt", "desc"), K(H(), "desc"), W(a)), (e) => {
1816
+ s.value = e.docs.map(g), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a), l.value = !1;
1724
1817
  }, (e) => {
1725
1818
  console.error("[memi-board:userComments] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
1726
1819
  });
@@ -1731,11 +1824,11 @@ function or(e, t = {}) {
1731
1824
  try {
1732
1825
  let e = m ?? p, t = [
1733
1826
  ...b(),
1734
- G("createdAt", "desc"),
1735
- G(V(), "desc"),
1736
- ...e ? [J(e)] : [],
1737
- U(a + 1)
1738
- ], n = await H(K(i(), ...t)), r = n.docs.slice(0, a), o = r.map(_), l = new Set([...c.value, ...s.value].map((e) => e.id));
1827
+ K("createdAt", "desc"),
1828
+ K(H(), "desc"),
1829
+ ...e ? [Y(e)] : [],
1830
+ W(a + 1)
1831
+ ], n = await U(q(i(), ...t)), r = n.docs.slice(0, a), o = r.map(g), l = new Set([...c.value, ...s.value].map((e) => e.id));
1739
1832
  c.value.push(...o.filter((e) => !l.has(e.id))), m = r.at(-1) ?? m, u.value = n.docs.length > a;
1740
1833
  } catch (e) {
1741
1834
  f.value = e.message || String(e), console.error("[memi-board:userComments] loadMore failed", e);
@@ -1748,7 +1841,7 @@ function or(e, t = {}) {
1748
1841
  h?.(), s.value = [], c.value = [], p = null, m = null, u.value = !0, f.value = "", l.value = !0, x();
1749
1842
  }
1750
1843
  return B(o, C, { immediate: !0 }), L(() => h?.()), {
1751
- comments: y,
1844
+ comments: v,
1752
1845
  commentsPending: l,
1753
1846
  hasMore: u,
1754
1847
  loadingMore: d,
@@ -1758,48 +1851,48 @@ function or(e, t = {}) {
1758
1851
  }
1759
1852
  //#endregion
1760
1853
  //#region src/composables/useMemiBoardCommentFeed.ts
1761
- var sr = 10;
1762
- function cr(e = "latest", t = {}) {
1763
- let n = Z(), r = () => P(), i = () => g(n, r()), a = I(() => {
1854
+ var br = 10;
1855
+ function xr(e = "latest", t = {}) {
1856
+ let n = Q(), r = () => y(), i = () => pe(n, r()), a = I(() => {
1764
1857
  let e = Math.floor(Number(z(t.pageSize)));
1765
- return Number.isFinite(e) && e > 0 ? e : sr;
1858
+ return Number.isFinite(e) && e > 0 ? e : br;
1766
1859
  }), o = I(() => z(e) === "likes" ? "likes" : "latest"), s = R([]), c = R([]), l = R(!0), u = R(!0), d = R(!1), f = R(""), p = null, m = null, h;
1767
- function _(e) {
1860
+ function g(e) {
1768
1861
  return {
1769
1862
  id: e.id,
1770
1863
  ...e.data()
1771
1864
  };
1772
1865
  }
1773
- function v(e) {
1866
+ function _(e) {
1774
1867
  return e.createdAt?.toMillis?.() ?? 0;
1775
1868
  }
1776
- function y(e, t) {
1869
+ function v(e, t) {
1777
1870
  if (o.value === "likes") {
1778
1871
  let n = (t.likeCount ?? 0) - (e.likeCount ?? 0);
1779
1872
  if (n) return n;
1780
1873
  }
1781
- return v(t) - v(e) || String(t.id).localeCompare(String(e.id));
1874
+ return _(t) - _(e) || String(t.id).localeCompare(String(e.id));
1782
1875
  }
1783
1876
  let b = I(() => {
1784
1877
  let e = /* @__PURE__ */ new Map();
1785
1878
  for (let t of [...c.value, ...s.value]) t.id && e.set(t.id, t);
1786
- return [...e.values()].sort(y);
1879
+ return [...e.values()].sort(v);
1787
1880
  });
1788
1881
  function x() {
1789
1882
  return o.value === "likes" ? [
1790
- X("listed", "==", !0),
1791
- G("likeCount", "desc"),
1792
- G("createdAt", "desc"),
1793
- G(V(), "desc")
1883
+ Z("listed", "==", !0),
1884
+ K("likeCount", "desc"),
1885
+ K("createdAt", "desc"),
1886
+ K(H(), "desc")
1794
1887
  ] : [
1795
- X("listed", "==", !0),
1796
- G("createdAt", "desc"),
1797
- G(V(), "desc")
1888
+ Z("listed", "==", !0),
1889
+ K("createdAt", "desc"),
1890
+ K(H(), "desc")
1798
1891
  ];
1799
1892
  }
1800
1893
  function S() {
1801
- h?.(), h = W(K(i(), ...x(), U(a.value)), (e) => {
1802
- s.value = e.docs.map(_), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
1894
+ h?.(), h = G(q(i(), ...x(), W(a.value)), (e) => {
1895
+ s.value = e.docs.map(g), p = e.docs.at(-1) ?? null, m || (u.value = e.docs.length >= a.value), l.value = !1;
1803
1896
  }, (e) => {
1804
1897
  console.error("[memi-board:commentFeed] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
1805
1898
  });
@@ -1808,7 +1901,7 @@ function cr(e = "latest", t = {}) {
1808
1901
  if (!(d.value || !u.value || l.value)) {
1809
1902
  d.value = !0, f.value = "";
1810
1903
  try {
1811
- let e = m ?? p, t = await H(K(i(), ...x(), ...e ? [J(e)] : [], U(a.value + 1))), n = t.docs.slice(0, a.value), r = n.map(_), o = new Set([...c.value, ...s.value].map((e) => e.id));
1904
+ let e = m ?? p, t = await U(q(i(), ...x(), ...e ? [Y(e)] : [], W(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));
1812
1905
  c.value.push(...r.filter((e) => !o.has(e.id))), m = n.at(-1) ?? m, u.value = t.docs.length > a.value;
1813
1906
  } catch (e) {
1814
1907
  f.value = e.message || String(e), console.error("[memi-board:commentFeed] loadMore failed", e);
@@ -1832,32 +1925,32 @@ function cr(e = "latest", t = {}) {
1832
1925
  }
1833
1926
  //#endregion
1834
1927
  //#region src/composables/useMemiBoardAuthorMemo.ts
1835
- var lr = 100, ur = /* @__PURE__ */ new Map();
1836
- function $(e) {
1837
- let t = ur.get(e);
1838
- return t || (t = pe({
1928
+ var Sr = 100, Cr = /* @__PURE__ */ new Map();
1929
+ function wr(e) {
1930
+ let t = Cr.get(e);
1931
+ return t || (t = me({
1839
1932
  text: "",
1840
1933
  sentiment: null,
1841
1934
  loaded: !1,
1842
1935
  pending: !1,
1843
1936
  saving: !1,
1844
1937
  error: ""
1845
- }), ur.set(e, t)), t;
1938
+ }), Cr.set(e, t)), t;
1846
1939
  }
1847
- function dr(e) {
1848
- let t = Z(), n = () => P(), { user: r } = Wt(), { t: i, formatNumber: a } = N(), o = I(() => z(e)), s = I(() => `${r.value?.uid ?? ""}:${o.value}`), c = I(() => {
1940
+ function Tr(e) {
1941
+ let t = Q(), n = () => y(), { user: r } = Wt(), { t: i, formatNumber: a } = O(), o = I(() => z(e)), s = I(() => `${r.value?.uid ?? ""}:${o.value}`), c = I(() => {
1849
1942
  let e = r.value?.uid, i = o.value;
1850
- return !e || !i ? null : f(t, n(), e, i);
1943
+ return !e || !i ? null : p(t, n(), e, i);
1851
1944
  }), l = I({
1852
- get: () => $(s.value).text,
1945
+ get: () => wr(s.value).text,
1853
1946
  set: (e) => {
1854
- $(s.value).text = e;
1947
+ wr(s.value).text = e;
1855
1948
  }
1856
- }), u = I(() => $(s.value).sentiment), d = I(() => $(s.value).loaded), p = I(() => $(s.value).pending), m = I(() => $(s.value).saving), h = I(() => $(s.value).error);
1949
+ }), u = I(() => wr(s.value).sentiment), d = I(() => wr(s.value).loaded), f = I(() => wr(s.value).pending), m = I(() => wr(s.value).saving), h = I(() => wr(s.value).error);
1857
1950
  async function g() {
1858
1951
  let e = c.value;
1859
1952
  if (!e) return;
1860
- let t = $(s.value);
1953
+ let t = wr(s.value);
1861
1954
  t.pending = !0, t.error = "";
1862
1955
  try {
1863
1956
  let n = (await xe(e)).data();
@@ -1873,13 +1966,13 @@ function dr(e) {
1873
1966
  if (!n) return;
1874
1967
  let r = e.trim();
1875
1968
  if (r.length > 100) throw Error(i("authorMemo.tooLong", { max: a(100) }));
1876
- let o = $(s.value);
1969
+ let o = wr(s.value);
1877
1970
  o.saving = !0, o.error = "";
1878
1971
  try {
1879
1972
  await De(n, {
1880
1973
  text: r,
1881
1974
  sentiment: t,
1882
- updatedAt: q()
1975
+ updatedAt: J()
1883
1976
  }), o.text = r, o.sentiment = t, o.loaded = !0;
1884
1977
  } catch (e) {
1885
1978
  throw o.error = e.message || String(e), console.error("[memi-board:authorMemo] save failed", e), e;
@@ -1890,10 +1983,10 @@ function dr(e) {
1890
1983
  async function v() {
1891
1984
  let e = c.value;
1892
1985
  if (!e) return;
1893
- let t = $(s.value);
1986
+ let t = wr(s.value);
1894
1987
  t.saving = !0, t.error = "";
1895
1988
  try {
1896
- await ge(e), t.text = "", t.sentiment = null, t.loaded = !0;
1989
+ await _e(e), t.text = "", t.sentiment = null, t.loaded = !0;
1897
1990
  } catch (e) {
1898
1991
  throw t.error = e.message || String(e), console.error("[memi-board:authorMemo] remove failed", e), e;
1899
1992
  } finally {
@@ -1904,7 +1997,7 @@ function dr(e) {
1904
1997
  text: l,
1905
1998
  sentiment: u,
1906
1999
  loaded: d,
1907
- pending: p,
2000
+ pending: f,
1908
2001
  saving: m,
1909
2002
  error: h,
1910
2003
  load: g,
@@ -1914,7 +2007,7 @@ function dr(e) {
1914
2007
  }
1915
2008
  //#endregion
1916
2009
  //#region src/composables/useMemiBoardWritingAssistant.ts
1917
- var fr = 20, pr = 864e5, mr = 200, hr = {
2010
+ var Er = 20, Dr = 864e5, Or = 200, kr = {
1918
2011
  proofread: "맞춤법, 띄어쓰기, 문법 오류만 고쳐라. 의미와 말투는 바꾸지 마라.",
1919
2012
  polish: "뜻과 작성자의 말투를 유지하면서 더 자연스럽고 읽기 좋은 문장으로 다듬어라.",
1920
2013
  continue: "앞의 맥락과 말투에 맞는 내용을 과장 없이 한두 문단 이어서 작성하라.",
@@ -1923,7 +2016,7 @@ var fr = 20, pr = 864e5, mr = 200, hr = {
1923
2016
  "translate-ko": "자연스러운 한국어로 번역하라. 고유명사와 기술 용어는 정확히 유지하라.",
1924
2017
  title: "본문을 대표하는 간결한 한국어 제목 하나를 만들어라. 따옴표나 설명 없이 제목만 출력하라."
1925
2018
  };
1926
- function gr(e) {
2019
+ function Ar(e) {
1927
2020
  return {
1928
2021
  proofread: "Fix only spelling, spacing, and grammar errors. Do not change the meaning or tone.",
1929
2022
  polish: "Refine the text into more natural, readable sentences while keeping the meaning and the author's tone.",
@@ -1934,27 +2027,27 @@ function gr(e) {
1934
2027
  title: `Create one concise title in ${e} that represents the body. Output only the title, without quotes or explanation.`
1935
2028
  };
1936
2029
  }
1937
- function _r(e, t, n) {
1938
- let r = t === "ko", i = wn(t);
2030
+ function jr(e, t, n) {
2031
+ let r = t === "ko", i = Ln(t);
1939
2032
  if (e.action !== "custom") {
1940
- if (r) return hr[e.action];
1941
- let t = gr(i)[e.action];
2033
+ if (r) return kr[e.action];
2034
+ let t = Ar(i)[e.action];
1942
2035
  return e.action === "translate-en" || e.action === "translate-ko" || e.action === "title" ? t : `${t} Write the result in the same language as the original text; if unclear, write in ${i}.`;
1943
2036
  }
1944
- let a = e.customInstruction?.trim().slice(0, mr);
2037
+ let a = e.customInstruction?.trim().slice(0, Or);
1945
2038
  if (!a) throw Error(n("writingAssistant.customRequired"));
1946
2039
  return r ? `뜻은 유지하면서 다음 스타일 지시를 반영해 다시 써라: ${a}` : `Rewrite the text applying the following style instruction while keeping the meaning: ${a}`;
1947
2040
  }
1948
- function vr(e) {
2041
+ function Mr(e) {
1949
2042
  return e.trim().replace(/^```(?:html|text)?\s*/i, "").replace(/\s*```$/, "").trim();
1950
2043
  }
1951
- function yr(e) {
2044
+ function Nr(e) {
1952
2045
  return !e || typeof e != "object" ? null : "toMillis" in e && typeof e.toMillis == "function" ? e.toMillis() : null;
1953
2046
  }
1954
- function br(e = {}) {
1955
- let t = N(), n = I(() => F(z(e.locale)) ?? t.locale.value), r = (e, t) => M(n.value, e, t), i = Me(), a = Z(), o = Ae(), s = v(), { translateEntries: c, translateHtml: l, detectSourceLocale: u } = Un();
1956
- function d(e, t) {
1957
- let n = yr(e.aiWritingWindowAt), r = n != null && t - n < pr, i = Math.max(0, Math.floor(Number(e.aiWritingCount) || 0)), a = Math.max(0, Math.floor(Number(e.aiWritingPending) || 0));
2047
+ function Pr(e = {}) {
2048
+ let t = O(), n = I(() => D(z(e.locale)) ?? t.locale.value), r = (e, t) => j(n.value, e, t), o = Me(), s = Q(), c = Ae(), l = i(), { translateEntries: u, translateHtml: d, detectSourceLocale: f } = nr();
2049
+ function p(e, t) {
2050
+ let n = Nr(e.aiWritingWindowAt), r = n != null && t - n < Dr, i = Math.max(0, Math.floor(Number(e.aiWritingCount) || 0)), a = Math.max(0, Math.floor(Number(e.aiWritingPending) || 0));
1958
2051
  return {
1959
2052
  active: r,
1960
2053
  windowAt: n,
@@ -1962,68 +2055,68 @@ function br(e = {}) {
1962
2055
  pending: r ? a : 0
1963
2056
  };
1964
2057
  }
1965
- function f(e, t) {
1966
- let n = e + pr, i = Math.max(1, Math.ceil((n - t) / 36e5));
2058
+ function m(e, t) {
2059
+ let n = e + Dr, i = Math.max(1, Math.ceil((n - t) / 36e5));
1967
2060
  return Error(r("writingAssistant.dailyLimit", {
1968
2061
  limit: 20,
1969
2062
  hours: i
1970
2063
  }));
1971
2064
  }
1972
- async function p(e) {
1973
- let t = o.value?.uid;
2065
+ async function h(e) {
2066
+ let t = c.value?.uid;
1974
2067
  if (!t) throw Error(r("writingAssistant.loginRequired"));
1975
- await Ee(a, async (n) => {
1976
- let i = h(a, P(), t), o = await n.get(i);
2068
+ await Ee(s, async (n) => {
2069
+ let i = a(s, y(), t), o = await n.get(i);
1977
2070
  if (!o.exists()) throw Error(r("writingAssistant.userMissing"));
1978
- let s = o.data(), c = e(d(s, Date.now()), s);
1979
- c && n.update(i, {
1980
- ...c,
1981
- updatedAt: q()
2071
+ let c = o.data(), l = e(p(c, Date.now()), c);
2072
+ l && n.update(i, {
2073
+ ...l,
2074
+ updatedAt: J()
1982
2075
  });
1983
2076
  });
1984
2077
  }
1985
- async function m() {
1986
- await p((e) => {
1987
- if (e.active && e.windowAt != null && e.count + e.pending >= 20) throw f(e.windowAt, Date.now());
2078
+ async function g() {
2079
+ await h((e) => {
2080
+ if (e.active && e.windowAt != null && e.count + e.pending >= 20) throw m(e.windowAt, Date.now());
1988
2081
  return e.active ? { aiWritingPending: e.pending + 1 } : {
1989
2082
  aiWritingCount: 0,
1990
2083
  aiWritingPending: 1,
1991
- aiWritingWindowAt: q()
2084
+ aiWritingWindowAt: J()
1992
2085
  };
1993
2086
  });
1994
2087
  }
1995
- async function g() {
1996
- await p((e) => !e.active || e.pending < 1 || e.count >= 20 ? null : {
2088
+ async function _() {
2089
+ await h((e) => !e.active || e.pending < 1 || e.count >= 20 ? null : {
1997
2090
  aiWritingCount: e.count + 1,
1998
2091
  aiWritingPending: e.pending - 1
1999
2092
  });
2000
2093
  }
2001
- async function _() {
2002
- await p((e) => !e.active || e.pending < 1 ? null : { aiWritingPending: e.pending - 1 });
2094
+ async function v() {
2095
+ await h((e) => !e.active || e.pending < 1 ? null : { aiWritingPending: e.pending - 1 });
2003
2096
  }
2004
- async function y(e) {
2005
- await m();
2097
+ async function b(e) {
2098
+ await g();
2006
2099
  try {
2007
2100
  let t = await e();
2008
2101
  try {
2009
- await g();
2102
+ await _();
2010
2103
  } catch {}
2011
2104
  return t;
2012
2105
  } catch (e) {
2013
- throw await _().catch(() => {}), e;
2106
+ throw await v().catch(() => {}), e;
2014
2107
  }
2015
2108
  }
2016
- async function b(e) {
2017
- (e.action === "translate-en" || e.action === "translate-ko") && D();
2018
- let t = n.value, a = t === "ko", o = _r(e, t, r);
2109
+ async function x(e) {
2110
+ (e.action === "translate-en" || e.action === "translate-ko") && F();
2111
+ let t = n.value, i = t === "ko", a = jr(e, t, r);
2019
2112
  if (!e.content.trim()) throw Error(r("writingAssistant.contentRequired"));
2020
- return y(async () => {
2021
- let t = s.moderation ?? {}, n = Xe(i, {
2113
+ return b(async () => {
2114
+ let t = l.moderation ?? {}, n = Xe(o, {
2022
2115
  backend: new Je(),
2023
2116
  useLimitedUseAppCheckTokens: t.useLimitedUseAppCheckTokens !== !1
2024
- }), c = Ze(n, {
2117
+ }), s = Ze(n, {
2025
2118
  model: t.model ?? "gemini-3.5-flash-lite",
2026
- systemInstruction: (a ? [
2119
+ systemInstruction: (i ? [
2027
2120
  "너는 게시판 글쓰기 편집 도우미다.",
2028
2121
  "사용자가 요청한 편집 결과만 출력하고 설명, 인사, 마크다운 코드 펜스를 붙이지 마라.",
2029
2122
  e.action === "title" || e.selection ? "출력은 일반 텍스트로 작성하라." : "입력의 HTML 구조와 링크, 이미지 태그를 보존하고 결과도 HTML 조각으로 출력하라."
@@ -2036,51 +2129,51 @@ function br(e = {}) {
2036
2129
  temperature: e.action === "continue" || e.action === "title" || e.action === "custom" ? .6 : .2,
2037
2130
  maxOutputTokens: 2048
2038
2131
  }
2039
- }), l = e.content.trim(), u = (a ? [
2040
- `작업: ${o}`,
2132
+ }), c = e.content.trim(), u = (i ? [
2133
+ `작업: ${a}`,
2041
2134
  e.title ? `현재 제목: ${e.title}` : "",
2042
- `본문:\n${l.slice(0, 12e3)}`
2135
+ `본문:\n${c.slice(0, 12e3)}`
2043
2136
  ] : [
2044
- `Task: ${o}`,
2137
+ `Task: ${a}`,
2045
2138
  e.title ? `Current title: ${e.title}` : "",
2046
- `Body:\n${l.slice(0, 12e3)}`
2047
- ]).filter(Boolean).join("\n\n"), d = vr((await c.generateContent(u)).response.text());
2139
+ `Body:\n${c.slice(0, 12e3)}`
2140
+ ]).filter(Boolean).join("\n\n"), d = Mr((await s.generateContent(u)).response.text());
2048
2141
  if (!d) throw Error(r("writingAssistant.emptyResult"));
2049
2142
  return d;
2050
2143
  });
2051
2144
  }
2052
- async function x(e) {
2053
- D();
2145
+ async function S(e) {
2146
+ F();
2054
2147
  let t = e.targets?.length ? e.targets : pt(), n = e.title?.trim() ?? "", i = e.summary?.trim() ?? "", a = e.content ?? "", o = {};
2055
2148
  n && (o.title = n), i && (o.summary = i);
2056
2149
  let s = !!ln(a);
2057
2150
  if (!Object.keys(o).length && !s) throw Error(r("writingAssistant.translateEmpty"));
2058
2151
  if (s && a.length > 12e3) throw Error(r("writingAssistant.translateTooLong", {
2059
- limit: Rn,
2152
+ limit: Zn,
2060
2153
  count: t.length
2061
2154
  }));
2062
- return y(async () => {
2063
- let d = e.source ?? await u([
2155
+ return b(async () => {
2156
+ let c = e.source ?? await f([
2064
2157
  ln(a),
2065
2158
  n,
2066
2159
  i
2067
- ].filter(Boolean).join("\n")), f = [...t, d], [p, m] = await Promise.all([Object.keys(o).length ? c([{
2160
+ ].filter(Boolean).join("\n")), l = [...t, c], [p, m] = await Promise.all([Object.keys(o).length ? u([{
2068
2161
  id: "post",
2069
2162
  fields: o,
2070
2163
  context: "message board post title and short summary"
2071
2164
  }], {
2072
- source: d,
2165
+ source: c,
2073
2166
  targets: t,
2074
2167
  purpose: "message board post title and short summary"
2075
- }) : Promise.resolve({}), s ? l(a, {
2076
- source: d,
2168
+ }) : Promise.resolve({}), s ? d(a, {
2169
+ source: c,
2077
2170
  targets: t
2078
- }) : Promise.resolve({})]), h = ft(d, o, p.post);
2079
- if (Object.keys(o).length && !ht(h, Object.keys(o), f)) throw Error(r("writingAssistant.translateIncomplete"));
2171
+ }) : Promise.resolve({})]), h = ft(c, o, p.post);
2172
+ if (Object.keys(o).length && !ht(h, Object.keys(o), l)) throw Error(r("writingAssistant.translateIncomplete"));
2080
2173
  let g = {
2081
2174
  i18n: h,
2082
2175
  i18nSource: {
2083
- locale: d,
2176
+ locale: c,
2084
2177
  title: n,
2085
2178
  summary: i
2086
2179
  }
@@ -2088,26 +2181,26 @@ function br(e = {}) {
2088
2181
  if (s) {
2089
2182
  let e = {};
2090
2183
  for (let [t, n] of Object.entries(m)) {
2091
- let r = F(t);
2184
+ let r = D(t);
2092
2185
  r && typeof n == "string" && n.trim() && (e[r] = { content: n.trim() });
2093
2186
  }
2094
- let t = ft(d, { content: a }, e);
2095
- if (!ht(t, ["content"], f)) throw Error(r("writingAssistant.translateIncomplete"));
2187
+ let t = ft(c, { content: a }, e);
2188
+ if (!ht(t, ["content"], l)) throw Error(r("writingAssistant.translateIncomplete"));
2096
2189
  g.contentI18n = t, g.contentI18nSource = {
2097
- locale: d,
2190
+ locale: c,
2098
2191
  hash: ct(a)
2099
2192
  };
2100
2193
  }
2101
2194
  return g;
2102
2195
  });
2103
2196
  }
2104
- async function S(e) {
2105
- D();
2197
+ async function C(e) {
2198
+ F();
2106
2199
  let t = e.body.trim();
2107
2200
  if (!t) throw Error(r("writingAssistant.translateEmpty"));
2108
2201
  let n = e.targets?.length ? e.targets : pt();
2109
- return y(async () => {
2110
- let e = await u(t), i = await c([{
2202
+ return b(async () => {
2203
+ let e = await f(t), i = await u([{
2111
2204
  id: "comment",
2112
2205
  fields: { body: t },
2113
2206
  context: "message board comment or reply, plain text"
@@ -2127,226 +2220,226 @@ function br(e = {}) {
2127
2220
  });
2128
2221
  }
2129
2222
  return {
2130
- assist: b,
2131
- translatePost: x,
2132
- translateComment: S
2223
+ assist: x,
2224
+ translatePost: S,
2225
+ translateComment: C
2133
2226
  };
2134
2227
  }
2135
2228
  //#endregion
2136
2229
  //#region src/utils/subscribeCommentRange.ts
2137
- function xr(e, t, n, r, i, a) {
2138
- return W(K(g(e, t), X("postId", "==", n), ...r.rootId ? [X("rootId", "==", r.rootId), X("isReply", "==", !0)] : [X("parentId", "==", null)], G("createdAt", "asc"), G(V(), "asc"), ...r.hasMore && r.cursor ? [ye(r.cursor)] : []), (e) => i(e.docs.map((e) => ({
2230
+ function Fr(e, t, n, r, i, a) {
2231
+ return G(q(pe(e, t), Z("postId", "==", n), ...r.rootId ? [Z("rootId", "==", r.rootId), Z("isReply", "==", !0)] : [Z("parentId", "==", null)], K("createdAt", "asc"), K(H(), "asc"), ...r.hasMore && r.cursor ? [ye(r.cursor)] : []), (e) => i(e.docs.map((e) => ({
2139
2232
  ...e.data(),
2140
2233
  id: e.id
2141
2234
  }))), a);
2142
2235
  }
2143
2236
  //#endregion
2144
2237
  //#region src/composables/useMemiBoardComments.ts
2145
- var Sr = 10, Cr = 5, wr = 1e3;
2146
- function Tr(e, { t, formatNumber: n }) {
2238
+ var Ir = 10, Lr = 5, Rr = 1e3;
2239
+ function zr(e, { t, formatNumber: n }) {
2147
2240
  let r = e.trim();
2148
2241
  if (!r) throw Error(t("comments.bodyRequired"));
2149
- if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(wr) }));
2242
+ if (r.length > 1e3) throw Error(t("comments.bodyTooLong", { max: n(Rr) }));
2150
2243
  return r;
2151
2244
  }
2152
- function Er(e, t, r = {}) {
2153
- let i = Z(), a = Me(), o = () => P(), { isBoardHidden: s, getBoard: c } = Jn(), { translateComment: l } = br(), u, f = R(!1);
2154
- async function p(e, t) {
2155
- if (f.value = !1, !n()) return {};
2245
+ function Br(e, t, n = {}) {
2246
+ let r = Q(), i = Me(), a = () => y(), { isBoardHidden: s, getBoard: c } = sr(), { translateComment: l } = Pr(), u, d = R(!1);
2247
+ async function f(e, t) {
2248
+ if (d.value = !1, !de()) return {};
2156
2249
  if (t?.i18nSource.body === e) return t;
2157
- if (c(v.value)?.autoTranslatePosts !== !0) return {};
2250
+ if (c(g.value)?.autoTranslatePosts !== !0) return {};
2158
2251
  if (u?.i18nSource.body !== e) try {
2159
2252
  u = await l({
2160
2253
  body: e,
2161
- targets: pt(c(v.value))
2254
+ targets: pt(c(g.value))
2162
2255
  });
2163
2256
  } catch (e) {
2164
- return import.meta.dev && console.warn("[memi-board] comment auto-translation skipped", e), f.value = !0, {};
2257
+ return import.meta.dev && console.warn("[memi-board] comment auto-translation skipped", e), d.value = !0, {};
2165
2258
  }
2166
2259
  return u;
2167
2260
  }
2168
- let m = N(), { t: h } = m, _ = () => g(i, o()), v = I(() => z(e)), b = I(() => z(t)), S = () => !s(v.value), C = R([]), w = R(r.subscribe !== !1), T = R([]), E = R(!1), D = R(r.subscribe !== !1), ee = R(r.subscribe !== !1), O = null, k = 0, A = 0, j;
2169
- function te(e) {
2261
+ let p = O(), { t: m } = p, h = () => pe(r, a()), g = I(() => z(e)), v = I(() => z(t)), b = () => !s(g.value), x = R([]), C = R(n.subscribe !== !1), w = R([]), T = R(!1), E = R(n.subscribe !== !1), D = R(n.subscribe !== !1), k = null, A = 0, ee = 0, j;
2262
+ function M(e) {
2170
2263
  return e.createdAt?.toMillis?.() ?? 0;
2171
2264
  }
2172
- let ne = I(() => {
2265
+ let te = I(() => {
2173
2266
  let e = /* @__PURE__ */ new Map();
2174
- for (let t of [...C.value, ...T.value]) t.id && e.set(t.id, t);
2175
- return [...e.values()].sort((e, t) => te(e) - te(t) || String(e.id).localeCompare(String(t.id)));
2267
+ for (let t of [...x.value, ...w.value]) t.id && e.set(t.id, t);
2268
+ return [...e.values()].sort((e, t) => M(e) - M(t) || String(e.id).localeCompare(String(t.id)));
2176
2269
  });
2177
- B([b, v], async ([e]) => {
2178
- let t = ++k;
2179
- if (A++, E.value = !1, T.value = [], C.value = [], O = null, j?.(), j = void 0, D.value = r.subscribe !== !1, r.subscribe !== !1) {
2180
- w.value = !0, ee.value = !0;
2270
+ B([v, g], async ([e]) => {
2271
+ let t = ++A;
2272
+ if (ee++, T.value = !1, w.value = [], x.value = [], k = null, j?.(), j = void 0, E.value = n.subscribe !== !1, n.subscribe !== !1) {
2273
+ C.value = !0, D.value = !0;
2181
2274
  try {
2182
- let n = H(K(_(), X("postId", "==", e), G("createdAt", "desc"), G(V(), "desc")));
2275
+ let n = U(q(h(), Z("postId", "==", e), K("createdAt", "desc"), K(H(), "desc")));
2183
2276
  if (await Promise.all([n.then((e) => {
2184
- if (t !== k) return;
2277
+ if (t !== A) return;
2185
2278
  let n = e.docs.map((e) => ({
2186
2279
  id: e.id,
2187
2280
  ...e.data()
2188
2281
  }));
2189
- C.value = n.filter((e) => e.parentId === void 0);
2190
- }), M()]), t !== k) return;
2282
+ x.value = n.filter((e) => e.parentId === void 0);
2283
+ }), re()]), t !== A) return;
2191
2284
  } finally {
2192
- t === k && (w.value = !1, ee.value = !1);
2285
+ t === A && (C.value = !1, D.value = !1);
2193
2286
  }
2194
2287
  }
2195
2288
  }, { immediate: !0 });
2196
- function re() {
2289
+ function ne() {
2197
2290
  j?.();
2198
- let e = ++A;
2199
- j = xr(i, o(), b.value, {
2200
- cursor: O,
2201
- hasMore: D.value
2291
+ let e = ++ee;
2292
+ j = Fr(r, a(), v.value, {
2293
+ cursor: k,
2294
+ hasMore: E.value
2202
2295
  }, (t) => {
2203
- e === A && (T.value = t);
2296
+ e === ee && (w.value = t);
2204
2297
  }, (e) => {
2205
2298
  console.error("[memi-board:comments] onSnapshot failed", e);
2206
2299
  });
2207
2300
  }
2208
- async function M() {
2209
- if (E.value || !D.value) return;
2210
- let e = k;
2211
- E.value = !0;
2301
+ async function re() {
2302
+ if (T.value || !E.value) return;
2303
+ let e = A;
2304
+ T.value = !0;
2212
2305
  try {
2213
2306
  let t = [
2214
- X("postId", "==", b.value),
2215
- X("parentId", "==", null),
2216
- G("createdAt", "asc"),
2217
- G(V(), "asc"),
2218
- ...O ? [J(O)] : [],
2219
- U(11)
2220
- ], n = await H(K(_(), ...t));
2221
- if (e !== k) return;
2222
- let r = n.docs.slice(0, Sr), i = r.map((e) => ({
2307
+ Z("postId", "==", v.value),
2308
+ Z("parentId", "==", null),
2309
+ K("createdAt", "asc"),
2310
+ K(H(), "asc"),
2311
+ ...k ? [Y(k)] : [],
2312
+ W(11)
2313
+ ], n = await U(q(h(), ...t));
2314
+ if (e !== A) return;
2315
+ let r = n.docs.slice(0, Ir), i = r.map((e) => ({
2223
2316
  id: e.id,
2224
2317
  ...e.data()
2225
- })), a = new Set(T.value.map((e) => e.id));
2226
- T.value.push(...i.filter((e) => !a.has(e.id))), O = r.at(-1) ?? O, D.value = n.size > Sr, re();
2318
+ })), a = new Set(w.value.map((e) => e.id));
2319
+ w.value.push(...i.filter((e) => !a.has(e.id))), k = r.at(-1) ?? k, E.value = n.size > Ir, ne();
2227
2320
  } finally {
2228
- e === k && (E.value = !1);
2321
+ e === A && (T.value = !1);
2229
2322
  }
2230
2323
  }
2231
2324
  L(() => {
2232
- k++, A++, j?.();
2325
+ A++, ee++, j?.();
2233
2326
  });
2234
2327
  function ie() {
2235
- return ve(_()).id;
2328
+ return ve(h()).id;
2236
2329
  }
2237
2330
  function ae(e) {
2238
- if (!e) return ve(_());
2239
- if (!/^[A-Za-z0-9]{10,128}$/.test(e)) throw Error(h("commentForm.uploadFailed"));
2240
- return d(i, o(), e);
2331
+ if (!e) return ve(h());
2332
+ if (!/^[A-Za-z0-9]{10,128}$/.test(e)) throw Error(m("commentForm.uploadFailed"));
2333
+ return _(r, a(), e);
2241
2334
  }
2242
- function oe(e, t) {
2243
- let n = `${x(o(), b.value)}/comment-images/${e}/`;
2335
+ function N(e, t) {
2336
+ let n = `${o(a(), v.value)}/comment-images/${e}/`;
2244
2337
  return se(t).filter((e) => e.path.startsWith(n));
2245
2338
  }
2246
- async function le(e, t) {
2247
- let n = oe(t, e.images), r = Tr(e.body, m);
2339
+ async function oe(e, t) {
2340
+ let n = N(t, e.images), r = zr(e.body, p);
2248
2341
  return {
2249
- postId: b.value,
2250
- boardId: v.value,
2251
- listed: S(),
2342
+ postId: v.value,
2343
+ boardId: g.value,
2344
+ listed: b(),
2252
2345
  body: r,
2253
- ...await p(r, e.translations),
2346
+ ...await f(r, e.translations),
2254
2347
  authorUid: e.authorUid,
2255
2348
  authorName: e.authorName,
2256
2349
  authorPhoto: e.authorPhoto,
2257
2350
  moderationStatus: "approved",
2258
2351
  replyCount: 0,
2259
2352
  likeCount: 0,
2260
- createdAt: q(),
2261
- updatedAt: q(),
2353
+ createdAt: J(),
2354
+ updatedAt: J(),
2262
2355
  ...n.length ? { images: n } : {}
2263
2356
  };
2264
2357
  }
2265
- async function ue(e) {
2358
+ async function ce(e) {
2266
2359
  if (!e.length) return;
2267
- let t = We(a);
2360
+ let t = We(i);
2268
2361
  await Promise.all(e.map((e) => He(qe(t, e)).catch(() => {})));
2269
2362
  }
2270
- async function de(e) {
2271
- let t = Oe(i), n = ae(e.id);
2363
+ async function ue(e) {
2364
+ let t = Oe(r), n = ae(e.id);
2272
2365
  t.set(n, {
2273
- ...await le(e, n.id),
2366
+ ...await oe(e, n.id),
2274
2367
  parentId: null,
2275
2368
  rootId: n.id,
2276
2369
  depth: 0,
2277
2370
  replyToUid: null,
2278
2371
  replyToName: null,
2279
2372
  isReply: !1
2280
- }), t.update(y(i, o(), b.value), { commentCount: we(1) }), await t.commit();
2373
+ }), t.update(S(r, a(), v.value), { commentCount: we(1) }), await t.commit();
2281
2374
  }
2282
- async function F(e) {
2283
- if (!e.parent.id) throw Error(h("comments.replyTargetNotFound"));
2284
- let t = Oe(i), n = ae(e.id), r = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
2285
- if (!r) throw Error(h("comments.threadNotFound"));
2286
- let a = Math.min((e.parent.depth ?? 0) + 1, 2);
2375
+ async function P(e) {
2376
+ if (!e.parent.id) throw Error(m("comments.replyTargetNotFound"));
2377
+ let t = Oe(r), n = ae(e.id), i = e.parent.parentId == null ? e.parent.id : e.parent.rootId;
2378
+ if (!i) throw Error(m("comments.threadNotFound"));
2379
+ let o = Math.min((e.parent.depth ?? 0) + 1, 2);
2287
2380
  t.set(n, {
2288
- ...await le(e, n.id),
2381
+ ...await oe(e, n.id),
2289
2382
  parentId: e.parent.id,
2290
- rootId: r,
2291
- depth: a,
2383
+ rootId: i,
2384
+ depth: o,
2292
2385
  replyToUid: e.parent.authorUid,
2293
2386
  replyToName: e.parent.authorName,
2294
2387
  isReply: !0
2295
- }), t.update(d(i, o(), r), { replyCount: we(1) }), t.update(y(i, o(), b.value), { commentCount: we(1) }), await t.commit();
2388
+ }), t.update(_(r, a(), i), { replyCount: we(1) }), t.update(S(r, a(), v.value), { commentCount: we(1) }), await t.commit();
2296
2389
  }
2297
- async function fe(e) {
2390
+ async function F(e) {
2298
2391
  if (!e.id) return;
2299
- if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(h("comments.hasRepliesCannotDelete"));
2300
- let t = ce(e.images, `${x(o(), b.value)}/comment-images/${e.id}/`);
2301
- await sn(i, o(), e.id);
2302
- let n = Oe(i);
2303
- n.delete(d(i, o(), e.id)), e.parentId && e.rootId && n.update(d(i, o(), e.rootId), { replyCount: we(-1) }), n.update(y(i, o(), b.value), { commentCount: we(-1) }), await n.commit(), await ue(t), T.value = T.value.filter((t) => t.id !== e.id), C.value = C.value.filter((t) => t.id !== e.id);
2304
- }
2305
- async function pe(e, t, n, r) {
2306
- let a = Tr(t, m), s = {
2307
- body: a,
2308
- updatedAt: q()
2392
+ if (e.parentId == null && (e.replyCount ?? 0) > 0) throw Error(m("comments.hasRepliesCannotDelete"));
2393
+ let t = le(e.images, `${o(a(), v.value)}/comment-images/${e.id}/`);
2394
+ await sn(r, a(), e.id);
2395
+ let n = Oe(r);
2396
+ n.delete(_(r, a(), e.id)), e.parentId && e.rootId && n.update(_(r, a(), e.rootId), { replyCount: we(-1) }), n.update(S(r, a(), v.value), { commentCount: we(-1) }), await n.commit(), await ce(t), w.value = w.value.filter((t) => t.id !== e.id), x.value = x.value.filter((t) => t.id !== e.id);
2397
+ }
2398
+ async function fe(e, t, n, i) {
2399
+ let o = zr(t, p), s = {
2400
+ body: o,
2401
+ updatedAt: J()
2309
2402
  };
2310
2403
  if (n !== void 0) {
2311
- let t = oe(e, n);
2312
- s.images = t.length ? t : _e();
2404
+ let t = N(e, n);
2405
+ s.images = t.length ? t : V();
2313
2406
  }
2314
- await Y(d(i, o(), e), {
2407
+ await X(_(r, a(), e), {
2315
2408
  ...s,
2316
- ...await p(a, r)
2409
+ ...await f(o, i)
2317
2410
  });
2318
2411
  }
2319
2412
  async function me(e, t, n) {
2320
- await Y(d(i, o(), e), {
2413
+ await X(_(r, a(), e), {
2321
2414
  isBlinded: t,
2322
- moderatedAt: q(),
2415
+ moderatedAt: J(),
2323
2416
  moderatedBy: n
2324
2417
  });
2325
2418
  }
2326
2419
  return {
2327
- comments: ne,
2328
- commentsPending: I(() => ee.value || w.value),
2329
- hasMore: D,
2330
- loadingMore: E,
2331
- loadMore: M,
2420
+ comments: te,
2421
+ commentsPending: I(() => D.value || C.value),
2422
+ hasMore: E,
2423
+ loadingMore: T,
2424
+ loadMore: re,
2332
2425
  newCommentId: ie,
2333
- translationSkipped: f,
2334
- addComment: de,
2335
- addReply: F,
2336
- updateComment: pe,
2426
+ translationSkipped: d,
2427
+ addComment: ue,
2428
+ addReply: P,
2429
+ updateComment: fe,
2337
2430
  setCommentBlinded: me,
2338
- deleteComment: fe
2431
+ deleteComment: F
2339
2432
  };
2340
2433
  }
2341
- function Dr(e, t, n) {
2342
- let r = Z(), i = () => P(), a = () => g(r, i()), o = t.trim(), s = R([]), c = R(!1), l = R(!1), u = R(!0), d = null, f, p = 0, m = 0;
2434
+ function Vr(e, t, n) {
2435
+ let r = Q(), i = () => y(), a = () => pe(r, i()), o = t.trim(), s = R([]), c = R(!1), l = R(!1), u = R(!0), d = null, f, p = 0, m = 0;
2343
2436
  function h(e) {
2344
2437
  return e.sort((e, t) => (e.createdAt?.toMillis?.() ?? 0) - (t.createdAt?.toMillis?.() ?? 0) || String(e.id).localeCompare(String(t.id)));
2345
2438
  }
2346
- function _() {
2439
+ function g() {
2347
2440
  f?.();
2348
2441
  let e = ++m;
2349
- f = xr(r, i(), o, {
2442
+ f = Fr(r, i(), o, {
2350
2443
  rootId: n,
2351
2444
  cursor: d,
2352
2445
  hasMore: u.value
@@ -2356,35 +2449,35 @@ function Dr(e, t, n) {
2356
2449
  console.error("[memi-board:replies] onSnapshot failed", e);
2357
2450
  });
2358
2451
  }
2359
- async function v() {
2452
+ async function _() {
2360
2453
  if (c.value || !u.value) return;
2361
2454
  let e = p;
2362
2455
  c.value = !0;
2363
2456
  try {
2364
2457
  let t = [
2365
- X("postId", "==", o),
2366
- X("rootId", "==", n),
2367
- X("isReply", "==", !0),
2368
- G("createdAt", "asc"),
2369
- G(V(), "asc"),
2370
- ...d ? [J(d)] : [],
2371
- U(6)
2372
- ], r = await H(K(a(), ...t));
2458
+ Z("postId", "==", o),
2459
+ Z("rootId", "==", n),
2460
+ Z("isReply", "==", !0),
2461
+ K("createdAt", "asc"),
2462
+ K(H(), "asc"),
2463
+ ...d ? [Y(d)] : [],
2464
+ W(6)
2465
+ ], r = await U(q(a(), ...t));
2373
2466
  if (e !== p) return;
2374
- let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0, Cr), f = c.map((e) => ({
2467
+ let i = new Set(s.value.map((e) => e.id)), c = r.docs.slice(0, Lr), f = c.map((e) => ({
2375
2468
  id: e.id,
2376
2469
  ...e.data()
2377
2470
  })).filter((e) => !i.has(e.id));
2378
- s.value = h([...s.value, ...f]), d = c.at(-1) ?? d, l.value = !0, u.value = r.size > Cr, _();
2471
+ s.value = h([...s.value, ...f]), d = c.at(-1) ?? d, l.value = !0, u.value = r.size > Lr, g();
2379
2472
  } finally {
2380
2473
  e === p && (c.value = !1);
2381
2474
  }
2382
2475
  }
2383
- function y() {
2476
+ function v() {
2384
2477
  p++, m++, c.value = !1, f?.(), f = void 0, s.value = [], d = null, l.value = !1, u.value = !0;
2385
2478
  }
2386
2479
  async function b() {
2387
- y(), await v();
2480
+ v(), await _();
2388
2481
  }
2389
2482
  return L(() => {
2390
2483
  p++, m++, f?.();
@@ -2393,106 +2486,106 @@ function Dr(e, t, n) {
2393
2486
  loading: c,
2394
2487
  loaded: l,
2395
2488
  hasMore: u,
2396
- loadMore: v,
2489
+ loadMore: _,
2397
2490
  refresh: b
2398
2491
  };
2399
2492
  }
2400
2493
  //#endregion
2401
2494
  //#region src/composables/useMemiBoardLikes.ts
2402
- function Or(e, t) {
2403
- let n = () => P(), r = Z(), i = Ae(), { t: a } = N(), o = R(!1), s = R(!1), c;
2404
- function l(e) {
2405
- return fe(r, n(), t, e);
2495
+ function Hr(e, n) {
2496
+ let r = () => y(), i = Q(), a = Ae(), { t: o } = O(), s = R(!1), c = R(!1), l;
2497
+ function u(e) {
2498
+ return t(i, r(), n, e);
2406
2499
  }
2407
- B(i, (e) => {
2408
- if (c?.(), c = void 0, !e) {
2409
- o.value = !1;
2500
+ B(a, (e) => {
2501
+ if (l?.(), l = void 0, !e) {
2502
+ s.value = !1;
2410
2503
  return;
2411
2504
  }
2412
- c = W(l(e.uid), (e) => {
2413
- o.value = e.exists();
2505
+ l = G(u(e.uid), (e) => {
2506
+ s.value = e.exists();
2414
2507
  }, (e) => {
2415
2508
  console.error("[memi-board:likes] onSnapshot failed", e);
2416
2509
  });
2417
- }, { immediate: !0 }), L(() => c?.());
2418
- async function u() {
2419
- let c = i.value?.uid;
2420
- if (!c) throw Error(a("likes.signInRequired"));
2421
- if (s.value) return o.value;
2422
- s.value = !0;
2510
+ }, { immediate: !0 }), L(() => l?.());
2511
+ async function d() {
2512
+ let t = a.value?.uid;
2513
+ if (!t) throw Error(o("likes.signInRequired"));
2514
+ if (c.value) return s.value;
2515
+ c.value = !0;
2423
2516
  try {
2424
- let i = l(c), a = y(r, n(), t);
2425
- return await Ee(r, async (n) => (await n.get(i)).exists() ? (n.delete(i), n.update(a, { likeCount: we(-1) }), !1) : (n.set(i, {
2426
- uid: c,
2427
- postId: t,
2517
+ let a = u(t), o = S(i, r(), n);
2518
+ return await Ee(i, async (r) => (await r.get(a)).exists() ? (r.delete(a), r.update(o, { likeCount: we(-1) }), !1) : (r.set(a, {
2519
+ uid: t,
2520
+ postId: n,
2428
2521
  boardId: e,
2429
- createdAt: q()
2430
- }), n.update(a, { likeCount: we(1) }), !0));
2522
+ createdAt: J()
2523
+ }), r.update(o, { likeCount: we(1) }), !0));
2431
2524
  } finally {
2432
- s.value = !1;
2525
+ c.value = !1;
2433
2526
  }
2434
2527
  }
2435
2528
  return {
2436
- isLiked: o,
2437
- likePending: s,
2438
- toggleLike: u
2529
+ isLiked: s,
2530
+ likePending: c,
2531
+ toggleLike: d
2439
2532
  };
2440
2533
  }
2441
- var kr = Symbol.for("memi-board:comment-likes");
2442
- function Ar(e, t) {
2443
- let n = () => P(), r = Z(), i = Ae(), { t: a } = N(), o = I(() => z(e)), s = I(() => z(t)), c = R(/* @__PURE__ */ new Set()), l = R(null), u;
2444
- B([i, s], ([e, t]) => {
2445
- u?.(), u = void 0, c.value = /* @__PURE__ */ new Set(), e && t && (u = W(K(b(r, n()), X("uid", "==", e.uid), X("postId", "==", t), X("target", "==", "comment")), (e) => {
2534
+ var Ur = Symbol.for("memi-board:comment-likes");
2535
+ function Wr(e, n) {
2536
+ let r = () => y(), i = Q(), a = Ae(), { t: o } = O(), c = I(() => z(e)), l = I(() => z(n)), u = R(/* @__PURE__ */ new Set()), d = R(null), f;
2537
+ B([a, l], ([e, t]) => {
2538
+ f?.(), f = void 0, u.value = /* @__PURE__ */ new Set(), e && t && (f = G(q(s(i, r()), Z("uid", "==", e.uid), Z("postId", "==", t), Z("target", "==", "comment")), (e) => {
2446
2539
  let t = /* @__PURE__ */ new Set();
2447
2540
  for (let n of e.docs) {
2448
2541
  let e = n.data().commentId;
2449
2542
  typeof e == "string" && e && t.add(e);
2450
2543
  }
2451
- c.value = t;
2544
+ u.value = t;
2452
2545
  }, (e) => {
2453
2546
  console.error("[memi-board:comment-likes] onSnapshot failed", e);
2454
2547
  }));
2455
- }, { immediate: !0 }), L(() => u?.());
2456
- function f(e) {
2457
- return !!e && c.value.has(e);
2458
- }
2548
+ }, { immediate: !0 }), L(() => f?.());
2459
2549
  function p(e) {
2460
- return !!e && l.value === e;
2550
+ return !!e && u.value.has(e);
2461
2551
  }
2462
- async function m(e) {
2463
- let t = i.value?.uid;
2464
- if (!t) throw Error(a("likes.signInRequired"));
2552
+ function m(e) {
2553
+ return !!e && d.value === e;
2554
+ }
2555
+ async function h(e) {
2556
+ let n = a.value?.uid;
2557
+ if (!n) throw Error(o("likes.signInRequired"));
2465
2558
  if (!e) return !1;
2466
- if (l.value) return f(e);
2467
- l.value = e;
2559
+ if (d.value) return p(e);
2560
+ d.value = e;
2468
2561
  try {
2469
- let i = fe(r, n(), e, t), l = d(r, n(), e), u = await Ee(r, async (n) => {
2470
- let r = await n.get(i), c = await n.get(l);
2471
- if (!c.exists()) throw Error(a("likes.commentNotFound"));
2472
- let u = Number(c.data()?.likeCount ?? 0);
2473
- return r.exists() ? (n.delete(i), n.update(l, { likeCount: Math.max(0, u - 1) }), !1) : (n.set(i, {
2474
- uid: t,
2475
- postId: s.value,
2476
- boardId: o.value,
2562
+ let a = t(i, r(), e, n), s = _(i, r(), e), d = await Ee(i, async (t) => {
2563
+ let r = await t.get(a), i = await t.get(s);
2564
+ if (!i.exists()) throw Error(o("likes.commentNotFound"));
2565
+ let u = Number(i.data()?.likeCount ?? 0);
2566
+ return r.exists() ? (t.delete(a), t.update(s, { likeCount: Math.max(0, u - 1) }), !1) : (t.set(a, {
2567
+ uid: n,
2568
+ postId: l.value,
2569
+ boardId: c.value,
2477
2570
  commentId: e,
2478
2571
  target: "comment",
2479
- createdAt: q()
2480
- }), n.update(l, { likeCount: u + 1 }), !0);
2481
- }), f = new Set(c.value);
2482
- return u ? f.add(e) : f.delete(e), c.value = f, u;
2572
+ createdAt: J()
2573
+ }), t.update(s, { likeCount: u + 1 }), !0);
2574
+ }), f = new Set(u.value);
2575
+ return d ? f.add(e) : f.delete(e), u.value = f, d;
2483
2576
  } finally {
2484
- l.value = null;
2577
+ d.value = null;
2485
2578
  }
2486
2579
  }
2487
2580
  return {
2488
- isLiked: f,
2489
- isPending: p,
2490
- toggleLike: m
2581
+ isLiked: p,
2582
+ isPending: m,
2583
+ toggleLike: h
2491
2584
  };
2492
2585
  }
2493
2586
  //#endregion
2494
2587
  //#region src/composables/useMemiBoardReports.ts
2495
- var jr = 200, Mr = [
2588
+ var Gr = 200, Kr = [
2496
2589
  {
2497
2590
  value: "spam",
2498
2591
  label: "스팸·광고"
@@ -2514,17 +2607,17 @@ var jr = 200, Mr = [
2514
2607
  label: "기타"
2515
2608
  }
2516
2609
  ];
2517
- function Nr(e, t) {
2518
- return Mr.some((t) => t.value === e) ? M(t, `reports.reason.${e}`) : e || M(t, "reports.fallbackLabel");
2610
+ function qr(e, t) {
2611
+ return Kr.some((t) => t.value === e) ? j(t, `reports.reason.${e}`) : e || j(t, "reports.fallbackLabel");
2519
2612
  }
2520
- function Pr(e, t) {
2521
- let n = () => P(), r = Z(), i = Ae(), { t: a } = N(), o = R(!1), s = R(!1), c;
2613
+ function Jr(e, t) {
2614
+ let n = () => y(), r = Q(), i = Ae(), { t: a } = O(), o = R(!1), s = R(!1), c;
2522
2615
  B(i, (e) => {
2523
2616
  if (c?.(), c = void 0, !e) {
2524
2617
  o.value = !1;
2525
2618
  return;
2526
2619
  }
2527
- c = W(u(r, n(), t, e.uid), (e) => {
2620
+ c = G(oe(r, n(), t, e.uid), (e) => {
2528
2621
  o.value = e.exists();
2529
2622
  }, (e) => {
2530
2623
  console.error("[memi-board:reports] onSnapshot failed", e);
@@ -2535,24 +2628,24 @@ function Pr(e, t) {
2535
2628
  if (!l) throw Error(a("reports.signInRequired"));
2536
2629
  if (s.value) return;
2537
2630
  if (c.authorUid && c.authorUid === l) throw Error(a("reports.cannotReportOwn"));
2538
- let d = Mr.some((e) => e.value === c.reason) ? c.reason : null;
2539
- if (!d) throw Error(a("reports.reasonRequired"));
2540
- let f = (c.detail || "").trim();
2541
- if (f.length > 200) throw Error(a("reports.detailTooLong", { max: 200 }));
2631
+ let u = Kr.some((e) => e.value === c.reason) ? c.reason : null;
2632
+ if (!u) throw Error(a("reports.reasonRequired"));
2633
+ let d = (c.detail || "").trim();
2634
+ if (d.length > 200) throw Error(a("reports.detailTooLong", { max: 200 }));
2542
2635
  s.value = !0;
2543
2636
  try {
2544
- await De(u(r, n(), t, l), {
2637
+ await De(oe(r, n(), t, l), {
2545
2638
  uid: l,
2546
2639
  target: "post",
2547
2640
  postId: t,
2548
2641
  boardId: e,
2549
- reason: d,
2550
- detail: f,
2642
+ reason: u,
2643
+ detail: d,
2551
2644
  status: "open",
2552
2645
  postTitle: (c.postTitle || "").trim().slice(0, 200),
2553
2646
  authorUid: c.authorUid || "",
2554
2647
  authorName: c.authorName ?? null,
2555
- createdAt: q()
2648
+ createdAt: J()
2556
2649
  }), o.value = !0;
2557
2650
  } finally {
2558
2651
  s.value = !1;
@@ -2564,64 +2657,64 @@ function Pr(e, t) {
2564
2657
  submitReport: l
2565
2658
  };
2566
2659
  }
2567
- var Fr = 20;
2568
- function Ir(e = {}) {
2569
- let t = () => P(), n = Z(), { isAdmin: r, canManageContent: i, canManageBoard: a } = Wt(), o = e.pageSize ?? Fr, s = I(() => z(e.boardId)?.trim() || ""), c = R([]), d = R(!0), f = R(!1), p = R(!1), m = R(""), h = null, g;
2570
- function _(e) {
2660
+ var Yr = 20;
2661
+ function Xr(e = {}) {
2662
+ let t = () => y(), n = Q(), { isAdmin: r, canManageContent: i, canManageBoard: a } = Wt(), o = e.pageSize ?? Yr, s = I(() => z(e.boardId)?.trim() || ""), c = R([]), l = R(!0), u = R(!1), d = R(!1), f = R(""), p = null, m;
2663
+ function h(e) {
2571
2664
  return {
2572
2665
  id: e.id,
2573
2666
  ...e.data()
2574
2667
  };
2575
2668
  }
2576
- function v() {
2577
- if (g?.(), !i.value || !r.value && !s.value) {
2578
- c.value = [], d.value = !1;
2669
+ function g() {
2670
+ if (m?.(), !i.value || !r.value && !s.value) {
2671
+ c.value = [], l.value = !1;
2579
2672
  return;
2580
2673
  }
2581
- d.value = !0;
2582
- let e = s.value ? [X("status", "==", "open"), X("boardId", "==", s.value)] : [X("status", "==", "open"), X("target", "==", "post")];
2583
- g = W(K(l(n, t()), ...e, G("createdAt", "desc"), G(V(), "desc"), U(o)), (e) => {
2584
- c.value = e.docs.map(_).filter((e) => a(e.boardId)), h = e.docs.at(-1) ?? null, p.value = e.docs.length >= o, d.value = !1;
2674
+ l.value = !0;
2675
+ let e = s.value ? [Z("status", "==", "open"), Z("boardId", "==", s.value)] : [Z("status", "==", "open"), Z("target", "==", "post")];
2676
+ m = G(q(w(n, t()), ...e, K("createdAt", "desc"), K(H(), "desc"), W(o)), (e) => {
2677
+ c.value = e.docs.map(h).filter((e) => a(e.boardId)), p = e.docs.at(-1) ?? null, d.value = e.docs.length >= o, l.value = !1;
2585
2678
  }, (e) => {
2586
- console.error("[memi-board:report-queue] onSnapshot failed", e), m.value = e.message || String(e), d.value = !1;
2679
+ console.error("[memi-board:report-queue] onSnapshot failed", e), f.value = e.message || String(e), l.value = !1;
2587
2680
  });
2588
2681
  }
2589
- B([i, s], v, { immediate: !0 }), L(() => g?.());
2590
- async function y() {
2591
- if (!f.value && p.value && h && i.value) {
2592
- f.value = !0, m.value = "";
2682
+ B([i, s], g, { immediate: !0 }), L(() => m?.());
2683
+ async function _() {
2684
+ if (!u.value && d.value && p && i.value) {
2685
+ u.value = !0, f.value = "";
2593
2686
  try {
2594
- let e = s.value ? [X("status", "==", "open"), X("boardId", "==", s.value)] : [X("status", "==", "open"), X("target", "==", "post")], r = await H(K(l(n, t()), ...e, G("createdAt", "desc"), G(V(), "desc"), J(h), U(o + 1))), i = r.docs.slice(0, o), u = new Set(c.value.map((e) => e.id));
2595
- c.value.push(...i.map(_).filter((e) => !u.has(e.id) && a(e.boardId))), h = i.at(-1) ?? h, p.value = r.docs.length > o;
2687
+ let e = s.value ? [Z("status", "==", "open"), Z("boardId", "==", s.value)] : [Z("status", "==", "open"), Z("target", "==", "post")], r = await U(q(w(n, t()), ...e, K("createdAt", "desc"), K(H(), "desc"), Y(p), W(o + 1))), i = r.docs.slice(0, o), l = new Set(c.value.map((e) => e.id));
2688
+ c.value.push(...i.map(h).filter((e) => !l.has(e.id) && a(e.boardId))), p = i.at(-1) ?? p, d.value = r.docs.length > o;
2596
2689
  } catch (e) {
2597
- m.value = e.message || String(e);
2690
+ f.value = e.message || String(e);
2598
2691
  } finally {
2599
- f.value = !1;
2692
+ u.value = !1;
2600
2693
  }
2601
2694
  }
2602
2695
  }
2603
- async function b(e, r) {
2604
- e.id && a(e.boardId) && await Y(u(n, t(), e.postId, e.uid), {
2696
+ async function v(e, r) {
2697
+ e.id && a(e.boardId) && await X(oe(n, t(), e.postId, e.uid), {
2605
2698
  status: r,
2606
- reviewedAt: q(),
2699
+ reviewedAt: J(),
2607
2700
  reviewedBy: Ae().value?.uid || ""
2608
2701
  });
2609
2702
  }
2610
2703
  return {
2611
2704
  reports: c,
2612
- pending: d,
2613
- loadingMore: f,
2614
- hasMore: p,
2615
- loadError: m,
2616
- loadMore: y,
2617
- dismissReport: (e) => b(e, "dismissed"),
2618
- actionReport: (e) => b(e, "actioned")
2705
+ pending: l,
2706
+ loadingMore: u,
2707
+ hasMore: d,
2708
+ loadError: f,
2709
+ loadMore: _,
2710
+ dismissReport: (e) => v(e, "dismissed"),
2711
+ actionReport: (e) => v(e, "actioned")
2619
2712
  };
2620
2713
  }
2621
2714
  //#endregion
2622
2715
  //#region src/composables/useMemiBoardViews.ts
2623
- function Lr() {
2624
- let e = () => P(), t = Z();
2716
+ function Zr() {
2717
+ let e = () => y(), t = Q();
2625
2718
  function n(t, n) {
2626
2719
  let { postsCollection: r } = e();
2627
2720
  return `memi-board:viewed:${r}:${t}:${n}`;
@@ -2644,7 +2737,7 @@ function Lr() {
2644
2737
  if (s && c && !r(s, c)) {
2645
2738
  i(s, c);
2646
2739
  try {
2647
- await Y(y(t, e(), c), { viewCount: we(1) });
2740
+ await X(S(t, e(), c), { viewCount: we(1) });
2648
2741
  } catch (e) {
2649
2742
  try {
2650
2743
  sessionStorage.removeItem(n(s, c));
@@ -2660,20 +2753,20 @@ function Lr() {
2660
2753
  }
2661
2754
  //#endregion
2662
2755
  //#region src/composables/useMemiBoardModeration.ts
2663
- var Rr = {
2756
+ var Qr = {
2664
2757
  flagged: !1,
2665
2758
  category: "none",
2666
2759
  reason: "",
2667
2760
  via: "empty"
2668
2761
  };
2669
- function zr(e = {}) {
2670
- let t = N(), n = I(() => F(z(e.locale)) ?? t.locale.value), r = v().moderation ?? {}, i = Me(), a = (e) => M(n.value, e), { isWriteRestricted: o, restrictedMessage: s, recordContentModerationBlock: c } = Wt(), l = Nn([...Mn, ...r.localBlocklist ?? []]);
2671
- function u(e) {
2672
- let t = e.match(l);
2762
+ function $r(e = {}) {
2763
+ let t = O(), n = I(() => D(z(e.locale)) ?? t.locale.value), r = i().moderation ?? {}, a = Me(), o = (e) => j(n.value, e), { isWriteRestricted: s, restrictedMessage: c, recordContentModerationBlock: l } = Wt(), u = Kn([...Gn, ...r.localBlocklist ?? []]);
2764
+ function d(e) {
2765
+ let t = e.match(u);
2673
2766
  return t ? {
2674
2767
  flagged: !0,
2675
2768
  category: "abuse",
2676
- reason: jn({
2769
+ reason: Wn({
2677
2770
  via: "local",
2678
2771
  localHit: t[0] || "",
2679
2772
  category: "abuse"
@@ -2681,14 +2774,14 @@ function zr(e = {}) {
2681
2774
  via: "local"
2682
2775
  } : null;
2683
2776
  }
2684
- function d() {
2685
- let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1, a = Xe(i, {
2777
+ function f() {
2778
+ let e = r.model ?? "gemini-3.5-flash-lite", t = r.useLimitedUseAppCheckTokens !== !1, i = Xe(a, {
2686
2779
  backend: new Je(),
2687
2780
  useLimitedUseAppCheckTokens: t
2688
2781
  });
2689
- return Ze(a, {
2782
+ return Ze(i, {
2690
2783
  model: e,
2691
- systemInstruction: En(n.value),
2784
+ systemInstruction: zn(n.value),
2692
2785
  generationConfig: {
2693
2786
  temperature: 0,
2694
2787
  maxOutputTokens: 256,
@@ -2701,11 +2794,11 @@ function zr(e = {}) {
2701
2794
  }
2702
2795
  });
2703
2796
  }
2704
- function f() {
2797
+ function p() {
2705
2798
  return r.onError === "block" ? {
2706
2799
  flagged: !0,
2707
2800
  category: "other",
2708
- reason: a("moderation.reviewFailed"),
2801
+ reason: o("moderation.reviewFailed"),
2709
2802
  error: !0,
2710
2803
  via: "ai-error-block"
2711
2804
  } : {
@@ -2716,8 +2809,8 @@ function zr(e = {}) {
2716
2809
  via: "ai-error-allow"
2717
2810
  };
2718
2811
  }
2719
- function p(e, t = "") {
2720
- let n = jn({
2812
+ function m(e, t = "") {
2813
+ let n = Wn({
2721
2814
  reason: e.reason,
2722
2815
  category: e.category,
2723
2816
  via: e.via
@@ -2727,98 +2820,94 @@ function zr(e = {}) {
2727
2820
  reason: r
2728
2821
  };
2729
2822
  }
2730
- async function m(e) {
2823
+ async function h(e) {
2731
2824
  if (!e.flagged || e.error || e.via !== "local" && e.via !== "ai") return e;
2732
2825
  try {
2733
- let { messageSuffix: t } = await c();
2734
- return p(e, t);
2826
+ let { messageSuffix: t } = await l();
2827
+ return m(e, t);
2735
2828
  } catch (t) {
2736
- return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t), p(e);
2829
+ return console.warn("[memi-board] record moderation strike failed", t instanceof Error ? t.message : t), m(e);
2737
2830
  }
2738
2831
  }
2739
- async function h(e, t) {
2740
- if (o.value) return {
2832
+ async function g(e) {
2833
+ if (s.value) return {
2741
2834
  flagged: !0,
2742
2835
  category: "other",
2743
- reason: s.value || a("moderation.writeRestricted"),
2836
+ reason: c.value || o("moderation.writeRestricted"),
2744
2837
  via: "restricted"
2745
2838
  };
2746
- let i = e.trim();
2747
- if (!i) return {
2748
- ...Rr,
2839
+ let t = e.trim();
2840
+ if (!t) return {
2841
+ ...Qr,
2749
2842
  via: "empty"
2750
2843
  };
2751
- if (t?.skipFilter) return {
2752
- ...Rr,
2753
- via: "admin-override"
2754
- };
2755
- let c = u(i);
2756
- if (c) return m(c);
2844
+ let i = d(t);
2845
+ if (i) return h(i);
2757
2846
  if (r.enabled === !1) return {
2758
- ...Rr,
2847
+ ...Qr,
2759
2848
  via: "disabled"
2760
2849
  };
2761
2850
  try {
2762
- let e = Fn((await d().generateContent(Dn(i, n.value))).response.text());
2763
- if (!e) return f();
2764
- let t = {
2851
+ let e = Jn((await f().generateContent(Bn(t, n.value))).response.text());
2852
+ if (!e) return p();
2853
+ let r = {
2765
2854
  flagged: e.flagged,
2766
2855
  category: e.category,
2767
- reason: jn({
2856
+ reason: Wn({
2768
2857
  reason: e.reason,
2769
2858
  category: e.category,
2770
2859
  via: "ai"
2771
2860
  }),
2772
2861
  via: "ai"
2773
2862
  };
2774
- return t.flagged ? m(t) : t;
2863
+ return r.flagged ? h(r) : r;
2775
2864
  } catch (e) {
2776
- return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e), f();
2865
+ return console.warn("[memi-board] moderation AI failed", e instanceof Error ? e.message : e), p();
2777
2866
  }
2778
2867
  }
2779
- async function g(e) {
2780
- if (o.value) return {
2868
+ async function _(e) {
2869
+ if (s.value) return {
2781
2870
  flagged: !0,
2782
2871
  category: "other",
2783
- reason: s.value || a("moderation.writeRestricted"),
2872
+ reason: c.value || o("moderation.writeRestricted"),
2784
2873
  via: "restricted"
2785
2874
  };
2786
2875
  if (r.enabled === !1 || !r.moderateImages) return {
2787
- ...Rr,
2876
+ ...Qr,
2788
2877
  via: "disabled"
2789
2878
  };
2790
2879
  try {
2791
2880
  let t = await new Promise((t, n) => {
2792
2881
  let r = new FileReader();
2793
2882
  r.onload = () => t(r.result.split(",")[1] ?? ""), r.onerror = n, r.readAsDataURL(e);
2794
- }), r = Fn((await d().generateContent([{ inlineData: {
2883
+ }), r = Jn((await f().generateContent([{ inlineData: {
2795
2884
  mimeType: e.type || "image/jpeg",
2796
2885
  data: t
2797
- } }, On(n.value)])).response.text());
2798
- if (!r) return f();
2886
+ } }, Vn(n.value)])).response.text());
2887
+ if (!r) return p();
2799
2888
  let i = {
2800
2889
  flagged: r.flagged,
2801
2890
  category: r.category,
2802
- reason: jn({
2891
+ reason: Wn({
2803
2892
  reason: r.reason,
2804
2893
  category: r.category,
2805
2894
  via: "ai"
2806
2895
  }),
2807
2896
  via: "ai"
2808
2897
  };
2809
- return i.flagged ? m(i) : i;
2898
+ return i.flagged ? h(i) : i;
2810
2899
  } catch (e) {
2811
- return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e), f();
2900
+ return console.warn("[memi-board] moderation AI image failed", e instanceof Error ? e.message : e), p();
2812
2901
  }
2813
2902
  }
2814
2903
  return {
2815
- checkText: h,
2816
- checkImage: g
2904
+ checkText: g,
2905
+ checkImage: _
2817
2906
  };
2818
2907
  }
2819
2908
  //#endregion
2820
2909
  //#region src/composables/useMemiBoardUsers.ts
2821
- var Br = [
2910
+ var ei = [
2822
2911
  "owner",
2823
2912
  "admin",
2824
2913
  "manager",
@@ -2826,39 +2915,39 @@ var Br = [
2826
2915
  "user"
2827
2916
  ].map((e) => ({
2828
2917
  value: e,
2829
- label: M("ko", `common.role.${e}`),
2830
- description: M("ko", `boardUsers.roleDescription.${e}`)
2918
+ label: j("ko", `common.role.${e}`),
2919
+ description: j("ko", `boardUsers.roleDescription.${e}`)
2831
2920
  }));
2832
- function Vr(e = {}) {
2833
- let t = () => P(), n = Z(), { t: r } = N(), i = I(() => z(e.enabled) ?? !0 ? c(n, t()) : null), a = ke(i, { ssrKey: p(t(), "users-management") });
2834
- async function o(e, i) {
2835
- if (!Br.some((e) => e.value === i)) throw Error(r("boardUsers.unsupportedRole"));
2836
- await Y(h(n, t(), e), {
2921
+ function ti(e = {}) {
2922
+ let t = () => y(), n = Q(), { t: r } = O(), i = I(() => z(e.enabled) ?? !0 ? d(n, t()) : null), o = ke(i, { ssrKey: h(t(), "users-management") });
2923
+ async function s(e, i) {
2924
+ if (!ei.some((e) => e.value === i)) throw Error(r("boardUsers.unsupportedRole"));
2925
+ await X(a(n, t(), e), {
2837
2926
  role: i,
2838
- updatedAt: q()
2927
+ updatedAt: J()
2839
2928
  });
2840
2929
  }
2841
2930
  return {
2842
- users: a,
2843
- usersPending: a.pending,
2844
- updateUserRole: o
2931
+ users: o,
2932
+ usersPending: o.pending,
2933
+ updateUserRole: s
2845
2934
  };
2846
2935
  }
2847
2936
  //#endregion
2848
2937
  //#region src/composables/useMemiBoardUserProfile.ts
2849
- function Hr(e) {
2850
- let t = Z(), n = () => P(), r = I(() => z(e)), i = I(() => {
2938
+ function ni(e) {
2939
+ let t = Q(), n = () => y(), r = I(() => z(e)), i = I(() => {
2851
2940
  let e = r.value;
2852
- return e ? h(t, n(), e) : null;
2853
- }), { data: a, pending: o } = je(i);
2941
+ return e ? a(t, n(), e) : null;
2942
+ }), { data: o, pending: s } = je(i);
2854
2943
  return {
2855
- profile: a,
2856
- profilePending: o
2944
+ profile: o,
2945
+ profilePending: s
2857
2946
  };
2858
2947
  }
2859
2948
  //#endregion
2860
2949
  //#region src/utils/section.ts
2861
- var Ur = [
2950
+ var ri = [
2862
2951
  3,
2863
2952
  4,
2864
2953
  5,
@@ -2868,43 +2957,43 @@ var Ur = [
2868
2957
  9,
2869
2958
  12
2870
2959
  ];
2871
- function Wr(e) {
2960
+ function ii(e) {
2872
2961
  return [
2873
2962
  {
2874
2963
  value: "list",
2875
- label: M(e, "sectionUtil.kind.list")
2964
+ label: j(e, "sectionUtil.kind.list")
2876
2965
  },
2877
2966
  {
2878
2967
  value: "post",
2879
- label: M(e, "sectionUtil.kind.post")
2968
+ label: j(e, "sectionUtil.kind.post")
2880
2969
  },
2881
2970
  {
2882
2971
  value: "comments",
2883
- label: M(e, "sectionUtil.kind.comments")
2972
+ label: j(e, "sectionUtil.kind.comments")
2884
2973
  }
2885
2974
  ];
2886
2975
  }
2887
- function Gr(e) {
2976
+ function ai(e) {
2888
2977
  return [{
2889
2978
  value: "latest",
2890
- label: M(e, "sectionUtil.sort.latest")
2979
+ label: j(e, "sectionUtil.sort.latest")
2891
2980
  }, {
2892
2981
  value: "likes",
2893
- label: M(e, "sectionUtil.sort.likes")
2982
+ label: j(e, "sectionUtil.sort.likes")
2894
2983
  }];
2895
2984
  }
2896
- var Kr = Wr("ko"), qr = Gr("ko");
2897
- function Jr(e) {
2985
+ var oi = ii("ko"), si = ai("ko");
2986
+ function ci(e) {
2898
2987
  return e === "list" ? 5 : 4;
2899
2988
  }
2900
- function Yr(e, t) {
2989
+ function li(e, t) {
2901
2990
  let n = Math.floor(Number(t));
2902
- return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : Jr(e);
2991
+ return Number.isFinite(n) ? Math.min(e === "list" ? 20 : 10, Math.max(1, n)) : ci(e);
2903
2992
  }
2904
- function Xr(e) {
2993
+ function ui(e) {
2905
2994
  return e === 12 ? null : 12 - e;
2906
2995
  }
2907
- function Zr(e) {
2996
+ function di(e) {
2908
2997
  return {
2909
2998
  3: "col-span-12 md:col-span-3",
2910
2999
  4: "col-span-12 md:col-span-4",
@@ -2916,36 +3005,36 @@ function Zr(e) {
2916
3005
  12: "col-span-12"
2917
3006
  }[e];
2918
3007
  }
2919
- function Qr(e) {
3008
+ function fi(e) {
2920
3009
  return e === "sm" ? "min-h-40" : e === "lg" ? "min-h-80" : "min-h-56";
2921
3010
  }
2922
- function $r(e) {
3011
+ function pi(e) {
2923
3012
  let t = e.boardId || e.category || "free";
2924
3013
  return e.slug ? `/board/${t}/${e.slug}` : `/board/${t}`;
2925
3014
  }
2926
- function ei(e) {
3015
+ function mi(e) {
2927
3016
  return e.kind === "comments" ? e.sort === "likes" ? "/boardComments?sort=likes" : "/boardComments" : e.kind === "list" && e.boardId ? `/board/${e.boardId}` : "/board";
2928
3017
  }
2929
- function ti(e) {
3018
+ function hi(e) {
2930
3019
  if (e.boardId && e.postId) return `/board/${e.boardId}/post/${e.postId}`;
2931
3020
  }
2932
- function ni(e) {
3021
+ function gi(e) {
2933
3022
  return e.previewImage || e.attachments?.find((e) => e.type.startsWith("image/"))?.url;
2934
3023
  }
2935
- function ri(e, t) {
2936
- return vt(e, t).trim() || yt(e, t).trim() || M(t, "sectionUtil.untitledPost");
3024
+ function _i(e, t) {
3025
+ return vt(e, t).trim() || yt(e, t).trim() || j(t, "sectionUtil.untitledPost");
2937
3026
  }
2938
- function ii(e) {
3027
+ function vi(e) {
2939
3028
  return e === "image" || e === "video" ? "media" : "list";
2940
3029
  }
2941
- function ai(e, t) {
2942
- return M(t, ii(e) === "media" ? "sectionUtil.view.media" : "sectionUtil.view.list");
3030
+ function yi(e, t) {
3031
+ return j(t, vi(e) === "media" ? "sectionUtil.view.media" : "sectionUtil.view.list");
2943
3032
  }
2944
- function oi(e, t) {
3033
+ function bi(e, t) {
2945
3034
  return e ? t(e)?.listView ?? "default" : "default";
2946
3035
  }
2947
- function si(e, t) {
2948
- let n = e.map((e) => oi(e.boardId, t));
3036
+ function xi(e, t) {
3037
+ let n = e.map((e) => bi(e.boardId, t));
2949
3038
  if (!n.length) return "default";
2950
3039
  if (n.every((e) => e === n[0])) return n[0];
2951
3040
  let r = n.filter((e) => e === "image").length, i = n.filter((e) => e === "video").length;
@@ -2953,27 +3042,27 @@ function si(e, t) {
2953
3042
  }
2954
3043
  //#endregion
2955
3044
  //#region src/composables/useMemiBoardSections.ts
2956
- var ci = [];
2957
- function li(e) {
3045
+ var Si = [];
3046
+ function Ci(e) {
2958
3047
  let t = Number(e.cols);
2959
- if (Ur.includes(t)) return t;
3048
+ if (ri.includes(t)) return t;
2960
3049
  let n = e.width;
2961
3050
  return n === "xs" ? 3 : n === "sm" ? 4 : n === "lg" || Number(e.span) === 2 ? 12 : 6;
2962
3051
  }
2963
- function ui(e) {
3052
+ function wi(e) {
2964
3053
  let t = e.height ?? e.size;
2965
3054
  return t === "sm" || t === "lg" ? t : "md";
2966
3055
  }
2967
- function di(e) {
3056
+ function Ti(e) {
2968
3057
  return e.kind === "post" || e.kind === "comments" ? e.kind : "list";
2969
3058
  }
2970
- function fi(e) {
3059
+ function Ei(e) {
2971
3060
  return e.sort === "likes" ? "likes" : "latest";
2972
3061
  }
2973
- function pi(e) {
3062
+ function Di(e) {
2974
3063
  return (typeof e.boardId == "string" ? e.boardId.trim() : "") || null;
2975
3064
  }
2976
- function mi(e, t) {
3065
+ function Oi(e, t) {
2977
3066
  let n = Array.isArray(e.postIds) ? e.postIds : [], r = [];
2978
3067
  for (let e of n) {
2979
3068
  let n = String(e || "").trim();
@@ -2981,131 +3070,155 @@ function mi(e, t) {
2981
3070
  }
2982
3071
  return r;
2983
3072
  }
2984
- function hi(e, t) {
2985
- return M(t, "sections.defaultTitle", { n: e + 1 });
3073
+ function ki(e, t) {
3074
+ return j(t, "sections.defaultTitle", { n: e + 1 });
2986
3075
  }
2987
- function gi(e, t, n) {
2988
- let r = di(e), i = Yr(r, e.count), a = Q(e.i18n), o = ut(e.i18nSource);
3076
+ function Ai(e, t, n) {
3077
+ let r = Ti(e), i = li(r, e.count), a = $(e.i18n), o = ut(e.i18nSource);
2989
3078
  return {
2990
3079
  id: String(e.id || `box-${t + 1}`),
2991
- title: String(e.title || hi(t, n)),
3080
+ title: String(e.title || ki(t, n)),
2992
3081
  showTitle: e.showTitle !== !1,
2993
3082
  kind: r,
2994
- boardId: pi(e),
3083
+ boardId: Di(e),
2995
3084
  count: i,
2996
- postIds: mi(e, i),
2997
- sort: fi(e),
2998
- cols: li(e),
2999
- height: ui(e),
3085
+ postIds: Oi(e, i),
3086
+ sort: Ei(e),
3087
+ cols: Ci(e),
3088
+ height: wi(e),
3000
3089
  order: t,
3001
3090
  ...a ? { i18n: a } : {},
3002
3091
  ...o ? { i18nSource: o } : {}
3003
3092
  };
3004
3093
  }
3005
- function _i() {
3006
- let { locale: e } = N(), { translateEntries: t } = Un(), r = Z(), i = ve(r, "settings", "homeLayout"), { data: a, pending: o } = je(i), s = I(() => (Array.isArray(a.value?.blocks) ? a.value.blocks : ci).map((t, n) => gi(t, n, e.value)));
3007
- async function c(r) {
3008
- if (!n()) return r;
3009
- let i = e.value, a = r.filter((e) => {
3094
+ function ji() {
3095
+ let { locale: e } = O(), { translateEntries: t } = nr(), n = Q(), r = ve(n, "settings", "homeLayout"), { data: i, pending: a } = je(r), o = I(() => (Array.isArray(i.value?.blocks) ? i.value.blocks : Si).map((t, n) => Ai(t, n, e.value)));
3096
+ async function s(n) {
3097
+ if (!de()) return n;
3098
+ let r = e.value, i = n.filter((e) => {
3010
3099
  let t = e.title.trim();
3011
3100
  return t ? !(e.i18nSource?.title === t && ht(e.i18n, ["title"])) : !1;
3012
3101
  });
3013
- if (!a.length) return r;
3014
- let o = await t(a.map((e) => ({
3102
+ if (!i.length) return n;
3103
+ let a = await t(i.map((e) => ({
3015
3104
  id: e.id,
3016
3105
  fields: { title: e.title.trim() },
3017
3106
  context: e.kind
3018
3107
  })), {
3019
- source: i,
3108
+ source: r,
3020
3109
  purpose: "section heading on a website home page"
3021
3110
  });
3022
- return r.map((e) => {
3023
- let t = o[e.id];
3111
+ return n.map((e) => {
3112
+ let t = a[e.id];
3024
3113
  if (!t) return e;
3025
- let n = e.title.trim(), r = ft(i, { title: n }, t);
3026
- return ht(r, ["title"]) ? {
3114
+ let n = e.title.trim(), i = ft(r, { title: n }, t);
3115
+ return ht(i, ["title"]) ? {
3027
3116
  ...e,
3028
3117
  title: n,
3029
- i18n: r,
3118
+ i18n: i,
3030
3119
  i18nSource: {
3031
- locale: i,
3120
+ locale: r,
3032
3121
  title: n
3033
3122
  }
3034
3123
  } : e;
3035
3124
  });
3036
3125
  }
3037
- function l(t, n) {
3038
- let r = t, i = di(r), a = Yr(i, t.count), o = t.title.trim() || hi(n, e.value);
3126
+ function c(t, n) {
3127
+ let r = t, i = Ti(r), a = li(i, t.count), o = t.title.trim() || ki(n, e.value);
3039
3128
  return {
3040
3129
  id: t.id,
3041
3130
  title: o,
3042
3131
  showTitle: t.showTitle !== !1,
3043
3132
  kind: i,
3044
- boardId: pi(r),
3133
+ boardId: Di(r),
3045
3134
  count: a,
3046
- postIds: mi(r, a),
3047
- sort: fi(r),
3048
- cols: li(r),
3049
- height: ui(r),
3135
+ postIds: Oi(r, a),
3136
+ sort: Ei(r),
3137
+ cols: Ci(r),
3138
+ height: wi(r),
3050
3139
  order: n,
3051
3140
  ...t.i18n ? { i18n: t.i18n } : {},
3052
3141
  ...t.i18nSource?.title === o ? { i18nSource: t.i18nSource } : {}
3053
3142
  };
3054
3143
  }
3055
- async function u(e) {
3144
+ async function l(e) {
3056
3145
  let t = e;
3057
3146
  try {
3058
- t = await c(e);
3147
+ t = await s(e);
3059
3148
  } catch (e) {
3060
3149
  console.warn("[memi-board] section translation skipped", e);
3061
3150
  }
3062
- await De(i, {
3151
+ await De(r, {
3063
3152
  columns: 12,
3064
- blocks: t.map((e, t) => l(e, t)),
3065
- updatedAt: q()
3153
+ blocks: t.map((e, t) => c(e, t)),
3154
+ updatedAt: J()
3066
3155
  });
3067
3156
  }
3068
3157
  return {
3069
- settings: a,
3070
- pending: o,
3071
- sections: s,
3072
- blocks: s,
3073
- hasSavedLayout: I(() => Array.isArray(a.value?.blocks)),
3074
- saveSections: u,
3075
- saveBlocks: u
3158
+ settings: i,
3159
+ pending: a,
3160
+ sections: o,
3161
+ blocks: o,
3162
+ hasSavedLayout: I(() => Array.isArray(i.value?.blocks)),
3163
+ saveSections: l,
3164
+ saveBlocks: l
3076
3165
  };
3077
3166
  }
3078
3167
  //#endregion
3079
3168
  //#region src/composables/useMemiBoardMiniPosts.ts
3080
- function vi(e, t) {
3081
- let n = Z(), r = () => P(), i = z(e)?.trim() || "all", a = I(() => {
3082
- let i = Math.max(1, Math.floor(Number(z(t)) || 5)), a = z(e)?.trim() || "", s = [X("isPublished", "==", !0), X("listed", "==", !0)];
3083
- return a && s.unshift(X("boardId", "==", a)), K(o(n, r()), ...s, G("createdAt", "desc"), U(i));
3084
- }), { data: s, pending: c, error: l } = ke(a, { ssrKey: p(r(), `mini-list/${i}`) });
3169
+ function Mi(e, t) {
3170
+ let n = Q(), r = () => y(), i = z(e)?.trim() || "all", a = I(() => {
3171
+ let i = Math.max(1, Math.floor(Number(z(t)) || 5)), a = z(e)?.trim() || "", o = [Z("isPublished", "==", !0), Z("listed", "==", !0)];
3172
+ return a && o.unshift(Z("boardId", "==", a)), q(u(n, r()), ...o, K("createdAt", "desc"), W(i));
3173
+ }), { data: o, pending: s, error: c } = ke(a, { ssrKey: h(r(), `mini-list/${i}`) });
3085
3174
  return {
3086
- posts: I(() => s.value ?? []),
3087
- pending: c,
3088
- error: l
3175
+ posts: I(() => o.value ?? []),
3176
+ pending: s,
3177
+ error: c
3089
3178
  };
3090
3179
  }
3091
- function yi(e) {
3092
- let t = Z(), n = () => P(), r = I(() => [...new Set(z(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = I(() => r.value.length ? K(o(t, n()), X(V(), "in", r.value)) : null), { data: s, pending: c, error: l } = ke(a, { ssrKey: p(n(), `mini-picked/${i}`) });
3180
+ function Ni(e) {
3181
+ let t = Q(), n = () => y(), r = I(() => [...new Set(z(e).map((e) => e.trim()).filter(Boolean))].slice(0, 10)), i = r.value.join(",") || "none", a = I(() => r.value.length ? q(u(t, n()), Z(H(), "in", r.value)) : null), { data: o, pending: s, error: c } = ke(a, { ssrKey: h(n(), `mini-picked/${i}`) });
3093
3182
  return {
3094
3183
  posts: I(() => {
3095
- let e = new Map((s.value ?? []).map((e) => [e.id, e])), t = [];
3184
+ let e = new Map((o.value ?? []).map((e) => [e.id, e])), t = [];
3096
3185
  for (let n of r.value) {
3097
3186
  let r = e.get(n);
3098
3187
  r && r.isPublished !== !1 && t.push(r);
3099
3188
  }
3100
3189
  return t;
3101
3190
  }),
3102
- pending: c,
3103
- error: l
3191
+ pending: s,
3192
+ error: c
3104
3193
  };
3105
3194
  }
3106
3195
  //#endregion
3107
3196
  //#region src/data/versionHistory.ts
3108
- var bi = [
3197
+ var Pi = [
3198
+ {
3199
+ version: "0.53.0",
3200
+ date: "2026-11-04",
3201
+ highlights: [
3202
+ "게시판마다 커스텀 필드를 정해 글에 추가 값을 넣을 수 있어요",
3203
+ "파일은 끌어다 놓거나 클릭해서 첨부할 수 있어요",
3204
+ "게시판 설정은 카드 목록에서 고르고, 이름·설명·주소로 정렬할 수 있어요"
3205
+ ],
3206
+ highlightsEn: [
3207
+ "Each board can define custom fields and store extra values on posts",
3208
+ "Files can be attached by dropping them or clicking the drop zone",
3209
+ "Board settings open from a card list that can be sorted by name, description, or address"
3210
+ ],
3211
+ note: "규칙이나 인덱스 배포는 필요 없어요. 새 게시판 이름은 40자까지이고 주소가 돼요.",
3212
+ noteEn: "No rules or index deploy is required. A new board name is limited to 40 characters and becomes its address."
3213
+ },
3214
+ {
3215
+ version: "0.52.5",
3216
+ date: "2026-10-30",
3217
+ highlights: ["Safari에서 글·댓글 로딩이 늦을 때 long polling을 적용하는 호스트 설정 안내를 추가했어요"],
3218
+ highlightsEn: ["Added host setup guidance for using long polling when posts and comments load slowly in Safari"],
3219
+ note: "문서 안내 추가이며, 통신 설정은 호스트 앱에서 적용해야 해요.",
3220
+ noteEn: "This is a documentation update; the host app must apply the transport setting."
3221
+ },
3109
3222
  {
3110
3223
  version: "0.52.4",
3111
3224
  date: "2026-10-30",
@@ -3671,14 +3784,14 @@ var bi = [
3671
3784
  ];
3672
3785
  //#endregion
3673
3786
  //#region src/utils/renderMarkdown.ts
3674
- function xi(e) {
3787
+ function Fi(e) {
3675
3788
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
3676
3789
  }
3677
- function Si(e) {
3790
+ function Ii(e) {
3678
3791
  let t = e;
3679
3792
  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;
3680
3793
  }
3681
- function Ci(e) {
3794
+ function Li(e) {
3682
3795
  if (!e?.trim()) return "";
3683
3796
  let t = e.replace(/\r\n/g, "\n").split("\n"), n = [], r = 0, i = !1, a = [], o = null, s = [];
3684
3797
  function c() {
@@ -3687,7 +3800,7 @@ function Ci(e) {
3687
3800
  return;
3688
3801
  }
3689
3802
  let e = o;
3690
- n.push(`<${e}>${s.map((e) => `<li>${Si(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3803
+ n.push(`<${e}>${s.map((e) => `<li>${Ii(e)}</li>`).join("")}</${e}>`), o = null, s = [];
3691
3804
  }
3692
3805
  for (; r < t.length;) {
3693
3806
  let e = t[r] ?? "", l = e.match(/^```(\w*)\s*$/);
@@ -3696,7 +3809,7 @@ function Ci(e) {
3696
3809
  continue;
3697
3810
  }
3698
3811
  if (i) {
3699
- a.push(xi(e)), r++;
3812
+ a.push(Fi(e)), r++;
3700
3813
  continue;
3701
3814
  }
3702
3815
  if (/^(-{3,}|\*{3,}|_{3,})\s*$/.test(e)) {
@@ -3707,24 +3820,24 @@ function Ci(e) {
3707
3820
  if (u) {
3708
3821
  c();
3709
3822
  let e = u[1].length;
3710
- n.push(`<h${e} class="font-semibold mt-4 mb-2">${Si(xi(u[2]))}</h${e}>`), r++;
3823
+ n.push(`<h${e} class="font-semibold mt-4 mb-2">${Ii(Fi(u[2]))}</h${e}>`), r++;
3711
3824
  continue;
3712
3825
  }
3713
3826
  if (e.startsWith("> ")) {
3714
3827
  c();
3715
3828
  let e = [];
3716
- for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(xi((t[r] ?? "").slice(2))), r++;
3717
- n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${Si(e.join("<br />"))}</blockquote>`);
3829
+ for (; r < t.length && (t[r] ?? "").startsWith("> ");) e.push(Fi((t[r] ?? "").slice(2))), r++;
3830
+ n.push(`<blockquote class="border-l-4 border-default pl-3 text-muted my-3">${Ii(e.join("<br />"))}</blockquote>`);
3718
3831
  continue;
3719
3832
  }
3720
3833
  let d = e.match(/^[-*+]\s+(.+)$/);
3721
3834
  if (d) {
3722
- o && o !== "ul" && c(), o = "ul", s.push(xi(d[1])), r++;
3835
+ o && o !== "ul" && c(), o = "ul", s.push(Fi(d[1])), r++;
3723
3836
  continue;
3724
3837
  }
3725
3838
  let f = e.match(/^\d+\.\s+(.+)$/);
3726
3839
  if (f) {
3727
- o && o !== "ol" && c(), o = "ol", s.push(xi(f[1])), r++;
3840
+ o && o !== "ol" && c(), o = "ol", s.push(Fi(f[1])), r++;
3728
3841
  continue;
3729
3842
  }
3730
3843
  if (!e.trim()) {
@@ -3736,22 +3849,22 @@ function Ci(e) {
3736
3849
  for (; r < t.length;) {
3737
3850
  let e = t[r] ?? "";
3738
3851
  if (!e.trim() || /^(#{1,3}\s|```|[-*+]\s|\d+\.\s|> |(-{3,}|\*{3,})\s*$)/.test(e)) break;
3739
- p.push(xi(e)), r++;
3852
+ p.push(Fi(e)), r++;
3740
3853
  }
3741
- n.push(`<p class="my-2 leading-relaxed">${Si(p.join("<br />"))}</p>`);
3854
+ n.push(`<p class="my-2 leading-relaxed">${Ii(p.join("<br />"))}</p>`);
3742
3855
  }
3743
3856
  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");
3744
3857
  }
3745
3858
  //#endregion
3746
3859
  //#region src/utils/orphanCleanup.ts
3747
- function wi(e, t, n, r) {
3860
+ function Ri(e, t, n, r) {
3748
3861
  return typeof t.postId != "string" || !t.postId || t.postId.includes("/") ? !1 : !n.has(t.postId) || e === "like" && t.target === "comment" && typeof t.commentId == "string" && !!t.commentId && !t.commentId.includes("/") && !r.has(t.commentId);
3749
3862
  }
3750
- function Ti(e, t) {
3863
+ function zi(e, t) {
3751
3864
  let n = Date.parse(e);
3752
3865
  return Number.isFinite(n) && t - n >= 864e5;
3753
3866
  }
3754
- function Ei(e, t) {
3867
+ function Bi(e, t) {
3755
3868
  if (!e.startsWith(`${t}/`)) return null;
3756
3869
  let n = e.slice(t.length + 1).split("/");
3757
3870
  if (n.some((e) => !e || e === "." || e === "..")) return null;
@@ -3761,18 +3874,18 @@ function Ei(e, t) {
3761
3874
  commentId: a
3762
3875
  } : null;
3763
3876
  }
3764
- function Di(e, t, n) {
3877
+ function Vi(e, t, n) {
3765
3878
  let r = `${t === "comment" ? n.commentsCollection : n.likesCollection}/`, i = e.startsWith(r) ? e.slice(r.length) : "";
3766
3879
  return !!i && !i.includes("/") && i !== "." && i !== "..";
3767
3880
  }
3768
3881
  //#endregion
3769
3882
  //#region src/composables/useMemiBoardCleanup.ts
3770
- function Oi() {
3771
- let e = Z(), t = Me(), { isAdmin: n, rolePending: r } = Wt(), { t: i } = N(), a = R([]), o = R(!1), s = R(!1), c = R(""), l = R(""), u = [], d = "", f = /* @__PURE__ */ new Map();
3883
+ function Hi() {
3884
+ let e = Q(), t = Me(), { isAdmin: n, rolePending: r } = Wt(), { t: i } = O(), a = R([]), o = R(!1), s = R(!1), c = R(""), l = R(""), u = [], d = "", f = /* @__PURE__ */ new Map();
3772
3885
  function p() {
3773
3886
  let e = Le(t).currentUser?.uid;
3774
3887
  if (!e) throw Error(i("settings.noAccess"));
3775
- return JSON.stringify([e, P()]);
3888
+ return JSON.stringify([e, y()]);
3776
3889
  }
3777
3890
  function m(e) {
3778
3891
  if (h(), p() !== e) throw Error(i("settings.cleanup.contextChanged"));
@@ -3781,10 +3894,10 @@ function Oi() {
3781
3894
  if (!n.value || r.value || !Le(t).currentUser) throw Error(i("settings.noAccess"));
3782
3895
  }
3783
3896
  async function g() {
3784
- let t = P(), [n, r, i] = await Promise.all([
3785
- Ce(he(e, t.postsCollection)),
3786
- Ce(he(e, t.commentsCollection)),
3787
- Ce(he(e, t.likesCollection))
3897
+ let t = y(), [n, r, i] = await Promise.all([
3898
+ Ce(ge(e, t.postsCollection)),
3899
+ Ce(ge(e, t.commentsCollection)),
3900
+ Ce(ge(e, t.likesCollection))
3788
3901
  ]), a = /* @__PURE__ */ new Set();
3789
3902
  function o(e) {
3790
3903
  if (typeof e == "string") {
@@ -3798,7 +3911,7 @@ function Oi() {
3798
3911
  } else Array.isArray(e) ? e.forEach(o) : e && typeof e == "object" && Object.getPrototypeOf(e) === Object.prototype && Object.values(e).forEach(o);
3799
3912
  }
3800
3913
  n.docs.forEach((e) => o(e.data())), r.docs.forEach((e) => o(e.data()));
3801
- for (let e of n.docs) (await Ce(he(e.ref, "body"))).docs.forEach((e) => o(e.data()));
3914
+ for (let e of n.docs) (await Ce(ge(e.ref, "body"))).docs.forEach((e) => o(e.data()));
3802
3915
  for (let e of [...a]) {
3803
3916
  let t = e.match(/^(.*\/images\/)([^/]+)\.[^/.]+$/);
3804
3917
  t && a.add(`${t[1]}thumbnails/${t[2]}.jpg`);
@@ -3822,7 +3935,7 @@ function Oi() {
3822
3935
  let r = [];
3823
3936
  for (let [e, t] of [["comment", n.commentDocs], ["like", n.likes]]) for (let i of t) {
3824
3937
  let t = i.data();
3825
- wi(e, t, n.posts, n.comments) && r.push({
3938
+ Ri(e, t, n.posts, n.comments) && r.push({
3826
3939
  kind: e,
3827
3940
  path: i.ref.path,
3828
3941
  postId: t.postId,
@@ -3840,12 +3953,12 @@ function Oi() {
3840
3953
  });
3841
3954
  o.push(...e.prefixes);
3842
3955
  for (let t of e.items) {
3843
- let e = Ei(t.fullPath, n.cfg.postsCollection);
3956
+ let e = Bi(t.fullPath, n.cfg.postsCollection);
3844
3957
  if (!e) continue;
3845
3958
  let { postId: i, commentId: a } = e;
3846
3959
  if (n.referenced.has(t.fullPath) || n.posts.has(i) && (!a || n.comments.has(a))) continue;
3847
3960
  let o = await Ue(t);
3848
- Ti(o.updated, Date.now()) && (f.set(t.fullPath, o.generation), r.push({
3961
+ zi(o.updated, Date.now()) && (f.set(t.fullPath, o.generation), r.push({
3849
3962
  kind: "file",
3850
3963
  path: t.fullPath,
3851
3964
  postId: i,
@@ -3878,23 +3991,23 @@ function Oi() {
3878
3991
  try {
3879
3992
  let i = !1;
3880
3993
  if (n.kind === "file") {
3881
- if (!Ei(n.path, o.cfg.postsCollection)) throw Error("Invalid cleanup path");
3994
+ if (!Bi(n.path, o.cfg.postsCollection)) throw Error("Invalid cleanup path");
3882
3995
  let r = We(t), a = qe(r, n.path), [s, c, l] = await Promise.all([
3883
3996
  Se(ve(e, o.cfg.postsCollection, n.postId)),
3884
3997
  n.commentId ? Se(ve(e, o.cfg.commentsCollection, n.commentId)) : null,
3885
3998
  Ue(a)
3886
3999
  ]);
3887
- m(d), l.generation === f.get(n.path) && !o.referenced.has(n.path) && Ti(l.updated, Date.now()) && (!s.exists() || n.commentId && !c?.exists()) && (await He(a), i = !0);
4000
+ m(d), l.generation === f.get(n.path) && !o.referenced.has(n.path) && zi(l.updated, Date.now()) && (!s.exists() || n.commentId && !c?.exists()) && (await He(a), i = !0);
3888
4001
  } else {
3889
4002
  let t = n.kind;
3890
- if (!Di(n.path, t, o.cfg)) throw Error("Invalid cleanup path");
4003
+ if (!Vi(n.path, t, o.cfg)) throw Error("Invalid cleanup path");
3891
4004
  i = await Ee(e, async (r) => {
3892
4005
  let i = await r.get(ve(e, n.path));
3893
4006
  if (!i.exists()) return !0;
3894
4007
  let a = i.data();
3895
4008
  if (typeof a.postId != "string" || !a.postId || a.postId.includes("/")) return !1;
3896
4009
  let s = await r.get(ve(e, o.cfg.postsCollection, a.postId)), c = n.kind === "like" && a.target === "comment" && typeof a.commentId == "string" && a.commentId && !a.commentId.includes("/") ? await r.get(ve(e, o.cfg.commentsCollection, a.commentId)) : null;
3897
- return wi(t, a, new Set(s.exists() ? [a.postId] : []), new Set(c?.exists() ? [a.commentId] : [])) ? (m(d), r.delete(i.ref), !0) : !1;
4010
+ return Ri(t, a, new Set(s.exists() ? [a.postId] : []), new Set(c?.exists() ? [a.commentId] : [])) ? (m(d), r.delete(i.ref), !0) : !1;
3898
4011
  });
3899
4012
  }
3900
4013
  i ? r++ : p++, a.value = a.value.filter((e) => e.path !== n.path);
@@ -3914,16 +4027,16 @@ function Oi() {
3914
4027
  }
3915
4028
  }
3916
4029
  return {
3917
- items: me(a),
3918
- busy: me(o),
3919
- scanned: me(s),
3920
- error: me(c),
3921
- result: me(l),
4030
+ items: he(a),
4031
+ busy: he(o),
4032
+ scanned: he(s),
4033
+ error: he(c),
4034
+ result: he(l),
3922
4035
  scan: _,
3923
4036
  remove: v
3924
4037
  };
3925
4038
  }
3926
4039
  //#endregion
3927
- export { lr as AUTHOR_MEMO_MAX_LENGTH, Ur as BOARD_SECTION_COLS, Kr as BOARD_SECTION_KINDS, qr as BOARD_SECTION_SORTS, Br as BOARD_USER_ROLES, wr as COMMENT_BODY_MAX_LENGTH, It as DEFAULT_BLOCK_BAN_DECAY_MS, Ft as DEFAULT_BLOCK_BAN_THRESHOLD, Wn as DEFAULT_BOARDS, Gn as DEFAULT_CATEGORIES, i as DEFAULT_COMMENTS_COLLECTION, r as DEFAULT_LIKES_COLLECTION, j as DEFAULT_MEMI_BOARD_LOCALE, m as DEFAULT_POSTS_COLLECTION, ne as DEFAULT_REPORTS_COLLECTION, e as DEFAULT_SETTINGS_COLLECTION, te as DEFAULT_USERS_COLLECTION, A as FALLBACK_MEMI_BOARD_LOCALE, Rn as HTML_MAX_CHARS, T as MEMI_BOARD_LOCALES, jr as REPORT_DETAIL_MAX_LENGTH, Mr as REPORT_REASONS, fr as WRITING_ASSISTANT_DAILY_LIMIT, $e as asHttpUrl, xt as boardCopyIsTranslated, at as boardListOgDescription, it as boardListOgTitle, rt as boardPostOgDescription, nt as boardPostOgTitle, Wr as boardSectionKinds, Gr as boardSectionSorts, p as boardSsrKey, pt as boardTranslationLocales, h as boardUserDoc, c as boardUsersCol, _n as buildPostPreview, At as canManageBoardByRole, jt as canWriteCommentByRole, Yr as clampSectionCount, d as commentDoc, g as commentsCol, de as configureMemiBoard, ht as coversLocales, Jr as defaultSectionCount, St as displayCommentBody, bt as displayPostContent, yt as displayPostSummary, vt as displayPostTitle, _t as displayStoredField, Lt as effectiveModerationBlockCount, Xt as extractEditorImageUrls, Dt as fetchPublicListForSeo, Et as fetchPublicPostForSeo, ee as formatDate, re as formatFullDate, le as formatRelativeDate, Bt as formatRestrictedUntilLabel, O as formatTimestampDetails, fn as hasBodyImage, dn as hasBodyText, ct as hashText, Jt as imeSafeSubmitClick, qt as imeSafeSubmitPointerDown, kt as isAssignedStaff, pn as isContentEmpty, Xn as isFirestorePermissionDenied, _ as isMemiBoardI18nEnabled, k as isMemiBoardLocaleLoaded, n as isMemiBoardTranslationEnabled, zt as isModerationWriteRestricted, fe as likeDoc, t as likeDocId, b as likesCol, ae as loadMemiBoardLocale, gt as localizedText, kr as memiBoardCommentLikesKey, ie as memiBoardHostLocaleKey, ue as memiBoardLocaleInfo, ft as mergeSourceFields, oi as miniBoardView, ti as miniCommentLink, ei as miniMoreLink, ni as miniPostImage, $r as miniPostLink, ri as miniPostTitle, si as miniPostsView, ii as miniViewGroup, ai as miniViewLabel, Rt as moderationWriteRestrictedUntilMs, ot as normalizeBasePath, gi as normalizeBoardSection, F as normalizeMemiBoardLocale, Xr as pairSectionCols, ln as plainTextFromHtml, s as postBodyDoc, y as postDoc, Qt as postNamespaceFromStoragePath, x as postStorageFolder, o as postsCol, ut as readI18nSource, Q as readLocalizedFields, Ci as renderMarkdownToHtml, u as reportDoc, oe as reportDocId, Nr as reportReasonLabel, l as reportsCol, C as resolveBoardPathConfig, Ct as resolvePublicSeoDb, Zr as sectionColClass, Qr as sectionMinHeight, S as settingsCol, w as settingsDoc, E as slugify, Zt as storagePathFromDownloadUrl, un as titleFromBody, tt as toAbsoluteUrl, et as toBoardOgImageUrl, M as translate, P as useBoardPathConfig, Wt as useMemiBoardAuth, dr as useMemiBoardAuthorMemo, Un as useMemiBoardAutoTranslate, Oi as useMemiBoardCleanup, cr as useMemiBoardCommentFeed, Ar as useMemiBoardCommentLikes, Er as useMemiBoardComments, v as useMemiBoardConfig, N as useMemiBoardI18n, Or as useMemiBoardLikes, vi as useMemiBoardMiniLatest, yi as useMemiBoardMiniPicked, zr as useMemiBoardModeration, nr as useMemiBoardPost, tr as useMemiBoardPostList, Qn as useMemiBoardPosts, Dr as useMemiBoardReplies, Ir as useMemiBoardReportQueue, Pr as useMemiBoardReports, _i as useMemiBoardSections, Jn as useMemiBoardSettings, or as useMemiBoardUserComments, ir as useMemiBoardUserPosts, Hr as useMemiBoardUserProfile, Vr as useMemiBoardUsers, Lr as useMemiBoardViews, br as useMemiBoardWritingAssistant, bi as versionHistory, gn as videoListCoverUrl, hn as youtubeId };
4040
+ export { Sr as AUTHOR_MEMO_MAX_LENGTH, M as BOARD_NAME_MAX, ri as BOARD_SECTION_COLS, oi as BOARD_SECTION_KINDS, si as BOARD_SECTION_SORTS, ei as BOARD_USER_ROLES, Rr as COMMENT_BODY_MAX_LENGTH, yn as CUSTOM_FIELD_LABEL_MAX, vn as CUSTOM_FIELD_MAX, bn as CUSTOM_FIELD_PLACEHOLDER_MAX, xn as CUSTOM_FIELD_VALUE_MAX, It as DEFAULT_BLOCK_BAN_DECAY_MS, Ft as DEFAULT_BLOCK_BAN_THRESHOLD, rr as DEFAULT_BOARDS, ir as DEFAULT_CATEGORIES, r as DEFAULT_COMMENTS_COLLECTION, m as DEFAULT_LIKES_COLLECTION, ee as DEFAULT_MEMI_BOARD_LOCALE, ne as DEFAULT_POSTS_COLLECTION, e as DEFAULT_REPORTS_COLLECTION, te as DEFAULT_SETTINGS_COLLECTION, f as DEFAULT_USERS_COLLECTION, E as FALLBACK_MEMI_BOARD_LOCALE, Zn as HTML_MAX_CHARS, P as MEMI_BOARD_LOCALES, Gr as REPORT_DETAIL_MAX_LENGTH, Kr as REPORT_REASONS, Er as WRITING_ASSISTANT_DAILY_LIMIT, $e as asHttpUrl, xt as boardCopyIsTranslated, at as boardListOgDescription, it as boardListOgTitle, rt as boardPostOgDescription, nt as boardPostOgTitle, ii as boardSectionKinds, ai as boardSectionSorts, h as boardSsrKey, pt as boardTranslationLocales, a as boardUserDoc, d as boardUsersCol, _n as buildPostPreview, At as canManageBoardByRole, jt as canWriteCommentByRole, li as clampSectionCount, _ as commentDoc, pe as commentsCol, v as configureMemiBoard, ht as coversLocales, ci as defaultSectionCount, St as displayCommentBody, bt as displayPostContent, yt as displayPostSummary, vt as displayPostTitle, _t as displayStoredField, Lt as effectiveModerationBlockCount, An as extendForFields, Xt as extractEditorImageUrls, Dt as fetchPublicListForSeo, Et as fetchPublicPostForSeo, re as formatDate, ue as formatFullDate, k as formatRelativeDate, Bt as formatRestrictedUntilLabel, A as formatTimestampDetails, fn as hasBodyImage, dn as hasBodyText, ct as hashText, Jt as imeSafeSubmitClick, qt as imeSafeSubmitPointerDown, kt as isAssignedStaff, pn as isContentEmpty, lr as isFirestorePermissionDenied, n as isMemiBoardI18nEnabled, N as isMemiBoardLocaleLoaded, de as isMemiBoardTranslationEnabled, zt as isModerationWriteRestricted, t as likeDoc, x as likeDocId, s as likesCol, ie as loadMemiBoardLocale, gt as localizedText, Ur as memiBoardCommentLikesKey, ce as memiBoardHostLocaleKey, fe as memiBoardLocaleInfo, ft as mergeSourceFields, bi as miniBoardView, hi as miniCommentLink, mi as miniMoreLink, gi as miniPostImage, pi as miniPostLink, _i as miniPostTitle, xi as miniPostsView, vi as miniViewGroup, yi as miniViewLabel, Rt as moderationWriteRestrictedUntilMs, ot as normalizeBasePath, Ai as normalizeBoardSection, D as normalizeMemiBoardLocale, ui as pairSectionCols, ln as plainTextFromHtml, b as postBodyDoc, S as postDoc, Qt as postNamespaceFromStoragePath, o as postStorageFolder, u as postsCol, On as prepareCustomFields, Dn as readCustomFields, kn as readExtend, ut as readI18nSource, $ as readLocalizedFields, Li as renderMarkdownToHtml, oe as reportDoc, l as reportDocId, qr as reportReasonLabel, w as reportsCol, C as resolveBoardPathConfig, Ct as resolvePublicSeoDb, di as sectionColClass, fi as sectionMinHeight, T as settingsCol, g as settingsDoc, ae as slugify, Zt as storagePathFromDownloadUrl, un as titleFromBody, tt as toAbsoluteUrl, et as toBoardOgImageUrl, j as translate, y as useBoardPathConfig, Wt as useMemiBoardAuth, Tr as useMemiBoardAuthorMemo, nr as useMemiBoardAutoTranslate, Hi as useMemiBoardCleanup, xr as useMemiBoardCommentFeed, Wr as useMemiBoardCommentLikes, Br as useMemiBoardComments, i as useMemiBoardConfig, O as useMemiBoardI18n, Hr as useMemiBoardLikes, Mi as useMemiBoardMiniLatest, Ni as useMemiBoardMiniPicked, $r as useMemiBoardModeration, hr as useMemiBoardPost, mr as useMemiBoardPostList, dr as useMemiBoardPosts, Vr as useMemiBoardReplies, Xr as useMemiBoardReportQueue, Jr as useMemiBoardReports, ji as useMemiBoardSections, sr as useMemiBoardSettings, yr as useMemiBoardUserComments, _r as useMemiBoardUserPosts, ni as useMemiBoardUserProfile, ti as useMemiBoardUsers, Zr as useMemiBoardViews, Pr as useMemiBoardWritingAssistant, Pi as versionHistory, gn as videoListCoverUrl, hn as youtubeId };
3928
4041
 
3929
4042
  //# sourceMappingURL=index.js.map