memi-board 0.21.0 → 0.23.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 (33) hide show
  1. package/README.md +26 -40
  2. package/dist/composables/useMemiBoardComments.d.ts +6 -1
  3. package/dist/composables/useMemiBoardPosts.d.ts +1 -0
  4. package/dist/composables/useMemiBoardSettings.d.ts +2 -2
  5. package/dist/composables/useMemiBoardStorage.d.ts +2 -2
  6. package/dist/composables/useMemiBoardUserPosts.d.ts +20 -0
  7. package/dist/composables/useMemiBoardUsers.d.ts +1 -1
  8. package/dist/composables/useMemiBoardViews.d.ts +1 -1
  9. package/dist/config.d.ts +8 -2
  10. package/dist/index.d.ts +3 -2
  11. package/dist/index.js +609 -476
  12. package/dist/index.js.map +1 -1
  13. package/dist/runtime/components/Attachments.vue +1 -2
  14. package/dist/runtime/components/AuthorMenu.vue +47 -0
  15. package/dist/runtime/components/CategorySettings.vue +40 -6
  16. package/dist/runtime/components/CommentItem.vue +8 -7
  17. package/dist/runtime/components/Detail.vue +95 -17
  18. package/dist/runtime/components/Editor.vue +2 -3
  19. package/dist/runtime/components/Footer.vue +9 -7
  20. package/dist/runtime/components/List.vue +3 -0
  21. package/dist/runtime/components/ListDefault.vue +56 -36
  22. package/dist/runtime/components/ListDense.vue +67 -50
  23. package/dist/runtime/components/ListImage.vue +10 -2
  24. package/dist/runtime/components/ListVideo.vue +63 -40
  25. package/dist/runtime/components/SwipeHint.vue +83 -0
  26. package/dist/runtime/components/UserPostList.vue +83 -0
  27. package/dist/types.d.ts +30 -5
  28. package/dist/utils/boardPaths.d.ts +26 -15
  29. package/docs/firebase-setup.md +3 -4
  30. package/docs/firestore.indexes.json.example +127 -0
  31. package/docs/firestore.rules.example +119 -60
  32. package/docs/storage.rules.example +13 -12
  33. package/package.json +1 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@ Nuxt 4 + Nuxt UI + Firebase 프로젝트에 게시판을 붙이는 npm 패키지
10
10
  **서버 / Firebase Admin 불필요** (권한은 Rules, 검열은 브라우저 — 우회 가능, 아래 한계 참고).
11
11
  공개 목록·글 상세만 SSR로 OG를 채우고, 쓰기·설정은 CSR로 두면 된다.
12
12
 
13
- 같은 스택(Nuxt 4 · `@nuxt/ui` · `nuxt-vuefire` · Firebase)이면 **다른 호스트 앱에도 그대로 재사용** 가능하다. Firebase 프로젝트는 호스트마다 달라도 되고, 같은 프로젝트에서는 `boardId`로 게시판 인스턴스를 나눈다 (`memiBoards/{boardId}/…`).
13
+ 같은 스택(Nuxt 4 · `@nuxt/ui` · `nuxt-vuefire` · Firebase)이면 **다른 호스트 앱에도 그대로 재사용** 가능하다. Firebase 프로젝트는 호스트마다 달라도 되고, 같은 프로젝트에서는 `boardId`로 게시판 인스턴스를 나눈다 — `memiBoardPosts`/`memiBoardComments`/`memiBoardLikes`는 모두 최상위 flat 컬렉션이고 `boardId`는 각 문서의 필드다(경로 세그먼트가 아니다).
14
14
 
15
15
  ## 플랫폼 요구사항
16
16
 
