ont-run 0.0.5 → 0.0.7

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.
@@ -132,7 +132,6 @@ export declare function hasUserContextMetadata(schema: unknown): schema is UserC
132
132
  /**
133
133
  * Get all userContext field names from a Zod object schema
134
134
  *
135
- * Note: Uses _def.typeName check instead of instanceof to work across
136
- * module boundaries in bundled CLI.
135
+ * Note: Uses zod-utils for bundler compatibility (instanceof fails across module boundaries)
137
136
  */
138
137
  export declare function getUserContextFields(schema: z.ZodType): string[];
@@ -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
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
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
- }, "strip", z.ZodTypeAny, {
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
- }, "strip", z.ZodTypeAny, {
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, "many">;
39
- entities: z.ZodArray<z.ZodString, "many">;
40
- inputs: z.ZodType<z.ZodType<any, z.ZodTypeDef, any>, z.ZodTypeDef, z.ZodType<any, z.ZodTypeDef, any>>;
41
- outputs: z.ZodOptional<z.ZodType<z.ZodType<any, z.ZodTypeDef, any>, z.ZodTypeDef, z.ZodType<any, z.ZodTypeDef, any>>>;
42
- resolver: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
43
- }, "strip", z.ZodTypeAny, {
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
- }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
70
- debug: z.ZodOptional<z.ZodBoolean>;
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
- }, "strip", z.ZodTypeAny, {
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
- }, "strip", z.ZodTypeAny, {
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, "many">;
92
- entities: z.ZodArray<z.ZodString, "many">;
93
- inputs: z.ZodType<z.ZodType<any, z.ZodTypeDef, any>, z.ZodTypeDef, z.ZodType<any, z.ZodTypeDef, any>>;
94
- outputs: z.ZodOptional<z.ZodType<z.ZodType<any, z.ZodTypeDef, any>, z.ZodTypeDef, z.ZodType<any, z.ZodTypeDef, any>>>;
95
- resolver: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
96
- }, "strip", z.ZodTypeAny, {
97
- description: string;
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,48 @@
1
+ /**
2
+ * Utility functions for inspecting Zod 4 schemas.
3
+ * These use duck typing to work across bundle boundaries.
4
+ */
5
+ /**
6
+ * Check if a value is a Zod 3 schema (has _def but not _zod)
7
+ */
8
+ export declare function isZod3Schema(val: unknown): boolean;
9
+ /**
10
+ * Check if a value is a Zod schema (duck typing to work across bundle boundaries)
11
+ */
12
+ export declare function isZodSchema(val: unknown): boolean;
13
+ /**
14
+ * Get the Zod type name from a schema
15
+ */
16
+ export declare function getZodTypeName(schema: unknown): string | undefined;
17
+ /**
18
+ * Check if schema is a ZodObject
19
+ */
20
+ export declare function isZodObject(schema: unknown): boolean;
21
+ /**
22
+ * Check if schema is a ZodOptional
23
+ */
24
+ export declare function isZodOptional(schema: unknown): boolean;
25
+ /**
26
+ * Check if schema is a ZodNullable
27
+ */
28
+ export declare function isZodNullable(schema: unknown): boolean;
29
+ /**
30
+ * Check if schema is a ZodArray
31
+ */
32
+ export declare function isZodArray(schema: unknown): boolean;
33
+ /**
34
+ * Check if schema is a ZodDefault
35
+ */
36
+ export declare function isZodDefault(schema: unknown): boolean;
37
+ /**
38
+ * Get the shape of a ZodObject schema
39
+ */
40
+ export declare function getObjectShape(schema: unknown): Record<string, unknown> | undefined;
41
+ /**
42
+ * Get the inner schema from Optional/Nullable/Default
43
+ */
44
+ export declare function getInnerSchema(schema: unknown): unknown;
45
+ /**
46
+ * Get the element schema from a ZodArray
47
+ */
48
+ 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.5",
3
+ "version": "0.0.7",
4
4
  "description": "Ontology-enforced API framework for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "scripts": {
22
22
  "dev": "bun run bin/ont.ts",
23
23
  "build": "bun build ./src/index.ts --outdir ./dist --target node",
24
- "build:cli": "bun build ./bin/ont.ts --outfile ./dist/bin/ont.js --target node --external @modelcontextprotocol/sdk",
24
+ "build:cli": "bun build ./bin/ont.ts --outfile ./dist/bin/ont.js --target node --external @modelcontextprotocol/sdk --external zod",
25
25
  "build:types": "tsc --declaration --emitDeclarationOnly",
26
26
  "prepublishOnly": "bun run build && bun run build:cli && bun run build:types",
27
27
  "docs": "cd docs && bun run dev",
@@ -34,16 +34,16 @@
34
34
  "citty": "^0.1.6",
35
35
  "consola": "^3.2.0",
36
36
  "hono": "^4.6.0",
37
- "open": "^10.0.0",
38
- "zod": "^3.24.0",
39
- "zod-to-json-schema": "^3.23.0"
37
+ "open": "^10.0.0"
40
38
  },
