@btst/stack 2.1.0 → 2.3.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 (229) hide show
  1. package/dist/api/index.cjs +9 -1
  2. package/dist/api/index.d.cts +4 -4
  3. package/dist/api/index.d.mts +4 -4
  4. package/dist/api/index.d.ts +4 -4
  5. package/dist/api/index.mjs +9 -1
  6. package/dist/client/index.d.cts +2 -2
  7. package/dist/client/index.d.mts +2 -2
  8. package/dist/client/index.d.ts +2 -2
  9. package/dist/index.d.cts +1 -1
  10. package/dist/index.d.mts +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/packages/stack/src/plugins/ai-chat/api/getters.cjs +42 -0
  13. package/dist/packages/stack/src/plugins/ai-chat/api/getters.mjs +39 -0
  14. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +5 -0
  15. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +5 -0
  16. package/dist/packages/stack/src/plugins/blog/api/getters.cjs +131 -0
  17. package/dist/packages/stack/src/plugins/blog/api/getters.mjs +127 -0
  18. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +60 -107
  19. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +60 -107
  20. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.cjs +18 -0
  21. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.mjs +15 -0
  22. package/dist/packages/stack/src/plugins/blog/api/serializers.cjs +21 -0
  23. package/dist/packages/stack/src/plugins/blog/api/serializers.mjs +18 -0
  24. package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +16 -1
  25. package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +17 -2
  26. package/dist/packages/stack/src/plugins/cms/api/getters.cjs +156 -0
  27. package/dist/packages/stack/src/plugins/cms/api/getters.mjs +147 -0
  28. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +624 -617
  29. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +623 -616
  30. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.cjs +29 -0
  31. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.mjs +26 -0
  32. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +1 -1
  33. package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +1 -1
  34. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.cjs +6 -3
  35. package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.mjs +6 -3
  36. package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +15 -0
  37. package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +16 -1
  38. package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +120 -0
  39. package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +112 -0
  40. package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +75 -86
  41. package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +71 -82
  42. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.cjs +37 -0
  43. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.mjs +33 -0
  44. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +1 -1
  45. package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +1 -1
  46. package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +15 -0
  47. package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +16 -1
  48. package/dist/packages/stack/src/plugins/kanban/api/getters.cjs +84 -0
  49. package/dist/packages/stack/src/plugins/kanban/api/getters.mjs +81 -0
  50. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +37 -123
  51. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +37 -123
  52. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.cjs +26 -0
  53. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.mjs +23 -0
  54. package/dist/packages/stack/src/plugins/kanban/api/serializers.cjs +30 -0
  55. package/dist/packages/stack/src/plugins/kanban/api/serializers.mjs +26 -0
  56. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +11 -1
  57. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +12 -2
  58. package/dist/packages/stack/src/plugins/utils.cjs +6 -0
  59. package/dist/packages/stack/src/plugins/utils.mjs +6 -1
  60. package/dist/plugins/ai-chat/api/index.cjs +3 -0
  61. package/dist/plugins/ai-chat/api/index.d.cts +27 -4
  62. package/dist/plugins/ai-chat/api/index.d.mts +27 -4
  63. package/dist/plugins/ai-chat/api/index.d.ts +27 -4
  64. package/dist/plugins/ai-chat/api/index.mjs +1 -0
  65. package/dist/plugins/ai-chat/client/hooks/index.d.cts +2 -2
  66. package/dist/plugins/ai-chat/client/hooks/index.d.mts +2 -2
  67. package/dist/plugins/ai-chat/client/hooks/index.d.ts +2 -2
  68. package/dist/plugins/ai-chat/query-keys.d.cts +9 -284
  69. package/dist/plugins/ai-chat/query-keys.d.mts +9 -284
  70. package/dist/plugins/ai-chat/query-keys.d.ts +9 -284
  71. package/dist/plugins/api/index.d.cts +4 -3
  72. package/dist/plugins/api/index.d.mts +4 -3
  73. package/dist/plugins/api/index.d.ts +4 -3
  74. package/dist/plugins/blog/api/index.cjs +9 -0
  75. package/dist/plugins/blog/api/index.d.cts +20 -4
  76. package/dist/plugins/blog/api/index.d.mts +20 -4
  77. package/dist/plugins/blog/api/index.d.ts +20 -4
  78. package/dist/plugins/blog/api/index.mjs +3 -0
  79. package/dist/plugins/blog/client/hooks/index.d.cts +5 -5
  80. package/dist/plugins/blog/client/hooks/index.d.mts +5 -5
  81. package/dist/plugins/blog/client/hooks/index.d.ts +5 -5
  82. package/dist/plugins/blog/client/index.d.cts +1 -1
  83. package/dist/plugins/blog/client/index.d.mts +1 -1
  84. package/dist/plugins/blog/client/index.d.ts +1 -1
  85. package/dist/plugins/blog/query-keys.cjs +13 -9
  86. package/dist/plugins/blog/query-keys.d.cts +8 -333
  87. package/dist/plugins/blog/query-keys.d.mts +8 -333
  88. package/dist/plugins/blog/query-keys.d.ts +8 -333
  89. package/dist/plugins/blog/query-keys.mjs +13 -9
  90. package/dist/plugins/client/index.cjs +1 -0
  91. package/dist/plugins/client/index.d.cts +10 -3
  92. package/dist/plugins/client/index.d.mts +10 -3
  93. package/dist/plugins/client/index.d.ts +10 -3
  94. package/dist/plugins/client/index.mjs +1 -1
  95. package/dist/plugins/cms/api/index.cjs +10 -0
  96. package/dist/plugins/cms/api/index.d.cts +7 -163
  97. package/dist/plugins/cms/api/index.d.mts +7 -163
  98. package/dist/plugins/cms/api/index.d.ts +7 -163
  99. package/dist/plugins/cms/api/index.mjs +2 -0
  100. package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
  101. package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
  102. package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
  103. package/dist/plugins/cms/query-keys.cjs +2 -1
  104. package/dist/plugins/cms/query-keys.d.cts +6 -9
  105. package/dist/plugins/cms/query-keys.d.mts +6 -9
  106. package/dist/plugins/cms/query-keys.d.ts +6 -9
  107. package/dist/plugins/cms/query-keys.mjs +2 -1
  108. package/dist/plugins/form-builder/api/index.cjs +10 -0
  109. package/dist/plugins/form-builder/api/index.d.cts +7 -141
  110. package/dist/plugins/form-builder/api/index.d.mts +7 -141
  111. package/dist/plugins/form-builder/api/index.d.ts +7 -141
  112. package/dist/plugins/form-builder/api/index.mjs +2 -0
  113. package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
  114. package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
  115. package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
  116. package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
  117. package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
  118. package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
  119. package/dist/plugins/form-builder/query-keys.cjs +3 -2
  120. package/dist/plugins/form-builder/query-keys.d.cts +7 -6
  121. package/dist/plugins/form-builder/query-keys.d.mts +7 -6
  122. package/dist/plugins/form-builder/query-keys.d.ts +7 -6
  123. package/dist/plugins/form-builder/query-keys.mjs +3 -2
  124. package/dist/plugins/kanban/api/index.cjs +9 -0
  125. package/dist/plugins/kanban/api/index.d.cts +17 -395
  126. package/dist/plugins/kanban/api/index.d.mts +17 -395
  127. package/dist/plugins/kanban/api/index.d.ts +17 -395
  128. package/dist/plugins/kanban/api/index.mjs +3 -0
  129. package/dist/plugins/kanban/client/components/index.d.cts +1 -1
  130. package/dist/plugins/kanban/client/components/index.d.mts +1 -1
  131. package/dist/plugins/kanban/client/components/index.d.ts +1 -1
  132. package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
  133. package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
  134. package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
  135. package/dist/plugins/kanban/client/index.d.cts +1 -1
  136. package/dist/plugins/kanban/client/index.d.mts +1 -1
  137. package/dist/plugins/kanban/client/index.d.ts +1 -1
  138. package/dist/plugins/kanban/query-keys.cjs +6 -12
  139. package/dist/plugins/kanban/query-keys.d.cts +5 -16
  140. package/dist/plugins/kanban/query-keys.d.mts +5 -16
  141. package/dist/plugins/kanban/query-keys.d.ts +5 -16
  142. package/dist/plugins/kanban/query-keys.mjs +6 -12
  143. package/dist/plugins/open-api/api/index.d.cts +2 -2
  144. package/dist/plugins/open-api/api/index.d.mts +2 -2
  145. package/dist/plugins/open-api/api/index.d.ts +2 -2
  146. package/dist/plugins/route-docs/client/index.d.cts +1 -1
  147. package/dist/plugins/route-docs/client/index.d.mts +1 -1
  148. package/dist/plugins/route-docs/client/index.d.ts +1 -1
  149. package/dist/plugins/ui-builder/index.d.cts +1 -1
  150. package/dist/plugins/ui-builder/index.d.mts +1 -1
  151. package/dist/plugins/ui-builder/index.d.ts +1 -1
  152. package/dist/shared/{stack.BoA0xkJv.d.cts → stack.7n9Y_u7N.d.cts} +33 -7
  153. package/dist/shared/{stack.BoA0xkJv.d.mts → stack.7n9Y_u7N.d.mts} +33 -7
  154. package/dist/shared/{stack.BoA0xkJv.d.ts → stack.7n9Y_u7N.d.ts} +33 -7
  155. package/dist/shared/stack.B1EeBt1b.d.ts +297 -0
  156. package/dist/shared/stack.BIXEI6v_.d.mts +419 -0
  157. package/dist/shared/stack.BKfolAyK.d.ts +419 -0
  158. package/dist/shared/stack.BeSm90va.d.ts +289 -0
  159. package/dist/shared/stack.BpolpQpf.d.cts +445 -0
  160. package/dist/shared/stack.C5dtIncc.d.mts +293 -0
  161. package/dist/shared/stack.CIP6QS9l.d.ts +293 -0
  162. package/dist/shared/stack.CMh_EdxW.d.cts +289 -0
  163. package/dist/shared/stack.CP68pFEH.d.mts +297 -0
  164. package/dist/shared/{stack.BsXokfNh.d.mts → stack.CVDTkMoO.d.cts} +8 -2
  165. package/dist/shared/{stack.BsXokfNh.d.ts → stack.CVDTkMoO.d.mts} +8 -2
  166. package/dist/shared/{stack.BsXokfNh.d.cts → stack.CVDTkMoO.d.ts} +8 -2
  167. package/dist/shared/{stack.DKDMI-QO.d.mts → stack.DJaKVY7v.d.cts} +7 -1
  168. package/dist/shared/{stack.DKDMI-QO.d.ts → stack.DJaKVY7v.d.mts} +7 -1
  169. package/dist/shared/{stack.DKDMI-QO.d.cts → stack.DJaKVY7v.d.ts} +7 -1
  170. package/dist/shared/{stack.DzH_wcvr.d.mts → stack.DdI5W6MB.d.cts} +9 -3
  171. package/dist/shared/{stack.DzH_wcvr.d.ts → stack.DdI5W6MB.d.mts} +9 -3
  172. package/dist/shared/{stack.DzH_wcvr.d.cts → stack.DdI5W6MB.d.ts} +9 -3
  173. package/dist/shared/stack.Dg09R0oB.d.mts +289 -0
  174. package/dist/shared/stack.Dw0Ly2TM.d.cts +293 -0
  175. package/dist/shared/stack.IdtKDRka.d.cts +297 -0
  176. package/dist/shared/stack.TIBF2AOx.d.ts +445 -0
  177. package/dist/shared/stack.rTy7-wQU.d.mts +445 -0
  178. package/dist/shared/stack.snB1EDP7.d.cts +419 -0
  179. package/package.json +3 -3
  180. package/src/__tests__/stack-api.test.ts +118 -0
  181. package/src/api/index.ts +15 -1
  182. package/src/plugins/ai-chat/__tests__/getters.test.ts +109 -0
  183. package/src/plugins/ai-chat/api/getters.ts +71 -0
  184. package/src/plugins/ai-chat/api/index.ts +1 -0
  185. package/src/plugins/ai-chat/api/plugin.ts +8 -0
  186. package/src/plugins/api/index.ts +3 -1
  187. package/src/plugins/blog/__tests__/getters.test.ts +540 -0
  188. package/src/plugins/blog/api/getters.ts +243 -0
  189. package/src/plugins/blog/api/index.ts +9 -0
  190. package/src/plugins/blog/api/plugin.ts +98 -141
  191. package/src/plugins/blog/api/query-key-defs.ts +46 -0
  192. package/src/plugins/blog/api/serializers.ts +27 -0
  193. package/src/plugins/blog/client/plugin.tsx +21 -1
  194. package/src/plugins/blog/query-keys.ts +21 -20
  195. package/src/plugins/client/index.ts +1 -1
  196. package/src/plugins/cms/__tests__/getters.test.ts +206 -0
  197. package/src/plugins/cms/api/getters.ts +268 -0
  198. package/src/plugins/cms/api/index.ts +15 -1
  199. package/src/plugins/cms/api/plugin.ts +151 -150
  200. package/src/plugins/cms/api/query-key-defs.ts +53 -0
  201. package/src/plugins/cms/api/serializers.ts +12 -0
  202. package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +1 -1
  203. package/src/plugins/cms/client/hooks/cms-hooks.tsx +3 -0
  204. package/src/plugins/cms/client/plugin.tsx +19 -0
  205. package/src/plugins/cms/query-keys.ts +2 -1
  206. package/src/plugins/cms/types.ts +1 -1
  207. package/src/plugins/form-builder/__tests__/getters.test.ts +159 -0
  208. package/src/plugins/form-builder/api/getters.ts +226 -0
  209. package/src/plugins/form-builder/api/index.ts +15 -1
  210. package/src/plugins/form-builder/api/plugin.ts +107 -109
  211. package/src/plugins/form-builder/api/query-key-defs.ts +79 -0
  212. package/src/plugins/form-builder/api/serializers.ts +12 -0
  213. package/src/plugins/form-builder/client/components/pages/submissions-page.internal.tsx +1 -1
  214. package/src/plugins/form-builder/client/plugin.tsx +19 -0
  215. package/src/plugins/form-builder/query-keys.ts +6 -2
  216. package/src/plugins/form-builder/types.ts +2 -2
  217. package/src/plugins/kanban/__tests__/getters.test.ts +172 -0
  218. package/src/plugins/kanban/api/getters.ts +149 -0
  219. package/src/plugins/kanban/api/index.ts +4 -0
  220. package/src/plugins/kanban/api/plugin.ts +65 -146
  221. package/src/plugins/kanban/api/query-key-defs.ts +54 -0
  222. package/src/plugins/kanban/api/serializers.ts +49 -0
  223. package/src/plugins/kanban/client/plugin.tsx +15 -1
  224. package/src/plugins/kanban/query-keys.ts +10 -14
  225. package/src/plugins/utils.ts +19 -0
  226. package/src/types.ts +44 -5
  227. package/dist/shared/{stack.CbuN2zVV.d.cts → stack.CBON0dWL.d.cts} +7 -7
  228. package/dist/shared/{stack.CbuN2zVV.d.mts → stack.CBON0dWL.d.mts} +7 -7
  229. package/dist/shared/{stack.CbuN2zVV.d.ts → stack.CBON0dWL.d.ts} +7 -7
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  defineClientPlugin,
3
3
  createApiClient,
