Skip to content

Commit 1b3ccfc

Browse files
authored
doc: release 3.0.0-beta.24 (#509)
1 parent 66ea0da commit 1b3ccfc

File tree

10 files changed

+187
-11
lines changed

10 files changed

+187
-11
lines changed

docs/guides/multiple-schema.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ model Post extends Base
3232
viewCount Int @default(0)
3333
}
3434

35-
model ToDo extends Base
35+
model Todo extends Base
3636
{
3737
title String
3838
completed Boolean @default(false)

docs/quick-start/authentication/better-auth.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ type Auth {
110110
Here is how you could access it in the access policies:
111111

112112
```tsx
113-
model ToDo {
113+
model Todo {
114114
...
115115
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
116116
organizationId String? @default(auth().organizationId) @allow('update', false)

docs/quick-start/authentication/supabase.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ To get access policies to work, ZenStack needs to be connected to the authentica
1616
This section is only relevant if you're also using Supabase's Database service as the underlying Postgres database of Prisma/ZenStack.
1717
:::
1818

19-
This section is not directly to integrating authentication, but since ZenStack is based on Prisma, understanding how Prisma and Supabase should be set up appropriately when Supabase Auth is involved is important.
19+
This section is not directly related to integrating authentication, but since ZenStack is based on Prisma, understanding how Prisma and Supabase should be set up appropriately when Supabase Auth is involved is important.
2020

2121
Supabase Auth stores user data in a separate Postgres schema called "auth". Since that schema is managed by Supabase, it's good idea not to directly import it into ZModel and use it in your application, since Supabase team may decide to change table schemas at any time. Instead, a better approach is to define your own `User` model in ZModel, and use database triggers to synchronize user data from Supabase Auth to your `User` table.
2222

versioned_docs/version-1.x/guides/multiple-schema.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ model Post extends Base
3232
viewCount Int @default(0)
3333
}
3434

35-
model ToDo extends Base
35+
model Todo extends Base
3636
{
3737
title String
3838
completed Boolean @default(false)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
position: 1
2+
label: Integrating With Authentication
3+
collapsible: true
4+
collapsed: true
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
sidebar_position: 1
3+
---
4+
5+
import PackageInstall from '../../_components/PackageInstall';
6+
import PackageExec from '../../_components/PackageExec';
7+
8+
# Better-Auth Integration
9+
10+
[Better-Auth](https://better-auth.com) is a comprehensive authentication library for TypeScript applications. It supports a wide range of authentication providers and offers a flexible plugin system.
11+
12+
This guide will show you how to integrate better-auth with ZenStack.
13+
14+
## Using ZenStack as better-auth's database provider
15+
16+
ZenStack provides a better-auth database adapter in the `@zenstackhq/better-auth` package. You can use it to configure better-auth to use ZenStack ORM as its database backend.
17+
18+
### Installation
19+
20+
<PackageInstall dependencies={["@zenstackhq/better-auth@next"]} />
21+
22+
### Better-Auth configuration
23+
24+
Add the adapter to your better-auth configuration:
25+
26+
```ts
27+
import { zenstackAdapter } from '@zenstackhq/better-auth';
28+
import { db } from './db'; // your ZenStack ORM client
29+
30+
const auth = new BetterAuth({
31+
database: zenstackAdapter(db, {
32+
provider: 'postgresql',
33+
}),
34+
// other better-auth options...
35+
});
36+
```
37+
38+
### Schema generation
39+
40+
With the adapter set up, you can use better-auth CLI to populate its database models into your ZModel schema. Make sure you've installed the CLI:
41+
42+
<PackageInstall devDependencies={["@better-auth/cli"]} />
43+
44+
Then, run the "generate" command to generate the schema:
45+
46+
<PackageExec command="@better-auth/cli generate" />
47+
48+
Alternatively, you can refer to [better-auth schema documentation](https://www.better-auth.com/docs/concepts/database#core-schema) to manually add the necessary models.
49+
50+
After the schema is configured, you can then use the regular ZenStack database schema migration workflow to push the schema to your database.
51+
52+
## Integrating better-auth with ZenStack's access control
53+
54+
### Creating user-bound ORM client
55+
56+
ZenStack provides a powerful [access control system](../../orm/access-control/) that allows you to define fine-grained access policies for your data models. Enforcing access control often requires fetching the validated current user's identity, which is authentication system's responsibility.
57+
58+
With better-auth, you can use the `auth.api.getSession()` API to get the current session on the server side. The following code shows an example with Next.js:
59+
60+
```tsx
61+
import { betterAuth } from "better-auth";
62+
import { headers } from "next/headers";
63+
64+
export const auth = betterAuth({
65+
//...
66+
})
67+
68+
// calling get session on the server
69+
const {session} = await auth.api.getSession({
70+
headers: await headers() // some endpoint might require headers
71+
});
72+
73+
// get the userId from session data
74+
const userId = session.userId;
75+
```
76+
77+
Then you can pass it to `ZenStackClient`'s `$setAuth()` method to get a user-bound ORM client.
78+
79+
```tsx
80+
const userDb = db.$setAuth({ userId });
81+
```
82+
83+
### Organization plugin support
84+
85+
Better-Auth has a powerful plugin system that allows you to add new features that contribute extensions across the entire stack - data model, backend API, and frontend hooks. A good example is the [Organization plugin](https://www.better-auth.com/docs/plugins/organization), which sets the foundation for implementing multi-tenant apps with access control.
86+
87+
After enabling the Organization plugin and running the CLI to generate the additional models and fields in the schema, you can use the code below on the server side to get the organization info together with the user identity:
88+
89+
```tsx
90+
91+
let organizationRole: string | undefined = undefined;
92+
const organizationId = session.activeOrganizationId;
93+
const org = await auth.api.getFullOrganization({ headers: reqHeaders });
94+
if (org?.members) {
95+
const myMember = org.members.find(
96+
(m) => m.userId === session.userId
97+
);
98+
organizationRole = myMember?.role;
99+
}
100+
101+
// user identity with organization info
102+
const userContext = {
103+
userId: session.userId,
104+
organizationId,
105+
organizationRole,
106+
};
107+
```
108+
109+
Then you can use the full `userContext` object to get a user-bound client.
110+
111+
```tsx
112+
const userDb = db.$setAuth(userContext);
113+
```
114+
115+
The user context will be accessible in ZModel policy rules via the special `auth()` function. To get it to work, let's add a type in ZModel to define the shape of `auth()`:
116+
117+
```tsx
118+
type Auth {
119+
userId String @id
120+
organizationId String?
121+
organizationRole String?
122+
123+
@@auth
124+
}
125+
```
126+
127+
Now you can access the organization information in policy rules:
128+
129+
```tsx
130+
model Todo {
131+
...
132+
organization Organization? @relation(fields: [organizationId], references: [id], onDelete: Cascade)
133+
organizationId String? @default(auth().organizationId)
134+
135+
// deny access that don't belong to the user's active organization
136+
@@deny('all', auth().organizationId != organizationId)
137+
138+
// full access to: list owner, org owner, and org admins
139+
@@allow('all',
140+
auth().userId == ownerId ||
141+
auth().organizationRole == 'owner' ||
142+
auth().organizationRole == 'admin')
143+
}
144+
```
145+
146+
## Sample project
147+
148+
Here is a fully working multi-tenant sample project using better-auth, ZenStack v3, and Next.js:
149+
150+
[https://github.com/ymc9/better-auth-zenstack-multitenancy/tree/zenstack-v3](https://github.com/ymc9/better-auth-zenstack-multitenancy/tree/zenstack-v3)

versioned_docs/version-3.x/recipe/postgres-multi-schema.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
sidebar_position: 1
2+
sidebar_position: 2
33
---
44

55
# Working With PostgreSQL Schemas

versioned_docs/version-3.x/reference/plugins/prisma.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ Please note that ZenStack's ORM runtime doesn't depend on Prisma, so you don't n
1212

1313
## Options
1414

15-
- `output`: Specifies the path of the generated Prisma schema file. If a relative path is provided, it will be resolved relative to the ZModel schema.
15+
- `output`
16+
17+
Optional string. Specifies the path of the generated Prisma schema file. If a relative path is provided, it will be resolved relative to the ZModel schema. Defaults to the same directory as the ZModel schema.
1618

1719
## Example
1820

versioned_docs/version-3.x/reference/plugins/typescript.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,21 @@ The `@core/typescript` plugin generates TypeScript code from ZModel. The generat
1212

1313
## Options
1414

15-
- `output`: Specifies the output directory for the generated TypeScript code. If a relative path is provided, it will be resolved relative to the ZModel schema.
15+
- `output`
16+
17+
Optional string. Specifies the output directory for the generated TypeScript code. If a relative path is provided, it will be resolved relative to the ZModel schema. Defaults to the same directory as the ZModel schema.
18+
19+
- `lite`
20+
21+
Optional boolean. If set to `true`, the plugin will generate a lite version of schema file "schema-lite.ts" with attributes removed, along side with the full schema. The lite schema is suited to be used in frontend code like with the `@zenstackhq/tanstack-query` library. Defaults to `false`.
22+
23+
- `liteOnly`
24+
25+
Optional boolean. If set to `true`, the plugin will only generate the lite version of schema file "schema-lite.ts" with attributes removed, and skip generating the full schema. The lite schema is suited to be used in frontend code like with the `@zenstackhq/tanstack-query` library. Defaults to `false`.
26+
27+
- `importWithFileExtension`
28+
29+
Optional string. Used to control the `import` statements in the generated code. If set to a string value like ".js", the generated code will import from local modules with the specified file extension. This option is useful in ESM projects with certain TypeScript `moduleResolution` mode.
1630

1731
## Output
1832

versioned_docs/version-3.x/reference/zmodel/datasource.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,30 @@ datasource NAME {
2121

2222
- **`provider`**:
2323

24-
Name of database connector. Valid values:
24+
Required. Name of database connector. Valid values:
2525

2626
- sqlite
2727
- postgresql
2828

2929
- **`url`**:
3030

31-
Database connection string. Either a plain string or an invocation of `env` function to fetch from an environment variable. For SQLite provider, the URL should be a file protocol, like `file:./dev.db`. For PostgreSQL provider, it should be a postgres connection string, like `postgresql://user:password@localhost:5432/dbname`.
31+
Optional. Database connection string. Either a plain string or an invocation of `env` function to fetch from an environment variable. For SQLite provider, the URL should be a file protocol, like `file:./dev.db`. For PostgreSQL provider, it should be a postgres connection string, like `postgresql://user:password@localhost:5432/dbname`.
3232

3333
The `url` option is only used by the migration engine to connect to the database. The ORM runtime doesn't rely on it. Instead, you provide the connection information when constructing an ORM client.
3434

35+
- **`directUrl`**:
36+
37+
Optional. Connection URL for direct connection to the database.
38+
39+
If you use a connection pooler URL in the url argument, Prisma CLI commands that require a direct connection to the database use the URL in the directUrl argument. This option is passed through to Prisma Migrate for database migrations.
40+
3541
- **`defaultSchema`**:
3642

37-
(PostgreSQL only) The default schema to use for models that don't have an explicit `@@schema` attribute. Defaults to "public". See [Working With PostgreSQL Schemas](../../recipe/postgres-multi-schema.md) for more details.
43+
Optional. (PostgreSQL only) The default schema to use for models that don't have an explicit `@@schema` attribute. Defaults to "public". See [Working With PostgreSQL Schemas](../../recipe/postgres-multi-schema.md) for more details.
3844

3945
- **`schemas`**:
4046

41-
(PostgreSQL only) List of schemas to use. If specified, you can use the `@@schema` attribute to specify the schema name for a model. See [Working With PostgreSQL Schemas](../../recipe/postgres-multi-schema.md) for more details.
47+
Optional. (PostgreSQL only) List of schemas to use. If specified, you can use the `@@schema` attribute to specify the schema name for a model. See [Working With PostgreSQL Schemas](../../recipe/postgres-multi-schema.md) for more details.
4248

4349
## Example
4450

0 commit comments

Comments
 (0)