@decocms/runtime 0.28.1 → 1.0.0-alpha-candy.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/package.json +11 -77
  2. package/scripts/generate-json-schema.ts +24 -0
  3. package/src/asset-server/dev-server-proxy.ts +16 -0
  4. package/src/asset-server/index.ts +44 -0
  5. package/src/bindings/README.md +1 -1
  6. package/src/bindings/binder.ts +2 -5
  7. package/src/bindings/channels.ts +1 -1
  8. package/src/bindings/index.ts +0 -33
  9. package/src/bindings/language-model/utils.ts +0 -91
  10. package/src/bindings.ts +30 -108
  11. package/src/client.ts +1 -145
  12. package/src/index.ts +46 -175
  13. package/src/mcp.ts +8 -165
  14. package/src/proxy.ts +3 -62
  15. package/src/state.ts +1 -30
  16. package/src/tools.ts +336 -0
  17. package/src/wrangler.ts +5 -5
  18. package/tsconfig.json +8 -0
  19. package/dist/admin.d.ts +0 -5
  20. package/dist/admin.js +0 -21
  21. package/dist/admin.js.map +0 -1
  22. package/dist/bindings/deconfig/index.d.ts +0 -12
  23. package/dist/bindings/deconfig/index.js +0 -10
  24. package/dist/bindings/deconfig/index.js.map +0 -1
  25. package/dist/bindings/index.d.ts +0 -2315
  26. package/dist/bindings/index.js +0 -156
  27. package/dist/bindings/index.js.map +0 -1
  28. package/dist/chunk-3AWMDSOH.js +0 -96
  29. package/dist/chunk-3AWMDSOH.js.map +0 -1
  30. package/dist/chunk-4XSQKJLU.js +0 -105
  31. package/dist/chunk-4XSQKJLU.js.map +0 -1
  32. package/dist/chunk-5EYZ2LVM.js +0 -158
  33. package/dist/chunk-5EYZ2LVM.js.map +0 -1
  34. package/dist/chunk-7ITSLORK.js +0 -128
  35. package/dist/chunk-7ITSLORK.js.map +0 -1
  36. package/dist/chunk-I7BWSAN6.js +0 -49
  37. package/dist/chunk-I7BWSAN6.js.map +0 -1
  38. package/dist/chunk-L4OT2YDO.js +0 -27
  39. package/dist/chunk-L4OT2YDO.js.map +0 -1
  40. package/dist/chunk-SHQSNOFL.js +0 -769
  41. package/dist/chunk-SHQSNOFL.js.map +0 -1
  42. package/dist/chunk-UHR3BLMF.js +0 -92
  43. package/dist/chunk-UHR3BLMF.js.map +0 -1
  44. package/dist/chunk-UIJGM3NV.js +0 -518
  45. package/dist/chunk-UIJGM3NV.js.map +0 -1
  46. package/dist/chunk-ZPUT6RN6.js +0 -32
  47. package/dist/chunk-ZPUT6RN6.js.map +0 -1
  48. package/dist/client.d.ts +0 -28
  49. package/dist/client.js +0 -5
  50. package/dist/client.js.map +0 -1
  51. package/dist/d1-store.d.ts +0 -9
  52. package/dist/d1-store.js +0 -4
  53. package/dist/d1-store.js.map +0 -1
  54. package/dist/drizzle.d.ts +0 -49
  55. package/dist/drizzle.js +0 -121
  56. package/dist/drizzle.js.map +0 -1
  57. package/dist/index-LOfgE9a_.d.ts +0 -471
  58. package/dist/index-xKtm7A7B.d.ts +0 -530
  59. package/dist/index.d.ts +0 -10
  60. package/dist/index.js +0 -637
  61. package/dist/index.js.map +0 -1
  62. package/dist/mastra.d.ts +0 -10
  63. package/dist/mastra.js +0 -6
  64. package/dist/mastra.js.map +0 -1
  65. package/dist/mcp-87iLaW9V.d.ts +0 -105
  66. package/dist/mcp-client.d.ts +0 -232
  67. package/dist/mcp-client.js +0 -4
  68. package/dist/mcp-client.js.map +0 -1
  69. package/dist/proxy.d.ts +0 -11
  70. package/dist/proxy.js +0 -5
  71. package/dist/proxy.js.map +0 -1
  72. package/dist/resources.d.ts +0 -362
  73. package/dist/resources.js +0 -4
  74. package/dist/resources.js.map +0 -1
  75. package/dist/views.d.ts +0 -72
  76. package/dist/views.js +0 -4
  77. package/dist/views.js.map +0 -1
  78. package/src/admin.ts +0 -16
  79. package/src/auth.ts +0 -233
  80. package/src/bindings/deconfig/helpers.ts +0 -107
  81. package/src/bindings/deconfig/index.ts +0 -1
  82. package/src/bindings/deconfig/resources.ts +0 -659
  83. package/src/bindings/deconfig/types.ts +0 -106
  84. package/src/bindings/language-model/ai-sdk.ts +0 -87
  85. package/src/bindings/language-model/index.ts +0 -4
  86. package/src/bindings/resources/bindings.ts +0 -99
  87. package/src/bindings/resources/helpers.ts +0 -95
  88. package/src/bindings/resources/schemas.ts +0 -265
  89. package/src/bindings/views.ts +0 -14
  90. package/src/cf-imports.ts +0 -1
  91. package/src/d1-store.ts +0 -34
  92. package/src/deprecated.ts +0 -59
  93. package/src/drizzle.ts +0 -201
  94. package/src/mastra.ts +0 -898
  95. package/src/resources.ts +0 -168
  96. package/src/views.ts +0 -26
  97. package/src/workflow.ts +0 -193