4
+ isConnectionError,
4
5
  } from "@btst/stack/plugins/client";
5
6
  import { createRoute } from "@btst/yar";
6
7
  import type { QueryClient } from "@tanstack/react-query";
@@ -178,6 +179,12 @@ function createBoardsLoader(config: KanbanClientConfig) {
178
179
  await hooks.onLoadError(error, context);
179
180
  }
180
181
  } catch (error) {
182
+ if (isConnectionError(error)) {
183
+ console.warn(
184
+ "[btst/kanban] route.loader() failed — no server running at build time. " +
185
+ "Use myStack.api.kanban.prefetchForRoute() for SSG data prefetching.",
186
+ );
187
+ }
181
188
  if (hooks?.onLoadError) {
182
189
  await hooks.onLoadError(error as Error, context);
183
190
  }
@@ -241,6 +248,12 @@ function createBoardLoader(boardId: string, config: KanbanClientConfig) {
241
248
  await hooks.onLoadError(error, context);
242
249
  }
243
250
  } catch (error) {
251
+ if (isConnectionError(error)) {
252
+ console.warn(
253
+ "[btst/kanban] route.loader() failed — no server running at build time. " +
254
+ "Use myStack.api.kanban.prefetchForRoute() for SSG data prefetching.",
255
+ );
256
+ }
244
257
  if (hooks?.onLoadError) {
245
258
  await hooks.onLoadError(error as Error, context);
246
259
  }
@@ -437,7 +450,8 @@ export const kanbanClientPlugin = (config: KanbanClientConfig) =>
437
450
  method: "GET",
438
451
  query: { limit: 100 },
439
452
  });
440
- boards = ((res as { data?: unknown }).data ??
453
+ // /boards returns BoardListResult { items, total, limit, offset }
454
+ boards = ((res.data as any)?.items ??
441
455
  []) as SerializedBoardWithColumns[];
442
456
  } catch {
443
457
  // Ignore errors for sitemap
@@ -5,6 +5,7 @@ import {
5
5
  import type { KanbanApiRouter } from "./api";
6
6
  import { createApiClient } from "@btst/stack/plugins/client";
7
7
  import type { SerializedBoardWithColumns } from "./types";
8
+ import { boardsListDiscriminator } from "./api/query-key-defs";
8
9
 
9
10
  interface BoardsListParams {
10
11
  slug?: string;
@@ -63,15 +64,7 @@ function createBoardsQueries(
63
64
  ) {
64
65
  return createQueryKeys("boards", {
65
66
  list: (params?: BoardsListParams) => ({
66
- queryKey: [
67
- {
68
- slug: params?.slug,
69
- ownerId: params?.ownerId,
70
- organizationId: params?.organizationId,
71
- limit: params?.limit ?? 50,
72
- offset: params?.offset ?? 0,
73
- },
74
- ],
67
+ queryKey: [boardsListDiscriminator(params)],
75
68
  queryFn: async () => {
76
69
  try {
77
70
  const response = await client("/boards", {
@@ -91,8 +84,10 @@ function createBoardsQueries(
91
84
  throw toError(errorResponse.error);
92
85
  }
93
86
 
94
- return ((response as { data?: unknown }).data ??
95
- []) as unknown as SerializedBoardWithColumns[];
87
+ const envelope = (response as { data?: unknown }).data as
88
+ | { items?: SerializedBoardWithColumns[] }
89
+ | undefined;
90
+ return envelope?.items ?? ([] as SerializedBoardWithColumns[]);
96
91
  } catch (error) {
97
92
  throw error;
98
93
  }
@@ -142,9 +137,10 @@ function createBoardsQueries(
142
137
  throw toError(errorResponse.error);
143
138
  }
144
139
 
145
- const boards = ((response as { data?: unknown }).data ??
146
- []) as unknown as SerializedBoardWithColumns[];
147
- return boards[0] ?? null;
140
+ const envelope = (response as { data?: unknown }).data as
141
+ | { items?: SerializedBoardWithColumns[] }
142
+ | undefined;
143
+ return envelope?.items?.[0] ?? null;
148
144
  } catch (error) {
149
145
  throw error;
150
146
  }
@@ -1,4 +1,23 @@
1
1
  import { createClient } from "better-call/client";
2
+
3
+ /**
4
+ * Returns true when a fetch error is a connection-refused / no-server error.
5
+ * Used in SSR loaders to emit an actionable build-time warning when
6
+ * `route.loader()` is called during `next build` with no HTTP server running.
7
+ */
8
+ export function isConnectionError(err: unknown): boolean {
9
+ if (!(err instanceof Error)) return false;
10
+ const code =
11
+ (err as unknown as { cause?: { code?: string } }).cause?.code ??
12
+ (err as unknown as { code?: string }).code;
13
+ return (
14
+ err.message.includes("ECONNREFUSED") ||
15
+ err.message.includes("fetch failed") ||
16
+ err.message.includes("ERR_CONNECTION_REFUSED") ||
17
+ code === "ECONNREFUSED" ||
18
+ code === "ERR_CONNECTION_REFUSED"
19
+ );
20
+ }
2
21
  import type { Router, Endpoint } from "better-call";
3
22
 
4
23
  interface CreateApiClientOptions {
package/src/types.ts CHANGED
@@ -8,7 +8,7 @@ import type { Endpoint, Router } from "better-call";
8
8
  */
9
9
  export interface StackContext {
10
10
  /** All registered backend plugins */
11
- plugins: Record<string, BackendPlugin<any>>;
11
+ plugins: Record<string, BackendPlugin<any, any>>;
12
12
  /** The API base path (e.g., "/api/data") */
13
13
  basePath: string;
14
14
  /** The database adapter */
@@ -40,9 +40,13 @@ export interface ClientStackContext<
40
40
  * You can optionally provide a base schema via the dbSchema config option.
41
41
  *
42
42
  * @template TRoutes - The exact shape of routes this plugin provides (preserves keys and endpoint types)
43
+ * @template TApi - The shape of the server-side API surface exposed via `stack().api`.
44
+ * Defaults to `never` so that plugins without an `api` factory are excluded from the
45
+ * `stack().api` namespace entirely, preventing accidental access of `undefined` at runtime.
43
46
  */
44
47
  export interface BackendPlugin<
45
48
  TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>,
49
+ TApi extends Record<string, (...args: any[]) => any> = never,
46
50
  > {
47
51
  name: string;
48
52
 
@@ -56,6 +60,15 @@ export interface BackendPlugin<
56
60
  */
57
61
  routes: (adapter: Adapter, context?: StackContext) => TRoutes;
58
62
  dbPlugin: DbPlugin;
63
+
64
+ /**
65
+ * Optional factory that returns server-side getter functions bound to the adapter.
66
+ * The returned object is merged into `stack().api.<pluginName>.*` for direct
67
+ * server-side or SSG data access without going through HTTP.
68
+ *
69
+ * @param adapter - The adapter instance shared with `routes`
70
+ */
71
+ api?: (adapter: Adapter) => TApi;
59
72
  }
60
73
 
61
74
  /**
@@ -87,13 +100,30 @@ export interface ClientPlugin<
87
100
  sitemap?: () => Promise<Sitemap> | Sitemap;
88
101
  }
89
102
 
103
+ /**
104
+ * Utility type that maps each plugin key to the return type of its `api` factory.
105
+ * Plugin keys whose `TApi` resolves to `never` (i.e. plugins with no `api` factory)
106
+ * are excluded from the resulting type via key remapping, preventing TypeScript from
107
+ * suggesting callable functions on what is actually `undefined` at runtime.
108
+ */
109
+ export type PluginApis<
110
+ TPlugins extends Record<string, BackendPlugin<any, any>>,
111
+ > = {
112
+ [K in keyof TPlugins as _ApiOf<TPlugins[K]> extends never
113
+ ? never
114
+ : K]: _ApiOf<TPlugins[K]>;
115
+ };
116
+
117
+ /** @internal Extract the TApi parameter from a BackendPlugin type. */
118
+ type _ApiOf<T> = T extends BackendPlugin<any, infer TApi> ? TApi : never;
119
+
90
120
  /**
91
121
  * Configuration for creating the backend library
92
122
  */
93
123
  export interface BackendLibConfig<
94
- TPlugins extends Record<string, BackendPlugin<any>> = Record<
124
+ TPlugins extends Record<string, BackendPlugin<any, any>> = Record<
95
125
  string,
96
- BackendPlugin<any>
126
+ BackendPlugin<any, any>
97
127
  >,
98
128
  > {
99
129
  basePath: string;
@@ -150,11 +180,12 @@ export type PluginRoutes<
150
180
  * Example: { messages: { list: Endpoint } } => { messages_list: Endpoint }
151
181
  */
152
182
  export type PrefixedPluginRoutes<
153
- TPlugins extends Record<string, BackendPlugin<any>>,
183
+ TPlugins extends Record<string, BackendPlugin<any, any>>,
154
184
  > = UnionToIntersection<
155
185
  {
156
186
  [PluginKey in keyof TPlugins]: TPlugins[PluginKey] extends BackendPlugin<
157
- infer TRoutes
187
+ infer TRoutes,
188
+ any
158
189
  >
159
190
  ? {
160
191
  [RouteKey in keyof TRoutes as `${PluginKey & string}_${RouteKey & string}`]: TRoutes[RouteKey];
@@ -172,10 +203,18 @@ export type PrefixedPluginRoutes<
172
203
  */
173
204
  export interface BackendLib<
174
205
  TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>,
206
+ TApis extends Record<
207
+ string,
208
+ Record<string, (...args: any[]) => any>
209
+ > = Record<string, Record<string, (...args: any[]) => any>>,
175
210
  > {
176
211
  handler: (request: Request) => Promise<Response>; // API route handler
177
212
  router: Router; // Better-call router
178
213
  dbSchema: DatabaseDefinition; // Better-db schema
214
+ /** The database adapter shared across all plugins */
215
+ adapter: Adapter;
216
+ /** Fully-typed server-side getter functions, namespaced per plugin */
217
+ api: TApis;
179
218
  }
180
219
 
181
220
  /**
@@ -35,6 +35,13 @@ interface SerializedTag extends Omit<Tag, "createdAt" | "updatedAt"> {
35
35
  }
36
36
 
37
37
  declare const createPostSchema: z.ZodObject<{
38
+ tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
39
+ name: z.ZodString;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ id: z.ZodString;
42
+ name: z.ZodString;
43
+ slug: z.ZodString;
44
+ }, z.core.$strip>]>>>>;
38
45
  slug: z.ZodOptional<z.ZodString>;
39
46
  publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
40
47
  createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
@@ -44,13 +51,6 @@ declare const createPostSchema: z.ZodObject<{
44
51
  excerpt: z.ZodString;
45
52
  image: z.ZodOptional<z.ZodString>;
46
53
  published: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
47
- tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
48
- name: z.ZodString;
49
- }, z.core.$strip>, z.ZodObject<{
50
- id: z.ZodString;
51
- name: z.ZodString;
52
- slug: z.ZodString;
53
- }, z.core.$strip>]>>>>;
54
54
  }, z.core.$strip>;
55
55
  declare const updatePostSchema: z.ZodObject<{
56
56
  publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
@@ -35,6 +35,13 @@ interface SerializedTag extends Omit<Tag, "createdAt" | "updatedAt"> {
35
35
  }
36
36
 
37
37
  declare const createPostSchema: z.ZodObject<{
38
+ tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
39
+ name: z.ZodString;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ id: z.ZodString;
42
+ name: z.ZodString;
43
+ slug: z.ZodString;
44
+ }, z.core.$strip>]>>>>;
38
45
  slug: z.ZodOptional<z.ZodString>;
39
46
  publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
40
47
  createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
@@ -44,13 +51,6 @@ declare const createPostSchema: z.ZodObject<{
44
51
  excerpt: z.ZodString;
45
52
  image: z.ZodOptional<z.ZodString>;
46
53
  published: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
47
- tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
48
- name: z.ZodString;
49
- }, z.core.$strip>, z.ZodObject<{
50
- id: z.ZodString;
51
- name: z.ZodString;
52
- slug: z.ZodString;
53
- }, z.core.$strip>]>>>>;
54
54
  }, z.core.$strip>;
55
55
  declare const updatePostSchema: z.ZodObject<{
56
56
  publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
@@ -35,6 +35,13 @@ interface SerializedTag extends Omit<Tag, "createdAt" | "updatedAt"> {
35
35
  }
36
36
 
37
37
  declare const createPostSchema: z.ZodObject<{
38
+ tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
39
+ name: z.ZodString;
40
+ }, z.core.$strip>, z.ZodObject<{
41
+ id: z.ZodString;
42
+ name: z.ZodString;
43
+ slug: z.ZodString;
44
+ }, z.core.$strip>]>>>>;
38
45
  slug: z.ZodOptional<z.ZodString>;
39
46
  publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
40
47
  createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
@@ -44,13 +51,6 @@ declare const createPostSchema: z.ZodObject<{
44
51
  excerpt: z.ZodString;
45
52
  image: z.ZodOptional<z.ZodString>;
46
53
  published: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
47
- tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
48
- name: z.ZodString;
49
- }, z.core.$strip>, z.ZodObject<{
50
- id: z.ZodString;
51
- name: z.ZodString;
52
- slug: z.ZodString;
53
- }, z.core.$strip>]>>>>;
54
54
  }, z.core.$strip>;
55
55
  declare const updatePostSchema: z.ZodObject<{
56
56
  publishedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;