@btst/stack 2.7.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +1 -0
  2. package/dist/packages/stack/src/plugins/blog/client/components/loading/post-navigation-skeleton.cjs +13 -0
  3. package/dist/packages/stack/src/plugins/blog/client/components/loading/post-navigation-skeleton.mjs +11 -0
  4. package/dist/packages/stack/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.cjs +17 -0
  5. package/dist/packages/stack/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.mjs +15 -0
  6. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +18 -7
  7. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +18 -7
  8. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-navigation.cjs +48 -52
  9. package/dist/packages/stack/src/plugins/blog/client/components/shared/post-navigation.mjs +49 -53
  10. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.cjs +34 -37
  11. package/dist/packages/stack/src/plugins/blog/client/components/shared/recent-posts-carousel.mjs +35 -38
  12. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-hooks.cjs +4 -21
  13. package/dist/packages/stack/src/plugins/blog/client/hooks/blog-hooks.mjs +4 -21
  14. package/dist/packages/stack/src/plugins/comments/api/getters.cjs +284 -0
  15. package/dist/packages/stack/src/plugins/comments/api/getters.mjs +280 -0
  16. package/dist/packages/stack/src/plugins/comments/api/mutations.cjs +118 -0
  17. package/dist/packages/stack/src/plugins/comments/api/mutations.mjs +112 -0
  18. package/dist/packages/stack/src/plugins/comments/api/plugin.cjs +335 -0
  19. package/dist/packages/stack/src/plugins/comments/api/plugin.mjs +333 -0
  20. package/dist/packages/stack/src/plugins/comments/api/query-key-defs.cjs +60 -0
  21. package/dist/packages/stack/src/plugins/comments/api/query-key-defs.mjs +55 -0
  22. package/dist/packages/stack/src/plugins/comments/api/serializers.cjs +23 -0
  23. package/dist/packages/stack/src/plugins/comments/api/serializers.mjs +21 -0
  24. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.cjs +46 -0
  25. package/dist/packages/stack/src/plugins/comments/client/components/comment-count.mjs +44 -0
  26. package/dist/packages/stack/src/plugins/comments/client/components/comment-form.cjs +86 -0
  27. package/dist/packages/stack/src/plugins/comments/client/components/comment-form.mjs +84 -0
  28. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.cjs +540 -0
  29. package/dist/packages/stack/src/plugins/comments/client/components/comment-thread.mjs +538 -0
  30. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.cjs +64 -0
  31. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.cjs +426 -0
  32. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.internal.mjs +424 -0
  33. package/dist/packages/stack/src/plugins/comments/client/components/pages/moderation-page.mjs +62 -0
  34. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.cjs +66 -0
  35. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.cjs +256 -0
  36. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.internal.mjs +254 -0
  37. package/dist/packages/stack/src/plugins/comments/client/components/pages/my-comments-page.mjs +64 -0
  38. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.cjs +86 -0
  39. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.cjs +191 -0
  40. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.internal.mjs +189 -0
  41. package/dist/packages/stack/src/plugins/comments/client/components/pages/resource-comments-page.mjs +84 -0
  42. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.cjs +27 -0
  43. package/dist/packages/stack/src/plugins/comments/client/components/shared/page-wrapper.mjs +25 -0
  44. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.cjs +37 -0
  45. package/dist/packages/stack/src/plugins/comments/client/components/shared/pagination.mjs +35 -0
  46. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.cjs +476 -0
  47. package/dist/packages/stack/src/plugins/comments/client/hooks/use-comments.mjs +464 -0
  48. package/dist/packages/stack/src/plugins/comments/client/localization/comments-moderation.cjs +67 -0
  49. package/dist/packages/stack/src/plugins/comments/client/localization/comments-moderation.mjs +65 -0
  50. package/dist/packages/stack/src/plugins/comments/client/localization/comments-my.cjs +27 -0
  51. package/dist/packages/stack/src/plugins/comments/client/localization/comments-my.mjs +25 -0
  52. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.cjs +30 -0
  53. package/dist/packages/stack/src/plugins/comments/client/localization/comments-thread.mjs +28 -0
  54. package/dist/packages/stack/src/plugins/comments/client/localization/index.cjs +13 -0
  55. package/dist/packages/stack/src/plugins/comments/client/localization/index.mjs +11 -0
  56. package/dist/packages/stack/src/plugins/comments/client/plugin.cjs +116 -0
  57. package/dist/packages/stack/src/plugins/comments/client/plugin.mjs +114 -0
  58. package/dist/packages/stack/src/plugins/comments/client/utils.cjs +41 -0
  59. package/dist/packages/stack/src/plugins/comments/client/utils.mjs +37 -0
  60. package/dist/packages/stack/src/plugins/comments/db.cjs +75 -0
  61. package/dist/packages/stack/src/plugins/comments/db.mjs +73 -0
  62. package/dist/packages/stack/src/plugins/comments/schemas.cjs +45 -0
  63. package/dist/packages/stack/src/plugins/comments/schemas.mjs +38 -0
  64. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.cjs +0 -1
  65. package/dist/packages/stack/src/plugins/kanban/client/components/forms/task-form.mjs +0 -1
  66. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.cjs +39 -22
  67. package/dist/packages/stack/src/plugins/kanban/client/components/pages/board-page.internal.mjs +40 -23
  68. package/dist/packages/ui/src/components/avatar.mjs +1 -1
  69. package/dist/packages/ui/src/components/pagination-controls.cjs +64 -0
  70. package/dist/packages/ui/src/components/pagination-controls.mjs +62 -0
  71. package/dist/packages/ui/src/components/when-visible.cjs +39 -0
  72. package/dist/packages/ui/src/components/when-visible.mjs +37 -0
  73. package/dist/plugins/blog/client/hooks/index.d.cts +1 -1
  74. package/dist/plugins/blog/client/hooks/index.d.mts +1 -1
  75. package/dist/plugins/blog/client/hooks/index.d.ts +1 -1
  76. package/dist/plugins/blog/client/index.d.cts +24 -2
  77. package/dist/plugins/blog/client/index.d.mts +24 -2
  78. package/dist/plugins/blog/client/index.d.ts +24 -2
  79. package/dist/plugins/comments/api/index.cjs +21 -0
  80. package/dist/plugins/comments/api/index.d.cts +126 -0
  81. package/dist/plugins/comments/api/index.d.mts +126 -0
  82. package/dist/plugins/comments/api/index.d.ts +126 -0
  83. package/dist/plugins/comments/api/index.mjs +5 -0
  84. package/dist/plugins/comments/client/components/index.cjs +15 -0
  85. package/dist/plugins/comments/client/components/index.d.cts +125 -0
  86. package/dist/plugins/comments/client/components/index.d.mts +125 -0
  87. package/dist/plugins/comments/client/components/index.d.ts +125 -0
  88. package/dist/plugins/comments/client/components/index.mjs +5 -0
  89. package/dist/plugins/comments/client/hooks/index.cjs +17 -0
  90. package/dist/plugins/comments/client/hooks/index.d.cts +200 -0
  91. package/dist/plugins/comments/client/hooks/index.d.mts +200 -0
  92. package/dist/plugins/comments/client/hooks/index.d.ts +200 -0
  93. package/dist/plugins/comments/client/hooks/index.mjs +1 -0
  94. package/dist/plugins/comments/client/index.cjs +9 -0
  95. package/dist/plugins/comments/client/index.d.cts +262 -0
  96. package/dist/plugins/comments/client/index.d.mts +262 -0
  97. package/dist/plugins/comments/client/index.d.ts +262 -0
  98. package/dist/plugins/comments/client/index.mjs +2 -0
  99. package/dist/plugins/comments/client.css +2 -0
  100. package/dist/plugins/comments/query-keys.cjs +113 -0
  101. package/dist/plugins/comments/query-keys.d.cts +71 -0
  102. package/dist/plugins/comments/query-keys.d.mts +71 -0
  103. package/dist/plugins/comments/query-keys.d.ts +71 -0
  104. package/dist/plugins/comments/query-keys.mjs +111 -0
  105. package/dist/plugins/comments/style.css +15 -0
  106. package/dist/plugins/kanban/api/index.d.cts +1 -1
  107. package/dist/plugins/kanban/api/index.d.mts +1 -1
  108. package/dist/plugins/kanban/api/index.d.ts +1 -1
  109. package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
  110. package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
  111. package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
  112. package/dist/plugins/kanban/client/index.d.cts +1 -1
  113. package/dist/plugins/kanban/client/index.d.mts +1 -1
  114. package/dist/plugins/kanban/client/index.d.ts +1 -1
  115. package/dist/plugins/kanban/query-keys.d.cts +1 -1
  116. package/dist/plugins/kanban/query-keys.d.mts +1 -1
  117. package/dist/plugins/kanban/query-keys.d.ts +1 -1
  118. package/dist/shared/{stack.FeaWkglm.d.ts → stack.BxFl46lB.d.cts} +24 -1
  119. package/dist/shared/stack.C-b3Sn8j.d.cts +142 -0
  120. package/dist/shared/stack.C-b3Sn8j.d.mts +142 -0
  121. package/dist/shared/stack.C-b3Sn8j.d.ts +142 -0
  122. package/dist/shared/stack.CJE9sAjV.d.ts +335 -0
  123. package/dist/shared/stack.CmHRdhl8.d.cts +335 -0
  124. package/dist/shared/{stack.CNLHlv7r.d.mts → stack.DOZ1EXjM.d.mts} +6 -12
  125. package/dist/shared/{stack.FeaWkglm.d.mts → stack.DRpeDS6X.d.ts} +24 -1
  126. package/dist/shared/{stack.CQAZwXhV.d.cts → stack.DX-tQ93o.d.cts} +6 -12
  127. package/dist/shared/stack.Dcz6636A.d.mts +335 -0
  128. package/dist/shared/{stack.FeaWkglm.d.cts → stack.Jb0kQDJC.d.mts} +24 -1
  129. package/dist/shared/stack.Ldfkr5b2.d.cts +112 -0
  130. package/dist/shared/stack.Ldfkr5b2.d.mts +112 -0
  131. package/dist/shared/stack.Ldfkr5b2.d.ts +112 -0
  132. package/dist/shared/{stack.D3BsrpAz.d.ts → stack.VF6FhyZw.d.ts} +6 -12
  133. package/package.json +69 -4
  134. package/src/plugins/blog/client/components/loading/post-navigation-skeleton.tsx +10 -0
  135. package/src/plugins/blog/client/components/loading/recent-posts-carousel-skeleton.tsx +18 -0
  136. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +23 -8
  137. package/src/plugins/blog/client/components/shared/post-navigation.tsx +0 -5
  138. package/src/plugins/blog/client/components/shared/recent-posts-carousel.tsx +1 -5
  139. package/src/plugins/blog/client/hooks/blog-hooks.tsx +8 -33
  140. package/src/plugins/blog/client/overrides.ts +26 -1
  141. package/src/plugins/cms/client/components/shared/pagination.tsx +14 -42
  142. package/src/plugins/comments/api/getters.ts +444 -0
  143. package/src/plugins/comments/api/index.ts +21 -0
  144. package/src/plugins/comments/api/mutations.ts +206 -0
  145. package/src/plugins/comments/api/plugin.ts +628 -0
  146. package/src/plugins/comments/api/query-key-defs.ts +143 -0
  147. package/src/plugins/comments/api/serializers.ts +37 -0
  148. package/src/plugins/comments/client/components/comment-count.tsx +66 -0
  149. package/src/plugins/comments/client/components/comment-form.tsx +112 -0
  150. package/src/plugins/comments/client/components/comment-thread.tsx +799 -0
  151. package/src/plugins/comments/client/components/index.tsx +11 -0
  152. package/src/plugins/comments/client/components/pages/moderation-page.internal.tsx +550 -0
  153. package/src/plugins/comments/client/components/pages/moderation-page.tsx +70 -0
  154. package/src/plugins/comments/client/components/pages/my-comments-page.internal.tsx +367 -0
  155. package/src/plugins/comments/client/components/pages/my-comments-page.tsx +72 -0
  156. package/src/plugins/comments/client/components/pages/resource-comments-page.internal.tsx +225 -0
  157. package/src/plugins/comments/client/components/pages/resource-comments-page.tsx +97 -0
  158. package/src/plugins/comments/client/components/shared/page-wrapper.tsx +32 -0
  159. package/src/plugins/comments/client/components/shared/pagination.tsx +44 -0
  160. package/src/plugins/comments/client/hooks/index.tsx +13 -0
  161. package/src/plugins/comments/client/hooks/use-comments.tsx +717 -0
  162. package/src/plugins/comments/client/index.ts +14 -0
  163. package/src/plugins/comments/client/localization/comments-moderation.ts +75 -0
  164. package/src/plugins/comments/client/localization/comments-my.ts +32 -0
  165. package/src/plugins/comments/client/localization/comments-thread.ts +32 -0
  166. package/src/plugins/comments/client/localization/index.ts +11 -0
  167. package/src/plugins/comments/client/overrides.ts +164 -0
  168. package/src/plugins/comments/client/plugin.tsx +195 -0
  169. package/src/plugins/comments/client/utils.ts +67 -0
  170. package/src/plugins/comments/client.css +2 -0
  171. package/src/plugins/comments/db.ts +77 -0
  172. package/src/plugins/comments/query-keys.ts +189 -0
  173. package/src/plugins/comments/schemas.ts +72 -0
  174. package/src/plugins/comments/style.css +15 -0
  175. package/src/plugins/comments/types.ts +73 -0
  176. package/src/plugins/kanban/client/components/forms/task-form.tsx +0 -1
  177. package/src/plugins/kanban/client/components/pages/board-page.internal.tsx +46 -27
  178. package/src/plugins/kanban/client/overrides.ts +27 -1
  179. package/dist/shared/{stack.Rtcvl8sS.d.cts → stack.BOokfhZD.d.cts} +3 -3
  180. package/dist/shared/{stack.D4Cea8II.d.ts → stack.BvCR4-9H.d.ts} +3 -3
  181. package/dist/shared/{stack.HE_IvqV5.d.mts → stack.CWxAl9K3.d.mts} +3 -3
