@decocms/bindings 1.0.0 → 1.0.1-alpha.4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/bindings",
3
- "version": "1.0.0",
3
+ "version": "1.0.1-alpha.4",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "vitest run",
@@ -19,6 +19,7 @@
19
19
  "./llm": "./src/well-known/language-model.ts",
20
20
  "./connection": "./src/core/connection.ts",
21
21
  "./client": "./src/core/client/index.ts",
22
+ "./mcp": "./src/well-known/mcp.ts",
22
23
  "./agent": "./src/well-known/agent.ts"
23
24
  },
24
25
  "devDependencies": {
@@ -16,8 +16,7 @@ type JsonSchema = Record<string, unknown>;
16
16
  /**
17
17
  * Checks if a value is a Zod schema by looking for the _def property
18
18
  */
19
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
- function isZodSchema(value: unknown): value is ZodType<any> {
19
+ function isZodSchema(value: unknown): value is ZodType<unknown> {
21
20
  return (
22
21
  value !== null &&
23
22
  typeof value === "object" &&
@@ -34,15 +33,15 @@ function isZodSchema(value: unknown): value is ZodType<any> {
34
33
  * @returns The JSON schema representation, or null if input is null/undefined
35
34
  */
36
35
  export function normalizeToJsonSchema(
37
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
- schema: ZodType<any> | JsonSchema | null | undefined,
36
+ schema: ZodType<unknown> | JsonSchema | null | undefined,
39
37
  ): JsonSchema | null {
40
38
  if (schema == null) {
41
39
  return null;
42
40
  }
43
41
 
44
42
  if (isZodSchema(schema)) {
45
- return zodToJsonSchema(schema) as JsonSchema;
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ return zodToJsonSchema(schema as any) as JsonSchema;
46
45
  }
47
46
 
48
47
  // Already a JSON schema
@@ -261,45 +261,71 @@ export function createCollectionBindings<
261
261
  const upperName = collectionName.toUpperCase() as Uppercase<TName>;
262
262
  const readOnly = options?.readOnly ?? false;
263
263
 
264
- const bindings: CollectionBinding<TEntitySchema, Uppercase<TName>>[number][] =
265
- [
266
- {
267
- name: `COLLECTION_${upperName}_LIST` as const,
268
- inputSchema: CollectionListInputSchema,
269
- outputSchema: createCollectionListOutputSchema(entitySchema),
270
- },
271
- {
272
- name: `COLLECTION_${upperName}_GET` as const,
273
- inputSchema: CollectionGetInputSchema,
274
- outputSchema: createCollectionGetOutputSchema(entitySchema),
275
- },
276
- ];
264
+ const bindings: ToolBinder[] = [
265
+ {
266
+ name: `COLLECTION_${upperName}_LIST` as const,
267
+ inputSchema: CollectionListInputSchema,
268
+ outputSchema: createCollectionListOutputSchema(entitySchema) as z.ZodType<
269
+ CollectionListOutput<z.infer<TEntitySchema>>
270
+ >,
271
+ },
272
+ {
273
+ name: `COLLECTION_${upperName}_GET` as const,
274
+ inputSchema: CollectionGetInputSchema,
275
+ outputSchema: createCollectionGetOutputSchema(entitySchema) as z.ZodType<
276
+ CollectionGetOutput<z.infer<TEntitySchema>>
277
+ >,
278
+ },
279
+ ];
277
280
 
278
281
  // Only include mutation operations if not read-only
279
282
  if (!readOnly) {
280
283
  bindings.push(
281
284
  {
282
285
  name: `COLLECTION_${upperName}_CREATE` as const,
283
- inputSchema: createCollectionInsertInputSchema(entitySchema),
284
- outputSchema: createCollectionInsertOutputSchema(entitySchema),
286
+ inputSchema: createCollectionInsertInputSchema(
287
+ entitySchema,
288
+ ) as unknown as z.ZodType<
289
+ CollectionInsertInput<z.infer<TEntitySchema>>
290
+ >,
291
+ outputSchema: createCollectionInsertOutputSchema(
292
+ entitySchema,
293
+ ) as unknown as z.ZodType<
294
+ CollectionInsertOutput<z.infer<TEntitySchema>>
295
+ >,
285
296
  opt: true,
286
297
  },
287
298
  {
288
299
  name: `COLLECTION_${upperName}_UPDATE` as const,
289
- inputSchema: createCollectionUpdateInputSchema(entitySchema),
290
- outputSchema: createCollectionUpdateOutputSchema(entitySchema),
300
+ inputSchema: createCollectionUpdateInputSchema(
301
+ entitySchema,
302
+ ) as unknown as z.ZodType<
303
+ CollectionUpdateInput<z.infer<TEntitySchema>>
304
+ >,
305
+ outputSchema: createCollectionUpdateOutputSchema(
306
+ entitySchema,
307
+ ) as unknown as z.ZodType<
308
+ CollectionUpdateOutput<z.infer<TEntitySchema>>
309
+ >,
291
310
  opt: true,
292
311
  },
293
312
  {
294
313
  name: `COLLECTION_${upperName}_DELETE` as const,
295
314
  inputSchema: CollectionDeleteInputSchema,
296
- outputSchema: createCollectionDeleteOutputSchema(entitySchema),
315
+ outputSchema: createCollectionDeleteOutputSchema(
316
+ entitySchema,
317
+ ) as unknown as z.ZodType<
318
+ CollectionDeleteOutput<z.infer<TEntitySchema>>
319
+ >,
297
320
  opt: true,
298
321
  },
299
322
  );
300
323
  }
301
324
 
302
- return bindings satisfies readonly ToolBinder[];
325
+ return bindings as unknown as readonly CollectionBinding<
326
+ TEntitySchema,
327
+ Uppercase<TName>
328
+ >[number][];
303
329
  }
304
330
 
305
331
  export type ReadOnlyCollectionBinding<
@@ -309,16 +335,12 @@ export type ReadOnlyCollectionBinding<
309
335
  {
310
336
  name: `COLLECTION_${TUpperName}_LIST`;
311
337
  inputSchema: typeof CollectionListInputSchema;
312
- outputSchema: ReturnType<
313
- typeof createCollectionListOutputSchema<TEntitySchema>
314
- >;
338
+ outputSchema: z.ZodType<CollectionListOutput<z.infer<TEntitySchema>>>;
315
339
  },
316
340
  {
317
341
  name: `COLLECTION_${TUpperName}_GET`;
318
342
  inputSchema: typeof CollectionGetInputSchema;
319
- outputSchema: ReturnType<
320
- typeof createCollectionGetOutputSchema<TEntitySchema>
321
- >;
343
+ outputSchema: z.ZodType<CollectionGetOutput<z.infer<TEntitySchema>>>;
322
344
  },
323
345
  ];
324
346
  /**
@@ -328,33 +350,32 @@ export type CollectionBinding<
328
350
  TEntitySchema extends BaseCollectionEntitySchemaType,
329
351
  TUpperName extends Uppercase<string> = Uppercase<string>,
330
352
  > = [
331
- ...ReadOnlyCollectionBinding<TEntitySchema, TUpperName>,
353
+ {
354
+ name: `COLLECTION_${TUpperName}_LIST`;
355
+ inputSchema: typeof CollectionListInputSchema;
356
+ outputSchema: z.ZodType<CollectionListOutput<z.infer<TEntitySchema>>>;
357
+ },
358
+ {
359
+ name: `COLLECTION_${TUpperName}_GET`;
360
+ inputSchema: typeof CollectionGetInputSchema;
361
+ outputSchema: z.ZodType<CollectionGetOutput<z.infer<TEntitySchema>>>;
362
+ },
332
363
  {
333
364
  name: `COLLECTION_${TUpperName}_CREATE`;
334
- inputSchema: ReturnType<
335
- typeof createCollectionInsertInputSchema<TEntitySchema>
336
- >;
337
- outputSchema: ReturnType<
338
- typeof createCollectionInsertOutputSchema<TEntitySchema>
339
- >;
365
+ inputSchema: z.ZodType<CollectionInsertInput<z.infer<TEntitySchema>>>;
366
+ outputSchema: z.ZodType<CollectionInsertOutput<z.infer<TEntitySchema>>>;
340
367
  opt: true;
341
368
  },
342
369
  {
343
370
  name: `COLLECTION_${TUpperName}_UPDATE`;
344
- inputSchema: ReturnType<
345
- typeof createCollectionUpdateInputSchema<TEntitySchema>
346
- >;
347
- outputSchema: ReturnType<
348
- typeof createCollectionUpdateOutputSchema<TEntitySchema>
349
- >;
371
+ inputSchema: z.ZodType<CollectionUpdateInput<z.infer<TEntitySchema>>>;
372
+ outputSchema: z.ZodType<CollectionUpdateOutput<z.infer<TEntitySchema>>>;
350
373
  opt: true;
351
374
  },
352
375
  {
353
376
  name: `COLLECTION_${TUpperName}_DELETE`;
354
377
  inputSchema: typeof CollectionDeleteInputSchema;
355
- outputSchema: ReturnType<
356
- typeof createCollectionDeleteOutputSchema<TEntitySchema>
357
- >;
378
+ outputSchema: z.ZodType<CollectionDeleteOutput<z.infer<TEntitySchema>>>;
358
379
  opt: true;
359
380
  },
360
381
  ];
@@ -373,6 +394,21 @@ export type CollectionGetInput = z.infer<typeof CollectionGetInputSchema>;
373
394
  export type CollectionDeleteInput = z.infer<typeof CollectionDeleteInputSchema>;
374
395
  export type OrderByExpression = z.infer<typeof OrderByExpressionSchema>;
375
396
 
397
+ /**
398
+ * Type helper for insert input with generic item type
399
+ */
400
+ export type CollectionInsertInput<T> = {
401
+ data: T;
402
+ };
403
+
404
+ /**
405
+ * Type helper for update input with generic item type
406
+ */
407
+ export type CollectionUpdateInput<T> = {
408
+ id: string;
409
+ data: Partial<T>;
410
+ };
411
+
376
412
  /**
377
413
  * Type helper for list output with generic item type
378
414
  */
@@ -0,0 +1,35 @@
1
+ /**
2
+ * MCP Well-Known Binding
3
+ *
4
+ * Defines the interface for retrieving MCP configuration.
5
+ */
6
+
7
+ import { z } from "zod/v3";
8
+ import type { Binder } from "../core/binder";
9
+
10
+ /**
11
+ * MCP Configuration Output Schema
12
+ */
13
+ export const McpConfigurationOutputSchema = z.object({
14
+ scopes: z.array(z.string()).describe("List of scopes available"),
15
+ stateSchema: z
16
+ .record(z.string(), z.unknown())
17
+ .describe("JSON Schema (draft-07) defining the state structure"),
18
+ });
19
+
20
+ export type McpConfigurationOutput = z.infer<
21
+ typeof McpConfigurationOutputSchema
22
+ >;
23
+
24
+ /**
25
+ * MCP Binding
26
+ *
27
+ * Tool to retrieve the MCP configuration including scopes and state schema.
28
+ */
29
+ export const MCP_BINDING = [
30
+ {
31
+ name: "MCP_CONFIGURATION",
32
+ inputSchema: z.object({}),
33
+ outputSchema: McpConfigurationOutputSchema,
34
+ },
35
+ ] as const satisfies Binder;
@@ -0,0 +1,40 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ MCP_BINDING,
4
+ McpConfigurationOutputSchema,
5
+ } from "../src/well-known/mcp";
6
+
7
+ describe("MCP Binding", () => {
8
+ it("should match the expected structure", () => {
9
+ expect(MCP_BINDING).toHaveLength(1);
10
+ const tool = MCP_BINDING[0];
11
+ expect(tool.name).toBe("MCP_CONFIGURATION");
12
+ expect(tool.inputSchema).toBeDefined();
13
+ expect(tool.outputSchema).toBeDefined();
14
+ });
15
+
16
+ it("should validate correct output", () => {
17
+ const validOutput = {
18
+ scopes: ["scope1", "scope2"],
19
+ stateSchema: {
20
+ type: "object",
21
+ properties: {
22
+ foo: { type: "string" },
23
+ },
24
+ },
25
+ };
26
+
27
+ const result = McpConfigurationOutputSchema.safeParse(validOutput);
28
+ expect(result.success).toBe(true);
29
+ });
30
+
31
+ it("should fail on invalid output", () => {
32
+ const invalidOutput = {
33
+ scopes: "not-an-array", // Invalid
34
+ stateSchema: { type: "object" },
35
+ };
36
+
37
+ const result = McpConfigurationOutputSchema.safeParse(invalidOutput);
38
+ expect(result.success).toBe(false);
39
+ });
40
+ });