package/src/client.ts CHANGED
@@ -1,35 +1,3 @@
1
- import { toAsyncIterator } from "./bindings/deconfig/helpers.ts";
2
- // Extract resource name from DECO_RESOURCE_${NAME}_READ pattern
3
- type ExtractResourceName<K> = K extends `DECO_RESOURCE_${infer Name}_READ`
4
- ? Name
5
- : never;
6
-
7
- // Generate SUBSCRIBE method name from resource name
8
- type SubscribeMethodName<Name extends string> =
9
- `DECO_RESOURCE_${Name}_SUBSCRIBE`;
10
-
11
- // Extract data type from READ method return type
12
- type ExtractReadData<T> = T extends Promise<{ data: infer D }>
13
- ? D
14
- : T extends { data: infer D }
15
- ? D
16
- : never;
17
-
18
- // Generate all SUBSCRIBE method names for a given type
19
- type SubscribeMethods<T> = {
20
- [K in keyof T as K extends `DECO_RESOURCE_${string}_READ`
21
- ? SubscribeMethodName<ExtractResourceName<K>>
22
- : never]: K extends `DECO_RESOURCE_${string}_READ`
23
- ? // oxlint-disable-next-line no-explicit-any
24
- T[K] extends (...args: any) => any
25
- ? (args: { id: string } | { uri: string }) => AsyncIterableIterator<{
26
- uri: string;
27
- data: ExtractReadData<Awaited<ReturnType<T[K]>>>;
28
- }>
29
- : never
30
- : never;
31
- };
32
-
33
1
  export type MCPClient<T> = {
34
2
  // oxlint-disable-next-line no-explicit-any
35
3
  [K in keyof T]: T[K] extends (...args: any) => any
@@ -38,7 +6,7 @@ export type MCPClient<T> = {
38
6
  init?: CustomInit,
39
7
  ) => Promise<Awaited<ReturnType<T[K]>>>
40
8
  : never;
41
- } & SubscribeMethods<T>;
9
+ };
42
10
 
43
11
  export type CustomInit = RequestInit & {
44
12
  handleResponse?: (response: Response) => Promise<unknown>;
@@ -53,123 +21,11 @@ export const DEFAULT_INIT: CustomInit = {
53
21
  },
54
22
  };
55
23
 
