@btst/stack 2.4.0 → 2.5.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/packages/stack/src/plugins/ai-chat/api/plugin.cjs +33 -47
- package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +33 -47
- package/dist/packages/stack/src/plugins/ai-chat/client/plugin.cjs +14 -21
- package/dist/packages/stack/src/plugins/ai-chat/client/plugin.mjs +15 -22
- package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +28 -45
- package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +22 -39
- package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +23 -27
- package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +24 -28
- package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +14 -17
- package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +14 -17
- package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +11 -15
- package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +12 -16
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +58 -62
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +58 -62
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +12 -12
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +13 -13
- package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +86 -117
- package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +83 -114
- package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +22 -29
- package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +23 -30
- package/dist/packages/stack/src/plugins/ui-builder/client/plugin.cjs +8 -8
- package/dist/packages/stack/src/plugins/ui-builder/client/plugin.mjs +9 -9
- package/dist/packages/stack/src/plugins/utils.cjs +42 -0
- package/dist/packages/stack/src/plugins/utils.mjs +41 -1
- package/dist/plugins/ai-chat/api/index.d.cts +1 -1
- package/dist/plugins/ai-chat/api/index.d.mts +1 -1
- package/dist/plugins/ai-chat/api/index.d.ts +1 -1
- package/dist/plugins/ai-chat/client/hooks/index.d.cts +1 -1
- package/dist/plugins/ai-chat/client/hooks/index.d.mts +1 -1
- package/dist/plugins/ai-chat/client/hooks/index.d.ts +1 -1
- package/dist/plugins/ai-chat/client/index.d.cts +8 -8
- package/dist/plugins/ai-chat/client/index.d.mts +8 -8
- package/dist/plugins/ai-chat/client/index.d.ts +8 -8
- package/dist/plugins/ai-chat/query-keys.d.cts +1 -1
- package/dist/plugins/ai-chat/query-keys.d.mts +1 -1
- package/dist/plugins/ai-chat/query-keys.d.ts +1 -1
- package/dist/plugins/blog/api/index.d.cts +1 -1
- package/dist/plugins/blog/api/index.d.mts +1 -1
- package/dist/plugins/blog/api/index.d.ts +1 -1
- package/dist/plugins/blog/client/index.d.cts +12 -12
- package/dist/plugins/blog/client/index.d.mts +12 -12
- package/dist/plugins/blog/client/index.d.ts +12 -12
- package/dist/plugins/blog/query-keys.d.cts +1 -1
- package/dist/plugins/blog/query-keys.d.mts +1 -1
- package/dist/plugins/blog/query-keys.d.ts +1 -1
- package/dist/plugins/client/index.cjs +1 -0
- package/dist/plugins/client/index.d.cts +8 -1
- package/dist/plugins/client/index.d.mts +8 -1
- package/dist/plugins/client/index.d.ts +8 -1
- package/dist/plugins/client/index.mjs +1 -1
- package/dist/plugins/cms/api/index.d.cts +2 -2
- package/dist/plugins/cms/api/index.d.mts +2 -2
- package/dist/plugins/cms/api/index.d.ts +2 -2
- 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/client/index.d.cts +6 -6
- package/dist/plugins/cms/client/index.d.mts +6 -6
- package/dist/plugins/cms/client/index.d.ts +6 -6
- package/dist/plugins/cms/query-keys.d.cts +2 -2
- package/dist/plugins/cms/query-keys.d.mts +2 -2
- package/dist/plugins/cms/query-keys.d.ts +2 -2
- package/dist/plugins/form-builder/api/index.d.cts +2 -2
- package/dist/plugins/form-builder/api/index.d.mts +2 -2
- package/dist/plugins/form-builder/api/index.d.ts +2 -2
- 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/client/index.d.cts +6 -6
- package/dist/plugins/form-builder/client/index.d.mts +6 -6
- package/dist/plugins/form-builder/client/index.d.ts +6 -6
- package/dist/plugins/form-builder/query-keys.d.cts +2 -2
- package/dist/plugins/form-builder/query-keys.d.mts +2 -2
- package/dist/plugins/form-builder/query-keys.d.ts +2 -2
- package/dist/plugins/kanban/api/index.d.cts +1 -1
- package/dist/plugins/kanban/api/index.d.mts +1 -1
- package/dist/plugins/kanban/api/index.d.ts +1 -1
- package/dist/plugins/kanban/client/index.d.cts +12 -12
- package/dist/plugins/kanban/client/index.d.mts +12 -12
- package/dist/plugins/kanban/client/index.d.ts +12 -12
- package/dist/plugins/kanban/query-keys.d.cts +1 -1
- package/dist/plugins/kanban/query-keys.d.mts +1 -1
- package/dist/plugins/kanban/query-keys.d.ts +1 -1
- package/dist/plugins/ui-builder/client/hooks/index.d.cts +1 -1
- package/dist/plugins/ui-builder/client/hooks/index.d.mts +1 -1
- package/dist/plugins/ui-builder/client/hooks/index.d.ts +1 -1
- package/dist/plugins/ui-builder/client/index.d.cts +3 -3
- package/dist/plugins/ui-builder/client/index.d.mts +3 -3
- package/dist/plugins/ui-builder/client/index.d.ts +3 -3
- package/dist/plugins/ui-builder/index.d.cts +2 -2
- package/dist/plugins/ui-builder/index.d.mts +2 -2
- package/dist/plugins/ui-builder/index.d.ts +2 -2
- package/dist/shared/{stack.C-WUPMT6.d.cts → stack.B2xZTSiO.d.cts} +4 -4
- package/dist/shared/{stack.CczspVn2.d.mts → stack.B58oHdqm.d.mts} +1 -1
- package/dist/shared/{stack.CVDTkMoO.d.mts → stack.B8QD11QU.d.cts} +7 -7
- package/dist/shared/{stack.CVDTkMoO.d.cts → stack.B8QD11QU.d.mts} +7 -7
- package/dist/shared/{stack.CVDTkMoO.d.ts → stack.B8QD11QU.d.ts} +7 -7
- package/dist/shared/{stack.Kq2-QzOC.d.ts → stack.BDVEpue1.d.ts} +2 -2
- package/dist/shared/{stack.B7ONvlD_.d.mts → stack.BTvbxZvw.d.cts} +2 -2
- package/dist/shared/{stack.DdI5W6MB.d.mts → stack.BozPgbrZ.d.cts} +19 -19
- package/dist/shared/{stack.DdI5W6MB.d.cts → stack.BozPgbrZ.d.mts} +19 -19
- package/dist/shared/{stack.DdI5W6MB.d.ts → stack.BozPgbrZ.d.ts} +19 -19
- package/dist/shared/{stack.BUkC2EsZ.d.cts → stack.C9Mg2Q46.d.cts} +1 -1
- package/dist/shared/{stack.BEn34wW6.d.ts → stack.CTDVxbrA.d.ts} +12 -12
- package/dist/shared/{stack.C-Ptrz8s.d.ts → stack.Cj_zKww4.d.ts} +4 -4
- package/dist/shared/{stack.BepFXT3w.d.mts → stack.CxaFNQCV.d.mts} +25 -25
- package/dist/shared/{stack.DWoCZff7.d.cts → stack.D-b5zbPm.d.cts} +12 -12
- package/dist/shared/{stack.kcdnD4gA.d.cts → stack.DTtmJPQO.d.mts} +2 -2
- package/dist/shared/{stack.CL8ts1Mu.d.ts → stack.DXnclTG7.d.ts} +8 -8
- package/dist/shared/{stack.heOA9gzA.d.cts → stack.DaZM10cp.d.cts} +8 -8
- package/dist/shared/{stack.DTDxgFj8.d.mts → stack.FVWf2JhZ.d.mts} +12 -12
- package/dist/shared/{stack.Dk5r4W1F.d.mts → stack.cfCkioTe.d.mts} +8 -8
- package/dist/shared/{stack.6fUOjLs9.d.mts → stack.dH7u-TJH.d.mts} +4 -4
- package/dist/shared/{stack.CgWzG5jH.d.ts → stack.j75TpKh2.d.ts} +25 -25
- package/dist/shared/{stack.D3GB6wKv.d.cts → stack.n1_i1p2B.d.cts} +25 -25
- package/dist/shared/{stack.DASmUVjX.d.ts → stack.sO33ZDhK.d.ts} +1 -1
- package/package.json +1 -1
- package/src/plugins/ai-chat/api/plugin.ts +48 -63
- package/src/plugins/ai-chat/client/plugin.tsx +23 -31
- package/src/plugins/blog/api/plugin.ts +31 -47
- package/src/plugins/blog/client/plugin.tsx +36 -39
- package/src/plugins/client/index.ts +5 -1
- package/src/plugins/cms/api/plugin.ts +14 -17
- package/src/plugins/cms/client/plugin.tsx +18 -21
- package/src/plugins/cms/types.ts +7 -7
- package/src/plugins/form-builder/api/plugin.ts +64 -64
- package/src/plugins/form-builder/client/plugin.tsx +19 -18
- package/src/plugins/form-builder/types.ts +19 -24
- package/src/plugins/kanban/api/plugin.ts +111 -136
- package/src/plugins/kanban/client/plugin.tsx +35 -41
- package/src/plugins/ui-builder/client/plugin.tsx +11 -10
- package/src/plugins/ui-builder/types.ts +4 -4
- package/src/plugins/utils.ts +92 -1
|
@@ -7,12 +7,12 @@ import { QueryClient } from '@tanstack/react-query';
|
|
|
7
7
|
|
|
8
8
|
declare const createBoardSchema: z.ZodObject<{
|
|
9
9
|
description: z.ZodOptional<z.ZodString>;
|
|
10
|
+
name: z.ZodString;
|
|
10
11
|
slug: z.ZodOptional<z.ZodString>;
|
|
11
12
|
ownerId: z.ZodOptional<z.ZodString>;
|
|
12
13
|
organizationId: z.ZodOptional<z.ZodString>;
|
|
13
14
|
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
14
15
|
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
15
|
-
name: z.ZodString;
|
|
16
16
|
}, z.core.$strip>;
|
|
17
17
|
declare const updateBoardSchema: z.ZodObject<{
|
|
18
18
|
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
@@ -189,25 +189,25 @@ interface KanbanApiContext<TBody = unknown, TParams = unknown, TQuery = unknown>
|
|
|
189
189
|
*/
|
|
190
190
|
interface KanbanBackendHooks {
|
|
191
191
|
/**
|
|
192
|
-
* Called before listing boards.
|
|
192
|
+
* Called before listing boards. Throw an error to deny access.
|
|
193
193
|
*/
|
|
194
|
-
onBeforeListBoards?: (filter: z.infer<typeof BoardListQuerySchema>, context: KanbanApiContext) => Promise<
|
|
194
|
+
onBeforeListBoards?: (filter: z.infer<typeof BoardListQuerySchema>, context: KanbanApiContext) => Promise<void> | void;
|
|
195
195
|
/**
|
|
196
|
-
* Called before creating a board.
|
|
196
|
+
* Called before creating a board. Throw an error to deny access.
|
|
197
197
|
*/
|
|
198
|
-
onBeforeCreateBoard?: (data: z.infer<typeof createBoardSchema>, context: KanbanApiContext) => Promise<
|
|
198
|
+
onBeforeCreateBoard?: (data: z.infer<typeof createBoardSchema>, context: KanbanApiContext) => Promise<void> | void;
|
|
199
199
|
/**
|
|
200
|
-
* Called before reading a single board.
|
|
200
|
+
* Called before reading a single board. Throw an error to deny access.
|
|
201
201
|
*/
|
|
202
|
-
onBeforeReadBoard?: (boardId: string, context: KanbanApiContext) => Promise<
|
|
202
|
+
onBeforeReadBoard?: (boardId: string, context: KanbanApiContext) => Promise<void> | void;
|
|
203
203
|
/**
|
|
204
|
-
* Called before updating a board.
|
|
204
|
+
* Called before updating a board. Throw an error to deny access.
|
|
205
205
|
*/
|
|
206
|
-
onBeforeUpdateBoard?: (boardId: string, data: z.infer<typeof updateBoardSchema>, context: KanbanApiContext) => Promise<
|
|
206
|
+
onBeforeUpdateBoard?: (boardId: string, data: z.infer<typeof updateBoardSchema>, context: KanbanApiContext) => Promise<void> | void;
|
|
207
207
|
/**
|
|
208
|
-
* Called before deleting a board.
|
|
208
|
+
* Called before deleting a board. Throw an error to deny access.
|
|
209
209
|
*/
|
|
210
|
-
onBeforeDeleteBoard?: (boardId: string, context: KanbanApiContext) => Promise<
|
|
210
|
+
onBeforeDeleteBoard?: (boardId: string, context: KanbanApiContext) => Promise<void> | void;
|
|
211
211
|
/**
|
|
212
212
|
* Called after boards are listed successfully.
|
|
213
213
|
* Receives the items array (same shape as `board[]`) for consistency
|
|
@@ -251,17 +251,17 @@ interface KanbanBackendHooks {
|
|
|
251
251
|
*/
|
|
252
252
|
onDeleteBoardError?: (error: Error, context: KanbanApiContext) => Promise<void> | void;
|
|
253
253
|
/**
|
|
254
|
-
* Called before creating a column.
|
|
254
|
+
* Called before creating a column. Throw an error to deny access.
|
|
255
255
|
*/
|
|
256
|
-
onBeforeCreateColumn?: (data: z.infer<typeof createColumnSchema>, context: KanbanApiContext) => Promise<
|
|
256
|
+
onBeforeCreateColumn?: (data: z.infer<typeof createColumnSchema>, context: KanbanApiContext) => Promise<void> | void;
|
|
257
257
|
/**
|
|
258
|
-
* Called before updating a column.
|
|
258
|
+
* Called before updating a column. Throw an error to deny access.
|
|
259
259
|
*/
|
|
260
|
-
onBeforeUpdateColumn?: (columnId: string, data: z.infer<typeof updateColumnSchema>, context: KanbanApiContext) => Promise<
|
|
260
|
+
onBeforeUpdateColumn?: (columnId: string, data: z.infer<typeof updateColumnSchema>, context: KanbanApiContext) => Promise<void> | void;
|
|
261
261
|
/**
|
|
262
|
-
* Called before deleting a column.
|
|
262
|
+
* Called before deleting a column. Throw an error to deny access.
|
|
263
263
|
*/
|
|
264
|
-
onBeforeDeleteColumn?: (columnId: string, context: KanbanApiContext) => Promise<
|
|
264
|
+
onBeforeDeleteColumn?: (columnId: string, context: KanbanApiContext) => Promise<void> | void;
|
|
265
265
|
/**
|
|
266
266
|
* Called after a column is created successfully
|
|
267
267
|
*/
|
|
@@ -275,17 +275,17 @@ interface KanbanBackendHooks {
|
|
|
275
275
|
*/
|
|
276
276
|
onColumnDeleted?: (columnId: string, context: KanbanApiContext) => Promise<void> | void;
|
|
277
277
|
/**
|
|
278
|
-
* Called before creating a task.
|
|
278
|
+
* Called before creating a task. Throw an error to deny access.
|
|
279
279
|
*/
|
|
280
|
-
onBeforeCreateTask?: (data: z.infer<typeof createTaskSchema>, context: KanbanApiContext) => Promise<
|
|
280
|
+
onBeforeCreateTask?: (data: z.infer<typeof createTaskSchema>, context: KanbanApiContext) => Promise<void> | void;
|
|
281
281
|
/**
|
|
282
|
-
* Called before updating a task.
|
|
282
|
+
* Called before updating a task. Throw an error to deny access.
|
|
283
283
|
*/
|
|
284
|
-
onBeforeUpdateTask?: (taskId: string, data: z.infer<typeof updateTaskSchema>, context: KanbanApiContext) => Promise<
|
|
284
|
+
onBeforeUpdateTask?: (taskId: string, data: z.infer<typeof updateTaskSchema>, context: KanbanApiContext) => Promise<void> | void;
|
|
285
285
|
/**
|
|
286
|
-
* Called before deleting a task.
|
|
286
|
+
* Called before deleting a task. Throw an error to deny access.
|
|
287
287
|
*/
|
|
288
|
-
onBeforeDeleteTask?: (taskId: string, context: KanbanApiContext) => Promise<
|
|
288
|
+
onBeforeDeleteTask?: (taskId: string, context: KanbanApiContext) => Promise<void> | void;
|
|
289
289
|
/**
|
|
290
290
|
* Called after a task is created successfully
|
|
291
291
|
*/
|
|
@@ -323,12 +323,12 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
323
323
|
method: "POST";
|
|
324
324
|
body: z.ZodObject<{
|
|
325
325
|
description: z.ZodOptional<z.ZodString>;
|
|
326
|
+
name: z.ZodString;
|
|
326
327
|
slug: z.ZodOptional<z.ZodString>;
|
|
327
328
|
ownerId: z.ZodOptional<z.ZodString>;
|
|
328
329
|
organizationId: z.ZodOptional<z.ZodString>;
|
|
329
330
|
createdAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
330
331
|
updatedAt: z.ZodOptional<z.ZodCoercedDate<unknown>>;
|
|
331
|
-
name: z.ZodString;
|
|
332
332
|
}, z.core.$strip>;
|
|
333
333
|
}, {
|
|
334
334
|
columns: ColumnWithTasks[];
|
|
@@ -345,12 +345,12 @@ declare const kanbanBackendPlugin: (hooks?: KanbanBackendHooks) => _btst_stack_p
|
|
|
345
345
|
method: "PUT";
|
|
346
346
|
body: z.ZodObject<{
|
|
347
347
|
description: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
348
|
+
name: z.ZodOptional<z.ZodString>;
|
|
348
349
|
slug: z.ZodOptional<z.ZodString>;
|
|
349
350
|
ownerId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
350
351
|
organizationId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
351
352
|
createdAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
352
353
|
updatedAt: z.ZodOptional<z.ZodOptional<z.ZodCoercedDate<unknown>>>;
|
|
353
|
-
name: z.ZodOptional<z.ZodString>;
|
|
354
354
|
}, z.core.$strip>;
|
|
355
355
|
}, Board>;
|
|
356
356
|
readonly deleteBoard: better_call.StrictEndpoint<"/boards/:id", {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _btst_stack_plugins_api from '@btst/stack/plugins/api';
|
|
2
|
-
import { a as SerializedContentItemWithType, S as SerializedContentType, b as ContentType, c as ContentItem, d as SerializedContentItem, e as ContentItemWithType, f as CMSBackendConfig, I as InverseRelation } from './stack.
|
|
2
|
+
import { a as SerializedContentItemWithType, S as SerializedContentType, b as ContentType, c as ContentItem, d as SerializedContentItem, e as ContentItemWithType, f as CMSBackendConfig, I as InverseRelation } from './stack.B8QD11QU.js';
|
|
3
3
|
import * as better_call from 'better-call';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { Adapter } from '@btst/db';
|
package/package.json
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST,
|
|
22
22
|
BUILT_IN_PAGE_TOOL_SCHEMAS,
|
|
23
23
|
} from "./page-tools";
|
|
24
|
+
import { runHookWithShim } from "../../utils";
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* Context passed to AI Chat API hooks
|
|
@@ -40,48 +41,46 @@ export interface ChatApiContext<TBody = any, TParams = any, TQuery = any> {
|
|
|
40
41
|
*/
|
|
41
42
|
export interface AiChatBackendHooks {
|
|
42
43
|
// ============== Authorization Hooks ==============
|
|
43
|
-
//
|
|
44
|
+
// Throw an error to deny access
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
|
-
* Called before processing a chat message.
|
|
47
|
+
* Called before processing a chat message. Throw an error to deny access.
|
|
47
48
|
* @param messages - Array of messages being sent
|
|
48
49
|
* @param context - Request context with headers, etc.
|
|
49
50
|
*/
|
|
50
51
|
onBeforeChat?: (
|
|
51
52
|
messages: Array<{ role: string; content: string }>,
|
|
52
53
|
context: ChatApiContext,
|
|
53
|
-
) => Promise<
|
|
54
|
+
) => Promise<void> | void;
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
|
-
* Called before listing conversations.
|
|
57
|
+
* Called before listing conversations. Throw an error to deny access.
|
|
57
58
|
* @param context - Request context with headers, etc.
|
|
58
59
|
*/
|
|
59
|
-
onBeforeListConversations?: (
|
|
60
|
-
context: ChatApiContext,
|
|
61
|
-
) => Promise<boolean> | boolean;
|
|
60
|
+
onBeforeListConversations?: (context: ChatApiContext) => Promise<void> | void;
|
|
62
61
|
|
|
63
62
|
/**
|
|
64
|
-
* Called before getting a single conversation.
|
|
63
|
+
* Called before getting a single conversation. Throw an error to deny access.
|
|
65
64
|
* @param conversationId - ID of the conversation being accessed
|
|
66
65
|
* @param context - Request context with headers, etc.
|
|
67
66
|
*/
|
|
68
67
|
onBeforeGetConversation?: (
|
|
69
68
|
conversationId: string,
|
|
70
69
|
context: ChatApiContext,
|
|
71
|
-
) => Promise<
|
|
70
|
+
) => Promise<void> | void;
|
|
72
71
|
|
|
73
72
|
/**
|
|
74
|
-
* Called before creating a conversation.
|
|
73
|
+
* Called before creating a conversation. Throw an error to deny access.
|
|
75
74
|
* @param data - Conversation data being created
|
|
76
75
|
* @param context - Request context with headers, etc.
|
|
77
76
|
*/
|
|
78
77
|
onBeforeCreateConversation?: (
|
|
79
78
|
data: { id?: string; title?: string },
|
|
80
79
|
context: ChatApiContext,
|
|
81
|
-
) => Promise<
|
|
80
|
+
) => Promise<void> | void;
|
|
82
81
|
|
|
83
82
|
/**
|
|
84
|
-
* Called before updating a conversation.
|
|
83
|
+
* Called before updating a conversation. Throw an error to deny access.
|
|
85
84
|
* @param conversationId - ID of the conversation being updated
|
|
86
85
|
* @param data - Updated conversation data
|
|
87
86
|
* @param context - Request context with headers, etc.
|
|
@@ -90,17 +89,17 @@ export interface AiChatBackendHooks {
|
|
|
90
89
|
conversationId: string,
|
|
91
90
|
data: { title?: string },
|
|
92
91
|
context: ChatApiContext,
|
|
93
|
-
) => Promise<
|
|
92
|
+
) => Promise<void> | void;
|
|
94
93
|
|
|
95
94
|
/**
|
|
96
|
-
* Called before deleting a conversation.
|
|
95
|
+
* Called before deleting a conversation. Throw an error to deny access.
|
|
97
96
|
* @param conversationId - ID of the conversation being deleted
|
|
98
97
|
* @param context - Request context with headers, etc.
|
|
99
98
|
*/
|
|
100
99
|
onBeforeDeleteConversation?: (
|
|
101
100
|
conversationId: string,
|
|
102
101
|
context: ChatApiContext,
|
|
103
|
-
) => Promise<
|
|
102
|
+
) => Promise<void> | void;
|
|
104
103
|
|
|
105
104
|
/**
|
|
106
105
|
* Called after the structural routeName/allowlist validation, with the list
|
|
@@ -452,15 +451,11 @@ export const aiChatBackendPlugin = <
|
|
|
452
451
|
role: msg.role,
|
|
453
452
|
content: getMessageTextContent(msg),
|
|
454
453
|
}));
|
|
455
|
-
|
|
456
|
-
messagesForHook,
|
|
457
|
-
|
|
454
|
+
await runHookWithShim(
|
|
455
|
+
() => config.hooks!.onBeforeChat!(messagesForHook, context),
|
|
456
|
+
ctx.error,
|
|
457
|
+
"Unauthorized: Cannot start chat",
|
|
458
458
|
);
|
|
459
|
-
if (!canChat) {
|
|
460
|
-
throw ctx.error(403, {
|
|
461
|
-
message: "Unauthorized: Cannot start chat",
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
459
|
}
|
|
465
460
|
|
|
466
461
|
const firstMessage = uiMessages[0];
|
|
@@ -848,15 +843,15 @@ export const aiChatBackendPlugin = <
|
|
|
848
843
|
|
|
849
844
|
// Authorization hook
|
|
850
845
|
if (config.hooks?.onBeforeCreateConversation) {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
846
|
+
await runHookWithShim(
|
|
847
|
+
() =>
|
|
848
|
+
config.hooks!.onBeforeCreateConversation!(
|
|
849
|
+
{ id, title },
|
|
850
|
+
context,
|
|
851
|
+
),
|
|
852
|
+
ctx.error,
|
|
853
|
+
"Unauthorized: Cannot create conversation",
|
|
854
854
|
);
|
|
855
|
-
if (!canCreate) {
|
|
856
|
-
throw ctx.error(403, {
|
|
857
|
-
message: "Unauthorized: Cannot create conversation",
|
|
858
|
-
});
|
|
859
|
-
}
|
|
860
855
|
}
|
|
861
856
|
|
|
862
857
|
const newConv = await adapter.create<Conversation>({
|
|
@@ -914,13 +909,11 @@ export const aiChatBackendPlugin = <
|
|
|
914
909
|
|
|
915
910
|
// Authorization hook
|
|
916
911
|
if (config.hooks?.onBeforeListConversations) {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
});
|
|
923
|
-
}
|
|
912
|
+
await runHookWithShim(
|
|
913
|
+
() => config.hooks!.onBeforeListConversations!(context),
|
|
914
|
+
ctx.error,
|
|
915
|
+
"Unauthorized: Cannot list conversations",
|
|
916
|
+
);
|
|
924
917
|
}
|
|
925
918
|
|
|
926
919
|
// Build where conditions - filter by userId if set
|
|
@@ -991,15 +984,11 @@ export const aiChatBackendPlugin = <
|
|
|
991
984
|
|
|
992
985
|
// Authorization hook
|
|
993
986
|
if (config.hooks?.onBeforeGetConversation) {
|
|
994
|
-
|
|
995
|
-
id,
|
|
996
|
-
|
|
987
|
+
await runHookWithShim(
|
|
988
|
+
() => config.hooks!.onBeforeGetConversation!(id, context),
|
|
989
|
+
ctx.error,
|
|
990
|
+
"Unauthorized: Cannot get conversation",
|
|
997
991
|
);
|
|
998
|
-
if (!canGet) {
|
|
999
|
-
throw ctx.error(403, {
|
|
1000
|
-
message: "Unauthorized: Cannot get conversation",
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
1003
992
|
}
|
|
1004
993
|
|
|
1005
994
|
// Fetch conversation with messages in a single query using join
|
|
@@ -1116,16 +1105,16 @@ export const aiChatBackendPlugin = <
|
|
|
1116
1105
|
|
|
1117
1106
|
// Authorization hook
|
|
1118
1107
|
if (config.hooks?.onBeforeUpdateConversation) {
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1108
|
+
await runHookWithShim(
|
|
1109
|
+
() =>
|
|
1110
|
+
config.hooks!.onBeforeUpdateConversation!(
|
|
1111
|
+
id,
|
|
1112
|
+
{ title },
|
|
1113
|
+
context,
|
|
1114
|
+
),
|
|
1115
|
+
ctx.error,
|
|
1116
|
+
"Unauthorized: Cannot update conversation",
|
|
1123
1117
|
);
|
|
1124
|
-
if (!canUpdate) {
|
|
1125
|
-
throw ctx.error(403, {
|
|
1126
|
-
message: "Unauthorized: Cannot update conversation",
|
|
1127
|
-
});
|
|
1128
|
-
}
|
|
1129
1118
|
}
|
|
1130
1119
|
|
|
1131
1120
|
const updated = await adapter.update<Conversation>({
|
|
@@ -1211,15 +1200,11 @@ export const aiChatBackendPlugin = <
|
|
|
1211
1200
|
|
|
1212
1201
|
// Authorization hook
|
|
1213
1202
|
if (config.hooks?.onBeforeDeleteConversation) {
|
|
1214
|
-
|
|
1215
|
-
id,
|
|
1216
|
-
|
|
1203
|
+
await runHookWithShim(
|
|
1204
|
+
() => config.hooks!.onBeforeDeleteConversation!(id, context),
|
|
1205
|
+
ctx.error,
|
|
1206
|
+
"Unauthorized: Cannot delete conversation",
|
|
1217
1207
|
);
|
|
1218
|
-
if (!canDelete) {
|
|
1219
|
-
throw ctx.error(403, {
|
|
1220
|
-
message: "Unauthorized: Cannot delete conversation",
|
|
1221
|
-
});
|
|
1222
|
-
}
|
|
1223
1208
|
}
|
|
1224
1209
|
|
|
1225
1210
|
// Messages are automatically deleted via cascade (onDelete: "cascade")
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defineClientPlugin,
|
|
3
3
|
createApiClient,
|
|
4
|
+
runClientHookWithShim,
|
|
4
5
|
} from "@btst/stack/plugins/client";
|
|
5
6
|
import { createRoute } from "@btst/yar";
|
|
6
7
|
import type { QueryClient } from "@tanstack/react-query";
|
|
@@ -92,35 +93,33 @@ export interface AiChatClientConfig {
|
|
|
92
93
|
*/
|
|
93
94
|
export interface AiChatClientHooks {
|
|
94
95
|
/**
|
|
95
|
-
* Called before loading conversations list.
|
|
96
|
+
* Called before loading conversations list. Throw an error to cancel loading.
|
|
96
97
|
* @param context - Loader context with path, params, etc.
|
|
97
98
|
*/
|
|
98
|
-
beforeLoadConversations?: (
|
|
99
|
-
context: LoaderContext,
|
|
100
|
-
) => Promise<boolean> | boolean;
|
|
99
|
+
beforeLoadConversations?: (context: LoaderContext) => Promise<void> | void;
|
|
101
100
|
|
|
102
101
|
/**
|
|
103
|
-
* Called after conversations are loaded.
|
|
102
|
+
* Called after conversations are loaded. Throw an error to cancel further processing.
|
|
104
103
|
* @param conversations - Array of loaded conversations or null
|
|
105
104
|
* @param context - Loader context
|
|
106
105
|
*/
|
|
107
106
|
afterLoadConversations?: (
|
|
108
107
|
conversations: SerializedConversation[] | null,
|
|
109
108
|
context: LoaderContext,
|
|
110
|
-
) => Promise<
|
|
109
|
+
) => Promise<void> | void;
|
|
111
110
|
|
|
112
111
|
/**
|
|
113
|
-
* Called before loading a single conversation.
|
|
112
|
+
* Called before loading a single conversation. Throw an error to cancel loading.
|
|
114
113
|
* @param id - Conversation ID being loaded
|
|
115
114
|
* @param context - Loader context
|
|
116
115
|
*/
|
|
117
116
|
beforeLoadConversation?: (
|
|
118
117
|
id: string,
|
|
119
118
|
context: LoaderContext,
|
|
120
|
-
) => Promise<
|
|
119
|
+
) => Promise<void> | void;
|
|
121
120
|
|
|
122
121
|
/**
|
|
123
|
-
* Called after a conversation is loaded.
|
|
122
|
+
* Called after a conversation is loaded. Throw an error to cancel further processing.
|
|
124
123
|
* @param conversation - Loaded conversation or null if not found
|
|
125
124
|
* @param id - Conversation ID that was requested
|
|
126
125
|
* @param context - Loader context
|
|
@@ -131,7 +130,7 @@ export interface AiChatClientHooks {
|
|
|
131
130
|
| null,
|
|
132
131
|
id: string,
|
|
133
132
|
context: LoaderContext,
|
|
134
|
-
) => Promise<
|
|
133
|
+
) => Promise<void> | void;
|
|
135
134
|
|
|
136
135
|
/**
|
|
137
136
|
* Called when a loading error occurs
|
|
@@ -163,10 +162,10 @@ function createConversationsLoader(config: AiChatClientConfig) {
|
|
|
163
162
|
try {
|
|
164
163
|
// Before hook
|
|
165
164
|
if (hooks?.beforeLoadConversations) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
await runClientHookWithShim(
|
|
166
|
+
() => hooks.beforeLoadConversations!(context),
|
|
167
|
+
"Load prevented by beforeLoadConversations hook",
|
|
168
|
+
);
|
|
170
169
|
}
|
|
171
170
|
|
|
172
171
|
const client = createApiClient<AiChatApiRouter>({
|
|
@@ -185,13 +184,10 @@ function createConversationsLoader(config: AiChatClientConfig) {
|
|
|
185
184
|
queryClient.getQueryData<SerializedConversation[]>(
|
|
186
185
|
listQuery.queryKey,
|
|
187
186
|
) || null;
|
|
188
|
-
|
|
189
|
-
conversations,
|
|
190
|
-
|
|
187
|
+
await runClientHookWithShim(
|
|
188
|
+
() => hooks.afterLoadConversations!(conversations, context),
|
|
189
|
+
"Load prevented by afterLoadConversations hook",
|
|
191
190
|
);
|
|
192
|
-
if (canContinue === false) {
|
|
193
|
-
throw new Error("Load prevented by afterLoadConversations hook");
|
|
194
|
-
}
|
|
195
191
|
}
|
|
196
192
|
|
|
197
193
|
// Check for errors
|
|
@@ -230,10 +226,10 @@ function createConversationLoader(id: string, config: AiChatClientConfig) {
|
|
|
230
226
|
try {
|
|
231
227
|
// Before hook
|
|
232
228
|
if (hooks?.beforeLoadConversation) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
229
|
+
await runClientHookWithShim(
|
|
230
|
+
() => hooks.beforeLoadConversation!(id, context),
|
|
231
|
+
"Load prevented by beforeLoadConversation hook",
|
|
232
|
+
);
|
|
237
233
|
}
|
|
238
234
|
|
|
239
235
|
const client = createApiClient<AiChatApiRouter>({
|
|
@@ -258,14 +254,10 @@ function createConversationLoader(id: string, config: AiChatClientConfig) {
|
|
|
258
254
|
queryClient.getQueryData<
|
|
259
255
|
SerializedConversation & { messages: SerializedMessage[] }
|
|
260
256
|
>(conversationQuery.queryKey) || null;
|
|
261
|
-
|
|
262
|
-
conversation,
|
|
263
|
-
|
|
264
|
-
context,
|
|
257
|
+
await runClientHookWithShim(
|
|
258
|
+
() => hooks.afterLoadConversation!(conversation, id, context),
|
|
259
|
+
"Load prevented by afterLoadConversation hook",
|
|
265
260
|
);
|
|
266
|
-
if (canContinue === false) {
|
|
267
|
-
throw new Error("Load prevented by afterLoadConversation hook");
|
|
268
|
-
}
|
|
269
261
|
}
|
|
270
262
|
|
|
271
263
|
// Check for errors
|
|
@@ -10,6 +10,7 @@ import { getAllPosts, getPostBySlug, getAllTags } from "./getters";
|
|
|
10
10
|
import { BLOG_QUERY_KEYS } from "./query-key-defs";
|
|
11
11
|
import { serializePost, serializeTag } from "./serializers";
|
|
12
12
|
import type { QueryClient } from "@tanstack/react-query";
|
|
13
|
+
import { runHookWithShim } from "../../utils";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Route keys for the blog plugin — matches the keys returned by
|
|
@@ -131,25 +132,25 @@ export interface BlogApiContext<TBody = any, TParams = any, TQuery = any> {
|
|
|
131
132
|
*/
|
|
132
133
|
export interface BlogBackendHooks {
|
|
133
134
|
/**
|
|
134
|
-
* Called before listing posts.
|
|
135
|
+
* Called before listing posts. Throw an error to deny access.
|
|
135
136
|
* @param filter - Query parameters for filtering posts
|
|
136
137
|
* @param context - Request context with headers, etc.
|
|
137
138
|
*/
|
|
138
139
|
onBeforeListPosts?: (
|
|
139
140
|
filter: z.infer<typeof PostListQuerySchema>,
|
|
140
141
|
context: BlogApiContext,
|
|
141
|
-
) => Promise<
|
|
142
|
+
) => Promise<void> | void;
|
|
142
143
|
/**
|
|
143
|
-
* Called before creating a post.
|
|
144
|
+
* Called before creating a post. Throw an error to deny access.
|
|
144
145
|
* @param data - Post data being created
|
|
145
146
|
* @param context - Request context with headers, etc.
|
|
146
147
|
*/
|
|
147
148
|
onBeforeCreatePost?: (
|
|
148
149
|
data: z.infer<typeof createPostSchema>,
|
|
149
150
|
context: BlogApiContext,
|
|
150
|
-
) => Promise<
|
|
151
|
+
) => Promise<void> | void;
|
|
151
152
|
/**
|
|
152
|
-
* Called before updating a post.
|
|
153
|
+
* Called before updating a post. Throw an error to deny access.
|
|
153
154
|
* @param postId - ID of the post being updated
|
|
154
155
|
* @param data - Updated post data
|
|
155
156
|
* @param context - Request context with headers, etc.
|
|
@@ -158,16 +159,16 @@ export interface BlogBackendHooks {
|
|
|
158
159
|
postId: string,
|
|
159
160
|
data: z.infer<typeof updatePostSchema>,
|
|
160
161
|
context: BlogApiContext,
|
|
161
|
-
) => Promise<
|
|
162
|
+
) => Promise<void> | void;
|
|
162
163
|
/**
|
|
163
|
-
* Called before deleting a post.
|
|
164
|
+
* Called before deleting a post. Throw an error to deny access.
|
|
164
165
|
* @param postId - ID of the post being deleted
|
|
165
166
|
* @param context - Request context with headers, etc.
|
|
166
167
|
*/
|
|
167
168
|
onBeforeDeletePost?: (
|
|
168
169
|
postId: string,
|
|
169
170
|
context: BlogApiContext,
|
|
170
|
-
) => Promise<
|
|
171
|
+
) => Promise<void> | void;
|
|
171
172
|
|
|
172
173
|
/**
|
|
173
174
|
* Called after posts are read successfully
|
|
@@ -350,12 +351,11 @@ export const blogBackendPlugin = (hooks?: BlogBackendHooks) =>
|
|
|
350
351
|
|
|
351
352
|
try {
|
|
352
353
|
if (hooks?.onBeforeListPosts) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
354
|
+
await runHookWithShim(
|
|
355
|
+
() => hooks.onBeforeListPosts!(query, context),
|
|
356
|
+
ctx.error,
|
|
357
|
+
"Unauthorized: Cannot list posts",
|
|
358
|
+
);
|
|
359
359
|
}
|
|
360
360
|
|
|
361
361
|
const result = await getAllPosts(adapter, query);
|
|
@@ -387,15 +387,11 @@ export const blogBackendPlugin = (hooks?: BlogBackendHooks) =>
|
|
|
387
387
|
|
|
388
388
|
try {
|
|
389
389
|
if (hooks?.onBeforeCreatePost) {
|
|
390
|
-
|
|
391
|
-
ctx.body,
|
|
392
|
-
|
|
390
|
+
await runHookWithShim(
|
|
391
|
+
() => hooks.onBeforeCreatePost!(ctx.body, context),
|
|
392
|
+
ctx.error,
|
|
393
|
+
"Unauthorized: Cannot create post",
|
|
393
394
|
);
|
|
394
|
-
if (!canCreate) {
|
|
395
|
-
throw ctx.error(403, {
|
|
396
|
-
message: "Unauthorized: Cannot create post",
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
395
|
}
|
|
400
396
|
|
|
401
397
|
const { tags, ...postData } = ctx.body;
|
|
@@ -471,16 +467,12 @@ export const blogBackendPlugin = (hooks?: BlogBackendHooks) =>
|
|
|
471
467
|
|
|
472
468
|
try {
|
|
473
469
|
if (hooks?.onBeforeUpdatePost) {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
470
|
+
await runHookWithShim(
|
|
471
|
+
() =>
|
|
472
|
+
hooks.onBeforeUpdatePost!(ctx.params.id, ctx.body, context),
|
|
473
|
+
ctx.error,
|
|
474
|
+
"Unauthorized: Cannot update post",
|
|
478
475
|
);
|
|
479
|
-
if (!canUpdate) {
|
|
480
|
-
throw ctx.error(403, {
|
|
481
|
-
message: "Unauthorized: Cannot update post",
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
476
|
}
|
|
485
477
|
|
|
486
478
|
const { tags, slug: rawSlug, ...restPostData } = ctx.body;
|
|
@@ -598,15 +590,11 @@ export const blogBackendPlugin = (hooks?: BlogBackendHooks) =>
|
|
|
598
590
|
try {
|
|
599
591
|
// Authorization hook
|
|
600
592
|
if (hooks?.onBeforeDeletePost) {
|
|
601
|
-
|
|
602
|
-
ctx.params.id,
|
|
603
|
-
|
|
593
|
+
await runHookWithShim(
|
|
594
|
+
() => hooks.onBeforeDeletePost!(ctx.params.id, context),
|
|
595
|
+
ctx.error,
|
|
596
|
+
"Unauthorized: Cannot delete post",
|
|
604
597
|
);
|
|
605
|
-
if (!canDelete) {
|
|
606
|
-
throw ctx.error(403, {
|
|
607
|
-
message: "Unauthorized: Cannot delete post",
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
598
|
}
|
|
611
599
|
|
|
612
600
|
await adapter.delete<Post>({
|
|
@@ -642,15 +630,11 @@ export const blogBackendPlugin = (hooks?: BlogBackendHooks) =>
|
|
|
642
630
|
|
|
643
631
|
try {
|
|
644
632
|
if (hooks?.onBeforeListPosts) {
|
|
645
|
-
|
|
646
|
-
{ published: true },
|
|
647
|
-
|
|
633
|
+
await runHookWithShim(
|
|
634
|
+
() => hooks.onBeforeListPosts!({ published: true }, context),
|
|
635
|
+
ctx.error,
|
|
636
|
+
"Unauthorized: Cannot list posts",
|
|
648
637
|
);
|
|
649
|
-
if (!canList) {
|
|
650
|
-
throw ctx.error(403, {
|
|
651
|
-
message: "Unauthorized: Cannot list posts",
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
638
|
}
|
|
655
639
|
|
|
656
640
|
const date = query.date;
|