Skip to content

Commit 0289b94

Browse files
authored
docs: release 2.8.0 (#381)
* docs: release 2.8.0 * add limitations * updates * update * update
1 parent ea766be commit 0289b94

File tree

7 files changed

+338
-13
lines changed

7 files changed

+338
-13
lines changed

docs/guides/authentication/lucia.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ sidebar_position: 5
44
sidebar_label: Lucia
55
---
66

7-
# Integrating With Lucia
7+
# Integrating With Lucia (Deprecated)
8+
9+
:::info
10+
Lucia's is [not in active development anymore](https://github.com/lucia-auth/lucia/discussions/1714).
11+
:::
812

913
[Lucia](https://lucia-auth.com/) is an auth library for your server that abstracts away the complexity of handling sessions. It is a good choice if you need to add custom logic to the auth flow or use email and password authentication.
1014

docs/guides/authentication/next-auth.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ sidebar_label: Auth.js (NextAuth)
66

77
# Integrating With Auth.js (NextAuth)
88

9-
[NextAuth](https://authjs.dev/) is a comprehensive framework for implementing authentication in Next.js projects. It offers a pluggable mechanism for configuring how user data is persisted.
9+
[Auth.js](https://authjs.dev/) is a comprehensive framework for implementing authentication in Next.js projects. It offers a pluggable mechanism for configuring how user data is persisted.
1010

11-
To get access policies to work, ZenStack needs to be connected to the authentication system to get the user's identity. This guide introduces tasks required for integrating ZenStack with NextAuth. You can find a complete example [here](https://github.com/zenstackhq/sample-todo-nextjs ':target=blank').
11+
To get access policies to work, ZenStack needs to be connected to the authentication system to get the user's identity. This guide introduces tasks required for integrating ZenStack with Auth.js. You can find a complete example [here](https://github.com/zenstackhq/sample-todo-nextjs ':target=blank').
1212

1313
### Data model requirement
1414

15-
NextAuth is agnostic about the underlying database type, but it requires specific table structures, depending on how you configure it. Therefore, your ZModel definitions should reflect these requirements. A sample `User` model is shown here (to be used with `CredentialsProvider`):
15+
Auth.js is agnostic about the underlying database type, but it requires specific table structures, depending on how you configure it. Therefore, your ZModel definitions should reflect these requirements. A sample `User` model is shown here (to be used with `CredentialsProvider`):
1616

1717
```zmodel title='/schema.zmodel'
1818
model User {
@@ -35,7 +35,7 @@ You can find the detailed database model requirements [here](https://authjs.dev/
3535

3636
### Adapter
3737

38-
Adapter is a NextAuth mechanism for hooking in custom persistence of auth-related entities, like User, Account, etc. Since ZenStack is based on Prisma, you can use PrismaAdapter for the job:
38+
Adapter is a Auth.js mechanism for hooking in custom persistence of auth-related entities, like User, Account, etc. Since ZenStack is based on Prisma, you can use PrismaAdapter for the job:
3939

4040
```ts title='/src/pages/api/auth/[...nextauth].ts'
4141
import { PrismaAdapter } from "@next-auth/prisma-adapter";
@@ -108,7 +108,7 @@ function authorize(prisma: PrismaClient) {
108108

109109
You can create an enhanced Prisma client which automatically validates access policies, field validation rules etc., during CRUD operations. For more details, please refer to [ZModel Language](../../reference/zmodel-language) reference.
110110

111-
To create such a client with a standard setup, call the `enhance` API with a regular Prisma client and the current user (fetched with NextAuth API). Here's an example:
111+
To create such a client with a standard setup, call the `enhance` API with a regular Prisma client and the current user (fetched with Auth.js API). Here's an example:
112112

113113
```ts
114114
import type { NextApiRequest, NextApiResponse } from 'next';

docs/guides/edge.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Guide for deploying ZenStack to edge runtime.
33
sidebar_position: 12
44
---
55

6-
# Deploying to Edge Runtime (Preview)
6+
# Deploying to Edge Runtime
77

88
## Introduction
99

docs/guides/typing-json.md

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
---
2+
description: Typing JSON fields
3+
sidebar_position: 15
4+
---
5+
6+
# Typing JSON Fields (Preview)
7+
8+
> The design and implementation are inspired by [prisma-json-types-generator](https://github.com/arthurfiorette/prisma-json-types-generator).
9+
10+
Relational databases provide the benefit of strong schema enforcement, but sometimes, you want to step out of that guardrail and have more flexibility around data modeling. Prisma's JSON type allows you to store arbitrary JSON data in a column. It can be a good fit for use cases like:
11+
12+
- You want to store objects along with the main entity, but it's not worth creating a separate table for them.
13+
- Your objects have many possible fields, but you don't want to create tables with wide columns.
14+
- Your object's structure is not fixed and can change over time in a non-backward-compatible way.
15+
16+
JSON fields provide great flexibility but at the cost of losing strong typing and validation. ZenStack's strongly typed JSON field feature helps you regain the lost benefits.
17+
18+
## Defining types
19+
20+
To type JSON fields, you'll first need to create type declarations in your ZModel schema. For example, you can define a user profile type like:
21+
22+
```zmodel
23+
type Profile {
24+
name String
25+
age Int
26+
}
27+
```
28+
29+
Types can include fields of other types too:
30+
31+
```zmodel
32+
type Address {
33+
state String
34+
city String
35+
zip String
36+
}
37+
38+
type Profile {
39+
name String
40+
age Int
41+
address Address?
42+
}
43+
```
44+
45+
Type declarations are similar to model declarations with the following differences:
46+
47+
- Types are not mapped to database tables.
48+
- Types cannot inherit from other types yet. This will be supported in future releases.
49+
- Types cannot have relations with models (since they aren't tables anyway).
50+
51+
## Defining strongly-typed JSON fields
52+
53+
You can then use these types to define strongly typed JSON fields in data models:
54+
55+
```zmodel
56+
model User {
57+
id String @id @default(cuid())
58+
profile Profile @json
59+
60+
@@allow('all', true)
61+
}
62+
```
63+
64+
:::info
65+
66+
Strongly typed JSON fields must be annotated with the `@json` attribute. The purpose is to make them easily distinguishable from relational fields.
67+
68+
The feature is only supported for PostgreSQL database for now.
69+
70+
:::
71+
72+
## `PrismaClient` typing
73+
74+
ZenStack's enhanced `PrismaClient` provides type-safe mutation input and query results for strongly typed JSON fields.
75+
76+
```ts
77+
import { enhance } from '@zenstackhq/runtime';
78+
import { prisma } from '~/db';
79+
80+
const db = enhance(prisma);
81+
82+
// The following create call results in a type error because of the
83+
// incorrect type of the `age` field
84+
await db.user.create({
85+
data: {
86+
profile: { name: 'Alice', age: '30' /* incorrect type */ }
87+
}
88+
});
89+
90+
// The query result is typed as:
91+
// {
92+
// id: string;
93+
// profile: {
94+
// name: string;
95+
// age: number;
96+
// address: {
97+
// state: string;
98+
// city: string;
99+
// zip: string;
100+
// } | null;
101+
// };
102+
// }
103+
await user = await db.user.findFirstOrThrow();
104+
```
105+
106+
The query also deals with transforming JSON fields into proper JavaScript types. For example, `DateTime` field values will be parsed from strings into `Date` objects.
107+
108+
Please note that ZenStack **DOES NOT** validate if the query result data conforms to the JSON field types. If you have non-conforming existing data, you'll have to do additional checking or transformation, instead of trusting the TypeScript typing. We thought this was a reasonable trade-off to preserve the flexibility of JSON fields.
109+
110+
:::info
111+
Prisma filter clauses are not enhanced, which means when you filter by the JSON fields, you'll still need to use [Prisma's JSON filter syntax](https://www.prisma.io/docs/orm/prisma-client/special-fields-and-types/working-with-json-fields#filter-on-a-json-field-simple).
112+
113+
In the future, we may provide a more natural filtering experience, like:
114+
115+
```ts
116+
await db.user.findMany({
117+
where: {
118+
profile: { name: 'Alice' }
119+
}
120+
});
121+
```
122+
123+
However, it can potentially confuse code readers on whether the filter happens on a JSON field or a relational field (which involves joins). [Let us know your thoughts](https://discord.gg/Ykhr738dUe) on this!
124+
125+
:::
126+
127+
## Mutation payload validation
128+
129+
During mutation, the enhanced `PrismaClient` validates if the input data conforms to the JSON field type. Even if you bypass TypeScript's type checking, ZenStack will reject an incorrect payload with a runtime error.
130+
131+
```ts
132+
await db.user.create({
133+
data: {
134+
email: 'abc',
135+
profile: { name: 'Alice', age: '30' /* incorrect type */ },
136+
},
137+
} as any // bypass TypeScript type checking
138+
);
139+
```
140+
141+
```plain
142+
Error calling enhanced Prisma method `user.create`: denied by policy: user
143+
entities failed 'create' check, input failed validation: Validation error:
144+
Expected number, received string at "profile.age"
145+
```
146+
147+
You can also annotate the type declaration with additional [validation attributes](../reference/zmodel-language#data-validation):
148+
149+
```zmodel
150+
type Profile {
151+
name String
152+
age Int @gte(18) @lt(150) // must be between 18 and 150
153+
address Address?
154+
}
155+
```
156+
157+
Such validations will also be enforced during mutation. For example, the following call will be rejected:
158+
159+
```ts
160+
await db.user.create({
161+
data: {
162+
email: 'abc',
163+
profile: { name: 'Alice', age: 16 },
164+
},
165+
});
166+
```
167+
168+
```plain
169+
Error calling enhanced Prisma method `user.create`: denied by policy: user
170+
entities failed 'create' check, input failed validation: Validation error:
171+
Number must be greater than or equal to 18 at "profile.age"
172+
```
173+
174+
## TypeScript types
175+
176+
ZenStack generates TypeScript types for the "type" declarations. You can import them from `@zenstackhq/runtime/models`:
177+
178+
```ts
179+
import type { Profile } from '@zenstackhq/runtime/models';
180+
181+
const profile: Profile = {
182+
name: 'Alice',
183+
age: 30,
184+
address: { state: 'WA', city: 'Seattle', zip: '98019' }
185+
};
186+
```
187+
188+
## Zod schemas
189+
190+
ZenStack also generates Zod schemas for the "type" declarations. You can import them from `@zenstackhq/runtime/zod/models`:
191+
192+
```ts
193+
import { ProfileSchema } from '@zenstackhq/runtime/zod/models';
194+
195+
const profile = ProfileSchema.parse({
196+
name: 'Alice',
197+
age: 30,
198+
address: { state: 'WA', city: 'Seattle', zip: '98019' }
199+
});
200+
```
201+
202+
## Limitations
203+
204+
This feature is in preview and has the following limitations:
205+
206+
1. Types cannot inherit from other types.
207+
1. Models cannot inherit from types.
208+
1. Types and abstract models are conceptually similar and they should probably be consolidated.
209+
1. JSON field members cannot be used in access policies.
210+
211+
We would like to continue gathering feedback and address these limitations in future releases.

docs/reference/cli.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ You don't need to `await` the Prisma method call result. The REPL session will a
157157
| ----- | ------------------- | ------- |
158158
| --debug | Enable debug output. Can be toggled on the fly in the repl session with the ".debug" command. | false |
159159
| --table | Enable table format. Can be toggled on the fly in the repl session with the ".table" command. | false |
160-
| --prisma-client | Path to load PrismaClient module. | "./node_modules/.prisma/client" |
160+
| --prisma-client <path> | Path to load PrismaClient module. | "node_modules/.prisma/client" |
161+
| --load-path <path> | Path to load modules generated by ZenStack. | "node_modules/.zenstack" |
161162

162163
#### Repl Commands
163164

0 commit comments

Comments
 (0)