@decocms/bindings 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -16
- package/dist/{chunk-L7E6ONLJ.js → chunk-JMM4EZYL.js} +18 -24
- package/dist/chunk-JMM4EZYL.js.map +1 -0
- package/dist/index.js.map +1 -1
- package/dist/well-known/collections.d.ts +51 -19
- package/dist/well-known/collections.js +1 -1
- package/dist/well-known/models.d.ts +2 -2
- package/dist/well-known/models.js +1 -1
- package/dist/well-known/models.js.map +1 -1
- package/package.json +5 -6
- package/src/core/binder.ts +8 -3
- package/src/index.ts +0 -1
- package/src/well-known/collections.ts +66 -31
- package/src/well-known/models.ts +33 -25
- package/dist/chunk-L7E6ONLJ.js.map +0 -1
package/README.md
CHANGED
|
@@ -272,11 +272,11 @@ const todoChecker = createBindingChecker(TODO_COLLECTION_BINDING);
|
|
|
272
272
|
|
|
273
273
|
// Check if available tools implement the binding
|
|
274
274
|
const availableTools = [
|
|
275
|
-
{ name: "
|
|
276
|
-
{ name: "
|
|
277
|
-
{ name: "
|
|
278
|
-
{ name: "
|
|
279
|
-
{ name: "
|
|
275
|
+
{ name: "COLLECTION_TODOS_LIST" },
|
|
276
|
+
{ name: "COLLECTION_TODOS_GET" },
|
|
277
|
+
{ name: "COLLECTION_TODOS_CREATE" },
|
|
278
|
+
{ name: "COLLECTION_TODOS_UPDATE" },
|
|
279
|
+
{ name: "COLLECTION_TODOS_DELETE" },
|
|
280
280
|
];
|
|
281
281
|
|
|
282
282
|
const isImplemented = await todoChecker.isImplementedBy(availableTools);
|
|
@@ -289,29 +289,29 @@ The `createCollectionBindings` function generates tool bindings based on the `re
|
|
|
289
289
|
|
|
290
290
|
**Required operations (always included):**
|
|
291
291
|
|
|
292
|
-
1. **LIST** - `
|
|
292
|
+
1. **LIST** - `COLLECTION_{NAME}_LIST`
|
|
293
293
|
- Query/search entities with filtering, sorting, and pagination
|
|
294
294
|
- Input: `where?`, `orderBy?`, `limit?`, `offset?`
|
|
295
295
|
- Output: `items[]`, `totalCount?`, `hasMore?`
|
|
296
296
|
|
|
297
|
-
2. **GET** - `
|
|
297
|
+
2. **GET** - `COLLECTION_{NAME}_GET`
|
|
298
298
|
- Get a single entity by ID
|
|
299
299
|
- Input: `id` (string)
|
|
300
300
|
- Output: `item | null`
|
|
301
301
|
|
|
302
302
|
**Optional operations (excluded if `readOnly: true`):**
|
|
303
303
|
|
|
304
|
-
3. **
|
|
304
|
+
3. **CREATE** - `COLLECTION_{NAME}_CREATE`
|
|
305
305
|
- Create a new entity
|
|
306
306
|
- Input: `data` (id may be auto-generated by the server)
|
|
307
307
|
- Output: `item` (with generated id)
|
|
308
308
|
|
|
309
|
-
4. **UPDATE** - `
|
|
309
|
+
4. **UPDATE** - `COLLECTION_{NAME}_UPDATE`
|
|
310
310
|
- Update an existing entity
|
|
311
311
|
- Input: `id` (string), `data` (partial)
|
|
312
312
|
- Output: `item`
|
|
313
313
|
|
|
314
|
-
5. **DELETE** - `
|
|
314
|
+
5. **DELETE** - `COLLECTION_{NAME}_DELETE`
|
|
315
315
|
- Delete an entity
|
|
316
316
|
- Input: `id` (string)
|
|
317
317
|
- Output: `success` (boolean), `id` (string)
|
|
@@ -346,8 +346,8 @@ const modelsChecker = createBindingChecker(MODELS_BINDING);
|
|
|
346
346
|
|
|
347
347
|
// Check if available tools implement the binding
|
|
348
348
|
const availableTools = [
|
|
349
|
-
{ name: "
|
|
350
|
-
{ name: "
|
|
349
|
+
{ name: "COLLECTION_MODELS_LIST" },
|
|
350
|
+
{ name: "COLLECTION_MODELS_GET" },
|
|
351
351
|
];
|
|
352
352
|
|
|
353
353
|
const isImplemented = await modelsChecker.isImplementedBy(availableTools);
|
|
@@ -358,13 +358,13 @@ console.log(isImplemented); // true if all required tools are present
|
|
|
358
358
|
|
|
359
359
|
The `MODELS_BINDING` includes:
|
|
360
360
|
|
|
361
|
-
1. **
|
|
361
|
+
1. **COLLECTION_MODELS_LIST** (required)
|
|
362
362
|
- List available AI models with their capabilities and streaming endpoints
|
|
363
363
|
- Uses collection binding LIST operation
|
|
364
364
|
- Input: `where?`, `orderBy?`, `limit?`, `offset?`
|
|
365
365
|
- Output: `items[]` (array of model entities with endpoint info)
|
|
366
366
|
|
|
367
|
-
2. **
|
|
367
|
+
2. **COLLECTION_MODELS_GET** (required)
|
|
368
368
|
- Get a single model by ID
|
|
369
369
|
- Uses collection binding GET operation
|
|
370
370
|
- Input: `id` (string)
|
|
@@ -576,14 +576,14 @@ import type {
|
|
|
576
576
|
CollectionListInput,
|
|
577
577
|
CollectionGetInput,
|
|
578
578
|
CollectionDeleteInput,
|
|
579
|
-
} from "@decocms/bindings/
|
|
579
|
+
} from "@decocms/bindings/collections";
|
|
580
580
|
|
|
581
581
|
// Extract the binding type
|
|
582
582
|
type TodoBinding = typeof TODO_COLLECTION_BINDING;
|
|
583
583
|
|
|
584
584
|
// Extract tool names
|
|
585
585
|
type TodoTools = CollectionTools<typeof TodoSchema>;
|
|
586
|
-
// "
|
|
586
|
+
// "COLLECTION_TODOS_LIST" | "COLLECTION_TODOS_GET" | ...
|
|
587
587
|
|
|
588
588
|
// Get input types
|
|
589
589
|
type ListInput = CollectionListInput;
|
|
@@ -11,16 +11,7 @@ var BaseCollectionEntitySchema = z.object({
|
|
|
11
11
|
});
|
|
12
12
|
var ComparisonExpressionSchema = z.object({
|
|
13
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
|
-
]),
|
|
14
|
+
operator: z.enum(["eq", "gt", "gte", "lt", "lte", "in", "like", "contains"]),
|
|
24
15
|
value: z.unknown()
|
|
25
16
|
});
|
|
26
17
|
var WhereExpressionSchema = z.union([
|
|
@@ -58,7 +49,9 @@ function createCollectionGetOutputSchema(entitySchema) {
|
|
|
58
49
|
}
|
|
59
50
|
function createCollectionInsertInputSchema(entitySchema) {
|
|
60
51
|
return z.object({
|
|
61
|
-
data: entitySchema.describe(
|
|
52
|
+
data: entitySchema.describe(
|
|
53
|
+
"Data for the new entity (id may be auto-generated)"
|
|
54
|
+
)
|
|
62
55
|
});
|
|
63
56
|
}
|
|
64
57
|
function createCollectionInsertOutputSchema(entitySchema) {
|
|
@@ -80,21 +73,22 @@ function createCollectionUpdateOutputSchema(entitySchema) {
|
|
|
80
73
|
var CollectionDeleteInputSchema = z.object({
|
|
81
74
|
id: z.string().describe("ID of the entity to delete")
|
|
82
75
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
});
|
|
76
|
+
function createCollectionDeleteOutputSchema(entitySchema) {
|
|
77
|
+
return z.object({
|
|
78
|
+
item: entitySchema.describe("The deleted entity")
|
|
79
|
+
});
|
|
80
|
+
}
|
|
87
81
|
function createCollectionBindings(collectionName, entitySchema, options) {
|
|
88
82
|
const upperName = collectionName.toUpperCase();
|
|
89
83
|
const readOnly = options?.readOnly ?? false;
|
|
90
84
|
const bindings = [
|
|
91
85
|
{
|
|
92
|
-
name: `
|
|
86
|
+
name: `COLLECTION_${upperName}_LIST`,
|
|
93
87
|
inputSchema: CollectionListInputSchema,
|
|
94
88
|
outputSchema: createCollectionListOutputSchema(entitySchema)
|
|
95
89
|
},
|
|
96
90
|
{
|
|
97
|
-
name: `
|
|
91
|
+
name: `COLLECTION_${upperName}_GET`,
|
|
98
92
|
inputSchema: CollectionGetInputSchema,
|
|
99
93
|
outputSchema: createCollectionGetOutputSchema(entitySchema)
|
|
100
94
|
}
|
|
@@ -102,21 +96,21 @@ function createCollectionBindings(collectionName, entitySchema, options) {
|
|
|
102
96
|
if (!readOnly) {
|
|
103
97
|
bindings.push(
|
|
104
98
|
{
|
|
105
|
-
name: `
|
|
99
|
+
name: `COLLECTION_${upperName}_CREATE`,
|
|
106
100
|
inputSchema: createCollectionInsertInputSchema(entitySchema),
|
|
107
101
|
outputSchema: createCollectionInsertOutputSchema(entitySchema),
|
|
108
102
|
opt: true
|
|
109
103
|
},
|
|
110
104
|
{
|
|
111
|
-
name: `
|
|
105
|
+
name: `COLLECTION_${upperName}_UPDATE`,
|
|
112
106
|
inputSchema: createCollectionUpdateInputSchema(entitySchema),
|
|
113
107
|
outputSchema: createCollectionUpdateOutputSchema(entitySchema),
|
|
114
108
|
opt: true
|
|
115
109
|
},
|
|
116
110
|
{
|
|
117
|
-
name: `
|
|
111
|
+
name: `COLLECTION_${upperName}_DELETE`,
|
|
118
112
|
inputSchema: CollectionDeleteInputSchema,
|
|
119
|
-
outputSchema:
|
|
113
|
+
outputSchema: createCollectionDeleteOutputSchema(entitySchema),
|
|
120
114
|
opt: true
|
|
121
115
|
}
|
|
122
116
|
);
|
|
@@ -124,6 +118,6 @@ function createCollectionBindings(collectionName, entitySchema, options) {
|
|
|
124
118
|
return bindings;
|
|
125
119
|
}
|
|
126
120
|
|
|
127
|
-
export { BaseCollectionEntitySchema, CollectionDeleteInputSchema,
|
|
128
|
-
//# sourceMappingURL=chunk-
|
|
129
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
export { BaseCollectionEntitySchema, CollectionDeleteInputSchema, CollectionGetInputSchema, CollectionListInputSchema, OrderByExpressionSchema, WhereExpressionSchema, createCollectionBindings, createCollectionDeleteOutputSchema, createCollectionGetOutputSchema, createCollectionInsertInputSchema, createCollectionInsertOutputSchema, createCollectionListOutputSchema, createCollectionUpdateInputSchema, createCollectionUpdateOutputSchema };
|
|
122
|
+
//# sourceMappingURL=chunk-JMM4EZYL.js.map
|
|
123
|
+
//# sourceMappingURL=chunk-JMM4EZYL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/well-known/collections.ts"],"names":[],"mappings":"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","file":"chunk-JMM4EZYL.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: `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([\"eq\", \"gt\", \"gte\", \"lt\", \"lte\", \"in\", \"like\", \"contains\"]),\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(\n \"Data for the new entity (id may be auto-generated)\",\n ),\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 * Factory function to create delete output schema\n */\nexport function createCollectionDeleteOutputSchema<T extends z.ZodTypeAny>(\n entitySchema: T,\n) {\n return z.object({\n item: entitySchema.describe(\"The deleted entity\"),\n });\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 * - COLLECTION_{NAME}_LIST - Query/search entities with filtering and sorting (required)\n * - COLLECTION_{NAME}_GET - Get a single entity by ID (required)\n * - COLLECTION_{NAME}_CREATE - Create a new entity (optional, excluded if readOnly=true)\n * - COLLECTION_{NAME}_UPDATE - Update an existing entity (optional, excluded if readOnly=true)\n * - 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: `COLLECTION_${upperName}_LIST` as const,\n inputSchema: CollectionListInputSchema,\n outputSchema: createCollectionListOutputSchema(entitySchema),\n },\n {\n name: `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: `COLLECTION_${upperName}_CREATE` as const,\n inputSchema: createCollectionInsertInputSchema(entitySchema),\n outputSchema: createCollectionInsertOutputSchema(entitySchema),\n opt: true,\n },\n {\n name: `COLLECTION_${upperName}_UPDATE` as const,\n inputSchema: createCollectionUpdateInputSchema(entitySchema),\n outputSchema: createCollectionUpdateOutputSchema(entitySchema),\n opt: true,\n },\n {\n name: `COLLECTION_${upperName}_DELETE` as const,\n inputSchema: CollectionDeleteInputSchema,\n outputSchema: createCollectionDeleteOutputSchema(entitySchema),\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 OrderByExpression = z.infer<typeof OrderByExpressionSchema>;\n\n/**\n * Type helper for list output with generic item type\n */\nexport type CollectionListOutput<T> = {\n items: T[];\n totalCount?: number;\n hasMore?: boolean;\n};\n\n/**\n * Type helper for get output with generic item type\n */\nexport type CollectionGetOutput<T> = {\n item: T | null;\n};\n\n/**\n * Type helper for insert output with generic item type\n */\nexport type CollectionInsertOutput<T> = {\n item: T;\n};\n\n/**\n * Type helper for update output with generic item type\n */\nexport type CollectionUpdateOutput<T> = {\n item: T;\n};\n\n/**\n * Type helper for delete output with generic item type\n */\nexport type CollectionDeleteOutput<T> = {\n item: T;\n};\n\n/**\n * Base collection entity type - inferred from BaseCollectionEntitySchema\n */\nexport type BaseCollectionEntity = z.infer<typeof BaseCollectionEntitySchema>;\n"]}
|
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 = 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 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"]}
|
|
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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n inputSchema?: ZodType<any> | Record<string, unknown>;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\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 */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\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 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"]}
|
|
@@ -9,7 +9,7 @@ import { ToolBinder } from '../index.js';
|
|
|
9
9
|
*
|
|
10
10
|
* Key Features:
|
|
11
11
|
* - Generic collection bindings that work with any entity type
|
|
12
|
-
* - Standardized tool naming: `
|
|
12
|
+
* - Standardized tool naming: `COLLECTION_{COLLECTION}_*`
|
|
13
13
|
* - Compatible with TanStack DB query-collection
|
|
14
14
|
* - Full TypeScript support with proper type constraints
|
|
15
15
|
* - Support for filtering, sorting, and pagination
|
|
@@ -315,18 +315,15 @@ declare const CollectionDeleteInputSchema: z.ZodObject<{
|
|
|
315
315
|
id: string;
|
|
316
316
|
}>;
|
|
317
317
|
/**
|
|
318
|
-
*
|
|
318
|
+
* Factory function to create delete output schema
|
|
319
319
|
*/
|
|
320
|
-
declare
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
id: string;
|
|
328
|
-
success: boolean;
|
|
329
|
-
}>;
|
|
320
|
+
declare function createCollectionDeleteOutputSchema<T extends z.ZodTypeAny>(entitySchema: T): z.ZodObject<{
|
|
321
|
+
item: T;
|
|
322
|
+
}, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
|
|
323
|
+
item: T;
|
|
324
|
+
}>, any> extends infer T_1 ? { [k in keyof T_1]: T_1[k]; } : never, z.baseObjectInputType<{
|
|
325
|
+
item: T;
|
|
326
|
+
}> extends infer T_2 ? { [k_1 in keyof T_2]: T_2[k_1]; } : never>;
|
|
330
327
|
/**
|
|
331
328
|
* Options for creating collection bindings
|
|
332
329
|
*/
|
|
@@ -342,11 +339,11 @@ interface CollectionBindingOptions {
|
|
|
342
339
|
*
|
|
343
340
|
* This function generates standardized tool bindings that work with any collection/table
|
|
344
341
|
* by accepting a custom entity schema and collection name. The bindings provide:
|
|
345
|
-
* -
|
|
346
|
-
* -
|
|
347
|
-
* -
|
|
348
|
-
* -
|
|
349
|
-
* -
|
|
342
|
+
* - COLLECTION_{NAME}_LIST - Query/search entities with filtering and sorting (required)
|
|
343
|
+
* - COLLECTION_{NAME}_GET - Get a single entity by ID (required)
|
|
344
|
+
* - COLLECTION_{NAME}_CREATE - Create a new entity (optional, excluded if readOnly=true)
|
|
345
|
+
* - COLLECTION_{NAME}_UPDATE - Update an existing entity (optional, excluded if readOnly=true)
|
|
346
|
+
* - COLLECTION_{NAME}_DELETE - Delete an entity (optional, excluded if readOnly=true)
|
|
350
347
|
*
|
|
351
348
|
* @param collectionName - The name of the collection/table (e.g., "users", "products", "orders")
|
|
352
349
|
* @param entitySchema - The Zod schema for the entity type (must extend BaseCollectionEntitySchema)
|
|
@@ -384,7 +381,42 @@ type CollectionTools<TEntitySchema extends BaseCollectionEntitySchemaType> = Col
|
|
|
384
381
|
type CollectionListInput = z.infer<typeof CollectionListInputSchema>;
|
|
385
382
|
type CollectionGetInput = z.infer<typeof CollectionGetInputSchema>;
|
|
386
383
|
type CollectionDeleteInput = z.infer<typeof CollectionDeleteInputSchema>;
|
|
387
|
-
type CollectionDeleteOutput = z.infer<typeof CollectionDeleteOutputSchema>;
|
|
388
384
|
type OrderByExpression = z.infer<typeof OrderByExpressionSchema>;
|
|
385
|
+
/**
|
|
386
|
+
* Type helper for list output with generic item type
|
|
387
|
+
*/
|
|
388
|
+
type CollectionListOutput<T> = {
|
|
389
|
+
items: T[];
|
|
390
|
+
totalCount?: number;
|
|
391
|
+
hasMore?: boolean;
|
|
392
|
+
};
|
|
393
|
+
/**
|
|
394
|
+
* Type helper for get output with generic item type
|
|
395
|
+
*/
|
|
396
|
+
type CollectionGetOutput<T> = {
|
|
397
|
+
item: T | null;
|
|
398
|
+
};
|
|
399
|
+
/**
|
|
400
|
+
* Type helper for insert output with generic item type
|
|
401
|
+
*/
|
|
402
|
+
type CollectionInsertOutput<T> = {
|
|
403
|
+
item: T;
|
|
404
|
+
};
|
|
405
|
+
/**
|
|
406
|
+
* Type helper for update output with generic item type
|
|
407
|
+
*/
|
|
408
|
+
type CollectionUpdateOutput<T> = {
|
|
409
|
+
item: T;
|
|
410
|
+
};
|
|
411
|
+
/**
|
|
412
|
+
* Type helper for delete output with generic item type
|
|
413
|
+
*/
|
|
414
|
+
type CollectionDeleteOutput<T> = {
|
|
415
|
+
item: T;
|
|
416
|
+
};
|
|
417
|
+
/**
|
|
418
|
+
* Base collection entity type - inferred from BaseCollectionEntitySchema
|
|
419
|
+
*/
|
|
420
|
+
type BaseCollectionEntity = z.infer<typeof BaseCollectionEntitySchema>;
|
|
389
421
|
|
|
390
|
-
export { BaseCollectionEntitySchema, type BaseCollectionEntitySchemaType, type CollectionBinding, type CollectionBindingOptions, type CollectionDeleteInput, CollectionDeleteInputSchema, type CollectionDeleteOutput,
|
|
422
|
+
export { type BaseCollectionEntity, BaseCollectionEntitySchema, type BaseCollectionEntitySchemaType, type CollectionBinding, type CollectionBindingOptions, type CollectionDeleteInput, CollectionDeleteInputSchema, type CollectionDeleteOutput, type CollectionGetInput, CollectionGetInputSchema, type CollectionGetOutput, type CollectionInsertOutput, type CollectionListInput, CollectionListInputSchema, type CollectionListOutput, type CollectionTools, type CollectionUpdateOutput, type OrderByExpression, OrderByExpressionSchema, type WhereExpression, WhereExpressionSchema, createCollectionBindings, createCollectionDeleteOutputSchema, createCollectionGetOutputSchema, createCollectionInsertInputSchema, createCollectionInsertOutputSchema, createCollectionListOutputSchema, createCollectionUpdateInputSchema, createCollectionUpdateOutputSchema };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { BaseCollectionEntitySchema, CollectionDeleteInputSchema,
|
|
1
|
+
export { BaseCollectionEntitySchema, CollectionDeleteInputSchema, CollectionGetInputSchema, CollectionListInputSchema, OrderByExpressionSchema, WhereExpressionSchema, createCollectionBindings, createCollectionDeleteOutputSchema, createCollectionGetOutputSchema, createCollectionInsertInputSchema, createCollectionInsertOutputSchema, createCollectionListOutputSchema, createCollectionUpdateInputSchema, createCollectionUpdateOutputSchema } from '../chunk-JMM4EZYL.js';
|
|
2
2
|
//# sourceMappingURL=collections.js.map
|
|
3
3
|
//# sourceMappingURL=collections.js.map
|
|
@@ -119,8 +119,8 @@ declare const MODELS_COLLECTION_BINDING: ToolBinder<string, any, object>[];
|
|
|
119
119
|
* Any MCP that implements this binding can provide AI models and streaming endpoints.
|
|
120
120
|
*
|
|
121
121
|
* Required tools:
|
|
122
|
-
* -
|
|
123
|
-
* -
|
|
122
|
+
* - COLLECTION_MODELS_LIST: List available AI models with their capabilities
|
|
123
|
+
* - COLLECTION_MODELS_GET: Get a single model by ID (includes streaming endpoint info)
|
|
124
124
|
*/
|
|
125
125
|
declare const MODELS_BINDING: readonly ToolBinder<string, any, object>[];
|
|
126
126
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseCollectionEntitySchema, createCollectionBindings } from '../chunk-
|
|
1
|
+
import { BaseCollectionEntitySchema, createCollectionBindings } from '../chunk-JMM4EZYL.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
var ModelSchema = BaseCollectionEntitySchema.extend({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/well-known/models.ts"],"names":[],"mappings":";;;AAsBO,IAAM,WAAA,GAAc,2BAA2B,MAAA,CAAO;AAAA;AAAA,EAE3D,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,
|
|
1
|
+
{"version":3,"sources":["../../src/well-known/models.ts"],"names":[],"mappings":";;;AAsBO,IAAM,WAAA,GAAc,2BAA2B,MAAA,CAAO;AAAA;AAAA,EAE3D,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,EACL,MAAA,CAAO;AAAA,IACN,aAAA,EAAe,EAAE,MAAA,EAAO;AAAA,IACxB,eAAA,EAAiB,EAAE,MAAA;AAAO,GAC3B,EACA,QAAA,EAAS;AAAA,EACZ,KAAA,EAAO,EACJ,MAAA,CAAO;AAAA,IACN,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,IAChB,MAAA,EAAQ,EAAE,MAAA;AAAO,GAClB,EACA,QAAA,EAAS;AAAA;AAAA,EAEZ,QAAA,EAAU,EACP,IAAA,CAAK;AAAA,IACJ,QAAA;AAAA,IACA,WAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACD,EACA,QAAA,EAAS;AAAA;AAAA,EAEZ,QAAA,EAAU,EACP,MAAA,CAAO;AAAA,IACN,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,EACA,QAAA;AACL,CAAC;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 */\nexport const 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\n .object({\n contextWindow: z.number(),\n maxOutputTokens: z.number(),\n })\n .nullable(),\n costs: z\n .object({\n input: z.number(),\n output: z.number(),\n })\n .nullable(),\n // Provider information\n provider: z\n .enum([\n \"openai\",\n \"anthropic\",\n \"google\",\n \"xai\",\n \"deepseek\",\n \"openai-compatible\",\n \"openrouter\",\n ])\n .nullable(),\n // Streaming endpoint information\n endpoint: z\n .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 })\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 * - COLLECTION_MODELS_LIST: List available AI models with their capabilities\n * - 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.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "tsup",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"zod-to-json-schema": "^3.24.4"
|
|
15
15
|
},
|
|
16
16
|
"main": "./dist/index.js",
|
|
17
|
-
"types": "./
|
|
17
|
+
"types": "./src/index.ts",
|
|
18
18
|
"files": [
|
|
19
19
|
"dist/**/*",
|
|
20
20
|
"src/**/*"
|
|
@@ -22,17 +22,17 @@
|
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
|
24
24
|
"source": "./src/index.ts",
|
|
25
|
-
"types": "./
|
|
25
|
+
"types": "./src/index.ts",
|
|
26
26
|
"default": "./dist/index.js"
|
|
27
27
|
},
|
|
28
28
|
"./models": {
|
|
29
29
|
"source": "./src/well-known/models.ts",
|
|
30
|
-
"types": "./
|
|
30
|
+
"types": "./src/well-known/models.ts",
|
|
31
31
|
"default": "./dist/well-known/models.js"
|
|
32
32
|
},
|
|
33
33
|
"./collections": {
|
|
34
34
|
"source": "./src/well-known/collections.ts",
|
|
35
|
-
"types": "./
|
|
35
|
+
"types": "./src/well-known/collections.ts",
|
|
36
36
|
"default": "./dist/well-known/collections.js"
|
|
37
37
|
}
|
|
38
38
|
},
|
|
@@ -48,4 +48,3 @@
|
|
|
48
48
|
"access": "public"
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
|
package/src/core/binder.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { diffSchemas } from "json-schema-diff";
|
|
|
20
20
|
export interface ToolBinder<
|
|
21
21
|
TName extends string | RegExp = string,
|
|
22
22
|
// biome-ignore lint/suspicious/noExplicitAny: Generic type parameter
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
24
|
TInput = any,
|
|
24
25
|
TReturn extends object | null | boolean = object,
|
|
25
26
|
> {
|
|
@@ -63,13 +64,16 @@ export type Binder<
|
|
|
63
64
|
*/
|
|
64
65
|
export interface ToolWithSchemas {
|
|
65
66
|
name: string;
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
68
|
inputSchema?: ZodType<any> | Record<string, unknown>;
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
67
70
|
outputSchema?: ZodType<any> | Record<string, unknown>;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
73
|
/**
|
|
71
74
|
* Converts a schema to JSON Schema format if it's a Zod schema
|
|
72
75
|
*/
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
77
|
function normalizeSchema(schema: any): Record<string, unknown> | undefined {
|
|
74
78
|
if (!schema) return undefined;
|
|
75
79
|
|
|
@@ -142,9 +146,10 @@ export function createBindingChecker<TDefinition extends readonly ToolBinder[]>(
|
|
|
142
146
|
isImplementedBy: async (tools: ToolWithSchemas[]) => {
|
|
143
147
|
for (const binderTool of binderTools) {
|
|
144
148
|
// Find matching tool by name (exact or regex)
|
|
145
|
-
const pattern =
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
const pattern =
|
|
150
|
+
typeof binderTool.name === "string"
|
|
151
|
+
? new RegExp(`^${binderTool.name}$`)
|
|
152
|
+
: binderTool.name;
|
|
148
153
|
|
|
149
154
|
const matchedTool = tools.find((t) => pattern.test(t.name));
|
|
150
155
|
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { ToolBinder } from "../core/binder";
|
|
|
9
9
|
*
|
|
10
10
|
* Key Features:
|
|
11
11
|
* - Generic collection bindings that work with any entity type
|
|
12
|
-
* - Standardized tool naming: `
|
|
12
|
+
* - Standardized tool naming: `COLLECTION_{COLLECTION}_*`
|
|
13
13
|
* - Compatible with TanStack DB query-collection
|
|
14
14
|
* - Full TypeScript support with proper type constraints
|
|
15
15
|
* - Support for filtering, sorting, and pagination
|
|
@@ -39,16 +39,7 @@ export type BaseCollectionEntitySchemaType = typeof BaseCollectionEntitySchema;
|
|
|
39
39
|
*/
|
|
40
40
|
const ComparisonExpressionSchema = z.object({
|
|
41
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
|
-
]),
|
|
42
|
+
operator: z.enum(["eq", "gt", "gte", "lt", "lte", "in", "like", "contains"]),
|
|
52
43
|
value: z.unknown(),
|
|
53
44
|
});
|
|
54
45
|
|
|
@@ -153,7 +144,9 @@ export function createCollectionInsertInputSchema<T extends z.ZodTypeAny>(
|
|
|
153
144
|
) {
|
|
154
145
|
// Remove id field since it may be auto-generated by the server
|
|
155
146
|
return z.object({
|
|
156
|
-
data: entitySchema.describe(
|
|
147
|
+
data: entitySchema.describe(
|
|
148
|
+
"Data for the new entity (id may be auto-generated)",
|
|
149
|
+
),
|
|
157
150
|
});
|
|
158
151
|
}
|
|
159
152
|
|
|
@@ -201,12 +194,15 @@ export const CollectionDeleteInputSchema = z.object({
|
|
|
201
194
|
});
|
|
202
195
|
|
|
203
196
|
/**
|
|
204
|
-
*
|
|
197
|
+
* Factory function to create delete output schema
|
|
205
198
|
*/
|
|
206
|
-
export
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
199
|
+
export function createCollectionDeleteOutputSchema<T extends z.ZodTypeAny>(
|
|
200
|
+
entitySchema: T,
|
|
201
|
+
) {
|
|
202
|
+
return z.object({
|
|
203
|
+
item: entitySchema.describe("The deleted entity"),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
210
206
|
|
|
211
207
|
/**
|
|
212
208
|
* Options for creating collection bindings
|
|
@@ -224,11 +220,11 @@ export interface CollectionBindingOptions {
|
|
|
224
220
|
*
|
|
225
221
|
* This function generates standardized tool bindings that work with any collection/table
|
|
226
222
|
* by accepting a custom entity schema and collection name. The bindings provide:
|
|
227
|
-
* -
|
|
228
|
-
* -
|
|
229
|
-
* -
|
|
230
|
-
* -
|
|
231
|
-
* -
|
|
223
|
+
* - COLLECTION_{NAME}_LIST - Query/search entities with filtering and sorting (required)
|
|
224
|
+
* - COLLECTION_{NAME}_GET - Get a single entity by ID (required)
|
|
225
|
+
* - COLLECTION_{NAME}_CREATE - Create a new entity (optional, excluded if readOnly=true)
|
|
226
|
+
* - COLLECTION_{NAME}_UPDATE - Update an existing entity (optional, excluded if readOnly=true)
|
|
227
|
+
* - COLLECTION_{NAME}_DELETE - Delete an entity (optional, excluded if readOnly=true)
|
|
232
228
|
*
|
|
233
229
|
* @param collectionName - The name of the collection/table (e.g., "users", "products", "orders")
|
|
234
230
|
* @param entitySchema - The Zod schema for the entity type (must extend BaseCollectionEntitySchema)
|
|
@@ -266,12 +262,12 @@ export function createCollectionBindings<
|
|
|
266
262
|
|
|
267
263
|
const bindings: ToolBinder[] = [
|
|
268
264
|
{
|
|
269
|
-
name: `
|
|
265
|
+
name: `COLLECTION_${upperName}_LIST` as const,
|
|
270
266
|
inputSchema: CollectionListInputSchema,
|
|
271
267
|
outputSchema: createCollectionListOutputSchema(entitySchema),
|
|
272
268
|
},
|
|
273
269
|
{
|
|
274
|
-
name: `
|
|
270
|
+
name: `COLLECTION_${upperName}_GET` as const,
|
|
275
271
|
inputSchema: CollectionGetInputSchema,
|
|
276
272
|
outputSchema: createCollectionGetOutputSchema(entitySchema),
|
|
277
273
|
},
|
|
@@ -281,21 +277,21 @@ export function createCollectionBindings<
|
|
|
281
277
|
if (!readOnly) {
|
|
282
278
|
bindings.push(
|
|
283
279
|
{
|
|
284
|
-
name: `
|
|
280
|
+
name: `COLLECTION_${upperName}_CREATE` as const,
|
|
285
281
|
inputSchema: createCollectionInsertInputSchema(entitySchema),
|
|
286
282
|
outputSchema: createCollectionInsertOutputSchema(entitySchema),
|
|
287
283
|
opt: true,
|
|
288
284
|
},
|
|
289
285
|
{
|
|
290
|
-
name: `
|
|
286
|
+
name: `COLLECTION_${upperName}_UPDATE` as const,
|
|
291
287
|
inputSchema: createCollectionUpdateInputSchema(entitySchema),
|
|
292
288
|
outputSchema: createCollectionUpdateOutputSchema(entitySchema),
|
|
293
289
|
opt: true,
|
|
294
290
|
},
|
|
295
291
|
{
|
|
296
|
-
name: `
|
|
292
|
+
name: `COLLECTION_${upperName}_DELETE` as const,
|
|
297
293
|
inputSchema: CollectionDeleteInputSchema,
|
|
298
|
-
outputSchema:
|
|
294
|
+
outputSchema: createCollectionDeleteOutputSchema(entitySchema),
|
|
299
295
|
opt: true,
|
|
300
296
|
},
|
|
301
297
|
);
|
|
@@ -322,7 +318,46 @@ export type CollectionTools<
|
|
|
322
318
|
export type CollectionListInput = z.infer<typeof CollectionListInputSchema>;
|
|
323
319
|
export type CollectionGetInput = z.infer<typeof CollectionGetInputSchema>;
|
|
324
320
|
export type CollectionDeleteInput = z.infer<typeof CollectionDeleteInputSchema>;
|
|
325
|
-
export type CollectionDeleteOutput = z.infer<
|
|
326
|
-
typeof CollectionDeleteOutputSchema
|
|
327
|
-
>;
|
|
328
321
|
export type OrderByExpression = z.infer<typeof OrderByExpressionSchema>;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Type helper for list output with generic item type
|
|
325
|
+
*/
|
|
326
|
+
export type CollectionListOutput<T> = {
|
|
327
|
+
items: T[];
|
|
328
|
+
totalCount?: number;
|
|
329
|
+
hasMore?: boolean;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Type helper for get output with generic item type
|
|
334
|
+
*/
|
|
335
|
+
export type CollectionGetOutput<T> = {
|
|
336
|
+
item: T | null;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Type helper for insert output with generic item type
|
|
341
|
+
*/
|
|
342
|
+
export type CollectionInsertOutput<T> = {
|
|
343
|
+
item: T;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Type helper for update output with generic item type
|
|
348
|
+
*/
|
|
349
|
+
export type CollectionUpdateOutput<T> = {
|
|
350
|
+
item: T;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Type helper for delete output with generic item type
|
|
355
|
+
*/
|
|
356
|
+
export type CollectionDeleteOutput<T> = {
|
|
357
|
+
item: T;
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Base collection entity type - inferred from BaseCollectionEntitySchema
|
|
362
|
+
*/
|
|
363
|
+
export type BaseCollectionEntity = z.infer<typeof BaseCollectionEntitySchema>;
|
package/src/well-known/models.ts
CHANGED
|
@@ -25,31 +25,39 @@ export const ModelSchema = BaseCollectionEntitySchema.extend({
|
|
|
25
25
|
logo: z.string().nullable(),
|
|
26
26
|
description: z.string().nullable(),
|
|
27
27
|
capabilities: z.array(z.string()),
|
|
28
|
-
limits: z
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
limits: z
|
|
29
|
+
.object({
|
|
30
|
+
contextWindow: z.number(),
|
|
31
|
+
maxOutputTokens: z.number(),
|
|
32
|
+
})
|
|
33
|
+
.nullable(),
|
|
34
|
+
costs: z
|
|
35
|
+
.object({
|
|
36
|
+
input: z.number(),
|
|
37
|
+
output: z.number(),
|
|
38
|
+
})
|
|
39
|
+
.nullable(),
|
|
36
40
|
// Provider information
|
|
37
|
-
provider: z
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
provider: z
|
|
42
|
+
.enum([
|
|
43
|
+
"openai",
|
|
44
|
+
"anthropic",
|
|
45
|
+
"google",
|
|
46
|
+
"xai",
|
|
47
|
+
"deepseek",
|
|
48
|
+
"openai-compatible",
|
|
49
|
+
"openrouter",
|
|
50
|
+
])
|
|
51
|
+
.nullable(),
|
|
46
52
|
// Streaming endpoint information
|
|
47
|
-
endpoint: z
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
endpoint: z
|
|
54
|
+
.object({
|
|
55
|
+
url: z.string().url(),
|
|
56
|
+
method: z.string().default("POST"),
|
|
57
|
+
contentType: z.string().default("application/json"),
|
|
58
|
+
stream: z.boolean().default(true),
|
|
59
|
+
})
|
|
60
|
+
.nullable(),
|
|
53
61
|
});
|
|
54
62
|
|
|
55
63
|
/**
|
|
@@ -71,8 +79,8 @@ export const MODELS_COLLECTION_BINDING = createCollectionBindings(
|
|
|
71
79
|
* Any MCP that implements this binding can provide AI models and streaming endpoints.
|
|
72
80
|
*
|
|
73
81
|
* Required tools:
|
|
74
|
-
* -
|
|
75
|
-
* -
|
|
82
|
+
* - COLLECTION_MODELS_LIST: List available AI models with their capabilities
|
|
83
|
+
* - COLLECTION_MODELS_GET: Get a single model by ID (includes streaming endpoint info)
|
|
76
84
|
*/
|
|
77
85
|
export const MODELS_BINDING = [
|
|
78
86
|
...MODELS_COLLECTION_BINDING,
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|