From f462286ed35a63c0b1c8838e5d835826e3be5c4e Mon Sep 17 00:00:00 2001 From: David Plugge <59972093+david-plugge@users.noreply.github.com> Date: Tue, 6 Feb 2024 09:51:10 +0100 Subject: [PATCH] Custom client (#29) * custom client * fix incorrect name * pre-release * remove cjs build * add realtime support * expand can be undefined * add changesets * only expose supported types in subscribe options * fix sort param parsing * new version * update pocketbase * handle plural relations * new version * fix filters * fix filters * make password and passwordConfirm optional on update * allow deleting files by providing null as value * exit prerelease mode * correctly type empty select --- .changeset/afraid-eggs-fold.md | 5 + .changeset/brave-rabbits-scream.md | 5 + .changeset/cuddly-cherries-add.md | 5 + .changeset/cuddly-parrots-shout.md | 5 + .changeset/gentle-schools-flow.md | 5 + .changeset/gold-socks-wink.md | 5 + .changeset/honest-ants-rest.md | 5 + .changeset/pre.json | 19 ++ .changeset/sixty-hotels-complain.md | 5 + .changeset/smooth-insects-guess.md | 5 + .changeset/tough-books-smoke.md | 5 + .changeset/young-apes-brush.md | 5 + .vscode/settings.json | 3 - CHANGELOG.md | 50 +++ README.md | 208 +++++------- example/Database.d.ts | 253 ++++++++++---- example/index.ts | 105 +++--- package.json | 11 +- pnpm-lock.yaml | 507 ++++++++++++++++------------ src/client.ts | 334 ++++++++++++++++++ src/codegen/cli.ts | 2 +- src/codegen/index.ts | 411 +++++++++++++--------- src/filter.ts | 49 ++- src/index.ts | 39 +-- src/queryParams.ts | 193 ----------- src/record-service.ts | 93 ----- src/select.ts | 115 +++++++ src/sort.ts | 34 +- src/types.ts | 2 + tsup.config.ts | 2 +- 30 files changed, 1495 insertions(+), 990 deletions(-) create mode 100644 .changeset/afraid-eggs-fold.md create mode 100644 .changeset/brave-rabbits-scream.md create mode 100644 .changeset/cuddly-cherries-add.md create mode 100644 .changeset/cuddly-parrots-shout.md create mode 100644 .changeset/gentle-schools-flow.md create mode 100644 .changeset/gold-socks-wink.md create mode 100644 .changeset/honest-ants-rest.md create mode 100644 .changeset/pre.json create mode 100644 .changeset/sixty-hotels-complain.md create mode 100644 .changeset/smooth-insects-guess.md create mode 100644 .changeset/tough-books-smoke.md create mode 100644 .changeset/young-apes-brush.md delete mode 100644 .vscode/settings.json create mode 100644 src/client.ts delete mode 100644 src/queryParams.ts delete mode 100644 src/record-service.ts create mode 100644 src/select.ts diff --git a/.changeset/afraid-eggs-fold.md b/.changeset/afraid-eggs-fold.md new file mode 100644 index 0000000..3219479 --- /dev/null +++ b/.changeset/afraid-eggs-fold.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +fix sort param parsing diff --git a/.changeset/brave-rabbits-scream.md b/.changeset/brave-rabbits-scream.md new file mode 100644 index 0000000..d4164bd --- /dev/null +++ b/.changeset/brave-rabbits-scream.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +correctly type empty select diff --git a/.changeset/cuddly-cherries-add.md b/.changeset/cuddly-cherries-add.md new file mode 100644 index 0000000..2bf97c0 --- /dev/null +++ b/.changeset/cuddly-cherries-add.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +fix filters diff --git a/.changeset/cuddly-parrots-shout.md b/.changeset/cuddly-parrots-shout.md new file mode 100644 index 0000000..0c734e9 --- /dev/null +++ b/.changeset/cuddly-parrots-shout.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +realtime support diff --git a/.changeset/gentle-schools-flow.md b/.changeset/gentle-schools-flow.md new file mode 100644 index 0000000..55f8306 --- /dev/null +++ b/.changeset/gentle-schools-flow.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +remove cjs bundle diff --git a/.changeset/gold-socks-wink.md b/.changeset/gold-socks-wink.md new file mode 100644 index 0000000..b894644 --- /dev/null +++ b/.changeset/gold-socks-wink.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +only expose supported types for subscribe options diff --git a/.changeset/honest-ants-rest.md b/.changeset/honest-ants-rest.md new file mode 100644 index 0000000..42bcabb --- /dev/null +++ b/.changeset/honest-ants-rest.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": minor +--- + +custom client diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000..b116a8d --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,19 @@ +{ + "mode": "exit", + "tag": "pre", + "initialVersions": { + "typed-pocketbase": "0.0.9" + }, + "changesets": [ + "afraid-eggs-fold", + "cuddly-cherries-add", + "cuddly-parrots-shout", + "gentle-schools-flow", + "gold-socks-wink", + "honest-ants-rest", + "sixty-hotels-complain", + "smooth-insects-guess", + "tough-books-smoke", + "young-apes-brush" + ] +} diff --git a/.changeset/sixty-hotels-complain.md b/.changeset/sixty-hotels-complain.md new file mode 100644 index 0000000..89d8660 --- /dev/null +++ b/.changeset/sixty-hotels-complain.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +account for plural relations diff --git a/.changeset/smooth-insects-guess.md b/.changeset/smooth-insects-guess.md new file mode 100644 index 0000000..fdcb03d --- /dev/null +++ b/.changeset/smooth-insects-guess.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +allow deleting files by providing null as value diff --git a/.changeset/tough-books-smoke.md b/.changeset/tough-books-smoke.md new file mode 100644 index 0000000..2933a82 --- /dev/null +++ b/.changeset/tough-books-smoke.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +make password and passwordConfirm optional on update diff --git a/.changeset/young-apes-brush.md b/.changeset/young-apes-brush.md new file mode 100644 index 0000000..1d717d6 --- /dev/null +++ b/.changeset/young-apes-brush.md @@ -0,0 +1,5 @@ +--- +"typed-pocketbase": patch +--- + +expand can be undefined diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b7047d4..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "prettier.prettierPath": "./node_modules/prettier" -} diff --git a/CHANGELOG.md b/CHANGELOG.md index 062f051..40547be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,55 @@ # typed-pocketbase +## 0.1.0-pre.7 + +### Patch Changes + +- allow deleting files by providing null as value + +## 0.1.0-pre.6 + +### Patch Changes + +- make password and passwordConfirm optional on update + +## 0.1.0-pre.5 + +### Patch Changes + +- fix filters + +## 0.1.0-pre.4 + +### Patch Changes + +- account for plural relations + +## 0.1.0-pre.3 + +### Patch Changes + +- fix sort param parsing + +## 0.1.0-pre.2 + +### Patch Changes + +- only expose supported types for subscribe options + +## 0.1.0-pre.1 + +### Patch Changes + +- realtime support +- remove cjs bundle +- expand can be undefined + +## 0.1.0-pre.0 + +### Minor Changes + +- custom client + ## 0.0.9 ### Patch Changes diff --git a/README.md b/README.md index 52d560a..9f4629e 100644 --- a/README.md +++ b/README.md @@ -36,49 +36,44 @@ import PocketBase from 'pocketbase'; import { TypedPocketBase } from 'typed-pocketbase'; import { Schema } from './Database'; -const db = new PocketBase('http://localhost:8090') as TypedPocketBase; +const db = new TypedPocketBase('http://localhost:8090'); ``` Enjoy full type-safety: ```ts -import { createOptions, neq, sort } from 'typed-pocketbase'; +import { neq } from 'typed-pocketbase'; -db.collection('posts').getList(1, 10, createOptions({ +db.from('posts').getFullList({ select: { id: true, title: true, - content: true + content: true, + expand: { + owner: { + username: true + } + } } sort: '-date', filter: neq('content', '') -})); +}); ``` -Supported methods - -- getFullList -- getList -- getFirstListItem -- getOne -- create -- update -- subscribe - ## Selecting fields ```ts import { createOptions } from 'typed-pocketbase'; -db.collection('posts').getFullList( - createOptions({ - select: { - id: showId, - title: true, - content: true - } - }) -); +const showId = Math.random() < 0.5; + +db.from('posts').getFullList({ + select: { + id: showId, + title: true, + content: true + } +}); ``` ## Filtering columns @@ -86,60 +81,46 @@ db.collection('posts').getFullList( Use the `and`, `or` and other utility functions to filter rows: ```ts -import { createOptions, and, or, eq } from 'typed-pocketbase'; +import { and, or, eq, gte, lt } from 'typed-pocketbase'; // get all posts created in 2022 -db.collection('posts').getFullList( - createOptions({ - // a "manual" filter is a tuple of length 3 - filter: and(['date', '<', '2023-01-01'], ['data', '>=', '2022-01-01']) - }) -); +db.from('posts').getFullList({ + // a "manual" filter is a tuple of length 3 + filter: and(['date', '<', '2023-01-01'], ['data', '>=', '2022-01-01']) +}); // get all posts expect for those created in 2022 -db.collection('posts').getFullList( - createOptions({ - filter: or(['date', '>=', '2023-01-01'], ['data', '<', '2022-01-01']) - }) -); +db.from('posts').getFullList({ + filter: or(['date', '>=', '2023-01-01'], ['data', '<', '2022-01-01']) +}); // get all posts that were create at '2023-01-01' -db.collection('posts').getFullList( - createOptions({ - filter: eq('date', '2023-01-01') - }) -); +db.from('posts').getFullList({ filter: eq('date', '2023-01-01') }); // combine or/and with helpers and manual filters -db.collection('posts').getFullList( - createOptions({ - filter: or( - // - ['date', '>=', '2023-01-01'], - lt('date', '2022-01-01') - ) - }) -); +db.from('posts').getFullList({ + filter: or( + // + ['date', '>=', '2023-01-01'], + lt('date', '2022-01-01') + ) +}); // conditionally filter rows // falsy values are excluded -db.collection('posts').getFullList( - createOptions({ - filter: and( - // - gte('date', '2022-01-01'), - !untilNow && lt('date', '2023-01-01') - ) - }) -); +db.from('posts').getFullList({ + filter: and( + // + gte('date', '2022-01-01'), + !untilNow && lt('date', '2023-01-01') + ) +}); // filter for columns in relations // works up to 6 levels deep, including the top level -db.collection('posts').getFullList( - createOptions({ - filter: eq('owner.name', 'me') - }) -); +db.from('posts').getFullList({ + filter: eq('owner.name', 'me') +}); ``` Most filter operators are available as short hand function. @@ -148,51 +129,22 @@ Visit the [pocketbase documentation](https://pocketbase.io/docs/api-records/) to ## Sorting rows -Use `sort`, `asc` and `desc` to sort the rows: - ```ts -import { createOptions, sort, asc, desc } from 'typed-pocketbase'; - -db.collection('posts').getFullList( - createOptions({ - // sort by descending 'date' - sort: desc('date') - }) -); - -db.collection('posts').getFullList( - createOptions({ - // sort by descending 'date' and ascending 'title' - sort: sort('-date', '+title') - }) -); - -db.collection('posts').getFullList( - createOptions({ - // sort by descending 'date' and ascending 'title' - sort: sort(desc('date'), asc('title')) - }) -); - -// you can mix functions with +/- prefixes -db.collection('posts').getFullList( - createOptions({ - // sort by descending 'date' and ascending 'title' - sort: sort(desc('date'), '+title') - }) -); +db.from('posts').getFullList({ + // sort by descending 'date' + sort: '-date' +}); + +db.from('posts').getFullList({ + // sort by descending 'date' and ascending 'title' + sort: ['-date', '+title'] +}); // conditionally sort rows // falsy values are excluded -db.collection('posts').getFullList( - createOptions({ - sort: sort( - // - desc('date'), - sortTitle && asc('title') - ) - }) -); +db.from('posts').getFullList({ + sort: ['-date', sortTitle && '+title'] +}); ``` ## Expanding @@ -200,57 +152,53 @@ db.collection('posts').getFullList( The `createOptions` function automatically expands your models: ```ts -import { createOptions } from 'typed-pocketbase'; - -db.collection('posts').getFullList( - createOptions({ - $expand: { +db.from('posts').getFullList({ + select: { + expand: { user: true } - }) -); + } +}); // select nested columns -db.collection('posts').getFullList( - createOptions({ - $expand: { +db.from('posts').getFullList({ + select: { + expand: { user: { name: true avatar: true } } - }) -); + } +}); // nested expand -db.collection('posts').getFullList( - createOptions({ - $expand: { +db.from('posts').getFullList({ + select:{ + expand: { user: { - $expand: { + expand: { profile: true } } } - }) -); + } +}); ``` [Back relation expanding](https://pocketbase.io/docs/working-with-relations/#back-relation-expand) is support aswell: ```ts -import { createOptions } from 'typed-pocketbase'; - -db.collection('user').getFullList( - createOptions({ - $expand: { +db.from('user').getFullList({ + select: { + expand: { 'posts(user)': { title: true, created: true } } - }) -); + } +}); ``` ## License diff --git a/example/Database.d.ts b/example/Database.d.ts index c2e01a6..e46adba 100644 --- a/example/Database.d.ts +++ b/example/Database.d.ts @@ -3,24 +3,129 @@ */ // https://pocketbase.io/docs/collections/#base-collection -interface BaseCollectionRecord { +export interface BaseCollectionResponse { + /** + * 15 characters string to store as record ID. + */ id: string; + /** + * Date string representation for the creation date. + */ created: string; + /** + * Date string representation for the creation date. + */ updated: string; + /** + * The collection id. + */ collectionId: string; + /** + * The collection name. + */ collectionName: string; } +// https://pocketbase.io/docs/api-records/#create-record +export interface BaseCollectionCreate { + /** + * 15 characters string to store as record ID. + * If not set, it will be auto generated. + */ + id?: string; +} + +// https://pocketbase.io/docs/api-records/#update-record +export interface BaseCollectionUpdate {} + // https://pocketbase.io/docs/collections/#auth-collection -interface AuthCollectionRecord extends BaseCollectionRecord { +export interface AuthCollectionResponse extends BaseCollectionResponse { + /** + * The username of the auth record. + */ username: string; + /** + * Auth record email address. + */ email: string; + /** + * Whether to show/hide the auth record email when fetching the record data. + */ emailVisibility: boolean; + /** + * Indicates whether the auth record is verified or not. + */ verified: boolean; } +// https://pocketbase.io/docs/api-records/#create-record +export interface AuthCollectionCreate extends BaseCollectionCreate { + /** + * The username of the auth record. + * If not set, it will be auto generated. + */ + username?: string; + /** + * Auth record email address. + */ + email?: string; + /** + * Whether to show/hide the auth record email when fetching the record data. + */ + emailVisibility?: boolean; + /** + * Auth record password. + */ + password: string; + /** + * Auth record password confirmation. + */ + passwordConfirm: string; + /** + * Indicates whether the auth record is verified or not. + * This field can be set only by admins or auth records with "Manage" access. + */ + verified?: boolean; +} + +// https://pocketbase.io/docs/api-records/#update-record +export interface AuthCollectionUpdate { + /** + * The username of the auth record. + */ + username?: string; + /** + * The auth record email address. + * This field can be updated only by admins or auth records with "Manage" access. + * Regular accounts can update their email by calling "Request email change". + */ + email?: string; + /** + * Whether to show/hide the auth record email when fetching the record data. + */ + emailVisibility?: boolean; + /** + * Old auth record password. + * This field is required only when changing the record password. Admins and auth records with "Manage" access can skip this field. + */ + oldPassword?: string; + /** + * New auth record password. + */ + password: string; + /** + * New auth record password confirmation. + */ + passwordConfirm: string; + /** + * Indicates whether the auth record is verified or not. + * This field can be set only by admins or auth records with "Manage" access. + */ + verified?: boolean; +} + // https://pocketbase.io/docs/collections/#view-collection -interface ViewCollectionRecord { +export interface ViewCollectionRecord { id: string; } @@ -30,20 +135,20 @@ type MaybeArray = T | T[]; // ===== users ===== -export interface UsersResponse extends AuthCollectionRecord { +export interface UsersResponse extends AuthCollectionResponse { collectionName: 'users'; - name?: string; - avatar?: string; + name: string; + avatar: string; } -export interface UsersCreate { +export interface UsersCreate extends AuthCollectionCreate { name?: string; - avatar?: string; + avatar?: File; } -export interface UsersUpdate { +export interface UsersUpdate extends AuthCollectionUpdate { name?: string; - avatar?: string; + avatar?: File; } export interface UsersCollection { @@ -54,70 +159,55 @@ export interface UsersCollection { create: UsersCreate; update: UsersUpdate; relations: { - 'posts(owner)': PostsCollection[]; + 'posts(owner)': PostsCollection; }; } -// ===== posts ===== +// ===== test2 ===== -export interface PostsResponse extends BaseCollectionRecord { - collectionName: 'posts'; - title: string; - content?: string; - published?: boolean; - owner?: string; - slug: string; - date?: string; +export interface Test2Response extends BaseCollectionResponse { + collectionName: 'test2'; + test: string; } -export interface PostsCreate { - title: string; - content?: string; - published?: boolean; - owner?: string; - slug: string; - date?: string | Date; +export interface Test2Create extends BaseCollectionCreate { + test?: string; } -export interface PostsUpdate { - title?: string; - content?: string; - published?: boolean; - owner?: string; - slug?: string; - date?: string | Date; +export interface Test2Update extends BaseCollectionUpdate { + test?: string; } -export interface PostsCollection { +export interface Test2Collection { type: 'base'; collectionId: string; - collectionName: 'posts'; - response: PostsResponse; - create: PostsCreate; - update: PostsUpdate; + collectionName: 'test2'; + response: Test2Response; + create: Test2Create; + update: Test2Update; relations: { - owner: UsersCollection; + 'test(relation)': TestCollection; }; } // ===== test ===== -export interface TestResponse extends BaseCollectionRecord { +export interface TestResponse extends BaseCollectionResponse { collectionName: 'test'; - test?: string; - editor?: string; - number?: number; - bool?: boolean; - email?: string; - url?: string; - date?: string; - select?: 'a' | 'b' | 'c' | 'd'; - file?: string; - relation?: string; - json?: any; + test: string; + editor: string; + number: number; + bool: boolean; + email: string; + url: string; + date: string; + select: '' | 'a' | 'b' | 'c' | 'd'; + file: string; + relation: string; + json: any; } -export interface TestCreate { +export interface TestCreate extends BaseCollectionCreate { test?: string; editor?: string; number?: number; @@ -125,13 +215,13 @@ export interface TestCreate { email?: string; url?: string | URL; date?: string | Date; - select?: 'a' | 'b' | 'c' | 'd'; - file?: string; + select?: '' | 'a' | 'b' | 'c' | 'd'; + file?: File; relation?: string; json?: any; } -export interface TestUpdate { +export interface TestUpdate extends BaseCollectionUpdate { test?: string; editor?: string; number?: number; @@ -141,8 +231,8 @@ export interface TestUpdate { email?: string; url?: string | URL; date?: string | Date; - select?: 'a' | 'b' | 'c' | 'd'; - file?: string; + select?: '' | 'a' | 'b' | 'c' | 'd'; + file?: File; relation?: string; json?: any; } @@ -159,30 +249,45 @@ export interface TestCollection { }; } -// ===== test2 ===== +// ===== posts ===== -export interface Test2Response extends BaseCollectionRecord { - collectionName: 'test2'; - test?: string; +export interface PostsResponse extends BaseCollectionResponse { + collectionName: 'posts'; + title: string; + content: string; + published: boolean; + owner: string; + slug: string; + date: string; } -export interface Test2Create { - test?: string; +export interface PostsCreate extends BaseCollectionCreate { + title: string; + content?: string; + published?: boolean; + owner?: string; + slug: string; + date?: string | Date; } -export interface Test2Update { - test?: string; +export interface PostsUpdate extends BaseCollectionUpdate { + title?: string; + content?: string; + published?: boolean; + owner?: string; + slug?: string; + date?: string | Date; } -export interface Test2Collection { +export interface PostsCollection { type: 'base'; collectionId: string; - collectionName: 'test2'; - response: Test2Response; - create: Test2Create; - update: Test2Update; + collectionName: 'posts'; + response: PostsResponse; + create: PostsCreate; + update: PostsUpdate; relations: { - 'test(relation)': TestCollection; + owner: UsersCollection; }; } @@ -190,7 +295,7 @@ export interface Test2Collection { export type Schema = { users: UsersCollection; - posts: PostsCollection; - test: TestCollection; test2: Test2Collection; + test: TestCollection; + posts: PostsCollection; }; diff --git a/example/index.ts b/example/index.ts index 3280d43..26ded83 100644 --- a/example/index.ts +++ b/example/index.ts @@ -1,63 +1,84 @@ -import PocketBase from 'pocketbase'; import { Schema } from './Database.js'; -import { TypedPocketBase, eq, asc } from '../src/index.js'; -import { createOptions } from '../src/queryParams.js'; +import { TypedPocketBase, eq, or } from '../src/index.js'; -const db = new PocketBase('http://localhost:8090') as TypedPocketBase; +const db = new TypedPocketBase('http://localhost:8090'); await db.admins.authWithPassword('admin@example.com', 'secretpassword'); { - const posts = await db.collection('posts').getFullList( - createOptions({ - select: { - id: true, - title: true, - slug: true, - content: true, - $expand: { - owner: { - $expand: { - 'posts(owner)': { - owner: true - } - } + const posts = await db.from('posts').getFullList({ + select: { + id: true, + title: true, + slug: true, + content: true, + expand: { + owner: { + expand: { + 'posts(owner)': true } } - }, - sort: '+date', - filter: eq('published', true) - }) - ); + } + }, + sort: '+date', + filter: eq('published', true) + }); - console.log(posts); + console.log(posts[0].expand); } { - const posts = await db.collection('posts').getFullList( - createOptions({ - select: { - $expand: { - owner: true - } - }, - sort: asc('date'), - filter: eq('owner.email', 'user@test.com') - }) - ); + const posts = await db.from('posts').getFullList({ + select: { + expand: { + owner: true + } + }, + sort: '+date', + filter: eq('owner.email', 'user@test.com') + }); - console.log(posts[0].expand.owner); + console.log(posts[0].expand); } { - const post = await db.collection('posts').getFirstListItem( - eq('owner.email', 'user@test.com'), - createOptions({ + const post = await db + .from('posts') + .getFirstListItem(eq('owner.email', 'user@test.com'), { select: { - $expand: { + expand: { owner: true } } - }) - ); + }); console.log(post); } + +{ + const sort = db.from('posts').createSort('+id'); + + const filter = db + .from('posts') + .createFilter(or(eq('content', 'bla'), eq('published', true))); + + const select = db.from('posts').createSelect({ + id: true, + content: true, + owner: true, + collectionName: true, + asd: true, + expand: { + owner: { + username: true, + email: true + } + } + }); + + const posts = await db.from('posts').getFullList({ + filter, + select, + sort + }); + + console.log(posts); +} diff --git a/package.json b/package.json index 38d3ad8..7987586 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typed-pocketbase", - "version": "0.0.9", + "version": "0.1.0-pre.7", "description": "Add types to the PocketBase JavaScript SDK", "author": "David Plugge", "repository": { @@ -17,7 +17,6 @@ "src" ], "type": "module", - "main": "./dist/client/index.cjs", "module": "./dist/client/index.js", "types": "./dist/client/index.d.ts", "bin": { @@ -31,16 +30,16 @@ "ci:release": "changeset publish" }, "peerDependencies": { - "pocketbase": "^0.20.0" + "pocketbase": "^0.21.0" }, "dependencies": { "sade": "^1.8.1" }, "devDependencies": { "@changesets/cli": "^2.27.1", - "@types/node": "^20.10.4", - "pocketbase": "^0.20.1", - "prettier": "^3.1.1", + "@types/node": "^20.11.13", + "pocketbase": "^0.21.0", + "prettier": "^3.2.4", "tsup": "^8.0.1", "typescript": "^5.3.3" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b93bbc0..b969975 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,14 +14,14 @@ devDependencies: specifier: ^2.27.1 version: 2.27.1 '@types/node': - specifier: ^20.10.4 - version: 20.10.4 + specifier: ^20.11.13 + version: 20.11.13 pocketbase: - specifier: ^0.20.1 - version: 0.20.1 + specifier: ^0.21.0 + version: 0.21.1 prettier: - specifier: ^3.1.1 - version: 3.1.1 + specifier: ^3.2.4 + version: 3.2.4 tsup: specifier: ^8.0.1 version: 8.0.1(typescript@5.3.3) @@ -53,17 +53,17 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/runtime@7.23.6: - resolution: {integrity: sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==} + /@babel/runtime@7.23.9: + resolution: {integrity: sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==} engines: {node: '>=6.9.0'} dependencies: - regenerator-runtime: 0.14.0 + regenerator-runtime: 0.14.1 dev: true /@changesets/apply-release-plan@7.0.0: resolution: {integrity: sha512-vfi69JR416qC9hWmFGSxj7N6wA5J222XNBmezSVATPWDVPIF7gkd4d8CpbEbXmRWbVrkoli3oerGS6dcL/BGsQ==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/config': 3.0.0 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.0 @@ -81,7 +81,7 @@ packages: /@changesets/assemble-release-plan@6.0.0: resolution: {integrity: sha512-4QG7NuisAjisbW4hkLCmGW2lRYdPrKzro+fCtZaILX+3zdUELSvYjpL4GTv0E4aM9Mef3PuIQp89VmHJ4y2bfw==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.0.0 '@changesets/types': 6.0.0 @@ -99,7 +99,7 @@ packages: resolution: {integrity: sha512-iJ91xlvRnnrJnELTp4eJJEOPjgpF3NOh4qeQehM6Ugiz9gJPRZ2t+TsXun6E3AMN4hScZKjqVXl0TX+C7AB3ZQ==} hasBin: true dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/apply-release-plan': 7.0.0 '@changesets/assemble-release-plan': 6.0.0 '@changesets/changelog-git': 0.2.0 @@ -164,7 +164,7 @@ packages: /@changesets/get-release-plan@4.0.0: resolution: {integrity: sha512-9L9xCUeD/Tb6L/oKmpm8nyzsOzhdNBBbt/ZNcjynbHC07WW4E1eX8NMGC5g5SbM5z/V+MOrYsJ4lRW41GCbg3w==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/assemble-release-plan': 6.0.0 '@changesets/config': 3.0.0 '@changesets/pre': 2.0.0 @@ -180,7 +180,7 @@ packages: /@changesets/git@3.0.0: resolution: {integrity: sha512-vvhnZDHe2eiBNRFHEgMiGd2CT+164dfYyrJDhwwxTVD/OW0FUD6G7+4DIx1dNwkwjHyzisxGAU96q0sVNBns0w==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -205,7 +205,7 @@ packages: /@changesets/pre@2.0.0: resolution: {integrity: sha512-HLTNYX/A4jZxc+Sq8D1AMBsv+1qD6rmmJtjsCJa/9MSRybdxh0mjbTvE6JYZQ/ZiQ0mMlDOlGPXTm9KLTU3jyw==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -215,7 +215,7 @@ packages: /@changesets/read@0.6.0: resolution: {integrity: sha512-ZypqX8+/im1Fm98K4YcZtmLKgjs1kDQ5zHpc2U1qdtNBmZZfo/IBiG162RoP0CUF05tvp2y4IspH11PLnPxuuw==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/git': 3.0.0 '@changesets/logger': 0.1.0 '@changesets/parse': 0.4.0 @@ -236,15 +236,24 @@ packages: /@changesets/write@0.3.0: resolution: {integrity: sha512-slGLb21fxZVUYbyea+94uFiD6ntQW0M2hIKNznFizDhZPDgn2c/fv1UzzlW43RVzh1BEDuIqW6hzlJ1OflNmcw==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/types': 6.0.0 fs-extra: 7.0.1 human-id: 1.0.2 prettier: 2.8.8 dev: true - /@esbuild/android-arm64@0.19.9: - resolution: {integrity: sha512-q4cR+6ZD0938R19MyEW3jEsMzbb/1rulLXiNAJQADD/XYp7pT+rOS5JGxvpRW8dFDEfjW4wLgC/3FXIw4zYglQ==} + /@esbuild/aix-ppc64@0.19.12: + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.12: + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -252,8 +261,8 @@ packages: dev: true optional: true - /@esbuild/android-arm@0.19.9: - resolution: {integrity: sha512-jkYjjq7SdsWuNI6b5quymW0oC83NN5FdRPuCbs9HZ02mfVdAP8B8eeqLSYU3gb6OJEaY5CQabtTFbqBf26H3GA==} + /@esbuild/android-arm@0.19.12: + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -261,8 +270,8 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.19.9: - resolution: {integrity: sha512-KOqoPntWAH6ZxDwx1D6mRntIgZh9KodzgNOy5Ebt9ghzffOk9X2c1sPwtM9P+0eXbefnDhqYfkh5PLP5ULtWFA==} + /@esbuild/android-x64@0.19.12: + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -270,8 +279,8 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64@0.19.9: - resolution: {integrity: sha512-KBJ9S0AFyLVx2E5D8W0vExqRW01WqRtczUZ8NRu+Pi+87opZn5tL4Y0xT0mA4FtHctd0ZgwNoN639fUUGlNIWw==} + /@esbuild/darwin-arm64@0.19.12: + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -279,8 +288,8 @@ packages: dev: true optional: true - /@esbuild/darwin-x64@0.19.9: - resolution: {integrity: sha512-vE0VotmNTQaTdX0Q9dOHmMTao6ObjyPm58CHZr1UK7qpNleQyxlFlNCaHsHx6Uqv86VgPmR4o2wdNq3dP1qyDQ==} + /@esbuild/darwin-x64@0.19.12: + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -288,8 +297,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.19.9: - resolution: {integrity: sha512-uFQyd/o1IjiEk3rUHSwUKkqZwqdvuD8GevWF065eqgYfexcVkxh+IJgwTaGZVu59XczZGcN/YMh9uF1fWD8j1g==} + /@esbuild/freebsd-arm64@0.19.12: + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -297,8 +306,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-x64@0.19.9: - resolution: {integrity: sha512-WMLgWAtkdTbTu1AWacY7uoj/YtHthgqrqhf1OaEWnZb7PQgpt8eaA/F3LkV0E6K/Lc0cUr/uaVP/49iE4M4asA==} + /@esbuild/freebsd-x64@0.19.12: + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -306,8 +315,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm64@0.19.9: - resolution: {integrity: sha512-PiPblfe1BjK7WDAKR1Cr9O7VVPqVNpwFcPWgfn4xu0eMemzRp442hXyzF/fSwgrufI66FpHOEJk0yYdPInsmyQ==} + /@esbuild/linux-arm64@0.19.12: + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -315,8 +324,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm@0.19.9: - resolution: {integrity: sha512-C/ChPohUYoyUaqn1h17m/6yt6OB14hbXvT8EgM1ZWaiiTYz7nWZR0SYmMnB5BzQA4GXl3BgBO1l8MYqL/He3qw==} + /@esbuild/linux-arm@0.19.12: + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -324,8 +333,8 @@ packages: dev: true optional: true - /@esbuild/linux-ia32@0.19.9: - resolution: {integrity: sha512-f37i/0zE0MjDxijkPSQw1CO/7C27Eojqb+r3BbHVxMLkj8GCa78TrBZzvPyA/FNLUMzP3eyHCVkAopkKVja+6Q==} + /@esbuild/linux-ia32@0.19.12: + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -333,8 +342,8 @@ packages: dev: true optional: true - /@esbuild/linux-loong64@0.19.9: - resolution: {integrity: sha512-t6mN147pUIf3t6wUt3FeumoOTPfmv9Cc6DQlsVBpB7eCpLOqQDyWBP1ymXn1lDw4fNUSb/gBcKAmvTP49oIkaA==} + /@esbuild/linux-loong64@0.19.12: + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -342,8 +351,8 @@ packages: dev: true optional: true - /@esbuild/linux-mips64el@0.19.9: - resolution: {integrity: sha512-jg9fujJTNTQBuDXdmAg1eeJUL4Jds7BklOTkkH80ZgQIoCTdQrDaHYgbFZyeTq8zbY+axgptncko3v9p5hLZtw==} + /@esbuild/linux-mips64el@0.19.12: + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -351,8 +360,8 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.19.9: - resolution: {integrity: sha512-tkV0xUX0pUUgY4ha7z5BbDS85uI7ABw3V1d0RNTii7E9lbmV8Z37Pup2tsLV46SQWzjOeyDi1Q7Wx2+QM8WaCQ==} + /@esbuild/linux-ppc64@0.19.12: + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -360,8 +369,8 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.19.9: - resolution: {integrity: sha512-DfLp8dj91cufgPZDXr9p3FoR++m3ZJ6uIXsXrIvJdOjXVREtXuQCjfMfvmc3LScAVmLjcfloyVtpn43D56JFHg==} + /@esbuild/linux-riscv64@0.19.12: + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -369,8 +378,8 @@ packages: dev: true optional: true - /@esbuild/linux-s390x@0.19.9: - resolution: {integrity: sha512-zHbglfEdC88KMgCWpOl/zc6dDYJvWGLiUtmPRsr1OgCViu3z5GncvNVdf+6/56O2Ca8jUU+t1BW261V6kp8qdw==} + /@esbuild/linux-s390x@0.19.12: + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -378,8 +387,8 @@ packages: dev: true optional: true - /@esbuild/linux-x64@0.19.9: - resolution: {integrity: sha512-JUjpystGFFmNrEHQnIVG8hKwvA2DN5o7RqiO1CVX8EN/F/gkCjkUMgVn6hzScpwnJtl2mPR6I9XV1oW8k9O+0A==} + /@esbuild/linux-x64@0.19.12: + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -387,8 +396,8 @@ packages: dev: true optional: true - /@esbuild/netbsd-x64@0.19.9: - resolution: {integrity: sha512-GThgZPAwOBOsheA2RUlW5UeroRfESwMq/guy8uEe3wJlAOjpOXuSevLRd70NZ37ZrpO6RHGHgEHvPg1h3S1Jug==} + /@esbuild/netbsd-x64@0.19.12: + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -396,8 +405,8 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64@0.19.9: - resolution: {integrity: sha512-Ki6PlzppaFVbLnD8PtlVQfsYw4S9n3eQl87cqgeIw+O3sRr9IghpfSKY62mggdt1yCSZ8QWvTZ9jo9fjDSg9uw==} + /@esbuild/openbsd-x64@0.19.12: + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -405,8 +414,8 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.19.9: - resolution: {integrity: sha512-MLHj7k9hWh4y1ddkBpvRj2b9NCBhfgBt3VpWbHQnXRedVun/hC7sIyTGDGTfsGuXo4ebik2+3ShjcPbhtFwWDw==} + /@esbuild/sunos-x64@0.19.12: + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -414,8 +423,8 @@ packages: dev: true optional: true - /@esbuild/win32-arm64@0.19.9: - resolution: {integrity: sha512-GQoa6OrQ8G08guMFgeXPH7yE/8Dt0IfOGWJSfSH4uafwdC7rWwrfE6P9N8AtPGIjUzdo2+7bN8Xo3qC578olhg==} + /@esbuild/win32-arm64@0.19.12: + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -423,8 +432,8 @@ packages: dev: true optional: true - /@esbuild/win32-ia32@0.19.9: - resolution: {integrity: sha512-UOozV7Ntykvr5tSOlGCrqU3NBr3d8JqPes0QWN2WOXfvkWVGRajC+Ym0/Wj88fUgecUCLDdJPDF0Nna2UK3Qtg==} + /@esbuild/win32-ia32@0.19.12: + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -432,8 +441,8 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.19.9: - resolution: {integrity: sha512-oxoQgglOP7RH6iasDrhY+R/3cHrfwIDvRlT4CGChflq6twk8iENeVvMJjmvBb94Ik1Z+93iGO27err7w6l54GQ==} + /@esbuild/win32-x64@0.19.12: + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -441,13 +450,25 @@ packages: dev: true optional: true + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + dev: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.20 + '@jridgewell/trace-mapping': 0.3.22 dev: true /@jridgewell/resolve-uri@3.1.1: @@ -464,8 +485,8 @@ packages: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} dev: true - /@jridgewell/trace-mapping@0.3.20: - resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + /@jridgewell/trace-mapping@0.3.22: + resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 @@ -474,7 +495,7 @@ packages: /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 @@ -483,7 +504,7 @@ packages: /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.23.6 + '@babel/runtime': 7.23.9 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -509,113 +530,124 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.15.0 + fastq: 1.17.0 dev: true - /@rollup/rollup-android-arm-eabi@4.9.0: - resolution: {integrity: sha512-+1ge/xmaJpm1KVBuIH38Z94zj9fBD+hp+/5WLaHgyY8XLq1ibxk/zj6dTXaqM2cAbYKq8jYlhHd6k05If1W5xA==} + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm-eabi@4.9.6: + resolution: {integrity: sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.9.0: - resolution: {integrity: sha512-im6hUEyQ7ZfoZdNvtwgEJvBWZYauC9KVKq1w58LG2Zfz6zMd8gRrbN+xCVoqA2hv/v6fm9lp5LFGJ3za8EQH3A==} + /@rollup/rollup-android-arm64@4.9.6: + resolution: {integrity: sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.9.0: - resolution: {integrity: sha512-u7aTMskN6Dmg1lCT0QJ+tINRt+ntUrvVkhbPfFz4bCwRZvjItx2nJtwJnJRlKMMaQCHRjrNqHRDYvE4mBm3DlQ==} + /@rollup/rollup-darwin-arm64@4.9.6: + resolution: {integrity: sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.9.0: - resolution: {integrity: sha512-8FvEl3w2ExmpcOmX5RJD0yqXcVSOqAJJUJ29Lca29Ik+3zPS1yFimr2fr5JSZ4Z5gt8/d7WqycpgkX9nocijSw==} + /@rollup/rollup-darwin-x64@4.9.6: + resolution: {integrity: sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.9.0: - resolution: {integrity: sha512-lHoKYaRwd4gge+IpqJHCY+8Vc3hhdJfU6ukFnnrJasEBUvVlydP8PuwndbWfGkdgSvZhHfSEw6urrlBj0TSSfg==} + /@rollup/rollup-linux-arm-gnueabihf@4.9.6: + resolution: {integrity: sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.9.0: - resolution: {integrity: sha512-JbEPfhndYeWHfOSeh4DOFvNXrj7ls9S/2omijVsao+LBPTPayT1uKcK3dHW3MwDJ7KO11t9m2cVTqXnTKpeaiw==} + /@rollup/rollup-linux-arm64-gnu@4.9.6: + resolution: {integrity: sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.9.0: - resolution: {integrity: sha512-ahqcSXLlcV2XUBM3/f/C6cRoh7NxYA/W7Yzuv4bDU1YscTFw7ay4LmD7l6OS8EMhTNvcrWGkEettL1Bhjf+B+w==} + /@rollup/rollup-linux-arm64-musl@4.9.6: + resolution: {integrity: sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.9.0: - resolution: {integrity: sha512-uwvOYNtLw8gVtrExKhdFsYHA/kotURUmZYlinH2VcQxNCQJeJXnkmWgw2hI9Xgzhgu7J9QvWiq9TtTVwWMDa+w==} + /@rollup/rollup-linux-riscv64-gnu@4.9.6: + resolution: {integrity: sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.9.0: - resolution: {integrity: sha512-m6pkSwcZZD2LCFHZX/zW2aLIISyzWLU3hrLLzQKMI12+OLEzgruTovAxY5sCZJkipklaZqPy/2bEEBNjp+Y7xg==} + /@rollup/rollup-linux-x64-gnu@4.9.6: + resolution: {integrity: sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.9.0: - resolution: {integrity: sha512-VFAC1RDRSbU3iOF98X42KaVicAfKf0m0OvIu8dbnqhTe26Kh6Ym9JrDulz7Hbk7/9zGc41JkV02g+p3BivOdAg==} + /@rollup/rollup-linux-x64-musl@4.9.6: + resolution: {integrity: sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.9.0: - resolution: {integrity: sha512-9jPgMvTKXARz4inw6jezMLA2ihDBvgIU9Ml01hjdVpOcMKyxFBJrn83KVQINnbeqDv0+HdO1c09hgZ8N0s820Q==} + /@rollup/rollup-win32-arm64-msvc@4.9.6: + resolution: {integrity: sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.9.0: - resolution: {integrity: sha512-WE4pT2kTXQN2bAv40Uog0AsV7/s9nT9HBWXAou8+++MBCnY51QS02KYtm6dQxxosKi1VIz/wZIrTQO5UP2EW+Q==} + /@rollup/rollup-win32-ia32-msvc@4.9.6: + resolution: {integrity: sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.9.0: - resolution: {integrity: sha512-aPP5Q5AqNGuT0tnuEkK/g4mnt3ZhheiXrDIiSVIHN9mcN21OyXDVbEMqmXPE7e2OplNLDkcvV+ZoGJa2ZImFgw==} + /@rollup/rollup-win32-x64-msvc@4.9.6: + resolution: {integrity: sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: true + /@types/minimist@1.2.5: resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} dev: true @@ -624,8 +656,8 @@ packages: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true - /@types/node@20.10.4: - resolution: {integrity: sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==} + /@types/node@20.11.13: + resolution: {integrity: sha512-5G4zQwdiQBSWYTDAH1ctw2eidqdhMJaNsiIDKHFr55ihz5Trl2qqR8fdrT732yPBho5gkNxXm67OxWFBqX9aPg==} dependencies: undici-types: 5.26.5 dev: true @@ -648,6 +680,11 @@ packages: engines: {node: '>=8'} dev: true + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -662,6 +699,11 @@ packages: color-convert: 2.0.1 dev: true + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} dev: true @@ -741,11 +783,10 @@ packages: engines: {node: '>=8'} dev: true - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - concat-map: 0.0.1 dev: true /braces@3.0.2: @@ -761,13 +802,13 @@ packages: wcwidth: 1.0.1 dev: true - /bundle-require@4.0.2(esbuild@0.19.9): + /bundle-require@4.0.2(esbuild@0.19.12): resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: esbuild: '>=0.17' dependencies: - esbuild: 0.19.9 + esbuild: 0.19.12 load-tsconfig: 0.2.5 dev: true @@ -781,7 +822,7 @@ packages: dependencies: function-bind: 1.1.2 get-intrinsic: 1.2.2 - set-function-length: 1.1.1 + set-function-length: 1.2.0 dev: true /camelcase-keys@6.2.2: @@ -887,10 +928,6 @@ packages: engines: {node: '>= 6'} dev: true - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - /cross-spawn@5.1.0: resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} dependencies: @@ -991,10 +1028,18 @@ packages: path-type: 4.0.0 dev: true + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} @@ -1041,8 +1086,8 @@ packages: object-keys: 1.1.1 object.assign: 4.1.5 regexp.prototype.flags: 1.5.1 - safe-array-concat: 1.0.1 - safe-regex-test: 1.0.0 + safe-array-concat: 1.1.0 + safe-regex-test: 1.0.2 string.prototype.trim: 1.2.8 string.prototype.trimend: 1.0.7 string.prototype.trimstart: 1.0.7 @@ -1078,34 +1123,35 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild@0.19.9: - resolution: {integrity: sha512-U9CHtKSy+EpPsEBa+/A2gMs/h3ylBC0H0KSqIg7tpztHerLi6nrrcoUJAkNCEPumx8yJ+Byic4BVwHgRbN0TBg==} + /esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.19.9 - '@esbuild/android-arm64': 0.19.9 - '@esbuild/android-x64': 0.19.9 - '@esbuild/darwin-arm64': 0.19.9 - '@esbuild/darwin-x64': 0.19.9 - '@esbuild/freebsd-arm64': 0.19.9 - '@esbuild/freebsd-x64': 0.19.9 - '@esbuild/linux-arm': 0.19.9 - '@esbuild/linux-arm64': 0.19.9 - '@esbuild/linux-ia32': 0.19.9 - '@esbuild/linux-loong64': 0.19.9 - '@esbuild/linux-mips64el': 0.19.9 - '@esbuild/linux-ppc64': 0.19.9 - '@esbuild/linux-riscv64': 0.19.9 - '@esbuild/linux-s390x': 0.19.9 - '@esbuild/linux-x64': 0.19.9 - '@esbuild/netbsd-x64': 0.19.9 - '@esbuild/openbsd-x64': 0.19.9 - '@esbuild/sunos-x64': 0.19.9 - '@esbuild/win32-arm64': 0.19.9 - '@esbuild/win32-ia32': 0.19.9 - '@esbuild/win32-x64': 0.19.9 + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 dev: true /escalade@3.1.1: @@ -1163,8 +1209,8 @@ packages: micromatch: 4.0.5 dev: true - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + /fastq@1.17.0: + resolution: {integrity: sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==} dependencies: reusify: 1.0.4 dev: true @@ -1205,6 +1251,14 @@ packages: is-callable: 1.2.7 dev: true + /foreground-child@3.1.1: + resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + dev: true + /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -1223,10 +1277,6 @@ packages: universalify: 0.1.2 dev: true - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1287,15 +1337,16 @@ packages: is-glob: 4.0.3 dev: true - /glob@7.1.6: - resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} + /glob@10.3.10: + resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + foreground-child: 3.1.1 + jackspeak: 2.3.6 + minimatch: 9.0.3 + minipass: 7.0.4 + path-scurry: 1.10.1 dev: true /globalthis@1.0.3: @@ -1410,17 +1461,6 @@ packages: engines: {node: '>=8'} dev: true - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - /internal-slot@1.0.6: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} engines: {node: '>= 0.4'} @@ -1586,6 +1626,15 @@ packages: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + /joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -1669,6 +1718,11 @@ packages: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} dev: true + /lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + dev: true + /lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} dependencies: @@ -1737,10 +1791,11 @@ packages: engines: {node: '>=4'} dev: true - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + /minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} dependencies: - brace-expansion: 1.1.11 + brace-expansion: 2.0.1 dev: true /minimist-options@4.1.0: @@ -1752,6 +1807,11 @@ packages: kind-of: 6.0.3 dev: true + /minipass@7.0.4: + resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + /mixme@0.5.10: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} @@ -1819,12 +1879,6 @@ packages: object-keys: 1.1.1 dev: true - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} @@ -1901,11 +1955,6 @@ packages: engines: {node: '>=8'} dev: true - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1915,6 +1964,14 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /path-scurry@1.10.1: + resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + lru-cache: 10.2.0 + minipass: 7.0.4 + dev: true + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -1942,8 +1999,8 @@ packages: find-up: 4.1.0 dev: true - /pocketbase@0.20.1: - resolution: {integrity: sha512-Gl51UBc1U03JlwmwMkUIa1OHbcTmmdhyMPV1aJyHp9HuY5VUlh0t4hcx6D1fdhYsJcoh3kc6mpwhTBfXDoyn8w==} + /pocketbase@0.21.1: + resolution: {integrity: sha512-0PvCP4pKtxsV9kwldEGyibEvhwOcx9jSCrz3WN5CgPILJfM0z76f1op9WE8/8UgikDsMdRsc5iBLfKintrJS1g==} dev: true /postcss-load-config@4.0.2: @@ -1978,8 +2035,8 @@ packages: hasBin: true dev: true - /prettier@3.1.1: - resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} + /prettier@3.2.4: + resolution: {integrity: sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==} engines: {node: '>=14'} hasBin: true dev: true @@ -2046,8 +2103,8 @@ packages: strip-indent: 3.0.0 dev: true - /regenerator-runtime@0.14.0: - resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} dev: true /regexp.prototype.flags@1.5.1: @@ -2087,24 +2144,26 @@ packages: engines: {iojs: '>=1.0.0', node: '>=0.10.0'} dev: true - /rollup@4.9.0: - resolution: {integrity: sha512-bUHW/9N21z64gw8s6tP4c88P382Bq/L5uZDowHlHx6s/QWpjJXivIAbEw6LZthgSvlEizZBfLC4OAvWe7aoF7A==} + /rollup@4.9.6: + resolution: {integrity: sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + dependencies: + '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.9.0 - '@rollup/rollup-android-arm64': 4.9.0 - '@rollup/rollup-darwin-arm64': 4.9.0 - '@rollup/rollup-darwin-x64': 4.9.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.9.0 - '@rollup/rollup-linux-arm64-gnu': 4.9.0 - '@rollup/rollup-linux-arm64-musl': 4.9.0 - '@rollup/rollup-linux-riscv64-gnu': 4.9.0 - '@rollup/rollup-linux-x64-gnu': 4.9.0 - '@rollup/rollup-linux-x64-musl': 4.9.0 - '@rollup/rollup-win32-arm64-msvc': 4.9.0 - '@rollup/rollup-win32-ia32-msvc': 4.9.0 - '@rollup/rollup-win32-x64-msvc': 4.9.0 + '@rollup/rollup-android-arm-eabi': 4.9.6 + '@rollup/rollup-android-arm64': 4.9.6 + '@rollup/rollup-darwin-arm64': 4.9.6 + '@rollup/rollup-darwin-x64': 4.9.6 + '@rollup/rollup-linux-arm-gnueabihf': 4.9.6 + '@rollup/rollup-linux-arm64-gnu': 4.9.6 + '@rollup/rollup-linux-arm64-musl': 4.9.6 + '@rollup/rollup-linux-riscv64-gnu': 4.9.6 + '@rollup/rollup-linux-x64-gnu': 4.9.6 + '@rollup/rollup-linux-x64-musl': 4.9.6 + '@rollup/rollup-win32-arm64-msvc': 4.9.6 + '@rollup/rollup-win32-ia32-msvc': 4.9.6 + '@rollup/rollup-win32-x64-msvc': 4.9.6 fsevents: 2.3.3 dev: true @@ -2121,8 +2180,8 @@ packages: mri: 1.2.0 dev: false - /safe-array-concat@1.0.1: - resolution: {integrity: sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==} + /safe-array-concat@1.1.0: + resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} engines: {node: '>=0.4'} dependencies: call-bind: 1.0.5 @@ -2131,8 +2190,9 @@ packages: isarray: 2.0.5 dev: true - /safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + /safe-regex-test@1.0.2: + resolution: {integrity: sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.5 get-intrinsic: 1.2.2 @@ -2160,11 +2220,12 @@ packages: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} dev: true - /set-function-length@1.1.1: - resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + /set-function-length@1.2.0: + resolution: {integrity: sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==} engines: {node: '>= 0.4'} dependencies: define-data-property: 1.1.1 + function-bind: 1.1.2 get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.1 @@ -2215,6 +2276,11 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -2254,14 +2320,14 @@ packages: spdx-license-ids: 3.0.16 dev: true - /spdx-exceptions@2.3.0: - resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + /spdx-exceptions@2.4.0: + resolution: {integrity: sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==} dev: true /spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: - spdx-exceptions: 2.3.0 + spdx-exceptions: 2.4.0 spdx-license-ids: 3.0.16 dev: true @@ -2288,6 +2354,15 @@ packages: strip-ansi: 6.0.1 dev: true + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + /string.prototype.trim@1.2.8: resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} engines: {node: '>= 0.4'} @@ -2320,6 +2395,13 @@ packages: ansi-regex: 5.0.1 dev: true + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -2337,14 +2419,14 @@ packages: min-indent: 1.0.1 dev: true - /sucrase@3.34.0: - resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==} - engines: {node: '>=8'} + /sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} hasBin: true dependencies: '@jridgewell/gen-mapping': 0.3.3 commander: 4.1.1 - glob: 7.1.6 + glob: 10.3.10 lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.6 @@ -2441,19 +2523,19 @@ packages: typescript: optional: true dependencies: - bundle-require: 4.0.2(esbuild@0.19.9) + bundle-require: 4.0.2(esbuild@0.19.12) cac: 6.7.14 chokidar: 3.5.3 debug: 4.3.4 - esbuild: 0.19.9 + esbuild: 0.19.12 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 postcss-load-config: 4.0.2 resolve-from: 5.0.0 - rollup: 4.9.0 + rollup: 4.9.6 source-map: 0.8.0-beta.0 - sucrase: 3.34.0 + sucrase: 3.35.0 tree-kill: 1.2.2 typescript: 5.3.3 transitivePeerDependencies: @@ -2643,8 +2725,13 @@ packages: strip-ansi: 6.0.1 dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 dev: true /y18n@4.0.3: diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 0000000..318a0db --- /dev/null +++ b/src/client.ts @@ -0,0 +1,334 @@ +import PocketBase, { + ListResult, + OAuth2AuthConfig, + RecordAuthResponse, + RecordOptions, + RecordService, + RecordSubscription, + SendOptions, + UnsubscribeFunc +} from 'pocketbase'; +import { + BaseRecord, + GenericCollection, + GenericSchema, + MaybeArray, + RecordWithExpandToDotPath +} from './types.js'; +import { + ResolveSelectWithExpand, + SelectWithExpand, + resolveSelect +} from './select.js'; +import { Sort } from './sort.js'; +import { Filter, serializeFilter } from './filter.js'; + +export interface ViewCollectionService< + Collection extends GenericCollection, + ExpandedRecord extends BaseRecord = RecordWithExpandToDotPath +> { + collectionName: Collection['collectionName']; + client: PocketBase; + + subscribe | undefined>( + topic: string, + callback: ( + data: RecordSubscription< + ResolveSelectWithExpand + > + ) => void, + options?: { + select?: TSelect; + } & SendOptions + ): Promise; + + getFullList | undefined>( + options?: { + select?: TSelect; + page?: number; + perPage?: number; + sort?: MaybeArray>; + filter?: Filter; + } & SendOptions + ): Promise[]>; + getList = {}>( + page?: number, + perPage?: number, + options?: { + select?: TSelect; + sort?: MaybeArray>; + filter?: Filter; + } & SendOptions + ): Promise>>; + getFirstListItem = {}>( + filter: Filter, + options?: { + select?: TSelect; + sort?: MaybeArray>; + } & SendOptions + ): Promise>; + getOne = {}>( + id: string, + options?: { + select?: TSelect; + } & SendOptions + ): Promise>; + + createFilter(filter: Filter): Filter; + + createSort(...sort: Sort[]): Sort; + + createSelect>(select: T): T; +} + +export interface BaseCollectionService + extends ViewCollectionService { + create = {}>( + bodyParams: Collection['create'], + options?: { + select?: TSelect; + } & SendOptions + ): Promise>; + update = {}>( + id: string, + bodyParams: Collection['update'], + options?: { + select?: TSelect; + } & SendOptions + ): Promise>; + delete(id: string): Promise; +} + +export interface AuthCollectionService + extends BaseCollectionService, + Pick { + authWithPassword = {}>( + usernameOrEmail: string, + password: string, + options?: { + select?: TSelect; + } & SendOptions + ): Promise< + RecordAuthResponse> + >; + authWithOAuth2Code = {}>( + provider: string, + code: string, + codeVerifier: string, + redirectUrl: string, + createData?: { + [key: string]: any; + }, + options?: { + select?: TSelect; + } & SendOptions + ): Promise< + RecordAuthResponse> + >; + authWithOAuth2( + options: Omit & { + createData?: Collection['create']; + } & SendOptions + ): Promise>; + authRefresh = {}>( + options?: { + select?: TSelect; + } & SendOptions + ): Promise< + RecordAuthResponse> + >; +} + +const FORWARD_METHODS = [ + 'unsubscribe', + + 'listAuthMethods', + 'requestPasswordReset', + 'confirmPasswordReset', + 'requestVerification', + 'confirmVerification', + 'requestEmailChange', + 'confirmEmailChange', + 'listExternalAuths', + 'unlinkExternalAuth' +] as const; + +export class TypedRecordService + implements BaseCollectionService +{ + constructor(readonly service: RecordService) { + for (const name of FORWARD_METHODS) { + // @ts-ignore + this[name] = this.service[name].bind(this.service); + } + } + + get client() { + return this.service.client; + } + + get collectionName() { + return this.service.collectionIdOrName; + } + + private prepareOptions({ + select, + filter, + sort, + ...options + }: RecordOptions = {}): RecordOptions { + const { expand, fields } = resolveSelect(select); + + if (fields) options.fields = fields; + if (expand) options.expand = expand; + if (filter) options.filter = serializeFilter(filter) ?? ''; + + if (Array.isArray(sort) && sort.length) { + options.sort = sort.join(','); + } else if (sort) { + options.sort = sort; + } + + return options; + } + + createFilter(filter: Filter>) { + return serializeFilter(filter); + } + + createSort(...sorters: any[]): any { + return sorters.filter((x) => typeof x === 'string').join(','); + } + + createSelect(select: any) { + return select; + } + + subscribe( + topic: string, + callback: (data: RecordSubscription) => void, + options?: SendOptions + ): Promise { + return this.service.subscribe( + topic, + callback, + this.prepareOptions(options) + ); + } + + getFullList(options?: SendOptions) { + return this.service.getFullList(this.prepareOptions(options)); + } + + getList(page?: number, perPage?: number, options?: SendOptions) { + return this.service.getList( + page, + perPage, + this.prepareOptions(options) + ); + } + + getFirstListItem(filter: string, options?: SendOptions) { + return this.service.getFirstListItem( + filter, + this.prepareOptions(options) + ); + } + + getOne( + id: string, + options?: { + select?: any; + } & SendOptions + ): Promise { + return this.service.getOne(id, this.prepareOptions(options)); + } + + create( + bodyParams?: + | { + [key: string]: any; + } + | FormData, + options?: { + select?: any; + } & SendOptions + ) { + return this.service.create(bodyParams, this.prepareOptions(options)); + } + + update( + id: string, + bodyParams?: + | FormData + | { + [key: string]: any; + }, + options?: { + select?: any; + } & SendOptions + ) { + return this.service.update( + id, + bodyParams, + this.prepareOptions(options) + ); + } + + delete(id: string, options?: SendOptions) { + return this.service.delete(id, this.prepareOptions(options)); + } + + authWithPassword( + usernameOrEmail: string, + password: string, + options?: RecordOptions | undefined + ) { + return this.service.authWithPassword( + usernameOrEmail, + password, + this.prepareOptions(options) + ); + } + + authWithOAuth2Code( + provider: string, + code: string, + codeVerifier: string, + redirectUrl: string, + createData?: { [key: string]: any } | undefined, + options?: RecordOptions | undefined + ) { + return this.service.authWithOAuth2Code( + provider, + code, + codeVerifier, + redirectUrl, + createData, + this.prepareOptions(options) + ); + } + + authWithOAuth2(options: OAuth2AuthConfig): Promise { + return this.service.authWithOAuth2(options); + } + + authRefresh(options?: RecordOptions | undefined) { + return this.service.authRefresh(this.prepareOptions(options)); + } +} + +export class TypedPocketBase extends PocketBase { + from< + CollectionName extends keyof Schema, + Collection extends GenericCollection = Schema[CollectionName] + >( + name: CollectionName + ): Collection['type'] extends 'view' + ? ViewCollectionService + : Collection['type'] extends 'base' + ? BaseCollectionService + : AuthCollectionService { + return new TypedRecordService(this.collection(name as string)) as any; + } +} diff --git a/src/codegen/cli.ts b/src/codegen/cli.ts index fc4744f..a841183 100644 --- a/src/codegen/cli.ts +++ b/src/codegen/cli.ts @@ -52,7 +52,7 @@ sade(PKG_NAME, true) if (out) { const file = resolve(out); await mkdir(dirname(file), { recursive: true }); - await writeFile(file, definition, 'utf-8'); + await writeFile(file, definition + '\n', 'utf-8'); } else { console.log(definition); } diff --git a/src/codegen/index.ts b/src/codegen/index.ts index abdc1c4..8c4899c 100644 --- a/src/codegen/index.ts +++ b/src/codegen/index.ts @@ -15,133 +15,154 @@ interface Columns { interface Relation { name: string; - target: string; + target: CollectionDefinition; + unique: boolean; +} + +interface CollectionDefinition { + id: string; + name: string; + type: Collection['type']; + typeName: string; + columns: Columns; + relations: Relation[]; } export async function generateTypes({ url, email, password }: GenerateOptions) { const pb = new PocketBase(url); await pb.admins.authWithPassword(email, password); - const collections: Collection[] = await pb.collections.getFullList(); - const deferred: Array<() => void> = []; - - const tables = collections.map((collection) => { - const typeName = pascalCase(collection.name); - - const columns: Columns = { - create: [], - update: [], - response: [] - }; - const relations: Relation[] = []; - - collection.schema.forEach((field) => { - getFieldType(field, columns); - - if (field.type === 'relation') { - deferred.push(() => { - const target = tableMap.get(field.options.collectionId); - - if (!target) - throw new Error( - `Collection ${field.options.collectionId} not found for relation ${collection.name}.${field.name}` - ); - - relations.push({ - name: field.name, - target: `${target.typeName}Collection${ - field.options.maxSelect === 1 ? '' : '[]' - }` - }); - - /** - * indirect expand - * @see https://pocketbase.io/docs/expanding-relations/#indirect-expand - */ - - const indicies = collection.indexes.map(parseIndex); - - const isUnique = indicies.some( - (i) => - i && - i.unique && - i.fields.length === 1 && - i.fields[0] === field.name - ); - - target.relations.push({ - name: `'${collection.name}(${field.name})'`, - target: `${typeName}Collection${isUnique ? '' : '[]'}` - }); - }); - } - }); - - return { - id: collection.id, - name: collection.name, - type: collection.type, - typeName, - columns, - relations - }; - }); - - const tableMap = new Map(tables.map((t) => [t.id, t])); - - deferred.forEach((c) => c()); - - const indent = '\t'; + const collections = await pb.collections.getFullList(); + const definitions = buildCollectionDefinitions(collections); - const definition = ` -/** + const definition = `/** * This file was @generated using typed-pocketbase */ // https://pocketbase.io/docs/collections/#base-collection -interface BaseCollectionRecord { +export interface BaseCollectionResponse { + /** + * 15 characters string to store as record ID. + */ id: string; + /** + * Date string representation for the creation date. + */ created: string; + /** + * Date string representation for the creation date. + */ updated: string; + /** + * The collection id. + */ collectionId: string; + /** + * The collection name. + */ collectionName: string; } // https://pocketbase.io/docs/api-records/#create-record -interface BaseCollectionRecordCreate { +export interface BaseCollectionCreate { + /** + * 15 characters string to store as record ID. + * If not set, it will be auto generated. + */ id?: string; } +// https://pocketbase.io/docs/api-records/#update-record +export interface BaseCollectionUpdate {} + // https://pocketbase.io/docs/collections/#auth-collection -interface AuthCollectionRecord extends BaseCollectionRecord { +export interface AuthCollectionResponse extends BaseCollectionResponse { + /** + * The username of the auth record. + */ username: string; + /** + * Auth record email address. + */ email: string; + /** + * Whether to show/hide the auth record email when fetching the record data. + */ emailVisibility: boolean; + /** + * Indicates whether the auth record is verified or not. + */ verified: boolean; } // https://pocketbase.io/docs/api-records/#create-record -interface AuthCollectionRecordCreate extends BaseCollectionRecordCreate { +export interface AuthCollectionCreate extends BaseCollectionCreate { + /** + * The username of the auth record. + * If not set, it will be auto generated. + */ username?: string; + /** + * Auth record email address. + */ email?: string; + /** + * Whether to show/hide the auth record email when fetching the record data. + */ emailVisibility?: boolean; - verified?: boolean; + /** + * Auth record password. + */ password: string; + /** + * Auth record password confirmation. + */ passwordConfirm: string; + /** + * Indicates whether the auth record is verified or not. + * This field can be set only by admins or auth records with "Manage" access. + */ + verified?: boolean; } // https://pocketbase.io/docs/api-records/#update-record -interface AuthCollectionRecordUpdate { +export interface AuthCollectionUpdate { + /** + * The username of the auth record. + */ username?: string; + /** + * The auth record email address. + * This field can be updated only by admins or auth records with "Manage" access. + * Regular accounts can update their email by calling "Request email change". + */ email?: string; + /** + * Whether to show/hide the auth record email when fetching the record data. + */ emailVisibility?: boolean; - verified?: boolean; + /** + * Old auth record password. + * This field is required only when changing the record password. Admins and auth records with "Manage" access can skip this field. + */ + oldPassword?: string; + /** + * New auth record password. + */ password?: string; + /** + * New auth record password confirmation. + */ passwordConfirm?: string; + /** + * Indicates whether the auth record is verified or not. + * This field can be set only by admins or auth records with "Manage" access. + */ + verified?: boolean; } // https://pocketbase.io/docs/collections/#view-collection -interface ViewCollectionRecord { +export interface ViewCollectionRecord { id: string; } @@ -149,81 +170,164 @@ interface ViewCollectionRecord { type MaybeArray = T | T[]; -${tables - .map((t) => { - const baseRecord = - t.type === 'base' - ? 'BaseCollectionRecord' - : t.type === 'auth' - ? 'AuthCollectionRecord' - : 'ViewCollectionRecord'; - - return ` -// ===== ${t.name} ===== - -export interface ${t.typeName}Response extends ${baseRecord} { - collectionName: '${t.name}';${!t.columns.response.length ? '' : ` - ${t.columns.response.join('\n' + indent)}`} -} -${ - // view collections are readonly - t.type === 'view' - ? '' - : ` -export interface ${t.typeName}Create extends ${t.type === "base" ? "BaseCollectionRecordCreate" : "AuthCollectionRecordCreate"} ${!t.columns.create.length ? '{}' : `{ - ${t.columns.create.join('\n' + indent)} -}`} - -export interface ${t.typeName}Update${t.type === "base" ? "" : " extends AuthCollectionRecordUpdate"} ${!t.columns.update.length ? '{}' : `{ - ${t.columns.update.join('\n' + indent)} -}`} -` +${definitions.map(createCollectionTypes).join('\n\n')} + +// ===== Schema ===== + +export type Schema = { + ${definitions + .map(({ name }) => `${name}: ${pascalCase(name)}Collection;`) + .join(`\n\t`)} +};`; + + return definition; } -export interface ${t.typeName}Collection { - type: '${t.type}'; - collectionId: string; - collectionName: '${t.name}'; - response: ${t.typeName}Response;${ - t.type === 'view' - ? '' - : ` - create: ${t.typeName}Create; - update: ${t.typeName}Update;` + +function createCollectionTypes({ + name, + relations, + columns, + type, + typeName +}: CollectionDefinition) { + const prefix = pascalCase(type); + const base = `${prefix}Collection`; + + let out = `// ===== ${name} =====`; + + const { response, create, update } = columns; + + const responseColumns = [`collectionName: '${name}';`, ...response]; + + out += `\n\nexport interface ${typeName}Response extends ${base}Response {\n\t${responseColumns.join( + `\n\t` + )}\n}`; + + if (type !== 'view') { + const createBody = create.length + ? `{\n\t${create.join(`\n\t`)}\n}` + : '{}'; + + out += `\n\nexport interface ${typeName}Create extends ${base}Create ${createBody}`; + + const updateBody = update.length + ? `{\n\t${update.join(`\n\t`)}\n}` + : '{}'; + + out += `\n\nexport interface ${typeName}Update extends ${base}Update ${updateBody}`; } - relations: ${ - t.relations.length === 0 - ? 'Record' - : `{ - ${t.relations - .map((col) => `${col.name}: ${col.target};`) - .join('\n' + indent.repeat(2))} - }` + + const createRelations = () => { + return relations + .map( + (r) => + `${/^\w+$/.test(r.name) ? r.name : `'${r.name}'`}: ${ + r.target.typeName + }Collection${r.unique ? '' : '[]'};` + ) + .join('\n\t\t'); }; + + const collectionBody = [ + `type: '${type}';`, + `collectionId: string;`, + `collectionName: '${name}';`, + `response: ${typeName}Response;`, + type !== 'view' && `create: ${typeName}Create;`, + type !== 'view' && `update: ${typeName}Update;`, + `relations: ${ + relations.length === 0 + ? 'Record;' + : `{\n\t\t${createRelations()}\n\t};` + }` + ].filter(Boolean); + + out += `\n\nexport interface ${typeName}Collection { + ${collectionBody.join('\n\t')} +}`; + + return out; } -`.trim(); - }) - .join('\n\n')} +function buildCollectionDefinitions(collections: Collection[]) { + const deferred: Array<() => void> = []; + const definitions = new Map(); -// ===== Schema ===== + for (const collection of collections) { + const columns: Columns = { + create: [], + update: [], + response: [] + }; + const relations: Relation[] = []; -export type Schema = { - ${tables - .map(({ name, typeName }) => `${name}: ${typeName}Collection;`) - .join('\n' + indent)} -}; -`.trim(); + for (const field of collection.schema) { + getFieldType(field, columns); - return definition; + if (field.type === 'relation') { + deferred.push(() => { + const from = definitions.get(collection.id); + const target = definitions.get(field.options.collectionId); + + if (!from) + throw new Error( + `Collection ${collection.id} not found for relation ${collection.name}.${field.name}` + ); + if (!target) + throw new Error( + `Collection ${field.options.collectionId} not found for relation ${collection.name}.${field.name}` + ); + + relations.push({ + name: field.name, + target, + unique: field.options.maxSelect === 1 + }); + + /** + * indirect expand + * @see https://pocketbase.io/docs/expanding-relations/#indirect-expand + */ + + const indicies = collection.indexes.map(parseIndex); + + const isUnique = indicies.some( + (index) => + index && + index.unique && + index.fields.length === 1 && + index.fields[0] === field.name + ); + + target.relations.push({ + name: `${collection.name}(${field.name})`, + target: from, + unique: isUnique + }); + }); + } + } + + definitions.set(collection.id, { + id: collection.id, + name: collection.name, + type: collection.type, + columns, + relations, + typeName: pascalCase(collection.name) + }); + } + + deferred.forEach((c) => c()); + + return Array.from(definitions.values()); } function getFieldType(field: Field, { response, create, update }: Columns) { - const req = field.required ? '' : '?'; - const addResponse = (type: string, name = field.name) => response.push(`${name}: ${type};`); const addCreate = (type: string, name = field.name) => - create.push(`${name}${req}: ${type};`); + create.push(`${name}${field.required ? '' : '?'}: ${type};`); const addUpdate = (type: string, name = field.name) => update.push(`${name}?: ${type};`); const addAll = (type: string) => { @@ -264,12 +368,11 @@ function getFieldType(field: Field, { response, create, update }: Columns) { } case 'select': { const single = field.options.maxSelect === 1; - const values = !field.required && single - ? ["", ...field.options.values] - : field.options.values; - const singleType = values - .map((v) => `'${v}'`) - .join(' | '); + const values = + !field.required && single + ? ['', ...field.options.values] + : field.options.values; + const singleType = values.map((v) => `'${v}'`).join(' | '); const type = single ? `${singleType}` : `MaybeArray<${singleType}>`; addResponse(single ? singleType : `Array<${singleType}>`); @@ -285,7 +388,7 @@ function getFieldType(field: Field, { response, create, update }: Columns) { case 'relation': { const singleType = 'string'; const single = field.options.maxSelect === 1; - const type = single ? `${singleType}` : `MaybeArray<${singleType}>`; + const type = single ? singleType : `MaybeArray<${singleType}>`; addResponse(single ? singleType : `Array<${singleType}>`); addCreate(type); @@ -297,15 +400,13 @@ function getFieldType(field: Field, { response, create, update }: Columns) { break; } case 'file': { - const singleType = 'string'; const single = field.options.maxSelect === 1; - const type = single ? `${singleType}` : `MaybeArray<${singleType}>`; - addResponse(single ? singleType : `Array<${singleType}>`); - addCreate(type); - addUpdate(type); + addResponse(single ? 'string' : `Array`); + addCreate(single ? `File | null` : `MaybeArray`); + addUpdate(single ? `File | null` : `MaybeArray`); if (!single) { - addUpdate(type, `'${field.name}-'`); + addUpdate('string', `'${field.name}-'`); } break; } diff --git a/src/filter.ts b/src/filter.ts index 09beed5..1fda6d9 100644 --- a/src/filter.ts +++ b/src/filter.ts @@ -1,8 +1,4 @@ -import { - BaseRecord, - GenericCollection, - RecordWithExpandToDotPath -} from './types.js'; +import type { BaseRecord } from './types.js'; type ActualFilter = [ K, @@ -30,18 +26,14 @@ export type FilterOperand = export type FilterParam = { __record__?: T } & string; -export type Filter = FilterParam< - RecordWithExpandToDotPath ->; - -export type FilterInput = +export type Filter = | ActualFilter | FilterParam | false | null | undefined; -function serializeFilter([key, op, val]: ActualFilter) { +export function serializeFilterTuple([key, op, val]: ActualFilter) { const type = typeof val; if (type === 'boolean' || type === 'number') { val = val.toString(); @@ -55,19 +47,20 @@ function serializeFilter([key, op, val]: ActualFilter) { val = "'" + JSON.stringify(val).replace(/'/g, "\\'") + "'"; } - return `${String(key)}${op}${val}`; + return `${String(key)} ${op} ${val}`; +} + +export function serializeFilter(filter: Filter): string | null { + if (!filter) return null; + return Array.isArray(filter) ? serializeFilterTuple(filter) : filter; } -export function serializeFilters(filters: FilterInput[]) { - return filters - .filter(Boolean) - .map((filter) => - Array.isArray(filter) ? serializeFilter(filter) : filter - ); +export function serializeFilters(filters: Filter[]) { + return filters.filter((val) => !!val).map(serializeFilter); } export function and( - ...filters: FilterInput[] + ...filters: Filter[] ): FilterParam { const str = serializeFilters(filters).join(' && '); if (!str.length) return ''; @@ -75,7 +68,7 @@ export function and( } export function or( - ...filters: FilterInput[] + ...filters: Filter[] ): FilterParam { const str = serializeFilters(filters).join(' || '); if (!str.length) return ''; @@ -86,54 +79,54 @@ export function eq( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '=', value]); + return serializeFilterTuple([column, '=', value]); } export function neq( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '!=', value]); + return serializeFilterTuple([column, '!=', value]); } export function gt( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '>', value]); + return serializeFilterTuple([column, '>', value]); } export function gte( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '>=', value]); + return serializeFilterTuple([column, '>=', value]); } export function lt( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '<', value]); + return serializeFilterTuple([column, '<', value]); } export function lte( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '<=', value]); + return serializeFilterTuple([column, '<=', value]); } export function like( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '~', value]); + return serializeFilterTuple([column, '~', value]); } export function nlike( column: Key, value: T[Key] ): FilterParam { - return serializeFilter([column, '!~', value]); + return serializeFilterTuple([column, '!~', value]); } diff --git a/src/index.ts b/src/index.ts index 64cf288..3ee968a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,21 +1,9 @@ -import PocketBase, { RecordModel, RecordService } from 'pocketbase'; -import { GenericSchema } from './types.js'; -import { TypedRecordService } from './record-service.js'; - -export { - createOptions, +export type { ResolveSelect, ResolveSelectWithExpand, Select, - SelectWithExpand, - TypedBaseQueryParams, - TypedFullListQueryParams, - TypedListQueryParams, - TypedRecordFullListQueryParams, - TypedRecordListQueryParams, - TypedRecordQueryParams -} from './queryParams.js'; - + SelectWithExpand +} from './select.js'; export { and, or, @@ -27,15 +15,14 @@ export { lte, neq, nlike, - Filter + type Filter } from './filter.js'; -export { asc, desc, sort, Sort } from './sort.js'; -export { GenericSchema, GenericCollection, TypedRecord } from './types.js'; - -export interface TypedPocketBase - extends PocketBase { - collection( - idOrName: C - ): TypedRecordService; - collection(idOrName: string): RecordService; -} +export type { Sort } from './sort.js'; +export type { GenericSchema, GenericCollection, TypedRecord } from './types.js'; +export { + type AuthCollectionService, + type BaseCollectionService, + type ViewCollectionService, + TypedPocketBase, + TypedRecordService +} from './client.js'; diff --git a/src/queryParams.ts b/src/queryParams.ts deleted file mode 100644 index b78dc8b..0000000 --- a/src/queryParams.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { FilterParam } from './filter.js'; -import { Sort } from './sort.js'; -import { - ArrayInnerType, - GenericCollection, - MaybeArray, - MaybeMakeArray, - Prettify, - RecordWithExpandToDotPath -} from './types.js'; - -export type Select = { - [K in keyof Collection['response']]?: boolean; -}; - -export type SelectWithExpand = - Select & { - $expand?: { - [K in keyof Collection['relations']]?: - | SelectWithExpand> - | boolean; - }; - }; - -export type ResolveSelect< - TCollection extends GenericCollection, - TSelect extends Select -> = Extract extends never - ? TCollection['response'] - : { - [K in keyof TSelect & - keyof TCollection['response'] as TSelect[K] extends true - ? K - : never]: TCollection['response'][K]; - }; - -export type ResolveSelectWithExpand< - TCollection extends GenericCollection, - TSelect extends Select -> = Prettify< - ResolveSelect & - ('$expand' extends keyof TSelect - ? { - expand: { - [Relation in keyof TSelect['$expand'] & - keyof TCollection['relations'] as TSelect['$expand'][Relation] extends false - ? never - : Relation]: TSelect['$expand'][Relation] extends true - ? MaybeMakeArray< - TCollection['relations'][Relation], - ArrayInnerType< - TCollection['relations'][Relation] - >['response'] - > - : TSelect['$expand'][Relation] extends object - ? MaybeMakeArray< - TCollection['relations'][Relation], - ResolveSelectWithExpand< - ArrayInnerType< - TCollection['relations'][Relation] - >, - TSelect['$expand'][Relation] - > - > - : never; - }; - } - : {}) ->; - -export interface CreateOptions { - < - TCollection extends GenericCollection, - TSelect extends SelectWithExpand - >( - options: TypedRecordFullListQueryParams - ): TypedRecordFullListQueryParams; - < - TCollection extends GenericCollection, - TSelect extends SelectWithExpand - >( - options: TypedRecordListQueryParams - ): TypedRecordListQueryParams; - < - TCollection extends GenericCollection, - TSelect extends SelectWithExpand - >( - options: TypedRecordQueryParams - ): TypedRecordQueryParams; -} - -export const createOptions: CreateOptions = (options) => { - const fields: string[] = []; - const expand: string[] = []; - - if (options.select) { - (function recurse( - { $expand, ...rest }: SelectWithExpand, - fieldsParent: string[] = [], - expandParent: string[] = [] - ) { - if (Object.keys(rest).length === 0) { - fields.push([...fieldsParent, '*'].join('.')); - } else { - for (const key in rest) { - if (rest[key]) { - fields.push([...fieldsParent, key].join('.')); - } - } - } - - if ($expand) { - for (const key in $expand) { - const sub = $expand[key]; - if (sub === true) { - expand.push([...expandParent, key].join('.')); - fields.push( - [...fieldsParent, 'expand', key, '*'].join('.') - ); - } else if (sub) { - expand.push([...expandParent, key].join('.')); - recurse( - sub, - [...fieldsParent, 'expand', key], - [...expandParent, key] - ); - } - } - } - })(options.select); - } else { - fields.push('*'); - } - - let { sort } = options as any; - if (Array.isArray(sort)) { - sort = sort.join(','); - } - - return { - ...options, - fields: fields.join(','), - expand: expand.join(','), - sort - }; -}; - -export interface TypedBaseQueryParams { - select?: TSelect; - requestKey?: string | null; - /** - * @deprecated use `requestKey:null` instead - */ - $autoCancel?: boolean; - /** - * @deprecated use `requestKey:string` instead - */ - $cancelKey?: string; -} - -export interface TypedListQueryParams< - TCollection extends GenericCollection, - TSelect -> extends TypedBaseQueryParams { - page?: number; - perPage?: number; - sort?: MaybeArray>; - filter?: FilterParam>; -} - -export interface TypedFullListQueryParams< - TCollection extends GenericCollection, - TSelect -> extends TypedListQueryParams { - batch?: number; -} - -export interface TypedRecordQueryParams - extends TypedBaseQueryParams { - select?: TSelect; -} - -export interface TypedRecordListQueryParams< - TCollection extends GenericCollection, - TSelect -> extends TypedListQueryParams, - TypedRecordQueryParams {} - -export interface TypedRecordFullListQueryParams< - TCollection extends GenericCollection, - TSelect -> extends TypedFullListQueryParams, - TypedRecordQueryParams {} diff --git a/src/record-service.ts b/src/record-service.ts deleted file mode 100644 index d636116..0000000 --- a/src/record-service.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { ListResult, RecordAuthResponse, RecordService } from 'pocketbase'; -import { GenericCollection } from './types.js'; -import { Filter } from './filter.js'; -import { - ResolveSelectWithExpand, - SelectWithExpand, - TypedRecordFullListQueryParams, - TypedRecordListQueryParams, - TypedRecordQueryParams -} from './queryParams.js'; - -// @ts-expect-error -export interface TypedRecordService - extends RecordService { - getFullList>( - options?: TypedRecordFullListQueryParams - ): Promise[]>; - getFullList>( - batch?: number, - options?: TypedRecordListQueryParams - ): Promise[]>; - - getList>( - page?: number, - perPage?: number, - options?: TypedRecordListQueryParams - ): Promise>>; - - getFirstListItem>( - filter: Filter, - options?: TypedRecordListQueryParams - ): Promise>; - - getOne>( - id: string, - options?: TypedRecordQueryParams - ): Promise>; - - create>( - bodyParams: Collection['create'], - options?: TypedRecordQueryParams - ): Promise>; - - update>( - id: string, - bodyParams: Collection['update'], - options?: TypedRecordQueryParams - ): Promise>; - - // ===== AUTH ===== - authWithPassword>( - usernameOrEmail: string, - password: string, - options?: TypedRecordQueryParams - ): Promise< - RecordAuthResponse> - >; - - authWithOAuth2Code>( - provider: string, - code: string, - codeVerifier: string, - redirectUrl: string, - createData?: { - [key: string]: any; - }, - options?: TypedRecordQueryParams - ): Promise< - RecordAuthResponse> - >; - - authWithOAuth2>( - provider: string, - code: string, - codeVerifier: string, - redirectUrl: string, - createData?: { - [key: string]: any; - }, - bodyParams?: { - [key: string]: any; - }, - options?: TypedRecordQueryParams - ): Promise< - RecordAuthResponse> - >; - - authRefresh>( - options?: TypedRecordQueryParams - ): Promise< - RecordAuthResponse> - >; -} diff --git a/src/select.ts b/src/select.ts new file mode 100644 index 0000000..2c9b1f3 --- /dev/null +++ b/src/select.ts @@ -0,0 +1,115 @@ +import { + ArrayInnerType, + GenericCollection, + MaybeMakeArray, + Prettify +} from './types.js'; + +export type Select = { + [K in keyof Collection['response']]?: boolean; +}; + +export type SelectWithExpand = + Select & { + expand?: { + [K in keyof Collection['relations']]?: + | SelectWithExpand> + | boolean; + }; + }; + +export type ResolveSelect< + TCollection extends GenericCollection, + TSelect extends Select | undefined +> = + Extract extends never + ? TCollection['response'] + : { + [K in keyof TSelect & + keyof TCollection['response'] as TSelect[K] extends true + ? K + : never]: TCollection['response'][K]; + }; + +export type ResolveSelectWithExpand< + TCollection extends GenericCollection, + TSelect extends Select | undefined +> = Prettify< + ResolveSelect & + ('expand' extends keyof TSelect + ? { + expand?: { + [Relation in keyof TSelect['expand'] & + keyof TCollection['relations'] as TSelect['expand'][Relation] extends false + ? never + : Relation]?: TSelect['expand'][Relation] extends true + ? MaybeMakeArray< + TCollection['relations'][Relation], + ArrayInnerType< + TCollection['relations'][Relation] + >['response'] + > + : TSelect['expand'][Relation] extends object + ? MaybeMakeArray< + TCollection['relations'][Relation], + ResolveSelectWithExpand< + ArrayInnerType< + TCollection['relations'][Relation] + >, + TSelect['expand'][Relation] + > + > + : never; + }; + } + : {}) +>; + +export function resolveSelect(select: any) { + const fieldList: string[] = []; + const expandList: string[] = []; + + if (select) { + (function recurse( + { expand, ...rest }: SelectWithExpand, + fieldsParent: string[] = [], + expandParent: string[] = [] + ) { + if (Object.keys(rest).length === 0) { + fieldList.push([...fieldsParent, '*'].join('.')); + } else { + for (const key in rest) { + if (rest[key]) { + fieldList.push([...fieldsParent, key].join('.')); + } + } + } + + if (expand) { + for (const key in expand) { + const sub = expand[key]; + if (sub === true) { + expandList.push([...expandParent, key].join('.')); + fieldList.push( + [...fieldsParent, 'expand', key, '*'].join('.') + ); + } else if (sub) { + expandList.push([...expandParent, key].join('.')); + recurse( + sub, + [...fieldsParent, 'expand', key], + [...expandParent, key] + ); + } + } + } + })(select); + } else { + fieldList.push('*'); + } + + return { + fields: fieldList.join(','), + expand: expandList.join(',') + }; +} diff --git a/src/sort.ts b/src/sort.ts index ca3c040..b495062 100644 --- a/src/sort.ts +++ b/src/sort.ts @@ -1,29 +1,7 @@ -import { - BaseRecord, - GenericCollection, - RecordWithExpandToDotPath -} from './types.js'; +import type { BaseRecord } from './types.js'; -export type SortParam = { - __record__?: T; -} & string; - -export type Sort = - | SortParam> - | PrefixedSortItem>; - -export type PrefixedSortItem = T extends string ? `${'+' | '-'}${T}` : never; - -export function sort( - ...sorters: Array | PrefixedSortItem> -): SortParam { - return sorters.filter(Boolean).join(','); -} - -export function asc(column: keyof T): SortParam { - return `+${String(column)}`; -} - -export function desc(column: keyof T): SortParam { - return `-${String(column)}`; -} +export type Sort = + | `${'+' | '-'}${keyof T & string}` + | false + | null + | undefined; diff --git a/src/types.ts b/src/types.ts index 3562e42..555bfd7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -106,3 +106,5 @@ type _RecordWithExpandToDotPath< export type RecordWithExpandToDotPath = Prettify< _RecordWithExpandToDotPath >; + +export type ReservedRecordNames = 'collectionId' | 'collectionName'; diff --git a/tsup.config.ts b/tsup.config.ts index 56ed27a..7ef0234 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -4,7 +4,7 @@ import { name, version } from './package.json'; export default defineConfig([ { entry: ['src/index.ts'], - format: ['esm', 'cjs'], + format: ['esm'], outDir: 'dist/client', dts: true, sourcemap: true,