From 44be6fcad023f7be010907d7ea4b6da126b899bb Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 16:49:19 +0530 Subject: [PATCH 1/8] refactor(ts): initial --- packages/bruno-schema/package.json | 3 ++- .../{index.spec.js => index.spec.ts} | 0 .../src/collections/{index.js => index.ts} | 0 ...{itemSchema.spec.js => itemSchema.spec.ts} | 0 ...stSchema.spec.js => requestSchema.spec.ts} | 0 .../src/common/{index.js => index.ts} | 0 .../bruno-schema/src/{index.js => index.ts} | 0 .../src/utils/{testUtils.js => testUtils.ts} | 0 packages/bruno-schema/tsconfig.json | 20 +++++++++++++++++++ 9 files changed, 22 insertions(+), 1 deletion(-) rename packages/bruno-schema/src/collections/{index.spec.js => index.spec.ts} (100%) rename packages/bruno-schema/src/collections/{index.js => index.ts} (100%) rename packages/bruno-schema/src/collections/{itemSchema.spec.js => itemSchema.spec.ts} (100%) rename packages/bruno-schema/src/collections/{requestSchema.spec.js => requestSchema.spec.ts} (100%) rename packages/bruno-schema/src/common/{index.js => index.ts} (100%) rename packages/bruno-schema/src/{index.js => index.ts} (100%) rename packages/bruno-schema/src/utils/{testUtils.js => testUtils.ts} (100%) create mode 100644 packages/bruno-schema/tsconfig.json diff --git a/packages/bruno-schema/package.json b/packages/bruno-schema/package.json index 61542cf698..47c60aff2a 100644 --- a/packages/bruno-schema/package.json +++ b/packages/bruno-schema/package.json @@ -2,7 +2,8 @@ "name": "@usebruno/schema", "version": "0.7.0", "license": "MIT", - "main": "src/index.js", + "main": "src/index.ts", + "types": "src/index.ts", "files": [ "src", "package.json" diff --git a/packages/bruno-schema/src/collections/index.spec.js b/packages/bruno-schema/src/collections/index.spec.ts similarity index 100% rename from packages/bruno-schema/src/collections/index.spec.js rename to packages/bruno-schema/src/collections/index.spec.ts diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.ts similarity index 100% rename from packages/bruno-schema/src/collections/index.js rename to packages/bruno-schema/src/collections/index.ts diff --git a/packages/bruno-schema/src/collections/itemSchema.spec.js b/packages/bruno-schema/src/collections/itemSchema.spec.ts similarity index 100% rename from packages/bruno-schema/src/collections/itemSchema.spec.js rename to packages/bruno-schema/src/collections/itemSchema.spec.ts diff --git a/packages/bruno-schema/src/collections/requestSchema.spec.js b/packages/bruno-schema/src/collections/requestSchema.spec.ts similarity index 100% rename from packages/bruno-schema/src/collections/requestSchema.spec.js rename to packages/bruno-schema/src/collections/requestSchema.spec.ts diff --git a/packages/bruno-schema/src/common/index.js b/packages/bruno-schema/src/common/index.ts similarity index 100% rename from packages/bruno-schema/src/common/index.js rename to packages/bruno-schema/src/common/index.ts diff --git a/packages/bruno-schema/src/index.js b/packages/bruno-schema/src/index.ts similarity index 100% rename from packages/bruno-schema/src/index.js rename to packages/bruno-schema/src/index.ts diff --git a/packages/bruno-schema/src/utils/testUtils.js b/packages/bruno-schema/src/utils/testUtils.ts similarity index 100% rename from packages/bruno-schema/src/utils/testUtils.js rename to packages/bruno-schema/src/utils/testUtils.ts diff --git a/packages/bruno-schema/tsconfig.json b/packages/bruno-schema/tsconfig.json new file mode 100644 index 0000000000..aebf9ea3a9 --- /dev/null +++ b/packages/bruno-schema/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "allowJs": true, + "checkJs": false, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "lib": ["ES2022"], + "skipLibCheck": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} From 343caafe82fb9a13610d2a3aec8d7b412bda877a Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 18:18:04 +0530 Subject: [PATCH 2/8] refactor(ts): initial --- package-lock.json | 2 +- packages/bruno-schema/package.json | 6 +- .../src/collections/index.spec.ts | 15 +- .../bruno-schema/src/collections/index.ts | 770 +++++++++--------- .../src/collections/requestSchema.spec.ts | 5 +- packages/bruno-schema/src/common/index.ts | 9 +- packages/bruno-schema/src/utils/testUtils.ts | 19 +- packages/bruno-schema/tsconfig.json | 25 +- 8 files changed, 445 insertions(+), 406 deletions(-) diff --git a/package-lock.json b/package-lock.json index e7838e2810..f28c9ebbfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2412,7 +2412,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" diff --git a/packages/bruno-schema/package.json b/packages/bruno-schema/package.json index 47c60aff2a..e381675871 100644 --- a/packages/bruno-schema/package.json +++ b/packages/bruno-schema/package.json @@ -9,7 +9,11 @@ "package.json" ], "scripts": { - "test": "jest" + "test": "jest", + "typecheck": "tsc --noEmit" + }, + "devDependencies": { + "@types/yup": "^0.29.14" }, "peerDependencies": { "yup": "^0.32.11" diff --git a/packages/bruno-schema/src/collections/index.spec.ts b/packages/bruno-schema/src/collections/index.spec.ts index f15031c4cf..888db49be0 100644 --- a/packages/bruno-schema/src/collections/index.spec.ts +++ b/packages/bruno-schema/src/collections/index.spec.ts @@ -1,6 +1,5 @@ -const { expect } = require('@jest/globals'); -const { uuid } = require('../utils/testUtils'); -const { collectionSchema } = require('./index'); +import { expect, uuid } from '../utils/testUtils'; +import { collectionSchema } from './index'; describe('Collection Schema Validation', () => { it('collection schema must validate successfully - simple collection, no items', async () => { @@ -136,7 +135,7 @@ describe('Collection Schema Validation', () => { ] }; - expect(collectionSchema.validate(collection)).rejects.toThrow('items[0].request field has unspecified keys: params'); + await expect(collectionSchema.validate(collection)).rejects.toThrow('items[0].request field has unspecified keys: params'); }); @@ -144,7 +143,7 @@ describe('Collection Schema Validation', () => { const collection = { version: '1', uid: uuid(), - name: 'My Collection', + name: 'My collection', items: [ { uid: uuid(), @@ -169,7 +168,7 @@ describe('Collection Schema Validation', () => { const collection = { version: '1', uid: uuid(), - name: 'My Collection', + name: 'My collection', items: [ { uid: uuid(), @@ -178,7 +177,7 @@ describe('Collection Schema Validation', () => { items: [ { uid: uuid(), - name: 'Get Countries', + name: 'Get countries', type: 'http-request', request: { url: 'https://restcountries.com/v2/alpha/in', @@ -192,7 +191,7 @@ describe('Collection Schema Validation', () => { }, { uid: uuid(), - name: 'Second Level Folder', + name: 'Second level folder', type: 'folder' } ] diff --git a/packages/bruno-schema/src/collections/index.ts b/packages/bruno-schema/src/collections/index.ts index 908822fd2f..fa046fde04 100644 --- a/packages/bruno-schema/src/collections/index.ts +++ b/packages/bruno-schema/src/collections/index.ts @@ -1,39 +1,38 @@ -const Yup = require('yup'); -const { uidSchema } = require('../common'); +import * as yup from 'yup'; +import { uidSchema } from '../common'; -const environmentVariablesSchema = Yup.object({ +const environmentVariablesSchema = yup.object({ uid: uidSchema, - name: Yup.string().nullable(), - // Allow mixed types (string, number, boolean, object) to support setting non-string values via scripts. - value: Yup.mixed().nullable(), - type: Yup.string().oneOf(['text']).required('type is required'), - enabled: Yup.boolean().defined(), - secret: Yup.boolean() + name: yup.string().nullable(), + value: yup.mixed().nullable(), + type: yup.string().oneOf(['text']).required('type is required'), + enabled: yup.boolean().defined(), + secret: yup.boolean() }) .noUnknown(true) .strict(); -const environmentSchema = Yup.object({ +export const environmentSchema = yup.object({ uid: uidSchema, - name: Yup.string().min(1).required('name is required'), - variables: Yup.array().of(environmentVariablesSchema).required('variables are required') + name: yup.string().min(1).required('name is required'), + variables: yup.array().of(environmentVariablesSchema).required('variables are required') }) .noUnknown(true) .strict(); -const environmentsSchema = Yup.array().of(environmentSchema); +export const environmentsSchema = yup.array().of(environmentSchema); -const keyValueSchema = Yup.object({ +const keyValueSchema = yup.object({ uid: uidSchema, - name: Yup.string().nullable(), - value: Yup.string().nullable(), - description: Yup.string().nullable(), - enabled: Yup.boolean() + name: yup.string().nullable(), + value: yup.string().nullable(), + description: yup.string().nullable(), + enabled: yup.boolean() }) .noUnknown(true) .strict(); -const assertionOperators = [ +const assertionOperators: string[] = [ 'eq', 'neq', 'gt', @@ -65,7 +64,8 @@ const assertionOperators = [ ]; const assertionSchema = keyValueSchema.shape({ - operator: Yup.string() + operator: yup + .string() .oneOf(assertionOperators) .nullable() .optional() @@ -73,264 +73,265 @@ const assertionSchema = keyValueSchema.shape({ .noUnknown(true) .strict(); -const varsSchema = Yup.object({ +const varsSchema = yup.object({ uid: uidSchema, - name: Yup.string().nullable(), - value: Yup.string().nullable(), - description: Yup.string().nullable(), - enabled: Yup.boolean(), - - // todo - // anoop(4 feb 2023) - nobody uses this, and it needs to be removed - local: Yup.boolean() + name: yup.string().nullable(), + value: yup.string().nullable(), + description: yup.string().nullable(), + enabled: yup.boolean(), + local: yup.boolean() }) .noUnknown(true) .strict(); -const requestUrlSchema = Yup.string().min(0).defined(); -const requestMethodSchema = Yup.string() +const requestUrlSchema = yup.string().min(0).defined(); +const requestMethodSchema = yup + .string() .min(1, 'method is required') .required('method is required'); -const graphqlBodySchema = Yup.object({ - query: Yup.string().nullable(), - variables: Yup.string().nullable() +const graphqlBodySchema = yup.object({ + query: yup.string().nullable(), + variables: yup.string().nullable() }) .noUnknown(true) .strict(); -const multipartFormSchema = Yup.object({ +const multipartFormSchema = yup.object({ uid: uidSchema, - type: Yup.string().oneOf(['file', 'text']).required('type is required'), - name: Yup.string().nullable(), - value: Yup.mixed().when('type', { + type: yup.string().oneOf(['file', 'text']).required('type is required'), + name: yup.string().nullable(), + value: yup.mixed().when('type', { is: 'file', - then: Yup.array().of(Yup.string().nullable()).nullable(), - otherwise: Yup.string().nullable() + then: yup.array().of(yup.string().nullable()).nullable(), + otherwise: yup.string().nullable() }), - description: Yup.string().nullable(), - contentType: Yup.string().nullable(), - enabled: Yup.boolean() + description: yup.string().nullable(), + contentType: yup.string().nullable(), + enabled: yup.boolean() }) .noUnknown(true) .strict(); - -const fileSchema = Yup.object({ +const fileSchema = yup.object({ uid: uidSchema, - filePath: Yup.string().nullable(), - contentType: Yup.string().nullable(), - selected: Yup.boolean() + filePath: yup.string().nullable(), + contentType: yup.string().nullable(), + selected: yup.boolean() }) .noUnknown(true) .strict(); -const requestBodySchema = Yup.object({ - mode: Yup.string() +const requestBodySchema = yup.object({ + mode: yup + .string() .oneOf(['none', 'json', 'text', 'xml', 'formUrlEncoded', 'multipartForm', 'graphql', 'sparql', 'file']) .required('mode is required'), - json: Yup.string().nullable(), - text: Yup.string().nullable(), - xml: Yup.string().nullable(), - sparql: Yup.string().nullable(), - formUrlEncoded: Yup.array().of(keyValueSchema).nullable(), - multipartForm: Yup.array().of(multipartFormSchema).nullable(), + json: yup.string().nullable(), + text: yup.string().nullable(), + xml: yup.string().nullable(), + sparql: yup.string().nullable(), + formUrlEncoded: yup.array().of(keyValueSchema).nullable(), + multipartForm: yup.array().of(multipartFormSchema).nullable(), graphql: graphqlBodySchema.nullable(), - file: Yup.array().of(fileSchema).nullable() + file: yup.array().of(fileSchema).nullable() }) .noUnknown(true) .strict(); -const authAwsV4Schema = Yup.object({ - accessKeyId: Yup.string().nullable(), - secretAccessKey: Yup.string().nullable(), - sessionToken: Yup.string().nullable(), - service: Yup.string().nullable(), - region: Yup.string().nullable(), - profileName: Yup.string().nullable() +const authAwsV4Schema = yup.object({ + accessKeyId: yup.string().nullable(), + secretAccessKey: yup.string().nullable(), + sessionToken: yup.string().nullable(), + service: yup.string().nullable(), + region: yup.string().nullable(), + profileName: yup.string().nullable() }) .noUnknown(true) .strict(); -const authBasicSchema = Yup.object({ - username: Yup.string().nullable(), - password: Yup.string().nullable() +const authBasicSchema = yup.object({ + username: yup.string().nullable(), + password: yup.string().nullable() }) .noUnknown(true) .strict(); -const authWsseSchema = Yup.object({ - username: Yup.string().nullable(), - password: Yup.string().nullable() +const authWsseSchema = yup.object({ + username: yup.string().nullable(), + password: yup.string().nullable() }) .noUnknown(true) .strict(); -const authBearerSchema = Yup.object({ - token: Yup.string().nullable() +const authBearerSchema = yup.object({ + token: yup.string().nullable() }) .noUnknown(true) .strict(); -const authDigestSchema = Yup.object({ - username: Yup.string().nullable(), - password: Yup.string().nullable() +const authDigestSchema = yup.object({ + username: yup.string().nullable(), + password: yup.string().nullable() }) .noUnknown(true) .strict(); +const authNTLMSchema = yup.object({ + username: yup.string().nullable(), + password: yup.string().nullable(), + domain: yup.string().nullable() +}) + .noUnknown(true) + .strict(); - - const authNTLMSchema = Yup.object({ - username: Yup.string().nullable(), - password: Yup.string().nullable(), - domain: Yup.string().nullable() - - }) - .noUnknown(true) - .strict(); - -const authApiKeySchema = Yup.object({ - key: Yup.string().nullable(), - value: Yup.string().nullable(), - placement: Yup.string().oneOf(['header', 'queryparams']).nullable() +const authApiKeySchema = yup.object({ + key: yup.string().nullable(), + value: yup.string().nullable(), + placement: yup.string().oneOf(['header', 'queryparams']).nullable() }) .noUnknown(true) .strict(); -const oauth2AuthorizationAdditionalParametersSchema = Yup.object({ - name: Yup.string().nullable(), - value: Yup.string().nullable(), - sendIn: Yup.string() +const oauth2AuthorizationAdditionalParametersSchema = yup.object({ + name: yup.string().nullable(), + value: yup.string().nullable(), + sendIn: yup + .string() .oneOf(['headers', 'queryparams']) .required('send in property is required'), - enabled: Yup.boolean() + enabled: yup.boolean() }) .noUnknown(true) .strict(); -const oauth2AdditionalParametersSchema = Yup.object({ - name: Yup.string().nullable(), - value: Yup.string().nullable(), - sendIn: Yup.string() - .oneOf(['headers', 'queryparams', 'body']) - .required('send in property is required'), - enabled: Yup.boolean() - }) - .noUnknown(true) - .strict(); +const oauth2AdditionalParametersSchema = yup.object({ + name: yup.string().nullable(), + value: yup.string().nullable(), + sendIn: yup + .string() + .oneOf(['headers', 'queryparams', 'body']) + .required('send in property is required'), + enabled: yup.boolean() +}) + .noUnknown(true) + .strict(); -const oauth2Schema = Yup.object({ - grantType: Yup.string() +const oauth2Schema = yup.object({ + grantType: yup + .string() .oneOf(['client_credentials', 'password', 'authorization_code', 'implicit']) .required('grantType is required'), - username: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + username: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - password: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + password: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - callbackUrl: Yup.string().when('grantType', { - is: (val) => ['authorization_code', 'implicit'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + callbackUrl: yup.string().when('grantType', { + is: (val: unknown): val is string => ['authorization_code', 'implicit'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - authorizationUrl: Yup.string().when('grantType', { - is: (val) => ['authorization_code', 'implicit'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + authorizationUrl: yup.string().when('grantType', { + is: (val: unknown): val is string => ['authorization_code', 'implicit'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - accessTokenUrl: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + accessTokenUrl: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - clientId: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + clientId: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - clientSecret: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + clientSecret: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - scope: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + scope: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - state: Yup.string().when('grantType', { - is: (val) => ['authorization_code', 'implicit'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + state: yup.string().when('grantType', { + is: (val: unknown): val is string => ['authorization_code', 'implicit'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - pkce: Yup.boolean().when('grantType', { - is: (val) => ['authorization_code'].includes(val), - then: Yup.boolean().default(false), - otherwise: Yup.boolean() + pkce: yup.boolean().when('grantType', { + is: (val: unknown): val is string => ['authorization_code'].includes(val as string), + then: yup.boolean().default(false), + otherwise: yup.boolean() }), - credentialsPlacement: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + credentialsPlacement: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - credentialsId: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + credentialsId: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - tokenPlacement: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + tokenPlacement: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - tokenHeaderPrefix: Yup.string().when(['grantType', 'tokenPlacement'], { - is: (grantType, tokenPlacement) => - ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(grantType) && tokenPlacement === 'header', - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + tokenHeaderPrefix: yup.string().when(['grantType', 'tokenPlacement'], { + is: (grantType: unknown, tokenPlacement: unknown): boolean => + ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(grantType as string) && + tokenPlacement === 'header', + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - tokenQueryKey: Yup.string().when(['grantType', 'tokenPlacement'], { - is: (grantType, tokenPlacement) => - ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(grantType) && tokenPlacement === 'url', - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + tokenQueryKey: yup.string().when(['grantType', 'tokenPlacement'], { + is: (grantType: unknown, tokenPlacement: unknown): boolean => + ['client_credentials', 'password', 'authorization_code', 'implicit'].includes(grantType as string) && + tokenPlacement === 'url', + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - refreshTokenUrl: Yup.string().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code'].includes(val), - then: Yup.string().nullable(), - otherwise: Yup.string().nullable().strip() + refreshTokenUrl: yup.string().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code'].includes(val as string), + then: yup.string().nullable(), + otherwise: yup.string().nullable().strip() }), - autoRefreshToken: Yup.boolean().when('grantType', { - is: (val) => ['client_credentials', 'password', 'authorization_code'].includes(val), - then: Yup.boolean().default(false), - otherwise: Yup.boolean() + autoRefreshToken: yup.boolean().when('grantType', { + is: (val: unknown): val is string => ['client_credentials', 'password', 'authorization_code'].includes(val as string), + then: yup.boolean().default(false), + otherwise: yup.boolean() }), - autoFetchToken: Yup.boolean().when('grantType', { - is: (val) => ['authorization_code', 'implicit'].includes(val), - then: Yup.boolean().default(true), - otherwise: Yup.boolean() + autoFetchToken: yup.boolean().when('grantType', { + is: (val: unknown): val is string => ['authorization_code', 'implicit'].includes(val as string), + then: yup.boolean().default(true), + otherwise: yup.boolean() }), - additionalParameters: Yup.object({ - authorization: Yup.mixed().when('grantType', { + additionalParameters: yup.object({ + authorization: yup.mixed().when('grantType', { is: 'authorization_code', - then: Yup.array().of(oauth2AuthorizationAdditionalParametersSchema).required(), - otherwise: Yup.mixed().nullable().optional() + then: yup.array().of(oauth2AuthorizationAdditionalParametersSchema).required(), + otherwise: yup.mixed().nullable().optional() }), - token: Yup.array().of(oauth2AdditionalParametersSchema).optional(), - refresh: Yup.array().of(oauth2AdditionalParametersSchema).optional() + token: yup.array().of(oauth2AdditionalParametersSchema).optional(), + refresh: yup.array().of(oauth2AdditionalParametersSchema).optional() }) }) .noUnknown(true) .strict(); -const authSchema = Yup.object({ - mode: Yup.string() +const authSchema = yup.object({ + mode: yup + .string() .oneOf(['inherit', 'none', 'awsv4', 'basic', 'bearer', 'digest', 'ntlm', 'oauth2', 'wsse', 'apikey']) .required('mode is required'), awsv4: authAwsV4Schema.nullable(), @@ -346,42 +347,49 @@ const authSchema = Yup.object({ .strict() .nullable(); -const requestParamsSchema = Yup.object({ +const requestParamsSchema = yup.object({ uid: uidSchema, - name: Yup.string().nullable(), - value: Yup.string().nullable(), - description: Yup.string().nullable(), - type: Yup.string().oneOf(['query', 'path']).required('type is required'), - enabled: Yup.boolean() + name: yup.string().nullable(), + value: yup.string().nullable(), + description: yup.string().nullable(), + type: yup.string().oneOf(['query', 'path']).required('type is required'), + enabled: yup.boolean() }) .noUnknown(true) .strict(); -const exampleSchema = Yup.object({ +const exampleSchema = yup.object({ uid: uidSchema, itemUid: uidSchema, - name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'), - description: Yup.string().nullable(), - type: Yup.string().oneOf(['http-request', 'graphql-request', 'grpc-request',]).required('type is required'), - request: Yup.object({ - url: requestUrlSchema, - method: requestMethodSchema, - headers: Yup.array().of(keyValueSchema).required('headers are required'), - params: Yup.array().of(requestParamsSchema).required('params are required'), - body: requestBodySchema - }) + name: yup.string().min(1, 'name must be at least 1 character').required('name is required'), + description: yup.string().nullable(), + type: yup + .string() + .oneOf(['http-request', 'graphql-request', 'grpc-request']) + .required('type is required'), + request: yup + .object({ + url: requestUrlSchema, + method: requestMethodSchema, + headers: yup.array().of(keyValueSchema).required('headers are required'), + params: yup.array().of(requestParamsSchema).required('params are required'), + body: requestBodySchema + }) .noUnknown(true) .strict() .nullable(), - response: Yup.object({ - status: Yup.string().nullable(), - statusText: Yup.string().nullable(), - headers: Yup.array().of(keyValueSchema).nullable(), - body: Yup.object({ - type: Yup.string().oneOf(['json', 'text', 'xml', 'html', 'binary']).nullable(), - content: Yup.mixed().nullable() - }).nullable() - }) + response: yup + .object({ + status: yup.string().nullable(), + statusText: yup.string().nullable(), + headers: yup.array().of(keyValueSchema).nullable(), + body: yup + .object({ + type: yup.string().oneOf(['json', 'text', 'xml', 'html', 'binary']).nullable(), + content: yup.mixed().nullable() + }) + .nullable() + }) .noUnknown(true) .strict() .nullable() @@ -389,149 +397,167 @@ const exampleSchema = Yup.object({ .noUnknown(true) .strict(); -// Right now, the request schema is very tightly coupled with http request -// As we introduce more request types in the future, we will improve the definition to support -// schema structure based on other request type -const requestSchema = Yup.object({ +export const requestSchema = yup.object({ url: requestUrlSchema, method: requestMethodSchema, - headers: Yup.array().of(keyValueSchema).required('headers are required'), - params: Yup.array().of(requestParamsSchema).required('params are required'), + headers: yup.array().of(keyValueSchema).required('headers are required'), + params: yup.array().of(requestParamsSchema).required('params are required'), auth: authSchema, body: requestBodySchema, - script: Yup.object({ - req: Yup.string().nullable(), - res: Yup.string().nullable() - }) + script: yup + .object({ + req: yup.string().nullable(), + res: yup.string().nullable() + }) .noUnknown(true) .strict(), - vars: Yup.object({ - req: Yup.array().of(varsSchema).nullable(), - res: Yup.array().of(varsSchema).nullable() - }) + vars: yup + .object({ + req: yup.array().of(varsSchema).nullable(), + res: yup.array().of(varsSchema).nullable() + }) .noUnknown(true) .strict() .nullable(), - assertions: Yup.array().of(assertionSchema).nullable(), - tests: Yup.string().nullable(), - docs: Yup.string().nullable() + assertions: yup.array().of(assertionSchema).nullable(), + tests: yup.string().nullable(), + docs: yup.string().nullable() }) .noUnknown(true) .strict(); -const grpcRequestSchema = Yup.object({ +const grpcRequestSchema = yup.object({ url: requestUrlSchema, - method: Yup.string().optional(), - methodType: Yup.string().oneOf(['unary', 'client-streaming', 'server-streaming', 'bidi-streaming', '']).nullable(), - protoPath: Yup.string().nullable(), - headers: Yup.array().of(keyValueSchema).required('headers are required'), + method: yup.string().optional(), + methodType: yup + .string() + .oneOf(['unary', 'client-streaming', 'server-streaming', 'bidi-streaming', '']) + .nullable(), + protoPath: yup.string().nullable(), + headers: yup.array().of(keyValueSchema).required('headers are required'), auth: authSchema, - body: Yup.object({ - mode: Yup.string().oneOf(['grpc']).required('mode is required'), - grpc: Yup.array().of(Yup.object({ - name: Yup.string().nullable(), - content: Yup.string().nullable() - })).nullable() - }) + body: yup + .object({ + mode: yup.string().oneOf(['grpc']).required('mode is required'), + grpc: yup + .array() + .of( + yup.object({ + name: yup.string().nullable(), + content: yup.string().nullable() + }) + ) + .nullable() + }) .strict() .required('body is required'), - script: Yup.object({ - req: Yup.string().nullable(), - res: Yup.string().nullable() - }) + script: yup + .object({ + req: yup.string().nullable(), + res: yup.string().nullable() + }) .noUnknown(true) .strict(), - vars: Yup.object({ - req: Yup.array().of(varsSchema).nullable(), - res: Yup.array().of(varsSchema).nullable() - }) + vars: yup + .object({ + req: yup.array().of(varsSchema).nullable(), + res: yup.array().of(varsSchema).nullable() + }) .noUnknown(true) .strict() .nullable(), - assertions: Yup.array().of(assertionSchema).nullable(), - tests: Yup.string().nullable(), - docs: Yup.string().nullable(), + assertions: yup.array().of(assertionSchema).nullable(), + tests: yup.string().nullable(), + docs: yup.string().nullable() }) .noUnknown(true) .strict(); -const wsRequestSchema = Yup.object({ +const wsRequestSchema = yup.object({ url: requestUrlSchema, - headers: Yup.array().of(keyValueSchema).required('headers are required'), + headers: yup.array().of(keyValueSchema).required('headers are required'), auth: authSchema, - body: Yup.object({ - mode: Yup.string().oneOf(['ws']).required('mode is required'), - ws: Yup.array() - .of( - Yup.object({ - name: Yup.string().nullable(), - type: Yup.string().nullable(), - content: Yup.string().nullable() - }) - ) - .nullable() - }) + body: yup + .object({ + mode: yup.string().oneOf(['ws']).required('mode is required'), + ws: yup + .array() + .of( + yup.object({ + name: yup.string().nullable(), + type: yup.string().nullable(), + content: yup.string().nullable() + }) + ) + .nullable() + }) .strict() .required('body is required'), - script: Yup.object({ - req: Yup.string().nullable(), - res: Yup.string().nullable() - }) + script: yup + .object({ + req: yup.string().nullable(), + res: yup.string().nullable() + }) .noUnknown(true) .strict(), - vars: Yup.object({ - req: Yup.array().of(varsSchema).nullable(), - res: Yup.array().of(varsSchema).nullable() - }) + vars: yup + .object({ + req: yup.array().of(varsSchema).nullable(), + res: yup.array().of(varsSchema).nullable() + }) .noUnknown(true) .strict() .nullable(), - assertions: Yup.array().of(assertionSchema).nullable(), - tests: Yup.string().nullable(), - docs: Yup.string().nullable() + assertions: yup.array().of(assertionSchema).nullable(), + tests: yup.string().nullable(), + docs: yup.string().nullable() }) .noUnknown(true) .strict(); -const wsSettingsSchema = Yup.object({ - settings: Yup.object({ - timeout: Yup.number() - .default(500), - keepAliveInterval: Yup.number() - .default(0) - }).noUnknown(true) +const wsSettingsSchema = yup.object({ + settings: yup + .object({ + timeout: yup.number().default(500), + keepAliveInterval: yup.number().default(0) + }) + .noUnknown(true) .strict() .nullable() }); -const folderRootSchema = Yup.object({ - request: Yup.object({ - headers: Yup.array().of(keyValueSchema).nullable(), - auth: authSchema, - script: Yup.object({ - req: Yup.string().nullable(), - res: Yup.string().nullable() - }) - .noUnknown(true) - .strict() - .nullable(), - vars: Yup.object({ - req: Yup.array().of(varsSchema).nullable(), - res: Yup.array().of(varsSchema).nullable() +const folderRootSchema = yup.object({ + request: yup + .object({ + headers: yup.array().of(keyValueSchema).nullable(), + auth: authSchema, + script: yup + .object({ + req: yup.string().nullable(), + res: yup.string().nullable() + }) + .noUnknown(true) + .strict() + .nullable(), + vars: yup + .object({ + req: yup.array().of(varsSchema).nullable(), + res: yup.array().of(varsSchema).nullable() + }) + .noUnknown(true) + .strict() + .nullable(), + tests: yup.string().nullable() }) - .noUnknown(true) - .strict() - .nullable(), - tests: Yup.string().nullable() - }) .noUnknown(true) .strict() .nullable(), - docs: Yup.string().nullable(), - meta: Yup.object({ - name: Yup.string().nullable(), - seq: Yup.number().min(1).nullable() - }) + docs: yup.string().nullable(), + meta: yup + .object({ + name: yup.string().nullable(), + seq: yup.number().min(1).nullable() + }) .noUnknown(true) .strict() .nullable() @@ -539,87 +565,93 @@ const folderRootSchema = Yup.object({ .noUnknown(true) .nullable(); -const itemSchema = Yup.object({ +export const itemSchema: any = yup.object({ uid: uidSchema, - type: Yup.string().oneOf(['http-request', 'graphql-request', 'folder', 'js', 'grpc-request', 'ws-request']).required('type is required'), - seq: Yup.number().min(1), - name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'), - tags: Yup.array().of(Yup.string().matches(/^[\w-]+$/, 'tag must be alphanumeric')), - request: Yup.mixed().when('type', { - is: (type) => type === 'grpc-request', - then: grpcRequestSchema.required('request is required when item-type is grpc-request'), - otherwise: Yup.mixed().when('type', { - is: (type) => type === 'ws-request', - then: wsRequestSchema.required('request is required when item-type is ws-request'), - otherwise: requestSchema.when('type', { - is: (type) => ['http-request', 'graphql-request'].includes(type), - then: (schema) => schema.required('request is required when item-type is request') - }) - }) - }), - settings: Yup.mixed() + type: yup + .string() + .oneOf(['http-request', 'graphql-request', 'folder', 'js', 'grpc-request', 'ws-request']) + .required('type is required'), + seq: yup.number().min(1), + name: yup.string().min(1, 'name must be at least 1 character').required('name is required'), + tags: yup.array().of(yup.string().matches(/^[\w-]+$/, 'tag must be alphanumeric')), + request: yup + .mixed() + .when('type', { + is: (type: unknown): type is string => type === 'grpc-request', + then: grpcRequestSchema.required('request is required when item-type is grpc-request'), + otherwise: yup + .mixed() + .when('type', { + is: (type: unknown): type is string => type === 'ws-request', + then: wsRequestSchema.required('request is required when item-type is ws-request'), + otherwise: requestSchema.when('type', { + is: (type: unknown): type is string => + ['http-request', 'graphql-request'].includes(type as string), + then: (schema) => schema.required('request is required when item-type is request') + }) + }) + }), + settings: yup + .mixed() .when('type', { - is: (type) => type === 'ws-request', + is: (type: unknown): type is string => type === 'ws-request', then: wsSettingsSchema, - otherwise: Yup.object({ - encodeUrl: Yup.boolean().nullable(), - followRedirects: Yup.boolean().nullable(), - maxRedirects: Yup.number().min(0).max(50).nullable(), - timeout: Yup.mixed().nullable(), - }).noUnknown(true) - .strict() - .nullable() + otherwise: yup + .object({ + encodeUrl: yup.boolean().nullable(), + followRedirects: yup.boolean().nullable(), + maxRedirects: yup.number().min(0).max(50).nullable(), + timeout: yup.mixed().nullable() + }) + .noUnknown(true) + .strict() + .nullable() }), - fileContent: Yup.string().when('type', { - // If the type is 'js', the fileContent field is expected to be a string. - // This can include an empty string, indicating that the JS file may not have any content. + fileContent: yup.string().when('type', { is: 'js', - then: Yup.string(), - // For all other types, the fileContent field is not required and can be null. - otherwise: Yup.string().nullable() + then: yup.string(), + otherwise: yup.string().nullable() }), - root: Yup.mixed().when('type', { + root: yup.mixed().when('type', { is: 'folder', then: folderRootSchema, - otherwise: Yup.mixed().nullable().notRequired() + otherwise: yup.mixed().nullable().notRequired() }), - items: Yup.lazy(() => Yup.array().of(itemSchema)), - examples: Yup.array().of(exampleSchema).when('type', { - is: (type) => ['http-request', 'graphql-request', 'grpc-request'].includes(type), + items: yup.array().of( + yup.lazy(() => { + return itemSchema; + }) + ), + examples: yup.array().of(exampleSchema).when('type', { + is: (type: unknown): type is string => + ['http-request', 'graphql-request', 'grpc-request'].includes(type as string), then: (schema) => schema.nullable(), - otherwise: Yup.array().strip() + otherwise: yup.array().strip() }), - filename: Yup.string().nullable(), - pathname: Yup.string().nullable() + filename: yup.string().nullable(), + pathname: yup.string().nullable() }) .noUnknown(true) .strict(); -const collectionSchema = Yup.object({ - version: Yup.string().oneOf(['1']).required('version is required'), +export const collectionSchema = yup.object({ + version: yup.string().oneOf(['1']).required('version is required'), uid: uidSchema, - name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'), - items: Yup.array().of(itemSchema), - activeEnvironmentUid: Yup.string() + name: yup.string().min(1, 'name must be at least 1 character').required('name is required'), + items: yup.array().of(itemSchema), + activeEnvironmentUid: yup + .string() .length(21, 'activeEnvironmentUid must be 21 characters in length') .matches(/^[a-zA-Z0-9]*$/, 'uid must be alphanumeric') .nullable(), environments: environmentsSchema, - pathname: Yup.string().nullable(), - runnerResult: Yup.object({ - items: Yup.array() + pathname: yup.string().nullable(), + runnerResult: yup.object({ + items: yup.array() }), - runtimeVariables: Yup.object(), - brunoConfig: Yup.object(), + runtimeVariables: yup.object(), + brunoConfig: yup.object(), root: folderRootSchema }) .noUnknown(true) .strict(); - -module.exports = { - requestSchema, - itemSchema, - environmentSchema, - environmentsSchema, - collectionSchema -}; diff --git a/packages/bruno-schema/src/collections/requestSchema.spec.ts b/packages/bruno-schema/src/collections/requestSchema.spec.ts index 258b1138f3..41c6f8ddd2 100644 --- a/packages/bruno-schema/src/collections/requestSchema.spec.ts +++ b/packages/bruno-schema/src/collections/requestSchema.spec.ts @@ -1,6 +1,5 @@ -const { expect } = require('@jest/globals'); -const { uuid, validationErrorWithMessages } = require('../utils/testUtils'); -const { requestSchema } = require('./index'); +import { expect, uuid } from '../utils/testUtils'; +import { requestSchema } from './index'; describe('Request Schema Validation', () => { it('request schema must validate successfully - simple request', async () => { diff --git a/packages/bruno-schema/src/common/index.ts b/packages/bruno-schema/src/common/index.ts index 9f29df8ff5..b22557288f 100644 --- a/packages/bruno-schema/src/common/index.ts +++ b/packages/bruno-schema/src/common/index.ts @@ -1,11 +1,8 @@ -const Yup = require('yup'); +import * as yup from 'yup'; -const uidSchema = Yup.string() +export const uidSchema = yup + .string() .length(21, 'uid must be 21 characters in length') .matches(/^[a-zA-Z0-9]*$/, 'uid must be alphanumeric') .required('uid is required') .strict(); - -module.exports = { - uidSchema -}; diff --git a/packages/bruno-schema/src/utils/testUtils.ts b/packages/bruno-schema/src/utils/testUtils.ts index 1c3e08c7e1..8174a01ba6 100644 --- a/packages/bruno-schema/src/utils/testUtils.ts +++ b/packages/bruno-schema/src/utils/testUtils.ts @@ -1,22 +1,17 @@ -const { customAlphabet } = require('nanoid'); -const { expect } = require('@jest/globals'); +import { customAlphabet } from 'nanoid'; +import { expect } from '@jest/globals'; -// a customized version of nanoid without using _ and - -const uuid = () => { - // https://github.com/ai/nanoid/blob/main/url-alphabet/index.js - const urlAlphabet = 'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict'; - const customNanoId = customAlphabet(urlAlphabet, 21); +const urlAlphabet = 'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict'; +export const uuid = (): string => { + const customNanoId = customAlphabet(urlAlphabet, 21); return customNanoId(); }; -const validationErrorWithMessages = (...errors) => { +export const validationErrorWithMessages = (...errors: string[]): any => { return expect.objectContaining({ errors }); }; -module.exports = { - uuid, - validationErrorWithMessages -}; +export { expect }; diff --git a/packages/bruno-schema/tsconfig.json b/packages/bruno-schema/tsconfig.json index aebf9ea3a9..566b017d30 100644 --- a/packages/bruno-schema/tsconfig.json +++ b/packages/bruno-schema/tsconfig.json @@ -1,20 +1,33 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, "outDir": "./dist", "rootDir": "./src", - "allowJs": true, - "checkJs": false, - "esModuleInterop": true, + "resolveJsonModule": true, "allowSyntheticDefaultImports": true, - "lib": ["ES2022"], - "skipLibCheck": true + "moduleResolution": "node", + "declaration": true, + "declarationDir": "./dist/types", + "allowJs": false, + "checkJs": false, + "noImplicitAny": false, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true }, "include": [ "src/**/*" ], "exclude": [ "node_modules", - "dist" + "dist", + "**/*.spec.ts" ] } From 9be8f49b79d0c12fd3fc5a2f57b80d3fc5b7f19a Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 18:20:57 +0530 Subject: [PATCH 3/8] Update import statements in index.spec.ts --- packages/bruno-schema/src/collections/index.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/bruno-schema/src/collections/index.spec.ts b/packages/bruno-schema/src/collections/index.spec.ts index 888db49be0..46a09ab820 100644 --- a/packages/bruno-schema/src/collections/index.spec.ts +++ b/packages/bruno-schema/src/collections/index.spec.ts @@ -1,4 +1,6 @@ -import { expect, uuid } from '../utils/testUtils'; + +import { expect } from "@jest/globals" +import { uuid } from '../utils/testUtils'; import { collectionSchema } from './index'; describe('Collection Schema Validation', () => { From 67591de6a3fa3132052c19fcccaf00551f19d3a5 Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 18:27:07 +0530 Subject: [PATCH 4/8] refactor(tests): update imports to use ES module syntax and enhance type definitions for schemas --- .../src/collections/index.spec.ts | 3 +- .../bruno-schema/src/collections/index.ts | 4 +- .../src/collections/itemSchema.spec.ts | 39 +++++++++---------- .../src/collections/requestSchema.spec.ts | 3 +- packages/bruno-schema/src/utils/testUtils.ts | 4 +- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/packages/bruno-schema/src/collections/index.spec.ts b/packages/bruno-schema/src/collections/index.spec.ts index 46a09ab820..8596db0200 100644 --- a/packages/bruno-schema/src/collections/index.spec.ts +++ b/packages/bruno-schema/src/collections/index.spec.ts @@ -1,5 +1,4 @@ - -import { expect } from "@jest/globals" +import { expect } from '@jest/globals'; import { uuid } from '../utils/testUtils'; import { collectionSchema } from './index'; diff --git a/packages/bruno-schema/src/collections/index.ts b/packages/bruno-schema/src/collections/index.ts index fa046fde04..bb2a7597c6 100644 --- a/packages/bruno-schema/src/collections/index.ts +++ b/packages/bruno-schema/src/collections/index.ts @@ -565,7 +565,7 @@ const folderRootSchema = yup.object({ .noUnknown(true) .nullable(); -export const itemSchema: any = yup.object({ +export const itemSchema: yup.AnyObjectSchema = yup.object({ uid: uidSchema, type: yup .string() @@ -620,7 +620,7 @@ export const itemSchema: any = yup.object({ items: yup.array().of( yup.lazy(() => { return itemSchema; - }) + }) as unknown as yup.AnySchema ), examples: yup.array().of(exampleSchema).when('type', { is: (type: unknown): type is string => diff --git a/packages/bruno-schema/src/collections/itemSchema.spec.ts b/packages/bruno-schema/src/collections/itemSchema.spec.ts index 9d52132da6..769d74cc95 100644 --- a/packages/bruno-schema/src/collections/itemSchema.spec.ts +++ b/packages/bruno-schema/src/collections/itemSchema.spec.ts @@ -1,9 +1,10 @@ -const { expect } = require('@jest/globals'); -const { uuid, validationErrorWithMessages } = require('../utils/testUtils'); -const { itemSchema } = require('./index'); +import { expect } from '@jest/globals'; +import { uuid, validationErrorWithMessages } from '../utils/testUtils'; +import { itemSchema } from './index'; describe('Item Schema Validation', () => { it('item schema must validate successfully - simple items', async () => { + /** @type {{ uid: string; name: string; type: 'folder'; tags: readonly string[] }} */ const item = { uid: uuid(), name: 'A Folder', @@ -16,55 +17,51 @@ describe('Item Schema Validation', () => { }); it('item schema must throw an error if name is missing', async () => { + /** @type {{ uid: string; type: 'folder' }} */ const item = { uid: uuid(), type: 'folder' }; - return Promise.all([ - expect(itemSchema.validate(item)).rejects.toEqual(validationErrorWithMessages('name is required')) - ]); + await expect(itemSchema.validate(item)).rejects.toEqual(validationErrorWithMessages('name is required')); }); it('item schema must throw an error if name is empty', async () => { + /** @type {{ uid: string; name: string; type: 'folder' }} */ const item = { uid: uuid(), name: '', type: 'folder' }; - return Promise.all([ - expect(itemSchema.validate(item)).rejects.toEqual( - validationErrorWithMessages('name must be at least 1 character') - ) - ]); + await expect(itemSchema.validate(item)).rejects.toEqual( + validationErrorWithMessages('name must be at least 1 character') + ); }); it('item schema must throw an error if request is not present when item-type is http-request', async () => { + /** @type {{ uid: string; name: string; type: 'http-request' }} */ const item = { uid: uuid(), name: 'Get Users', type: 'http-request' }; - return Promise.all([ - expect(itemSchema.validate(item)).rejects.toEqual( - validationErrorWithMessages('request is required when item-type is request') - ) - ]); + await expect(itemSchema.validate(item)).rejects.toEqual( + validationErrorWithMessages('request is required when item-type is request') + ); }); it('item schema must throw an error if request is not present when item-type is graphql-request', async () => { + /** @type {{ uid: string; name: string; type: 'graphql-request' }} */ const item = { uid: uuid(), name: 'Get Users', type: 'graphql-request' }; - return Promise.all([ - expect(itemSchema.validate(item)).rejects.toEqual( - validationErrorWithMessages('request is required when item-type is request') - ) - ]); + await expect(itemSchema.validate(item)).rejects.toEqual( + validationErrorWithMessages('request is required when item-type is request') + ); }); }); diff --git a/packages/bruno-schema/src/collections/requestSchema.spec.ts b/packages/bruno-schema/src/collections/requestSchema.spec.ts index 41c6f8ddd2..b2d554579a 100644 --- a/packages/bruno-schema/src/collections/requestSchema.spec.ts +++ b/packages/bruno-schema/src/collections/requestSchema.spec.ts @@ -1,4 +1,5 @@ -import { expect, uuid } from '../utils/testUtils'; +import { expect } from "@jest/globals"; +import { uuid } from '../utils/testUtils'; import { requestSchema } from './index'; describe('Request Schema Validation', () => { diff --git a/packages/bruno-schema/src/utils/testUtils.ts b/packages/bruno-schema/src/utils/testUtils.ts index 8174a01ba6..5d99572ccc 100644 --- a/packages/bruno-schema/src/utils/testUtils.ts +++ b/packages/bruno-schema/src/utils/testUtils.ts @@ -8,10 +8,8 @@ export const uuid = (): string => { return customNanoId(); }; -export const validationErrorWithMessages = (...errors: string[]): any => { +export const validationErrorWithMessages = (...errors: string[]): ReturnType => { return expect.objectContaining({ errors }); }; - -export { expect }; From 1a4f3c8b12f506c3b5e804d5d2035279f6dbd913 Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 18:30:58 +0530 Subject: [PATCH 5/8] chore: add Jest preset configuration and clean up TypeScript configuration --- packages/bruno-schema/package.json | 5 ++++- packages/bruno-schema/src/collections/requestSchema.spec.ts | 1 - packages/bruno-schema/tsconfig.json | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/bruno-schema/package.json b/packages/bruno-schema/package.json index e381675871..aef1854e51 100644 --- a/packages/bruno-schema/package.json +++ b/packages/bruno-schema/package.json @@ -20,5 +20,8 @@ }, "dependencies": { "nanoid": "3.3.8" + }, + "jest": { + "preset": "ts-jest" } -} +} \ No newline at end of file diff --git a/packages/bruno-schema/src/collections/requestSchema.spec.ts b/packages/bruno-schema/src/collections/requestSchema.spec.ts index b2d554579a..f91ecde6ad 100644 --- a/packages/bruno-schema/src/collections/requestSchema.spec.ts +++ b/packages/bruno-schema/src/collections/requestSchema.spec.ts @@ -1,5 +1,4 @@ import { expect } from "@jest/globals"; -import { uuid } from '../utils/testUtils'; import { requestSchema } from './index'; describe('Request Schema Validation', () => { diff --git a/packages/bruno-schema/tsconfig.json b/packages/bruno-schema/tsconfig.json index 566b017d30..1454fde770 100644 --- a/packages/bruno-schema/tsconfig.json +++ b/packages/bruno-schema/tsconfig.json @@ -1,5 +1,4 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { "target": "ES2020", "module": "ESNext", @@ -30,4 +29,4 @@ "dist", "**/*.spec.ts" ] -} +} \ No newline at end of file From a5b59776db006595b523831e5640d543f6b79018 Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 18:32:58 +0530 Subject: [PATCH 6/8] chore: undiff --- packages/bruno-schema/src/collections/index.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/bruno-schema/src/collections/index.spec.ts b/packages/bruno-schema/src/collections/index.spec.ts index 8596db0200..3b98b28c1d 100644 --- a/packages/bruno-schema/src/collections/index.spec.ts +++ b/packages/bruno-schema/src/collections/index.spec.ts @@ -144,7 +144,7 @@ describe('Collection Schema Validation', () => { const collection = { version: '1', uid: uuid(), - name: 'My collection', + name: 'My Collection', items: [ { uid: uuid(), @@ -169,7 +169,7 @@ describe('Collection Schema Validation', () => { const collection = { version: '1', uid: uuid(), - name: 'My collection', + name: 'My Collection', items: [ { uid: uuid(), @@ -178,7 +178,7 @@ describe('Collection Schema Validation', () => { items: [ { uid: uuid(), - name: 'Get countries', + name: 'Get Countries', type: 'http-request', request: { url: 'https://restcountries.com/v2/alpha/in', @@ -192,7 +192,7 @@ describe('Collection Schema Validation', () => { }, { uid: uuid(), - name: 'Second level folder', + name: 'Second Level Folder', type: 'folder' } ] From 724850db3405e0e987868ed606fbe7bce26f1661 Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 18:38:07 +0530 Subject: [PATCH 7/8] chore: build script --- packages/bruno-schema/.gitignore | 2 ++ packages/bruno-schema/package.json | 15 +++++++++++---- packages/bruno-schema/tsconfig.json | 3 +-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/bruno-schema/.gitignore b/packages/bruno-schema/.gitignore index 024348ee56..50447684ed 100644 --- a/packages/bruno-schema/.gitignore +++ b/packages/bruno-schema/.gitignore @@ -5,3 +5,5 @@ out pnpm-lock.yaml package-lock.json yarn.lock + +/dist diff --git a/packages/bruno-schema/package.json b/packages/bruno-schema/package.json index aef1854e51..2ef05e6760 100644 --- a/packages/bruno-schema/package.json +++ b/packages/bruno-schema/package.json @@ -2,18 +2,25 @@ "name": "@usebruno/schema", "version": "0.7.0", "license": "MIT", - "main": "src/index.ts", - "types": "src/index.ts", + "main": "dist/index.js", + "types": "dist/index.d.ts", "files": [ + "dist", "src", "package.json" ], "scripts": { + "clean": "rimraf dist", + "prebuild": "npm run clean", + "build": "tsc", "test": "jest", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "prepack": "npm run build" }, "devDependencies": { - "@types/yup": "^0.29.14" + "@types/yup": "^0.29.14", + "rimraf": "^6.0.1", + "typescript": "^5.8.3" }, "peerDependencies": { "yup": "^0.32.11" diff --git a/packages/bruno-schema/tsconfig.json b/packages/bruno-schema/tsconfig.json index 1454fde770..78dc4cc37d 100644 --- a/packages/bruno-schema/tsconfig.json +++ b/packages/bruno-schema/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "target": "ES2020", - "module": "ESNext", + "module": "commonjs", "strict": true, "esModuleInterop": true, "skipLibCheck": true, @@ -12,7 +12,6 @@ "allowSyntheticDefaultImports": true, "moduleResolution": "node", "declaration": true, - "declarationDir": "./dist/types", "allowJs": false, "checkJs": false, "noImplicitAny": false, From 3eeb14fef6d5be9cb79ceb426b5ca8796ae92446 Mon Sep 17 00:00:00 2001 From: Sid Date: Mon, 5 Jan 2026 18:38:49 +0530 Subject: [PATCH 8/8] chore: force type --- packages/bruno-schema/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/bruno-schema/package.json b/packages/bruno-schema/package.json index 2ef05e6760..6b966446f5 100644 --- a/packages/bruno-schema/package.json +++ b/packages/bruno-schema/package.json @@ -4,6 +4,7 @@ "license": "MIT", "main": "dist/index.js", "types": "dist/index.d.ts", + "type": "commonjs", "files": [ "dist", "src",