@decocms/bindings 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -186,8 +186,8 @@ const isValid = checker.isImplementedBy(availableTools);
186
186
 
187
187
  The package includes pre-defined bindings for common use cases. Well-known bindings are organized in the `well-known` folder and must be imported directly:
188
188
 
189
- - **Collections**: `@decocms/bindings/well-known/collections` - Collection bindings for SQL table-like structures
190
- - **Models**: `@decocms/bindings/well-known/models` - AI model providers interface
189
+ - **Collections**: `@decocms/bindings/collections` - Collection bindings for SQL table-like structures
190
+ - **Models**: `@decocms/bindings/models` - AI model providers interface
191
191
 
192
192
  See the [Collection Bindings](#collection-bindings) and [Models Bindings](#models-bindings) sections below for detailed usage examples.
193
193
 
@@ -243,7 +243,7 @@ Collection bindings are a well-known binding pattern for SQL table-like structur
243
243
 
244
244
  ```typescript
245
245
  import { z } from "zod";
246
- import { createCollectionBindings } from "@decocms/bindings/well-known/collections";
246
+ import { createCollectionBindings } from "@decocms/bindings/collections";
247
247
  import { createBindingChecker } from "@decocms/bindings";
248
248
 
249
249
  // Define your entity schema extending the base schema
@@ -338,7 +338,7 @@ Models bindings provide a well-known interface for AI model providers. They use
338
338
  ### Using Models Bindings
339
339
 
340
340
  ```typescript
341
- import { MODELS_BINDING, MODELS_COLLECTION_BINDING } from "@decocms/bindings/well-known/models";
341
+ import { MODELS_BINDING, MODELS_COLLECTION_BINDING } from "@decocms/bindings/models";
342
342
  import { createBindingChecker } from "@decocms/bindings";
343
343
 
344
344
  // Use the pre-defined MODELS_BINDING
@@ -407,7 +407,7 @@ Models follow the collection entity schema with additional model-specific fields
407
407
  Here's how you would implement the models binding in an MCP server:
408
408
 
409
409
  ```typescript
410
- import { MODELS_BINDING } from "@decocms/bindings/well-known/models";
410
+ import { MODELS_BINDING } from "@decocms/bindings/models";
411
411
  import { impl } from "@decocms/sdk/mcp/bindings/binder";
412
412
 
413
413
  const modelTools = impl(MODELS_BINDING, [
@@ -492,7 +492,7 @@ Here's how you would implement a collection binding in an MCP server:
492
492
 
493
493
  ```typescript
494
494
  import { z } from "zod";
495
- import { createCollectionBindings } from "@decocms/bindings/well-known/collections";
495
+ import { createCollectionBindings } from "@decocms/bindings/collections";
496
496
  import { impl } from "@decocms/sdk/mcp/bindings/binder";
497
497
 
498
498
  const TodoSchema = z.object({
@@ -0,0 +1,129 @@
1
+ import { z } from 'zod';
2
+
3
+ // src/well-known/collections.ts
4
+ var BaseCollectionEntitySchema = z.object({
5
+ id: z.string().describe("Unique identifier for the entity"),
6
+ title: z.string().describe("Human-readable title for the entity"),
7
+ created_at: z.string().datetime(),
8
+ updated_at: z.string().datetime(),
9
+ created_by: z.string().optional(),
10
+ updated_by: z.string().optional()
11
+ });
12
+ var ComparisonExpressionSchema = z.object({
13
+ field: z.array(z.string()),
14
+ operator: z.enum([
15
+ "eq",
16
+ "gt",
17
+ "gte",
18
+ "lt",
19
+ "lte",
20
+ "in",
21
+ "like",
22
+ "contains"
23
+ ]),
24
+ value: z.unknown()
25
+ });
26
+ var WhereExpressionSchema = z.union([
27
+ ComparisonExpressionSchema,
28
+ z.object({
29
+ operator: z.enum(["and", "or", "not"]),
30
+ conditions: z.array(ComparisonExpressionSchema)
31
+ })
32
+ ]);
33
+ var OrderByExpressionSchema = z.object({
34
+ field: z.array(z.string()),
35
+ direction: z.enum(["asc", "desc"]),
36
+ nulls: z.enum(["first", "last"]).optional()
37
+ });
38
+ var CollectionListInputSchema = z.object({
39
+ where: WhereExpressionSchema.optional().describe("Filter expression"),
40
+ orderBy: z.array(OrderByExpressionSchema).optional().describe("Sort expressions"),
41
+ limit: z.number().int().min(1).max(1e3).optional().describe("Maximum number of items to return"),
42
+ offset: z.number().int().min(0).optional().describe("Number of items to skip")
43
+ });
44
+ function createCollectionListOutputSchema(entitySchema) {
45
+ return z.object({
46
+ items: z.array(entitySchema).describe("Array of collection items"),
47
+ totalCount: z.number().int().min(0).optional().describe("Total number of matching items (if available)"),
48
+ hasMore: z.boolean().optional().describe("Whether there are more items available")
49
+ });
50
+ }
51
+ var CollectionGetInputSchema = z.object({
52
+ id: z.string().describe("ID of the entity to retrieve")
53
+ });
54
+ function createCollectionGetOutputSchema(entitySchema) {
55
+ return z.object({
56
+ item: entitySchema.nullable().describe("The retrieved item, or null if not found")
57
+ });
58
+ }
59
+ function createCollectionInsertInputSchema(entitySchema) {
60
+ return z.object({
61
+ data: entitySchema.describe("Data for the new entity (id may be auto-generated)")
62
+ });
63
+ }
64
+ function createCollectionInsertOutputSchema(entitySchema) {
65
+ return z.object({
66
+ item: entitySchema.describe("The created entity with generated id")
67
+ });
68
+ }
69
+ function createCollectionUpdateInputSchema(entitySchema) {
70
+ return z.object({
71
+ id: z.string().describe("ID of the entity to update"),
72
+ data: entitySchema.partial().describe("Partial entity data to update")
73
+ });
74
+ }
75
+ function createCollectionUpdateOutputSchema(entitySchema) {
76
+ return z.object({
77
+ item: entitySchema.describe("The updated entity")
78
+ });
79
+ }
80
+ var CollectionDeleteInputSchema = z.object({
81
+ id: z.string().describe("ID of the entity to delete")
82
+ });
83
+ var CollectionDeleteOutputSchema = z.object({
84
+ success: z.boolean().describe("Whether the deletion was successful"),
85
+ id: z.string().describe("ID of the deleted entity")
86
+ });
87
+ function createCollectionBindings(collectionName, entitySchema, options) {
88
+ const upperName = collectionName.toUpperCase();
89
+ const readOnly = options?.readOnly ?? false;
90
+ const bindings = [
91
+ {
92
+ name: `DECO_COLLECTION_${upperName}_LIST`,
93
+ inputSchema: CollectionListInputSchema,
94
+ outputSchema: createCollectionListOutputSchema(entitySchema)
95
+ },
96
+ {
97
+ name: `DECO_COLLECTION_${upperName}_GET`,
98
+ inputSchema: CollectionGetInputSchema,
99
+ outputSchema: createCollectionGetOutputSchema(entitySchema)
100
+ }
101
+ ];
102
+ if (!readOnly) {
103
+ bindings.push(
104
+ {
105
+ name: `DECO_COLLECTION_${upperName}_INSERT`,
106
+ inputSchema: createCollectionInsertInputSchema(entitySchema),
107
+ outputSchema: createCollectionInsertOutputSchema(entitySchema),
108
+ opt: true
109
+ },
110
+ {
111
+ name: `DECO_COLLECTION_${upperName}_UPDATE`,
112
+ inputSchema: createCollectionUpdateInputSchema(entitySchema),
113
+ outputSchema: createCollectionUpdateOutputSchema(entitySchema),
114
+ opt: true
115
+ },
116
+ {
117
+ name: `DECO_COLLECTION_${upperName}_DELETE`,
118
+ inputSchema: CollectionDeleteInputSchema,
119
+ outputSchema: CollectionDeleteOutputSchema,
120
+ opt: true
121
+ }
122
+ );
123
+ }
124
+ return bindings;
125
+ }
126
+
127
+ export { BaseCollectionEntitySchema, CollectionDeleteInputSchema, CollectionDeleteOutputSchema, CollectionGetInputSchema, CollectionListInputSchema, OrderByExpressionSchema, WhereExpressionSchema, createCollectionBindings, createCollectionGetOutputSchema, createCollectionInsertInputSchema, createCollectionInsertOutputSchema, createCollectionListOutputSchema, createCollectionUpdateInputSchema, createCollectionUpdateOutputSchema };
128
+ //# sourceMappingURL=chunk-L7E6ONLJ.js.map
129
+ //# sourceMappingURL=chunk-L7E6ONLJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/well-known/collections.ts"],"names":[],"mappings":"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","file":"chunk-L7E6ONLJ.js","sourcesContent":["import { z } from \"zod\";\nimport type { ToolBinder } from \"../core/binder\";\n\n/**\n * Collection Bindings\n *\n * This module provides standardized tool bindings for Collections, representing\n * SQL table-like structures with CRUD + Search operations compatible with TanStack DB.\n *\n * Key Features:\n * - Generic collection bindings that work with any entity type\n * - Standardized tool naming: `DECO_COLLECTION_{COLLECTION}_*`\n * - Compatible with TanStack DB query-collection\n * - Full TypeScript support with proper type constraints\n * - Support for filtering, sorting, and pagination\n * - Simple id and title fields for human-readable identification\n */\n\n/**\n * Base schema for collection entities\n * All collection entities must have an id, title, and audit trail fields\n */\nexport const BaseCollectionEntitySchema = z.object({\n id: z.string().describe(\"Unique identifier for the entity\"),\n title: z.string().describe(\"Human-readable title for the entity\"),\n created_at: z.string().datetime(),\n updated_at: z.string().datetime(),\n created_by: z.string().optional(),\n updated_by: z.string().optional(),\n});\n\n/**\n * Type helper for BaseCollectionEntitySchema\n */\nexport type BaseCollectionEntitySchemaType = typeof BaseCollectionEntitySchema;\n\n/**\n * Comparison expression schema for filtering\n */\nconst ComparisonExpressionSchema = z.object({\n field: z.array(z.string()),\n operator: z.enum([\n \"eq\",\n \"gt\",\n \"gte\",\n \"lt\",\n \"lte\",\n \"in\",\n \"like\",\n \"contains\",\n ]),\n value: z.unknown(),\n});\n\n/**\n * Where expression schema for filtering\n * Supports TanStack DB predicate push-down patterns\n */\nexport const WhereExpressionSchema = z.union([\n ComparisonExpressionSchema,\n z.object({\n operator: z.enum([\"and\", \"or\", \"not\"]),\n conditions: z.array(ComparisonExpressionSchema),\n }),\n]);\n\n/**\n * Where expression type for filtering\n * Derived from WhereExpressionSchema\n */\nexport type WhereExpression = z.infer<typeof WhereExpressionSchema>;\n\n/**\n * Order by expression for sorting\n */\nexport const OrderByExpressionSchema = z.object({\n field: z.array(z.string()),\n direction: z.enum([\"asc\", \"desc\"]),\n nulls: z.enum([\"first\", \"last\"]).optional(),\n});\n\n/**\n * List/Query input schema for collections\n * Compatible with TanStack DB LoadSubsetOptions\n */\nexport const CollectionListInputSchema = z.object({\n where: WhereExpressionSchema.optional().describe(\"Filter expression\"),\n orderBy: z\n .array(OrderByExpressionSchema)\n .optional()\n .describe(\"Sort expressions\"),\n limit: z\n .number()\n .int()\n .min(1)\n .max(1000)\n .optional()\n .describe(\"Maximum number of items to return\"),\n offset: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe(\"Number of items to skip\"),\n});\n\n/**\n * Factory function to create list output schema for a specific collection type\n */\nexport function createCollectionListOutputSchema<T extends z.ZodTypeAny>(\n entitySchema: T,\n) {\n return z.object({\n items: z.array(entitySchema).describe(\"Array of collection items\"),\n totalCount: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe(\"Total number of matching items (if available)\"),\n hasMore: z\n .boolean()\n .optional()\n .describe(\"Whether there are more items available\"),\n });\n}\n\n/**\n * Get by ID input schema\n */\nexport const CollectionGetInputSchema = z.object({\n id: z.string().describe(\"ID of the entity to retrieve\"),\n});\n\n/**\n * Factory function to create get output schema\n */\nexport function createCollectionGetOutputSchema<T extends z.ZodTypeAny>(\n entitySchema: T,\n) {\n return z.object({\n item: entitySchema\n .nullable()\n .describe(\"The retrieved item, or null if not found\"),\n });\n}\n\n/**\n * Factory function to create insert input schema\n */\nexport function createCollectionInsertInputSchema<T extends z.ZodTypeAny>(\n entitySchema: T,\n) {\n // Remove id field since it may be auto-generated by the server\n return z.object({\n data: entitySchema.describe(\"Data for the new entity (id may be auto-generated)\"),\n });\n}\n\n/**\n * Factory function to create insert output schema\n */\nexport function createCollectionInsertOutputSchema<T extends z.ZodTypeAny>(\n entitySchema: T,\n) {\n return z.object({\n item: entitySchema.describe(\"The created entity with generated id\"),\n });\n}\n\n/**\n * Factory function to create update input schema\n */\nexport function createCollectionUpdateInputSchema<T extends z.ZodTypeAny>(\n entitySchema: T,\n) {\n return z.object({\n id: z.string().describe(\"ID of the entity to update\"),\n data: (entitySchema as unknown as z.AnyZodObject)\n .partial()\n .describe(\"Partial entity data to update\"),\n });\n}\n\n/**\n * Factory function to create update output schema\n */\nexport function createCollectionUpdateOutputSchema<T extends z.ZodTypeAny>(\n entitySchema: T,\n) {\n return z.object({\n item: entitySchema.describe(\"The updated entity\"),\n });\n}\n\n/**\n * Delete input schema\n */\nexport const CollectionDeleteInputSchema = z.object({\n id: z.string().describe(\"ID of the entity to delete\"),\n});\n\n/**\n * Delete output schema\n */\nexport const CollectionDeleteOutputSchema = z.object({\n success: z.boolean().describe(\"Whether the deletion was successful\"),\n id: z.string().describe(\"ID of the deleted entity\"),\n});\n\n/**\n * Options for creating collection bindings\n */\nexport interface CollectionBindingOptions {\n /**\n * If true, only LIST and GET operations will be included (read-only collection)\n * @default false\n */\n readOnly?: boolean;\n}\n\n/**\n * Creates generic collection bindings for a specific entity type\n *\n * This function generates standardized tool bindings that work with any collection/table\n * by accepting a custom entity schema and collection name. The bindings provide:\n * - DECO_COLLECTION_{NAME}_LIST - Query/search entities with filtering and sorting (required)\n * - DECO_COLLECTION_{NAME}_GET - Get a single entity by ID (required)\n * - DECO_COLLECTION_{NAME}_INSERT - Create a new entity (optional, excluded if readOnly=true)\n * - DECO_COLLECTION_{NAME}_UPDATE - Update an existing entity (optional, excluded if readOnly=true)\n * - DECO_COLLECTION_{NAME}_DELETE - Delete an entity (optional, excluded if readOnly=true)\n *\n * @param collectionName - The name of the collection/table (e.g., \"users\", \"products\", \"orders\")\n * @param entitySchema - The Zod schema for the entity type (must extend BaseCollectionEntitySchema)\n * @param options - Optional configuration for the collection bindings\n * @returns Array of tool bindings for Collection CRUD + Query operations\n *\n * @example\n * ```typescript\n * const UserSchema = z.object({\n * id: z.string(),\n * title: z.string(),\n * created_at: z.string().datetime(),\n * updated_at: z.string().datetime(),\n * created_by: z.string().optional(),\n * updated_by: z.string().optional(),\n * email: z.string().email(),\n * });\n *\n * // Full CRUD collection\n * const USER_COLLECTION_BINDING = createCollectionBindings(\"users\", UserSchema);\n *\n * // Read-only collection (only LIST and GET)\n * const READONLY_COLLECTION_BINDING = createCollectionBindings(\"products\", ProductSchema, { readOnly: true });\n * ```\n */\nexport function createCollectionBindings<\n TEntitySchema extends BaseCollectionEntitySchemaType,\n>(\n collectionName: string,\n entitySchema: TEntitySchema,\n options?: CollectionBindingOptions,\n) {\n const upperName = collectionName.toUpperCase();\n const readOnly = options?.readOnly ?? false;\n\n const bindings: ToolBinder[] = [\n {\n name: `DECO_COLLECTION_${upperName}_LIST` as const,\n inputSchema: CollectionListInputSchema,\n outputSchema: createCollectionListOutputSchema(entitySchema),\n },\n {\n name: `DECO_COLLECTION_${upperName}_GET` as const,\n inputSchema: CollectionGetInputSchema,\n outputSchema: createCollectionGetOutputSchema(entitySchema),\n },\n ];\n\n // Only include mutation operations if not read-only\n if (!readOnly) {\n bindings.push(\n {\n name: `DECO_COLLECTION_${upperName}_INSERT` as const,\n inputSchema: createCollectionInsertInputSchema(entitySchema),\n outputSchema: createCollectionInsertOutputSchema(entitySchema),\n opt: true,\n },\n {\n name: `DECO_COLLECTION_${upperName}_UPDATE` as const,\n inputSchema: createCollectionUpdateInputSchema(entitySchema),\n outputSchema: createCollectionUpdateOutputSchema(entitySchema),\n opt: true,\n },\n {\n name: `DECO_COLLECTION_${upperName}_DELETE` as const,\n inputSchema: CollectionDeleteInputSchema,\n outputSchema: CollectionDeleteOutputSchema,\n opt: true,\n },\n );\n }\n\n return bindings satisfies readonly ToolBinder[];\n}\n\n/**\n * Type helper to extract the collection binding type\n */\nexport type CollectionBinding<\n TEntitySchema extends BaseCollectionEntitySchemaType,\n> = ReturnType<typeof createCollectionBindings<TEntitySchema>>;\n\n/**\n * Type helper to extract tool names from a collection binding\n */\nexport type CollectionTools<\n TEntitySchema extends BaseCollectionEntitySchemaType,\n> = CollectionBinding<TEntitySchema>[number][\"name\"];\n\n// Export types for TypeScript usage\nexport type CollectionListInput = z.infer<typeof CollectionListInputSchema>;\nexport type CollectionGetInput = z.infer<typeof CollectionGetInputSchema>;\nexport type CollectionDeleteInput = z.infer<typeof CollectionDeleteInputSchema>;\nexport type CollectionDeleteOutput = z.infer<\n typeof CollectionDeleteOutputSchema\n>;\nexport type OrderByExpression = z.infer<typeof OrderByExpressionSchema>;\n"]}
package/dist/index.js CHANGED
@@ -36,6 +36,7 @@ function createBindingChecker(binderTools) {
36
36
  }
37
37
  const binderInputSchema = normalizeSchema(binderTool.inputSchema);
38
38
  const toolInputSchema = normalizeSchema(matchedTool.inputSchema);
39
+ console.log(JSON.stringify(binderInputSchema, null, 2));
39
40
  if (binderInputSchema && toolInputSchema) {
40
41
  try {
41
42
  const inputDiff = await diffSchemas({
@@ -46,6 +47,7 @@ function createBindingChecker(binderTools) {
46
47
  return false;
47
48
  }
48
49
  } catch (error) {
50
+ console.error("Schema diff failed", error);
49
51
  return false;
50
52
  }
51
53
  } else if (binderInputSchema && !toolInputSchema) {
@@ -63,6 +65,7 @@ function createBindingChecker(binderTools) {
63
65
  return false;
64
66
  }
65
67
  } catch (error) {
68
+ console.error("Schema diff failed", error);
66
69
  return false;
67
70
  }
68
71
  } else if (binderOutputSchema && !toolOutputSchema) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/binder.ts"],"names":["jsonSchema"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Core Binder Types and Utilities\n *\n * This module provides the core types and utilities for the bindings system.\n * Bindings define standardized interfaces that integrations (MCPs) can implement.\n */\n\nimport type { ZodType } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { diffSchemas } from \"json-schema-diff\";\n\n/**\n * ToolBinder defines a single tool within a binding.\n * It specifies the tool name, input/output schemas, and whether it's optional.\n *\n * @template TName - The tool name (can be a string or RegExp for pattern matching)\n * @template TInput - The input type (inferred from inputSchema)\n * @template TReturn - The return type (inferred from outputSchema)\n */\nexport interface ToolBinder<\n TName extends string | RegExp = string,\n // biome-ignore lint/suspicious/noExplicitAny: Generic type parameter\n TInput = any,\n TReturn extends object | null | boolean = object,\n> {\n /** The name of the tool (e.g., \"DECO_CHAT_CHANNELS_JOIN\") */\n name: TName;\n\n /** Zod schema for validating tool input */\n inputSchema: ZodType<TInput>;\n\n /** Optional Zod schema for validating tool output */\n outputSchema?: ZodType<TReturn>;\n\n /**\n * Whether this tool is optional in the binding.\n * If true, an implementation doesn't need to provide this tool.\n */\n opt?: true;\n}\n\n/**\n * Binder represents a collection of tool definitions that form a binding.\n * A binding is like a TypeScript interface - it defines what tools must be implemented.\n *\n * @template TDefinition - Array of ToolBinder definitions\n *\n * @example\n * ```ts\n * const MY_BINDING = [{\n * name: \"MY_TOOL\" as const,\n * inputSchema: z.object({ id: z.string() }),\n * outputSchema: z.object({ success: z.boolean() }),\n * }] as const satisfies Binder;\n * ```\n */\nexport type Binder<\n TDefinition extends readonly ToolBinder[] = readonly ToolBinder[],\n> = TDefinition;\n\n/**\n * Tool with schemas for validation\n */\nexport interface ToolWithSchemas {\n name: string;\n inputSchema?: ZodType<any> | Record<string, unknown>;\n outputSchema?: ZodType<any> | Record<string, unknown>;\n}\n\n/**\n * Converts a schema to JSON Schema format if it's a Zod schema\n */\nfunction normalizeSchema(schema: any): Record<string, unknown> | undefined {\n if (!schema) return undefined;\n\n // If it's a Zod schema (has _def property), convert it\n if (schema._def) {\n const jsonSchema = zodToJsonSchema(schema, {\n // Don't add additionalProperties: false to allow structural compatibility\n $refStrategy: \"none\",\n }) as Record<string, unknown>;\n\n // Remove additionalProperties constraint to allow subtyping\n if (jsonSchema.type === \"object\") {\n delete jsonSchema.additionalProperties;\n }\n\n return jsonSchema;\n }\n\n // Otherwise assume it's already a JSON Schema\n const jsonSchema = schema as Record<string, unknown>;\n\n // Remove additionalProperties constraint if present\n if (jsonSchema.type === \"object\" && \"additionalProperties\" in jsonSchema) {\n const copy = { ...jsonSchema };\n delete copy.additionalProperties;\n return copy;\n }\n\n return jsonSchema;\n}\n\n/**\n * Binding checker interface\n */\nexport interface BindingChecker {\n /**\n * Check if a set of tools implements the binding with full schema validation.\n *\n * Validates:\n * - Tool name matches (exact or regex)\n * - Input schema: Tool accepts what binder requires (no removals from binder to tool)\n * - Output schema: Tool provides what binder expects (no removals from tool to binder)\n *\n * @param tools - Array of tools with names and schemas\n * @returns Promise<boolean> - true if all tools implement the binding correctly\n */\n isImplementedBy: (tools: ToolWithSchemas[]) => Promise<boolean>;\n}\n\n/**\n * Creates a binding checker with full schema validation using json-schema-diff.\n *\n * This performs strict compatibility checking:\n * - For input schemas: Validates that the tool can accept what the binder requires\n * - For output schemas: Validates that the tool provides what the binder expects\n *\n * @param binderTools - The binding definition to check against\n * @returns A binding checker with an async isImplementedBy method\n *\n * @example\n * ```ts\n * const checker = createBindingChecker(MY_BINDING);\n * const isCompatible = await checker.isImplementedBy(availableTools);\n * ```\n */\nexport function createBindingChecker<TDefinition extends readonly ToolBinder[]>(\n binderTools: TDefinition,\n): BindingChecker {\n return {\n isImplementedBy: async (tools: ToolWithSchemas[]) => {\n for (const binderTool of binderTools) {\n // Find matching tool by name (exact or regex)\n const pattern =\n typeof binderTool.name === \"string\"\n ? new RegExp(`^${binderTool.name}$`)\n : binderTool.name;\n\n const matchedTool = tools.find((t) => pattern.test(t.name));\n\n // Skip optional tools that aren't present\n if (!matchedTool && binderTool.opt) {\n continue;\n }\n\n // Required tool not found\n if (!matchedTool) {\n return false;\n }\n\n // === INPUT SCHEMA VALIDATION ===\n // Tool must accept what binder requires\n // Check: binder (source) -> tool (destination)\n // If removals found, tool doesn't accept something binder requires\n const binderInputSchema = normalizeSchema(binderTool.inputSchema);\n const toolInputSchema = normalizeSchema(matchedTool.inputSchema);\n\n if (binderInputSchema && toolInputSchema) {\n try {\n const inputDiff = await diffSchemas({\n sourceSchema: binderInputSchema,\n destinationSchema: toolInputSchema,\n });\n\n // If something was removed from binder to tool, tool can't accept it\n if (inputDiff.removalsFound) {\n return false;\n }\n } catch (error) {\n // Schema diff failed - consider incompatible\n return false;\n }\n } else if (binderInputSchema && !toolInputSchema) {\n // Binder requires input schema but tool doesn't have one\n return false;\n }\n\n // === OUTPUT SCHEMA VALIDATION ===\n // Tool must provide what binder expects (but can provide more)\n // Check: binder (source) -> tool (destination)\n // If removals found, tool doesn't provide something binder expects\n const binderOutputSchema = normalizeSchema(binderTool.outputSchema);\n const toolOutputSchema = normalizeSchema(matchedTool.outputSchema);\n\n if (binderOutputSchema && toolOutputSchema) {\n try {\n const outputDiff = await diffSchemas({\n sourceSchema: binderOutputSchema,\n destinationSchema: toolOutputSchema,\n });\n\n // If something was removed from binder to tool, tool doesn't provide it\n if (outputDiff.removalsFound) {\n return false;\n }\n } catch (error) {\n // Schema diff failed - consider incompatible\n return false;\n }\n } else if (binderOutputSchema && !toolOutputSchema) {\n // Binder expects output schema but tool doesn't have one\n return false;\n }\n }\n\n return true;\n },\n };\n}\n\n"]}
1
+ {"version":3,"sources":["../src/core/binder.ts"],"names":["jsonSchema"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Core Binder Types and Utilities\n *\n * This module provides the core types and utilities for the bindings system.\n * Bindings define standardized interfaces that integrations (MCPs) can implement.\n */\n\nimport type { ZodType } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { diffSchemas } from \"json-schema-diff\";\n\n/**\n * ToolBinder defines a single tool within a binding.\n * It specifies the tool name, input/output schemas, and whether it's optional.\n *\n * @template TName - The tool name (can be a string or RegExp for pattern matching)\n * @template TInput - The input type (inferred from inputSchema)\n * @template TReturn - The return type (inferred from outputSchema)\n */\nexport interface ToolBinder<\n TName extends string | RegExp = string,\n // biome-ignore lint/suspicious/noExplicitAny: Generic type parameter\n TInput = any,\n TReturn extends object | null | boolean = object,\n> {\n /** The name of the tool (e.g., \"DECO_CHAT_CHANNELS_JOIN\") */\n name: TName;\n\n /** Zod schema for validating tool input */\n inputSchema: ZodType<TInput>;\n\n /** Optional Zod schema for validating tool output */\n outputSchema?: ZodType<TReturn>;\n\n /**\n * Whether this tool is optional in the binding.\n * If true, an implementation doesn't need to provide this tool.\n */\n opt?: true;\n}\n\n/**\n * Binder represents a collection of tool definitions that form a binding.\n * A binding is like a TypeScript interface - it defines what tools must be implemented.\n *\n * @template TDefinition - Array of ToolBinder definitions\n *\n * @example\n * ```ts\n * const MY_BINDING = [{\n * name: \"MY_TOOL\" as const,\n * inputSchema: z.object({ id: z.string() }),\n * outputSchema: z.object({ success: z.boolean() }),\n * }] as const satisfies Binder;\n * ```\n */\nexport type Binder<\n TDefinition extends readonly ToolBinder[] = readonly ToolBinder[],\n> = TDefinition;\n\n/**\n * Tool with schemas for validation\n */\nexport interface ToolWithSchemas {\n name: string;\n inputSchema?: ZodType<any> | Record<string, unknown>;\n outputSchema?: ZodType<any> | Record<string, unknown>;\n}\n\n/**\n * Converts a schema to JSON Schema format if it's a Zod schema\n */\nfunction normalizeSchema(schema: any): Record<string, unknown> | undefined {\n if (!schema) return undefined;\n\n // If it's a Zod schema (has _def property), convert it\n if (schema._def) {\n const jsonSchema = zodToJsonSchema(schema, {\n // Don't add additionalProperties: false to allow structural compatibility\n $refStrategy: \"none\",\n }) as Record<string, unknown>;\n\n // Remove additionalProperties constraint to allow subtyping\n if (jsonSchema.type === \"object\") {\n delete jsonSchema.additionalProperties;\n }\n\n return jsonSchema;\n }\n\n // Otherwise assume it's already a JSON Schema\n const jsonSchema = schema as Record<string, unknown>;\n\n // Remove additionalProperties constraint if present\n if (jsonSchema.type === \"object\" && \"additionalProperties\" in jsonSchema) {\n const copy = { ...jsonSchema };\n delete copy.additionalProperties;\n return copy;\n }\n\n return jsonSchema;\n}\n\n/**\n * Binding checker interface\n */\nexport interface BindingChecker {\n /**\n * Check if a set of tools implements the binding with full schema validation.\n *\n * Validates:\n * - Tool name matches (exact or regex)\n * - Input schema: Tool accepts what binder requires (no removals from binder to tool)\n * - Output schema: Tool provides what binder expects (no removals from tool to binder)\n *\n * @param tools - Array of tools with names and schemas\n * @returns Promise<boolean> - true if all tools implement the binding correctly\n */\n isImplementedBy: (tools: ToolWithSchemas[]) => Promise<boolean>;\n}\n\n/**\n * Creates a binding checker with full schema validation using json-schema-diff.\n *\n * This performs strict compatibility checking:\n * - For input schemas: Validates that the tool can accept what the binder requires\n * - For output schemas: Validates that the tool provides what the binder expects\n *\n * @param binderTools - The binding definition to check against\n * @returns A binding checker with an async isImplementedBy method\n *\n * @example\n * ```ts\n * const checker = createBindingChecker(MY_BINDING);\n * const isCompatible = await checker.isImplementedBy(availableTools);\n * ```\n */\nexport function createBindingChecker<TDefinition extends readonly ToolBinder[]>(\n binderTools: TDefinition,\n): BindingChecker {\n return {\n isImplementedBy: async (tools: ToolWithSchemas[]) => {\n for (const binderTool of binderTools) {\n // Find matching tool by name (exact or regex)\n const pattern = typeof binderTool.name === \"string\"\n ? new RegExp(`^${binderTool.name}$`)\n : binderTool.name;\n\n const matchedTool = tools.find((t) => pattern.test(t.name));\n\n // Skip optional tools that aren't present\n if (!matchedTool && binderTool.opt) {\n continue;\n }\n\n // Required tool not found\n if (!matchedTool) {\n return false;\n }\n\n // === INPUT SCHEMA VALIDATION ===\n // Tool must accept what binder requires\n // Check: binder (source) -> tool (destination)\n // If removals found, tool doesn't accept something binder requires\n const binderInputSchema = normalizeSchema(binderTool.inputSchema);\n const toolInputSchema = normalizeSchema(matchedTool.inputSchema);\n\n console.log(JSON.stringify(binderInputSchema, null, 2));\n\n if (binderInputSchema && toolInputSchema) {\n try {\n const inputDiff = await diffSchemas({\n sourceSchema: binderInputSchema,\n destinationSchema: toolInputSchema,\n });\n\n // If something was removed from binder to tool, tool can't accept it\n if (inputDiff.removalsFound) {\n return false;\n }\n } catch (error) {\n console.error(\"Schema diff failed\", error);\n // Schema diff failed - consider incompatible\n return false;\n }\n } else if (binderInputSchema && !toolInputSchema) {\n // Binder requires input schema but tool doesn't have one\n return false;\n }\n\n // === OUTPUT SCHEMA VALIDATION ===\n // Tool must provide what binder expects (but can provide more)\n // Check: binder (source) -> tool (destination)\n // If removals found, tool doesn't provide something binder expects\n const binderOutputSchema = normalizeSchema(binderTool.outputSchema);\n const toolOutputSchema = normalizeSchema(matchedTool.outputSchema);\n\n if (binderOutputSchema && toolOutputSchema) {\n try {\n const outputDiff = await diffSchemas({\n sourceSchema: binderOutputSchema,\n destinationSchema: toolOutputSchema,\n });\n\n // If something was removed from binder to tool, tool doesn't provide it\n if (outputDiff.removalsFound) {\n return false;\n }\n } catch (error) {\n console.error(\"Schema diff failed\", error);\n // Schema diff failed - consider incompatible\n return false;\n }\n } else if (binderOutputSchema && !toolOutputSchema) {\n // Binder expects output schema but tool doesn't have one\n return false;\n }\n }\n\n return true;\n },\n };\n}\n"]}
@@ -0,0 +1,390 @@
1
+ import { z } from 'zod';
2
+ import { ToolBinder } from '../index.js';
3
+
4
+ /**
5
+ * Collection Bindings
6
+ *
7
+ * This module provides standardized tool bindings for Collections, representing
8
+ * SQL table-like structures with CRUD + Search operations compatible with TanStack DB.
9
+ *
10
+ * Key Features:
11
+ * - Generic collection bindings that work with any entity type
12
+ * - Standardized tool naming: `DECO_COLLECTION_{COLLECTION}_*`
13
+ * - Compatible with TanStack DB query-collection
14
+ * - Full TypeScript support with proper type constraints
15
+ * - Support for filtering, sorting, and pagination
16
+ * - Simple id and title fields for human-readable identification
17
+ */
18
+ /**
19
+ * Base schema for collection entities
20
+ * All collection entities must have an id, title, and audit trail fields
21
+ */
22
+ declare const BaseCollectionEntitySchema: z.ZodObject<{
23
+ id: z.ZodString;
24
+ title: z.ZodString;
25
+ created_at: z.ZodString;
26
+ updated_at: z.ZodString;
27
+ created_by: z.ZodOptional<z.ZodString>;
28
+ updated_by: z.ZodOptional<z.ZodString>;
29
+ }, "strip", z.ZodTypeAny, {
30
+ id: string;
31
+ title: string;
32
+ created_at: string;
33
+ updated_at: string;
34
+ created_by?: string | undefined;
35
+ updated_by?: string | undefined;
36
+ }, {
37
+ id: string;
38
+ title: string;
39
+ created_at: string;
40
+ updated_at: string;
41
+ created_by?: string | undefined;
42
+ updated_by?: string | undefined;
43
+ }>;
44
+ /**
45
+ * Type helper for BaseCollectionEntitySchema
46
+ */
47
+ type BaseCollectionEntitySchemaType = typeof BaseCollectionEntitySchema;
48
+ /**
49
+ * Where expression schema for filtering
50
+ * Supports TanStack DB predicate push-down patterns
51
+ */
52
+ declare const WhereExpressionSchema: z.ZodUnion<[z.ZodObject<{
53
+ field: z.ZodArray<z.ZodString, "many">;
54
+ operator: z.ZodEnum<["eq", "gt", "gte", "lt", "lte", "in", "like", "contains"]>;
55
+ value: z.ZodUnknown;
56
+ }, "strip", z.ZodTypeAny, {
57
+ field: string[];
58
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
59
+ value?: unknown;
60
+ }, {
61
+ field: string[];
62
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
63
+ value?: unknown;
64
+ }>, z.ZodObject<{
65
+ operator: z.ZodEnum<["and", "or", "not"]>;
66
+ conditions: z.ZodArray<z.ZodObject<{
67
+ field: z.ZodArray<z.ZodString, "many">;
68
+ operator: z.ZodEnum<["eq", "gt", "gte", "lt", "lte", "in", "like", "contains"]>;
69
+ value: z.ZodUnknown;
70
+ }, "strip", z.ZodTypeAny, {
71
+ field: string[];
72
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
73
+ value?: unknown;
74
+ }, {
75
+ field: string[];
76
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
77
+ value?: unknown;
78
+ }>, "many">;
79
+ }, "strip", z.ZodTypeAny, {
80
+ operator: "and" | "or" | "not";
81
+ conditions: {
82
+ field: string[];
83
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
84
+ value?: unknown;
85
+ }[];
86
+ }, {
87
+ operator: "and" | "or" | "not";
88
+ conditions: {
89
+ field: string[];
90
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
91
+ value?: unknown;
92
+ }[];
93
+ }>]>;
94
+ /**
95
+ * Where expression type for filtering
96
+ * Derived from WhereExpressionSchema
97
+ */
98
+ type WhereExpression = z.infer<typeof WhereExpressionSchema>;
99
+ /**
100
+ * Order by expression for sorting
101
+ */
102
+ declare const OrderByExpressionSchema: z.ZodObject<{
103
+ field: z.ZodArray<z.ZodString, "many">;
104
+ direction: z.ZodEnum<["asc", "desc"]>;
105
+ nulls: z.ZodOptional<z.ZodEnum<["first", "last"]>>;
106
+ }, "strip", z.ZodTypeAny, {
107
+ field: string[];
108
+ direction: "asc" | "desc";
109
+ nulls?: "first" | "last" | undefined;
110
+ }, {
111
+ field: string[];
112
+ direction: "asc" | "desc";
113
+ nulls?: "first" | "last" | undefined;
114
+ }>;
115
+ /**
116
+ * List/Query input schema for collections
117
+ * Compatible with TanStack DB LoadSubsetOptions
118
+ */
119
+ declare const CollectionListInputSchema: z.ZodObject<{
120
+ where: z.ZodOptional<z.ZodUnion<[z.ZodObject<{
121
+ field: z.ZodArray<z.ZodString, "many">;
122
+ operator: z.ZodEnum<["eq", "gt", "gte", "lt", "lte", "in", "like", "contains"]>;
123
+ value: z.ZodUnknown;
124
+ }, "strip", z.ZodTypeAny, {
125
+ field: string[];
126
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
127
+ value?: unknown;
128
+ }, {
129
+ field: string[];
130
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
131
+ value?: unknown;
132
+ }>, z.ZodObject<{
133
+ operator: z.ZodEnum<["and", "or", "not"]>;
134
+ conditions: z.ZodArray<z.ZodObject<{
135
+ field: z.ZodArray<z.ZodString, "many">;
136
+ operator: z.ZodEnum<["eq", "gt", "gte", "lt", "lte", "in", "like", "contains"]>;
137
+ value: z.ZodUnknown;
138
+ }, "strip", z.ZodTypeAny, {
139
+ field: string[];
140
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
141
+ value?: unknown;
142
+ }, {
143
+ field: string[];
144
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
145
+ value?: unknown;
146
+ }>, "many">;
147
+ }, "strip", z.ZodTypeAny, {
148
+ operator: "and" | "or" | "not";
149
+ conditions: {
150
+ field: string[];
151
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
152
+ value?: unknown;
153
+ }[];
154
+ }, {
155
+ operator: "and" | "or" | "not";
156
+ conditions: {
157
+ field: string[];
158
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
159
+ value?: unknown;
160
+ }[];
161
+ }>]>>;
162
+ orderBy: z.ZodOptional<z.ZodArray<z.ZodObject<{
163
+ field: z.ZodArray<z.ZodString, "many">;
164
+ direction: z.ZodEnum<["asc", "desc"]>;
165
+ nulls: z.ZodOptional<z.ZodEnum<["first", "last"]>>;
166
+ }, "strip", z.ZodTypeAny, {
167
+ field: string[];
168
+ direction: "asc" | "desc";
169
+ nulls?: "first" | "last" | undefined;
170
+ }, {
171
+ field: string[];
172
+ direction: "asc" | "desc";
173
+ nulls?: "first" | "last" | undefined;
174
+ }>, "many">>;
175
+ limit: z.ZodOptional<z.ZodNumber>;
176
+ offset: z.ZodOptional<z.ZodNumber>;
177
+ }, "strip", z.ZodTypeAny, {
178
+ where?: {
179
+ field: string[];
180
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
181
+ value?: unknown;
182
+ } | {
183
+ operator: "and" | "or" | "not";
184
+ conditions: {
185
+ field: string[];
186
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
187
+ value?: unknown;
188
+ }[];
189
+ } | undefined;
190
+ orderBy?: {
191
+ field: string[];
192
+ direction: "asc" | "desc";
193
+ nulls?: "first" | "last" | undefined;
194
+ }[] | undefined;
195
+ limit?: number | undefined;
196
+ offset?: number | undefined;
197
+ }, {
198
+ where?: {
199
+ field: string[];
200
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
201
+ value?: unknown;
202
+ } | {
203
+ operator: "and" | "or" | "not";
204
+ conditions: {
205
+ field: string[];
206
+ operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
207
+ value?: unknown;
208
+ }[];
209
+ } | undefined;
210
+ orderBy?: {
211
+ field: string[];
212
+ direction: "asc" | "desc";
213
+ nulls?: "first" | "last" | undefined;
214
+ }[] | undefined;
215
+ limit?: number | undefined;
216
+ offset?: number | undefined;
217
+ }>;
218
+ /**
219
+ * Factory function to create list output schema for a specific collection type
220
+ */
221
+ declare function createCollectionListOutputSchema<T extends z.ZodTypeAny>(entitySchema: T): z.ZodObject<{
222
+ items: z.ZodArray<T, "many">;
223
+ totalCount: z.ZodOptional<z.ZodNumber>;
224
+ hasMore: z.ZodOptional<z.ZodBoolean>;
225
+ }, "strip", z.ZodTypeAny, {
226
+ items: T["_output"][];
227
+ totalCount?: number | undefined;
228
+ hasMore?: boolean | undefined;
229
+ }, {
230
+ items: T["_input"][];
231
+ totalCount?: number | undefined;
232
+ hasMore?: boolean | undefined;
233
+ }>;
234
+ /**
235
+ * Get by ID input schema
236
+ */
237
+ declare const CollectionGetInputSchema: z.ZodObject<{
238
+ id: z.ZodString;
239
+ }, "strip", z.ZodTypeAny, {
240
+ id: string;
241
+ }, {
242
+ id: string;
243
+ }>;
244
+ /**
245
+ * Factory function to create get output schema
246
+ */
247
+ declare function createCollectionGetOutputSchema<T extends z.ZodTypeAny>(entitySchema: T): z.ZodObject<{
248
+ item: z.ZodNullable<T>;
249
+ }, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
250
+ item: z.ZodNullable<T>;
251
+ }>, any> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never, z.baseObjectInputType<{
252
+ item: z.ZodNullable<T>;
253
+ }> extends infer T_2 ? { [k_1 in keyof T_2]: T_2[k_1]; } : never>;
254
+ /**
255
+ * Factory function to create insert input schema
256
+ */
257
+ declare function createCollectionInsertInputSchema<T extends z.ZodTypeAny>(entitySchema: T): z.ZodObject<{
258
+ data: T;
259
+ }, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
260
+ data: T;
261
+ }>, any> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never, z.baseObjectInputType<{
262
+ data: T;
263
+ }> extends infer T_2 ? { [k_1 in keyof T_2]: T_2[k_1]; } : never>;
264
+ /**
265
+ * Factory function to create insert output schema
266
+ */
267
+ declare function createCollectionInsertOutputSchema<T extends z.ZodTypeAny>(entitySchema: T): z.ZodObject<{
268
+ item: T;
269
+ }, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
270
+ item: T;
271
+ }>, any> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never, z.baseObjectInputType<{
272
+ item: T;
273
+ }> extends infer T_2 ? { [k_1 in keyof T_2]: T_2[k_1]; } : never>;
274
+ /**
275
+ * Factory function to create update input schema
276
+ */
277
+ declare function createCollectionUpdateInputSchema<T extends z.ZodTypeAny>(entitySchema: T): z.ZodObject<{
278
+ id: z.ZodString;
279
+ data: z.ZodObject<{
280
+ [x: string]: z.ZodOptional<any>;
281
+ }, any, any, {
282
+ [x: string]: any;
283
+ }, {
284
+ [x: string]: any;
285
+ }>;
286
+ }, "strip", z.ZodTypeAny, {
287
+ id: string;
288
+ data: {
289
+ [x: string]: any;
290
+ };
291
+ }, {
292
+ id: string;
293
+ data: {
294
+ [x: string]: any;
295
+ };
296
+ }>;
297
+ /**
298
+ * Factory function to create update output schema
299
+ */
300
+ declare function createCollectionUpdateOutputSchema<T extends z.ZodTypeAny>(entitySchema: T): z.ZodObject<{
301
+ item: T;
302
+ }, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
303
+ item: T;
304
+ }>, any> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never, z.baseObjectInputType<{
305
+ item: T;
306
+ }> extends infer T_2 ? { [k_1 in keyof T_2]: T_2[k_1]; } : never>;
307
+ /**
308
+ * Delete input schema
309
+ */
310
+ declare const CollectionDeleteInputSchema: z.ZodObject<{
311
+ id: z.ZodString;
312
+ }, "strip", z.ZodTypeAny, {
313
+ id: string;
314
+ }, {
315
+ id: string;
316
+ }>;
317
+ /**
318
+ * Delete output schema
319
+ */
320
+ declare const CollectionDeleteOutputSchema: z.ZodObject<{
321
+ success: z.ZodBoolean;
322
+ id: z.ZodString;
323
+ }, "strip", z.ZodTypeAny, {
324
+ id: string;
325
+ success: boolean;
326
+ }, {
327
+ id: string;
328
+ success: boolean;
329
+ }>;
330
+ /**
331
+ * Options for creating collection bindings
332
+ */
333
+ interface CollectionBindingOptions {
334
+ /**
335
+ * If true, only LIST and GET operations will be included (read-only collection)
336
+ * @default false
337
+ */
338
+ readOnly?: boolean;
339
+ }
340
+ /**
341
+ * Creates generic collection bindings for a specific entity type
342
+ *
343
+ * This function generates standardized tool bindings that work with any collection/table
344
+ * by accepting a custom entity schema and collection name. The bindings provide:
345
+ * - DECO_COLLECTION_{NAME}_LIST - Query/search entities with filtering and sorting (required)
346
+ * - DECO_COLLECTION_{NAME}_GET - Get a single entity by ID (required)
347
+ * - DECO_COLLECTION_{NAME}_INSERT - Create a new entity (optional, excluded if readOnly=true)
348
+ * - DECO_COLLECTION_{NAME}_UPDATE - Update an existing entity (optional, excluded if readOnly=true)
349
+ * - DECO_COLLECTION_{NAME}_DELETE - Delete an entity (optional, excluded if readOnly=true)
350
+ *
351
+ * @param collectionName - The name of the collection/table (e.g., "users", "products", "orders")
352
+ * @param entitySchema - The Zod schema for the entity type (must extend BaseCollectionEntitySchema)
353
+ * @param options - Optional configuration for the collection bindings
354
+ * @returns Array of tool bindings for Collection CRUD + Query operations
355
+ *
356
+ * @example
357
+ * ```typescript
358
+ * const UserSchema = z.object({
359
+ * id: z.string(),
360
+ * title: z.string(),
361
+ * created_at: z.string().datetime(),
362
+ * updated_at: z.string().datetime(),
363
+ * created_by: z.string().optional(),
364
+ * updated_by: z.string().optional(),
365
+ * email: z.string().email(),
366
+ * });
367
+ *
368
+ * // Full CRUD collection
369
+ * const USER_COLLECTION_BINDING = createCollectionBindings("users", UserSchema);
370
+ *
371
+ * // Read-only collection (only LIST and GET)
372
+ * const READONLY_COLLECTION_BINDING = createCollectionBindings("products", ProductSchema, { readOnly: true });
373
+ * ```
374
+ */
375
+ declare function createCollectionBindings<TEntitySchema extends BaseCollectionEntitySchemaType>(collectionName: string, entitySchema: TEntitySchema, options?: CollectionBindingOptions): ToolBinder<string, any, object>[];
376
+ /**
377
+ * Type helper to extract the collection binding type
378
+ */
379
+ type CollectionBinding<TEntitySchema extends BaseCollectionEntitySchemaType> = ReturnType<typeof createCollectionBindings<TEntitySchema>>;
380
+ /**
381
+ * Type helper to extract tool names from a collection binding
382
+ */
383
+ type CollectionTools<TEntitySchema extends BaseCollectionEntitySchemaType> = CollectionBinding<TEntitySchema>[number]["name"];
384
+ type CollectionListInput = z.infer<typeof CollectionListInputSchema>;
385
+ type CollectionGetInput = z.infer<typeof CollectionGetInputSchema>;
386
+ type CollectionDeleteInput = z.infer<typeof CollectionDeleteInputSchema>;
387
+ type CollectionDeleteOutput = z.infer<typeof CollectionDeleteOutputSchema>;
388
+ type OrderByExpression = z.infer<typeof OrderByExpressionSchema>;
389
+
390
+ export { BaseCollectionEntitySchema, type BaseCollectionEntitySchemaType, type CollectionBinding, type CollectionBindingOptions, type CollectionDeleteInput, CollectionDeleteInputSchema, type CollectionDeleteOutput, CollectionDeleteOutputSchema, type CollectionGetInput, CollectionGetInputSchema, type CollectionListInput, CollectionListInputSchema, type CollectionTools, type OrderByExpression, OrderByExpressionSchema, type WhereExpression, WhereExpressionSchema, createCollectionBindings, createCollectionGetOutputSchema, createCollectionInsertInputSchema, createCollectionInsertOutputSchema, createCollectionListOutputSchema, createCollectionUpdateInputSchema, createCollectionUpdateOutputSchema };
@@ -0,0 +1,3 @@
1
+ export { BaseCollectionEntitySchema, CollectionDeleteInputSchema, CollectionDeleteOutputSchema, CollectionGetInputSchema, CollectionListInputSchema, OrderByExpressionSchema, WhereExpressionSchema, createCollectionBindings, createCollectionGetOutputSchema, createCollectionInsertInputSchema, createCollectionInsertOutputSchema, createCollectionListOutputSchema, createCollectionUpdateInputSchema, createCollectionUpdateOutputSchema } from '../chunk-L7E6ONLJ.js';
2
+ //# sourceMappingURL=collections.js.map
3
+ //# sourceMappingURL=collections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"collections.js"}
@@ -0,0 +1,32 @@
1
+ import { ToolBinder } from '../index.js';
2
+ import 'zod';
3
+
4
+ /**
5
+ * Models Well-Known Binding
6
+ *
7
+ * Defines the interface for AI model providers.
8
+ * Any MCP that implements this binding can provide AI models and streaming endpoints.
9
+ *
10
+ * This binding uses collection bindings for LIST and GET operations (read-only).
11
+ * Streaming endpoint information is included directly in the model entity schema.
12
+ */
13
+ /**
14
+ * MODELS Collection Binding
15
+ *
16
+ * Collection bindings for models (read-only).
17
+ * Provides LIST and GET operations for AI models.
18
+ */
19
+ declare const MODELS_COLLECTION_BINDING: ToolBinder<string, any, object>[];
20
+ /**
21
+ * MODELS Binding
22
+ *
23
+ * Defines the interface for AI model providers.
24
+ * Any MCP that implements this binding can provide AI models and streaming endpoints.
25
+ *
26
+ * Required tools:
27
+ * - DECO_COLLECTION_MODELS_LIST: List available AI models with their capabilities
28
+ * - DECO_COLLECTION_MODELS_GET: Get a single model by ID (includes streaming endpoint info)
29
+ */
30
+ declare const MODELS_BINDING: readonly ToolBinder<string, any, object>[];
31
+
32
+ export { MODELS_BINDING, MODELS_COLLECTION_BINDING };
@@ -0,0 +1,36 @@
1
+ import { BaseCollectionEntitySchema, createCollectionBindings } from '../chunk-L7E6ONLJ.js';
2
+ import { z } from 'zod';
3
+
4
+ var ModelSchema = BaseCollectionEntitySchema.extend({
5
+ // Model-specific fields
6
+ logo: z.string().nullable(),
7
+ description: z.string().nullable(),
8
+ capabilities: z.array(z.string()),
9
+ limits: z.object({
10
+ contextWindow: z.number(),
11
+ maxOutputTokens: z.number()
12
+ }).nullable(),
13
+ costs: z.object({
14
+ input: z.number(),
15
+ output: z.number()
16
+ }).nullable(),
17
+ // Streaming endpoint information
18
+ endpoint: z.object({
19
+ url: z.string().url(),
20
+ method: z.string().default("POST"),
21
+ contentType: z.string().default("application/json"),
22
+ stream: z.boolean().default(true)
23
+ }).nullable()
24
+ });
25
+ var MODELS_COLLECTION_BINDING = createCollectionBindings(
26
+ "models",
27
+ ModelSchema,
28
+ { readOnly: true }
29
+ );
30
+ var MODELS_BINDING = [
31
+ ...MODELS_COLLECTION_BINDING
32
+ ];
33
+
34
+ export { MODELS_BINDING, MODELS_COLLECTION_BINDING };
35
+ //# sourceMappingURL=models.js.map
36
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/well-known/models.ts"],"names":[],"mappings":";;;AAsBA,IAAM,WAAA,GAAc,2BAA2B,MAAA,CAAO;AAAA;AAAA,EAEpD,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,YAAA,EAAc,CAAA,CAAE,KAAA,CAAM,CAAA,CAAE,QAAQ,CAAA;AAAA,EAChC,MAAA,EAAQ,EAAE,MAAA,CAAO;AAAA,IACf,aAAA,EAAe,EAAE,MAAA,EAAO;AAAA,IACxB,eAAA,EAAiB,EAAE,MAAA;AAAO,GAC3B,EAAE,QAAA,EAAS;AAAA,EACZ,KAAA,EAAO,EAAE,MAAA,CAAO;AAAA,IACd,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,IAChB,MAAA,EAAQ,EAAE,MAAA;AAAO,GAClB,EAAE,QAAA,EAAS;AAAA;AAAA,EAEZ,QAAA,EAAU,EAAE,MAAA,CAAO;AAAA,IACjB,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI;AAAA,IACpB,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,MAAM,CAAA;AAAA,IACjC,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,kBAAkB,CAAA;AAAA,IAClD,MAAA,EAAQ,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,IAAI;AAAA,GACjC,EAAE,QAAA;AACL,CAAC,CAAA;AAQM,IAAM,yBAAA,GAA4B,wBAAA;AAAA,EACvC,QAAA;AAAA,EACA,WAAA;AAAA,EACA,EAAE,UAAU,IAAA;AACd;AAYO,IAAM,cAAA,GAAiB;AAAA,EAC5B,GAAG;AACL","file":"models.js","sourcesContent":["/**\n * Models Well-Known Binding\n *\n * Defines the interface for AI model providers.\n * Any MCP that implements this binding can provide AI models and streaming endpoints.\n *\n * This binding uses collection bindings for LIST and GET operations (read-only).\n * Streaming endpoint information is included directly in the model entity schema.\n */\n\nimport { z } from \"zod\";\nimport type { Binder } from \"../core/binder\";\nimport {\n BaseCollectionEntitySchema,\n createCollectionBindings,\n} from \"./collections\";\n\n/**\n * Model entity schema for AI models\n * Extends BaseCollectionEntitySchema with model-specific fields\n * Base schema already includes: id, title, created_at, updated_at, created_by, updated_by\n */\nconst ModelSchema = BaseCollectionEntitySchema.extend({\n // Model-specific fields\n logo: z.string().nullable(),\n description: z.string().nullable(),\n capabilities: z.array(z.string()),\n limits: z.object({\n contextWindow: z.number(),\n maxOutputTokens: z.number(),\n }).nullable(),\n costs: z.object({\n input: z.number(),\n output: z.number(),\n }).nullable(),\n // Streaming endpoint information\n endpoint: z.object({\n url: z.string().url(),\n method: z.string().default(\"POST\"),\n contentType: z.string().default(\"application/json\"),\n stream: z.boolean().default(true),\n }).nullable(),\n});\n\n/**\n * MODELS Collection Binding\n *\n * Collection bindings for models (read-only).\n * Provides LIST and GET operations for AI models.\n */\nexport const MODELS_COLLECTION_BINDING = createCollectionBindings(\n \"models\",\n ModelSchema,\n { readOnly: true },\n);\n\n/**\n * MODELS Binding\n *\n * Defines the interface for AI model providers.\n * Any MCP that implements this binding can provide AI models and streaming endpoints.\n *\n * Required tools:\n * - DECO_COLLECTION_MODELS_LIST: List available AI models with their capabilities\n * - DECO_COLLECTION_MODELS_GET: Get a single model by ID (includes streaming endpoint info)\n */\nexport const MODELS_BINDING = [\n ...MODELS_COLLECTION_BINDING,\n] as const satisfies Binder;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/bindings",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "tsup",
@@ -24,6 +24,16 @@
24
24
  "source": "./src/index.ts",
