diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 712831013..004d67b9a 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -11,6 +11,7 @@ env: permissions: contents: write + id-token: write jobs: publish-and-release: @@ -28,7 +29,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v4 with: - node-version: 22.x + node-version: 24.x cache: 'pnpm' registry-url: 'https://registry.npmjs.org' @@ -55,7 +56,7 @@ jobs: - name: Publish packages run: pnpm run publish-all env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: 'true' - name: Generate changelog id: changelog diff --git a/package.json b/package.json index a8076383a..8456e81df 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "zenstack-v3", "displayName": "ZenStack", "description": "ZenStack", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/auth-adapters/better-auth/package.json b/packages/auth-adapters/better-auth/package.json index ad40b27ee..a97ef4a75 100644 --- a/packages/auth-adapters/better-auth/package.json +++ b/packages/auth-adapters/better-auth/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/better-auth", "displayName": "ZenStack Better Auth Adapter", "description": "ZenStack Better Auth Adapter. This adapter is modified from better-auth's Prisma adapter.", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/cli/package.json b/packages/cli/package.json index 931b71ca3..5ce77f6cb 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/cli", "displayName": "ZenStack CLI", "description": "FullStack database toolkit with built-in access control and automatic API generation.", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/cli/test/db/pull.test.ts b/packages/cli/test/db/pull.test.ts index 811c20ccf..58649e3da 100644 --- a/packages/cli/test/db/pull.test.ts +++ b/packages/cli/test/db/pull.test.ts @@ -621,6 +621,7 @@ enum Status { `model User { id Int @id @default(autoincrement()) email String @unique @email + phone String @phone name String @length(min: 2, max: 100) website String? @url code String? @regex('^[A-Z]+$') diff --git a/packages/clients/client-helpers/README.md b/packages/clients/client-helpers/README.md new file mode 100644 index 000000000..5fc4a8416 --- /dev/null +++ b/packages/clients/client-helpers/README.md @@ -0,0 +1,3 @@ +# @zenstackhq/client-helpers + +Shared building blocks for implementing clients that consume ZenStack's CRUD service. Used internally by [`@zenstackhq/fetch-client`](../fetch-client) and [`@zenstackhq/tanstack-query`](../tanstack-query), and useful when building your own custom client. diff --git a/packages/clients/client-helpers/package.json b/packages/clients/client-helpers/package.json index 83fc10fba..40f5b6fbc 100644 --- a/packages/clients/client-helpers/package.json +++ b/packages/clients/client-helpers/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/client-helpers", "displayName": "ZenStack Client Helpers", "description": "Helpers for implementing clients that consume ZenStack's CRUD service", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/clients/fetch-client/README.md b/packages/clients/fetch-client/README.md new file mode 100644 index 000000000..1afb9986c --- /dev/null +++ b/packages/clients/fetch-client/README.md @@ -0,0 +1,32 @@ +# @zenstackhq/fetch-client + +A lightweight, type-safe fetch-based client for consuming ZenStack's RPC-style auto CRUD API. Provides the same model and operation surface as the server-side `ZenStackClient`, but issues HTTP requests instead of running queries locally. + +## Installation + +```bash +npm install @zenstackhq/fetch-client +``` + +## Usage + +```typescript +import { createClient } from '@zenstackhq/fetch-client'; +import { schema } from './schema'; + +const client = createClient(schema, { + endpoint: 'https://example.com/api/model', +}); + +const users = await client.user.findMany({ where: { active: true } }); +const post = await client.post.create({ data: { title: 'Hello' } }); + +const [user, newPost] = await client.$transaction([ + { model: 'User', op: 'create', args: { data: { email: 'alice@example.com' } } }, + { model: 'Post', op: 'create', args: { data: { title: 'Hello' } } }, +]); +``` + +## Learn More + +- [ZenStack Documentation](https://zenstack.dev/docs/service/client-sdk/fetch-client) diff --git a/packages/clients/fetch-client/package.json b/packages/clients/fetch-client/package.json index 3ffc77c2b..6836ffe1c 100644 --- a/packages/clients/fetch-client/package.json +++ b/packages/clients/fetch-client/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/fetch-client", "displayName": "ZenStack Fetch Client", "description": "Simple fetch-based client for consuming ZenStack's RPC-style CRUD API", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/clients/tanstack-query/README.md b/packages/clients/tanstack-query/README.md new file mode 100644 index 000000000..0f62ff0a1 --- /dev/null +++ b/packages/clients/tanstack-query/README.md @@ -0,0 +1,41 @@ +# @zenstackhq/tanstack-query + +[TanStack Query](https://tanstack.com/query) integration for ZenStack. Generates fully typed query and mutation hooks from your ZModel schema for React, Vue, and Svelte, with built-in cache invalidation and optimistic update helpers. + +## Supported Frameworks + +- **React** — `@zenstackhq/tanstack-query/react` +- **Vue** — `@zenstackhq/tanstack-query/vue` +- **Svelte** — `@zenstackhq/tanstack-query/svelte` + +## Installation + +```bash +npm install @zenstackhq/tanstack-query @tanstack/react-query +``` + +Replace `@tanstack/react-query` with `@tanstack/vue-query` or `@tanstack/svelte-query` as needed. + +## Usage (React example) + +```tsx +import { useClientQueries } from '@zenstackhq/tanstack-query/react'; +import { schema } from './schema'; + +function PostList() { + const client = useClientQueries(schema); + + const { data: posts } = client.post.useQuery({ + where: { published: true }, + include: { author: true }, + }); + + const { mutate: createPost } = client.post.useMutation(); + + return ; +} +``` + +## Learn More + +- [ZenStack Documentation](https://zenstack.dev/docs/service/client-sdk/tanstack-query/) diff --git a/packages/clients/tanstack-query/package.json b/packages/clients/tanstack-query/package.json index 54172d272..90d4add21 100644 --- a/packages/clients/tanstack-query/package.json +++ b/packages/clients/tanstack-query/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/tanstack-query", "displayName": "ZenStack TanStack Query Integration", "description": "TanStack Query Client for consuming ZenStack v3's CRUD service", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/common-helpers/package.json b/packages/common-helpers/package.json index 7ce8e86de..c570e0e58 100644 --- a/packages/common-helpers/package.json +++ b/packages/common-helpers/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/common-helpers", "displayName": "ZenStack Common Helpers", "description": "ZenStack Common Helpers", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/config/eslint-config/package.json b/packages/config/eslint-config/package.json index 8651d6432..560889bd7 100644 --- a/packages/config/eslint-config/package.json +++ b/packages/config/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/eslint-config", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "private": true, "license": "MIT" diff --git a/packages/config/tsdown-config/package.json b/packages/config/tsdown-config/package.json index 5203ce764..477d67c02 100644 --- a/packages/config/tsdown-config/package.json +++ b/packages/config/tsdown-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/tsdown-config", - "version": "3.7.1", + "version": "3.7.2", "private": true, "type": "module", "license": "MIT", diff --git a/packages/config/typescript-config/package.json b/packages/config/typescript-config/package.json index 673bb69f5..3f7337055 100644 --- a/packages/config/typescript-config/package.json +++ b/packages/config/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/typescript-config", - "version": "3.7.1", + "version": "3.7.2", "private": true, "license": "MIT" } diff --git a/packages/config/vitest-config/package.json b/packages/config/vitest-config/package.json index 713cabb63..058d5ce67 100644 --- a/packages/config/vitest-config/package.json +++ b/packages/config/vitest-config/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/vitest-config", "type": "module", - "version": "3.7.1", + "version": "3.7.2", "private": true, "license": "MIT", "exports": { diff --git a/packages/create-zenstack/package.json b/packages/create-zenstack/package.json index 8515e7629..f20cfed63 100644 --- a/packages/create-zenstack/package.json +++ b/packages/create-zenstack/package.json @@ -2,7 +2,7 @@ "name": "create-zenstack", "displayName": "Create ZenStack", "description": "Create a new ZenStack project", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/ide/vscode/package.json b/packages/ide/vscode/package.json index c6f85e050..7931002c9 100644 --- a/packages/ide/vscode/package.json +++ b/packages/ide/vscode/package.json @@ -1,7 +1,7 @@ { "name": "zenstack-v3", "publisher": "zenstack", - "version": "3.7.1", + "version": "3.7.2", "displayName": "ZenStack V3 Language Tools", "description": "VSCode extension for ZenStack (v3) ZModel language", "private": true, diff --git a/packages/language/package.json b/packages/language/package.json index 75a47aa41..97d5f2805 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/language", "displayName": "ZenStack Language Tooling", "description": "ZenStack ZModel language specification", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/language/res/stdlib.zmodel b/packages/language/res/stdlib.zmodel index 99dafdbd5..4561da14a 100644 --- a/packages/language/res/stdlib.zmodel +++ b/packages/language/res/stdlib.zmodel @@ -551,6 +551,11 @@ attribute @datetime(_ message: String?) @@@targetField([StringField]) @@@validat */ attribute @url(_ message: String?) @@@targetField([StringField]) @@@validation +/** + * Validates a string field value is a valid E.164 phone number. + */ +attribute @phone(_ message: String?) @@@targetField([StringField]) @@@validation + /** * Trims whitespaces from the start and end of the string. */ @@ -622,6 +627,12 @@ function isDateTime(field: String): Boolean { function isUrl(field: String): Boolean { } @@@expressionContext([ValidationRule]) +/** + * Validates a string field value is a valid E.164 phone number. + */ +function isPhone(field: String): Boolean { +} @@@expressionContext([ValidationRule]) + ////////////////////////////////////////////// // End validation attributes and functions ////////////////////////////////////////////// diff --git a/packages/orm/package.json b/packages/orm/package.json index a72106534..ce62edc31 100644 --- a/packages/orm/package.json +++ b/packages/orm/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/orm", "displayName": "ZenStack ORM", "description": "ZenStack ORM", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/plugins/policy/package.json b/packages/plugins/policy/package.json index fbea698c0..9cbb28126 100644 --- a/packages/plugins/policy/package.json +++ b/packages/plugins/policy/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/plugin-policy", "displayName": "ZenStack Access Policy Plugin", "description": "ZenStack plugin that enforces access control policies defined in the schema", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/schema/package.json b/packages/schema/package.json index efd85e628..a5e42c1fb 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/schema", "displayName": "ZenStack Schema Object Model", "description": "TypeScript representation of ZModel schema", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 54a23b2bf..d886d8765 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/sdk", "displayName": "ZenStack SDK", "description": "Utilities for building ZenStack plugins", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/server/package.json b/packages/server/package.json index 1f9cf3349..f71f11d6e 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/server", "displayName": "ZenStack Automatic CRUD Server", "description": "ZenStack automatic CRUD API handlers and server adapters for popular frameworks", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/testtools/package.json b/packages/testtools/package.json index d26f90f1b..5e9cb76e7 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/testtools", "displayName": "ZenStack Test Tools", "description": "ZenStack Test Tools", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/zod/package.json b/packages/zod/package.json index 3cae1587d..4161686f8 100644 --- a/packages/zod/package.json +++ b/packages/zod/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/zod", "displayName": "ZenStack Zod Integration", "description": "Automatically deriving Zod schemas from ZModel schemas", - "version": "3.7.1", + "version": "3.7.2", "type": "module", "author": { "name": "ZenStack Team", diff --git a/packages/zod/src/utils.ts b/packages/zod/src/utils.ts index 9081c1c86..f21d9196f 100644 --- a/packages/zod/src/utils.ts +++ b/packages/zod/src/utils.ts @@ -72,6 +72,9 @@ export function addStringValidation( case '@email': result = result.email(); break; + case '@phone': + result = result.e164(); + break; case '@datetime': result = result.datetime(); break; @@ -533,12 +536,19 @@ function evalCall(data: any, expr: CallExpression) { } case 'isEmail': case 'isUrl': + case 'isPhone': case 'isDateTime': { if (fieldArg === undefined || fieldArg === null || fieldArg === ABSENT) { return false; } invariant(typeof fieldArg === 'string', `"${f}" first argument must be a string`); - const fn = f === 'isEmail' ? ('email' as const) : f === 'isUrl' ? ('url' as const) : ('datetime' as const); + const fn = f === 'isEmail' + ? ('email' as const) + : f === 'isUrl' + ? ('url' as const) + : f === 'isPhone' + ? ('e164' as const) + : ('datetime' as const); return z.string()[fn]().safeParse(fieldArg).success; } // list functions diff --git a/packages/zod/test/factory.test.ts b/packages/zod/test/factory.test.ts index 0dd616c2d..f221d2b64 100644 --- a/packages/zod/test/factory.test.ts +++ b/packages/zod/test/factory.test.ts @@ -11,6 +11,7 @@ const factory = createSchemaFactory(schema); const validUser = { id: 'user123', email: 'test@example.com', + phone: '+15555555555', username: 'johndoe', website: null, code: 'USR001', @@ -44,6 +45,7 @@ describe('SchemaFactory - makeModelSchema', () => { // required string fields expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); // optional string field (nullable + optional) @@ -259,6 +261,18 @@ describe('SchemaFactory - makeModelSchema', () => { expect(result.success).toBe(true); }); + it('rejects invalid phone number for @phone field', () => { + const userSchema = factory.makeModelSchema('User'); + const result = userSchema.safeParse({ ...validUser, phone: 'not-a-phone' }); + expect(result.success).toBe(false); + }); + + it('accepts valid phone number for @phone field', () => { + const userSchema = factory.makeModelSchema('User'); + const result = userSchema.safeParse({ ...validUser, phone: '+15555555555' }); + expect(result.success).toBe(true); + }); + it('rejects code that does not start with "USR" for @startsWith', () => { const userSchema = factory.makeModelSchema('User'); const result = userSchema.safeParse({ ...validUser, code: 'ABC001' }); @@ -576,6 +590,7 @@ describe('SchemaFactory - makeTypeSchema', () => { const validUser = { id: 'u1', email: 'a@b.com', + phone: '+15555555555', username: 'alice', website: null, code: 'USR01', @@ -934,7 +949,9 @@ describe('SchemaFactory - makeModelSchema with options', () => { expectTypeOf().toHaveProperty('id'); expectTypeOf().toEqualTypeOf(); expectTypeOf().toHaveProperty('email'); + expectTypeOf().toHaveProperty('phone'); expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); }); it('omit: {} (empty) keeps all scalar fields', () => { @@ -954,6 +971,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { expectTypeOf().not.toHaveProperty('username'); expectTypeOf().not.toHaveProperty('avatar'); expectTypeOf().toHaveProperty('email'); + expectTypeOf().toHaveProperty('phone'); }); }); @@ -985,6 +1003,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { type Result = z.infer; expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); }); @@ -1039,6 +1058,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { type Result = z.infer; expectTypeOf().not.toHaveProperty('username'); expectTypeOf().toHaveProperty('email'); + expectTypeOf().toHaveProperty('phone'); expectTypeOf().toHaveProperty('posts'); }); }); @@ -1069,6 +1089,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { expectTypeOf().toEqualTypeOf(); expectTypeOf().not.toHaveProperty('username'); expectTypeOf().not.toHaveProperty('posts'); + expectTypeOf().not.toHaveProperty('phone'); }); it('select with a relation field (true) includes the relation', () => { @@ -1084,6 +1105,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { expectTypeOf().toHaveProperty('id'); expectTypeOf().toHaveProperty('posts'); expectTypeOf().not.toHaveProperty('email'); + expectTypeOf().not.toHaveProperty('phone'); }); it('select with nested options on a relation', () => { @@ -1214,6 +1236,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { type Result = z.infer; expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); @@ -1342,6 +1365,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { const _schema = factory.makeModelSchema('User', { optionality: 'all' }); type Result = z.infer; expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); // already-optional nullable field @@ -1356,6 +1380,7 @@ describe('SchemaFactory - makeModelSchema with options', () => { type Result = z.infer; expectTypeOf().not.toHaveProperty('username'); expectTypeOf().toEqualTypeOf(); + expectTypeOf().toEqualTypeOf(); }); it('infers selected fields as optional when optionality is all', () => { diff --git a/packages/zod/test/schema/schema.ts b/packages/zod/test/schema/schema.ts index e0dff2a49..3b8dd6eb2 100644 --- a/packages/zod/test/schema/schema.ts +++ b/packages/zod/test/schema/schema.ts @@ -26,6 +26,11 @@ export class SchemaType implements SchemaDef { type: "String", attributes: [{ name: "@email" }, { name: "@meta", args: [{ name: "name", value: ExpressionUtils.literal("description") }, { name: "value", value: ExpressionUtils.literal("The user's email address") }] }] as readonly AttributeApplication[] }, + phone: { + name: "phone", + type: "String", + attributes: [{ name: "@phone" }] as readonly AttributeApplication[] + }, username: { name: "username", type: "String", diff --git a/packages/zod/test/schema/schema.zmodel b/packages/zod/test/schema/schema.zmodel index 9e0d5716a..0fc3aec88 100644 --- a/packages/zod/test/schema/schema.zmodel +++ b/packages/zod/test/schema/schema.zmodel @@ -23,6 +23,7 @@ type Address { model User { id String @id @default(cuid()) email String @email @meta("description", "The user's email address") + phone String @phone username String @length(3, 50) website String? @url code String @startsWith("USR") diff --git a/samples/orm/package.json b/samples/orm/package.json index c8df85405..0368c8902 100644 --- a/samples/orm/package.json +++ b/samples/orm/package.json @@ -1,6 +1,6 @@ { "name": "sample-orm", - "version": "3.7.1", + "version": "3.7.2", "description": "", "main": "index.js", "private": true, diff --git a/tests/e2e/orm/validation/custom-validation.test.ts b/tests/e2e/orm/validation/custom-validation.test.ts index 35df71b60..905c99c92 100644 --- a/tests/e2e/orm/validation/custom-validation.test.ts +++ b/tests/e2e/orm/validation/custom-validation.test.ts @@ -12,6 +12,7 @@ describe('Custom validation tests', () => { str3 String? str4 String? str5 String? + str6 String? int1 Int? list1 Int[] list2 Int[] @@ -32,6 +33,8 @@ describe('Custom validation tests', () => { @@validate(str5 == null || isDateTime(str5), 'invalid str5') + @@validate(str6 == null || isPhone(str6), 'invalid str6') + @@validate(list1 == null || (has(list1, 1) && hasSome(list1, [2, 3]) && hasEvery(list1, [4, 5])), 'invalid list1') @@validate(list2 == null || isEmpty(list2), 'invalid list2', ['x', 'y']) @@ -77,6 +80,9 @@ describe('Custom validation tests', () => { // violates datetime await expect(_t({ str5: 'not-an-datetime' })).toBeRejectedByValidation(['invalid str5']); + // violates phone + await expect(_t({ str6: 'not-a-phone' })).toBeRejectedByValidation(['invalid str6']); + // violates has await expect(_t({ list1: [2, 3, 4, 5] })).toBeRejectedByValidation(['invalid list1']); @@ -107,6 +113,7 @@ describe('Custom validation tests', () => { str3: 'ab@c.com', str4: 'http://a.b.c', str5: new Date().toISOString(), + str6: '+15555555555', int1: 2, list1: [1, 2, 4, 5], list2: [], diff --git a/tests/e2e/orm/validation/toplevel.test.ts b/tests/e2e/orm/validation/toplevel.test.ts index fab16d636..65927e192 100644 --- a/tests/e2e/orm/validation/toplevel.test.ts +++ b/tests/e2e/orm/validation/toplevel.test.ts @@ -14,6 +14,7 @@ describe('Toplevel field validation tests', () => { str4 String? @url str5 String? @trim @lower str6 String? @upper + str7 String? @phone } `, ); @@ -83,6 +84,12 @@ describe('Toplevel field validation tests', () => { } else { await expect(_t({ str6: 'aBc' })).resolves.toMatchObject({ count: 1 }); } + + // violates @phone + await expect(_t({ str7: 'not-a-phone' })).toBeRejectedByValidation(['Invalid E.164']); + + // satisfies @phone + await expect(_t({ str7: '+15555555555' })).toResolveTruthy(); } }); diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 228ebee18..49f8aca55 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -1,6 +1,6 @@ { "name": "e2e", - "version": "3.7.1", + "version": "3.7.2", "private": true, "type": "module", "scripts": { diff --git a/tests/regression/package.json b/tests/regression/package.json index 6b1f35c80..6f7b4945f 100644 --- a/tests/regression/package.json +++ b/tests/regression/package.json @@ -1,6 +1,6 @@ { "name": "regression", - "version": "3.7.1", + "version": "3.7.2", "private": true, "type": "module", "scripts": { diff --git a/tests/runtimes/bun/package.json b/tests/runtimes/bun/package.json index bd6407caf..a99454a00 100644 --- a/tests/runtimes/bun/package.json +++ b/tests/runtimes/bun/package.json @@ -1,6 +1,6 @@ { "name": "bun-e2e", - "version": "3.7.1", + "version": "3.7.2", "private": true, "type": "module", "scripts": { diff --git a/tests/runtimes/edge-runtime/package.json b/tests/runtimes/edge-runtime/package.json index 32c5d6a2a..ba2e31069 100644 --- a/tests/runtimes/edge-runtime/package.json +++ b/tests/runtimes/edge-runtime/package.json @@ -1,6 +1,6 @@ { "name": "edge-runtime-e2e", - "version": "3.7.1", + "version": "3.7.2", "private": true, "type": "module", "scripts": {