This commit is contained in:
2025-10-05 13:50:18 +02:00
commit 41f083d69e
71 changed files with 17398 additions and 0 deletions

21
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

4
doc/.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}

11
doc/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}

13
doc/CHANGELOG.md Normal file
View File

@@ -0,0 +1,13 @@
# doc
## 0.1.0
### Minor Changes
- remove "cache" option for "helpersFrom" and replace it with "fetch" to allow a more generic custom fetch and remove "@11ty/eleventy-fetch" dependency
## 0.0.2
### Patch Changes
- update packages

55
doc/README.md Normal file
View File

@@ -0,0 +1,55 @@
# Starlight Starter Kit: Basics
[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)
```
npm create astro@latest -- --template starlight
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/withastro/starlight&create_from_path=examples/basics)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwithastro%2Fstarlight%2Ftree%2Fmain%2Fexamples%2Fbasics&project-name=my-starlight-docs&repository-name=my-starlight-docs)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro + Starlight project, you'll see the following folders and files:
```
.
├── public/
├── src/
│ ├── assets/
│ ├── content/
│ │ ├── docs/
│ │ └── config.ts
│ └── env.d.ts
├── astro.config.mjs
├── package.json
└── tsconfig.json
```
Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
Images can be added to `src/assets/` and embedded in Markdown with a relative link.
Static assets, like favicons, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Check out [Starlights docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).

29
doc/astro.config.mjs Normal file
View File

@@ -0,0 +1,29 @@
// @ts-check
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
// https://astro.build/config
export default defineConfig({
integrations: [
starlight({
title: "Zod PocketBase",
social: {
github: "https://github.com/gbouteiller/zod-pocketbase",
},
sidebar: [
{
label: "Start here",
autogenerate: { directory: "start-here" },
},
{
label: "Guides",
autogenerate: { directory: "guides" },
},
{
label: "Reference",
autogenerate: { directory: "reference" },
},
],
}),
],
});

19
doc/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "doc",
"type": "module",
"version": "0.1.0",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/starlight": "^0.30.3",
"astro": "^5.1.1",
"sharp": "^0.33.5",
"typescript": "^5.7.2"
}
}

5217
doc/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

1
doc/public/favicon.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path fill-rule="evenodd" d="M81 36 64 0 47 36l-1 2-9-10a6 6 0 0 0-9 9l10 10h-2L0 64l36 17h2L28 91a6 6 0 1 0 9 9l9-10 1 2 17 36 17-36v-2l9 10a6 6 0 1 0 9-9l-9-9 2-1 36-17-36-17-2-1 9-9a6 6 0 1 0-9-9l-9 10v-2Zm-17 2-2 5c-4 8-11 15-19 19l-5 2 5 2c8 4 15 11 19 19l2 5 2-5c4-8 11-15 19-19l5-2-5-2c-8-4-15-11-19-19l-2-5Z" clip-rule="evenodd"/><path d="M118 19a6 6 0 0 0-9-9l-3 3a6 6 0 1 0 9 9l3-3Zm-96 4c-2 2-6 2-9 0l-3-3a6 6 0 1 1 9-9l3 3c3 2 3 6 0 9Zm0 82c-2-2-6-2-9 0l-3 3a6 6 0 1 0 9 9l3-3c3-2 3-6 0-9Zm96 4a6 6 0 0 1-9 9l-3-3a6 6 0 1 1 9-9l3 3Z"/><style>path{fill:#000}@media (prefers-color-scheme:dark){path{fill:#fff}}</style></svg>

After

Width:  |  Height:  |  Size: 696 B

BIN
doc/src/assets/cli.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
doc/src/assets/houston.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -0,0 +1,6 @@
import { defineCollection } from 'astro:content';
import { docsSchema } from '@astrojs/starlight/schema';
export const collections = {
docs: defineCollection({ schema: docsSchema() }),
};

View File

@@ -0,0 +1,71 @@
---
title: CLI
description: The CLI generates Zod schemas for your PocketBase instance.
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
import cliImage from '../../../assets/cli.png';
The CLI generates Zod schemas for your PocketBase instance.
## Usage
To generate your schemas, run the following from your project directory:
<Tabs>
<TabItem label="npm">
```shell
npx zod-pocketbase
```
</TabItem>
<TabItem label="pnpm">
```shell
pnpm zod-pocketbase
```
</TabItem>
<TabItem label="yarn">
```shell
yarn zod-pocketbase
```
</TabItem>
</Tabs>
<Image src={cliImage} alt="Zod PocketBase CLI." />
## Config File
You can provide a `zod-pocketbase.config.ts` or `zod-pocketbase.config.js` config file.
```ts title="zod-pocketbase.config.ts"
import type { Config } from "zod-pocketbase";
export default {
// default values
adminEmail: undefined,
adminPassword: undefined,
ignore: [],
nameEnum: (name: string) => snakeCase(name).toUpperCase(),
nameEnumField: (collectionName: string, fieldName: string) => `${collectionName}${pascalCase(fieldName)}`,
nameEnumSchema: (name: string) => pascalCase(name),
nameEnumType: (name: string) => pascalCase(name),
nameEnumValues: (name: string) => `${name}Values`,
nameRecordSchema: (name: string) => `${pascalCase(name)}Record`,
nameRecordType: (name: string) => `${pascalCase(name)}Record`,
output: "./zod-pocketbase.ts",
url: undefined,
} satisfies Config;
```
:::tip[For more details]
See the [reference](/reference/config).
:::
## Environment variables
You can provide your admin credentials and your **PocketBase** instance url as environment variables:
```shell
ZOD_POCKETBASE_ADMIN_EMAIL="admin@mydomain.com"
ZOD_POCKETBASE_ADMIN_PASSWORD="mypassword"
ZOD_POCKETBASE_URL="https://myproject.pockethost.io"
```

View File

@@ -0,0 +1,52 @@
---
title: Helpers
description: Helpers are syntactic sugar to get records from your PocketBase instance.
---
Helpers are syntactic sugar to get records from your PocketBase instance. In addition to simplifying the process of fetching records, they also provide type safety, autocompletion and caching.
To access helpers, you have to, at least, provide an instance of PocketBase SDK to the `helpersFrom` function.
```ts
import Fetch from "@11ty/eleventy-fetch";
import { helpersFrom } from "zod-pocketbase";
import Pocketbase from "pocketbase";
const { getRecord, getRecords } = helpersFrom({
pocketbase: new Pocketbase(import.meta.env.ZOD_POCKETBASE_URL),
fetch: async (url, fetchOptions) => {
const { body, ...init } = await Fetch(url, { fetchOptions, returnType: "response", type: "json" });
return new Response(JSON.stringify(body), init);
},
});
```
## getRecord
`getRecord` is a helper to get a single record from your PocketBase instance. It takes a [RecordRef](/reference/types#recordref) as its first argument and an object with a schema as its second argument.
```ts
const myFirstPost = await getRecord({ collection: "posts", slug: "my-first-post" }, { schema: PostRecord });
const mySecondPost = await getRecord({ collection: "posts", id: "3vwc4g9d23orc1r" }, { schema: PostRecord });
```
:::tip[For more details]
See the [reference](/reference/methods#getrecord).
:::
## getRecords
`getRecords` is a helper to get multiple records from your PocketBase instance. It takes a collection name as its first argument and an object with some options (at least a record schema) as its second argument.
```ts
const { items: myPosts } = await getRecords("posts", { schema: PostRecord });
const { items: someSpecificPosts } = await getRecords("posts", { schema: PostRecord, sort: "-updated", page: 2, perPage: 10 });
```
:::caution
The provided schema is only for a record. The method returns a [RecordsList](/reference/types/#recordslist) object.
:::
:::tip[For more details]
See the [reference](/reference/methods#getrecords).
:::

View File

@@ -0,0 +1,121 @@
---
title: Schemas
description: How to secure and simplify schemas for your PocketBase instance.
---
Here you can find how to secure and simplify schemas for your PocketBase instance:
1. with the CLI generated schemas
2. with the `expand` method
3. with the `pick` method
4. with the `select` method
## 0 - A Zod schema for a Post collection
Here is the original schema for a `Post` collection:
```ts
const Post = z
.object({
content: z.string(),
expand: z.object({
author: z
.object({
name: z.string(),
expand: z.object({
image: z.object({
alt: z.string(),
src: z.string(),
}),
}),
})
.transform(({ expand, ...rest }) => ({ ...rest, ...expand })),
image: z.object({
alt: z.string(),
src: z.string(),
}),
}),
title: z.string(),
updated: z.coerce.date(),
})
.transform(({ expand, ...rest }) => ({ ...rest, ...expand }));
```
## 1 - With CLI generated schema
All schemas are generated from your PocketBase.
```ts
import {AuthorRecord, ImageRecord, PostRecord} from "./schemas";
const Post = PostRecord.pick({ content: true, title: true, updated: true })
.extend({
expand: z.object({
author: AuthorRecord.pick({ name: true })
.extend({
expand: z.object({
image: ImageRecord.pick({ alt: true, src: true }),
}),
})
.transform(({ expand, ...rest }) => ({ ...rest, ...expand })),
image: ImageRecord.pick({ alt: true, src: true }),
}),
})
.transform(({ expand, ...rest }) => ({ ...rest, ...expand }));
```
## 2 - With pick
`pick` is a syntactic sugar for native zod `pick`.
```ts
import { pick } from "zod-pocketbase";
import {AuthorRecord, ImageRecord, PostRecord} from "./schemas";
const Post = pick(PostRecord, ["content", "title", "updated"])
.extend({
expand: z.object({
author: pick(AuthorRecord, ["name"])
.extend({
expand: z.object({
image: pick(ImageRecord, ["alt", "src"]),
}),
})
.transform(({ expand, ...rest }) => ({ ...rest, ...expand })),
image: pick(ImageRecord, ["alt", "src"]),
}),
})
.transform(({ expand, ...rest }) => ({ ...rest, ...expand }));
```
## 3 - With expand
`expand` is a syntactic sugar for native zod `extend` on the property `expand` coupled with `transform`.
```ts
import { expand, pick } from "zod-pocketbase";
import {AuthorRecord, ImageRecord, PostRecord} from "./schemas";
const Post = expand(pick(PostRecord, ["content", "title", "updated"]), {
author: expand(pick(AuthorRecord, ["name"]), {
image: pick(ImageRecord, ["alt", "src"])
}),
image: pick(ImageRecord, ["alt", "src"])
});
```
## 4 - With select
`select` is the union of `pick` and `expand`.
```ts
import { select } from "zod-pocketbase";
import {AuthorRecord, ImageRecord, PostRecord} from "./schemas";
const Post = select(PostRecord, ["content", "title", "updated"], {
author: select(AuthorRecord, ["name"], {
image: select(ImageRecord, ["alt", "src"])
}),
image: select(ImageRecord, ["alt", "src"])
});
```

View File

@@ -0,0 +1,30 @@
---
title: Welcome to Zod PocketBase
description: This library adds Zod safety with ease to your PocketBase instance.
template: splash
hero:
tagline: Add Zod to PocketBase with ease!
image:
file: ../../assets/houston.webp
actions:
- text: Why this library?
link: /start-here/why/
icon: right-arrow
- text: View on GitHub
link: https://github.com/gbouteiller/zod-pocketbase
icon: external
variant: minimal
---
import { CardGrid, Card } from '@astrojs/starlight/components';
## Also check out...
<CardGrid stagger>
<Card title="Astro PocketBase" icon="puzzle">
Add [PocketBase to Astro](https://astro-pocketbase-five.vercel.app) with ease!
</Card>
<Card title="Astro Superforms" icon="puzzle">
Add [Superforms to Astro](https://astro-superforms.vercel.app) with ease!
</Card>
</CardGrid>

View File

@@ -0,0 +1,122 @@
---
title: Config
description: A reference for the Config file.
---
## ignore
- **Type:** `string[]`
- **Default:** `[]`
The `ignore` option allows you to ignore specific collections from being processed.
```ts
{
ignore: ["users"],
}
```
## adminEmail
- **Type:** `string`
- **Default:** `undefined`
`adminEmail` represents the email of an admin user of your PocketBase instance.
```ts
{
adminEmail: "admin@mydomain.com",
}
```
## adminPassword
- **Type:** `string`
- **Default:** `undefined`
`adminPassword` represents the password of the above admin user of your PocketBase instance.
```ts
{
adminPassword: "mypassword",
}
```
## nameEnum
- **Type:** `(enumFieldName: string) => string`
- **Default:** `(enumFieldName) => snakeCase(enumFieldName).toUpperCase()`
`nameEnum` is a function that takes an enum field name and returns the name of the generated enum.
## nameEnumField
- **Type:** `(collectionName: string, fieldName: string) => string`
- **Default:** `(collectionName, fieldName) => collectionName + pascalName(fieldName)`
`nameEnumField` is a function that takes a field name and its collection name and returns the name of the generated enum field.
## nameEnumSchema
- **Type:** `(enumFieldName: string) => string`
- **Default:** `(enumFieldName) => pascalName(enumFieldName)`
`nameEnumSchema` is a function that takes an enum field name and returns the name of the generated enum schema.
## nameEnumType
- **Type:** `(enumFieldName: string) => string`
- **Default:** `(enumFieldName) => pascalName(enumFieldName)`
`nameEnumType` is a function that takes an enum field name and returns the name of the generated enum type.
## nameEnumValues
- **Type:** `(enumFieldName: string) => string`
- **Default:** `(enumFieldName) => enumFieldName + "Values"`
`nameEnumValues` is a function that takes an enum field name and returns the name of the generated enum values.
## nameRecordSchema
- **Type:** `(collectionName: string) => string`
- **Default:** `(collectionName) => pascalName(collectionName) + "Record"`
`nameRecordSchema` is a function that takes a collection name and returns the name of the generated record schema.
## nameRecordType
- **Type:** `(collectionName: string) => string`
- **Default:** `(collectionName) => pascalName(collectionName) + "Record"`
`nameRecordType` is a function that takes a collection name and returns the name of the generated record type.
## output
- **Type:** `string`
- **Default:** `./zod-pocketbase.ts`
`output` represents the path of the generated file.
```ts
{
output: "./src/lib/pocketbase/schemas.ts",
}
```
:::caution
`output` must be a relative path.
:::
## url
- **Type:** `string`
- **Default:** `undefined`
`url` represents the url of your PocketBase instance.
```ts
{
url: "https://myproject.pockethost.io",
}
```

View File

@@ -0,0 +1,88 @@
---
title: Methods
description: A reference for the methods.
---
## helpersFrom
```ts
import { helpersFrom } from "zod-pocketbase";
const helpers = helpersFrom({ fetch, pocketbase });
```
The `helpersFrom` method returns an object with two methods: `getRecord` and `getRecords` described below.
### fetch
- **Type:** `(url: RequestInfo | URL, config?: RequestInit) => Promise<Response>`
Optional custom fetch function to use for sending the request.
### pocketbase
- **Required**
- **Type:** `TypedPocketbase`
The `pocketbase` parameter is a mandatory parameter that specifies a PocketBase instance.
## getRecord
```ts
const { getRecord } = helpersFrom({ pocketbase });
const record = await getRecord(reference, { schema });
```
The `getRecord` method returns a single record from your PocketBase instance.
### reference
- **Required**
- **Type:** [`RecordRef`](/reference/types#recordref)
### schema
- **Required**
- **Type:** [`AnyZodRecord`](/reference/types#anyzodrecord)
## getRecords
```ts
const { getRecords } = helpersFrom({ pocketbase });
const recordsList = await getRecords(collection, { filter, page, perPage, schema, skipTotal, sort });
```
The `getRecords` method returns a records list from your PocketBase instance.
### collection
- **Required**
- **Type:** `string`
### filter
- **Type:** `string`
### page
- **Type:** `number`
- **Default:** `1`
### perPage
- **Type:** `number`
- **Default:** `200`
### schema
- **Required**
- **Type:** [`AnyZodRecord`](/reference/types#anyzodrecord)
### skipTotal
- **Type:** `boolean`
- **Default:** `true`
### sort
- **Type:** [`ZodRecordSort`](/reference/types#zodrecordsort)

View File

@@ -0,0 +1,80 @@
---
title: Types
description: A reference for the types.
---
## RecordIdRef
`RecordIdRef` represents a reference to a record in a collection by its `id` and its `collection` name.
```ts
type RecordIdRef<C extends string> = { collection: C; id: string };
```
## RecordSlugRef
`RecordSlugRef` represents a reference to a record in a collection by its `slug` and its `collection` name.
```ts
type RecordSlugRef<C extends string> = { collection: C; slug: string };
```
:::tip[What is slug?]
`slug` is not a default field of a collection but it can be used as another unique identifier for a record more readble than its `id`.
:::
## RecordRef
`RecordRef` represents either a `RecordIdRef` or a `RecordSlugRef`.
```ts
type RecordRef<C extends string> = RecordIdRef<C> | RecordSlugRef<C>;
```
## RecordFullListOpts
```ts
type RecordFullListOpts<S extends AnyZodRecord> = RecordListOpts<S> & { batch?: number };
```
## RecordListOpts
```ts
type RecordListOpts<S extends AnyZodRecord> = {
filter?: string;
page?: number;
perPage?: number;
skipTotal?: boolean;
sort?: ZodRecordSort<S>;
};
```
## AnyZodRecord
`AnyZodRecord` represents the type for a record schema.
```ts
type AnyZodRecord = AnyZodObject | ZodEffects<AnyZodObject>;
```
## ZodRecordSort
`ZodRecordSort` represents the type for a record sort options.
```ts
export type ZodRecordSort<S extends AnyZodRecord> = `${"+" | "-"}${ZodRecordMainKeys<S>}` | "@random";
```
## RecordsList
`RecordsList` represents the type for a records list.
```ts
export type RecordsList<S extends AnyZodRecord> = {
items: S["_output"][];
page: number;
perPage: number;
totalItems: number;
totalPages: number;
};
```

View File

@@ -0,0 +1,32 @@
---
title: Getting started
description: This library adds Zod safety with ease to your PocketBase instance.
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
This library adds Zod safety with ease to your PocketBase instance. It provides you with:
- a CLI to generate schemas for your selected collections
- methods to make pocketbase SDK typesafe
- helpers to simplify the way you fetch your collections
## Installation
To install `zod-pocketbase`, run the following from your project directory:
<Tabs>
<TabItem label="npm">
```shell
npm install zod-pocketbase
```
</TabItem>
<TabItem label="pnpm">
```shell
pnpm add zod-pocketbase
```
</TabItem>
<TabItem label="yarn">
```shell
yarn install zod-pocketbase
```
</TabItem>
</Tabs>

View File

@@ -0,0 +1,202 @@
---
title: Why this library?
description: A guide in my new Starlight docs site.
---
You want to get the last 10 updated posts from your PocketBase collection. So you start with...
## The PocketBase SDK
```ts
import PocketBase from "pocketbase";
import { z } from "zod";
const pocketbase = new PocketBase("https://my-pocketbase.com");
const options = {
sort: "-updated"
};
const { items: firstPosts } = await pocketbase.collection("posts").getList(1, 10, options);
```
Oops, you forgot to expand the `author` field because you don't want the author id but the author name. So you...
## Expand
```diff lang="ts"
import PocketBase from "pocketbase";
import { z } from "zod";
const pocketbase = new PocketBase("https://my-pocketbase.com");
const options = {
sort: "-updated",
+ expand: ["author"],
};
const { items: firstPosts } = await pocketbase.collection("posts").getList(1, 10, options);
```
Great, but now you want to validate the data you get from PocketBase because the rule is that you should not trust anything for the outer world.
You also just include the fields that you really need for your app and remove the ugly `expand` properties. So you add...
## A Zod Schema
```diff lang="ts"
import PocketBase from "pocketbase";
import { z } from "zod";
const pocketbase = new PocketBase("https://my-pocketbase.com");
+ const Post = z
+ .object({
+ content: z.string(),
+ expand: z.object({
+ author: z.object({
+ name: z.string(),
+ }),
+ }),
+ title: z.string(),
+ })
+ .transform(({ expand, ...rest }) => ({ ...rest, ...expand }));
const options = {
sort: "-updated",
expand: ["author"],
};
const { items } = await pocketbase.collection("posts").getList(1, 10, options);
+ const firstPosts = Post.array().parse(items);
```
Better, but even if you get your validated structured data now, you could reduce the size of the response from the server by adding...
## Fields
```diff lang="ts"
import PocketBase from "pocketbase";
import { z } from "zod";
const pocketbase = new PocketBase("https://my-pocketbase.com");
const Post = z
.object({
content: z.string(),
expand: z.object({
author: z.object({
name: z.string(),
}),
}),
title: z.string(),
})
.transform(({ expand, ...rest }) => ({ ...rest, ...expand }));
const options = {
sort: "-updated",
expand: ["author"],
+ fields: ["content", "expand.author.name", "title"],
};
const { items } = await pocketbase.collection("posts").getList(1, 10, options);
const firstPosts = Post.array().parse(items);
```
Cool! So what would you need Zod PocketBase for?
## Generated Schemas
```diff lang="ts"
import PocketBase from "pocketbase";
import { z } from "zod";
+ import { pick, select } from "zod-pocketbase";
+ import { AuthorRecord, PostRecord } from "./schemas";
const pocketbase = new PocketBase("https://my-pocketbase.com");
- const Post = z
- .object({
- content: z.string(),
- expand: z.object({
- author: z.object({
- name: z.string(),
- }),
- }),
- title: z.string(),
- })
- .transform(({ expand, ...rest }) => ({ ...rest, ...expand }));
+ const Post = PostRecord.pick({content: true, title: true }).extend({
+ expand: z.object({
+ author: AuthorRecord.pick({ name: true })
+ }),
+ }).transform(({ expand, ...rest }) => ({ ...rest, ...expand }));
/* Or, for the syntactic sugar addicts */
+ const Post = select(PostRecord, ["content", "title"], {
+ author: select(AuthorRecord, ["name"])
+ });
const options = {
sort: "-updated",
expand: ["author"],
fields: ["content", "expand.author.name", "title"],
};
const { items } = await pocketbase.collection("posts").getList(1, 10, options);
const firstPosts = Post.array().parse(items);
```
## Type-safe expand and fields options
```diff lang="ts"
import PocketBase from "pocketbase";
import { z } from "zod";
import { select } from "zod-pocketbase";
+ import { expandFrom, fieldsFrom, listOptionsFrom } from "zod-pocketbase";
import { AuthorRecord, PostRecord } from "./schemas";
const pocketbase = new PocketBase("https://my-pocketbase.com");
const Post = select(PostRecord, ["content", "title"], {
author: select(AuthorRecord, ["name"])
});
const options = {
sort: "-updated",
- expand: ["author"],
+ expand: expandFrom(Post),
- fields: ["content", "expand.author.name", "title"],
+ fields: fieldsFrom(Post),
};
/* Or, for the syntactic sugar addicts */
+ const options = listOptionsFrom(Post, { sort: "-updated" });
const { items } = await pocketbase.collection("posts").getList(1, 10, options);
const firstPosts = Post.array().parse(items);
```
## More sugar with helpers
```diff lang="ts"
import PocketBase from "pocketbase";
import { z } from "zod";
import { select } from "zod-pocketbase";
+ import { helpersFrom } from "zod-pocketbase";
import { AuthorRecord, PostRecord } from "./schemas";
const pocketbase = new PocketBase("https://my-pocketbase.com");
+ const { getRecords } = helpersFrom({ pocketbase });
const Post = select(PostRecord, ["content", "title"], {
author: select(AuthorRecord, ["name"])
});
- const options = optionsFrom(Post, { sort: "-updated" });
+ const options = { perPage: 10, schema: Post, sort: "-updated" };
- const { items } = await pocketbase.collection("posts").getList(1, 10, options);
- const firstPosts = Post.array().parse(items);
+ const { items: firstPosts } = getRecords("posts", options);
```

2
doc/src/env.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

3
doc/tsconfig.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strict"
}