ont-run 0.0.5 → 0.0.6
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/dist/bin/ont.js +13778 -5146
- package/dist/index.js +16302 -7652
- package/dist/src/config/define.d.ts +1 -1
- package/dist/src/config/schema.d.ts +20 -116
- package/dist/src/config/zod-utils.d.ts +44 -0
- package/package.json +2 -3
- package/src/browser/transform.ts +40 -17
- package/src/cli/commands/init.ts +10 -5
- package/src/config/define.ts +3 -1
- package/src/config/schema.ts +49 -34
- package/src/config/zod-utils.ts +144 -0
- package/src/lockfile/hasher.ts +46 -22
- package/src/server/mcp/tools.ts +45 -22
|
@@ -38,7 +38,7 @@ import type { OntologyConfig, FunctionDefinition, AccessGroupConfig, Environment
|
|
|
38
38
|
* });
|
|
39
39
|
* ```
|
|
40
40
|
*/
|
|
41
|
-
export declare function defineOntology<TGroups extends string, TEntities extends string, TFunctions extends Record<string, FunctionDefinition<TGroups, TEntities>>>(config: {
|
|
41
|
+
export declare function defineOntology<TGroups extends string, TEntities extends string, TFunctions extends Record<string, FunctionDefinition<TGroups, TEntities, any, any>>>(config: {
|
|
42
42
|
name: string;
|
|
43
43
|
environments: Record<string, EnvironmentConfig>;
|
|
44
44
|
auth: AuthFunction;
|
|
@@ -5,60 +5,30 @@ import type { OntologyConfig } from "./types.js";
|
|
|
5
5
|
*/
|
|
6
6
|
export declare const EnvironmentConfigSchema: z.ZodObject<{
|
|
7
7
|
debug: z.ZodOptional<z.ZodBoolean>;
|
|
8
|
-
},
|
|
9
|
-
debug: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
11
|
-
debug: z.ZodOptional<z.ZodBoolean>;
|
|
12
|
-
}, z.ZodTypeAny, "passthrough">>;
|
|
8
|
+
}, z.core.$loose>;
|
|
13
9
|
/**
|
|
14
10
|
* Schema for access group configuration
|
|
15
11
|
*/
|
|
16
12
|
export declare const AccessGroupConfigSchema: z.ZodObject<{
|
|
17
13
|
description: z.ZodString;
|
|
18
|
-
},
|
|
19
|
-
description: string;
|
|
20
|
-
}, {
|
|
21
|
-
description: string;
|
|
22
|
-
}>;
|
|
14
|
+
}, z.core.$strip>;
|
|
23
15
|
/**
|
|
24
16
|
* Schema for entity definition
|
|
25
17
|
*/
|
|
26
18
|
export declare const EntityDefinitionSchema: z.ZodObject<{
|
|
27
19
|
description: z.ZodString;
|
|
28
|
-
},
|
|
29
|
-
description: string;
|
|
30
|
-
}, {
|
|
31
|
-
description: string;
|
|
32
|
-
}>;
|
|
20
|
+
}, z.core.$strip>;
|
|
33
21
|
/**
|
|
34
22
|
* Schema for function definition
|
|
35
23
|
*/
|
|
36
24
|
export declare const FunctionDefinitionSchema: z.ZodObject<{
|
|
37
25
|
description: z.ZodString;
|
|
38
|
-
access: z.ZodArray<z.ZodString
|
|
39
|
-
entities: z.ZodArray<z.ZodString
|
|
40
|
-
inputs: z.
|
|
41
|
-
outputs: z.ZodOptional<z.
|
|
42
|
-
resolver: z.
|
|
43
|
-
},
|
|
44
|
-
description: string;
|
|
45
|
-
access: string[];
|
|
46
|
-
entities: string[];
|
|
47
|
-
inputs: z.ZodType<any, z.ZodTypeDef, any>;
|
|
48
|
-
resolver: (...args: unknown[]) => unknown;
|
|
49
|
-
outputs?: z.ZodType<any, z.ZodTypeDef, any> | undefined;
|
|
50
|
-
}, {
|
|
51
|
-
description: string;
|
|
52
|
-
access: string[];
|
|
53
|
-
entities: string[];
|
|
54
|
-
inputs: z.ZodType<any, z.ZodTypeDef, any>;
|
|
55
|
-
resolver: (...args: unknown[]) => unknown;
|
|
56
|
-
outputs?: z.ZodType<any, z.ZodTypeDef, any> | undefined;
|
|
57
|
-
}>;
|
|
58
|
-
/**
|
|
59
|
-
* Schema for auth function
|
|
60
|
-
*/
|
|
61
|
-
export declare const AuthFunctionSchema: z.ZodFunction<z.ZodTuple<[z.ZodType<Request, z.ZodTypeDef, Request>], z.ZodUnknown>, z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodPromise<z.ZodArray<z.ZodString, "many">>]>>;
|
|
26
|
+
access: z.ZodArray<z.ZodString>;
|
|
27
|
+
entities: z.ZodArray<z.ZodString>;
|
|
28
|
+
inputs: z.ZodCustom<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
29
|
+
outputs: z.ZodOptional<z.ZodCustom<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
|
|
30
|
+
resolver: z.ZodCustom<(...args: unknown[]) => unknown, (...args: unknown[]) => unknown>;
|
|
31
|
+
}, z.core.$strip>;
|
|
62
32
|
/**
|
|
63
33
|
* Schema for the full ontology configuration
|
|
64
34
|
*/
|
|
@@ -66,89 +36,23 @@ export declare const OntologyConfigSchema: z.ZodObject<{
|
|
|
66
36
|
name: z.ZodString;
|
|
67
37
|
environments: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
68
38
|
debug: z.ZodOptional<z.ZodBoolean>;
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
72
|
-
debug: z.ZodOptional<z.ZodBoolean>;
|
|
73
|
-
}, z.ZodTypeAny, "passthrough">>>;
|
|
74
|
-
auth: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
39
|
+
}, z.core.$loose>>;
|
|
40
|
+
auth: z.ZodCustom<(req: Request) => unknown, (req: Request) => unknown>;
|
|
75
41
|
accessGroups: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
76
42
|
description: z.ZodString;
|
|
77
|
-
},
|
|
78
|
-
description: string;
|
|
79
|
-
}, {
|
|
80
|
-
description: string;
|
|
81
|
-
}>>;
|
|
43
|
+
}, z.core.$strip>>;
|
|
82
44
|
entities: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
83
45
|
description: z.ZodString;
|
|
84
|
-
},
|
|
85
|
-
description: string;
|
|
86
|
-
}, {
|
|
87
|
-
description: string;
|
|
88
|
-
}>>>;
|
|
46
|
+
}, z.core.$strip>>>;
|
|
89
47
|
functions: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
90
48
|
description: z.ZodString;
|
|
91
|
-
access: z.ZodArray<z.ZodString
|
|
92
|
-
entities: z.ZodArray<z.ZodString
|
|
93
|
-
inputs: z.
|
|
94
|
-
outputs: z.ZodOptional<z.
|
|
95
|
-
resolver: z.
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
access: string[];
|
|
99
|
-
entities: string[];
|
|
100
|
-
inputs: z.ZodType<any, z.ZodTypeDef, any>;
|
|
101
|
-
resolver: (...args: unknown[]) => unknown;
|
|
102
|
-
outputs?: z.ZodType<any, z.ZodTypeDef, any> | undefined;
|
|
103
|
-
}, {
|
|
104
|
-
description: string;
|
|
105
|
-
access: string[];
|
|
106
|
-
entities: string[];
|
|
107
|
-
inputs: z.ZodType<any, z.ZodTypeDef, any>;
|
|
108
|
-
resolver: (...args: unknown[]) => unknown;
|
|
109
|
-
outputs?: z.ZodType<any, z.ZodTypeDef, any> | undefined;
|
|
110
|
-
}>>;
|
|
111
|
-
}, "strip", z.ZodTypeAny, {
|
|
112
|
-
name: string;
|
|
113
|
-
environments: Record<string, z.objectOutputType<{
|
|
114
|
-
debug: z.ZodOptional<z.ZodBoolean>;
|
|
115
|
-
}, z.ZodTypeAny, "passthrough">>;
|
|
116
|
-
auth: (...args: unknown[]) => unknown;
|
|
117
|
-
accessGroups: Record<string, {
|
|
118
|
-
description: string;
|
|
119
|
-
}>;
|
|
120
|
-
functions: Record<string, {
|
|
121
|
-
description: string;
|
|
122
|
-
access: string[];
|
|
123
|
-
entities: string[];
|
|
124
|
-
inputs: z.ZodType<any, z.ZodTypeDef, any>;
|
|
125
|
-
resolver: (...args: unknown[]) => unknown;
|
|
126
|
-
outputs?: z.ZodType<any, z.ZodTypeDef, any> | undefined;
|
|
127
|
-
}>;
|
|
128
|
-
entities?: Record<string, {
|
|
129
|
-
description: string;
|
|
130
|
-
}> | undefined;
|
|
131
|
-
}, {
|
|
132
|
-
name: string;
|
|
133
|
-
environments: Record<string, z.objectInputType<{
|
|
134
|
-
debug: z.ZodOptional<z.ZodBoolean>;
|
|
135
|
-
}, z.ZodTypeAny, "passthrough">>;
|
|
136
|
-
auth: (...args: unknown[]) => unknown;
|
|
137
|
-
accessGroups: Record<string, {
|
|
138
|
-
description: string;
|
|
139
|
-
}>;
|
|
140
|
-
functions: Record<string, {
|
|
141
|
-
description: string;
|
|
142
|
-
access: string[];
|
|
143
|
-
entities: string[];
|
|
144
|
-
inputs: z.ZodType<any, z.ZodTypeDef, any>;
|
|
145
|
-
resolver: (...args: unknown[]) => unknown;
|
|
146
|
-
outputs?: z.ZodType<any, z.ZodTypeDef, any> | undefined;
|
|
147
|
-
}>;
|
|
148
|
-
entities?: Record<string, {
|
|
149
|
-
description: string;
|
|
150
|
-
}> | undefined;
|
|
151
|
-
}>;
|
|
49
|
+
access: z.ZodArray<z.ZodString>;
|
|
50
|
+
entities: z.ZodArray<z.ZodString>;
|
|
51
|
+
inputs: z.ZodCustom<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>;
|
|
52
|
+
outputs: z.ZodOptional<z.ZodCustom<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>>>;
|
|
53
|
+
resolver: z.ZodCustom<(...args: unknown[]) => unknown, (...args: unknown[]) => unknown>;
|
|
54
|
+
}, z.core.$strip>>;
|
|
55
|
+
}, z.core.$strip>;
|
|
152
56
|
/**
|
|
153
57
|
* Validate that all function access groups exist in accessGroups
|
|
154
58
|
*/
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for inspecting Zod schemas.
|
|
3
|
+
* These use duck typing to work across Zod 3 and Zod 4.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if a value is a Zod schema (duck typing to work across bundle boundaries and Zod versions)
|
|
7
|
+
*/
|
|
8
|
+
export declare function isZodSchema(val: unknown): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Get the Zod type name from a schema (works with both Zod 3 and 4)
|
|
11
|
+
*/
|
|
12
|
+
export declare function getZodTypeName(schema: unknown): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Check if schema is a ZodObject (works with both Zod 3 and 4)
|
|
15
|
+
*/
|
|
16
|
+
export declare function isZodObject(schema: unknown): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Check if schema is a ZodOptional (works with both Zod 3 and 4)
|
|
19
|
+
*/
|
|
20
|
+
export declare function isZodOptional(schema: unknown): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Check if schema is a ZodNullable (works with both Zod 3 and 4)
|
|
23
|
+
*/
|
|
24
|
+
export declare function isZodNullable(schema: unknown): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Check if schema is a ZodArray (works with both Zod 3 and 4)
|
|
27
|
+
*/
|
|
28
|
+
export declare function isZodArray(schema: unknown): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Check if schema is a ZodDefault (works with both Zod 3 and 4)
|
|
31
|
+
*/
|
|
32
|
+
export declare function isZodDefault(schema: unknown): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Get the shape of a ZodObject schema (works with both Zod 3 and 4)
|
|
35
|
+
*/
|
|
36
|
+
export declare function getObjectShape(schema: unknown): Record<string, unknown> | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Get the inner schema from Optional/Nullable/Default (works with both Zod 3 and 4)
|
|
39
|
+
*/
|
|
40
|
+
export declare function getInnerSchema(schema: unknown): unknown;
|
|
41
|
+
/**
|
|
42
|
+
* Get the element schema from a ZodArray (works with both Zod 3 and 4)
|
|
43
|
+
*/
|
|
44
|
+
export declare function getArrayElement(schema: unknown): unknown;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ont-run",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Ontology-enforced API framework for AI coding agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -35,8 +35,7 @@
|
|
|
35
35
|
"consola": "^3.2.0",
|
|
36
36
|
"hono": "^4.6.0",
|
|
37
37
|
"open": "^10.0.0",
|
|
38
|
-
"zod": "
|
|
39
|
-
"zod-to-json-schema": "^3.23.0"
|
|
38
|
+
"zod": "4"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@types/bun": "latest",
|
package/src/browser/transform.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
3
2
|
import type { OntologyConfig } from "../config/types.js";
|
|
4
3
|
import type { OntologyDiff, FunctionChange } from "../lockfile/types.js";
|
|
5
4
|
import { getFieldFromMetadata, getUserContextFields } from "../config/categorical.js";
|
|
5
|
+
import {
|
|
6
|
+
isZodObject,
|
|
7
|
+
isZodOptional,
|
|
8
|
+
isZodNullable,
|
|
9
|
+
isZodArray,
|
|
10
|
+
isZodDefault,
|
|
11
|
+
getObjectShape,
|
|
12
|
+
getInnerSchema,
|
|
13
|
+
getArrayElement,
|
|
14
|
+
} from "../config/zod-utils.js";
|
|
6
15
|
|
|
7
16
|
export type NodeType = "entity" | "function" | "accessGroup";
|
|
8
17
|
export type EdgeType = "operates-on" | "requires-access" | "depends-on";
|
|
@@ -80,30 +89,44 @@ function extractFieldReferences(
|
|
|
80
89
|
});
|
|
81
90
|
}
|
|
82
91
|
|
|
83
|
-
if (schema
|
|
84
|
-
const shape = schema
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
if (isZodObject(schema)) {
|
|
93
|
+
const shape = getObjectShape(schema);
|
|
94
|
+
if (shape) {
|
|
95
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
96
|
+
const fieldPath = path ? `${path}.${key}` : key;
|
|
97
|
+
results.push(
|
|
98
|
+
...extractFieldReferences(value as z.ZodType<unknown>, fieldPath)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
90
101
|
}
|
|
91
102
|
}
|
|
92
103
|
|
|
93
|
-
if (schema
|
|
94
|
-
|
|
104
|
+
if (isZodOptional(schema)) {
|
|
105
|
+
const inner = getInnerSchema(schema);
|
|
106
|
+
if (inner) {
|
|
107
|
+
results.push(...extractFieldReferences(inner as z.ZodType<unknown>, path));
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
110
|
|
|
97
|
-
if (schema
|
|
98
|
-
|
|
111
|
+
if (isZodNullable(schema)) {
|
|
112
|
+
const inner = getInnerSchema(schema);
|
|
113
|
+
if (inner) {
|
|
114
|
+
results.push(...extractFieldReferences(inner as z.ZodType<unknown>, path));
|
|
115
|
+
}
|
|
99
116
|
}
|
|
100
117
|
|
|
101
|
-
if (schema
|
|
102
|
-
|
|
118
|
+
if (isZodArray(schema)) {
|
|
119
|
+
const element = getArrayElement(schema);
|
|
120
|
+
if (element) {
|
|
121
|
+
results.push(...extractFieldReferences(element as z.ZodType<unknown>, `${path}[]`));
|
|
122
|
+
}
|
|
103
123
|
}
|
|
104
124
|
|
|
105
|
-
if (schema
|
|
106
|
-
|
|
125
|
+
if (isZodDefault(schema)) {
|
|
126
|
+
const inner = getInnerSchema(schema);
|
|
127
|
+
if (inner) {
|
|
128
|
+
results.push(...extractFieldReferences(inner as z.ZodType<unknown>, path));
|
|
129
|
+
}
|
|
107
130
|
}
|
|
108
131
|
|
|
109
132
|
return results;
|
|
@@ -114,7 +137,7 @@ function extractFieldReferences(
|
|
|
114
137
|
*/
|
|
115
138
|
function safeZodToJsonSchema(schema: z.ZodTypeAny): Record<string, unknown> | undefined {
|
|
116
139
|
try {
|
|
117
|
-
const result =
|
|
140
|
+
const result = z.toJSONSchema(schema, { reused: "inline", unrepresentable: "any" }) as Record<string, unknown>;
|
|
118
141
|
delete result.$schema;
|
|
119
142
|
return result;
|
|
120
143
|
} catch {
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -54,6 +54,11 @@ export const initCommand = defineCommand({
|
|
|
54
54
|
const configTemplate = `import { defineOntology, userContext } from 'ont-run';
|
|
55
55
|
import { z } from 'zod';
|
|
56
56
|
|
|
57
|
+
// Import resolver functions - TypeScript enforces return types match outputs
|
|
58
|
+
import healthCheck from './resolvers/healthCheck.js';
|
|
59
|
+
import getUser from './resolvers/getUser.js';
|
|
60
|
+
import deleteUser from './resolvers/deleteUser.js';
|
|
61
|
+
|
|
57
62
|
export default defineOntology({
|
|
58
63
|
name: 'my-api',
|
|
59
64
|
|
|
@@ -98,7 +103,7 @@ export default defineOntology({
|
|
|
98
103
|
access: ['public', 'support', 'admin'],
|
|
99
104
|
entities: [],
|
|
100
105
|
inputs: z.object({}),
|
|
101
|
-
resolver:
|
|
106
|
+
resolver: healthCheck,
|
|
102
107
|
},
|
|
103
108
|
|
|
104
109
|
// Example: Restricted function with row-level access
|
|
@@ -114,7 +119,7 @@ export default defineOntology({
|
|
|
114
119
|
email: z.string(),
|
|
115
120
|
})),
|
|
116
121
|
}),
|
|
117
|
-
resolver:
|
|
122
|
+
resolver: getUser,
|
|
118
123
|
},
|
|
119
124
|
|
|
120
125
|
// Example: Admin-only function
|
|
@@ -126,7 +131,7 @@ export default defineOntology({
|
|
|
126
131
|
userId: z.string().uuid(),
|
|
127
132
|
reason: z.string().optional(),
|
|
128
133
|
}),
|
|
129
|
-
resolver:
|
|
134
|
+
resolver: deleteUser,
|
|
130
135
|
},
|
|
131
136
|
},
|
|
132
137
|
});
|
|
@@ -138,7 +143,7 @@ export default defineOntology({
|
|
|
138
143
|
// Write example resolvers
|
|
139
144
|
const healthCheckResolver = `import type { ResolverContext } from 'ont-run';
|
|
140
145
|
|
|
141
|
-
export default async function healthCheck(ctx: ResolverContext
|
|
146
|
+
export default async function healthCheck(ctx: ResolverContext) {
|
|
142
147
|
ctx.logger.info('Health check called');
|
|
143
148
|
|
|
144
149
|
return {
|
|
@@ -237,7 +242,7 @@ await startOnt();
|
|
|
237
242
|
packageJson.dependencies = {
|
|
238
243
|
...(packageJson.dependencies as Record<string, string> || {}),
|
|
239
244
|
"ont-run": "latest",
|
|
240
|
-
zod: "^
|
|
245
|
+
zod: "^4.0.0",
|
|
241
246
|
};
|
|
242
247
|
|
|
243
248
|
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
package/src/config/define.ts
CHANGED
|
@@ -56,7 +56,9 @@ import type {
|
|
|
56
56
|
export function defineOntology<
|
|
57
57
|
TGroups extends string,
|
|
58
58
|
TEntities extends string,
|
|
59
|
-
|
|
59
|
+
// Use `any` for input/output schema types to avoid contravariance issues with resolver functions.
|
|
60
|
+
// Without this, ResolverFunction<unknown, unknown> won't accept more specific resolver types.
|
|
61
|
+
TFunctions extends Record<string, FunctionDefinition<TGroups, TEntities, any, any>>,
|
|
60
62
|
>(config: {
|
|
61
63
|
name: string;
|
|
62
64
|
environments: Record<string, EnvironmentConfig>;
|
package/src/config/schema.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { getFieldFromMetadata, getUserContextFields } from "./categorical.js";
|
|
3
|
+
import {
|
|
4
|
+
isZodSchema,
|
|
5
|
+
isZodObject,
|
|
6
|
+
isZodOptional,
|
|
7
|
+
isZodNullable,
|
|
8
|
+
isZodArray,
|
|
9
|
+
isZodDefault,
|
|
10
|
+
getObjectShape,
|
|
11
|
+
getInnerSchema,
|
|
12
|
+
getArrayElement,
|
|
13
|
+
} from "./zod-utils.js";
|
|
3
14
|
import type { OntologyConfig } from "./types.js";
|
|
4
15
|
|
|
5
16
|
/**
|
|
@@ -26,16 +37,10 @@ export const EntityDefinitionSchema = z.object({
|
|
|
26
37
|
});
|
|
27
38
|
|
|
28
39
|
/**
|
|
29
|
-
* Check if a value is a
|
|
40
|
+
* Check if a value is a function
|
|
30
41
|
*/
|
|
31
|
-
function
|
|
32
|
-
return
|
|
33
|
-
val !== null &&
|
|
34
|
-
typeof val === "object" &&
|
|
35
|
-
"_def" in val &&
|
|
36
|
-
"safeParse" in val &&
|
|
37
|
-
typeof (val as { safeParse: unknown }).safeParse === "function"
|
|
38
|
-
);
|
|
42
|
+
function isFunction(val: unknown): val is (...args: unknown[]) => unknown {
|
|
43
|
+
return typeof val === "function";
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
/**
|
|
@@ -53,24 +58,20 @@ export const FunctionDefinitionSchema = z.object({
|
|
|
53
58
|
message: "outputs must be a Zod schema",
|
|
54
59
|
})
|
|
55
60
|
.optional(),
|
|
56
|
-
resolver: z.
|
|
61
|
+
resolver: z.custom<(...args: unknown[]) => unknown>(isFunction, {
|
|
62
|
+
message: "resolver must be a function",
|
|
63
|
+
}),
|
|
57
64
|
});
|
|
58
65
|
|
|
59
|
-
/**
|
|
60
|
-
* Schema for auth function
|
|
61
|
-
*/
|
|
62
|
-
export const AuthFunctionSchema = z
|
|
63
|
-
.function()
|
|
64
|
-
.args(z.custom<Request>())
|
|
65
|
-
.returns(z.union([z.array(z.string()), z.promise(z.array(z.string()))]));
|
|
66
|
-
|
|
67
66
|
/**
|
|
68
67
|
* Schema for the full ontology configuration
|
|
69
68
|
*/
|
|
70
69
|
export const OntologyConfigSchema = z.object({
|
|
71
70
|
name: z.string().min(1),
|
|
72
71
|
environments: z.record(z.string(), EnvironmentConfigSchema),
|
|
73
|
-
auth: z.
|
|
72
|
+
auth: z.custom<(req: Request) => unknown>(isFunction, {
|
|
73
|
+
message: "auth must be a function",
|
|
74
|
+
}),
|
|
74
75
|
accessGroups: z.record(z.string(), AccessGroupConfigSchema),
|
|
75
76
|
entities: z.record(z.string(), EntityDefinitionSchema).optional(),
|
|
76
77
|
functions: z.record(z.string(), FunctionDefinitionSchema),
|
|
@@ -141,34 +142,48 @@ function extractFieldFromRefs(
|
|
|
141
142
|
}
|
|
142
143
|
|
|
143
144
|
// Handle ZodObject - recurse into properties
|
|
144
|
-
if (schema
|
|
145
|
-
const shape = schema
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
if (isZodObject(schema)) {
|
|
146
|
+
const shape = getObjectShape(schema);
|
|
147
|
+
if (shape) {
|
|
148
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
149
|
+
const fieldPath = path ? `${path}.${key}` : key;
|
|
150
|
+
results.push(
|
|
151
|
+
...extractFieldFromRefs(value as z.ZodType<unknown>, fieldPath)
|
|
152
|
+
);
|
|
153
|
+
}
|
|
151
154
|
}
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
// Handle ZodOptional - unwrap
|
|
155
|
-
if (schema
|
|
156
|
-
|
|
158
|
+
if (isZodOptional(schema)) {
|
|
159
|
+
const inner = getInnerSchema(schema);
|
|
160
|
+
if (inner) {
|
|
161
|
+
results.push(...extractFieldFromRefs(inner as z.ZodType<unknown>, path));
|
|
162
|
+
}
|
|
157
163
|
}
|
|
158
164
|
|
|
159
165
|
// Handle ZodNullable - unwrap
|
|
160
|
-
if (schema
|
|
161
|
-
|
|
166
|
+
if (isZodNullable(schema)) {
|
|
167
|
+
const inner = getInnerSchema(schema);
|
|
168
|
+
if (inner) {
|
|
169
|
+
results.push(...extractFieldFromRefs(inner as z.ZodType<unknown>, path));
|
|
170
|
+
}
|
|
162
171
|
}
|
|
163
172
|
|
|
164
173
|
// Handle ZodArray - recurse into element
|
|
165
|
-
if (schema
|
|
166
|
-
|
|
174
|
+
if (isZodArray(schema)) {
|
|
175
|
+
const element = getArrayElement(schema);
|
|
176
|
+
if (element) {
|
|
177
|
+
results.push(...extractFieldFromRefs(element as z.ZodType<unknown>, `${path}[]`));
|
|
178
|
+
}
|
|
167
179
|
}
|
|
168
180
|
|
|
169
181
|
// Handle ZodDefault - unwrap
|
|
170
|
-
if (schema
|
|
171
|
-
|
|
182
|
+
if (isZodDefault(schema)) {
|
|
183
|
+
const inner = getInnerSchema(schema);
|
|
184
|
+
if (inner) {
|
|
185
|
+
results.push(...extractFieldFromRefs(inner as z.ZodType<unknown>, path));
|
|
186
|
+
}
|
|
172
187
|
}
|
|
173
188
|
|
|
174
189
|
return results;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for inspecting Zod schemas.
|
|
3
|
+
* These use duck typing to work across Zod 3 and Zod 4.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Check if a value is a Zod schema (duck typing to work across bundle boundaries and Zod versions)
|
|
8
|
+
*/
|
|
9
|
+
export function isZodSchema(val: unknown): boolean {
|
|
10
|
+
if (val === null || typeof val !== "object") return false;
|
|
11
|
+
// Zod 4 uses _zod property
|
|
12
|
+
if ("_zod" in val && "safeParse" in val) return true;
|
|
13
|
+
// Zod 3 uses _def property
|
|
14
|
+
if ("_def" in val && "safeParse" in val) return true;
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get the Zod type name from a schema (works with both Zod 3 and 4)
|
|
20
|
+
*/
|
|
21
|
+
export function getZodTypeName(schema: unknown): string | undefined {
|
|
22
|
+
if (!isZodSchema(schema)) return undefined;
|
|
23
|
+
const s = schema as Record<string, unknown>;
|
|
24
|
+
// Zod 4: check _zod.def.typeName
|
|
25
|
+
if (s._zod && typeof s._zod === "object") {
|
|
26
|
+
const zod = s._zod as Record<string, unknown>;
|
|
27
|
+
if (zod.def && typeof zod.def === "object") {
|
|
28
|
+
const def = zod.def as Record<string, unknown>;
|
|
29
|
+
if (typeof def.typeName === "string") return def.typeName;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Zod 3: check _def.typeName
|
|
33
|
+
if (s._def && typeof s._def === "object") {
|
|
34
|
+
const def = s._def as Record<string, unknown>;
|
|
35
|
+
if (typeof def.typeName === "string") return def.typeName;
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Check if schema is a ZodObject (works with both Zod 3 and 4)
|
|
42
|
+
*/
|
|
43
|
+
export function isZodObject(schema: unknown): boolean {
|
|
44
|
+
const typeName = getZodTypeName(schema);
|
|
45
|
+
return typeName === "ZodObject" || typeName === "object";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if schema is a ZodOptional (works with both Zod 3 and 4)
|
|
50
|
+
*/
|
|
51
|
+
export function isZodOptional(schema: unknown): boolean {
|
|
52
|
+
const typeName = getZodTypeName(schema);
|
|
53
|
+
return typeName === "ZodOptional" || typeName === "optional";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if schema is a ZodNullable (works with both Zod 3 and 4)
|
|
58
|
+
*/
|
|
59
|
+
export function isZodNullable(schema: unknown): boolean {
|
|
60
|
+
const typeName = getZodTypeName(schema);
|
|
61
|
+
return typeName === "ZodNullable" || typeName === "nullable";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if schema is a ZodArray (works with both Zod 3 and 4)
|
|
66
|
+
*/
|
|
67
|
+
export function isZodArray(schema: unknown): boolean {
|
|
68
|
+
const typeName = getZodTypeName(schema);
|
|
69
|
+
return typeName === "ZodArray" || typeName === "array";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Check if schema is a ZodDefault (works with both Zod 3 and 4)
|
|
74
|
+
*/
|
|
75
|
+
export function isZodDefault(schema: unknown): boolean {
|
|
76
|
+
const typeName = getZodTypeName(schema);
|
|
77
|
+
return typeName === "ZodDefault" || typeName === "default";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get the shape of a ZodObject schema (works with both Zod 3 and 4)
|
|
82
|
+
*/
|
|
83
|
+
export function getObjectShape(schema: unknown): Record<string, unknown> | undefined {
|
|
84
|
+
if (!isZodObject(schema)) return undefined;
|
|
85
|
+
const s = schema as Record<string, unknown>;
|
|
86
|
+
// Zod 4: shape is in _zod.def.shape
|
|
87
|
+
if (s._zod && typeof s._zod === "object") {
|
|
88
|
+
const zod = s._zod as Record<string, unknown>;
|
|
89
|
+
if (zod.def && typeof zod.def === "object") {
|
|
90
|
+
const def = zod.def as Record<string, unknown>;
|
|
91
|
+
if (def.shape && typeof def.shape === "object") {
|
|
92
|
+
return def.shape as Record<string, unknown>;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Zod 3: shape property directly on schema
|
|
97
|
+
if (typeof s.shape === "object" && s.shape !== null) {
|
|
98
|
+
return s.shape as Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Get the inner schema from Optional/Nullable/Default (works with both Zod 3 and 4)
|
|
105
|
+
*/
|
|
106
|
+
export function getInnerSchema(schema: unknown): unknown {
|
|
107
|
+
const s = schema as Record<string, unknown>;
|
|
108
|
+
// Zod 4: innerType is in _zod.def.innerType
|
|
109
|
+
if (s._zod && typeof s._zod === "object") {
|
|
110
|
+
const zod = s._zod as Record<string, unknown>;
|
|
111
|
+
if (zod.def && typeof zod.def === "object") {
|
|
112
|
+
const def = zod.def as Record<string, unknown>;
|
|
113
|
+
if (def.innerType) return def.innerType;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Zod 3: unwrap method or _def.innerType
|
|
117
|
+
if (typeof s.unwrap === "function") {
|
|
118
|
+
return (s.unwrap as () => unknown)();
|
|
119
|
+
}
|
|
120
|
+
if (s._def && typeof s._def === "object") {
|
|
121
|
+
const def = s._def as Record<string, unknown>;
|
|
122
|
+
if (def.innerType) return def.innerType;
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get the element schema from a ZodArray (works with both Zod 3 and 4)
|
|
129
|
+
*/
|
|
130
|
+
export function getArrayElement(schema: unknown): unknown {
|
|
131
|
+
if (!isZodArray(schema)) return undefined;
|
|
132
|
+
const s = schema as Record<string, unknown>;
|
|
133
|
+
// Zod 4: element is in _zod.def.element
|
|
134
|
+
if (s._zod && typeof s._zod === "object") {
|
|
135
|
+
const zod = s._zod as Record<string, unknown>;
|
|
136
|
+
if (zod.def && typeof zod.def === "object") {
|
|
137
|
+
const def = zod.def as Record<string, unknown>;
|
|
138
|
+
if (def.element) return def.element;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Zod 3: element property directly on schema
|
|
142
|
+
if (s.element) return s.element;
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|