41
39
  "devDependencies": {
42
40
  "@types/bun": "latest",
43
- "typescript": "^5.5.0"
41
+ "typescript": "^5.5.0",
42
+ "zod": "^4.0.0"
44
43
  },
45
44
  "peerDependencies": {
46
- "bun": ">=1.0.0"
45
+ "bun": ">=1.0.0",
46
+ "zod": ">=4"
47
47
  },
48
48
  "peerDependenciesMeta": {
49
49
  "bun": {
@@ -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 instanceof z.ZodObject) {
84
- const shape = schema.shape;
85
- for (const [key, value] of Object.entries(shape)) {
86
- const fieldPath = path ? `${path}.${key}` : key;
87
- results.push(
88
- ...extractFieldReferences(value as z.ZodType<unknown>, fieldPath)
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 instanceof z.ZodOptional) {
94
- results.push(...extractFieldReferences(schema.unwrap(), path));
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 instanceof z.ZodNullable) {
98
- results.push(...extractFieldReferences(schema.unwrap(), path));
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 instanceof z.ZodArray) {
102
- results.push(...extractFieldReferences(schema.element, `${path}[]`));
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 instanceof z.ZodDefault) {
106
- results.push(...extractFieldReferences(schema._def.innerType, path));
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 = zodToJsonSchema(schema, { $refStrategy: "none" }) as Record<string, unknown>;
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 {
@@ -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: './resolvers/healthCheck.ts',
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: './resolvers/getUser.ts',
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: './resolvers/deleteUser.ts',
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, args: {}) {
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: "^3.24.0",
245
+ zod: "^4.0.0",
241
246
  };
242
247
 
243
248
  writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { isZodObject, getObjectShape } from "./zod-utils";
2
3
 
3
4
  /**
4
5
  * Symbol for storing fieldFrom metadata on Zod schemas
@@ -175,19 +176,18 @@ export function hasUserContextMetadata(
175
176
  /**
176
177
  * Get all userContext field names from a Zod object schema
177
178
  *
178
- * Note: Uses _def.typeName check instead of instanceof to work across
179
- * module boundaries in bundled CLI.
179
+ * Note: Uses zod-utils for bundler compatibility (instanceof fails across module boundaries)
180
180
  */
181
181
  export function getUserContextFields(schema: z.ZodType): string[] {
182
182
  const fields: string[] = [];
183
183
 
184
- // Use _def.typeName check for bundler compatibility (instanceof fails across module boundaries)
185
- const def = (schema as unknown as { _def?: { typeName?: string; shape?: () => Record<string, unknown> } })._def;
186
- if (def?.typeName === "ZodObject" && typeof def.shape === "function") {
187
- const shape = def.shape();
188
- for (const [key, value] of Object.entries(shape)) {
189
- if (hasUserContextMetadata(value)) {
190
- fields.push(key);
184
+ if (isZodObject(schema)) {
185
+ const shape = getObjectShape(schema);
186
+ if (shape) {
187
+ for (const [key, value] of Object.entries(shape)) {
188
+ if (hasUserContextMetadata(value)) {
189
+ fields.push(key);
190
+ }
191
191
  }
192
192
  }
193
193
  }
@@ -56,7 +56,9 @@ import type {
56
56
  export function defineOntology<
57
57
  TGroups extends string,
58
58
  TEntities extends string,
59
- TFunctions extends Record<string, FunctionDefinition<TGroups, TEntities>>,
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>;
@@ -1,5 +1,17 @@
1
1
  import { z } from "zod";
2
2
  import { getFieldFromMetadata, getUserContextFields } from "./categorical.js";
3
+ import {
4
+ isZodSchema,
5
+ isZod3Schema,
6
+ isZodObject,
7
+ isZodOptional,
8
+ isZodNullable,
9
+ isZodArray,
10
+ isZodDefault,
11
+ getObjectShape,
12
+ getInnerSchema,
13
+ getArrayElement,
14
+ } from "./zod-utils.js";
3
15
  import type { OntologyConfig } from "./types.js";
4
16
 
5
17
  /**
@@ -26,16 +38,24 @@ export const EntityDefinitionSchema = z.object({
26
38
  });
27
39
 
28
40
  /**
29
- * Check if a value is a Zod schema (duck typing to work across bundle boundaries)
41
+ * Check if a value is a function
30
42
  */
31
- function isZodSchema(val: unknown): boolean {
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
- );
43
+ function isFunction(val: unknown): val is (...args: unknown[]) => unknown {
44
+ return typeof val === "function";
45
+ }
46
+
47
+ /**
48
+ * Validate that a value is a Zod 4 schema, with helpful error for Zod 3
49
+ */
50
+ function validateZodSchema(val: unknown, fieldName: string): boolean {
51
+ if (isZodSchema(val)) return true;
52
+ if (isZod3Schema(val)) {
53
+ throw new Error(
54
+ `${fieldName} appears to be a Zod 3 schema. ont-run requires Zod 4.\n` +
55
+ `Please upgrade: bun add zod@4`
56
+ );
57
+ }
58
+ return false;
39
59
  }
40
60
 
41
61
  /**
@@ -45,32 +65,28 @@ export const FunctionDefinitionSchema = z.object({
45
65
  description: z.string(),
46
66
  access: z.array(z.string()).min(1),
47
67
  entities: z.array(z.string()),
48
- inputs: z.custom<z.ZodType>(isZodSchema, {
49
- message: "inputs must be a Zod schema",
68
+ inputs: z.custom<z.ZodType>((val) => validateZodSchema(val, "inputs"), {
69
+ message: "inputs must be a Zod 4 schema",
50
70
  }),
51
71
  outputs: z
52
- .custom<z.ZodType>(isZodSchema, {
53
- message: "outputs must be a Zod schema",
72
+ .custom<z.ZodType>((val) => validateZodSchema(val, "outputs"), {
73
+ message: "outputs must be a Zod 4 schema",
54
74
  })
55
75
  .optional(),
56
- resolver: z.function(),
76
+ resolver: z.custom<(...args: unknown[]) => unknown>(isFunction, {
77
+ message: "resolver must be a function",
78
+ }),
57
79
  });
58
80
 
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
81
  /**
68
82
  * Schema for the full ontology configuration
69
83
  */
70
84
  export const OntologyConfigSchema = z.object({
71
85
  name: z.string().min(1),
72
86
  environments: z.record(z.string(), EnvironmentConfigSchema),
73
- auth: z.function(),
87
+ auth: z.custom<(req: Request) => unknown>(isFunction, {
88
+ message: "auth must be a function",
89
+ }),
74
90
  accessGroups: z.record(z.string(), AccessGroupConfigSchema),
75
91
  entities: z.record(z.string(), EntityDefinitionSchema).optional(),
76
92
  functions: z.record(z.string(), FunctionDefinitionSchema),
@@ -141,34 +157,48 @@ function extractFieldFromRefs(
141
157
  }
142
158
 
143
159
  // Handle ZodObject - recurse into properties
144
- if (schema instanceof z.ZodObject) {
145
- const shape = schema.shape;
146
- for (const [key, value] of Object.entries(shape)) {
147
- const fieldPath = path ? `${path}.${key}` : key;
148
- results.push(
149
- ...extractFieldFromRefs(value as z.ZodType<unknown>, fieldPath)
150
- );
160
+ if (isZodObject(schema)) {
161
+ const shape = getObjectShape(schema);
162
+ if (shape) {
163
+ for (const [key, value] of Object.entries(shape)) {
164
+ const fieldPath = path ? `${path}.${key}` : key;
165
+ results.push(
166
+ ...extractFieldFromRefs(value as z.ZodType<unknown>, fieldPath)
167
+ );
168
+ }
151
169
  }
152
170
  }
153
171
 
154
172
  // Handle ZodOptional - unwrap
155
- if (schema instanceof z.ZodOptional) {
156
- results.push(...extractFieldFromRefs(schema.unwrap(), path));
173
+ if (isZodOptional(schema)) {
174
+ const inner = getInnerSchema(schema);
175
+ if (inner) {
176
+ results.push(...extractFieldFromRefs(inner as z.ZodType<unknown>, path));
177
+ }
157
178
  }
158
179
 
159
180
  // Handle ZodNullable - unwrap
160
- if (schema instanceof z.ZodNullable) {
161
- results.push(...extractFieldFromRefs(schema.unwrap(), path));
181
+ if (isZodNullable(schema)) {
182
+ const inner = getInnerSchema(schema);
183
+ if (inner) {
184
+ results.push(...extractFieldFromRefs(inner as z.ZodType<unknown>, path));
185
+ }
162
186
  }
163
187
 
164
188
  // Handle ZodArray - recurse into element
165
- if (schema instanceof z.ZodArray) {
166
- results.push(...extractFieldFromRefs(schema.element, `${path}[]`));
189
+ if (isZodArray(schema)) {
190
+ const element = getArrayElement(schema);
191
+ if (element) {
192
+ results.push(...extractFieldFromRefs(element as z.ZodType<unknown>, `${path}[]`));
193
+ }
167
194
  }
168
195
 
169
196
  // Handle ZodDefault - unwrap
170
- if (schema instanceof z.ZodDefault) {
171
- results.push(...extractFieldFromRefs(schema._def.innerType, path));
197
+ if (isZodDefault(schema)) {
198
+ const inner = getInnerSchema(schema);
199
+ if (inner) {
200
+ results.push(...extractFieldFromRefs(inner as z.ZodType<unknown>, path));
201
+ }
172
202
  }
173
203
 
174
204
  return results;