From 9cbf918b35beb69508252d779b3859fa0af0d516 Mon Sep 17 00:00:00 2001 From: "Jorge G. Sancha" Date: Sat, 7 Mar 2026 14:27:09 +0100 Subject: [PATCH 1/2] fix: prevent jsonPath method from being serialized in schema output When isTypeValidator() returns false due to cross-module Symbol issues, getColumnJsonPath() fell through to check `column.jsonPath !== undefined`. Since validators have a jsonPath method, this returned the function itself, which got stringified in the generated .datasource files. Fix: check `typeof column.jsonPath === "string"` instead. Bumps version to 0.0.59. Fixes #124 Co-Authored-By: Claude Opus 4.5 --- package.json | 2 +- src/schema/datasource.test.ts | 12 ++++++++++++ src/schema/datasource.ts | 4 +++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6e0832e..bfb1969 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tinybirdco/sdk", - "version": "0.0.58", + "version": "0.0.59", "description": "TypeScript SDK for Tinybird Forward - define datasources and pipes as TypeScript", "type": "module", "main": "./dist/index.js", diff --git a/src/schema/datasource.test.ts b/src/schema/datasource.test.ts index e5d85c0..63ac174 100644 --- a/src/schema/datasource.test.ts +++ b/src/schema/datasource.test.ts @@ -259,6 +259,18 @@ describe("Datasource Schema", () => { expect(result).toBeUndefined(); }); + it("never returns a function even if isTypeValidator fails", () => { + // This tests the defensive check - if isTypeValidator incorrectly returns false + // for a validator (e.g., due to cross-module Symbol issues), getColumnJsonPath + // should still not return the jsonPath method as a value + const validator = t.string(); + const result = getColumnJsonPath(validator); + + // Result should be undefined, not the jsonPath function + expect(result).toBeUndefined(); + expect(typeof result).not.toBe("function"); + }); + it("returns jsonPath from validator modifier", () => { const validator = t.string().jsonPath("$.user.id"); const result = getColumnJsonPath(validator); diff --git a/src/schema/datasource.ts b/src/schema/datasource.ts index 8748a44..5cc393d 100644 --- a/src/schema/datasource.ts +++ b/src/schema/datasource.ts @@ -272,7 +272,9 @@ export function getColumnJsonPath(column: AnyTypeValidator | ColumnDefinition): return getModifiers(column).jsonPath; } - if (column.jsonPath !== undefined) { + // Check typeof to avoid returning the jsonPath method from validators + // if isTypeValidator incorrectly returns false (e.g., cross-module Symbol issues) + if (typeof column.jsonPath === "string") { return column.jsonPath; } From 5dfe97391917aa2aac825ba8282002438507c2bc Mon Sep 17 00:00:00 2001 From: Rafa Moreno Date: Sat, 7 Mar 2026 15:23:42 +0100 Subject: [PATCH 2/2] test: cover unbranded validator jsonPath fallback --- src/schema/datasource.test.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/schema/datasource.test.ts b/src/schema/datasource.test.ts index 63ac174..bca9594 100644 --- a/src/schema/datasource.test.ts +++ b/src/schema/datasource.test.ts @@ -7,7 +7,7 @@ import { getColumnNames, column, } from "./datasource.js"; -import { t } from "./types.js"; +import { t, type AnyTypeValidator } from "./types.js"; import { engine } from "./engines.js"; import { defineKafkaConnection, defineS3Connection, defineGCSConnection } from "./connection.js"; @@ -259,14 +259,16 @@ describe("Datasource Schema", () => { expect(result).toBeUndefined(); }); - it("never returns a function even if isTypeValidator fails", () => { - // This tests the defensive check - if isTypeValidator incorrectly returns false - // for a validator (e.g., due to cross-module Symbol issues), getColumnJsonPath - // should still not return the jsonPath method as a value + it("never returns a function when validator branding is missing", () => { const validator = t.string(); - const result = getColumnJsonPath(validator); + // Simulate a validator-like object where isTypeValidator() fails by + // removing symbol keys (including the validator brand). + const unbrandedValidator = Object.fromEntries( + Object.entries(validator as unknown as Record) + ) as unknown as AnyTypeValidator; + + const result = getColumnJsonPath(unbrandedValidator); - // Result should be undefined, not the jsonPath function expect(result).toBeUndefined(); expect(typeof result).not.toBe("function"); });