@decocms/bindings 1.4.8 → 1.4.10
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/package.json +1 -10
- package/src/index.ts +0 -45
- package/src/core/plugin-context-provider.tsx +0 -27
- package/src/core/plugin-context.ts +0 -183
- package/src/core/plugin-router.tsx +0 -236
- package/src/core/plugins.ts +0 -132
- package/src/core/server-plugin.ts +0 -227
- package/src/well-known/event-bus.ts +0 -454
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/bindings",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"check": "tsc --noEmit",
|
|
@@ -9,15 +9,9 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@decocms/mcp-utils": "^1.0.5",
|
|
11
11
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
12
|
-
"@tanstack/react-router": "1.169.2",
|
|
13
|
-
"react": "^19.2.6",
|
|
14
12
|
"zod": "^4.0.0",
|
|
15
13
|
"zod-from-json-schema": "^0.5.2"
|
|
16
14
|
},
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"hono": "^4.7.10",
|
|
19
|
-
"kysely": "^0.28.12"
|
|
20
|
-
},
|
|
21
15
|
"exports": {
|
|
22
16
|
".": "./src/index.ts",
|
|
23
17
|
"./collections": "./src/well-known/collections.ts",
|
|
@@ -28,10 +22,7 @@
|
|
|
28
22
|
"./mcp": "./src/well-known/mcp.ts",
|
|
29
23
|
"./assistant": "./src/well-known/assistant.ts",
|
|
30
24
|
"./prompt": "./src/well-known/prompt.ts",
|
|
31
|
-
"./plugins": "./src/core/plugins.ts",
|
|
32
|
-
"./plugin-router": "./src/core/plugin-router.tsx",
|
|
33
25
|
"./ai-gateway": "./src/well-known/ai-gateway.ts",
|
|
34
|
-
"./server-plugin": "./src/core/server-plugin.ts",
|
|
35
26
|
"./trigger": "./src/well-known/trigger.ts",
|
|
36
27
|
"./brand": "./src/well-known/brand.ts"
|
|
37
28
|
},
|
package/src/index.ts
CHANGED
|
@@ -17,16 +17,6 @@ export {
|
|
|
17
17
|
type ConnectionForBinding,
|
|
18
18
|
} from "./core/binder";
|
|
19
19
|
|
|
20
|
-
// Re-export plugin context types (not the React provider - use @decocms/bindings/plugins for that)
|
|
21
|
-
export {
|
|
22
|
-
type PluginContext,
|
|
23
|
-
type PluginContextPartial,
|
|
24
|
-
type PluginConnectionEntity,
|
|
25
|
-
type PluginOrgContext,
|
|
26
|
-
type PluginSession,
|
|
27
|
-
type TypedToolCaller,
|
|
28
|
-
} from "./core/plugin-context";
|
|
29
|
-
|
|
30
20
|
// Re-export registry binding types
|
|
31
21
|
export {
|
|
32
22
|
MCPRegistryServerSchema,
|
|
@@ -49,41 +39,6 @@ export {
|
|
|
49
39
|
type EventSubscriberBindingClient,
|
|
50
40
|
} from "./well-known/event-subscriber";
|
|
51
41
|
|
|
52
|
-
// Re-export event bus binding types (for interacting with an event bus)
|
|
53
|
-
export {
|
|
54
|
-
EventPublishInputSchema,
|
|
55
|
-
type EventPublishInput,
|
|
56
|
-
EventPublishOutputSchema,
|
|
57
|
-
type EventPublishOutput,
|
|
58
|
-
EventSubscribeInputSchema,
|
|
59
|
-
type EventSubscribeInput,
|
|
60
|
-
EventSubscribeOutputSchema,
|
|
61
|
-
type EventSubscribeOutput,
|
|
62
|
-
EventUnsubscribeInputSchema,
|
|
63
|
-
type EventUnsubscribeInput,
|
|
64
|
-
EventUnsubscribeOutputSchema,
|
|
65
|
-
type EventUnsubscribeOutput,
|
|
66
|
-
EventCancelInputSchema,
|
|
67
|
-
type EventCancelInput,
|
|
68
|
-
EventCancelOutputSchema,
|
|
69
|
-
type EventCancelOutput,
|
|
70
|
-
EventAckInputSchema,
|
|
71
|
-
type EventAckInput,
|
|
72
|
-
EventAckOutputSchema,
|
|
73
|
-
type EventAckOutput,
|
|
74
|
-
SubscriptionItemSchema,
|
|
75
|
-
type SubscriptionItem,
|
|
76
|
-
SubscriptionDetailSchema,
|
|
77
|
-
type SubscriptionDetail,
|
|
78
|
-
EventSyncSubscriptionsInputSchema,
|
|
79
|
-
type EventSyncSubscriptionsInput,
|
|
80
|
-
EventSyncSubscriptionsOutputSchema,
|
|
81
|
-
type EventSyncSubscriptionsOutput,
|
|
82
|
-
EVENT_BUS_BINDING,
|
|
83
|
-
EventBusBinding,
|
|
84
|
-
type EventBusBindingClient,
|
|
85
|
-
} from "./well-known/event-bus";
|
|
86
|
-
|
|
87
42
|
// Re-export trigger binding types (for connections that can emit triggers)
|
|
88
43
|
export {
|
|
89
44
|
TriggerParamSchema,
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin Context Provider Types
|
|
3
|
-
*
|
|
4
|
-
* The runtime implementations (PluginContextProvider, usePluginContext)
|
|
5
|
-
* have moved to @decocms/mesh-sdk/plugins. Only types remain here
|
|
6
|
-
* for backwards compatibility.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { Binder } from "./binder";
|
|
10
|
-
import type { PluginContext, PluginContextPartial } from "./plugin-context";
|
|
11
|
-
import type { ReactNode } from "react";
|
|
12
|
-
|
|
13
|
-
export interface PluginContextProviderProps<TBinding extends Binder> {
|
|
14
|
-
value: PluginContext<TBinding> | PluginContextPartial<TBinding>;
|
|
15
|
-
children: ReactNode;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Options for usePluginContext hook.
|
|
20
|
-
*/
|
|
21
|
-
export interface UsePluginContextOptions {
|
|
22
|
-
/**
|
|
23
|
-
* Set to true when calling from an empty state component.
|
|
24
|
-
* This returns nullable connection fields since no valid connection exists.
|
|
25
|
-
*/
|
|
26
|
-
partial?: boolean;
|
|
27
|
-
}
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plugin Context Types
|
|
3
|
-
*
|
|
4
|
-
* Provides typed context for plugins to access their selected connection
|
|
5
|
-
* and call tools with full type safety based on the plugin's binding.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { Binder, ToolBinder } from "./binder";
|
|
9
|
-
import type { z } from "zod";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Connection entity shape provided by the layout.
|
|
13
|
-
*/
|
|
14
|
-
export interface PluginConnectionEntity {
|
|
15
|
-
id: string;
|
|
16
|
-
title: string;
|
|
17
|
-
icon: string | null;
|
|
18
|
-
description: string | null;
|
|
19
|
-
app_name: string | null;
|
|
20
|
-
app_id: string | null;
|
|
21
|
-
tools: Array<{
|
|
22
|
-
name: string;
|
|
23
|
-
description?: string;
|
|
24
|
-
inputSchema?: Record<string, unknown>;
|
|
25
|
-
outputSchema?: Record<string, unknown>;
|
|
26
|
-
}> | null;
|
|
27
|
-
metadata: Record<string, unknown> | null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Organization context.
|
|
32
|
-
*/
|
|
33
|
-
export interface PluginOrgContext {
|
|
34
|
-
id: string;
|
|
35
|
-
slug: string;
|
|
36
|
-
name: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* User session provided to plugins.
|
|
41
|
-
*/
|
|
42
|
-
export interface PluginSession {
|
|
43
|
-
user: {
|
|
44
|
-
id: string;
|
|
45
|
-
name: string;
|
|
46
|
-
email: string;
|
|
47
|
-
image?: string | null;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Helper type to extract tool by name from a binding.
|
|
53
|
-
*/
|
|
54
|
-
type ExtractToolByName<TBinding extends Binder, TName extends string> = Extract<
|
|
55
|
-
TBinding[number],
|
|
56
|
-
{ name: TName }
|
|
57
|
-
>;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Typed tool caller for a specific binding.
|
|
61
|
-
* Provides type-safe tool calls based on the binding definition.
|
|
62
|
-
*
|
|
63
|
-
* @template TBinding - The binding type to derive tool types from
|
|
64
|
-
*/
|
|
65
|
-
export type TypedToolCaller<TBinding extends Binder> = <
|
|
66
|
-
TName extends TBinding[number]["name"] & string,
|
|
67
|
-
>(
|
|
68
|
-
toolName: TName,
|
|
69
|
-
args: ExtractToolByName<TBinding, TName> extends ToolBinder<
|
|
70
|
-
TName,
|
|
71
|
-
infer TInput,
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
73
|
-
infer _TOutput
|
|
74
|
-
>
|
|
75
|
-
? TInput extends z.ZodType
|
|
76
|
-
? z.infer<TInput>
|
|
77
|
-
: TInput
|
|
78
|
-
: unknown,
|
|
79
|
-
) => Promise<
|
|
80
|
-
ExtractToolByName<TBinding, TName> extends ToolBinder<
|
|
81
|
-
TName,
|
|
82
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
83
|
-
infer _TInput,
|
|
84
|
-
infer TOutput
|
|
85
|
-
>
|
|
86
|
-
? TOutput extends z.ZodType
|
|
87
|
-
? z.infer<TOutput>
|
|
88
|
-
: TOutput
|
|
89
|
-
: unknown
|
|
90
|
-
>;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Base plugin context with connection fields always available.
|
|
94
|
-
* Used by plugin routes where layout guarantees a valid connection.
|
|
95
|
-
*
|
|
96
|
-
* @template TBinding - The binding type the plugin requires
|
|
97
|
-
*
|
|
98
|
-
* @example
|
|
99
|
-
* ```tsx
|
|
100
|
-
* // In plugin route component (connection guaranteed)
|
|
101
|
-
* const { toolCaller, connection } = usePluginContext<typeof REGISTRY_APP_BINDING>();
|
|
102
|
-
*
|
|
103
|
-
* // toolCaller and connection are non-null
|
|
104
|
-
* const result = await toolCaller("COLLECTION_REGISTRY_APP_LIST", { limit: 20 });
|
|
105
|
-
* ```
|
|
106
|
-
*/
|
|
107
|
-
export interface PluginContext<TBinding extends Binder = Binder> {
|
|
108
|
-
/**
|
|
109
|
-
* The selected connection ID.
|
|
110
|
-
* Always defined in routes (layout handles empty state separately).
|
|
111
|
-
*/
|
|
112
|
-
connectionId: string;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* The selected connection entity.
|
|
116
|
-
* Always defined in routes.
|
|
117
|
-
*/
|
|
118
|
-
connection: PluginConnectionEntity;
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Typed tool caller for the selected connection.
|
|
122
|
-
* Call MCP tools with full type safety based on the plugin's binding.
|
|
123
|
-
*/
|
|
124
|
-
toolCaller: TypedToolCaller<TBinding>;
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Organization context.
|
|
128
|
-
* Always available.
|
|
129
|
-
*/
|
|
130
|
-
org: PluginOrgContext;
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Current user session.
|
|
134
|
-
* Available when user is authenticated.
|
|
135
|
-
*/
|
|
136
|
-
session: PluginSession | null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Partial plugin context with nullable connection fields.
|
|
141
|
-
* Used by empty state components where no valid connection exists.
|
|
142
|
-
*
|
|
143
|
-
* @template TBinding - The binding type the plugin requires
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* ```tsx
|
|
147
|
-
* // In empty state component (no connection)
|
|
148
|
-
* const { session, org } = usePluginContext<typeof REGISTRY_APP_BINDING>({ partial: true });
|
|
149
|
-
*
|
|
150
|
-
* // connection, connectionId, toolCaller are null
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
export interface PluginContextPartial<TBinding extends Binder = Binder> {
|
|
154
|
-
/**
|
|
155
|
-
* The selected connection ID.
|
|
156
|
-
* Null when no valid connection is available.
|
|
157
|
-
*/
|
|
158
|
-
connectionId: string | null;
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* The selected connection entity.
|
|
162
|
-
* Null when no valid connection is available.
|
|
163
|
-
*/
|
|
164
|
-
connection: PluginConnectionEntity | null;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Typed tool caller for the selected connection.
|
|
168
|
-
* Null when no valid connection is available.
|
|
169
|
-
*/
|
|
170
|
-
toolCaller: TypedToolCaller<TBinding> | null;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Organization context.
|
|
174
|
-
* Always available.
|
|
175
|
-
*/
|
|
176
|
-
org: PluginOrgContext;
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Current user session.
|
|
180
|
-
* Available when user is authenticated.
|
|
181
|
-
*/
|
|
182
|
-
session: PluginSession | null;
|
|
183
|
-
}
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import {
|
|
3
|
-
createRoute,
|
|
4
|
-
lazyRouteComponent,
|
|
5
|
-
Route,
|
|
6
|
-
useNavigate,
|
|
7
|
-
useParams,
|
|
8
|
-
useSearch,
|
|
9
|
-
useLocation,
|
|
10
|
-
Link as TanStackLink,
|
|
11
|
-
type AnyRoute,
|
|
12
|
-
type RouteIds,
|
|
13
|
-
type RouteById,
|
|
14
|
-
type LinkProps,
|
|
15
|
-
type NavigateOptions,
|
|
16
|
-
} from "@tanstack/react-router";
|
|
17
|
-
import type { PluginSetupContext } from "./plugins";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Prepends the plugin base path (/$org/projects/$virtualMcpId/$pluginId) to a route path.
|
|
21
|
-
* Handles both absolute plugin paths (starting with /) and relative paths.
|
|
22
|
-
*/
|
|
23
|
-
function prependBasePath(
|
|
24
|
-
to: string | undefined,
|
|
25
|
-
org: string,
|
|
26
|
-
virtualMcpId: string,
|
|
27
|
-
pluginId: string,
|
|
28
|
-
): string {
|
|
29
|
-
if (!to) return `/${org}/projects/${virtualMcpId}/${pluginId}`;
|
|
30
|
-
|
|
31
|
-
// If path starts with /, it's relative to the plugin root
|
|
32
|
-
if (to.startsWith("/")) {
|
|
33
|
-
return `/${org}/projects/${virtualMcpId}/${pluginId}${to}`;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Otherwise, it's already a full path or relative
|
|
37
|
-
return to;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Creates a typed plugin router from a route factory function.
|
|
42
|
-
*
|
|
43
|
-
* Routes are registered directly under ctx.parentRoute (which already has
|
|
44
|
-
* component: Outlet). Return an array of sibling routes for multiple pages.
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* ```tsx
|
|
48
|
-
* export const storeRouter = createPluginRouter((ctx) => {
|
|
49
|
-
* const indexRoute = ctx.routing.createRoute({
|
|
50
|
-
* getParentRoute: () => ctx.parentRoute,
|
|
51
|
-
* path: "/",
|
|
52
|
-
* component: ctx.routing.lazyRouteComponent(() => import("./routes/page.tsx")),
|
|
53
|
-
* });
|
|
54
|
-
*
|
|
55
|
-
* const detailRoute = ctx.routing.createRoute({
|
|
56
|
-
* getParentRoute: () => ctx.parentRoute,
|
|
57
|
-
* path: "/$appName",
|
|
58
|
-
* component: ctx.routing.lazyRouteComponent(() => import("./routes/detail.tsx")),
|
|
59
|
-
* validateSearch: z.object({ tab: z.string().optional() }),
|
|
60
|
-
* });
|
|
61
|
-
*
|
|
62
|
-
* return [indexRoute, detailRoute];
|
|
63
|
-
* });
|
|
64
|
-
*
|
|
65
|
-
* // In plugin setup - register each route
|
|
66
|
-
* export const storePlugin: AnyPlugin = {
|
|
67
|
-
* id: "store",
|
|
68
|
-
* setup: (ctx) => {
|
|
69
|
-
* const routes = storeRouter.createRoutes(ctx);
|
|
70
|
-
* for (const route of routes) {
|
|
71
|
-
* ctx.registerRootPluginRoute(route);
|
|
72
|
-
* }
|
|
73
|
-
* },
|
|
74
|
-
* };
|
|
75
|
-
*
|
|
76
|
-
* // In components
|
|
77
|
-
* function DetailPage() {
|
|
78
|
-
* const { appName } = storeRouter.useParams({ from: "/$appName" });
|
|
79
|
-
* const { tab } = storeRouter.useSearch({ from: "/$appName" });
|
|
80
|
-
*
|
|
81
|
-
* const navigate = storeRouter.useNavigate();
|
|
82
|
-
* navigate({ to: "/$appName", params: { appName: "other" } });
|
|
83
|
-
* }
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
export function createPluginRouter<TRoutes extends AnyRoute | AnyRoute[]>(
|
|
87
|
-
createRoutes: (ctx: PluginSetupContext) => TRoutes,
|
|
88
|
-
) {
|
|
89
|
-
// Extract route type from array or single route
|
|
90
|
-
type TRoute = TRoutes extends (infer R)[] ? R : TRoutes;
|
|
91
|
-
type TRouteId = TRoute extends AnyRoute ? RouteIds<TRoute> : never;
|
|
92
|
-
type TRouteById<TId extends TRouteId> = TRoute extends AnyRoute
|
|
93
|
-
? RouteById<TRoute, TId>
|
|
94
|
-
: never;
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
/**
|
|
98
|
-
* Create the route tree. Call this in your plugin's setup().
|
|
99
|
-
*/
|
|
100
|
-
createRoutes,
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get route params with TanStack's type inference.
|
|
104
|
-
*/
|
|
105
|
-
useParams: <TFrom extends TRouteId>(_options: { from: TFrom }) => {
|
|
106
|
-
return useParams({
|
|
107
|
-
strict: false,
|
|
108
|
-
}) as TRouteById<TFrom>["types"]["allParams"];
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Get search params with TanStack's type inference.
|
|
113
|
-
*/
|
|
114
|
-
useSearch: <TFrom extends TRouteId>(_options: { from: TFrom }) => {
|
|
115
|
-
return useSearch({
|
|
116
|
-
strict: false,
|
|
117
|
-
}) as TRouteById<TFrom>["types"]["fullSearchSchema"];
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Navigate within the plugin.
|
|
122
|
-
* Automatically prepends /$org/$pluginId to the path.
|
|
123
|
-
*/
|
|
124
|
-
useNavigate: () => {
|
|
125
|
-
const navigate = useNavigate();
|
|
126
|
-
const { org, virtualMcpId, pluginId } = useParams({ strict: false }) as {
|
|
127
|
-
org: string;
|
|
128
|
-
virtualMcpId: string;
|
|
129
|
-
pluginId: string;
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
return <TTo extends TRouteId>(
|
|
133
|
-
options: Omit<NavigateOptions, "to" | "params"> & {
|
|
134
|
-
to: TTo;
|
|
135
|
-
params?: TRouteById<TTo>["types"]["allParams"];
|
|
136
|
-
search?: TRouteById<TTo>["types"]["fullSearchSchema"];
|
|
137
|
-
},
|
|
138
|
-
) => {
|
|
139
|
-
const to = prependBasePath(options.to, org, virtualMcpId, pluginId);
|
|
140
|
-
|
|
141
|
-
return navigate({
|
|
142
|
-
...options,
|
|
143
|
-
to,
|
|
144
|
-
params: {
|
|
145
|
-
org,
|
|
146
|
-
virtualMcpId,
|
|
147
|
-
pluginId,
|
|
148
|
-
...(options.params as Record<string, string>),
|
|
149
|
-
},
|
|
150
|
-
} as NavigateOptions);
|
|
151
|
-
};
|
|
152
|
-
},
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Get the current location.
|
|
156
|
-
*/
|
|
157
|
-
useLocation: () => {
|
|
158
|
-
return useLocation();
|
|
159
|
-
},
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Link component for plugin navigation.
|
|
163
|
-
* Automatically prepends /$org/$pluginId to the path.
|
|
164
|
-
*/
|
|
165
|
-
Link: function PluginLink<TTo extends TRouteId>(
|
|
166
|
-
props: Omit<LinkProps, "to" | "params" | "search"> & {
|
|
167
|
-
to: TTo;
|
|
168
|
-
params?: TRouteById<TTo>["types"]["allParams"];
|
|
169
|
-
search?: TRouteById<TTo>["types"]["fullSearchSchema"];
|
|
170
|
-
className?: string;
|
|
171
|
-
children?: ReactNode;
|
|
172
|
-
},
|
|
173
|
-
) {
|
|
174
|
-
const { org, virtualMcpId, pluginId } = useParams({ strict: false }) as {
|
|
175
|
-
org: string;
|
|
176
|
-
virtualMcpId: string;
|
|
177
|
-
pluginId: string;
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const to = prependBasePath(
|
|
181
|
-
props.to as string,
|
|
182
|
-
org,
|
|
183
|
-
virtualMcpId,
|
|
184
|
-
pluginId,
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
return (
|
|
188
|
-
<TanStackLink
|
|
189
|
-
{...(props as LinkProps)}
|
|
190
|
-
to={to}
|
|
191
|
-
params={{
|
|
192
|
-
org,
|
|
193
|
-
virtualMcpId,
|
|
194
|
-
pluginId,
|
|
195
|
-
...props.params,
|
|
196
|
-
}}
|
|
197
|
-
/>
|
|
198
|
-
);
|
|
199
|
-
},
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Type helpers
|
|
203
|
-
*/
|
|
204
|
-
_types: {
|
|
205
|
-
routes: undefined as unknown as TRoutes,
|
|
206
|
-
routeIds: undefined as unknown as TRouteId,
|
|
207
|
-
},
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Type helper to extract route IDs from a plugin router
|
|
213
|
-
*/
|
|
214
|
-
export type PluginRouteIds<
|
|
215
|
-
TRouter extends ReturnType<typeof createPluginRouter>,
|
|
216
|
-
> = TRouter["_types"]["routeIds"];
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Type helper to extract routes from a plugin router
|
|
220
|
-
*/
|
|
221
|
-
export type PluginRoutes<
|
|
222
|
-
TRouter extends ReturnType<typeof createPluginRouter>,
|
|
223
|
-
> = TRouter["_types"]["routes"];
|
|
224
|
-
|
|
225
|
-
// Re-export TanStack utilities for plugins
|
|
226
|
-
export {
|
|
227
|
-
createRoute,
|
|
228
|
-
lazyRouteComponent,
|
|
229
|
-
Route,
|
|
230
|
-
TanStackLink as Link,
|
|
231
|
-
useNavigate,
|
|
232
|
-
useParams,
|
|
233
|
-
useSearch,
|
|
234
|
-
useLocation,
|
|
235
|
-
};
|
|
236
|
-
export type { AnyRoute, RouteIds, RouteById };
|
package/src/core/plugins.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createRoute,
|
|
3
|
-
lazyRouteComponent,
|
|
4
|
-
type AnyRoute,
|
|
5
|
-
} from "@tanstack/react-router";
|
|
6
|
-
import { Binder } from "./binder";
|
|
7
|
-
import type { ReactNode } from "react";
|
|
8
|
-
import type { PluginConnectionEntity } from "./plugin-context";
|
|
9
|
-
|
|
10
|
-
export interface ToolViewItem {
|
|
11
|
-
toolName: string;
|
|
12
|
-
label: string;
|
|
13
|
-
icon: ReactNode;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface RegisterRootSidebarItemParams {
|
|
17
|
-
icon: ReactNode;
|
|
18
|
-
label: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface RegisterSidebarGroupParams {
|
|
22
|
-
id: string;
|
|
23
|
-
label: string;
|
|
24
|
-
items: RegisterRootSidebarItemParams[];
|
|
25
|
-
defaultExpanded?: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface RegisterEmptyStateParams {
|
|
29
|
-
component: ReactNode;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface RegisterSettingsSidebarItemParams {
|
|
33
|
-
key: string;
|
|
34
|
-
icon: ReactNode;
|
|
35
|
-
label: string;
|
|
36
|
-
to: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface PluginSetupContext {
|
|
40
|
-
parentRoute: AnyRoute;
|
|
41
|
-
routing: {
|
|
42
|
-
createRoute: typeof createRoute;
|
|
43
|
-
lazyRouteComponent: typeof lazyRouteComponent;
|
|
44
|
-
};
|
|
45
|
-
registerRootSidebarItem: (params: RegisterRootSidebarItemParams) => void;
|
|
46
|
-
registerSidebarGroup: (params: RegisterSidebarGroupParams) => void;
|
|
47
|
-
registerSettingsSidebarItem: (
|
|
48
|
-
params: RegisterSettingsSidebarItemParams,
|
|
49
|
-
) => void;
|
|
50
|
-
registerPluginRoutes: (route: AnyRoute[]) => void;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export type PluginSetup = (context: PluginSetupContext) => void;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Props passed to plugin's renderHeader function.
|
|
57
|
-
*/
|
|
58
|
-
export interface PluginRenderHeaderProps {
|
|
59
|
-
connections: PluginConnectionEntity[];
|
|
60
|
-
selectedConnectionId: string;
|
|
61
|
-
onConnectionChange: (connectionId: string) => void;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Client Plugin interface.
|
|
66
|
-
*
|
|
67
|
-
* Defines the contract for client-side plugins that extend the Mesh UI.
|
|
68
|
-
* Client plugins are separate from server plugins to avoid bundling
|
|
69
|
-
* server code into the client bundle.
|
|
70
|
-
*/
|
|
71
|
-
export interface ClientPlugin<TBinding extends Binder = Binder> {
|
|
72
|
-
id: string;
|
|
73
|
-
/**
|
|
74
|
-
* Short description of the plugin shown in the settings UI.
|
|
75
|
-
*/
|
|
76
|
-
description?: string;
|
|
77
|
-
/**
|
|
78
|
-
* Binding schema used to filter compatible connections.
|
|
79
|
-
* Omit for plugins that manage their own connection (e.g. self MCP).
|
|
80
|
-
* @deprecated Use bindingName for server-side filtering instead.
|
|
81
|
-
*/
|
|
82
|
-
binding?: TBinding;
|
|
83
|
-
/**
|
|
84
|
-
* Server-side binding name to filter connections (e.g., "WORKFLOW", "LLM").
|
|
85
|
-
* Preferred over `binding` as it avoids loading all connections client-side.
|
|
86
|
-
*/
|
|
87
|
-
bindingName?: string;
|
|
88
|
-
setup?: PluginSetup;
|
|
89
|
-
/**
|
|
90
|
-
* Optional custom layout component for this plugin.
|
|
91
|
-
* If not provided, a default layout with connection selector will be used.
|
|
92
|
-
* @deprecated Use renderHeader and renderEmptyState instead.
|
|
93
|
-
*/
|
|
94
|
-
LayoutComponent?: React.ComponentType;
|
|
95
|
-
/**
|
|
96
|
-
* Render the header with connection selector.
|
|
97
|
-
* Receives the list of valid connections and current selection handlers.
|
|
98
|
-
*/
|
|
99
|
-
renderHeader?: (props: PluginRenderHeaderProps) => ReactNode;
|
|
100
|
-
/**
|
|
101
|
-
* Render the empty state when no valid connections are available.
|
|
102
|
-
*/
|
|
103
|
-
renderEmptyState?: () => ReactNode;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @deprecated Use ClientPlugin instead
|
|
108
|
-
*/
|
|
109
|
-
export interface Plugin<TBinding extends Binder>
|
|
110
|
-
extends ClientPlugin<TBinding> {
|
|
111
|
-
setup: PluginSetup; // Required for backwards compatibility
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export type AnyClientPlugin = ClientPlugin<Binder>;
|
|
115
|
-
export type AnyPlugin = Plugin<Binder>;
|
|
116
|
-
|
|
117
|
-
// Re-export plugin router utilities
|
|
118
|
-
export {
|
|
119
|
-
createPluginRouter,
|
|
120
|
-
type PluginRouteIds,
|
|
121
|
-
type PluginRoutes,
|
|
122
|
-
type AnyRoute,
|
|
123
|
-
type RouteIds,
|
|
124
|
-
type RouteById,
|
|
125
|
-
} from "./plugin-router";
|
|
126
|
-
|
|
127
|
-
// Note: PluginContextProvider and usePluginContext have been moved to @decocms/mesh-sdk/plugins.
|
|
128
|
-
// Types are re-exported here for backwards compatibility.
|
|
129
|
-
export type {
|
|
130
|
-
PluginContextProviderProps,
|
|
131
|
-
UsePluginContextOptions,
|
|
132
|
-
} from "./plugin-context-provider";
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server Plugin Interface
|
|
3
|
-
*
|
|
4
|
-
* Defines the contract for server-side plugins that can extend Mesh with:
|
|
5
|
-
* - MCP tools
|
|
6
|
-
* - API routes (authenticated and public)
|
|
7
|
-
* - Database migrations
|
|
8
|
-
* - Storage factories
|
|
9
|
-
* - Event handlers (via the event bus)
|
|
10
|
-
*
|
|
11
|
-
* Server plugins are separate from client plugins to avoid bundling
|
|
12
|
-
* server code into the client bundle.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { Hono } from "hono";
|
|
16
|
-
import type { Kysely } from "kysely";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Subset of StudioContext exposed to server plugin tool handlers.
|
|
20
|
-
*
|
|
21
|
-
* Plugins receive the full StudioContext at runtime but should only depend on
|
|
22
|
-
* these properties. This keeps the plugin contract stable and avoids coupling
|
|
23
|
-
* plugins to Mesh internals (db, vault, tracer, etc.).
|
|
24
|
-
*/
|
|
25
|
-
export interface ServerPluginToolContext {
|
|
26
|
-
organization: { id: string } | null;
|
|
27
|
-
access: { check: () => Promise<void> };
|
|
28
|
-
auth: {
|
|
29
|
-
user?: { id: string; email?: string; name?: string };
|
|
30
|
-
};
|
|
31
|
-
/** Kysely database instance for direct queries. */
|
|
32
|
-
db: Kysely<unknown>;
|
|
33
|
-
createMCPProxy: (connectionId: string) => Promise<{
|
|
34
|
-
callTool: (args: {
|
|
35
|
-
name: string;
|
|
36
|
-
arguments?: Record<string, unknown>;
|
|
37
|
-
}) => Promise<{
|
|
38
|
-
isError?: boolean;
|
|
39
|
-
content?: Array<{ type?: string; text?: string }>;
|
|
40
|
-
structuredContent?: unknown;
|
|
41
|
-
}>;
|
|
42
|
-
listTools: () => Promise<{
|
|
43
|
-
tools: Array<{
|
|
44
|
-
name: string;
|
|
45
|
-
title?: string;
|
|
46
|
-
description?: string;
|
|
47
|
-
inputSchema?: Record<string, unknown>;
|
|
48
|
-
outputSchema?: Record<string, unknown>;
|
|
49
|
-
annotations?: Record<string, unknown>;
|
|
50
|
-
}>;
|
|
51
|
-
}>;
|
|
52
|
-
close?: () => Promise<void>;
|
|
53
|
-
}>;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Tool definition for server plugins.
|
|
58
|
-
*/
|
|
59
|
-
export interface ServerPluginToolDefinition {
|
|
60
|
-
name: string;
|
|
61
|
-
description?: string;
|
|
62
|
-
inputSchema: unknown;
|
|
63
|
-
outputSchema?: unknown;
|
|
64
|
-
handler: (input: unknown, ctx: ServerPluginToolContext) => Promise<unknown>;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Database migration definition for plugins.
|
|
69
|
-
*/
|
|
70
|
-
export interface ServerPluginMigration {
|
|
71
|
-
/** Unique name for ordering (e.g., "001-initial-schema") */
|
|
72
|
-
name: string;
|
|
73
|
-
/** Apply the migration */
|
|
74
|
-
up: (db: Kysely<unknown>) => Promise<void>;
|
|
75
|
-
/** Revert the migration */
|
|
76
|
-
down: (db: Kysely<unknown>) => Promise<void>;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Context provided to server plugins for route registration and storage creation.
|
|
81
|
-
*/
|
|
82
|
-
export interface ServerPluginContext {
|
|
83
|
-
/** Database instance */
|
|
84
|
-
db: Kysely<unknown>;
|
|
85
|
-
/** Credential vault for encrypting sensitive data */
|
|
86
|
-
vault: {
|
|
87
|
-
encrypt: (value: string) => Promise<string>;
|
|
88
|
-
decrypt: (value: string) => Promise<string>;
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Event handler context provided to plugin event handlers.
|
|
94
|
-
* Contains the organization ID and a publish function for emitting follow-up events.
|
|
95
|
-
*/
|
|
96
|
-
export interface ServerPluginEventContext {
|
|
97
|
-
/** Organization ID the events belong to */
|
|
98
|
-
organizationId: string;
|
|
99
|
-
/** Connection ID of the SELF MCP for this organization */
|
|
100
|
-
connectionId: string;
|
|
101
|
-
/** Publish a follow-up event to the event bus */
|
|
102
|
-
publish: (
|
|
103
|
-
type: string,
|
|
104
|
-
subject: string,
|
|
105
|
-
data?: Record<string, unknown>,
|
|
106
|
-
options?: { deliverAt?: string },
|
|
107
|
-
) => Promise<void>;
|
|
108
|
-
/** Create an MCP proxy client for calling tools on a connection */
|
|
109
|
-
createMCPProxy: (connectionId: string) => Promise<{
|
|
110
|
-
callTool: (
|
|
111
|
-
params: { name: string; arguments?: Record<string, unknown> },
|
|
112
|
-
resultSchema?: unknown,
|
|
113
|
-
options?: { timeout?: number },
|
|
114
|
-
) => Promise<{
|
|
115
|
-
content?: unknown;
|
|
116
|
-
structuredContent?: unknown;
|
|
117
|
-
isError?: boolean;
|
|
118
|
-
}>;
|
|
119
|
-
close: () => Promise<void>;
|
|
120
|
-
}>;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Startup context provided to plugin onStartup hooks.
|
|
125
|
-
* Contains the database and a publish function for emitting recovery events.
|
|
126
|
-
*/
|
|
127
|
-
export interface ServerPluginStartupContext {
|
|
128
|
-
/** Database instance */
|
|
129
|
-
db: Kysely<unknown>;
|
|
130
|
-
/** Publish an event to the event bus for a given organization */
|
|
131
|
-
publish: (
|
|
132
|
-
organizationId: string,
|
|
133
|
-
event: { type: string; subject: string; data?: Record<string, unknown> },
|
|
134
|
-
) => Promise<void>;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Event definition for a CloudEvent received by a plugin.
|
|
139
|
-
*/
|
|
140
|
-
export interface ServerPluginEvent {
|
|
141
|
-
id: string;
|
|
142
|
-
type: string;
|
|
143
|
-
source: string;
|
|
144
|
-
subject?: string;
|
|
145
|
-
data?: unknown;
|
|
146
|
-
time?: string;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Server Plugin interface.
|
|
151
|
-
*
|
|
152
|
-
* Plugins export this interface from their server entry point.
|
|
153
|
-
* Tools are registered at startup but gated by org settings at runtime.
|
|
154
|
-
*/
|
|
155
|
-
export interface ServerPlugin {
|
|
156
|
-
/** Unique plugin identifier (e.g., "user-sandbox") */
|
|
157
|
-
id: string;
|
|
158
|
-
|
|
159
|
-
/** Short description shown in settings UI */
|
|
160
|
-
description?: string;
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* MCP tools this plugin provides.
|
|
164
|
-
* Tools are wrapped with org-enabled gating at registration time.
|
|
165
|
-
*/
|
|
166
|
-
tools?: ServerPluginToolDefinition[];
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Authenticated API routes.
|
|
170
|
-
* Mounted at /api/plugins/:pluginId/*
|
|
171
|
-
* Requires Mesh authentication.
|
|
172
|
-
*/
|
|
173
|
-
routes?: (app: Hono, ctx: ServerPluginContext) => void;
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Public API routes (no authentication required).
|
|
177
|
-
* Mounted at the root level.
|
|
178
|
-
* Use for endpoints that external users access (e.g., connect flow).
|
|
179
|
-
*/
|
|
180
|
-
publicRoutes?: (app: Hono, ctx: ServerPluginContext) => void;
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Database migrations for this plugin.
|
|
184
|
-
* Run alongside core migrations in name order.
|
|
185
|
-
*/
|
|
186
|
-
migrations?: ServerPluginMigration[];
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Factory to create plugin-specific storage adapters.
|
|
190
|
-
* Called during context initialization.
|
|
191
|
-
*/
|
|
192
|
-
createStorage?: (ctx: ServerPluginContext) => unknown;
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Event handler for this plugin.
|
|
196
|
-
*
|
|
197
|
-
* When defined, the system will:
|
|
198
|
-
* 1. Auto-subscribe the SELF connection to the specified event types per-organization
|
|
199
|
-
* 2. Route matching events from the event bus to this handler
|
|
200
|
-
*
|
|
201
|
-
* Events are durable (persisted in the event bus) with at-least-once delivery.
|
|
202
|
-
* The handler receives batches of events and a context for publishing follow-up events.
|
|
203
|
-
*/
|
|
204
|
-
onEvents?: {
|
|
205
|
-
/** Event type patterns this plugin handles (e.g., "workflow.execution.created") */
|
|
206
|
-
types: string[];
|
|
207
|
-
/** Handle a batch of events. Errors are logged but don't affect other plugins. */
|
|
208
|
-
handler: (
|
|
209
|
-
events: ServerPluginEvent[],
|
|
210
|
-
ctx: ServerPluginEventContext,
|
|
211
|
-
) => Promise<void> | void;
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Startup hook called once after the event bus is ready.
|
|
216
|
-
*
|
|
217
|
-
* Use this to recover from crashes (e.g., resume stuck workflow executions).
|
|
218
|
-
* Called after storage is initialized and the event bus worker has started.
|
|
219
|
-
* Errors are logged but don't prevent other plugins from starting.
|
|
220
|
-
*/
|
|
221
|
-
onStartup?: (ctx: ServerPluginStartupContext) => Promise<void>;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Type helper for any server plugin
|
|
226
|
-
*/
|
|
227
|
-
export type AnyServerPlugin = ServerPlugin;
|
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Event Bus Well-Known Binding
|
|
3
|
-
*
|
|
4
|
-
* Defines the interface for interacting with an event bus via MCP.
|
|
5
|
-
* Any MCP that implements this binding can publish events and manage subscriptions.
|
|
6
|
-
*
|
|
7
|
-
* This binding includes:
|
|
8
|
-
* - EVENT_PUBLISH: Publish an event to the bus
|
|
9
|
-
* - EVENT_SUBSCRIBE: Subscribe to events of a specific type
|
|
10
|
-
* - EVENT_UNSUBSCRIBE: Remove a subscription
|
|
11
|
-
*
|
|
12
|
-
* Events follow the CloudEvents v1.0 specification.
|
|
13
|
-
* @see https://cloudevents.io/
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { z } from "zod";
|
|
17
|
-
import { bindingClient, type ToolBinder } from "../core/binder";
|
|
18
|
-
|
|
19
|
-
// ============================================================================
|
|
20
|
-
// Publish Schemas
|
|
21
|
-
// ============================================================================
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* EVENT_PUBLISH Input Schema
|
|
25
|
-
*
|
|
26
|
-
* Input for publishing an event.
|
|
27
|
-
* Note: `source` is automatically set by the event bus from the caller's connection ID.
|
|
28
|
-
*/
|
|
29
|
-
export const EventPublishInputSchema = z.object({
|
|
30
|
-
/** Event type (e.g., "order.created", "user.signup") */
|
|
31
|
-
type: z.string().min(1).max(255).describe("Event type identifier"),
|
|
32
|
-
|
|
33
|
-
/** Optional subject/resource identifier */
|
|
34
|
-
subject: z
|
|
35
|
-
.string()
|
|
36
|
-
.max(255)
|
|
37
|
-
.optional()
|
|
38
|
-
.describe("Subject/resource identifier (e.g., order ID)"),
|
|
39
|
-
|
|
40
|
-
/** Event payload (any JSON value) */
|
|
41
|
-
data: z.unknown().optional().describe("Event payload"),
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Optional scheduled delivery time (ISO 8601 timestamp).
|
|
45
|
-
* If provided, the event will not be delivered until this time.
|
|
46
|
-
* If omitted, the event is delivered immediately.
|
|
47
|
-
* Cannot be used together with `cron`.
|
|
48
|
-
*/
|
|
49
|
-
deliverAt: z
|
|
50
|
-
.string()
|
|
51
|
-
.datetime()
|
|
52
|
-
.optional()
|
|
53
|
-
.describe(
|
|
54
|
-
"Scheduled delivery time (ISO 8601). Omit for immediate delivery.",
|
|
55
|
-
),
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Optional cron expression for recurring events.
|
|
59
|
-
* If provided, the event will be delivered repeatedly according to the schedule.
|
|
60
|
-
* Uses standard cron syntax (5 or 6 fields).
|
|
61
|
-
* Cannot be used together with `deliverAt`.
|
|
62
|
-
*
|
|
63
|
-
* Examples:
|
|
64
|
-
* - "0 9 * * 1" - Every Monday at 9:00 AM
|
|
65
|
-
* - "0 0 1 * *" - First day of every month at midnight
|
|
66
|
-
* - "0/15 * * * *" - Every 15 minutes
|
|
67
|
-
*/
|
|
68
|
-
cron: z
|
|
69
|
-
.string()
|
|
70
|
-
.max(100)
|
|
71
|
-
.optional()
|
|
72
|
-
.describe(
|
|
73
|
-
"Cron expression for recurring delivery. Use EVENT_CANCEL to stop.",
|
|
74
|
-
),
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
export type EventPublishInput = z.infer<typeof EventPublishInputSchema>;
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* EVENT_PUBLISH Output Schema
|
|
81
|
-
*/
|
|
82
|
-
export const EventPublishOutputSchema = z.object({
|
|
83
|
-
/** Created event ID */
|
|
84
|
-
id: z.string().describe("Unique event ID"),
|
|
85
|
-
|
|
86
|
-
/** Event type */
|
|
87
|
-
type: z.string().describe("Event type"),
|
|
88
|
-
|
|
89
|
-
/** Source connection ID */
|
|
90
|
-
source: z.string().describe("Source connection ID"),
|
|
91
|
-
|
|
92
|
-
/** Event timestamp (ISO 8601) */
|
|
93
|
-
time: z.string().describe("Event timestamp"),
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
export type EventPublishOutput = z.infer<typeof EventPublishOutputSchema>;
|
|
97
|
-
|
|
98
|
-
// ============================================================================
|
|
99
|
-
// Subscribe Schemas
|
|
100
|
-
// ============================================================================
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* EVENT_SUBSCRIBE Input Schema
|
|
104
|
-
*
|
|
105
|
-
* Input for subscribing to events.
|
|
106
|
-
* The subscriber connection ID is automatically set from the caller's token.
|
|
107
|
-
*/
|
|
108
|
-
export const EventSubscribeInputSchema = z.object({
|
|
109
|
-
/** Event type pattern to match */
|
|
110
|
-
eventType: z.string().min(1).max(255).describe("Event type to subscribe to"),
|
|
111
|
-
|
|
112
|
-
/** Optional: Only receive events from this publisher connection */
|
|
113
|
-
publisher: z
|
|
114
|
-
.string()
|
|
115
|
-
.optional()
|
|
116
|
-
.describe("Filter events by publisher connection ID"),
|
|
117
|
-
|
|
118
|
-
/** Optional: JSONPath filter expression on event data */
|
|
119
|
-
filter: z
|
|
120
|
-
.string()
|
|
121
|
-
.max(1000)
|
|
122
|
-
.optional()
|
|
123
|
-
.describe("JSONPath filter expression on event data"),
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
export type EventSubscribeInput = z.infer<typeof EventSubscribeInputSchema>;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* EVENT_SUBSCRIBE Output Schema
|
|
130
|
-
*/
|
|
131
|
-
export const EventSubscribeOutputSchema = z.object({
|
|
132
|
-
/** Created subscription */
|
|
133
|
-
subscription: z.object({
|
|
134
|
-
/** Subscription ID */
|
|
135
|
-
id: z.string().describe("Subscription ID"),
|
|
136
|
-
|
|
137
|
-
/** Subscriber connection ID */
|
|
138
|
-
connectionId: z.string().describe("Subscriber connection ID"),
|
|
139
|
-
|
|
140
|
-
/** Event type pattern */
|
|
141
|
-
eventType: z.string().describe("Event type pattern"),
|
|
142
|
-
|
|
143
|
-
/** Publisher connection filter */
|
|
144
|
-
publisher: z.string().nullable().describe("Publisher connection filter"),
|
|
145
|
-
|
|
146
|
-
/** JSONPath filter */
|
|
147
|
-
filter: z.string().nullable().describe("JSONPath filter expression"),
|
|
148
|
-
|
|
149
|
-
/** Whether subscription is enabled */
|
|
150
|
-
enabled: z.boolean().describe("Whether subscription is enabled"),
|
|
151
|
-
|
|
152
|
-
/** Created timestamp */
|
|
153
|
-
createdAt: z.string().datetime().describe("Created timestamp (ISO 8601)"),
|
|
154
|
-
|
|
155
|
-
/** Updated timestamp */
|
|
156
|
-
updatedAt: z.string().datetime().describe("Updated timestamp (ISO 8601)"),
|
|
157
|
-
}),
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
export type EventSubscribeOutput = z.infer<typeof EventSubscribeOutputSchema>;
|
|
161
|
-
|
|
162
|
-
// ============================================================================
|
|
163
|
-
// Sync Subscriptions Schemas
|
|
164
|
-
// ============================================================================
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Subscription item schema for sync operations
|
|
168
|
-
*/
|
|
169
|
-
export const SubscriptionItemSchema = z.object({
|
|
170
|
-
/** Event type pattern to match */
|
|
171
|
-
eventType: z.string().min(1).max(255).describe("Event type to subscribe to"),
|
|
172
|
-
|
|
173
|
-
/** Optional: Only receive events from this publisher connection */
|
|
174
|
-
publisher: z
|
|
175
|
-
.string()
|
|
176
|
-
.optional()
|
|
177
|
-
.describe("Filter events by publisher connection ID"),
|
|
178
|
-
|
|
179
|
-
/** Optional: JSONPath filter expression on event data */
|
|
180
|
-
filter: z
|
|
181
|
-
.string()
|
|
182
|
-
.max(1000)
|
|
183
|
-
.optional()
|
|
184
|
-
.describe("JSONPath filter expression on event data"),
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
export type SubscriptionItem = z.infer<typeof SubscriptionItemSchema>;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Subscription detail schema (returned in responses)
|
|
191
|
-
*/
|
|
192
|
-
export const SubscriptionDetailSchema = z.object({
|
|
193
|
-
/** Subscription ID */
|
|
194
|
-
id: z.string().describe("Subscription ID"),
|
|
195
|
-
|
|
196
|
-
/** Subscriber connection ID */
|
|
197
|
-
connectionId: z.string().describe("Subscriber connection ID"),
|
|
198
|
-
|
|
199
|
-
/** Event type pattern */
|
|
200
|
-
eventType: z.string().describe("Event type pattern"),
|
|
201
|
-
|
|
202
|
-
/** Publisher connection filter */
|
|
203
|
-
publisher: z.string().nullable().describe("Publisher connection filter"),
|
|
204
|
-
|
|
205
|
-
/** JSONPath filter */
|
|
206
|
-
filter: z.string().nullable().describe("JSONPath filter expression"),
|
|
207
|
-
|
|
208
|
-
/** Whether subscription is enabled */
|
|
209
|
-
enabled: z.boolean().describe("Whether subscription is enabled"),
|
|
210
|
-
|
|
211
|
-
/** Created timestamp */
|
|
212
|
-
createdAt: z.string().datetime().describe("Created timestamp (ISO 8601)"),
|
|
213
|
-
|
|
214
|
-
/** Updated timestamp */
|
|
215
|
-
updatedAt: z.string().datetime().describe("Updated timestamp (ISO 8601)"),
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
export type SubscriptionDetail = z.infer<typeof SubscriptionDetailSchema>;
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* EVENT_SYNC_SUBSCRIPTIONS Input Schema
|
|
222
|
-
*
|
|
223
|
-
* Input for syncing subscriptions to a desired state.
|
|
224
|
-
* The system will create new, delete removed, and update changed subscriptions.
|
|
225
|
-
* Subscriptions are identified by (eventType, publisher) - only one subscription
|
|
226
|
-
* per combination is allowed.
|
|
227
|
-
*/
|
|
228
|
-
export const EventSyncSubscriptionsInputSchema = z.object({
|
|
229
|
-
/** Desired subscriptions - system will create/update/delete to match */
|
|
230
|
-
subscriptions: z
|
|
231
|
-
.array(SubscriptionItemSchema)
|
|
232
|
-
.describe(
|
|
233
|
-
"Desired subscriptions - system will create/update/delete to match",
|
|
234
|
-
),
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
export type EventSyncSubscriptionsInput = z.infer<
|
|
238
|
-
typeof EventSyncSubscriptionsInputSchema
|
|
239
|
-
>;
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* EVENT_SYNC_SUBSCRIPTIONS Output Schema
|
|
243
|
-
*/
|
|
244
|
-
export const EventSyncSubscriptionsOutputSchema = z.object({
|
|
245
|
-
/** Number of new subscriptions created */
|
|
246
|
-
created: z.number().int().min(0).describe("Number of subscriptions created"),
|
|
247
|
-
|
|
248
|
-
/** Number of subscriptions with filter updated */
|
|
249
|
-
updated: z
|
|
250
|
-
.number()
|
|
251
|
-
.int()
|
|
252
|
-
.min(0)
|
|
253
|
-
.describe("Number of subscriptions with filter updated"),
|
|
254
|
-
|
|
255
|
-
/** Number of old subscriptions removed */
|
|
256
|
-
deleted: z.number().int().min(0).describe("Number of subscriptions removed"),
|
|
257
|
-
|
|
258
|
-
/** Number of subscriptions unchanged */
|
|
259
|
-
unchanged: z
|
|
260
|
-
.number()
|
|
261
|
-
.int()
|
|
262
|
-
.min(0)
|
|
263
|
-
.describe("Number of subscriptions unchanged"),
|
|
264
|
-
|
|
265
|
-
/** Current subscriptions after sync */
|
|
266
|
-
subscriptions: z
|
|
267
|
-
.array(SubscriptionDetailSchema)
|
|
268
|
-
.describe("Current subscriptions after sync"),
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
export type EventSyncSubscriptionsOutput = z.infer<
|
|
272
|
-
typeof EventSyncSubscriptionsOutputSchema
|
|
273
|
-
>;
|
|
274
|
-
|
|
275
|
-
// ============================================================================
|
|
276
|
-
// Unsubscribe Schemas
|
|
277
|
-
// ============================================================================
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* EVENT_UNSUBSCRIBE Input Schema
|
|
281
|
-
*/
|
|
282
|
-
export const EventUnsubscribeInputSchema = z.object({
|
|
283
|
-
/** Subscription ID to remove */
|
|
284
|
-
subscriptionId: z.string().describe("Subscription ID to remove"),
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
export type EventUnsubscribeInput = z.infer<typeof EventUnsubscribeInputSchema>;
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* EVENT_UNSUBSCRIBE Output Schema
|
|
291
|
-
*/
|
|
292
|
-
export const EventUnsubscribeOutputSchema = z.object({
|
|
293
|
-
/** Success status */
|
|
294
|
-
success: z.boolean().describe("Whether unsubscribe was successful"),
|
|
295
|
-
|
|
296
|
-
/** Subscription ID that was removed */
|
|
297
|
-
subscriptionId: z.string().describe("Subscription ID that was removed"),
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
export type EventUnsubscribeOutput = z.infer<
|
|
301
|
-
typeof EventUnsubscribeOutputSchema
|
|
302
|
-
>;
|
|
303
|
-
|
|
304
|
-
// ============================================================================
|
|
305
|
-
// Cancel Schemas (for stopping recurring events)
|
|
306
|
-
// ============================================================================
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* EVENT_CANCEL Input Schema
|
|
310
|
-
*
|
|
311
|
-
* Input for cancelling a recurring event.
|
|
312
|
-
* Only the publisher connection can cancel its own events.
|
|
313
|
-
*/
|
|
314
|
-
export const EventCancelInputSchema = z.object({
|
|
315
|
-
/** Event ID to cancel */
|
|
316
|
-
eventId: z.string().describe("Event ID to cancel"),
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
export type EventCancelInput = z.infer<typeof EventCancelInputSchema>;
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* EVENT_CANCEL Output Schema
|
|
323
|
-
*/
|
|
324
|
-
export const EventCancelOutputSchema = z.object({
|
|
325
|
-
/** Success status */
|
|
326
|
-
success: z.boolean().describe("Whether cancellation was successful"),
|
|
327
|
-
|
|
328
|
-
/** Event ID that was cancelled */
|
|
329
|
-
eventId: z.string().describe("Event ID that was cancelled"),
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
export type EventCancelOutput = z.infer<typeof EventCancelOutputSchema>;
|
|
333
|
-
|
|
334
|
-
// ============================================================================
|
|
335
|
-
// Ack Schemas (for acknowledging async event processing)
|
|
336
|
-
// ============================================================================
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* EVENT_ACK Input Schema
|
|
340
|
-
*
|
|
341
|
-
* Input for acknowledging an event delivery.
|
|
342
|
-
* Used when ON_EVENTS returns retryAfter - the subscriber must call EVENT_ACK
|
|
343
|
-
* to confirm successful processing, otherwise the event will be re-delivered.
|
|
344
|
-
*
|
|
345
|
-
* The subscriber connection ID is determined from the caller's token.
|
|
346
|
-
*/
|
|
347
|
-
export const EventAckInputSchema = z.object({
|
|
348
|
-
/** Event ID to acknowledge */
|
|
349
|
-
eventId: z.string().describe("Event ID to acknowledge"),
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
export type EventAckInput = z.infer<typeof EventAckInputSchema>;
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* EVENT_ACK Output Schema
|
|
356
|
-
*/
|
|
357
|
-
export const EventAckOutputSchema = z.object({
|
|
358
|
-
/** Success status */
|
|
359
|
-
success: z.boolean().describe("Whether ACK was successful"),
|
|
360
|
-
|
|
361
|
-
/** Event ID that was acknowledged */
|
|
362
|
-
eventId: z.string().describe("Event ID that was acknowledged"),
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
export type EventAckOutput = z.infer<typeof EventAckOutputSchema>;
|
|
366
|
-
|
|
367
|
-
// ============================================================================
|
|
368
|
-
// Event Bus Binding
|
|
369
|
-
// ============================================================================
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Event Bus Binding
|
|
373
|
-
*
|
|
374
|
-
* Defines the interface for interacting with an event bus.
|
|
375
|
-
* Implementations must provide PUBLISH, SUBSCRIBE, UNSUBSCRIBE, CANCEL, ACK, and SYNC_SUBSCRIPTIONS tools.
|
|
376
|
-
*
|
|
377
|
-
* Required tools:
|
|
378
|
-
* - EVENT_PUBLISH: Publish an event (supports one-time, scheduled, and recurring via cron)
|
|
379
|
-
* - EVENT_SUBSCRIBE: Subscribe to events
|
|
380
|
-
* - EVENT_UNSUBSCRIBE: Remove a subscription
|
|
381
|
-
* - EVENT_CANCEL: Cancel a recurring event (stops future deliveries)
|
|
382
|
-
* - EVENT_ACK: Acknowledge event delivery (for async processing with retryAfter)
|
|
383
|
-
* - EVENT_SYNC_SUBSCRIPTIONS: Sync subscriptions to desired state
|
|
384
|
-
*/
|
|
385
|
-
export const EVENT_BUS_BINDING = [
|
|
386
|
-
{
|
|
387
|
-
name: "EVENT_PUBLISH" as const,
|
|
388
|
-
inputSchema: EventPublishInputSchema,
|
|
389
|
-
outputSchema: EventPublishOutputSchema,
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
name: "EVENT_SUBSCRIBE" as const,
|
|
393
|
-
inputSchema: EventSubscribeInputSchema,
|
|
394
|
-
outputSchema: EventSubscribeOutputSchema,
|
|
395
|
-
},
|
|
396
|
-
{
|
|
397
|
-
name: "EVENT_UNSUBSCRIBE" as const,
|
|
398
|
-
inputSchema: EventUnsubscribeInputSchema,
|
|
399
|
-
outputSchema: EventUnsubscribeOutputSchema,
|
|
400
|
-
},
|
|
401
|
-
{
|
|
402
|
-
name: "EVENT_CANCEL" as const,
|
|
403
|
-
inputSchema: EventCancelInputSchema,
|
|
404
|
-
outputSchema: EventCancelOutputSchema,
|
|
405
|
-
},
|
|
406
|
-
{
|
|
407
|
-
name: "EVENT_ACK" as const,
|
|
408
|
-
inputSchema: EventAckInputSchema,
|
|
409
|
-
outputSchema: EventAckOutputSchema,
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
name: "EVENT_SYNC_SUBSCRIPTIONS" as const,
|
|
413
|
-
inputSchema: EventSyncSubscriptionsInputSchema,
|
|
414
|
-
outputSchema: EventSyncSubscriptionsOutputSchema,
|
|
415
|
-
},
|
|
416
|
-
] satisfies ToolBinder[];
|
|
417
|
-
|
|
418
|
-
/**
|
|
419
|
-
* Event Bus Binding Client
|
|
420
|
-
*
|
|
421
|
-
* Use this to create a client for interacting with an event bus.
|
|
422
|
-
*
|
|
423
|
-
* @example
|
|
424
|
-
* ```typescript
|
|
425
|
-
* import { EventBusBinding } from "@decocms/bindings/event-bus";
|
|
426
|
-
*
|
|
427
|
-
* // For a connection
|
|
428
|
-
* const client = EventBusBinding.forConnection(connection);
|
|
429
|
-
*
|
|
430
|
-
* // Publish an event
|
|
431
|
-
* const event = await client.EVENT_PUBLISH({
|
|
432
|
-
* type: "order.created",
|
|
433
|
-
* data: { orderId: "123" }
|
|
434
|
-
* });
|
|
435
|
-
*
|
|
436
|
-
* // Subscribe to events
|
|
437
|
-
* const sub = await client.EVENT_SUBSCRIBE({
|
|
438
|
-
* eventType: "order.created"
|
|
439
|
-
* });
|
|
440
|
-
*
|
|
441
|
-
* // Unsubscribe
|
|
442
|
-
* await client.EVENT_UNSUBSCRIBE({
|
|
443
|
-
* subscriptionId: sub.subscription.id
|
|
444
|
-
* });
|
|
445
|
-
* ```
|
|
446
|
-
*/
|
|
447
|
-
export const EventBusBinding = bindingClient(EVENT_BUS_BINDING);
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Type helper for the Event Bus binding client
|
|
451
|
-
*/
|
|
452
|
-
export type EventBusBindingClient = ReturnType<
|
|
453
|
-
typeof EventBusBinding.forConnection
|
|
454
|
-
>;
|