Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ env:

permissions:
contents: write
id-token: write

jobs:
publish-and-release:
Expand All @@ -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'

Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/auth-adapters/better-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/test/db/pull.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]+$')
Expand Down
3 changes: 3 additions & 0 deletions packages/clients/client-helpers/README.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion packages/clients/client-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
32 changes: 32 additions & 0 deletions packages/clients/fetch-client/README.md
Original file line number Diff line number Diff line change
@@ -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.
Comment thread
ymc9 marked this conversation as resolved.

## 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)
2 changes: 1 addition & 1 deletion packages/clients/fetch-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
41 changes: 41 additions & 0 deletions packages/clients/tanstack-query/README.md
Original file line number Diff line number Diff line change
@@ -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 <ul>{posts?.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;
}
```

## Learn More

- [ZenStack Documentation](https://zenstack.dev/docs/service/client-sdk/tanstack-query/)
2 changes: 1 addition & 1 deletion packages/clients/tanstack-query/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/common-helpers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/config/eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/eslint-config",
"version": "3.7.1",
"version": "3.7.2",
"type": "module",
"private": true,
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion packages/config/tsdown-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/tsdown-config",
"version": "3.7.1",
"version": "3.7.2",
"private": true,
"type": "module",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/config/typescript-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/typescript-config",
"version": "3.7.1",
"version": "3.7.2",
"private": true,
"license": "MIT"
}
2 changes: 1 addition & 1 deletion packages/config/vitest-config/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/vitest-config",
"type": "module",
"version": "3.7.1",
"version": "3.7.2",
"private": true,
"license": "MIT",
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/create-zenstack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/vscode/package.json
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/language/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 11 additions & 0 deletions packages/language/res/stdlib.zmodel
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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
//////////////////////////////////////////////
Expand Down
2 changes: 1 addition & 1 deletion packages/orm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/policy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/testtools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion packages/zod/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
12 changes: 11 additions & 1 deletion packages/zod/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading