@btst/stack 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.cjs +9 -1
- package/dist/api/index.d.cts +4 -4
- package/dist/api/index.d.mts +4 -4
- package/dist/api/index.d.ts +4 -4
- package/dist/api/index.mjs +9 -1
- package/dist/client/index.d.cts +2 -2
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/api/getters.cjs +42 -0
- package/dist/packages/stack/src/plugins/ai-chat/api/getters.mjs +39 -0
- package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +5 -0
- package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +5 -0
- package/dist/packages/stack/src/plugins/blog/api/getters.cjs +131 -0
- package/dist/packages/stack/src/plugins/blog/api/getters.mjs +127 -0
- package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +9 -107
- package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +9 -107
- package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +1 -1
- package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +1 -1
- package/dist/packages/stack/src/plugins/cms/api/getters.cjs +146 -0
- package/dist/packages/stack/src/plugins/cms/api/getters.mjs +138 -0
- package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +560 -622
- package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +559 -621
- package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.cjs +1 -1
- package/dist/packages/stack/src/plugins/cms/client/components/pages/content-editor-page.internal.mjs +1 -1
- package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.cjs +6 -3
- package/dist/packages/stack/src/plugins/cms/client/hooks/cms-hooks.mjs +6 -3
- package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +111 -0
- package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +104 -0
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +16 -88
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +12 -84
- package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.cjs +1 -1
- package/dist/packages/stack/src/plugins/form-builder/client/components/pages/submissions-page.internal.mjs +1 -1
- package/dist/packages/stack/src/plugins/kanban/api/getters.cjs +84 -0
- package/dist/packages/stack/src/plugins/kanban/api/getters.mjs +81 -0
- package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +9 -123
- package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +9 -123
- package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +1 -1
- package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +1 -1
- package/dist/plugins/ai-chat/api/index.cjs +3 -0
- package/dist/plugins/ai-chat/api/index.d.cts +27 -4
- package/dist/plugins/ai-chat/api/index.d.mts +27 -4
- package/dist/plugins/ai-chat/api/index.d.ts +27 -4
- package/dist/plugins/ai-chat/api/index.mjs +1 -0
- package/dist/plugins/ai-chat/client/hooks/index.d.cts +2 -2
- package/dist/plugins/ai-chat/client/hooks/index.d.mts +2 -2
- package/dist/plugins/ai-chat/client/hooks/index.d.ts +2 -2
- package/dist/plugins/ai-chat/query-keys.d.cts +9 -284
- package/dist/plugins/ai-chat/query-keys.d.mts +9 -284
- package/dist/plugins/ai-chat/query-keys.d.ts +9 -284
- package/dist/plugins/api/index.d.cts +4 -3
- package/dist/plugins/api/index.d.mts +4 -3
- package/dist/plugins/api/index.d.ts +4 -3
- package/dist/plugins/blog/api/index.cjs +4 -0
- package/dist/plugins/blog/api/index.d.cts +3 -2
- package/dist/plugins/blog/api/index.d.mts +3 -2
- package/dist/plugins/blog/api/index.d.ts +3 -2
- package/dist/plugins/blog/api/index.mjs +1 -0
- package/dist/plugins/blog/client/hooks/index.d.cts +4 -4
- package/dist/plugins/blog/client/hooks/index.d.mts +4 -4
- package/dist/plugins/blog/client/hooks/index.d.ts +4 -4
- package/dist/plugins/blog/client/index.d.cts +1 -1
- package/dist/plugins/blog/client/index.d.mts +1 -1
- package/dist/plugins/blog/client/index.d.ts +1 -1
- package/dist/plugins/blog/query-keys.cjs +7 -4
- package/dist/plugins/blog/query-keys.d.cts +81 -27
- package/dist/plugins/blog/query-keys.d.mts +81 -27
- package/dist/plugins/blog/query-keys.d.ts +81 -27
- package/dist/plugins/blog/query-keys.mjs +7 -4
- package/dist/plugins/client/index.d.cts +2 -2
- package/dist/plugins/client/index.d.mts +2 -2
- package/dist/plugins/client/index.d.ts +2 -2
- package/dist/plugins/cms/api/index.cjs +4 -0
- package/dist/plugins/cms/api/index.d.cts +61 -5
- package/dist/plugins/cms/api/index.d.mts +61 -5
- package/dist/plugins/cms/api/index.d.ts +61 -5
- package/dist/plugins/cms/api/index.mjs +1 -0
- package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
- package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
- package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
- package/dist/plugins/cms/query-keys.d.cts +2 -1
- package/dist/plugins/cms/query-keys.d.mts +2 -1
- package/dist/plugins/cms/query-keys.d.ts +2 -1
- package/dist/plugins/form-builder/api/index.cjs +4 -0
- package/dist/plugins/form-builder/api/index.d.cts +77 -7
- package/dist/plugins/form-builder/api/index.d.mts +77 -7
- package/dist/plugins/form-builder/api/index.d.ts +77 -7
- package/dist/plugins/form-builder/api/index.mjs +1 -0
- package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
- package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
- package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
- package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
- package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
- package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
- package/dist/plugins/form-builder/query-keys.d.cts +2 -1
- package/dist/plugins/form-builder/query-keys.d.mts +2 -1
- package/dist/plugins/form-builder/query-keys.d.ts +2 -1
- package/dist/plugins/kanban/api/index.cjs +3 -0
- package/dist/plugins/kanban/api/index.d.cts +40 -43
- package/dist/plugins/kanban/api/index.d.mts +40 -43
- package/dist/plugins/kanban/api/index.d.ts +40 -43
- package/dist/plugins/kanban/api/index.mjs +1 -0
- package/dist/plugins/kanban/client/components/index.d.cts +1 -1
- package/dist/plugins/kanban/client/components/index.d.mts +1 -1
- package/dist/plugins/kanban/client/components/index.d.ts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
- package/dist/plugins/kanban/client/index.d.cts +1 -1
- package/dist/plugins/kanban/client/index.d.mts +1 -1
- package/dist/plugins/kanban/client/index.d.ts +1 -1
- package/dist/plugins/kanban/query-keys.cjs +4 -3
- package/dist/plugins/kanban/query-keys.d.cts +2 -1
- package/dist/plugins/kanban/query-keys.d.mts +2 -1
- package/dist/plugins/kanban/query-keys.d.ts +2 -1
- package/dist/plugins/kanban/query-keys.mjs +4 -3
- package/dist/plugins/open-api/api/index.d.cts +2 -2
- package/dist/plugins/open-api/api/index.d.mts +2 -2
- package/dist/plugins/open-api/api/index.d.ts +2 -2
- package/dist/plugins/route-docs/client/index.d.cts +1 -1
- package/dist/plugins/route-docs/client/index.d.mts +1 -1
- package/dist/plugins/route-docs/client/index.d.ts +1 -1
- package/dist/plugins/ui-builder/index.d.cts +1 -1
- package/dist/plugins/ui-builder/index.d.mts +1 -1
- package/dist/plugins/ui-builder/index.d.ts +1 -1
- package/dist/shared/{stack.BoA0xkJv.d.cts → stack.7n9Y_u7N.d.cts} +33 -7
- package/dist/shared/{stack.BoA0xkJv.d.mts → stack.7n9Y_u7N.d.mts} +33 -7
- package/dist/shared/{stack.BoA0xkJv.d.ts → stack.7n9Y_u7N.d.ts} +33 -7
- package/dist/shared/stack.BeSm90va.d.ts +289 -0
- package/dist/shared/{stack.DzH_wcvr.d.mts → stack.CIrIsc-A.d.cts} +2 -2
- package/dist/shared/{stack.DzH_wcvr.d.ts → stack.CIrIsc-A.d.mts} +2 -2
- package/dist/shared/{stack.DzH_wcvr.d.cts → stack.CIrIsc-A.d.ts} +2 -2
- package/dist/shared/stack.CMh_EdxW.d.cts +289 -0
- package/dist/shared/{stack.BsXokfNh.d.mts → stack.CXjzTMsb.d.cts} +1 -1
- package/dist/shared/{stack.BsXokfNh.d.ts → stack.CXjzTMsb.d.mts} +1 -1
- package/dist/shared/{stack.BsXokfNh.d.cts → stack.CXjzTMsb.d.ts} +1 -1
- package/dist/shared/stack.Dg09R0oB.d.mts +289 -0
- package/dist/shared/{stack.DKDMI-QO.d.mts → stack.QD1y_7NY.d.cts} +7 -1
- package/dist/shared/{stack.DKDMI-QO.d.ts → stack.QD1y_7NY.d.mts} +7 -1
- package/dist/shared/{stack.DKDMI-QO.d.cts → stack.QD1y_7NY.d.ts} +7 -1
- package/package.json +1 -1
- package/src/__tests__/stack-api.test.ts +118 -0
- package/src/api/index.ts +15 -1
- package/src/plugins/ai-chat/__tests__/getters.test.ts +109 -0
- package/src/plugins/ai-chat/api/getters.ts +71 -0
- package/src/plugins/ai-chat/api/index.ts +1 -0
- package/src/plugins/ai-chat/api/plugin.ts +8 -0
- package/src/plugins/api/index.ts +3 -1
- package/src/plugins/blog/__tests__/getters.test.ts +540 -0
- package/src/plugins/blog/api/getters.ts +243 -0
- package/src/plugins/blog/api/index.ts +7 -0
- package/src/plugins/blog/api/plugin.ts +13 -141
- package/src/plugins/blog/client/plugin.tsx +2 -1
- package/src/plugins/blog/query-keys.ts +16 -13
- package/src/plugins/cms/__tests__/getters.test.ts +206 -0
- package/src/plugins/cms/api/getters.ts +244 -0
- package/src/plugins/cms/api/index.ts +5 -0
- package/src/plugins/cms/api/plugin.ts +50 -154
- package/src/plugins/cms/client/components/pages/content-editor-page.internal.tsx +1 -1
- package/src/plugins/cms/client/hooks/cms-hooks.tsx +3 -0
- package/src/plugins/cms/types.ts +1 -1
- package/src/plugins/form-builder/__tests__/getters.test.ts +159 -0
- package/src/plugins/form-builder/api/getters.ts +203 -0
- package/src/plugins/form-builder/api/index.ts +1 -0
- package/src/plugins/form-builder/api/plugin.ts +22 -115
- package/src/plugins/form-builder/client/components/pages/submissions-page.internal.tsx +1 -1
- package/src/plugins/form-builder/types.ts +2 -2
- package/src/plugins/kanban/__tests__/getters.test.ts +172 -0
- package/src/plugins/kanban/api/getters.ts +149 -0
- package/src/plugins/kanban/api/index.ts +1 -0
- package/src/plugins/kanban/api/plugin.ts +16 -146
- package/src/plugins/kanban/client/plugin.tsx +2 -1
- package/src/plugins/kanban/query-keys.ts +8 -5
- package/src/types.ts +44 -5
- package/dist/shared/{stack.CbuN2zVV.d.cts → stack.BkYlUT_8.d.cts} +6 -6
- package/dist/shared/{stack.CbuN2zVV.d.mts → stack.BkYlUT_8.d.mts} +6 -6
- package/dist/shared/{stack.CbuN2zVV.d.ts → stack.BkYlUT_8.d.ts} +6 -6
|
@@ -2,7 +2,7 @@ import * as _btst_stack_plugins_client from '@btst/stack/plugins/client';
|
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import * as _btst_yar from '@btst/yar';
|
|
4
4
|
import { QueryClient } from '@tanstack/react-query';
|
|
5
|
-
import { a as SitemapEntry, b as ClientStackContext } from '../../../shared/stack.
|
|
5
|
+
import { a as SitemapEntry, b as ClientStackContext } from '../../../shared/stack.7n9Y_u7N.mjs';
|
|
6
6
|
import '@btst/db';
|
|
7
7
|
import 'better-call';
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import * as _btst_stack_plugins_client from '@btst/stack/plugins/client';
|
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import * as _btst_yar from '@btst/yar';
|
|
4
4
|
import { QueryClient } from '@tanstack/react-query';
|
|
5
|
-
import { a as SitemapEntry, b as ClientStackContext } from '../../../shared/stack.
|
|
5
|
+
import { a as SitemapEntry, b as ClientStackContext } from '../../../shared/stack.7n9Y_u7N.js';
|
|
6
6
|
import '@btst/db';
|
|
7
7
|
import 'better-call';
|
|
8
8
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { C as ContentTypeConfig } from '../../shared/stack.
|
|
2
|
+
import { C as ContentTypeConfig } from '../../shared/stack.CXjzTMsb.cjs';
|
|
3
3
|
export { L as LoaderContext, b as PaginatedUIBuilderPages, P as ParsedUIBuilderPage, S as SerializedUIBuilderPage, c as UIBuilderClientHooks, a as UIBuilderPage, U as UIBuilderPageData } from '../../shared/stack.C-WUPMT6.cjs';
|
|
4
4
|
export { C as ComponentLayer, a as ComponentRegistry, R as RegistryEntry, V as Variable } from '../../shared/stack.B-YHz18S.cjs';
|
|
5
5
|
import 'react';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { C as ContentTypeConfig } from '../../shared/stack.
|
|
2
|
+
import { C as ContentTypeConfig } from '../../shared/stack.CXjzTMsb.mjs';
|
|
3
3
|
export { L as LoaderContext, b as PaginatedUIBuilderPages, P as ParsedUIBuilderPage, S as SerializedUIBuilderPage, c as UIBuilderClientHooks, a as UIBuilderPage, U as UIBuilderPageData } from '../../shared/stack.6fUOjLs9.mjs';
|
|
4
4
|
export { C as ComponentLayer, a as ComponentRegistry, R as RegistryEntry, V as Variable } from '../../shared/stack.D1DMlJp-.mjs';
|
|
5
5
|
import 'react';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { C as ContentTypeConfig } from '../../shared/stack.
|
|
2
|
+
import { C as ContentTypeConfig } from '../../shared/stack.CXjzTMsb.js';
|
|
3
3
|
export { L as LoaderContext, b as PaginatedUIBuilderPages, P as ParsedUIBuilderPage, S as SerializedUIBuilderPage, c as UIBuilderClientHooks, a as UIBuilderPage, U as UIBuilderPageData } from '../../shared/stack.C-Ptrz8s.js';
|
|
4
4
|
export { C as ComponentLayer, a as ComponentRegistry, R as RegistryEntry, V as Variable } from '../../shared/stack.GygI_T3X.js';
|
|
5
5
|
import 'react';
|
|
@@ -8,7 +8,7 @@ import { Endpoint, Router } from 'better-call';
|
|
|
8
8
|
*/
|
|
9
9
|
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 */
|
|
@@ -33,8 +33,11 @@ interface ClientStackContext<TPlugins extends Record<string, ClientPlugin<any, a
|
|
|
33
33
|
* You can optionally provide a base schema via the dbSchema config option.
|
|
34
34
|
*
|
|
35
35
|
* @template TRoutes - The exact shape of routes this plugin provides (preserves keys and endpoint types)
|
|
36
|
+
* @template TApi - The shape of the server-side API surface exposed via `stack().api`.
|
|
37
|
+
* Defaults to `never` so that plugins without an `api` factory are excluded from the
|
|
38
|
+
* `stack().api` namespace entirely, preventing accidental access of `undefined` at runtime.
|
|
36
39
|
*/
|
|
37
|
-
interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint
|
|
40
|
+
interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>, TApi extends Record<string, (...args: any[]) => any> = never> {
|
|
38
41
|
name: string;
|
|
39
42
|
/**
|
|
40
43
|
* Create API endpoints for this plugin
|
|
@@ -46,6 +49,14 @@ interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string
|
|
|
46
49
|
*/
|
|
47
50
|
routes: (adapter: Adapter, context?: StackContext) => TRoutes;
|
|
48
51
|
dbPlugin: DbPlugin;
|
|
52
|
+
/**
|
|
53
|
+
* Optional factory that returns server-side getter functions bound to the adapter.
|
|
54
|
+
* The returned object is merged into `stack().api.<pluginName>.*` for direct
|
|
55
|
+
* server-side or SSG data access without going through HTTP.
|
|
56
|
+
*
|
|
57
|
+
* @param adapter - The adapter instance shared with `routes`
|
|
58
|
+
*/
|
|
59
|
+
api?: (adapter: Adapter) => TApi;
|
|
49
60
|
}
|
|
50
61
|
/**
|
|
51
62
|
* Frontend plugin definition
|
|
@@ -70,10 +81,21 @@ interface ClientPlugin<TOverrides = Record<string, never>, TRoutes extends Recor
|
|
|
70
81
|
*/
|
|
71
82
|
sitemap?: () => Promise<Sitemap> | Sitemap;
|
|
72
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Utility type that maps each plugin key to the return type of its `api` factory.
|
|
86
|
+
* Plugin keys whose `TApi` resolves to `never` (i.e. plugins with no `api` factory)
|
|
87
|
+
* are excluded from the resulting type via key remapping, preventing TypeScript from
|
|
88
|
+
* suggesting callable functions on what is actually `undefined` at runtime.
|
|
89
|
+
*/
|
|
90
|
+
type PluginApis<TPlugins extends Record<string, BackendPlugin<any, any>>> = {
|
|
91
|
+
[K in keyof TPlugins as _ApiOf<TPlugins[K]> extends never ? never : K]: _ApiOf<TPlugins[K]>;
|
|
92
|
+
};
|
|
93
|
+
/** @internal Extract the TApi parameter from a BackendPlugin type. */
|
|
94
|
+
type _ApiOf<T> = T extends BackendPlugin<any, infer TApi> ? TApi : never;
|
|
73
95
|
/**
|
|
74
96
|
* Configuration for creating the backend library
|
|
75
97
|
*/
|
|
76
|
-
interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any>> = Record<string, BackendPlugin<any>>> {
|
|
98
|
+
interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any, any>> = Record<string, BackendPlugin<any, any>>> {
|
|
77
99
|
basePath: string;
|
|
78
100
|
dbSchema?: DatabaseDefinition;
|
|
79
101
|
plugins: TPlugins;
|
|
@@ -109,18 +131,22 @@ type PluginRoutes<TPlugins extends Record<string, ClientPlugin<any, any>>> = Mer
|
|
|
109
131
|
* Prefix all backend plugin route keys with the plugin name
|
|
110
132
|
* Example: { messages: { list: Endpoint } } => { messages_list: Endpoint }
|
|
111
133
|
*/
|
|
112
|
-
type PrefixedPluginRoutes<TPlugins extends Record<string, BackendPlugin<any>>> = UnionToIntersection<{
|
|
113
|
-
[PluginKey in keyof TPlugins]: TPlugins[PluginKey] extends BackendPlugin<infer TRoutes> ? {
|
|
134
|
+
type PrefixedPluginRoutes<TPlugins extends Record<string, BackendPlugin<any, any>>> = UnionToIntersection<{
|
|
135
|
+
[PluginKey in keyof TPlugins]: TPlugins[PluginKey] extends BackendPlugin<infer TRoutes, any> ? {
|
|
114
136
|
[RouteKey in keyof TRoutes as `${PluginKey & string}_${RouteKey & string}`]: TRoutes[RouteKey];
|
|
115
137
|
} : never;
|
|
116
138
|
}[keyof TPlugins]> extends infer U ? U extends Record<string, Endpoint> ? U : Record<string, Endpoint> : Record<string, Endpoint>;
|
|
117
139
|
/**
|
|
118
140
|
* Result of creating the backend library
|
|
119
141
|
*/
|
|
120
|
-
interface BackendLib<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>> {
|
|
142
|
+
interface BackendLib<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>, TApis extends Record<string, Record<string, (...args: any[]) => any>> = Record<string, Record<string, (...args: any[]) => any>>> {
|
|
121
143
|
handler: (request: Request) => Promise<Response>;
|
|
122
144
|
router: Router;
|
|
123
145
|
dbSchema: DatabaseDefinition;
|
|
146
|
+
/** The database adapter shared across all plugins */
|
|
147
|
+
adapter: Adapter;
|
|
148
|
+
/** Fully-typed server-side getter functions, namespaced per plugin */
|
|
149
|
+
api: TApis;
|
|
124
150
|
}
|
|
125
151
|
/**
|
|
126
152
|
* Helper type to extract routes from a client plugin
|
|
@@ -154,4 +180,4 @@ type SitemapEntry = {
|
|
|
154
180
|
};
|
|
155
181
|
type Sitemap = Array<SitemapEntry>;
|
|
156
182
|
|
|
157
|
-
export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, StackContext as S, SitemapEntry as a, ClientStackContext as b, Sitemap as c, PluginRoutes as d, ClientLibConfig as e, ClientLib as f, PrefixedPluginRoutes as g, BackendLibConfig as h, BackendLib as i };
|
|
183
|
+
export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, StackContext as S, SitemapEntry as a, ClientStackContext as b, Sitemap as c, PluginRoutes as d, ClientLibConfig as e, ClientLib as f, PrefixedPluginRoutes as g, BackendLibConfig as h, BackendLib as i, PluginApis as j };
|
|
@@ -8,7 +8,7 @@ import { Endpoint, Router } from 'better-call';
|
|
|
8
8
|
*/
|
|
9
9
|
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 */
|
|
@@ -33,8 +33,11 @@ interface ClientStackContext<TPlugins extends Record<string, ClientPlugin<any, a
|
|
|
33
33
|
* You can optionally provide a base schema via the dbSchema config option.
|
|
34
34
|
*
|
|
35
35
|
* @template TRoutes - The exact shape of routes this plugin provides (preserves keys and endpoint types)
|
|
36
|
+
* @template TApi - The shape of the server-side API surface exposed via `stack().api`.
|
|
37
|
+
* Defaults to `never` so that plugins without an `api` factory are excluded from the
|
|
38
|
+
* `stack().api` namespace entirely, preventing accidental access of `undefined` at runtime.
|
|
36
39
|
*/
|
|
37
|
-
interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint
|
|
40
|
+
interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>, TApi extends Record<string, (...args: any[]) => any> = never> {
|
|
38
41
|
name: string;
|
|
39
42
|
/**
|
|
40
43
|
* Create API endpoints for this plugin
|
|
@@ -46,6 +49,14 @@ interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string
|
|
|
46
49
|
*/
|
|
47
50
|
routes: (adapter: Adapter, context?: StackContext) => TRoutes;
|
|
48
51
|
dbPlugin: DbPlugin;
|
|
52
|
+
/**
|
|
53
|
+
* Optional factory that returns server-side getter functions bound to the adapter.
|
|
54
|
+
* The returned object is merged into `stack().api.<pluginName>.*` for direct
|
|
55
|
+
* server-side or SSG data access without going through HTTP.
|
|
56
|
+
*
|
|
57
|
+
* @param adapter - The adapter instance shared with `routes`
|
|
58
|
+
*/
|
|
59
|
+
api?: (adapter: Adapter) => TApi;
|
|
49
60
|
}
|
|
50
61
|
/**
|
|
51
62
|
* Frontend plugin definition
|
|
@@ -70,10 +81,21 @@ interface ClientPlugin<TOverrides = Record<string, never>, TRoutes extends Recor
|
|
|
70
81
|
*/
|
|
71
82
|
sitemap?: () => Promise<Sitemap> | Sitemap;
|
|
72
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Utility type that maps each plugin key to the return type of its `api` factory.
|
|
86
|
+
* Plugin keys whose `TApi` resolves to `never` (i.e. plugins with no `api` factory)
|
|
87
|
+
* are excluded from the resulting type via key remapping, preventing TypeScript from
|
|
88
|
+
* suggesting callable functions on what is actually `undefined` at runtime.
|
|
89
|
+
*/
|
|
90
|
+
type PluginApis<TPlugins extends Record<string, BackendPlugin<any, any>>> = {
|
|
91
|
+
[K in keyof TPlugins as _ApiOf<TPlugins[K]> extends never ? never : K]: _ApiOf<TPlugins[K]>;
|
|
92
|
+
};
|
|
93
|
+
/** @internal Extract the TApi parameter from a BackendPlugin type. */
|
|
94
|
+
type _ApiOf<T> = T extends BackendPlugin<any, infer TApi> ? TApi : never;
|
|
73
95
|
/**
|
|
74
96
|
* Configuration for creating the backend library
|
|
75
97
|
*/
|
|
76
|
-
interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any>> = Record<string, BackendPlugin<any>>> {
|
|
98
|
+
interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any, any>> = Record<string, BackendPlugin<any, any>>> {
|
|
77
99
|
basePath: string;
|
|
78
100
|
dbSchema?: DatabaseDefinition;
|
|
79
101
|
plugins: TPlugins;
|
|
@@ -109,18 +131,22 @@ type PluginRoutes<TPlugins extends Record<string, ClientPlugin<any, any>>> = Mer
|
|
|
109
131
|
* Prefix all backend plugin route keys with the plugin name
|
|
110
132
|
* Example: { messages: { list: Endpoint } } => { messages_list: Endpoint }
|
|
111
133
|
*/
|
|
112
|
-
type PrefixedPluginRoutes<TPlugins extends Record<string, BackendPlugin<any>>> = UnionToIntersection<{
|
|
113
|
-
[PluginKey in keyof TPlugins]: TPlugins[PluginKey] extends BackendPlugin<infer TRoutes> ? {
|
|
134
|
+
type PrefixedPluginRoutes<TPlugins extends Record<string, BackendPlugin<any, any>>> = UnionToIntersection<{
|
|
135
|
+
[PluginKey in keyof TPlugins]: TPlugins[PluginKey] extends BackendPlugin<infer TRoutes, any> ? {
|
|
114
136
|
[RouteKey in keyof TRoutes as `${PluginKey & string}_${RouteKey & string}`]: TRoutes[RouteKey];
|
|
115
137
|
} : never;
|
|
116
138
|
}[keyof TPlugins]> extends infer U ? U extends Record<string, Endpoint> ? U : Record<string, Endpoint> : Record<string, Endpoint>;
|
|
117
139
|
/**
|
|
118
140
|
* Result of creating the backend library
|
|
119
141
|
*/
|
|
120
|
-
interface BackendLib<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>> {
|
|
142
|
+
interface BackendLib<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>, TApis extends Record<string, Record<string, (...args: any[]) => any>> = Record<string, Record<string, (...args: any[]) => any>>> {
|
|
121
143
|
handler: (request: Request) => Promise<Response>;
|
|
122
144
|
router: Router;
|
|
123
145
|
dbSchema: DatabaseDefinition;
|
|
146
|
+
/** The database adapter shared across all plugins */
|
|
147
|
+
adapter: Adapter;
|
|
148
|
+
/** Fully-typed server-side getter functions, namespaced per plugin */
|
|
149
|
+
api: TApis;
|
|
124
150
|
}
|
|
125
151
|
/**
|
|
126
152
|
* Helper type to extract routes from a client plugin
|
|
@@ -154,4 +180,4 @@ type SitemapEntry = {
|
|
|
154
180
|
};
|
|
155
181
|
type Sitemap = Array<SitemapEntry>;
|
|
156
182
|
|
|
157
|
-
export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, StackContext as S, SitemapEntry as a, ClientStackContext as b, Sitemap as c, PluginRoutes as d, ClientLibConfig as e, ClientLib as f, PrefixedPluginRoutes as g, BackendLibConfig as h, BackendLib as i };
|
|
183
|
+
export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, StackContext as S, SitemapEntry as a, ClientStackContext as b, Sitemap as c, PluginRoutes as d, ClientLibConfig as e, ClientLib as f, PrefixedPluginRoutes as g, BackendLibConfig as h, BackendLib as i, PluginApis as j };
|
|
@@ -8,7 +8,7 @@ import { Endpoint, Router } from 'better-call';
|
|
|
8
8
|
*/
|
|
9
9
|
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 */
|
|
@@ -33,8 +33,11 @@ interface ClientStackContext<TPlugins extends Record<string, ClientPlugin<any, a
|
|
|
33
33
|
* You can optionally provide a base schema via the dbSchema config option.
|
|
34
34
|
*
|
|
35
35
|
* @template TRoutes - The exact shape of routes this plugin provides (preserves keys and endpoint types)
|
|
36
|
+
* @template TApi - The shape of the server-side API surface exposed via `stack().api`.
|
|
37
|
+
* Defaults to `never` so that plugins without an `api` factory are excluded from the
|
|
38
|
+
* `stack().api` namespace entirely, preventing accidental access of `undefined` at runtime.
|
|
36
39
|
*/
|
|
37
|
-
interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint
|
|
40
|
+
interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>, TApi extends Record<string, (...args: any[]) => any> = never> {
|
|
38
41
|
name: string;
|
|
39
42
|
/**
|
|
40
43
|
* Create API endpoints for this plugin
|
|
@@ -46,6 +49,14 @@ interface BackendPlugin<TRoutes extends Record<string, Endpoint> = Record<string
|
|
|
46
49
|
*/
|
|
47
50
|
routes: (adapter: Adapter, context?: StackContext) => TRoutes;
|
|
48
51
|
dbPlugin: DbPlugin;
|
|
52
|
+
/**
|
|
53
|
+
* Optional factory that returns server-side getter functions bound to the adapter.
|
|
54
|
+
* The returned object is merged into `stack().api.<pluginName>.*` for direct
|
|
55
|
+
* server-side or SSG data access without going through HTTP.
|
|
56
|
+
*
|
|
57
|
+
* @param adapter - The adapter instance shared with `routes`
|
|
58
|
+
*/
|
|
59
|
+
api?: (adapter: Adapter) => TApi;
|
|
49
60
|
}
|
|
50
61
|
/**
|
|
51
62
|
* Frontend plugin definition
|
|
@@ -70,10 +81,21 @@ interface ClientPlugin<TOverrides = Record<string, never>, TRoutes extends Recor
|
|
|
70
81
|
*/
|
|
71
82
|
sitemap?: () => Promise<Sitemap> | Sitemap;
|
|
72
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Utility type that maps each plugin key to the return type of its `api` factory.
|
|
86
|
+
* Plugin keys whose `TApi` resolves to `never` (i.e. plugins with no `api` factory)
|
|
87
|
+
* are excluded from the resulting type via key remapping, preventing TypeScript from
|
|
88
|
+
* suggesting callable functions on what is actually `undefined` at runtime.
|
|
89
|
+
*/
|
|
90
|
+
type PluginApis<TPlugins extends Record<string, BackendPlugin<any, any>>> = {
|
|
91
|
+
[K in keyof TPlugins as _ApiOf<TPlugins[K]> extends never ? never : K]: _ApiOf<TPlugins[K]>;
|
|
92
|
+
};
|
|
93
|
+
/** @internal Extract the TApi parameter from a BackendPlugin type. */
|
|
94
|
+
type _ApiOf<T> = T extends BackendPlugin<any, infer TApi> ? TApi : never;
|
|
73
95
|
/**
|
|
74
96
|
* Configuration for creating the backend library
|
|
75
97
|
*/
|
|
76
|
-
interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any>> = Record<string, BackendPlugin<any>>> {
|
|
98
|
+
interface BackendLibConfig<TPlugins extends Record<string, BackendPlugin<any, any>> = Record<string, BackendPlugin<any, any>>> {
|
|
77
99
|
basePath: string;
|
|
78
100
|
dbSchema?: DatabaseDefinition;
|
|
79
101
|
plugins: TPlugins;
|
|
@@ -109,18 +131,22 @@ type PluginRoutes<TPlugins extends Record<string, ClientPlugin<any, any>>> = Mer
|
|
|
109
131
|
* Prefix all backend plugin route keys with the plugin name
|
|
110
132
|
* Example: { messages: { list: Endpoint } } => { messages_list: Endpoint }
|
|
111
133
|
*/
|
|
112
|
-
type PrefixedPluginRoutes<TPlugins extends Record<string, BackendPlugin<any>>> = UnionToIntersection<{
|
|
113
|
-
[PluginKey in keyof TPlugins]: TPlugins[PluginKey] extends BackendPlugin<infer TRoutes> ? {
|
|
134
|
+
type PrefixedPluginRoutes<TPlugins extends Record<string, BackendPlugin<any, any>>> = UnionToIntersection<{
|
|
135
|
+
[PluginKey in keyof TPlugins]: TPlugins[PluginKey] extends BackendPlugin<infer TRoutes, any> ? {
|
|
114
136
|
[RouteKey in keyof TRoutes as `${PluginKey & string}_${RouteKey & string}`]: TRoutes[RouteKey];
|
|
115
137
|
} : never;
|
|
116
138
|
}[keyof TPlugins]> extends infer U ? U extends Record<string, Endpoint> ? U : Record<string, Endpoint> : Record<string, Endpoint>;
|
|
117
139
|
/**
|
|
118
140
|
* Result of creating the backend library
|
|
119
141
|
*/
|
|
120
|
-
interface BackendLib<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>> {
|
|
142
|
+
interface BackendLib<TRoutes extends Record<string, Endpoint> = Record<string, Endpoint>, TApis extends Record<string, Record<string, (...args: any[]) => any>> = Record<string, Record<string, (...args: any[]) => any>>> {
|
|
121
143
|
handler: (request: Request) => Promise<Response>;
|
|
122
144
|
router: Router;
|
|
123
145
|
dbSchema: DatabaseDefinition;
|
|
146
|
+
/** The database adapter shared across all plugins */
|
|
147
|
+
adapter: Adapter;
|
|
148
|
+
/** Fully-typed server-side getter functions, namespaced per plugin */
|
|
149
|
+
api: TApis;
|
|
124
150
|
}
|
|
125
151
|
/**
|
|
126
152
|
* Helper type to extract routes from a client plugin
|
|
@@ -154,4 +180,4 @@ type SitemapEntry = {
|
|
|
154
180
|
};
|
|
155
181
|
type Sitemap = Array<SitemapEntry>;
|
|
156
182
|
|
|
157
|
-
export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, StackContext as S, SitemapEntry as a, ClientStackContext as b, Sitemap as c, PluginRoutes as d, ClientLibConfig as e, ClientLib as f, PrefixedPluginRoutes as g, BackendLibConfig as h, BackendLib as i };
|
|
183
|
+
export type { BackendPlugin as B, ClientPlugin as C, PluginOverrides as P, StackContext as S, SitemapEntry as a, ClientStackContext as b, Sitemap as c, PluginRoutes as d, ClientLibConfig as e, ClientLib as f, PrefixedPluginRoutes as g, BackendLibConfig as h, BackendLib as i, PluginApis as j };
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
2
|
+
import { createApiClient } from '@btst/stack/plugins/client';
|
|
3
|
+
import { M as Message, C as Conversation, S as SerializedConversation, a as SerializedMessage } from './stack.Be1QIHEn.js';
|
|
4
|
+
import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
|
|
5
|
+
import * as better_call from 'better-call';
|
|
6
|
+
import * as zod_v4_core from 'zod/v4/core';
|
|
7
|
+
import * as zod from 'zod';
|
|
8
|
+
import { LanguageModel, Tool } from 'ai';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Context passed to AI Chat API hooks
|
|
12
|
+
*/
|
|
13
|
+
interface ChatApiContext<TBody = any, TParams = any, TQuery = any> {
|
|
14
|
+
body?: TBody;
|
|
15
|
+
params?: TParams;
|
|
16
|
+
query?: TQuery;
|
|
17
|
+
request?: Request;
|
|
18
|
+
headers?: Headers;
|
|
19
|
+
[key: string]: any;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configuration hooks for AI Chat backend plugin
|
|
23
|
+
* All hooks are optional and allow consumers to customize behavior
|
|
24
|
+
*/
|
|
25
|
+
interface AiChatBackendHooks {
|
|
26
|
+
/**
|
|
27
|
+
* Called before processing a chat message. Return false to deny access.
|
|
28
|
+
* @param messages - Array of messages being sent
|
|
29
|
+
* @param context - Request context with headers, etc.
|
|
30
|
+
*/
|
|
31
|
+
onBeforeChat?: (messages: Array<{
|
|
32
|
+
role: string;
|
|
33
|
+
content: string;
|
|
34
|
+
}>, context: ChatApiContext) => Promise<boolean> | boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Called before listing conversations. Return false to deny access.
|
|
37
|
+
* @param context - Request context with headers, etc.
|
|
38
|
+
*/
|
|
39
|
+
onBeforeListConversations?: (context: ChatApiContext) => Promise<boolean> | boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Called before getting a single conversation. Return false to deny access.
|
|
42
|
+
* @param conversationId - ID of the conversation being accessed
|
|
43
|
+
* @param context - Request context with headers, etc.
|
|
44
|
+
*/
|
|
45
|
+
onBeforeGetConversation?: (conversationId: string, context: ChatApiContext) => Promise<boolean> | boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Called before creating a conversation. Return false to deny access.
|
|
48
|
+
* @param data - Conversation data being created
|
|
49
|
+
* @param context - Request context with headers, etc.
|
|
50
|
+
*/
|
|
51
|
+
onBeforeCreateConversation?: (data: {
|
|
52
|
+
id?: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
}, context: ChatApiContext) => Promise<boolean> | boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Called before updating a conversation. Return false to deny access.
|
|
57
|
+
* @param conversationId - ID of the conversation being updated
|
|
58
|
+
* @param data - Updated conversation data
|
|
59
|
+
* @param context - Request context with headers, etc.
|
|
60
|
+
*/
|
|
61
|
+
onBeforeUpdateConversation?: (conversationId: string, data: {
|
|
62
|
+
title?: string;
|
|
63
|
+
}, context: ChatApiContext) => Promise<boolean> | boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Called before deleting a conversation. Return false to deny access.
|
|
66
|
+
* @param conversationId - ID of the conversation being deleted
|
|
67
|
+
* @param context - Request context with headers, etc.
|
|
68
|
+
*/
|
|
69
|
+
onBeforeDeleteConversation?: (conversationId: string, context: ChatApiContext) => Promise<boolean> | boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Called after a chat message is processed successfully
|
|
72
|
+
* @param conversationId - ID of the conversation
|
|
73
|
+
* @param messages - Array of messages in the conversation
|
|
74
|
+
* @param context - Request context
|
|
75
|
+
*/
|
|
76
|
+
onAfterChat?: (conversationId: string, messages: Message[], context: ChatApiContext) => Promise<void> | void;
|
|
77
|
+
/**
|
|
78
|
+
* Called after conversations are read successfully
|
|
79
|
+
* @param conversations - Array of conversations that were read
|
|
80
|
+
* @param context - Request context
|
|
81
|
+
*/
|
|
82
|
+
onConversationsRead?: (conversations: Conversation[], context: ChatApiContext) => Promise<void> | void;
|
|
83
|
+
/**
|
|
84
|
+
* Called after a single conversation is read successfully
|
|
85
|
+
* @param conversation - The conversation with messages
|
|
86
|
+
* @param context - Request context
|
|
87
|
+
*/
|
|
88
|
+
onConversationRead?: (conversation: Conversation & {
|
|
89
|
+
messages: Message[];
|
|
90
|
+
}, context: ChatApiContext) => Promise<void> | void;
|
|
91
|
+
/**
|
|
92
|
+
* Called after a conversation is created successfully
|
|
93
|
+
* @param conversation - The created conversation
|
|
94
|
+
* @param context - Request context
|
|
95
|
+
*/
|
|
96
|
+
onConversationCreated?: (conversation: Conversation, context: ChatApiContext) => Promise<void> | void;
|
|
97
|
+
/**
|
|
98
|
+
* Called after a conversation is updated successfully
|
|
99
|
+
* @param conversation - The updated conversation
|
|
100
|
+
* @param context - Request context
|
|
101
|
+
*/
|
|
102
|
+
onConversationUpdated?: (conversation: Conversation, context: ChatApiContext) => Promise<void> | void;
|
|
103
|
+
/**
|
|
104
|
+
* Called after a conversation is deleted successfully
|
|
105
|
+
* @param conversationId - ID of the deleted conversation
|
|
106
|
+
* @param context - Request context
|
|
107
|
+
*/
|
|
108
|
+
onConversationDeleted?: (conversationId: string, context: ChatApiContext) => Promise<void> | void;
|
|
109
|
+
/**
|
|
110
|
+
* Called when a chat operation fails
|
|
111
|
+
* @param error - The error that occurred
|
|
112
|
+
* @param context - Request context
|
|
113
|
+
*/
|
|
114
|
+
onChatError?: (error: Error, context: ChatApiContext) => Promise<void> | void;
|
|
115
|
+
/**
|
|
116
|
+
* Called when listing conversations fails
|
|
117
|
+
* @param error - The error that occurred
|
|
118
|
+
* @param context - Request context
|
|
119
|
+
*/
|
|
120
|
+
onListConversationsError?: (error: Error, context: ChatApiContext) => Promise<void> | void;
|
|
121
|
+
/**
|
|
122
|
+
* Called when getting a conversation fails
|
|
123
|
+
* @param error - The error that occurred
|
|
124
|
+
* @param context - Request context
|
|
125
|
+
*/
|
|
126
|
+
onGetConversationError?: (error: Error, context: ChatApiContext) => Promise<void> | void;
|
|
127
|
+
/**
|
|
128
|
+
* Called when creating a conversation fails
|
|
129
|
+
* @param error - The error that occurred
|
|
130
|
+
* @param context - Request context
|
|
131
|
+
*/
|
|
132
|
+
onCreateConversationError?: (error: Error, context: ChatApiContext) => Promise<void> | void;
|
|
133
|
+
/**
|
|
134
|
+
* Called when updating a conversation fails
|
|
135
|
+
* @param error - The error that occurred
|
|
136
|
+
* @param context - Request context
|
|
137
|
+
*/
|
|
138
|
+
onUpdateConversationError?: (error: Error, context: ChatApiContext) => Promise<void> | void;
|
|
139
|
+
/**
|
|
140
|
+
* Called when deleting a conversation fails
|
|
141
|
+
* @param error - The error that occurred
|
|
142
|
+
* @param context - Request context
|
|
143
|
+
*/
|
|
144
|
+
onDeleteConversationError?: (error: Error, context: ChatApiContext) => Promise<void> | void;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Plugin mode for AI Chat
|
|
148
|
+
* - 'authenticated': Conversations persisted with userId (default)
|
|
149
|
+
* - 'public': Stateless chat, no persistence (ideal for public chatbots)
|
|
150
|
+
*/
|
|
151
|
+
type AiChatMode = "authenticated" | "public";
|
|
152
|
+
/**
|
|
153
|
+
* Configuration for AI Chat backend plugin
|
|
154
|
+
*/
|
|
155
|
+
interface AiChatBackendConfig {
|
|
156
|
+
/**
|
|
157
|
+
* The language model to use for chat completions.
|
|
158
|
+
* Supports any model from AI SDK providers (OpenAI, Anthropic, Google, etc.)
|
|
159
|
+
*/
|
|
160
|
+
model: LanguageModel;
|
|
161
|
+
/**
|
|
162
|
+
* Plugin mode:
|
|
163
|
+
* - 'authenticated': Conversations persisted with userId (requires getUserId)
|
|
164
|
+
* - 'public': Stateless chat, no persistence (ideal for public chatbots)
|
|
165
|
+
* @default 'authenticated'
|
|
166
|
+
*/
|
|
167
|
+
mode?: AiChatMode;
|
|
168
|
+
/**
|
|
169
|
+
* Extract userId from request context (authenticated mode only).
|
|
170
|
+
* Return null/undefined to deny access in authenticated mode.
|
|
171
|
+
* This function is called for all conversation operations.
|
|
172
|
+
* @example (ctx) => ctx.headers?.get('x-user-id')
|
|
173
|
+
*/
|
|
174
|
+
getUserId?: (context: ChatApiContext) => string | null | undefined | Promise<string | null | undefined>;
|
|
175
|
+
/**
|
|
176
|
+
* Optional system prompt to prepend to all conversations
|
|
177
|
+
*/
|
|
178
|
+
systemPrompt?: string;
|
|
179
|
+
/**
|
|
180
|
+
* Optional tools to make available to the model.
|
|
181
|
+
* Uses AI SDK v5 tool format.
|
|
182
|
+
* @see https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling
|
|
183
|
+
*/
|
|
184
|
+
tools?: Record<string, Tool>;
|
|
185
|
+
/**
|
|
186
|
+
* Optional hooks for customizing plugin behavior
|
|
187
|
+
*/
|
|
188
|
+
hooks?: AiChatBackendHooks;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* AI Chat backend plugin
|
|
192
|
+
* Provides API endpoints for AI-powered chat with conversation history
|
|
193
|
+
* Uses AI SDK v5 for model interactions
|
|
194
|
+
*
|
|
195
|
+
* @param config - Configuration including model, tools, and optional hooks
|
|
196
|
+
*/
|
|
197
|
+
declare const aiChatBackendPlugin: (config: AiChatBackendConfig) => _btst_stack_plugins_api.BackendPlugin<{
|
|
198
|
+
chat: better_call.StrictEndpoint<"/chat", {
|
|
199
|
+
method: "POST";
|
|
200
|
+
body: zod.ZodObject<{
|
|
201
|
+
messages: zod.ZodArray<zod.ZodUnion<readonly [zod.ZodObject<{
|
|
202
|
+
role: zod.ZodEnum<{
|
|
203
|
+
system: "system";
|
|
204
|
+
user: "user";
|
|
205
|
+
assistant: "assistant";
|
|
206
|
+
data: "data";
|
|
207
|
+
}>;
|
|
208
|
+
content: zod.ZodString;
|
|
209
|
+
id: zod.ZodOptional<zod.ZodString>;
|
|
210
|
+
}, zod_v4_core.$strip>, zod.ZodObject<{
|
|
211
|
+
role: zod.ZodEnum<{
|
|
212
|
+
system: "system";
|
|
213
|
+
user: "user";
|
|
214
|
+
assistant: "assistant";
|
|
215
|
+
data: "data";
|
|
216
|
+
}>;
|
|
217
|
+
parts: zod.ZodArray<zod.ZodObject<{
|
|
218
|
+
type: zod.ZodString;
|
|
219
|
+
text: zod.ZodOptional<zod.ZodString>;
|
|
220
|
+
}, zod_v4_core.$loose>>;
|
|
221
|
+
id: zod.ZodOptional<zod.ZodString>;
|
|
222
|
+
metadata: zod.ZodOptional<zod.ZodAny>;
|
|
223
|
+
}, zod_v4_core.$strip>]>>;
|
|
224
|
+
conversationId: zod.ZodOptional<zod.ZodString>;
|
|
225
|
+
model: zod.ZodOptional<zod.ZodString>;
|
|
226
|
+
}, zod_v4_core.$strip>;
|
|
227
|
+
}, Response>;
|
|
228
|
+
createConversation: better_call.StrictEndpoint<"/chat/conversations", {
|
|
229
|
+
method: "POST";
|
|
230
|
+
body: zod.ZodObject<{
|
|
231
|
+
id: zod.ZodOptional<zod.ZodString>;
|
|
232
|
+
title: zod.ZodOptional<zod.ZodString>;
|
|
233
|
+
}, zod_v4_core.$strip>;
|
|
234
|
+
}, Conversation>;
|
|
235
|
+
listConversations: better_call.StrictEndpoint<"/chat/conversations", {
|
|
236
|
+
method: "GET";
|
|
237
|
+
}, Conversation[]>;
|
|
238
|
+
getConversation: better_call.StrictEndpoint<"/chat/conversations/:id", {
|
|
239
|
+
method: "GET";
|
|
240
|
+
}, Conversation & {
|
|
241
|
+
messages: Message[];
|
|
242
|
+
}>;
|
|
243
|
+
updateConversation: better_call.StrictEndpoint<"/chat/conversations/:id", {
|
|
244
|
+
method: "PUT";
|
|
245
|
+
body: zod.ZodObject<{
|
|
246
|
+
title: zod.ZodOptional<zod.ZodString>;
|
|
247
|
+
}, zod_v4_core.$strip>;
|
|
248
|
+
}, Conversation>;
|
|
249
|
+
deleteConversation: better_call.StrictEndpoint<"/chat/conversations/:id", {
|
|
250
|
+
method: "DELETE";
|
|
251
|
+
}, {
|
|
252
|
+
success: boolean;
|
|
253
|
+
}>;
|
|
254
|
+
}, {
|
|
255
|
+
getAllConversations: (userId?: string) => Promise<Conversation[]>;
|
|
256
|
+
getConversationById: (id: string) => Promise<(Conversation & {
|
|
257
|
+
messages: Message[];
|
|
258
|
+
}) | null>;
|
|
259
|
+
}>;
|
|
260
|
+
type AiChatApiRouter = ReturnType<ReturnType<typeof aiChatBackendPlugin>["routes"]>;
|
|
261
|
+
|
|
262
|
+
type ConversationWithMessages = SerializedConversation & {
|
|
263
|
+
messages: SerializedMessage[];
|
|
264
|
+
};
|
|
265
|
+
declare function createAiChatQueryKeys(client: ReturnType<typeof createApiClient<AiChatApiRouter>>, headers?: HeadersInit): {
|
|
266
|
+
conversations: {
|
|
267
|
+
_def: readonly ["conversations"];
|
|
268
|
+
} & {
|
|
269
|
+
list: (() => Omit<{
|
|
270
|
+
queryKey: readonly ["conversations", "list", string];
|
|
271
|
+
queryFn: _tanstack_react_query.QueryFunction<SerializedConversation[], readonly ["conversations", "list", string]>;
|
|
272
|
+
} & {
|
|
273
|
+
_def: readonly ["conversations", "list"];
|
|
274
|
+
}, "_def">) & {
|
|
275
|
+
_def: readonly ["conversations", "list"];
|
|
276
|
+
};
|
|
277
|
+
detail: ((id: string) => Omit<{
|
|
278
|
+
queryKey: readonly ["conversations", "detail", string];
|
|
279
|
+
queryFn: _tanstack_react_query.QueryFunction<ConversationWithMessages | null, readonly ["conversations", "detail", string]>;
|
|
280
|
+
} & {
|
|
281
|
+
_def: readonly ["conversations", "detail"];
|
|
282
|
+
}, "_def">) & {
|
|
283
|
+
_def: readonly ["conversations", "detail"];
|
|
284
|
+
};
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export { createAiChatQueryKeys as c, aiChatBackendPlugin as d };
|
|
289
|
+
export type { AiChatBackendHooks as A, ChatApiContext as C, AiChatMode as a, AiChatBackendConfig as b, AiChatApiRouter as e, ConversationWithMessages as f };
|
|
@@ -66,8 +66,8 @@ interface SerializedFormSubmission extends Omit<FormSubmission, "submittedAt"> {
|
|
|
66
66
|
* Serialized form submission with parsed data
|
|
67
67
|
*/
|
|
68
68
|
interface SerializedFormSubmissionWithData<TData = Record<string, unknown>> extends SerializedFormSubmission {
|
|
69
|
-
/** Parsed data object (JSON.parse of data field) */
|
|
70
|
-
parsedData: TData;
|
|
69
|
+
/** Parsed data object (JSON.parse of data field). Null when the stored JSON is corrupted. */
|
|
70
|
+
parsedData: TData | null;
|
|
71
71
|
/** Joined form */
|
|
72
72
|
form?: SerializedForm;
|
|
73
73
|
}
|
|
@@ -66,8 +66,8 @@ interface SerializedFormSubmission extends Omit<FormSubmission, "submittedAt"> {
|
|
|
66
66
|
* Serialized form submission with parsed data
|
|
67
67
|
*/
|
|
68
68
|
interface SerializedFormSubmissionWithData<TData = Record<string, unknown>> extends SerializedFormSubmission {
|
|
69
|
-
/** Parsed data object (JSON.parse of data field) */
|
|
70
|
-
parsedData: TData;
|
|
69
|
+
/** Parsed data object (JSON.parse of data field). Null when the stored JSON is corrupted. */
|
|
70
|
+
parsedData: TData | null;
|
|
71
71
|
/** Joined form */
|
|
72
72
|
form?: SerializedForm;
|
|
73
73
|
}
|
|
@@ -66,8 +66,8 @@ interface SerializedFormSubmission extends Omit<FormSubmission, "submittedAt"> {
|
|
|
66
66
|
* Serialized form submission with parsed data
|
|
67
67
|
*/
|
|
68
68
|
interface SerializedFormSubmissionWithData<TData = Record<string, unknown>> extends SerializedFormSubmission {
|
|
69
|
-
/** Parsed data object (JSON.parse of data field) */
|
|
70
|
-
parsedData: TData;
|
|
69
|
+
/** Parsed data object (JSON.parse of data field). Null when the stored JSON is corrupted. */
|
|
70
|
+
parsedData: TData | null;
|
|
71
71
|
/** Joined form */
|
|
72
72
|
form?: SerializedForm;
|
|
73
73
|
}
|