From 76ceb7f7a8ac302ca4fab6e030818dd699dc6722 Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Fri, 19 Dec 2025 11:25:28 -0500 Subject: [PATCH 1/6] fix:(js/core/schema): Allow disabling runtime schema compilation --- js/core/package.json | 7 ++-- js/core/src/index.ts | 7 +++- js/core/src/schema.ts | 64 +++++++++++++++++++++++++++++- js/core/tests/schema_test.ts | 33 ++++++++++++++-- js/genkit/src/common.ts | 1 + js/pnpm-lock.yaml | 76 ++++++++++++++++++++---------------- 6 files changed, 146 insertions(+), 42 deletions(-) diff --git a/js/core/package.json b/js/core/package.json index 280de87c10..444dbb22d5 100644 --- a/js/core/package.json +++ b/js/core/package.json @@ -26,25 +26,26 @@ "author": "genkit", "license": "Apache-2.0", "dependencies": { + "@cfworker/json-schema": "^4.1.1", "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "~1.25.0", "@opentelemetry/core": "~1.25.0", + "@opentelemetry/exporter-jaeger": "^1.25.0", "@opentelemetry/sdk-metrics": "~1.25.0", "@opentelemetry/sdk-node": "^0.52.0", "@opentelemetry/sdk-trace-base": "~1.25.0", - "@opentelemetry/exporter-jaeger": "^1.25.0", "@types/json-schema": "^7.0.15", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "async-mutex": "^0.5.0", "body-parser": "^1.20.3", "cors": "^2.8.5", + "dotprompt": "^1.1.1", "express": "^4.21.0", "get-port": "^5.1.0", "json-schema": "^0.4.0", "zod": "^3.23.8", - "zod-to-json-schema": "^3.22.4", - "dotprompt": "^1.1.1" + "zod-to-json-schema": "^3.22.4" }, "devDependencies": { "@types/express": "^4.17.21", diff --git a/js/core/src/index.ts b/js/core/src/index.ts index 632b9b30fc..132e4f0855 100644 --- a/js/core/src/index.ts +++ b/js/core/src/index.ts @@ -77,7 +77,12 @@ export { } from './flow.js'; export * from './plugin.js'; export * from './reflection.js'; -export { defineJsonSchema, defineSchema, type JSONSchema } from './schema.js'; +export { + defineJsonSchema, + defineSchema, + disableSchemaCodeGeneration, + type JSONSchema, +} from './schema.js'; export * from './telemetryTypes.js'; export * from './utils.js'; diff --git a/js/core/src/schema.ts b/js/core/src/schema.ts index 9b15b9c071..3021aa2a90 100644 --- a/js/core/src/schema.ts +++ b/js/core/src/schema.ts @@ -14,15 +14,27 @@ * limitations under the License. */ +import { Validator } from '@cfworker/json-schema'; import Ajv, { type ErrorObject, type JSONSchemaType } from 'ajv'; import addFormats from 'ajv-formats'; -import { z } from 'zod'; +import { z, type ZodIssue } from 'zod'; import zodToJsonSchema from 'zod-to-json-schema'; import { GenkitError } from './error.js'; import type { Registry } from './registry.js'; const ajv = new Ajv(); addFormats(ajv); +let validationMode: 'compile' | 'interpret' = 'compile'; + +/** + * Disable schema code generation in runtime. Use this if your runtime + * environment restricts the use of `eval` or `new Function`, for e.g., in + * CloudFlare workers. + */ +export function disableSchemaCodeGeneration() { + validationMode = 'interpret'; +} + export { z }; // provide a consistent zod to use throughout genkit /** @@ -32,6 +44,7 @@ export type JSONSchema = JSONSchemaType | any; const jsonSchemas = new WeakMap(); const validators = new WeakMap>(); +const cfWorkerValidators = new WeakMap(); /** * Wrapper object for various ways schema can be provided. @@ -97,6 +110,28 @@ function toErrorDetail(error: ErrorObject): ValidationErrorDetail { }; } +function zodErrorToValidationErrorDetail( + error: ZodIssue +): ValidationErrorDetail { + return { + path: error.path.join('.') || '(root)', + message: error.message, + }; +} + +function cfWorkerErrorToValidationErrorDetail(error: { + instanceLocation: string; + error: string; +}): ValidationErrorDetail { + const path = error.instanceLocation.startsWith('#/') + ? error.instanceLocation.substring(2) + : ''; + return { + path: path.replace(/\//g, '.') || '(root)', + message: error.error, + }; +} + /** * Validation response. */ @@ -115,6 +150,33 @@ export function validateSchema( if (!toValidate) { return { valid: true, schema: toValidate }; } + + if (options.schema && !options.jsonSchema) { + const parseResult = options.schema.safeParse(data); + if (parseResult.success) { + return { valid: true, schema: toValidate }; + } + return { + valid: false, + errors: parseResult.error.errors.map(zodErrorToValidationErrorDetail), + schema: toValidate, + }; + } + + if (validationMode === 'interpret') { + let validator = cfWorkerValidators.get(toValidate); + if (!validator) { + validator = new Validator(toValidate); + cfWorkerValidators.set(toValidate, validator); + } + const result = validator.validate(data); + return { + valid: result.valid, + errors: result.errors?.map(cfWorkerErrorToValidationErrorDetail), + schema: toValidate, + }; + } + const validator = validators.get(toValidate) || ajv.compile(toValidate); const valid = validator(data) as boolean; const errors = validator.errors?.map((e) => e); diff --git a/js/core/tests/schema_test.ts b/js/core/tests/schema_test.ts index c76abd7bbb..11362ffd55 100644 --- a/js/core/tests/schema_test.ts +++ b/js/core/tests/schema_test.ts @@ -14,11 +14,13 @@ * limitations under the License. */ +import Ajv from 'ajv'; import * as assert from 'assert'; -import { describe, it } from 'node:test'; +import { describe, it, mock } from 'node:test'; import { ValidationError, + disableSchemaCodeGeneration, parseSchema, toJsonSchema, validateSchema, @@ -65,7 +67,7 @@ describe('validate()', () => { schema: z.object({ foo: z.boolean() }), data: { foo: 123 }, valid: false, - errors: [{ path: 'foo', message: 'must be boolean' }], + errors: [{ path: 'foo', message: 'Expected boolean, received number' }], }, { it: 'should allow for date types', @@ -78,7 +80,9 @@ describe('validate()', () => { schema: z.object({ foo: z.array(z.object({ bar: z.boolean() })) }), data: { foo: [{ bar: 123 }] }, valid: false, - errors: [{ path: 'foo.0.bar', message: 'must be boolean' }], + errors: [ + { path: 'foo.0.bar', message: 'Expected boolean, received number' }, + ], }, { it: 'should be understandable for top-level errors', @@ -162,3 +166,26 @@ describe('toJsonSchema', () => { ); }); }); + +describe('disableSchemaCodeGeneration()', () => { + it('should validate using cfworker validator', () => { + const compileMock = mock.method(Ajv.prototype, 'compile'); + + disableSchemaCodeGeneration(); + const result = validateSchema( + { foo: 123 }, + { + jsonSchema: { + type: 'object', + properties: { foo: { type: 'boolean' } }, + }, + } + ); + + assert.strictEqual(result.valid, false); + const errorAtFoo = result.errors?.find((e) => e.path === 'foo'); + assert.ok(errorAtFoo, 'Should have error at foo'); + assert.strictEqual(compileMock.mock.callCount(), 0); + compileMock.mock.restore(); + }); +}); diff --git a/js/genkit/src/common.ts b/js/genkit/src/common.ts index c1f1959521..a22730bd9b 100644 --- a/js/genkit/src/common.ts +++ b/js/genkit/src/common.ts @@ -129,6 +129,7 @@ export { UserFacingError, defineJsonSchema, defineSchema, + disableSchemaCodeGeneration, getClientHeader, getCurrentEnv, getStreamingCallback, diff --git a/js/pnpm-lock.yaml b/js/pnpm-lock.yaml index 454817f405..783ebe491c 100644 --- a/js/pnpm-lock.yaml +++ b/js/pnpm-lock.yaml @@ -96,6 +96,9 @@ importers: core: dependencies: + '@cfworker/json-schema': + specifier: ^4.1.1 + version: 4.1.1 '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -181,7 +184,7 @@ importers: optionalDependencies: '@genkit-ai/firebase': specifier: ^1.16.1 - version: 1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + version: 1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) doc-snippets: dependencies: @@ -1088,7 +1091,7 @@ importers: version: link:../../plugins/compat-oai '@genkit-ai/express': specifier: ^1.1.0 - version: 1.12.0(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit) + version: 1.12.0(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit) genkit: specifier: workspace:* version: link:../../genkit @@ -1705,7 +1708,7 @@ importers: version: link:../../plugins/ollama genkitx-openai: specifier: ^0.10.1 - version: 0.10.1(@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3) + version: 0.10.1(@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3) devDependencies: rimraf: specifier: ^6.0.1 @@ -2336,6 +2339,9 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@cfworker/json-schema@4.1.1': + resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -2767,11 +2773,11 @@ packages: '@firebase/webchannel-wrapper@1.0.3': resolution: {integrity: sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==} - '@genkit-ai/ai@1.26.0-rc.0': - resolution: {integrity: sha512-TrNRK/fSuhM8XHOGAV6lDH9daGYfWCPyW55ZDtH3IeDAVNtfcvOhgmM+uvgtsvjKYeJiDHdwVQeabL1e9tzdYg==} + '@genkit-ai/ai@1.27.0-rc.0': + resolution: {integrity: sha512-sitamvMZTh6TaemuUY8PmDpop7uxVt/txp/bo6H77Y4fqmbjOarQMtaG0OpiegglVUQsFqkcRm6FrnYoU98vlg==} - '@genkit-ai/core@1.26.0-rc.0': - resolution: {integrity: sha512-ZnzyWLeb364csirXJusPKKV5i6ZqzsKHUc9ZKRGBSoPXkrz/w0hLGoPCFjCSbfm3DmRvC45/HOn3uEVtwkN2MA==} + '@genkit-ai/core@1.27.0-rc.0': + resolution: {integrity: sha512-H3vd8zzySUrU2V580HBMC57sbpFqmGYvoMThvykoRWRf3j0I/kEYRkV5N0hxwXqOnS4uTwMXNuAjg0IbTx5O3Q==} '@genkit-ai/express@1.12.0': resolution: {integrity: sha512-QAxSS07dX5ovSfsUB4s90KaDnv4zg1wnoxCZCa+jBsYUyv9NvCCTsOk25xAQgGxc7xi3+MD+3AsPier5oZILIg==} @@ -5948,8 +5954,8 @@ packages: resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} engines: {node: '>=18'} - genkit@1.26.0-rc.0: - resolution: {integrity: sha512-Yx4qtT0ImwE2Nu8ts1lrq4eL/qCa+vFmgNOWnCJLc205Vcco0yZEQ0Wr0OL3sBhIAyLuAfx6CCUPJE735ypTsg==} + genkit@1.27.0-rc.0: + resolution: {integrity: sha512-SODsh+uQbygZu7xaKRitkxIq/mIxPY/MwCYkWGxHSGxXMilGr5ltXgeERiY793XgBvQ4mGEEGyHwO2GN+DrdVw==} genkitx-openai@0.10.1: resolution: {integrity: sha512-E9/DzyQcBUSTy81xT2pvEmdnn9Q/cKoojEt6lD/EdOeinhqE9oa59d/kuXTokCMekTrj3Rk7LtNBQIDjnyjNOA==} @@ -9450,6 +9456,8 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@cfworker/json-schema@4.1.1': {} + '@colors/colors@1.5.0': optional: true @@ -9943,9 +9951,9 @@ snapshots: '@firebase/webchannel-wrapper@1.0.3': {} - '@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@opentelemetry/api': 1.9.0 '@types/node': 20.19.26 colorette: 2.0.20 @@ -9964,9 +9972,9 @@ snapshots: - supports-color optional: true - '@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': + '@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': dependencies: - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) '@opentelemetry/api': 1.9.0 '@types/node': 20.19.26 colorette: 2.0.20 @@ -9984,7 +9992,7 @@ snapshots: - genkit - supports-color - '@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) @@ -10006,7 +10014,7 @@ snapshots: zod: 3.25.76 zod-to-json-schema: 3.25.0(zod@3.25.76) optionalDependencies: - '@genkit-ai/firebase': 1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/firebase': 1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) transitivePeerDependencies: - '@google-cloud/firestore' - encoding @@ -10016,7 +10024,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': + '@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) @@ -10047,9 +10055,9 @@ snapshots: - genkit - supports-color - '@genkit-ai/express@1.12.0(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit)': + '@genkit-ai/express@1.12.0(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit)': dependencies: - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) body-parser: 1.20.3 cors: 2.8.5 express: 5.1.0 @@ -10057,12 +10065,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@genkit-ai/firebase@1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/firebase@1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/google-cloud': 1.16.1(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/google-cloud': 1.16.1(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@google-cloud/firestore': 7.11.6(encoding@0.1.13) firebase-admin: 13.5.0(encoding@0.1.13) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) optionalDependencies: firebase: 11.9.1 transitivePeerDependencies: @@ -10070,12 +10078,12 @@ snapshots: - supports-color optional: true - '@genkit-ai/firebase@1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/firebase@1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/google-cloud': 1.25.0(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/google-cloud': 1.25.0(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@google-cloud/firestore': 7.11.6(encoding@0.1.13) firebase-admin: 13.5.0(encoding@0.1.13) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) optionalDependencies: firebase: 11.9.1 transitivePeerDependencies: @@ -10096,7 +10104,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/google-cloud@1.16.1(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/google-cloud@1.16.1(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@google-cloud/logging-winston': 6.0.1(encoding@0.1.13)(winston@3.17.0) '@google-cloud/opentelemetry-cloud-monitoring-exporter': 0.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.0))(encoding@0.1.13) @@ -10112,7 +10120,7 @@ snapshots: '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) google-auth-library: 9.15.1(encoding@0.1.13) node-fetch: 3.3.2 winston: 3.17.0 @@ -10121,7 +10129,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/google-cloud@1.25.0(encoding@0.1.13)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/google-cloud@1.25.0(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@google-cloud/logging-winston': 6.0.1(encoding@0.1.13)(winston@3.19.0) '@google-cloud/opentelemetry-cloud-monitoring-exporter': 0.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.0))(encoding@0.1.13) @@ -10137,7 +10145,7 @@ snapshots: '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - genkit: 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) google-auth-library: 9.15.1(encoding@0.1.13) node-fetch: 3.3.2 winston: 3.19.0 @@ -13986,10 +13994,10 @@ snapshots: transitivePeerDependencies: - supports-color - genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1): + genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1): dependencies: - '@genkit-ai/ai': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/ai': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) uuid: 10.0.0 transitivePeerDependencies: - '@google-cloud/firestore' @@ -13999,10 +14007,10 @@ snapshots: - supports-color optional: true - genkitx-openai@0.10.1(@genkit-ai/ai@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3): + genkitx-openai@0.10.1(@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3): dependencies: - '@genkit-ai/ai': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) - '@genkit-ai/core': 1.26.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/ai': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) openai: 4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.67) zod: 3.25.67 transitivePeerDependencies: From e00ca105ba1ccb5148755218e95a3066bf10970b Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Fri, 19 Dec 2025 14:14:38 -0500 Subject: [PATCH 2/6] update --- js/core/package.json | 2 +- js/core/src/schema.ts | 13 +++- js/core/tests/schema_test.ts | 13 ++++ js/core/tsconfig.json | 1 + js/plugins/google-cloud/tests/traces_test.ts | 4 +- js/pnpm-lock.yaml | 77 ++++++++++---------- 6 files changed, 66 insertions(+), 44 deletions(-) diff --git a/js/core/package.json b/js/core/package.json index 444dbb22d5..0522ee7acd 100644 --- a/js/core/package.json +++ b/js/core/package.json @@ -26,7 +26,6 @@ "author": "genkit", "license": "Apache-2.0", "dependencies": { - "@cfworker/json-schema": "^4.1.1", "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "~1.25.0", "@opentelemetry/core": "~1.25.0", @@ -58,6 +57,7 @@ "typescript": "^4.9.0" }, "optionalDependencies": { + "@cfworker/json-schema": "^4.1.1", "@genkit-ai/firebase": "^1.16.1" }, "types": "lib/index.d.ts", diff --git a/js/core/src/schema.ts b/js/core/src/schema.ts index 3021aa2a90..69308b520b 100644 --- a/js/core/src/schema.ts +++ b/js/core/src/schema.ts @@ -20,11 +20,12 @@ import addFormats from 'ajv-formats'; import { z, type ZodIssue } from 'zod'; import zodToJsonSchema from 'zod-to-json-schema'; import { GenkitError } from './error.js'; +import { logger } from './logging.js'; import type { Registry } from './registry.js'; const ajv = new Ajv(); addFormats(ajv); -let validationMode: 'compile' | 'interpret' = 'compile'; +const SCHEMA_VALIDATION_MODE = 'schemaValidationMode' as const; /** * Disable schema code generation in runtime. Use this if your runtime @@ -32,7 +33,10 @@ let validationMode: 'compile' | 'interpret' = 'compile'; * CloudFlare workers. */ export function disableSchemaCodeGeneration() { - validationMode = 'interpret'; + logger.warn( + "It looks like you're trying to disable schema code generation. Please ensure that the '@cfworker/json-schema' package is installed: `npm i --save @cfworker/json-schema`" + ); + global[SCHEMA_VALIDATION_MODE] = 'interpret'; } export { z }; // provide a consistent zod to use throughout genkit @@ -150,8 +154,11 @@ export function validateSchema( if (!toValidate) { return { valid: true, schema: toValidate }; } + const validationMode = (global[SCHEMA_VALIDATION_MODE] ?? 'compile') as + | 'compile' + | 'interpret'; - if (options.schema && !options.jsonSchema) { + if (validationMode === 'compile' && options.schema && !options.jsonSchema) { const parseResult = options.schema.safeParse(data); if (parseResult.success) { return { valid: true, schema: toValidate }; diff --git a/js/core/tests/schema_test.ts b/js/core/tests/schema_test.ts index 11362ffd55..b154116a13 100644 --- a/js/core/tests/schema_test.ts +++ b/js/core/tests/schema_test.ts @@ -188,4 +188,17 @@ describe('disableSchemaCodeGeneration()', () => { assert.strictEqual(compileMock.mock.callCount(), 0); compileMock.mock.restore(); }); + + it('should validate zod schema using cfworker validator', () => { + disableSchemaCodeGeneration(); + const schema = z.object({ foo: z.boolean() }); + const parseSpy = mock.method(schema, 'safeParse'); + + const result = validateSchema({ foo: 123 }, { schema }); + + assert.strictEqual(result.valid, false); + const errorAtFoo = result.errors?.find((e) => e.path === 'foo'); + assert.ok(errorAtFoo, 'Should have error at foo'); + assert.strictEqual(parseSpy.mock.callCount(), 0); + }); }); diff --git a/js/core/tsconfig.json b/js/core/tsconfig.json index d96b77bbbb..e61dfcc81d 100644 --- a/js/core/tsconfig.json +++ b/js/core/tsconfig.json @@ -2,6 +2,7 @@ "extends": "../tsconfig.json", "include": ["src"], "compilerOptions": { + "skipLibCheck": true, // DOM is needed for streaming APIs. "lib": ["es2022", "dom"] } diff --git a/js/plugins/google-cloud/tests/traces_test.ts b/js/plugins/google-cloud/tests/traces_test.ts index c4c64de430..9a7467986d 100644 --- a/js/plugins/google-cloud/tests/traces_test.ts +++ b/js/plugins/google-cloud/tests/traces_test.ts @@ -105,8 +105,8 @@ describe('GoogleCloudTracing', () => { it('sub actions are contained within flows', async () => { const testFlow = createFlow(ai, 'testFlow', async () => { - return await ai.run('subAction', async () => { - return await ai.run('subAction2', async () => { + await ai.run('subAction', async () => { + await ai.run('subAction2', async () => { return 'done'; }); }); diff --git a/js/pnpm-lock.yaml b/js/pnpm-lock.yaml index 783ebe491c..a483ac8f77 100644 --- a/js/pnpm-lock.yaml +++ b/js/pnpm-lock.yaml @@ -96,9 +96,6 @@ importers: core: dependencies: - '@cfworker/json-schema': - specifier: ^4.1.1 - version: 4.1.1 '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 @@ -182,9 +179,12 @@ importers: specifier: ^4.9.0 version: 4.9.5 optionalDependencies: + '@cfworker/json-schema': + specifier: ^4.1.1 + version: 4.1.1 '@genkit-ai/firebase': specifier: ^1.16.1 - version: 1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + version: 1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) doc-snippets: dependencies: @@ -1091,7 +1091,7 @@ importers: version: link:../../plugins/compat-oai '@genkit-ai/express': specifier: ^1.1.0 - version: 1.12.0(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit) + version: 1.12.0(@genkit-ai/core@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit) genkit: specifier: workspace:* version: link:../../genkit @@ -1708,7 +1708,7 @@ importers: version: link:../../plugins/ollama genkitx-openai: specifier: ^0.10.1 - version: 0.10.1(@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3) + version: 0.10.1(@genkit-ai/ai@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3) devDependencies: rimraf: specifier: ^6.0.1 @@ -2773,11 +2773,11 @@ packages: '@firebase/webchannel-wrapper@1.0.3': resolution: {integrity: sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==} - '@genkit-ai/ai@1.27.0-rc.0': - resolution: {integrity: sha512-sitamvMZTh6TaemuUY8PmDpop7uxVt/txp/bo6H77Y4fqmbjOarQMtaG0OpiegglVUQsFqkcRm6FrnYoU98vlg==} + '@genkit-ai/ai@1.27.0-rc.1': + resolution: {integrity: sha512-Fc7vj26b+vG2GxQzPM6hR2sTq+h2WidKohaCjyu/Uc8um9Cx1qDVXNjyt3P7t0umgk6AdeTzTeGdiONdbzsapA==} - '@genkit-ai/core@1.27.0-rc.0': - resolution: {integrity: sha512-H3vd8zzySUrU2V580HBMC57sbpFqmGYvoMThvykoRWRf3j0I/kEYRkV5N0hxwXqOnS4uTwMXNuAjg0IbTx5O3Q==} + '@genkit-ai/core@1.27.0-rc.1': + resolution: {integrity: sha512-n5iMTDHPnjAiPYH6sYAJwBsRwkU6fZ6zTryE666ppdEkCqzU7jeFpJ7F3IQpj7/+sDoaE3qhgIQEV9Nc0iMWCg==} '@genkit-ai/express@1.12.0': resolution: {integrity: sha512-QAxSS07dX5ovSfsUB4s90KaDnv4zg1wnoxCZCa+jBsYUyv9NvCCTsOk25xAQgGxc7xi3+MD+3AsPier5oZILIg==} @@ -5954,8 +5954,8 @@ packages: resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} engines: {node: '>=18'} - genkit@1.27.0-rc.0: - resolution: {integrity: sha512-SODsh+uQbygZu7xaKRitkxIq/mIxPY/MwCYkWGxHSGxXMilGr5ltXgeERiY793XgBvQ4mGEEGyHwO2GN+DrdVw==} + genkit@1.27.0-rc.1: + resolution: {integrity: sha512-C21pPV9y0IYGmYf2DQl9D37B+KFlXZgFaBIN8ZtrxgIUL77cyl96VHTKDvJSW0jfcf+QCgyfGsO+yK+cLrxxSQ==} genkitx-openai@0.10.1: resolution: {integrity: sha512-E9/DzyQcBUSTy81xT2pvEmdnn9Q/cKoojEt6lD/EdOeinhqE9oa59d/kuXTokCMekTrj3Rk7LtNBQIDjnyjNOA==} @@ -9456,7 +9456,8 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@cfworker/json-schema@4.1.1': {} + '@cfworker/json-schema@4.1.1': + optional: true '@colors/colors@1.5.0': optional: true @@ -9951,9 +9952,9 @@ snapshots: '@firebase/webchannel-wrapper@1.0.3': {} - '@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/ai@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/core': 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@opentelemetry/api': 1.9.0 '@types/node': 20.19.26 colorette: 2.0.20 @@ -9972,9 +9973,9 @@ snapshots: - supports-color optional: true - '@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': + '@genkit-ai/ai@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': dependencies: - '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) '@opentelemetry/api': 1.9.0 '@types/node': 20.19.26 colorette: 2.0.20 @@ -9992,7 +9993,7 @@ snapshots: - genkit - supports-color - '@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/core@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) @@ -10014,7 +10015,7 @@ snapshots: zod: 3.25.76 zod-to-json-schema: 3.25.0(zod@3.25.76) optionalDependencies: - '@genkit-ai/firebase': 1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/firebase': 1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) transitivePeerDependencies: - '@google-cloud/firestore' - encoding @@ -10024,7 +10025,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': + '@genkit-ai/core@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) @@ -10055,9 +10056,9 @@ snapshots: - genkit - supports-color - '@genkit-ai/express@1.12.0(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit)': + '@genkit-ai/express@1.12.0(@genkit-ai/core@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(express@5.1.0)(genkit@genkit)': dependencies: - '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) body-parser: 1.20.3 cors: 2.8.5 express: 5.1.0 @@ -10065,12 +10066,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@genkit-ai/firebase@1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/firebase@1.16.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/google-cloud': 1.16.1(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/google-cloud': 1.16.1(encoding@0.1.13)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@google-cloud/firestore': 7.11.6(encoding@0.1.13) firebase-admin: 13.5.0(encoding@0.1.13) - genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) optionalDependencies: firebase: 11.9.1 transitivePeerDependencies: @@ -10078,12 +10079,12 @@ snapshots: - supports-color optional: true - '@genkit-ai/firebase@1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/firebase@1.25.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: - '@genkit-ai/google-cloud': 1.25.0(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/google-cloud': 1.25.0(encoding@0.1.13)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) '@google-cloud/firestore': 7.11.6(encoding@0.1.13) firebase-admin: 13.5.0(encoding@0.1.13) - genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) optionalDependencies: firebase: 11.9.1 transitivePeerDependencies: @@ -10104,7 +10105,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/google-cloud@1.16.1(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/google-cloud@1.16.1(encoding@0.1.13)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@google-cloud/logging-winston': 6.0.1(encoding@0.1.13)(winston@3.17.0) '@google-cloud/opentelemetry-cloud-monitoring-exporter': 0.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.0))(encoding@0.1.13) @@ -10120,7 +10121,7 @@ snapshots: '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) google-auth-library: 9.15.1(encoding@0.1.13) node-fetch: 3.3.2 winston: 3.17.0 @@ -10129,7 +10130,7 @@ snapshots: - supports-color optional: true - '@genkit-ai/google-cloud@1.25.0(encoding@0.1.13)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': + '@genkit-ai/google-cloud@1.25.0(encoding@0.1.13)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1))': dependencies: '@google-cloud/logging-winston': 6.0.1(encoding@0.1.13)(winston@3.19.0) '@google-cloud/opentelemetry-cloud-monitoring-exporter': 0.19.0(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.0))(encoding@0.1.13) @@ -10145,7 +10146,7 @@ snapshots: '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - genkit: 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) + genkit: 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1) google-auth-library: 9.15.1(encoding@0.1.13) node-fetch: 3.3.2 winston: 3.19.0 @@ -13994,10 +13995,10 @@ snapshots: transitivePeerDependencies: - supports-color - genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1): + genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1): dependencies: - '@genkit-ai/ai': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) - '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/ai': 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) + '@genkit-ai/core': 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)) uuid: 10.0.0 transitivePeerDependencies: - '@google-cloud/firestore' @@ -14007,10 +14008,10 @@ snapshots: - supports-color optional: true - genkitx-openai@0.10.1(@genkit-ai/ai@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3): + genkitx-openai@0.10.1(@genkit-ai/ai@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(@genkit-ai/core@1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit))(encoding@0.1.13)(ws@8.18.3): dependencies: - '@genkit-ai/ai': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) - '@genkit-ai/core': 1.27.0-rc.0(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/ai': 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) + '@genkit-ai/core': 1.27.0-rc.1(@google-cloud/firestore@7.11.6(encoding@0.1.13))(encoding@0.1.13)(firebase-admin@13.5.0(encoding@0.1.13))(firebase@11.9.1)(genkit@genkit) openai: 4.104.0(encoding@0.1.13)(ws@8.18.3)(zod@3.25.67) zod: 3.25.67 transitivePeerDependencies: From 9d232a76c58f67c28035f67bcca2345f5754d532 Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Fri, 19 Dec 2025 14:48:26 -0500 Subject: [PATCH 3/6] remove body-parser --- js/core/package.json | 1 - js/pnpm-lock.yaml | 3 --- 2 files changed, 4 deletions(-) diff --git a/js/core/package.json b/js/core/package.json index 0522ee7acd..4194728459 100644 --- a/js/core/package.json +++ b/js/core/package.json @@ -37,7 +37,6 @@ "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "async-mutex": "^0.5.0", - "body-parser": "^1.20.3", "cors": "^2.8.5", "dotprompt": "^1.1.1", "express": "^4.21.0", diff --git a/js/pnpm-lock.yaml b/js/pnpm-lock.yaml index a483ac8f77..e865f963b5 100644 --- a/js/pnpm-lock.yaml +++ b/js/pnpm-lock.yaml @@ -129,9 +129,6 @@ importers: async-mutex: specifier: ^0.5.0 version: 0.5.0 - body-parser: - specifier: ^1.20.3 - version: 1.20.3 cors: specifier: ^2.8.5 version: 2.8.5 From 339595758f18b76219c9b79ead05f45a30b3bc19 Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Fri, 19 Dec 2025 15:24:37 -0500 Subject: [PATCH 4/6] undos --- js/core/src/schema.ts | 28 +++++--------------- js/core/tests/schema_test.ts | 21 +++------------ js/core/tsconfig.json | 1 - js/plugins/google-cloud/tests/traces_test.ts | 4 +-- 4 files changed, 12 insertions(+), 42 deletions(-) diff --git a/js/core/src/schema.ts b/js/core/src/schema.ts index 69308b520b..67f3b58b87 100644 --- a/js/core/src/schema.ts +++ b/js/core/src/schema.ts @@ -17,7 +17,7 @@ import { Validator } from '@cfworker/json-schema'; import Ajv, { type ErrorObject, type JSONSchemaType } from 'ajv'; import addFormats from 'ajv-formats'; -import { z, type ZodIssue } from 'zod'; +import { z } from 'zod'; import zodToJsonSchema from 'zod-to-json-schema'; import { GenkitError } from './error.js'; import { logger } from './logging.js'; @@ -39,6 +39,11 @@ export function disableSchemaCodeGeneration() { global[SCHEMA_VALIDATION_MODE] = 'interpret'; } +/** Visible for testing */ +export function resetSchemaCodeGeneration() { + global[SCHEMA_VALIDATION_MODE] = undefined; +} + export { z }; // provide a consistent zod to use throughout genkit /** @@ -114,15 +119,6 @@ function toErrorDetail(error: ErrorObject): ValidationErrorDetail { }; } -function zodErrorToValidationErrorDetail( - error: ZodIssue -): ValidationErrorDetail { - return { - path: error.path.join('.') || '(root)', - message: error.message, - }; -} - function cfWorkerErrorToValidationErrorDetail(error: { instanceLocation: string; error: string; @@ -158,18 +154,6 @@ export function validateSchema( | 'compile' | 'interpret'; - if (validationMode === 'compile' && options.schema && !options.jsonSchema) { - const parseResult = options.schema.safeParse(data); - if (parseResult.success) { - return { valid: true, schema: toValidate }; - } - return { - valid: false, - errors: parseResult.error.errors.map(zodErrorToValidationErrorDetail), - schema: toValidate, - }; - } - if (validationMode === 'interpret') { let validator = cfWorkerValidators.get(toValidate); if (!validator) { diff --git a/js/core/tests/schema_test.ts b/js/core/tests/schema_test.ts index b154116a13..0e01dcef73 100644 --- a/js/core/tests/schema_test.ts +++ b/js/core/tests/schema_test.ts @@ -22,6 +22,7 @@ import { ValidationError, disableSchemaCodeGeneration, parseSchema, + resetSchemaCodeGeneration, toJsonSchema, validateSchema, z, @@ -67,7 +68,7 @@ describe('validate()', () => { schema: z.object({ foo: z.boolean() }), data: { foo: 123 }, valid: false, - errors: [{ path: 'foo', message: 'Expected boolean, received number' }], + errors: [{ path: 'foo', message: 'must be boolean' }], }, { it: 'should allow for date types', @@ -80,9 +81,7 @@ describe('validate()', () => { schema: z.object({ foo: z.array(z.object({ bar: z.boolean() })) }), data: { foo: [{ bar: 123 }] }, valid: false, - errors: [ - { path: 'foo.0.bar', message: 'Expected boolean, received number' }, - ], + errors: [{ path: 'foo.0.bar', message: 'must be boolean' }], }, { it: 'should be understandable for top-level errors', @@ -187,18 +186,6 @@ describe('disableSchemaCodeGeneration()', () => { assert.ok(errorAtFoo, 'Should have error at foo'); assert.strictEqual(compileMock.mock.callCount(), 0); compileMock.mock.restore(); - }); - - it('should validate zod schema using cfworker validator', () => { - disableSchemaCodeGeneration(); - const schema = z.object({ foo: z.boolean() }); - const parseSpy = mock.method(schema, 'safeParse'); - - const result = validateSchema({ foo: 123 }, { schema }); - - assert.strictEqual(result.valid, false); - const errorAtFoo = result.errors?.find((e) => e.path === 'foo'); - assert.ok(errorAtFoo, 'Should have error at foo'); - assert.strictEqual(parseSpy.mock.callCount(), 0); + resetSchemaCodeGeneration(); }); }); diff --git a/js/core/tsconfig.json b/js/core/tsconfig.json index e61dfcc81d..d96b77bbbb 100644 --- a/js/core/tsconfig.json +++ b/js/core/tsconfig.json @@ -2,7 +2,6 @@ "extends": "../tsconfig.json", "include": ["src"], "compilerOptions": { - "skipLibCheck": true, // DOM is needed for streaming APIs. "lib": ["es2022", "dom"] } diff --git a/js/plugins/google-cloud/tests/traces_test.ts b/js/plugins/google-cloud/tests/traces_test.ts index 9a7467986d..c4c64de430 100644 --- a/js/plugins/google-cloud/tests/traces_test.ts +++ b/js/plugins/google-cloud/tests/traces_test.ts @@ -105,8 +105,8 @@ describe('GoogleCloudTracing', () => { it('sub actions are contained within flows', async () => { const testFlow = createFlow(ai, 'testFlow', async () => { - await ai.run('subAction', async () => { - await ai.run('subAction2', async () => { + return await ai.run('subAction', async () => { + return await ai.run('subAction2', async () => { return 'done'; }); }); From 8f2c86e2cd16c994b88a31fd41e5e5fcb2d41db0 Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Tue, 13 Jan 2026 11:52:23 -0500 Subject: [PATCH 5/6] WIP, workign cfworker with changes --- genkit-tools/common/src/manager/manager.ts | 33 +++- genkit-tools/common/src/manager/types.ts | 2 +- js/core/src/reflection.ts | 208 +++++++++++++++++++++ js/core/src/schema.ts | 17 +- js/core/tests/schema_test.ts | 60 ++++++ js/genkit/src/common.ts | 1 + 6 files changed, 317 insertions(+), 4 deletions(-) diff --git a/genkit-tools/common/src/manager/manager.ts b/genkit-tools/common/src/manager/manager.ts index ac1ba913e5..50378e5332 100644 --- a/genkit-tools/common/src/manager/manager.ts +++ b/genkit-tools/common/src/manager/manager.ts @@ -37,6 +37,7 @@ import { projectNameFromGenkitFilePath, removeToolsInfoFile, retriable, + waitUntilHealthy, type DevToolsInfo, } from '../utils/utils'; import { ProcessManager } from './process-manager'; @@ -73,6 +74,7 @@ export class RuntimeManager { private eventEmitter = new EventEmitter(); private watchers: chokidar.FSWatcher[] = []; private healthCheckInterval?: NodeJS.Timeout; + private pendingRuntimeUrl?: string; private constructor( readonly telemetryServerUrl: string | undefined, @@ -98,6 +100,11 @@ export class RuntimeManager { ); await manager.setupRuntimesWatcher(); await manager.setupDevUiWatcher(); + + if (process.env.GENKIT_RUNTIME_URL) { + manager.pendingRuntimeUrl = process.env.GENKIT_RUNTIME_URL; + } + if (manager.manageHealth) { manager.healthCheckInterval = setInterval( async () => await manager.performHealthChecks(), @@ -824,12 +831,34 @@ export class RuntimeManager { * Performs health checks on all runtimes. */ private async performHealthChecks() { + if (this.pendingRuntimeUrl && !this.filenameToRuntimeMap['env:runtime']) { + if (await checkServerHealth(this.pendingRuntimeUrl)) { + const runtimeInfo: RuntimeInfo = { + id: 'env', + reflectionServerUrl: this.pendingRuntimeUrl, + timestamp: new Date().toISOString(), + genkitVersion: 'unknown', + reflectionApiSpecVersion: 1, + }; + this.filenameToRuntimeMap['env:runtime'] = runtimeInfo; + this.idToFileMap[runtimeInfo.id] = 'env:runtime'; + this.eventEmitter.emit(RuntimeEvent.ADD, runtimeInfo); + await this.notifyRuntime(runtimeInfo); + } + } + const healthCheckPromises = Object.entries(this.filenameToRuntimeMap).map( async ([fileName, runtime]) => { if ( !(await checkServerHealth(runtime.reflectionServerUrl, runtime.id)) ) { - await this.removeRuntime(fileName); + if (fileName === 'env:runtime') { + delete this.filenameToRuntimeMap[fileName]; + delete this.idToFileMap[runtime.id]; + this.eventEmitter.emit(RuntimeEvent.REMOVE, runtime); + } else { + await this.removeRuntime(fileName); + } } } ); @@ -866,7 +895,7 @@ function isValidRuntimeInfo(data: any): data is RuntimeInfo { typeof data === 'object' && data !== null && typeof data.id === 'string' && - typeof data.pid === 'number' && + (data.pid === undefined || typeof data.pid === 'number') && typeof data.reflectionServerUrl === 'string' && typeof data.timestamp === 'string' && !isNaN(Date.parse(timestamp)) && diff --git a/genkit-tools/common/src/manager/types.ts b/genkit-tools/common/src/manager/types.ts index fad53f8e6c..483399e333 100644 --- a/genkit-tools/common/src/manager/types.ts +++ b/genkit-tools/common/src/manager/types.ts @@ -33,7 +33,7 @@ export interface RuntimeInfo { /** Runtime ID (either user-set or `pid`). */ id: string; /** Process ID of the runtime. */ - pid: number; + pid?: number; /** URL of the reflection server. */ reflectionServerUrl: string; /** Timestamp when the runtime was started. */ diff --git a/js/core/src/reflection.ts b/js/core/src/reflection.ts index 9b9389ad9d..498eedb5ac 100644 --- a/js/core/src/reflection.ts +++ b/js/core/src/reflection.ts @@ -128,6 +128,13 @@ export class ReflectionServer { * The server will be registered to be shut down on process exit. */ async start() { + if ((global as any).schemaValidationMode === 'interpret') { + logger.debug( + 'Skipping ReflectionServer start: not supported in interpret mode (Cloudflare Workers).' + ); + return; + } + const server = express(); server.use(express.json({ limit: this.options.bodyLimit })); @@ -511,3 +518,204 @@ if (typeof module !== 'undefined' && 'hot' in module) { await ReflectionServer.stopAll(); }); } + +/** + * Creates a handler for the Reflection API that uses standard Web API Request/Response. + * This is suitable for use in Cloudflare Workers and other serverless environments. + */ +export function createReflectionApiHandler(registry: Registry) { + const activeActions = new Map< + string, + { + abortController: AbortController; + startTime: Date; + } + >(); + + return async (request: Request): Promise => { + const url = new URL(request.url); + const path = url.pathname; + + const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, x-genkit-version', + }; + + if (request.method === 'OPTIONS') { + return new Response(null, { headers: corsHeaders }); + } + + try { + if (request.method === 'GET' && path === '/api/actions') { + const actions = await registry.listResolvableActions(); + const convertedActions: any = {}; + Object.keys(actions).forEach((key) => { + const action = actions[key]; + convertedActions[key] = { + key, + name: action.name, + description: action.description, + metadata: action.metadata, + }; + if (action.inputSchema || action.inputJsonSchema) { + convertedActions[key].inputSchema = toJsonSchema({ + schema: action.inputSchema, + jsonSchema: action.inputJsonSchema, + }); + } + if (action.outputSchema || action.outputJsonSchema) { + convertedActions[key].outputSchema = toJsonSchema({ + schema: action.outputSchema, + jsonSchema: action.outputJsonSchema, + }); + } + }); + return new Response(JSON.stringify(convertedActions), { + headers: { 'Content-Type': 'application/json', ...corsHeaders }, + }); + } + + if (request.method === 'GET' && path === '/api/envs') { + return new Response(JSON.stringify(['dev']), { + headers: { 'Content-Type': 'application/json', ...corsHeaders }, + }); + } + + if (request.method === 'GET' && path === '/api/__health') { + return new Response('OK', { headers: corsHeaders }); + } + + if (request.method === 'POST' && path === '/api/runAction') { + const body = (await request.json()) as any; + const { key, input, context, telemetryLabels } = body; + const stream = url.searchParams.get('stream') === 'true'; + + const action = await registry.lookupAction(key); + if (!action) { + return new Response(`action ${key} not found`, { + status: 404, + headers: corsHeaders, + }); + } + + const abortController = new AbortController(); + let traceId: string | undefined; + + if (stream) { + const encoder = new TextEncoder(); + const readable = new ReadableStream({ + async start(controller) { + try { + const onTraceStartCallback = (metadata: any) => { + traceId = metadata.traceId; + activeActions.set(traceId!, { + abortController, + startTime: new Date(), + }); + }; + + const result = await action.run(input, { + context, + onChunk: (chunk) => { + controller.enqueue( + encoder.encode(JSON.stringify(chunk) + '\n') + ); + }, + telemetryLabels, + onTraceStart: onTraceStartCallback, + abortSignal: abortController.signal, + }); + + await flushTracing(); + controller.enqueue( + encoder.encode( + JSON.stringify({ + result: result.result, + telemetry: { traceId: result.telemetry.traceId }, + } as RunActionResponse) + ) + ); + controller.close(); + } catch (err: any) { + const errorResponse: Status = { + code: isAbortError(err) + ? StatusCodes.CANCELLED + : StatusCodes.INTERNAL, + message: isAbortError(err) + ? 'Action was cancelled' + : err.message, + details: { stack: err.stack }, + }; + if (err.traceId) errorResponse.details.traceId = err.traceId; + controller.enqueue( + encoder.encode( + JSON.stringify({ error: errorResponse } as RunActionResponse) + ) + ); + controller.close(); + } finally { + if (traceId) activeActions.delete(traceId); + } + }, + }); + + return new Response(readable, { + headers: { 'Content-Type': 'text/plain', ...corsHeaders }, + }); + } else { + // Non-streaming + let result; + try { + result = await action.run(input, { + context, + telemetryLabels, + onTraceStart: (metadata) => { + traceId = metadata.traceId; + activeActions.set(traceId!, { + abortController, + startTime: new Date(), + }); + }, + abortSignal: abortController.signal, + }); + await flushTracing(); + } catch (err: any) { + const errorResponse: Status = { + code: isAbortError(err) + ? StatusCodes.CANCELLED + : StatusCodes.INTERNAL, + message: isAbortError(err) ? 'Action was cancelled' : err.message, + details: { stack: err.stack, traceId }, + }; + return new Response( + JSON.stringify({ error: errorResponse } as RunActionResponse), + { + headers: { 'Content-Type': 'application/json', ...corsHeaders }, + } + ); + } finally { + if (traceId) activeActions.delete(traceId); + } + + return new Response( + JSON.stringify({ + result: result.result, + telemetry: { traceId: result.telemetry.traceId }, + } as RunActionResponse), + { + headers: { 'Content-Type': 'application/json', ...corsHeaders }, + } + ); + } + } + + return new Response('Not Found', { status: 404, headers: corsHeaders }); + } catch (e: any) { + return new Response(JSON.stringify({ error: e.message, stack: e.stack }), { + status: 500, + headers: corsHeaders, + }); + } + }; +} diff --git a/js/core/src/schema.ts b/js/core/src/schema.ts index 67f3b58b87..be9c350732 100644 --- a/js/core/src/schema.ts +++ b/js/core/src/schema.ts @@ -160,7 +160,7 @@ export function validateSchema( validator = new Validator(toValidate); cfWorkerValidators.set(toValidate, validator); } - const result = validator.validate(data); + const result = validator.validate(sanitizeForJsonSchema(data)); return { valid: result.valid, errors: result.errors?.map(cfWorkerErrorToValidationErrorDetail), @@ -215,3 +215,18 @@ export function defineJsonSchema( registry.registerSchema(name, { jsonSchema }); return jsonSchema; } + +function sanitizeForJsonSchema(data: any): any { + if (Array.isArray(data)) { + return data.map(sanitizeForJsonSchema); + } else if (data !== null && typeof data === 'object') { + const out: any = {}; + for (const key in data) { + if (data[key] !== undefined) { + out[key] = sanitizeForJsonSchema(data[key]); + } + } + return out; + } + return data; +} diff --git a/js/core/tests/schema_test.ts b/js/core/tests/schema_test.ts index 0e01dcef73..41bc352eae 100644 --- a/js/core/tests/schema_test.ts +++ b/js/core/tests/schema_test.ts @@ -188,4 +188,64 @@ describe('disableSchemaCodeGeneration()', () => { compileMock.mock.restore(); resetSchemaCodeGeneration(); }); + + it('should strip undefined values before validating', () => { + disableSchemaCodeGeneration(); + const result = validateSchema( + { foo: 'hello', bar: undefined }, + { + jsonSchema: { + type: 'object', + properties: { foo: { type: 'string' }, bar: { type: 'string' } }, + required: ['foo'], + }, + } + ); + assert.strictEqual(result.valid, true); + resetSchemaCodeGeneration(); + }); + + it('should strip undefined values recursively', () => { + disableSchemaCodeGeneration(); + const result = validateSchema( + { wrapper: { inner: 'hello', ignored: undefined } }, + { + jsonSchema: { + type: 'object', + properties: { + wrapper: { + type: 'object', + properties: { inner: { type: 'string' } }, + }, + }, + }, + } + ); + assert.strictEqual(result.valid, true); + resetSchemaCodeGeneration(); + }); + + it('should strip undefined values in objects inside arrays', () => { + disableSchemaCodeGeneration(); + const result = validateSchema( + { items: [{ name: 'item1', desc: undefined }, { name: 'item2' }] }, + { + jsonSchema: { + type: 'object', + properties: { + items: { + type: 'array', + items: { + type: 'object', + properties: { name: { type: 'string' } }, + required: ['name'], + }, + }, + }, + }, + } + ); + assert.strictEqual(result.valid, true); + resetSchemaCodeGeneration(); + }); }); diff --git a/js/genkit/src/common.ts b/js/genkit/src/common.ts index a22730bd9b..0b202255b9 100644 --- a/js/genkit/src/common.ts +++ b/js/genkit/src/common.ts @@ -127,6 +127,7 @@ export { StatusCodes, StatusSchema, UserFacingError, + createReflectionApiHandler, defineJsonSchema, defineSchema, disableSchemaCodeGeneration, From 428da6d284d7fbb529440c18d1db07d517b8091b Mon Sep 17 00:00:00 2001 From: Samuel Bushi Date: Tue, 13 Jan 2026 15:43:24 -0500 Subject: [PATCH 6/6] undo --- genkit-tools/common/src/manager/manager.ts | 33 +--- genkit-tools/common/src/manager/types.ts | 2 +- js/core/src/reflection.ts | 205 +-------------------- js/core/src/schema.ts | 2 +- js/genkit/src/common.ts | 1 - 5 files changed, 6 insertions(+), 237 deletions(-) diff --git a/genkit-tools/common/src/manager/manager.ts b/genkit-tools/common/src/manager/manager.ts index 50378e5332..ac1ba913e5 100644 --- a/genkit-tools/common/src/manager/manager.ts +++ b/genkit-tools/common/src/manager/manager.ts @@ -37,7 +37,6 @@ import { projectNameFromGenkitFilePath, removeToolsInfoFile, retriable, - waitUntilHealthy, type DevToolsInfo, } from '../utils/utils'; import { ProcessManager } from './process-manager'; @@ -74,7 +73,6 @@ export class RuntimeManager { private eventEmitter = new EventEmitter(); private watchers: chokidar.FSWatcher[] = []; private healthCheckInterval?: NodeJS.Timeout; - private pendingRuntimeUrl?: string; private constructor( readonly telemetryServerUrl: string | undefined, @@ -100,11 +98,6 @@ export class RuntimeManager { ); await manager.setupRuntimesWatcher(); await manager.setupDevUiWatcher(); - - if (process.env.GENKIT_RUNTIME_URL) { - manager.pendingRuntimeUrl = process.env.GENKIT_RUNTIME_URL; - } - if (manager.manageHealth) { manager.healthCheckInterval = setInterval( async () => await manager.performHealthChecks(), @@ -831,34 +824,12 @@ export class RuntimeManager { * Performs health checks on all runtimes. */ private async performHealthChecks() { - if (this.pendingRuntimeUrl && !this.filenameToRuntimeMap['env:runtime']) { - if (await checkServerHealth(this.pendingRuntimeUrl)) { - const runtimeInfo: RuntimeInfo = { - id: 'env', - reflectionServerUrl: this.pendingRuntimeUrl, - timestamp: new Date().toISOString(), - genkitVersion: 'unknown', - reflectionApiSpecVersion: 1, - }; - this.filenameToRuntimeMap['env:runtime'] = runtimeInfo; - this.idToFileMap[runtimeInfo.id] = 'env:runtime'; - this.eventEmitter.emit(RuntimeEvent.ADD, runtimeInfo); - await this.notifyRuntime(runtimeInfo); - } - } - const healthCheckPromises = Object.entries(this.filenameToRuntimeMap).map( async ([fileName, runtime]) => { if ( !(await checkServerHealth(runtime.reflectionServerUrl, runtime.id)) ) { - if (fileName === 'env:runtime') { - delete this.filenameToRuntimeMap[fileName]; - delete this.idToFileMap[runtime.id]; - this.eventEmitter.emit(RuntimeEvent.REMOVE, runtime); - } else { - await this.removeRuntime(fileName); - } + await this.removeRuntime(fileName); } } ); @@ -895,7 +866,7 @@ function isValidRuntimeInfo(data: any): data is RuntimeInfo { typeof data === 'object' && data !== null && typeof data.id === 'string' && - (data.pid === undefined || typeof data.pid === 'number') && + typeof data.pid === 'number' && typeof data.reflectionServerUrl === 'string' && typeof data.timestamp === 'string' && !isNaN(Date.parse(timestamp)) && diff --git a/genkit-tools/common/src/manager/types.ts b/genkit-tools/common/src/manager/types.ts index 483399e333..fad53f8e6c 100644 --- a/genkit-tools/common/src/manager/types.ts +++ b/genkit-tools/common/src/manager/types.ts @@ -33,7 +33,7 @@ export interface RuntimeInfo { /** Runtime ID (either user-set or `pid`). */ id: string; /** Process ID of the runtime. */ - pid?: number; + pid: number; /** URL of the reflection server. */ reflectionServerUrl: string; /** Timestamp when the runtime was started. */ diff --git a/js/core/src/reflection.ts b/js/core/src/reflection.ts index 498eedb5ac..9279063ba5 100644 --- a/js/core/src/reflection.ts +++ b/js/core/src/reflection.ts @@ -128,9 +128,9 @@ export class ReflectionServer { * The server will be registered to be shut down on process exit. */ async start() { - if ((global as any).schemaValidationMode === 'interpret') { + if (global[SCHEMA_VALIDATION_MODE] === 'interpret') { logger.debug( - 'Skipping ReflectionServer start: not supported in interpret mode (Cloudflare Workers).' + 'Skipping ReflectionServer start: not supported in interpret mode.' ); return; } @@ -518,204 +518,3 @@ if (typeof module !== 'undefined' && 'hot' in module) { await ReflectionServer.stopAll(); }); } - -/** - * Creates a handler for the Reflection API that uses standard Web API Request/Response. - * This is suitable for use in Cloudflare Workers and other serverless environments. - */ -export function createReflectionApiHandler(registry: Registry) { - const activeActions = new Map< - string, - { - abortController: AbortController; - startTime: Date; - } - >(); - - return async (request: Request): Promise => { - const url = new URL(request.url); - const path = url.pathname; - - const corsHeaders = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type, x-genkit-version', - }; - - if (request.method === 'OPTIONS') { - return new Response(null, { headers: corsHeaders }); - } - - try { - if (request.method === 'GET' && path === '/api/actions') { - const actions = await registry.listResolvableActions(); - const convertedActions: any = {}; - Object.keys(actions).forEach((key) => { - const action = actions[key]; - convertedActions[key] = { - key, - name: action.name, - description: action.description, - metadata: action.metadata, - }; - if (action.inputSchema || action.inputJsonSchema) { - convertedActions[key].inputSchema = toJsonSchema({ - schema: action.inputSchema, - jsonSchema: action.inputJsonSchema, - }); - } - if (action.outputSchema || action.outputJsonSchema) { - convertedActions[key].outputSchema = toJsonSchema({ - schema: action.outputSchema, - jsonSchema: action.outputJsonSchema, - }); - } - }); - return new Response(JSON.stringify(convertedActions), { - headers: { 'Content-Type': 'application/json', ...corsHeaders }, - }); - } - - if (request.method === 'GET' && path === '/api/envs') { - return new Response(JSON.stringify(['dev']), { - headers: { 'Content-Type': 'application/json', ...corsHeaders }, - }); - } - - if (request.method === 'GET' && path === '/api/__health') { - return new Response('OK', { headers: corsHeaders }); - } - - if (request.method === 'POST' && path === '/api/runAction') { - const body = (await request.json()) as any; - const { key, input, context, telemetryLabels } = body; - const stream = url.searchParams.get('stream') === 'true'; - - const action = await registry.lookupAction(key); - if (!action) { - return new Response(`action ${key} not found`, { - status: 404, - headers: corsHeaders, - }); - } - - const abortController = new AbortController(); - let traceId: string | undefined; - - if (stream) { - const encoder = new TextEncoder(); - const readable = new ReadableStream({ - async start(controller) { - try { - const onTraceStartCallback = (metadata: any) => { - traceId = metadata.traceId; - activeActions.set(traceId!, { - abortController, - startTime: new Date(), - }); - }; - - const result = await action.run(input, { - context, - onChunk: (chunk) => { - controller.enqueue( - encoder.encode(JSON.stringify(chunk) + '\n') - ); - }, - telemetryLabels, - onTraceStart: onTraceStartCallback, - abortSignal: abortController.signal, - }); - - await flushTracing(); - controller.enqueue( - encoder.encode( - JSON.stringify({ - result: result.result, - telemetry: { traceId: result.telemetry.traceId }, - } as RunActionResponse) - ) - ); - controller.close(); - } catch (err: any) { - const errorResponse: Status = { - code: isAbortError(err) - ? StatusCodes.CANCELLED - : StatusCodes.INTERNAL, - message: isAbortError(err) - ? 'Action was cancelled' - : err.message, - details: { stack: err.stack }, - }; - if (err.traceId) errorResponse.details.traceId = err.traceId; - controller.enqueue( - encoder.encode( - JSON.stringify({ error: errorResponse } as RunActionResponse) - ) - ); - controller.close(); - } finally { - if (traceId) activeActions.delete(traceId); - } - }, - }); - - return new Response(readable, { - headers: { 'Content-Type': 'text/plain', ...corsHeaders }, - }); - } else { - // Non-streaming - let result; - try { - result = await action.run(input, { - context, - telemetryLabels, - onTraceStart: (metadata) => { - traceId = metadata.traceId; - activeActions.set(traceId!, { - abortController, - startTime: new Date(), - }); - }, - abortSignal: abortController.signal, - }); - await flushTracing(); - } catch (err: any) { - const errorResponse: Status = { - code: isAbortError(err) - ? StatusCodes.CANCELLED - : StatusCodes.INTERNAL, - message: isAbortError(err) ? 'Action was cancelled' : err.message, - details: { stack: err.stack, traceId }, - }; - return new Response( - JSON.stringify({ error: errorResponse } as RunActionResponse), - { - headers: { 'Content-Type': 'application/json', ...corsHeaders }, - } - ); - } finally { - if (traceId) activeActions.delete(traceId); - } - - return new Response( - JSON.stringify({ - result: result.result, - telemetry: { traceId: result.telemetry.traceId }, - } as RunActionResponse), - { - headers: { 'Content-Type': 'application/json', ...corsHeaders }, - } - ); - } - } - - return new Response('Not Found', { status: 404, headers: corsHeaders }); - } catch (e: any) { - return new Response(JSON.stringify({ error: e.message, stack: e.stack }), { - status: 500, - headers: corsHeaders, - }); - } - }; -} diff --git a/js/core/src/schema.ts b/js/core/src/schema.ts index be9c350732..05e210a165 100644 --- a/js/core/src/schema.ts +++ b/js/core/src/schema.ts @@ -25,7 +25,7 @@ import type { Registry } from './registry.js'; const ajv = new Ajv(); addFormats(ajv); -const SCHEMA_VALIDATION_MODE = 'schemaValidationMode' as const; +export const SCHEMA_VALIDATION_MODE = 'schemaValidationMode' as const; /** * Disable schema code generation in runtime. Use this if your runtime diff --git a/js/genkit/src/common.ts b/js/genkit/src/common.ts index 0b202255b9..a22730bd9b 100644 --- a/js/genkit/src/common.ts +++ b/js/genkit/src/common.ts @@ -127,7 +127,6 @@ export { StatusCodes, StatusSchema, UserFacingError, - createReflectionApiHandler, defineJsonSchema, defineSchema, disableSchemaCodeGeneration,