@@ -71,9 +71,8 @@ export default defineNuxtConfig({
71
71
  ],
72
72
 
73
73
  memiBoard: {
74
- // Firestore: memiBoards/{boardId}/posts|settings|users
75
- boardsCollection: 'memiBoards', // 기본값
76
- boardId: 'main', // 게시판 인스턴스 ID (필수에 가깝다)
74
+ // Firestore: memiBoardPosts / memiBoardComments / memiBoardLikes / memiBoardSettings / memiBoardUsers
75
+ // (전부 flat 컬렉션 — boardId 는 각 문서의 필드. 컴포저블 호출 시 boardId 인자로 지정)
77
76
  auth: { providers: ['google', 'apple'] }, // + 'emailPassword'
78
77
  moderation: {
79
78
  enabled: true,
@@ -135,8 +134,11 @@ export default defineNuxtConfig({
135
134
 
136
135
  | 키 | 기본 | 설명 |
137
136
  |----|------|------|
138
- | `boardsCollection` | `'memiBoards'` | 루트 컬렉션 이름 |
139
- | `boardId` | `'default'` | `memiBoards/{boardId}/…` 게시판 문서 ID |
137
+ | `postsCollection` | `'memiBoardPosts'` | 글 컬렉션 이름 |
138
+ | `commentsCollection` | `'memiBoardComments'` | 댓글 컬렉션 이름 |
139
+ | `likesCollection` | `'memiBoardLikes'` | 좋아요 컬렉션 이름 |
140
+ | `settingsCollection` | `'memiBoardSettings'` | 보드 설정 컬렉션 이름 |
141
+ | `usersCollection` | `'memiBoardUsers'` | 역할 문서 컬렉션 이름 |
140
142
  | `auth.providers` | `['google','apple']` | 로그인 공급자 |
141
143
  | `moderation.*` | (아래 AI 절) | 로컬·Gemini 검열 |
142
144
  | `seo.enabled` | `true` | `false`면 SEO composable no-op |
@@ -213,7 +215,7 @@ const { post: postSeo } = await useMemiBoardPostSeo({
213
215
  ### 3. 부모 설정 체크리스트
214
216
 
215
217
  - [ ] `modules`에 `@nuxt/ui`, `nuxt-vuefire`, `memi-board`
216
- - [ ] `memiBoard.boardId` · `auth` · `moderation` · **`seo`**
218
+ - [ ] `memiBoard.auth` · `moderation` · **`seo`**
217
219
  - [ ] `seo.siteUrl` / `seo.siteName` / `seo.defaultOgImage` / `seo.basePath`
218
220
  - [ ] 공개 board 경로 **SSR on**, 쓰기·설정만 `ssr: false`
219
221
  - [ ] 목록·상세 페이지에 `await useMemiBoard*Seo(…)` 한 줄
@@ -236,9 +238,9 @@ const { post: postSeo } = await useMemiBoardPostSeo({
236
238
  ### 5. Security Rules + 인덱스 배포
237
239
 
238
240
  1. [docs/firestore.rules.example](docs/firestore.rules.example) → 호스트 `firestore.rules`에 병합
239
- (`memiBoards/{boardId}/…` 경로 — boardId 는 호스트 설정과 동일)
241
+ (`memiBoardPosts`/`memiBoardComments`/`memiBoardLikes`/`memiBoardSettings`/`memiBoardUsers` — 전부 최상위 flat 컬렉션)
240
242
  2. [docs/storage.rules.example](docs/storage.rules.example) → `storage.rules` 병합
241
- 3. 카테고리 필터 목록을 쓰면 복합 인덱스 필요 (아래)
243
+ 3. 목록/작성자별 쿼리에 필요한 복합 인덱스 배포 (아래)
242
244
  4. 배포:
243
245
  ```bash
244
246
  firebase deploy --only firestore:rules,storage,firestore:indexes
@@ -246,24 +248,9 @@ const { post: postSeo } = await useMemiBoardPostSeo({
246
248
 
247
249
  **Rules를 파일에만 넣고 배포 안 하면** 글쓰기에서 `permission-denied` — 가장 흔한 설치 실수.
248
250
 
249
- #### 카테고리 목록용 인덱스 예시
250
-
251
- `firestore.indexes.json` (컬렉션 ID는 prefix에 맞게):
252
-
253
- ```json
254
- {
255
- "indexes": [
256
- {
257
- "collectionGroup": "posts",
258
- "queryScope": "COLLECTION",
259
- "fields": [
260
- { "fieldPath": "category", "order": "ASCENDING" },
261
- { "fieldPath": "createdAt", "order": "DESCENDING" }
262
- ]
263
- }
264
- ]
265
- }
266
- ```
251
+ #### 복합 인덱스
252
+
253
+ [docs/firestore.indexes.json.example](docs/firestore.indexes.json.example) 를 호스트 `firestore.indexes.json`에 병합한다. 컬렉션 이름을 커스터마이즈했다면(`memiBoard.postsCollection` 등) 인덱스의 `collectionGroup` 값도 그에 맞게 바꿔야 한다.
267
254
 
268
255
  > ⚠️ npm 패키지 tarball에도 `docs/` 가 포함된다(0.4.7+). 구버전이면 GitHub의 `docs/`를 보면 된다.
269
256
 
@@ -272,9 +259,8 @@ const { post: postSeo } = await useMemiBoardPostSeo({
272
259
  Rules는 일반 사용자가 스스로 관리자가 되는 것을 막는다. 따라서 최초 한 번은 다음 순서가 필요하다.
273
260
 
274
261
  1. 아래 게시판 페이지를 만든 뒤 Google 또는 Apple로 로그인한다.
275
- 2. Firebase Console → Firestore에서 `memiBoards/{boardId}/users/{uid}` 문서를 찾는다.
262
+ 2. Firebase Console → Firestore에서 `memiBoardUsers/{uid}` 문서를 찾는다.
276
263
  3. 해당 문서의 `role`을 문자열 `admin`으로 변경한다.
277
- - 예: `boardId: 'main'` → `memiBoards/main/users/{uid}`
278
264
  - UID는 Firebase Console → Authentication → Users에서도 확인할 수 있다.
279
265
  4. `/board-settings`에서 첫 카테고리를 만든다. 카테고리가 없으면 글을 작성할 수 없다.
280
266
  5. 이후 역할 변경은 `/board-users`의 `MemiBoardUsers`에서 처리한다.
@@ -360,7 +346,7 @@ const router = useRouter()
360
346
 
361
347
  ### 관리 페이지
362
348
 
363
- 기본 Rules는 게시판의 `memiBoards/{boardId}/users/{uid}.role == 'admin'`을 검사한다. 컴포넌트도 같은 role을 확인하므로 기본 설치에서는 `authorized`를 전달하지 않는다.
349
+ 기본 Rules는 게시판의 `memiBoardUsers/{uid}.role == 'admin'`을 검사한다. 컴포넌트도 같은 role을 확인하므로 기본 설치에서는 `authorized`를 전달하지 않는다.
364
350
 
365
351
  ```vue
366
352
  <!-- app/pages/board-settings.vue -->
@@ -389,7 +375,7 @@ const router = useRouter()
389
375
  본문은 Nuxt UI **`UEditor`**(TipTap, `content-type="html"`). 호스트 `@nuxt/ui` 4.x 에 Editor 포함 필요.
390
376
 
391
377
  **에디터 이미지:** 툴바 / 붙여넣기 / 드롭 → Firebase Storage
392
- `memiBoards/{boardId}/posts/{postId}/images/*` + `.../images/thumbnails/*` (최적화 이미지+썸네일).
378
+ `memiBoardPosts/{postId}/images/*` + `.../images/thumbnails/*` (최적화 이미지+썸네일).
393
379
 
394
380
  본문 이미지는 휴대폰 원본 기준 최대 25MB까지 선택할 수 있다. 5MB를 넘으면 브라우저에서 최대 2560px·JPEG 85%로 최적화하고, 결과가 여전히 5MB를 넘으면 2048px·75%로 한 번 더 줄인 뒤 업로드한다. 5MB 이하 이미지는 원본을 유지한다.
395
381
  본문 HTML에는 원본 URL. 수정 중 버려진 파일은 호스트 스케줄러로 정리 (`extractEditorImageUrls` 로 본문 참조 비교).
@@ -403,12 +389,12 @@ const router = useRouter()
403
389
 
404
390
  댓글은 시간순으로 10개씩 cursor 조회하며, 실제 `댓글 더보기` 버튼이 화면에 들어오면 1초 후 자동으로 다음 페이지를 읽는다. 기존 댓글을 모두 읽은 뒤에만 최신 댓글 1개를 실시간 구독한다. 대댓글은 5개씩 조회하고 모두 읽은 뒤 최신 답글 1개를 실시간 구독하며, 화면 깊이는 최대 2단계로 표시한다.
405
391
 
406
- ### 카테고리
392
+ ### 보드 (구 카테고리)
407
393
 
408
- - 문서: `memiBoards/{boardId}/settings/config/categories/{categoryId}` → `{ label, listView, writeRole, order, updatedAt }`
409
- - 설정이 없으면 빈 목록이며 기본 카테고리를 자동 생성하지 않음
410
- - `MemiBoardSettings`에서 관리자가 카테고리별 저장·삭제·순서·리스트뷰·글쓰기 최소 역할 관리
411
- - `categoryId`는 문서 ID이자 게시글의 `category` 참조값이므로 생성 후 변경하지 않는 것을 권장
394
+ - 문서: `memiBoardSettings/{boardId}` → `{ label, listView, writeRole, commentWriteRole, visibility, allowedStaffUids, order, updatedAt }`
395
+ - 설정이 없으면 빈 목록이며 기본 보드를 자동 생성하지 않음
396
+ - `MemiBoardSettings`에서 관리자가 보드별 저장·삭제·순서·리스트뷰·글쓰기 최소 역할 관리
397
+ - `boardId`는 문서 ID이자 각 글(`memiBoardPosts`)의 `boardId` 참조값이므로 생성 후 변경하지 않는 것을 권장
412
398
 
413
399
  ### 로그인 공급자
414
400
 
@@ -432,7 +418,7 @@ const router = useRouter()
432
418
  | 글/댓글 읽기 | 공개 |
433
419
  | 글 작성 | 로그인 + 카테고리 `writeRole` 충족 + `moderationStatus == 'approved'` |
434
420
  | 댓글 작성 | 로그인 + `moderationStatus == 'approved'` (클라가 항상 approved 로 씀 — 검열 통과 후에만 write) |
435
- | 글 수정·삭제 | 작성자 또는 `memiBoards/{boardId}/users/{uid}.role in ['admin', 'staff']` |
421
+ | 글 수정·삭제 | 작성자 또는 `memiBoardUsers/{uid}.role in ['admin', 'staff']` |
436
422
  | 댓글 삭제 | 댓글 작성자 · 글 작성자 · admin · staff |
437
423
  | 역할 관리 | `MemiBoardUsers`에서 admin이 `admin`·`staff`·`user` 변경 |
438
424
 
@@ -452,7 +438,7 @@ const router = useRouter()
452
438
  | `blockBanThreshold` | `3` | 콘텐츠 차단(local/ai) 누적 이상이면 글·댓글 제한. `0` = off |
453
439
  | `blockBanDecayMs` | `86400000` | 경고 1회 차감 간격(기본 24h) |
454
440
 
455
- 콘텐츠 차단이 누적되면 `memiBoards/{boardId}/users/{uid}` 에 `moderationBlockCount` / `moderationBlockAt` 이 기록된다.
441
+ 콘텐츠 차단이 누적되면 `memiBoardUsers/{uid}` 에 `moderationBlockCount` / `moderationBlockAt` 이 기록된다.
456
442
  3회면 약 하루 동안 작성 불가(24h마다 1 차감). Rules 예시에서 본인은 **+1만** 가능하고 감소·리셋은 admin.
457
443
 
458
444
  콘솔에서 **AI Logic(Gemini Developer API)** 활성화. 신규 프로젝트는 구형 `gemini-2.5-flash` 가 404 날 수 있음 → 3.x Flash / Flash-Lite 사용.
@@ -498,12 +484,12 @@ export default defineNuxtPlugin(() => {
498
484
  - [ ] Rules 예시 병합 + **deploy**
499
485
  - [ ] 카테고리·listed 쿼리 사용 시 indexes deploy
500
486
  - [ ] 페이지·미들웨어 직접 작성 (또는 playground 복사)
501
- - [ ] 최초 로그인 후 Firebase Console에서 `memiBoards/{boardId}/users/{uid}.role = 'admin'`
487
+ - [ ] 최초 로그인 후 Firebase Console에서 `memiBoardUsers/{uid}.role = 'admin'`
502
488
  - [ ] 설정 페이지에서 첫 카테고리 생성
503
489
  - [ ] (검열) AI Logic 활성화 + 권장 모델 + App Check
504
490
  - [ ] `pnpm why vuefire` 로 이중 인스턴스 없는지 확인
505
491
 
506
- 같은 Firebase 프로젝트에 호스트 앱 유저 컬렉션이 있어도 무방 — 게시판 역할은 **`memiBoards/{boardId}/users` 전용**이다.
492
+ 같은 Firebase 프로젝트에 호스트 앱 유저 컬렉션이 있어도 무방 — 게시판 역할은 **`memiBoardUsers` 전용**이다.
507
493
 
508
494
  ## 문제 해결
509
495
 
@@ -25,11 +25,15 @@ export declare function useMemiBoardComments(boardId: MaybeRefOrGetter<string>,
25
25
  setCommentBlinded: (commentId: string, isBlinded: boolean, moderatorUid: string) => Promise<void>;
26
26
  deleteComment: (comment: CommentModel) => Promise<void>;
27
27
  };
28
- /** 펼친 스레드의 답글을 5개씩 일회성 조회한다. */
28
+ /**
29
+ * 펼친 스레드의 답글을 5개씩 일회성 조회한다.
30
+ * rootId 는 전역 고유(댓글 auto-ID)라 postId 필터 없이도 정확히 한 스레드로 스코핑된다.
31
+ */
29
32
  export declare function useMemiBoardReplies(boardId: string, postId: string, rootId: string): {
30
33
  replies: Ref<{
31
34
  id?: string | undefined;
32
35
  postId: string;
36
+ boardId: string;
33
37
  body: string;
34
38
  authorUid: string;
35
39
  authorName: string | null;
@@ -89,6 +93,7 @@ export declare function useMemiBoardReplies(boardId: string, postId: string, roo
89
93
  }[], CommentModel[] | {
90
94
  id?: string | undefined;
91
95
  postId: string;
96
+ boardId: string;
92
97
  body: string;
93
98
  authorUid: string;
94
99
  authorName: string | null;
@@ -50,6 +50,7 @@ export declare function useMemiBoardPosts(boardId: MaybeRefOrGetter<string>): {
50
50
  }>;
51
51
  createPost: (input: CreatePostInput) => Promise<string>;
52
52
  updatePost: (id: string, input: UpdatePostInput) => Promise<void>;
53
+ publishPost: (id: string) => Promise<void>;
53
54
  deletePost: (id: string) => Promise<void>;
54
55
  };
55
56
  export declare function useMemiBoardPostList(boardId: MaybeRefOrGetter<string>, options?: {
@@ -5,8 +5,8 @@ export declare const DEFAULT_BOARDS: BoardModel[];
5
5
  export declare const DEFAULT_CATEGORIES: BoardModel[];
6
6
  /**
7
7
  * 보드 목록·설정.
8
- * - 목록: memiBoards 컬렉션 (부모 문서에 메타 복제)
9
- * - 설정 원본: memiBoards/{boardId}/settings/config
8
+ * memiBoardSettings/{boardId} 하나가 목록 렌더링과 권한 검사를 모두 겸한다
9
+ * (구버전은 부모 문서 + settings/config 이중 문서였다).
10
10
  */
11
11
  export declare function useMemiBoardSettings(): {
12
12
  boards: import('vue').ComputedRef<BoardModel[]>;
@@ -4,11 +4,11 @@ export declare const EDITOR_IMAGE_MAX_BYTES: number;
4
4
  /** 휴대폰 원본 이미지 선택 허용 크기. 큰 이미지는 업로드 전에 최적화한다. */
5
5
  export declare const EDITOR_IMAGE_SOURCE_MAX_BYTES: number;
6
6
  export declare function useMemiBoardStorage(): {
7
- uploadAttachment: (file: File, boardId: string, postId: string, onProgress?: (ratio: number) => void) => {
7
+ uploadAttachment: (file: File, postId: string, onProgress?: (ratio: number) => void) => {
8
8
  promise: Promise<Attachment>;
9
9
  cancel: () => void;
10
10
  };
11
11
  deleteAttachment: (attachment: Pick<Attachment, "path">) => Promise<void>;
12
- uploadEditorImage: (file: File, boardId: string, postId: string) => Promise<EditorImageEntry>;
12
+ uploadEditorImage: (file: File, postId: string) => Promise<EditorImageEntry>;
13
13
  deleteEditorImage: (entry: Pick<EditorImageEntry, "originalPath" | "thumbnailPath">) => Promise<void>;
14
14
  };
@@ -0,0 +1,20 @@
1
+ import { MaybeRefOrGetter } from 'vue';
2
+ import { UserPostModel } from '../types';
3
+ /**
4
+ * 작성자 uid로 모든 보드를 가로질러 글을 모은다.
5
+ * memiBoardPosts 가 flat 컬렉션이라 일반 where('authorUid',...) 쿼리로 충분 —
6
+ * collectionGroup 이 필요했던 건 구버전이 보드별 posts 서브컬렉션이었을 때뿐.
7
+ * 공개 글만 — canReadPost rules와 같은 기준(listed && isPublished)이라
8
+ * 본인이 아니면 숨김 보드·미게시 글은 애초에 안 온다.
9
+ */
10
+ export declare function useMemiBoardUserPosts(uid: MaybeRefOrGetter<string>, options?: {
11
+ pageSize?: number;
12
+ }): {
13
+ posts: import('vue').ComputedRef<import('..').PostModel[]>;
14
+ postsPending: import('vue').Ref<boolean, boolean>;
15
+ hasMore: import('vue').Ref<boolean, boolean>;
16
+ loadingMore: import('vue').Ref<boolean, boolean>;
17
+ loadError: import('vue').Ref<string, string>;
18
+ loadMore: () => Promise<void>;
19
+ };
20
+ export type { UserPostModel };
@@ -10,7 +10,7 @@ export declare const BOARD_USER_ROLES: Array<{
10
10
  * 쿼리 자체를 시작하지 않는다 — 그냥 호출만 하면 권한 확인 전에 구독이 걸려서
11
11
  * 관리자가 아니거나 아직 role을 확인 중일 때 permission-denied로 화면이 죽는다.
12
12
  *
13
- * 경로: memiBoards/{boardId}/users/{uid}
13
+ * 경로: memiBoardUsers/{uid} (flat)
14
14
  */
15
15
  export declare function useMemiBoardUsers(options?: {
16
16
  enabled?: MaybeRefOrGetter<boolean>;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 게시글 조회수 (보드 단위 posts).
2
+ * 게시글 조회수 (memiBoardPosts, flat).
3
3
  */
4
4
  export declare function useMemiBoardViews(): {
5
5
  recordView: (boardId: string, postId: string) => Promise<void>;
package/dist/config.d.ts CHANGED
@@ -24,8 +24,14 @@ export interface MemiBoardSeoOptions {
24
24
  basePath?: string;
25
25
  }
26
26
  export interface MemiBoardConfig {
27
- /** 루트 컬렉션. 기본 `memiBoards` */
28
- boardsCollection: string;
27
+ /** 글 컬렉션. 기본 `memiBoardPosts` */
28
+ postsCollection: string;
29
+ /** 댓글 컬렉션. 기본 `memiBoardComments` */
30
+ commentsCollection: string;
31
+ /** 좋아요 컬렉션. 기본 `memiBoardLikes` */
32
+ likesCollection: string;
33
+ /** 보드 설정 컬렉션. 기본 `memiBoardSettings` */
34
+ settingsCollection: string;
29
35
  /** 역할 문서 컬렉션. 기본 `memiBoardUsers` */
30
36
  usersCollection: string;
31
37
  auth: MemiBoardAuthOptions;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /** Runtime API — composables / config / types only. UI SFC는 루트 Nuxt 모듈이 등록. */
2
2
  export { configureMemiBoard, useMemiBoardConfig, useBoardPathConfig } from './config';
3
3
  export type { MemiBoardConfig, MemiBoardAuthOptions, MemiBoardModerationOptions, MemiBoardSeoOptions, } from './config';
4
- export { DEFAULT_BOARDS_COLLECTION, DEFAULT_USERS_COLLECTION, resolveBoardPathConfig, boardsCol, boardDoc, boardSettingsDoc, boardPostsCol, boardPostDoc, boardPostBodyDoc, boardPostCommentsCol, boardPostCommentDoc, boardPostLikeDoc, boardUsersCol, boardUserDoc, boardStorageRoot, boardPostStorageFolder, boardSsrKey, } from './utils/boardPaths';
4
+ export { DEFAULT_POSTS_COLLECTION, DEFAULT_COMMENTS_COLLECTION, DEFAULT_LIKES_COLLECTION, DEFAULT_SETTINGS_COLLECTION, DEFAULT_USERS_COLLECTION, resolveBoardPathConfig, settingsCol, settingsDoc, postsCol, postDoc, postBodyDoc, commentsCol, commentDoc, likesCol, likeDoc, likeDocId, boardUsersCol, boardUserDoc, postStorageFolder, boardSsrKey, } from './utils/boardPaths';
5
5
  export type { BoardPathConfig } from './utils/boardPaths';
6
6
  export { fetchPublicPostForSeo, fetchPublicListForSeo, resolvePublicSeoDb, } from './composables/fetchPublicSeo';
7
7
  export type { PublicSeoDb } from './composables/fetchPublicSeo';
@@ -11,6 +11,7 @@ export { useMemiBoardAuth } from './composables/useMemiBoardAuth';
11
11
  export { useMemiBoardPosts, useMemiBoardPostList, useMemiBoardPost } from './composables/useMemiBoardPosts';
12
12
  export type { CreatePostInput, UpdatePostInput, GetPostBySlugResult } from './composables/useMemiBoardPosts';
13
13
  export { isFirestorePermissionDenied } from './composables/useMemiBoardPosts';
14
+ export { useMemiBoardUserPosts } from './composables/useMemiBoardUserPosts';
14
15
  export { COMMENT_BODY_MAX_LENGTH, useMemiBoardComments, useMemiBoardReplies } from './composables/useMemiBoardComments';
15
16
  export type { AddCommentInput, AddReplyInput } from './composables/useMemiBoardComments';
16
17
  export { useMemiBoardLikes } from './composables/useMemiBoardLikes';
@@ -24,7 +25,7 @@ export type { VersionHistoryEntry } from './data/versionHistory';
24
25
  export { formatDate, formatFullDate, formatRelativeDate, formatTimestampDetails } from './utils/formatDate';
25
26
  export { slugify } from './utils/slugify';
26
27
  export { DEFAULT_BLOCK_BAN_THRESHOLD, DEFAULT_BLOCK_BAN_DECAY_MS, effectiveModerationBlockCount, isModerationWriteRestricted, moderationWriteRestrictedUntilMs, formatRestrictedUntilLabel, } from './utils/moderation-strike';
27
- export type { Attachment, EditorImageEntry, ModerationStatus, PostModel, PostDetail, CommentModel, BoardUserRole, BoardUserModel, BoardCategory, BoardModel, BoardListView, BoardWriteRole, BoardVisibility, BoardSettingsModel, ModerationResult, } from './types';
28
+ export type { Attachment, EditorImageEntry, ModerationStatus, PostModel, PostDetail, UserPostModel, CommentModel, BoardUserRole, BoardUserModel, BoardCategory, BoardModel, BoardListView, BoardWriteRole, BoardVisibility, BoardSettingsModel, BoardLikeModel, ModerationResult, } from './types';
28
29
  export { plainTextFromHtml, hasBodyText, hasBodyImage, isContentEmpty, titleFromBody, } from './utils/postBody';
29
30
  export { compressImage } from './utils/compressImage';
30
31
  export { extractEditorImageUrls } from './utils/extractEditorImageUrls';