@@ -0,0 +1,262 @@
1
+ import * as _btst_stack_plugins_client from '@btst/stack/plugins/client';
2
+ import * as React from 'react';
3
+ import * as _btst_yar from '@btst/yar';
4
+ import { QueryClient } from '@tanstack/react-query';
5
+ import { C as CommentsLocalization } from '../../../shared/stack.Ldfkr5b2.mjs';
6
+ export { a as COMMENTS_LOCALIZATION } from '../../../shared/stack.Ldfkr5b2.mjs';
7
+
8
+ /**
9
+ * Context passed to loader hooks
10
+ */
11
+ interface LoaderContext {
12
+ /** Current route path */
13
+ path: string;
14
+ /** Route parameters */
15
+ params?: Record<string, string>;
16
+ /** Whether rendering on server (true) or client (false) */
17
+ isSSR: boolean;
18
+ /** Base URL for API calls */
19
+ apiBaseURL: string;
20
+ /** Path where the API is mounted */
21
+ apiBasePath: string;
22
+ /** Optional headers for the request */
23
+ headers?: Headers;
24
+ /** Additional context properties */
25
+ [key: string]: unknown;
26
+ }
27
+ /**
28
+ * Hooks for Comments client plugin
29
+ */
30
+ interface CommentsClientHooks {
31
+ /**
32
+ * Called before loading the moderation page. Throw to cancel.
33
+ */
34
+ beforeLoadModeration?: (context: LoaderContext) => Promise<void> | void;
35
+ /**
36
+ * Called before loading the User Comments page. Throw to cancel.
37
+ */
38
+ beforeLoadUserComments?: (context: LoaderContext) => Promise<void> | void;
39
+ /**
40
+ * Called when a loading error occurs.
41
+ */
42
+ onLoadError?: (error: Error, context: LoaderContext) => Promise<void> | void;
43
+ }
44
+ /**
45
+ * Configuration for the Comments client plugin
46
+ */
47
+ interface CommentsClientConfig {
48
+ /** Base URL for API calls (e.g., "http://localhost:3000") */
49
+ apiBaseURL: string;
50
+ /** Path where the API is mounted (e.g., "/api/data") */
51
+ apiBasePath: string;
52
+ /** Base URL of your site */
53
+ siteBaseURL: string;
54
+ /** Path where pages are mounted (e.g., "/pages") */
55
+ siteBasePath: string;
56
+ /** React Query client instance */
57
+ queryClient: QueryClient;
58
+ /** Optional headers for SSR */
59
+ headers?: Headers;
60
+ /** Optional lifecycle hooks */
61
+ hooks?: CommentsClientHooks;
62
+ }
63
+ /**
64
+ * Comments client plugin — registers admin moderation routes.
65
+ *
66
+ * The embeddable `CommentThread` and `CommentCount` components are standalone
67
+ * and do not require this plugin to be registered. Register them manually
68
+ * via the layout overrides pattern or use them directly in your pages.
69
+ */
70
+ declare const commentsClientPlugin: (config: CommentsClientConfig) => _btst_stack_plugins_client.ClientPlugin<Record<string, never>, {
71
+ moderation: {
72
+ (inputCtx_0?: _btst_yar.InputContext<"/comments/moderation", _btst_yar.RouteOptions> | undefined): {
73
+ PageComponent?: React.ComponentType<unknown> | undefined;
74
+ LoadingComponent?: React.ComponentType<unknown> | undefined;
75
+ ErrorComponent?: React.ComponentType<unknown> | undefined;
76
+ loader?: (() => Promise<void>) | undefined;
77
+ meta?: (() => ({
78
+ title: string;
79
+ name?: undefined;
80
+ content?: undefined;
81
+ property?: undefined;
82
+ } | {
83
+ name: string;
84
+ content: string;
85
+ title?: undefined;
86
+ property?: undefined;
87
+ } | {
88
+ property: string;
89
+ content: string;
90
+ title?: undefined;
91
+ name?: undefined;
92
+ })[]) | undefined;
93
+ extra?: (() => any) | undefined;
94
+ };
95
+ options: _btst_yar.RouteOptions | undefined;
96
+ path: "/comments/moderation";
97
+ meta: _btst_yar.RouteMeta | undefined;
98
+ };
99
+ userComments: {
100
+ (inputCtx_0?: _btst_yar.InputContext<"/comments", _btst_yar.RouteOptions> | undefined): {
101
+ PageComponent?: React.ComponentType<unknown> | undefined;
102
+ LoadingComponent?: React.ComponentType<unknown> | undefined;
103
+ ErrorComponent?: React.ComponentType<unknown> | undefined;
104
+ loader?: (() => Promise<void>) | undefined;
105
+ meta?: (() => ({
106
+ title: string;
107
+ name?: undefined;
108
+ content?: undefined;
109
+ property?: undefined;
110
+ } | {
111
+ name: string;
112
+ content: string;
113
+ title?: undefined;
114
+ property?: undefined;
115
+ } | {
116
+ property: string;
117
+ content: string;
118
+ title?: undefined;
119
+ name?: undefined;
120
+ })[]) | undefined;
121
+ extra?: (() => any) | undefined;
122
+ };
123
+ options: _btst_yar.RouteOptions | undefined;
124
+ path: "/comments";
125
+ meta: _btst_yar.RouteMeta | undefined;
126
+ };
127
+ }>;
128
+
129
+ /**
130
+ * Context passed to lifecycle hooks
131
+ */
132
+ interface RouteContext {
133
+ /** Current route path */
134
+ path: string;
135
+ /** Route parameters (e.g., { resourceId: "my-post", resourceType: "blog-post" }) */
136
+ params?: Record<string, string>;
137
+ /** Whether rendering on server (true) or client (false) */
138
+ isSSR: boolean;
139
+ /** Additional context properties */
140
+ [key: string]: unknown;
141
+ }
142
+
143
+ /**
144
+ * Overridable configuration and hooks for the Comments plugin.
145
+ *
146
+ * Provide these in the layout wrapping your pages via `PluginOverridesProvider`.
147
+ */
148
+ interface CommentsPluginOverrides {
149
+ /**
150
+ * Localization strings for all Comments plugin UI.
151
+ * Defaults to English when not provided.
152
+ */
153
+ localization?: Partial<CommentsLocalization>;
154
+ /**
155
+ * Base URL for API calls (e.g., "https://example.com")
156
+ */
157
+ apiBaseURL: string;
158
+ /**
159
+ * Path where the API is mounted (e.g., "/api/data")
160
+ */
161
+ apiBasePath: string;
162
+ /**
163
+ * Optional headers for authenticated API calls (e.g., forwarding cookies)
164
+ */
165
+ headers?: Record<string, string>;
166
+ /**
167
+ * Whether to show the "Powered by BTST" attribution on plugin pages.
168
+ * Defaults to true.
169
+ */
170
+ showAttribution?: boolean;
171
+ /**
172
+ * The ID of the currently authenticated user.
173
+ *
174
+ * Used by the User Comments page and the per-resource comments admin view to
175
+ * scope the comment list to the current user and to enable posting.
176
+ * Can be a static string or an async function (useful when the user ID must
177
+ * be resolved from a session cookie at render time).
178
+ *
179
+ * When absent both pages show a "Please log in" prompt.
180
+ */
181
+ currentUserId?: string | (() => string | undefined | Promise<string | undefined>);
182
+ /**
183
+ * URL to redirect unauthenticated users to when they try to post a comment.
184
+ *
185
+ * Forwarded to every embedded `CommentThread` (including the one on the
186
+ * per-resource admin comments view). When absent no login link is shown.
187
+ */
188
+ loginHref?: string;
189
+ /**
190
+ * Default number of top-level comments to load per page in `CommentThread`.
191
+ * Can be overridden per-instance via the `pageSize` prop.
192
+ * Defaults to 100 when not set.
193
+ */
194
+ defaultCommentPageSize?: number;
195
+ /**
196
+ * When false, the comment form and reply buttons are hidden in all
197
+ * `CommentThread` instances. Users can still read existing comments.
198
+ * Defaults to true.
199
+ *
200
+ * Can be overridden per-instance via the `allowPosting` prop on `CommentThread`.
201
+ */
202
+ allowPosting?: boolean;
203
+ /**
204
+ * When false, the edit button is hidden on all comment cards in all
205
+ * `CommentThread` instances.
206
+ * Defaults to true.
207
+ *
208
+ * Can be overridden per-instance via the `allowEditing` prop on `CommentThread`.
209
+ */
210
+ allowEditing?: boolean;
211
+ /**
212
+ * Per-resource-type URL builders used to link each comment back to its
213
+ * original resource on the User Comments page.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * resourceLinks: {
218
+ * "blog-post": (slug) => `/pages/blog/${slug}`,
219
+ * "kanban-task": (id) => `/pages/kanban?task=${id}`,
220
+ * }
221
+ * ```
222
+ *
223
+ * When a resource type has no entry the ID is shown as plain text.
224
+ */
225
+ resourceLinks?: Record<string, (id: string) => string>;
226
+ /**
227
+ * Called before the moderation dashboard page is rendered.
228
+ * Return false to block rendering (e.g., redirect to login or show 403).
229
+ * @param context - Route context
230
+ */
231
+ onBeforeModerationPageRendered?: (context: RouteContext) => boolean;
232
+ /**
233
+ * Called before the per-resource comments page is rendered.
234
+ * Return false to block rendering (e.g., for authorization).
235
+ * @param resourceType - The type of resource (e.g., "blog-post")
236
+ * @param resourceId - The ID of the resource
237
+ * @param context - Route context
238
+ */
239
+ onBeforeResourceCommentsRendered?: (resourceType: string, resourceId: string, context: RouteContext) => boolean;
240
+ /**
241
+ * Called before the User Comments page is rendered.
242
+ * Throw to block rendering (e.g., when the user is not authenticated).
243
+ * @param context - Route context
244
+ */
245
+ onBeforeUserCommentsPageRendered?: (context: RouteContext) => boolean | void;
246
+ /**
247
+ * Called when a route is rendered.
248
+ * @param routeName - Name of the route (e.g., 'moderation', 'resourceComments')
249
+ * @param context - Route context
250
+ */
251
+ onRouteRender?: (routeName: string, context: RouteContext) => void | Promise<void>;
252
+ /**
253
+ * Called when a route encounters an error.
254
+ * @param routeName - Name of the route
255
+ * @param error - The error that occurred
256
+ * @param context - Route context
257
+ */
258
+ onRouteError?: (routeName: string, error: Error, context: RouteContext) => void | Promise<void>;
259
+ }
260
+
261
+ export { CommentsLocalization, commentsClientPlugin };
262
+ export type { CommentsClientConfig, CommentsClientHooks, CommentsPluginOverrides, LoaderContext, RouteContext };
@@ -0,0 +1,262 @@
1
+ import * as _btst_stack_plugins_client from '@btst/stack/plugins/client';
2
+ import * as React from 'react';
3
+ import * as _btst_yar from '@btst/yar';
4
+ import { QueryClient } from '@tanstack/react-query';
5
+ import { C as CommentsLocalization } from '../../../shared/stack.Ldfkr5b2.js';
6
+ export { a as COMMENTS_LOCALIZATION } from '../../../shared/stack.Ldfkr5b2.js';
7
+
8
+ /**
9
+ * Context passed to loader hooks
10
+ */
11
+ interface LoaderContext {
12
+ /** Current route path */
13
+ path: string;
14
+ /** Route parameters */
15
+ params?: Record<string, string>;
16
+ /** Whether rendering on server (true) or client (false) */
17
+ isSSR: boolean;
18
+ /** Base URL for API calls */
19
+ apiBaseURL: string;
20
+ /** Path where the API is mounted */
21
+ apiBasePath: string;
22
+ /** Optional headers for the request */
23
+ headers?: Headers;
24
+ /** Additional context properties */
25
+ [key: string]: unknown;
26
+ }
27
+ /**
28
+ * Hooks for Comments client plugin
29
+ */
30
+ interface CommentsClientHooks {
31
+ /**
32
+ * Called before loading the moderation page. Throw to cancel.
33
+ */
34
+ beforeLoadModeration?: (context: LoaderContext) => Promise<void> | void;
35
+ /**
36
+ * Called before loading the User Comments page. Throw to cancel.
37
+ */
38
+ beforeLoadUserComments?: (context: LoaderContext) => Promise<void> | void;
39
+ /**
40
+ * Called when a loading error occurs.
41
+ */
42
+ onLoadError?: (error: Error, context: LoaderContext) => Promise<void> | void;
43
+ }
44
+ /**
45
+ * Configuration for the Comments client plugin
46
+ */
47
+ interface CommentsClientConfig {
48
+ /** Base URL for API calls (e.g., "http://localhost:3000") */
49
+ apiBaseURL: string;
50
+ /** Path where the API is mounted (e.g., "/api/data") */
51
+ apiBasePath: string;
52
+ /** Base URL of your site */
53
+ siteBaseURL: string;
54
+ /** Path where pages are mounted (e.g., "/pages") */
55
+ siteBasePath: string;
56
+ /** React Query client instance */
57
+ queryClient: QueryClient;
58
+ /** Optional headers for SSR */
59
+ headers?: Headers;
60
+ /** Optional lifecycle hooks */
61
+ hooks?: CommentsClientHooks;
62
+ }
63
+ /**
64
+ * Comments client plugin — registers admin moderation routes.
65
+ *
66
+ * The embeddable `CommentThread` and `CommentCount` components are standalone
67
+ * and do not require this plugin to be registered. Register them manually
68
+ * via the layout overrides pattern or use them directly in your pages.
69
+ */
70
+ declare const commentsClientPlugin: (config: CommentsClientConfig) => _btst_stack_plugins_client.ClientPlugin<Record<string, never>, {
71
+ moderation: {
72
+ (inputCtx_0?: _btst_yar.InputContext<"/comments/moderation", _btst_yar.RouteOptions> | undefined): {
73
+ PageComponent?: React.ComponentType<unknown> | undefined;
74
+ LoadingComponent?: React.ComponentType<unknown> | undefined;
75
+ ErrorComponent?: React.ComponentType<unknown> | undefined;
76
+ loader?: (() => Promise<void>) | undefined;
77
+ meta?: (() => ({
78
+ title: string;
79
+ name?: undefined;
80
+ content?: undefined;
81
+ property?: undefined;
82
+ } | {
83
+ name: string;
84
+ content: string;
85
+ title?: undefined;
86
+ property?: undefined;
87
+ } | {
88
+ property: string;
89
+ content: string;
90
+ title?: undefined;
91
+ name?: undefined;
92
+ })[]) | undefined;
93
+ extra?: (() => any) | undefined;
94
+ };
95
+ options: _btst_yar.RouteOptions | undefined;
96
+ path: "/comments/moderation";
97
+ meta: _btst_yar.RouteMeta | undefined;
98
+ };
99
+ userComments: {
100
+ (inputCtx_0?: _btst_yar.InputContext<"/comments", _btst_yar.RouteOptions> | undefined): {
101
+ PageComponent?: React.ComponentType<unknown> | undefined;
102
+ LoadingComponent?: React.ComponentType<unknown> | undefined;
103
+ ErrorComponent?: React.ComponentType<unknown> | undefined;
104
+ loader?: (() => Promise<void>) | undefined;
105
+ meta?: (() => ({
106
+ title: string;
107
+ name?: undefined;
108
+ content?: undefined;
109
+ property?: undefined;
110
+ } | {
111
+ name: string;
112
+ content: string;
113
+ title?: undefined;
114
+ property?: undefined;
115
+ } | {
116
+ property: string;
117
+ content: string;
118
+ title?: undefined;
119
+ name?: undefined;
120
+ })[]) | undefined;
121
+ extra?: (() => any) | undefined;
122
+ };
123
+ options: _btst_yar.RouteOptions | undefined;
124
+ path: "/comments";
125
+ meta: _btst_yar.RouteMeta | undefined;
126
+ };
127
+ }>;
128
+
129
+ /**
130
+ * Context passed to lifecycle hooks
131
+ */
132
+ interface RouteContext {
133
+ /** Current route path */
134
+ path: string;
135
+ /** Route parameters (e.g., { resourceId: "my-post", resourceType: "blog-post" }) */
136
+ params?: Record<string, string>;
137
+ /** Whether rendering on server (true) or client (false) */
138
+ isSSR: boolean;
139
+ /** Additional context properties */
140
+ [key: string]: unknown;
141
+ }
142
+
143
+ /**
144
+ * Overridable configuration and hooks for the Comments plugin.
145
+ *
146
+ * Provide these in the layout wrapping your pages via `PluginOverridesProvider`.
147
+ */
148
+ interface CommentsPluginOverrides {
149
+ /**
150
+ * Localization strings for all Comments plugin UI.
151
+ * Defaults to English when not provided.
152
+ */
153
+ localization?: Partial<CommentsLocalization>;
154
+ /**
155
+ * Base URL for API calls (e.g., "https://example.com")
156
+ */
157
+ apiBaseURL: string;
158
+ /**
159
+ * Path where the API is mounted (e.g., "/api/data")
160
+ */
161
+ apiBasePath: string;
162
+ /**
163
+ * Optional headers for authenticated API calls (e.g., forwarding cookies)
164
+ */
165
+ headers?: Record<string, string>;
166
+ /**
167
+ * Whether to show the "Powered by BTST" attribution on plugin pages.
168
+ * Defaults to true.
169
+ */
170
+ showAttribution?: boolean;
171
+ /**
172
+ * The ID of the currently authenticated user.
173
+ *
174
+ * Used by the User Comments page and the per-resource comments admin view to
175
+ * scope the comment list to the current user and to enable posting.
176
+ * Can be a static string or an async function (useful when the user ID must
177
+ * be resolved from a session cookie at render time).
178
+ *
179
+ * When absent both pages show a "Please log in" prompt.
180
+ */
181
+ currentUserId?: string | (() => string | undefined | Promise<string | undefined>);
182
+ /**
183
+ * URL to redirect unauthenticated users to when they try to post a comment.
184
+ *
185
+ * Forwarded to every embedded `CommentThread` (including the one on the
186
+ * per-resource admin comments view). When absent no login link is shown.
187
+ */
188
+ loginHref?: string;
189
+ /**
190
+ * Default number of top-level comments to load per page in `CommentThread`.
191
+ * Can be overridden per-instance via the `pageSize` prop.
192
+ * Defaults to 100 when not set.
193
+ */
194
+ defaultCommentPageSize?: number;
195
+ /**
196
+ * When false, the comment form and reply buttons are hidden in all
197
+ * `CommentThread` instances. Users can still read existing comments.
198
+ * Defaults to true.
199
+ *
200
+ * Can be overridden per-instance via the `allowPosting` prop on `CommentThread`.
201
+ */
202
+ allowPosting?: boolean;
203
+ /**
204
+ * When false, the edit button is hidden on all comment cards in all
205
+ * `CommentThread` instances.
206
+ * Defaults to true.
207
+ *
208
+ * Can be overridden per-instance via the `allowEditing` prop on `CommentThread`.
209
+ */
210
+ allowEditing?: boolean;
211
+ /**
212
+ * Per-resource-type URL builders used to link each comment back to its
213
+ * original resource on the User Comments page.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * resourceLinks: {
218
+ * "blog-post": (slug) => `/pages/blog/${slug}`,
219
+ * "kanban-task": (id) => `/pages/kanban?task=${id}`,
220
+ * }
221
+ * ```
222
+ *
223
+ * When a resource type has no entry the ID is shown as plain text.
224
+ */
225
+ resourceLinks?: Record<string, (id: string) => string>;
226
+ /**
227
+ * Called before the moderation dashboard page is rendered.
228
+ * Return false to block rendering (e.g., redirect to login or show 403).
229
+ * @param context - Route context
230
+ */
231
+ onBeforeModerationPageRendered?: (context: RouteContext) => boolean;
232
+ /**
233
+ * Called before the per-resource comments page is rendered.
234
+ * Return false to block rendering (e.g., for authorization).
235
+ * @param resourceType - The type of resource (e.g., "blog-post")
236
+ * @param resourceId - The ID of the resource
237
+ * @param context - Route context
238
+ */
239
+ onBeforeResourceCommentsRendered?: (resourceType: string, resourceId: string, context: RouteContext) => boolean;
240
+ /**
241
+ * Called before the User Comments page is rendered.
242
+ * Throw to block rendering (e.g., when the user is not authenticated).
243
+ * @param context - Route context
244
+ */
245
+ onBeforeUserCommentsPageRendered?: (context: RouteContext) => boolean | void;
246
+ /**
247
+ * Called when a route is rendered.
248
+ * @param routeName - Name of the route (e.g., 'moderation', 'resourceComments')
249
+ * @param context - Route context
250
+ */
251
+ onRouteRender?: (routeName: string, context: RouteContext) => void | Promise<void>;
252
+ /**
253
+ * Called when a route encounters an error.
254
+ * @param routeName - Name of the route
255
+ * @param error - The error that occurred
256
+ * @param context - Route context
257
+ */
258
+ onRouteError?: (routeName: string, error: Error, context: RouteContext) => void | Promise<void>;
259
+ }
260
+
261
+ export { CommentsLocalization, commentsClientPlugin };
262
+ export type { CommentsClientConfig, CommentsClientHooks, CommentsPluginOverrides, LoaderContext, RouteContext };
@@ -0,0 +1,2 @@
1
+ export { commentsClientPlugin } from '../../../packages/stack/src/plugins/comments/client/plugin.mjs';
2
+ export { COMMENTS_LOCALIZATION } from '../../../packages/stack/src/plugins/comments/client/localization/index.mjs';
@@ -0,0 +1,2 @@
1
+ /* Comments Plugin Client CSS */
2
+ /* No custom styles needed - uses shadcn/ui components */
@@ -0,0 +1,113 @@
1
+ 'use strict';
2
+
3
+ const queryKeyFactory = require('@lukemorales/query-key-factory');
4
+ const queryKeyDefs = require('../../packages/stack/src/plugins/comments/api/query-key-defs.cjs');
5
+ const utils = require('../../packages/stack/src/plugins/comments/client/utils.cjs');
6
+
7
+ function isErrorResponse(response) {
8
+ return typeof response === "object" && response !== null && "error" in response && response.error !== null && response.error !== void 0;
9
+ }
10
+ function createCommentsQueryKeys(client, headers) {
11
+ return queryKeyFactory.mergeQueryKeys(
12
+ createCommentsQueries(client, headers),
13
+ createCommentCountQueries(client, headers),
14
+ createCommentsThreadQueries(client, headers)
15
+ );
16
+ }
17
+ function createCommentsQueries(client, headers) {
18
+ return queryKeyFactory.createQueryKeys("comments", {
19
+ list: (params) => ({
20
+ queryKey: [queryKeyDefs.commentsListDiscriminator(params)],
21
+ queryFn: async () => {
22
+ const response = await client("/comments", {
23
+ method: "GET",
24
+ query: {
25
+ resourceId: params?.resourceId,
26
+ resourceType: params?.resourceType,
27
+ parentId: params?.parentId === null ? "null" : params?.parentId,
28
+ status: params?.status,
29
+ // currentUserId is intentionally NOT sent to the server.
30
+ // The server resolves the caller's identity server-side via the
31
+ // resolveCurrentUserId hook. Sending it would allow any caller to
32
+ // impersonate another user and read their pending comments.
33
+ // It is still included in the queryKey above for client-side
34
+ // cache segregation (different users get different cache entries).
35
+ authorId: params?.authorId,
36
+ sort: params?.sort,
37
+ limit: params?.limit ?? 20,
38
+ offset: params?.offset ?? 0
39
+ },
40
+ headers
41
+ });
42
+ if (isErrorResponse(response)) {
43
+ throw utils.toError(response.error);
44
+ }
45
+ const data = response.data;
46
+ return data ?? { items: [], total: 0, limit: 20, offset: 0 };
47
+ }
48
+ })
49
+ });
50
+ }
51
+ function createCommentCountQueries(client, headers) {
52
+ return queryKeyFactory.createQueryKeys("commentCount", {
53
+ byResource: (params) => ({
54
+ queryKey: [queryKeyDefs.commentCountDiscriminator(params)],
55
+ queryFn: async () => {
56
+ const response = await client("/comments/count", {
57
+ method: "GET",
58
+ query: {
59
+ resourceId: params.resourceId,
60
+ resourceType: params.resourceType,
61
+ status: params.status
62
+ },
63
+ headers
64
+ });
65
+ if (isErrorResponse(response)) {
66
+ throw utils.toError(response.error);
67
+ }
68
+ const data = response.data;
69
+ return data?.count ?? 0;
70
+ }
71
+ })
72
+ });
73
+ }
74
+ function createCommentsThreadQueries(client, headers) {
75
+ return queryKeyFactory.createQueryKeys("commentsThread", {
76
+ list: (params) => ({
77
+ // Offset is excluded from the key — it is driven by pageParam.
78
+ queryKey: [queryKeyDefs.commentsThreadDiscriminator(params)],
79
+ queryFn: async ({
80
+ pageParam
81
+ } = {}) => {
82
+ const response = await client("/comments", {
83
+ method: "GET",
84
+ query: {
85
+ resourceId: params?.resourceId,
86
+ resourceType: params?.resourceType,
87
+ parentId: params?.parentId === null ? "null" : params?.parentId,
88
+ status: params?.status,
89
+ // currentUserId is intentionally NOT sent to the server.
90
+ // The server resolves the caller's identity server-side via the
91
+ // resolveCurrentUserId hook. It is still included in the queryKey
92
+ // above for client-side cache segregation.
93
+ limit: params?.limit ?? 20,
94
+ offset: pageParam ?? 0
95
+ },
96
+ headers
97
+ });
98
+ if (isErrorResponse(response)) {
99
+ throw utils.toError(response.error);
100
+ }
101
+ const data = response.data;
102
+ return data ?? {
103
+ items: [],
104
+ total: 0,
105
+ limit: params?.limit ?? 20,
106
+ offset: pageParam ?? 0
107
+ };
108
+ }
109
+ })
110
+ });
111
+ }
112
+
113
+ exports.createCommentsQueryKeys = createCommentsQueryKeys;