56
- /**
57
- * Helper function to call an MCP tool via fetch
58
- */
59
- async function callMCPTool<T = unknown>(
60
- methodName: string,
61
- args: unknown,
62
- init?: CustomInit,
63
- ): Promise<T> {
64
- const mergedInit: CustomInit = {
65
- ...init,
66
- headers: {
67
- ...DEFAULT_INIT.headers,
68
- ...init?.headers,
69
- },
70
- };
71
-
72
- const response = await fetch(`/mcp/call-tool/${methodName}`, {
73
- method: "POST",
74
- body: JSON.stringify(args),
75
- credentials: "include",
76
- ...mergedInit,
77
- });
78
-
79
- if (!response.ok) {
80
- throw new Error(`Failed to call ${methodName}: ${response.statusText}`);
81
- }
82
-
83
- return response.json() as Promise<T>;
84
- }
85
-
86
- /**
87
- * Creates a subscribe method for a resource that returns an async iterator
88
- * yielding {uri, data} objects as resources are updated.
89
- */
90
- function createSubscribeMethod(
91
- resourceName: string,
92
- init?: CustomInit,
93
- ): (args: { id: string }) => AsyncIterableIterator<{
94
- uri: string;
95
- data: unknown;
96
- }> {
97
- return async function* (args: { id: string } | { uri: string }) {
98
- // Step 1: Call DESCRIBE to get watch endpoint configuration and URI template
99
- const describeMethodName = `DECO_RESOURCE_${resourceName}_DESCRIBE`;
100
- const readMethodName = `DECO_RESOURCE_${resourceName}_READ`;
101
-
102
- // Get describe information
103
- const describeData = await callMCPTool<{
104
- uriTemplate?: string;
105
- features?: {
106
- watch?: {
107
- pathname?: string;
108
- };
109
- };
110
- }>(describeMethodName, {}, init);
111
-
112
- const watchPathname = describeData?.features?.watch?.pathname;
113
- const uriTemplate = describeData?.uriTemplate;
114
-
115
- if (!watchPathname) {
116
- throw new Error(
117
- `Resource ${resourceName} does not support watch functionality`,
118
- );
119
- }
120
-
121
- if (!uriTemplate) {
122
- throw new Error(`Resource ${resourceName} does not provide uriTemplate`);
123
- }
124
-
125
- // Step 2: Construct URI from template by replacing * with id
126
- const resourceUri =
127
- "uri" in args ? args.uri : uriTemplate.replace("*", args.id);
128
-
129
- // Step 3: Construct watch URL and create EventSource
130
- const watchUrl = new URL(watchPathname, globalThis.location.origin);
131
- watchUrl.searchParams.set("uri", resourceUri);
132
-
133
- const eventSource = new EventSource(watchUrl.href);
134
-
135
- // Step 4: Use toAsyncIterator to consume SSE events and enrich with READ data
136
- const eventStream = toAsyncIterator<{ uri: string }>(
137
- eventSource,
138
- "message",
139
- );
140
-
141
- // Iterate over SSE events and enrich with full data
142
- for await (const event of eventStream) {
143
- const uri = event.uri;
144
-
145
- if (uri) {
146
- // Call READ to get full resource data
147
- const readData = await callMCPTool<{ data: unknown }>(
148
- readMethodName,
149
- { uri },
150
- init,
151
- );
152
-
153
- yield { uri, data: readData.data };
154
- }
155
- }
156
- };
157
- }
158
-
159
24
  export const createClient = <T>(init?: CustomInit): MCPClient<T> => {
160
25
  return new Proxy(
161
26
  {},
162
27
  {
163
28
  get: (_, prop) => {
164
- const propStr = String(prop);
165
-
166
- // Check if this is a SUBSCRIBE method call
167
- const subscribeMatch = propStr.match(/^DECO_RESOURCE_(.+)_SUBSCRIBE$/);
168
- if (subscribeMatch) {
169
- const resourceName = subscribeMatch[1];
170
- return createSubscribeMethod(resourceName, init);
171
- }
172
-
173
29
  // Regular method call
174
30
  return async (args: unknown, innerInit?: CustomInit) => {
175
31
  const mergedInit: CustomInit = {
package/src/index.ts CHANGED
@@ -1,30 +1,14 @@
1
1
  /* oxlint-disable no-explicit-any */
2
2
  import type { ExecutionContext } from "@cloudflare/workers-types";
3
3
  import { decodeJwt } from "jose";
4
- import type { z } from "zod/v3";
5
- import {
6
- getReqToken,
7
- handleAuthCallback,
8
- handleLogout,
9
- StateParser,
10
- } from "./auth.ts";
11
- import {
12
- createContractBinding,
13
- createIntegrationBinding,
14
- workspaceClient,
15
- } from "./bindings.ts";
16
- import { DeconfigResource } from "./bindings/deconfig/index.ts";
17
- import { DECO_MCP_CLIENT_HEADER } from "./client.ts";
18
- import { DeprecatedEnv } from "./deprecated.ts";
4
+ import type { z } from "zod";
5
+ import { createContractBinding, createIntegrationBinding } from "./bindings.ts";
6
+ import { State } from "./state.ts";
19
7
  import {
20
8
  createMCPServer,
21
9
  type CreateMCPServerOptions,
22
10
  MCPServer,
23
- } from "./mastra.ts";
24
- import { MCPClient, type QueryResult } from "./mcp.ts";
25
- import { State } from "./state.ts";
26
- import type { WorkflowDO } from "./workflow.ts";
27
- import { Workflow } from "./workflow.ts";
11
+ } from "./tools.ts";
28
12
  import type { Binding, ContractBinding, MCPBinding } from "./wrangler.ts";
29
13
  export { proxyConnectionForId } from "./bindings.ts";
30
14
  export {
@@ -32,30 +16,15 @@ export {
32
16
  type CreateStubAPIOptions,
33
17
  type ToolBinder,
34
18
  } from "./mcp.ts";
35
- export interface WorkspaceDB {
36
- query: (params: {
37
- sql: string;
38
- params: string[];
39
- }) => Promise<{ result: QueryResult[] }>;
40
- }
41
19
 
42
- export interface DefaultEnv<TSchema extends z.ZodTypeAny = any>
43
- extends DeprecatedEnv<TSchema> {
44
- DECO_REQUEST_CONTEXT: RequestContext<TSchema>;
45
- DECO_APP_NAME: string;
46
- DECO_APP_SLUG: string;
47
- DECO_APP_ENTRYPOINT: string;
48
- DECO_API_URL?: string;
49
- DECO_WORKSPACE: string;
50
- DECO_API_JWT_PUBLIC_KEY: string;
51
- DECO_APP_DEPLOYMENT_ID: string;
52
- DECO_BINDINGS: string;
53
- DECO_API_TOKEN: string;
54
- DECO_WORKFLOW_DO: DurableObjectNamespace<WorkflowDO>;
55
- DECO_WORKSPACE_DB: WorkspaceDB & {
56
- forContext: (ctx: RequestContext) => WorkspaceDB;
57
- };
20
+ export interface DefaultEnv<TSchema extends z.ZodTypeAny = any> {
21
+ MESH_REQUEST_CONTEXT: RequestContext<TSchema>;
22
+ MESH_BINDINGS: string;
23
+ MESH_APP_DEPLOYMENT_ID: string;
58
24
  IS_LOCAL: boolean;
25
+ MESH_URL?: string;
26
+ MESH_RUNTIME_TOKEN?: string;
27
+ MESH_APP_NAME?: string;
59
28
  [key: string]: unknown;
60
29
  }
61
30
 
@@ -63,7 +32,7 @@ export interface BindingsObject {
63
32
  bindings?: Binding[];
64
33
  }
65
34
 
66
- export const WorkersMCPBindings = {
35
+ export const MCPBindings = {
67
36
  parse: (bindings?: string): Binding[] => {
68
37
  if (!bindings) return [];
69
38
  try {
@@ -109,14 +78,13 @@ export interface User {
109
78
 
110
79
  export interface RequestContext<TSchema extends z.ZodTypeAny = any> {
111
80
  state: z.infer<TSchema>;
112
- branch?: string;
113
81
  token: string;
114
- workspace: string;
82
+ meshUrl: string;
115
83
  ensureAuthenticated: (options?: {
116
84
  workspaceHint?: string;
117
85
  }) => User | undefined;
118
86
  callerApp?: string;
119
- integrationId?: string;
87
+ connectionId?: string;
120
88
  }
121
89
 
122
90
  // 2. Map binding type to its creator function
@@ -136,26 +104,12 @@ const creatorByType: CreatorByType = {
136
104
  const withDefaultBindings = ({
137
105
  env,
138
106
  server,
139
- ctx,
140
107
  url,
141
108
  }: {
142
109
  env: DefaultEnv;
143
110
  server: MCPServer<any, any>;
144
- ctx: RequestContext;
145
111
  url?: string;
146
112
  }) => {
147
- const client = workspaceClient(ctx);
148
- const createWorkspaceDB = (ctx: RequestContext): WorkspaceDB => {
149
- const client = workspaceClient(ctx);
150
- return {
151
- query: ({ sql, params }) => {
152
- return client.DATABASES_RUN_SQL({
153
- sql,
154
- params,
155
- });
156
- },
157
- };
158
- };
159
113
  env["SELF"] = new Proxy(
160
114
  {},
161
115
  {
@@ -174,20 +128,6 @@ const withDefaultBindings = ({
174
128
  },
175
129
  );
176
130
 
177
- const workspaceDbBinding = {
178
- ...createWorkspaceDB(ctx),
179
- forContext: createWorkspaceDB,
180
- };
181
-
182
- env["DECO_API"] = MCPClient;
183
- env["DECO_WORKSPACE_API"] = client;
184
- env["DECO_WORKSPACE_DB"] = workspaceDbBinding;
185
-
186
- // Backwards compatibility
187
- env["DECO_CHAT_API"] = MCPClient;
188
- env["DECO_CHAT_WORKSPACE_API"] = client;
189
- env["DECO_CHAT_WORKSPACE_DB"] = workspaceDbBinding;
190
-
191
131
  env["IS_LOCAL"] =
192
132
  (url?.startsWith("http://localhost") ||
193
133
  url?.startsWith("http://127.0.0.1")) ??
@@ -204,13 +144,9 @@ export class UnauthorizedError extends Error {
204
144
  }
205
145
  }
206
146
 
207
- const AUTH_CALLBACK_ENDPOINT = "/oauth/callback";
208
- const AUTH_START_ENDPOINT = "/oauth/start";
209
- const AUTH_LOGOUT_ENDPOINT = "/oauth/logout";
210
- const AUTHENTICATED = (user?: unknown, workspace?: string) => () => {
147
+ const AUTHENTICATED = (user?: unknown) => () => {
211
148
  return {
212
149
  ...((user as User) ?? {}),
213
- workspace,
214
150
  } as User;
215
151
  };
216
152
 
@@ -218,68 +154,50 @@ export const withBindings = <TEnv>({
218
154
  env: _env,
219
155
  server,
220
156
  tokenOrContext,
221
- origin,
222
157
  url,
223
- branch,
224
158
  }: {
225
159
  env: TEnv;
226
160
  server: MCPServer<TEnv, any>;
227
161
  tokenOrContext?: string | RequestContext;
228
- origin?: string | null;
229
162
  url?: string;
230
- branch?: string | null;
231
163
  }): TEnv => {
232
- branch ??= undefined;
233
164
  const env = _env as DefaultEnv<any>;
234
165
 
235
- const apiUrl = env.DECO_API_URL ?? "https://api.decocms.com";
236
166
  let context;
237
167
  if (typeof tokenOrContext === "string") {
238
168
  const decoded = decodeJwt(tokenOrContext);
239
- const workspace = decoded.aud as string;
169
+ const metadata = decoded.metadata as {
170
+ state: Record<string, unknown>;
171
+ meshUrl: string;
172
+ connectionId: string;
173
+ };
240
174
 
241
175
  context = {
242
- state: decoded.state as Record<string, unknown>,
176
+ state: metadata.state,
243
177
  token: tokenOrContext,
244
- integrationId: decoded.integrationId as string,
245
- workspace,
246
- ensureAuthenticated: AUTHENTICATED(decoded.user, workspace),
247
- branch,
178
+ meshUrl: metadata.meshUrl,
179
+ connectionId: metadata.connectionId,
180
+ ensureAuthenticated: AUTHENTICATED(decoded.user),
248
181
  } as RequestContext<any>;
249
182
  } else if (typeof tokenOrContext === "object") {
250
183
  context = tokenOrContext;
251
184
  const decoded = decodeJwt(tokenOrContext.token);
252
- const workspace = decoded.aud as string;
185
+ const metadata = decoded.metadata as {
186
+ state: Record<string, unknown>;
187
+ meshUrl: string;
188
+ connectionId: string;
189
+ };
253
190
  const appName = decoded.appName as string | undefined;
254
191
  context.callerApp = appName;
255
- context.integrationId ??= decoded.integrationId as string;
256
- context.ensureAuthenticated = AUTHENTICATED(decoded.user, workspace);
192
+ context.connectionId ??= metadata.connectionId;
193
+ context.ensureAuthenticated = AUTHENTICATED(decoded.user);
257
194
  } else {
258
- context = {
259
- state: undefined,
260
- token: env.DECO_API_TOKEN,
261
- workspace: env.DECO_WORKSPACE,
262
- branch,
263
- ensureAuthenticated: (options?: { workspaceHint?: string }) => {
264
- const workspaceHint = options?.workspaceHint ?? env.DECO_WORKSPACE;
265
- const authUri = new URL("/apps/oauth", apiUrl);
266
- authUri.searchParams.set("client_id", env.DECO_APP_NAME);
267
- authUri.searchParams.set(
268
- "redirect_uri",
269
- new URL(AUTH_CALLBACK_ENDPOINT, origin ?? env.DECO_APP_ENTRYPOINT)
270
- .href,
271
- );
272
- workspaceHint &&
273
- authUri.searchParams.set("workspace_hint", workspaceHint);
274
- throw new UnauthorizedError("Unauthorized", authUri);
275
- },
276
- };
195
+ // should not reach here
196
+ throw new Error("Invalid token or context");
277
197
  }
278
198
 
279
- env.DECO_REQUEST_CONTEXT = context;
280
- // Backwards compatibility
281
- env.DECO_CHAT_REQUEST_CONTEXT = context;
282
- const bindings = WorkersMCPBindings.parse(env.DECO_BINDINGS);
199
+ env.MESH_REQUEST_CONTEXT = context;
200
+ const bindings = MCPBindings.parse(env.MESH_BINDINGS);
283
201
 
284
202
  for (const binding of bindings) {
285
203
  env[binding.name] = creatorByType[binding.type](binding as any, env);
@@ -288,7 +206,6 @@ export const withBindings = <TEnv>({
288
206
  withDefaultBindings({
289
207
  env,
290
208
  server,
291
- ctx: env.DECO_REQUEST_CONTEXT,
292
209
  url,
293
210
  });
294
211
 
@@ -297,9 +214,7 @@ export const withBindings = <TEnv>({
297
214
 
298
215
  export const withRuntime = <TEnv, TSchema extends z.ZodTypeAny = never>(
299
216
  userFns: UserDefaultExport<TEnv, TSchema>,
300
- ): ExportedHandler<TEnv & DefaultEnv<TSchema>> & {
301
- Workflow: ReturnType<typeof Workflow>;
302
- } => {
217
+ ): ExportedHandler<TEnv & DefaultEnv<TSchema>> => {
303
218
  const server = createMCPServer<TEnv, TSchema>(userFns);
304
219
  const fetcher = async (
305
220
  req: Request,
@@ -307,21 +222,6 @@ export const withRuntime = <TEnv, TSchema extends z.ZodTypeAny = never>(
307
222
  ctx: ExecutionContext,
308
223
  ) => {
309
224
  const url = new URL(req.url);
310
- if (url.pathname === AUTH_CALLBACK_ENDPOINT) {
311
- return handleAuthCallback(req, {
312
- apiUrl: env.DECO_API_URL,
313
- appName: env.DECO_APP_NAME,
314
- });
315
- }
316
- if (url.pathname === AUTH_START_ENDPOINT) {
317
- env.DECO_REQUEST_CONTEXT.ensureAuthenticated();
318
- const redirectTo = new URL("/", url);
319
- const next = url.searchParams.get("next");
320
- return Response.redirect(next ?? redirectTo, 302);
321
- }
322
- if (url.pathname === AUTH_LOGOUT_ENDPOINT) {
323
- return handleLogout(req);
324
- }
325
225
  if (url.pathname === "/mcp") {
326
226
  return server.fetch(req, env, ctx);
327
227
  }
@@ -348,56 +248,27 @@ export const withRuntime = <TEnv, TSchema extends z.ZodTypeAny = never>(
348
248
  });
349
249
  }
350
250
 
351
- if (url.pathname.startsWith(DeconfigResource.WatchPathNameBase)) {
352
- return DeconfigResource.watchAPI(req, env);
353
- }
354
251
  return (
355
252
  userFns.fetch?.(req, env, ctx) ||
356
253
  new Response("Not found", { status: 404 })
357
254
  );
358
255
  };
359
256
  return {
360
- Workflow: Workflow(server, userFns.workflows),
361
257
  fetch: async (
362
258
  req: Request,
363
259
  env: TEnv & DefaultEnv<TSchema>,
364
260
  ctx: ExecutionContext,
365
261
  ) => {
366
- const referer = req.headers.get("referer");
367
- const isFetchRequest = req.headers.has(DECO_MCP_CLIENT_HEADER);
368
-
369
- try {
370
- const bindings = withBindings({
371
- env,
372
- server,
373
- branch:
374
- req.headers.get("x-deco-branch") ??
375
- new URL(req.url).searchParams.get("__b"),
376
- tokenOrContext: await getReqToken(req, env),
377
- origin:
378
- referer ?? req.headers.get("origin") ?? new URL(req.url).origin,
379
- url: req.url,
380
- });
381
- return await State.run(
382
- { req, env: bindings, ctx },
383
- async () => await fetcher(req, bindings, ctx),
384
- );
385
- } catch (error) {
386
- if (error instanceof UnauthorizedError) {
387
- if (!isFetchRequest) {
388
- const url = new URL(req.url);
389
- error.redirectTo.searchParams.set(
390
- "state",
391
- StateParser.stringify({
392
- next: url.searchParams.get("next") ?? referer ?? req.url,
393
- }),
394
- );
395
- return Response.redirect(error.redirectTo, 302);
396
- }
397
- return new Response(null, { status: 401 });
398
- }
399
- throw error;
400
- }
262
+ const bindings = withBindings({
263
+ env,
264
+ server,
265
+ tokenOrContext: req.headers.get("x-mesh-token") ?? undefined,
266
+ url: req.url,
267
+ });
268
+ return await State.run(
269
+ { req, env: bindings, ctx },
270
+ async () => await fetcher(req, bindings, ctx),
271
+ );
401
272
  },
402
273
  };
403
274
  };
package/src/mcp.ts CHANGED
@@ -1,169 +1,12 @@
1
1
  /* oxlint-disable no-explicit-any */
2
- import { env } from "cloudflare:workers";
3
- import { z } from "zod/v3";
4
- import type { MCPConnection } from "./connection.ts";
5
- import type { DefaultEnv } from "./index.ts";
6
- import { createMCPClientProxy } from "./proxy.ts";
7
2
  import type { ToolBinder } from "@decocms/bindings";
8
-
9
- export interface FetchOptions extends RequestInit {
10
- path?: string;
11
- segments?: string[];
12
- }
13
-
14
- const Timings = z.object({
15
- sql_duration_ms: z.number().optional(),
16
- });
17
-
18
- const Meta = z.object({
19
- changed_db: z.boolean().optional(),
20
- changes: z.number().optional(),
21
- duration: z.number().optional(),
22
- last_row_id: z.number().optional(),
23
- rows_read: z.number().optional(),
24
- rows_written: z.number().optional(),
25
- served_by_primary: z.boolean().optional(),
26
- served_by_region: z
27
- .enum(["WNAM", "ENAM", "WEUR", "EEUR", "APAC", "OC"])
28
- .optional(),
29
- size_after: z.number().optional(),
30
- timings: Timings.optional(),
31
- });
32
-
33
- const QueryResult = z.object({
34
- meta: Meta.optional(),
35
- results: z.array(z.unknown()).optional(),
36
- success: z.boolean().optional(),
37
- });
38
-
39
- export type QueryResult = z.infer<typeof QueryResult>;
40
-
41
- const workspaceTools = [
42
- {
43
- name: "INTEGRATIONS_GET" as const,
44
- inputSchema: z.object({
45
- id: z.string(),
46
- }),
47
- outputSchema: z.object({
48
- connection: z.object({}),
49
- }),
50
- },
51
- {
52
- name: "DATABASES_RUN_SQL" as const,
53
- inputSchema: z.object({
54
- sql: z.string().describe("The SQL query to run"),
55
- params: z
56
- .array(z.string())
57
- .describe("The parameters to pass to the SQL query"),
58
- }),
59
- outputSchema: z.object({
60
- result: z.array(QueryResult),
61
- }),
62
- },
63
- ] satisfies ToolBinder<string, unknown, object>[];
64
-
65
- // Default fetcher instance with API_SERVER_URL and API_HEADERS
66
- const global = createMCPFetchStub<[]>({});
67
- export const MCPClient = new Proxy(
68
- {} as typeof global & {
69
- forWorkspace: (
70
- workspace: string,
71
- token?: string,
72
- ) => MCPClientFetchStub<typeof workspaceTools>;
73
- forConnection: <TDefinition extends readonly ToolBinder[]>(
74
- connection: MCPConnectionProvider,
75
- ) => MCPClientFetchStub<TDefinition>;
76
- },
77
- {
78
- get(_, name) {
79
- if (name === "toJSON") {
80
- return null;
81
- }
82
-
83
- if (name === "forWorkspace") {
84
- return (workspace: string, token?: string) =>
85
- createMCPFetchStub<[]>({
86
- workspace,
87
- token,
88
- decoCmsApiUrl: (env as DefaultEnv).DECO_API_URL,
89
- });
90
- }
91
- if (name === "forConnection") {
92
- return <TDefinition extends readonly ToolBinder[]>(
93
- connection: MCPConnectionProvider,
94
- ) =>
95
- createMCPFetchStub<TDefinition>({
96
- connection,
97
- decoCmsApiUrl: (env as DefaultEnv).DECO_API_URL,
98
- });
99
- }
100
- return global[name as keyof typeof global];
101
- },
102
- },
103
- );
3
+ export {
4
+ createMCPFetchStub,
5
+ isStreamableToolBinder,
6
+ MCPClient,
7
+ type CreateStubAPIOptions,
8
+ type MCPClientFetchStub,
9
+ type MCPClientStub,
10
+ } from "@decocms/bindings/client"; // Default fetcher instance with API_SERVER_URL and API_HEADERS
104
11
 
105
12
  export type { ToolBinder };
106
-
107
- export const isStreamableToolBinder = (
108
- toolBinder: ToolBinder,
109
- ): toolBinder is ToolBinder<string, any, any, true> => {
110
- return toolBinder.streamable === true;
111
- };
112
- export type MCPClientStub<TDefinition extends readonly ToolBinder[]> = {
113
- [K in TDefinition[number] as K["name"]]: K extends ToolBinder<
114
- string,
115
- infer TInput,
116
- infer TReturn
117
- >
118
- ? (params: TInput, init?: RequestInit) => Promise<TReturn>
119
- : never;
120
- };
121
-
122
- export type MCPClientFetchStub<TDefinition extends readonly ToolBinder[]> = {
123
- [K in TDefinition[number] as K["name"]]: K["streamable"] extends true
124
- ? K extends ToolBinder<string, infer TInput, any, true>
125
- ? (params: TInput, init?: RequestInit) => Promise<Response>
126
- : never
127
- : K extends ToolBinder<string, infer TInput, infer TReturn, any>
128
- ? (params: TInput, init?: RequestInit) => Promise<Awaited<TReturn>>
129
- : never;
130
- };
131
-
132
- export type MCPConnectionProvider = MCPConnection;
133
-
134
- export interface MCPClientRaw {
135
- callTool: (tool: string, args: unknown) => Promise<unknown>;
136
- listTools: () => Promise<
137
- {
138
- name: string;
139
- inputSchema: any;
140
- outputSchema?: any;
141
- description: string;
142
- }[]
143
- >;
144
- }
145
- export type JSONSchemaToZodConverter = (jsonSchema: any) => z.ZodTypeAny;
146
- export interface CreateStubAPIOptions {
147
- mcpPath?: string;
148
- decoCmsApiUrl?: string;
149
- workspace?: string;
150
- token?: string;
151
- connection?: MCPConnectionProvider;
152
- streamable?: Record<string, boolean>;
153
- debugId?: () => string;
154
- getErrorByStatusCode?: (
155
- statusCode: number,
156
- message?: string,
157
- traceId?: string,
158
- errorObject?: unknown,
159
- ) => Error;
160
- supportsToolName?: boolean;
161
- }
162
-
163
- export function createMCPFetchStub<TDefinition extends readonly ToolBinder[]>(
164
- options?: CreateStubAPIOptions,
165
- ): MCPClientFetchStub<TDefinition> {
166
- return createMCPClientProxy<MCPClientFetchStub<TDefinition>>({
167
- ...(options ?? {}),
168
- });
169
- }