25
25
  "types": "./dist/index.d.ts",
26
26
  "default": "./dist/index.js"
27
+ },
28
+ "./models": {
29
+ "source": "./src/well-known/models.ts",
30
+ "types": "./dist/well-known/models.d.ts",
31
+ "default": "./dist/well-known/models.js"
32
+ },
33
+ "./collections": {
34
+ "source": "./src/well-known/collections.ts",
35
+ "types": "./dist/well-known/collections.d.ts",
36
+ "default": "./dist/well-known/collections.js"
27
37
  }
28
38
  },
29
39
  "devDependencies": {
@@ -142,10 +142,9 @@ export function createBindingChecker<TDefinition extends readonly ToolBinder[]>(
142
142
  isImplementedBy: async (tools: ToolWithSchemas[]) => {
143
143
  for (const binderTool of binderTools) {
144
144
  // Find matching tool by name (exact or regex)
145
- const pattern =
146
- typeof binderTool.name === "string"
147
- ? new RegExp(`^${binderTool.name}$`)
148
- : binderTool.name;
145
+ const pattern = typeof binderTool.name === "string"
146
+ ? new RegExp(`^${binderTool.name}$`)
147
+ : binderTool.name;
149
148
 
150
149
  const matchedTool = tools.find((t) => pattern.test(t.name));
151
150
 
@@ -166,6 +165,8 @@ export function createBindingChecker<TDefinition extends readonly ToolBinder[]>(
166
165
  const binderInputSchema = normalizeSchema(binderTool.inputSchema);
167
166
  const toolInputSchema = normalizeSchema(matchedTool.inputSchema);
168
167
 
168
+ console.log(JSON.stringify(binderInputSchema, null, 2));
169
+
169
170
  if (binderInputSchema && toolInputSchema) {
170
171
  try {
171
172
  const inputDiff = await diffSchemas({
@@ -178,6 +179,7 @@ export function createBindingChecker<TDefinition extends readonly ToolBinder[]>(
178
179
  return false;
179
180
  }
180
181
  } catch (error) {
182
+ console.error("Schema diff failed", error);
181
183
  // Schema diff failed - consider incompatible
182
184
  return false;
183
185
  }
@@ -205,6 +207,7 @@ export function createBindingChecker<TDefinition extends readonly ToolBinder[]>(
205
207
  return false;
206
208
  }
207
209
  } catch (error) {
210
+ console.error("Schema diff failed", error);
208
211
  // Schema diff failed - consider incompatible
209
212
  return false;
210
213
  }
@@ -218,4 +221,3 @@ export function createBindingChecker<TDefinition extends readonly ToolBinder[]>(
218
221
  },
219
222
  };
220
223
  }
221
-
@@ -35,48 +35,40 @@ export const BaseCollectionEntitySchema = z.object({
35
35
  export type BaseCollectionEntitySchemaType = typeof BaseCollectionEntitySchema;
36
36
 
37
37
  /**
38
- * Where expression type for filtering
39
- * Supports TanStack DB predicate push-down patterns
38
+ * Comparison expression schema for filtering
40
39
  */
41
- export type WhereExpression =
42
- | {
43
- field: string[];
44
- operator: "eq" | "gt" | "gte" | "lt" | "lte" | "in" | "like" | "contains";
45
- value: unknown;
46
- }
47
- | {
48
- operator: "and" | "or" | "not";
49
- conditions: WhereExpression[];
50
- };
40
+ const ComparisonExpressionSchema = z.object({
41
+ field: z.array(z.string()),
42
+ operator: z.enum([
43
+ "eq",
44
+ "gt",
45
+ "gte",
46
+ "lt",
47
+ "lte",
48
+ "in",
49
+ "like",
50
+ "contains",
51
+ ]),
52
+ value: z.unknown(),
53
+ });
51
54
 
52
55
  /**
53
56
  * Where expression schema for filtering
54
57
  * Supports TanStack DB predicate push-down patterns
55
58
  */
56
- export const WhereExpressionSchema = z.lazy(() =>
57
- z.union([
58
- // Simple comparison
59
- z.object({
60
- field: z.array(z.string()),
61
- operator: z.enum([
62
- "eq",
63
- "gt",
64
- "gte",
65
- "lt",
66
- "lte",
67
- "in",
68
- "like",
69
- "contains",
70
- ]),
71
- value: z.unknown(),
72
- }),
73
- // Logical operators
74
- z.object({
75
- operator: z.enum(["and", "or", "not"]),
76
- conditions: z.array(WhereExpressionSchema),
77
- }),
78
- ])
79
- ) as z.ZodType<WhereExpression>;
59
+ export const WhereExpressionSchema = z.union([
60
+ ComparisonExpressionSchema,
61
+ z.object({
62
+ operator: z.enum(["and", "or", "not"]),
63
+ conditions: z.array(ComparisonExpressionSchema),
64
+ }),
65
+ ]);
66
+
67
+ /**
68
+ * Where expression type for filtering
69
+ * Derived from WhereExpressionSchema
70
+ */
71
+ export type WhereExpression = z.infer<typeof WhereExpressionSchema>;
80
72
 
81
73
  /**
82
74
  * Order by expression for sorting