Compare commits

...
92 Commits
Author SHA1 Message Date
Gani Georgiev 56b2641469 added hmac jsvm primitives and updated docs 2023-09-09 12:03:34 +03:00
Gani Georgiev f266621a0f updated go deps 2023-09-06 14:13:02 +03:00
Gani Georgiev ca136c5dc1 [#3265] silent the localStorage quota error to prevent breaking the record form panel 2023-09-06 14:11:58 +03:00
Gani Georgiev abfe18bcce [#3261] exclude the local temp dir from the backups 2023-09-06 07:09:28 +03:00
Gani Georgiev f3fc7f78d7 updated changelog 2023-09-05 11:54:09 +03:00
Gani Georgiev 26fd069d11 updated npm deps 2023-09-05 11:49:01 +03:00
Gani Georgiev 62bde9e1f3 updated jsvm types 2023-09-05 11:25:14 +03:00
Gani Georgiev b945cd2fdf updated changelog and ui/dist 2023-09-05 11:23:41 +03:00
Gani Georgiev 89a0520f7d [#3257] normalize pasted text in the editor field 2023-09-05 10:36:42 +03:00
Gani Georgiev a88b3c5db3 updated api docs and enabled paste_as_text editor option 2023-09-05 08:06:21 +03:00
Gani Georgiev a37d9cfb84 updated ui/dist 2023-09-04 11:35:39 +03:00
Gani Georgiev 5b084bbbfd fixed grammar 2023-09-01 14:28:49 +03:00
Gani Georgiev 322508f6d1 registered a custom Deflate compressor to speedup the backups generation 2023-09-01 14:27:23 +03:00
Gani Georgiev 78e70bd52b there is no need to nil the app.settings on ResetBootstrapState 2023-09-01 13:46:33 +03:00
Gani Georgiev 58401459bf updated ui/dist 2023-09-01 12:44:43 +03:00
Gani Georgiev f172754775 removed cgo build archives artifacts 2023-09-01 12:41:49 +03:00
Gani Georgiev 31670ab3e1 log cron job errors 2023-09-01 11:17:09 +03:00
Gani Georgiev baacf4913b updated api preview tabs style 2023-09-01 09:30:49 +03:00
Gani Georgiev 8a94ccea42 updated to Svelte 4 2023-09-01 09:22:49 +03:00
Gani Georgiev b2bab9573a removed forgotten svg icon font declaration 2023-08-30 20:39:39 +03:00
Gani Georgiev e5b5c1f76f added option to auto generate admin and auth record passwords from the Admin UI 2023-08-30 14:59:00 +03:00
Gani Georgiev ccb1c42220 updated jsvm types and removed unnecessary comment 2023-08-29 22:31:33 +03:00
Gani Georgiev a394777264 [#3191] added client-side validation and syntax highlight for the json field 2023-08-29 22:10:57 +03:00
Gani Georgiev 7d10b3c502 updated go deps 2023-08-29 19:23:01 +03:00
Gani Georgiev 64ffb308bb use singular NoDecimal option name 2023-08-29 18:41:20 +03:00
Gani Georgiev 916c74c218 [#3113] added NoDecimal number field option 2023-08-29 18:35:57 +03:00
Gani Georgiev 17974d534e added ellipsis for long backup titles 2023-08-28 21:05:35 +03:00
Gani Georgiev bde7a86b30 [#3066] added the application name as part of the autogenerated backup name for easier identification 2023-08-28 20:36:55 +03:00
Gani Georgiev f7f8f09336 [#2599] added option to upload a backup file from the Admin UI 2023-08-28 20:06:48 +03:00
Gani Georgiev 2a6b891a9b merged with master 2023-08-26 14:46:30 +03:00
Gani Georgiev b4cb35483b updated jsvm types 2023-08-26 14:43:55 +03:00
Gani Georgiev 1606cfd6e2 fixed cronAdd example 2023-08-26 14:34:47 +03:00
Gani Georgiev 08f97ef0bb Merge branch 'master' into develop 2023-08-26 10:38:13 +03:00
Gani Georgiev 0dc263a40c updated go deps and use the new fileblob NoTempDir option 2023-08-26 10:37:12 +03:00
Gani Georgiev 824031e1a4 updated changelog 2023-08-26 10:30:26 +03:00
Gani Georgiev 311bc74b7e [#3025] updated tests.ApiScenario fields 2023-08-25 22:14:04 +03:00
Gani Georgiev 4f3d1682de synced with master 2023-08-25 18:11:09 +03:00
Gani Georgiev 18728732b9 updated ui/dist and go deps 2023-08-25 16:49:59 +03:00
Gani Georgiev bb4f27cfb5 updated automigrate template test 2023-08-25 16:47:41 +03:00
impact-merlinmarekandMerlin Marek d423acad3b [#3192] fixed autogenerated down migration not preserving old rules state
Co-authored-by: Merlin Marek <merlin.marek@posteo.net>
2023-08-25 16:21:04 +03:00
Gani Georgiev ef73052546 added httpAddr default when domain name is missing 2023-08-25 12:06:24 +03:00
Gani Georgiev c89c68a4dc poc of serve domain args 2023-08-25 11:16:31 +03:00
Gani Georgiev 02495554cf [#3175] added jsvm crypto primitives 2023-08-24 11:25:00 +03:00
Gani Georgiev cdbe6d78d3 added basic fields wildcard support 2023-08-23 20:56:38 +03:00
Gani Georgiev ff6904f1f8 removed unnecessary test cases prefix 2023-08-23 16:50:43 +03:00
Gani Georgiev bc0222dcb4 [#3176] skip fields query param transformations for non 20x responses 2023-08-23 16:49:09 +03:00
Gani Georgiev 04826ba588 reduced the default prewarmed goja vms to 25 2023-08-22 22:09:33 +03:00
Gani Georgiev 6ca1f5c431 use crypto if available 2023-08-22 22:01:05 +03:00
Gani Georgiev 2863763a27 added option to control the default TinyMCE urls convert behavior 2023-08-22 14:39:21 +03:00
Gani Georgiev 9c0d952543 fixed isNew checks 2023-08-22 13:01:08 +03:00
Gani Georgiev ed4f7c7358 updated presentable fields sorting 2023-08-22 12:29:54 +03:00
Gani Georgiev 49f1c869c0 synced with master 2023-08-22 10:54:22 +03:00
Gani Georgiev 5e6949062f updated changelog 2023-08-21 18:15:34 +03:00
Gani Georgiev dc063b20fa bumped app version 2023-08-21 18:14:23 +03:00
Gani Georgiev f42bbfd927 updated go deps 2023-08-21 18:10:07 +03:00
Gani Georgiev f0af24d78f use the presentable prop when displaying relations 2023-08-21 18:06:35 +03:00
Gani Georgiev 26fd3d48df added migration to copy existing DisplayFields to the new Presentable field 2023-08-21 12:58:51 +03:00
Gani Georgiev 864bbe7e12 added SchemaField.Presentable field 2023-08-21 12:58:18 +03:00
Gani Georgiev 1e995552c8 updated apis.Serve godoc 2023-08-20 18:31:56 +03:00
Gani Georgiev 6baae97b5d added json marshal fallback for complex structs as placeholder param 2023-08-19 16:33:45 +03:00
Gani Georgiev bcfbbc53f8 [#3147] don't silence connectivity errors 2023-08-18 19:14:13 +03:00
Gani Georgiev 8a916cd636 added datetime macros 2023-08-18 08:48:33 +03:00
Gani Georgiev 75f58a28ac added placeholder params support for Dao.FindRecordsByFilter and Dao.FindFirstRecordByFilter 2023-08-18 06:31:14 +03:00
Gani Georgiev e87ef431c5 added jsvm .* binds 2023-08-17 20:50:00 +03:00
Gani Georgiev b2ac538580 [#3097] added SmtpConfig.LocalName option 2023-08-17 19:07:56 +03:00
Gani Georgiev 53b20ec104 updated LastVerificationSentAt and LastResetSentAt fill sequence 2023-08-17 14:03:11 +03:00
Gani Georgiev c8ef3c4050 updated ui/dist 2023-08-16 22:38:56 +03:00
Gani Georgiev 9113d30103 fixed typo 2023-08-16 17:38:08 +03:00
Gani Georgiev fef6e584b7 updated jsvm types and godoc list formatting 2023-08-15 12:35:52 +03:00
Gani Georgiev 67fa47b1bb [#3132] updated godoc 2023-08-15 12:25:24 +03:00
Gani Georgiev 5f21c4119f [#3132] added common cron expression macros 2023-08-15 12:21:33 +03:00
Gani Georgiev 734f35c504 synced with master 2023-08-15 12:10:21 +03:00
Gani Georgiev 038ae8f803 updated changelog 2023-08-15 01:14:10 +03:00
Gani Georgiev 2236288e57 quoted the wrapped view query columns 2023-08-15 01:09:53 +03:00
Gani Georgiev 8f10c66160 updated ui/dist 2023-08-15 00:58:34 +03:00
Gani Georgiev 5960dc5f2d removed js sdk dto helpers 2023-08-14 21:20:49 +03:00
Gani Georgiev cbf1215bb1 updated jsvm types 2023-08-11 14:40:25 +03:00
Gani Georgiev 1b633720be updated views migrations to use SaveCollection 2023-08-11 14:37:53 +03:00
Gani Georgiev adb5d6e998 [#3110] normalized view queries with numeric or expression ids 2023-08-11 14:29:18 +03:00
Gani Georgiev 3841946b61 downgraded temp gocloud until the os.NoTempDir is released 2023-08-10 21:38:13 +03:00
Gani Georgiev 369e2703c2 updated ui/dist 2023-08-10 08:56:26 +03:00
Gani Georgiev 4a45ad91fa [#3106] always refresh the Admins UI initial admins counter cache when there are none 2023-08-10 08:50:48 +03:00
Nikita Zhenev 265dac45ce [#3103] fixed jsvm registerMigrations error message typo 2023-08-09 18:40:34 +03:00
Gani Georgiev f152787578 updated changelog 2023-08-09 13:17:24 +03:00
Gani Georgiev 640623f4fd [#3098] fixed incorrect cascade delete tooltip message 2023-08-09 12:58:20 +03:00
Gani Georgiev 1aff89f377 use the logs maxDays before firing the goroutine 2023-08-09 12:23:49 +03:00
Gani Georgiev 7d6b12a4ef updated ui/dist 2023-08-08 14:33:08 +03:00
Gani Georgiev 7a3223e415 [#3089] use a temp dir inside pb_data to prevent backups cross-device link error 2023-08-08 14:15:29 +03:00
Gani Georgiev bd18688f35 [#3090] fixed relation to view error message 2023-08-08 12:41:51 +03:00
Gani Georgiev f90da96820 enabled lazy loading for the Admin UI thumb images 2023-08-06 21:51:55 +03:00
Gani Georgiev 6c8f2d2cd6 use scrollbar-gutter to minimize the table records listing layout shifts 2023-08-06 21:44:26 +03:00
Gani Georgiev 5e84305922 fixed changelog grammar 2023-08-05 10:12:22 +03:00
237 changed files with 9623 additions and 43284 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '>=1.20.3'
go-version: '>=1.21.0'
# This step usually is not needed because the /ui/dist is pregenerated locally
# but its here to ensure that each release embeds the latest admin ui artifacts.
+1 -8
View File
@@ -7,6 +7,7 @@ before:
- go mod tidy
builds:
# used only for tests
- id: build_cgo
main: ./examples/base
binary: pocketbase
@@ -46,14 +47,6 @@ release:
draft: true
archives:
- id: archive_cgo
builds: [build_cgo]
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}_cgo'
format: zip
files:
- LICENSE*
- CHANGELOG*
- id: archive_noncgo
builds: [build_noncgo]
format: zip
+195 -6
View File
@@ -1,8 +1,197 @@
## v0.18.2
- Prevent breaking the record form in the Admin UI in case the browser's localStorage quote has been exceeded when uploading or storing large `editor` values ([#3265](https://github.com/pocketbase/pocketbase/issues/3265)).
- Updated docs and missing JSVM typings.
- Exposed additional crypto primitives under the `$security.*` JSVM namespace ([#3273](https://github.com/pocketbase/pocketbase/discussions/3273)):
```
// HMAC with SHA256
$security.hs256("hello", "secret")
// HMAC with SHA512
$security.hs512("hello", "secret")
// compare 2 strings with a constant time
$security.equal(hash1, hash2)
```
## v0.18.1
- Excluded the local temp dir from the backups ([#3261](https://github.com/pocketbase/pocketbase/issues/3261)).
## v0.18.0
- Simplified the `serve` command to accept domain name(s) as argument to reduce any additional manual hosts setup that sometimes previously was needed when deploying on production ([#3190](https://github.com/pocketbase/pocketbase/discussions/3190)).
```sh
./pocketbase serve yourdomain.com
```
- Added `fields` wildcard (`*`) support.
- Added option to upload a backup file from the Admin UI ([#2599](https://github.com/pocketbase/pocketbase/issues/2599)).
- Registered a custom Deflate compressor to speedup (_nearly 2-3x_) the backups generation for the sake of a small zip size increase.
_Based on several local tests, `pb_data` of ~500MB (from which ~350MB+ are several hundred small files) results in a ~280MB zip generated for ~11s (previously it resulted in ~250MB zip but for ~35s)._
- Added the application name as part of the autogenerated backup name for easier identification ([#3066](https://github.com/pocketbase/pocketbase/issues/3066)).
- Added new `SmtpConfig.LocalName` option to specify a custom domain name (or IP address) for the initial EHLO/HELO exchange ([#3097](https://github.com/pocketbase/pocketbase/discussions/3097)).
_This is usually required for verification purposes only by some SMTP providers, such as on-premise [Gmail SMTP-relay](https://support.google.com/a/answer/2956491)._
- Added `NoDecimal` `number` field option.
- `editor` field improvements:
- Added new "Strip urls domain" option to allow controlling the default TinyMCE urls behavior (_default to `false` for new content_).
- Normalized pasted text while still preserving links, lists, tables, etc. formatting ([#3257](https://github.com/pocketbase/pocketbase/issues/3257)).
- Added option to auto generate admin and auth record passwords from the Admin UI.
- Added JSON validation and syntax highlight for the `json` field in the Admin UI ([#3191](https://github.com/pocketbase/pocketbase/issues/3191)).
- Added datetime filter macros:
```
// all macros are UTC based
@second - @now second number (0-59)
@minute - @now minute number (0-59)
@hour - @now hour number (0-23)
@weekday - @now weekday number (0-6)
@day - @now day number
@month - @now month number
@year - @now year number
@todayStart - beginning of the current day as datetime string
@todayEnd - end of the current day as datetime string
@monthStart - beginning of the current month as datetime string
@monthEnd - end of the current month as datetime string
@yearStart - beginning of the current year as datetime string
@yearEnd - end of the current year as datetime string
```
- Added cron expression macros ([#3132](https://github.com/pocketbase/pocketbase/issues/3132)):
```
@yearly - "0 0 1 1 *"
@annually - "0 0 1 1 *"
@monthly - "0 0 1 * *"
@weekly - "0 0 * * 0"
@daily - "0 0 * * *"
@midnight - "0 0 * * *"
@hourly - "0 * * * *"
```
- ⚠️ Added offset argument `Dao.FindRecordsByFilter(collection, filter, sort, limit, offset, [params...])`.
_If you don't need an offset, you can set it to `0`._
- To minimize the footguns with `Dao.FindFirstRecordByFilter()` and `Dao.FindRecordsByFilter()`, the functions now supports an optional placeholder params argument that is safe to be populated with untrusted user input.
The placeholders are in the same format as when binding regular SQL parameters.
```go
// unsanitized and untrusted filter variables
status := "..."
author := "..."
app.Dao().FindFirstRecordByFilter("articles", "status={:status} && author={:author}", dbx.Params{
"status": status,
"author": author,
})
app.Dao().FindRecordsByFilter("articles", "status={:status} && author={:author}", "-created", 10, 0, dbx.Params{
"status": status,
"author": author,
})
```
- Added JSVM `$mails.*` binds for the corresponding Go [mails package](https://pkg.go.dev/github.com/pocketbase/pocketbase/mails) functions.
- Added JSVM helper crypto primitives under the `$security.*` namespace:
```js
$security.md5(text)
$security.sha256(text)
$security.sha512(text)
```
- ⚠️ Fill the `LastVerificationSentAt` and `LastResetSentAt` fields only after a successfull email send ([#3121](https://github.com/pocketbase/pocketbase/issues/3121)).
- ⚠️ Skip API `fields` json transformations for non 20x responses ([#3176](https://github.com/pocketbase/pocketbase/issues/3176)).
- ⚠️ Changes to `tests.ApiScenario` struct:
- The `ApiScenario.AfterTestFunc` now receive as 3rd argument `*http.Response` pointer instead of `*echo.Echo` as the latter is not really useful in this context.
```go
// old
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo)
// new
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response)
```
- The `ApiScenario.TestAppFactory` now accept the test instance as argument and no longer expect an error as return result ([#3025](https://github.com/pocketbase/pocketbase/discussions/3025#discussioncomment-6592272)).
```go
// old
TestAppFactory: func() (*tests.TestApp, error)
// new
TestAppFactory: func(t *testing.T) *tests.TestApp
```
_Returning a `nil` app instance from the factory results in test failure. You can enforce a custom test failure by calling `t.Fatal(err)` inside the factory._
- Bumped the min required TLS version to 1.2 in order to improve the cert reputation score.
- Reduced the default JSVM prewarmed pool size to 25 to reduce the initial memory consumptions (_you can manually adjust the pool size with `--hooksPool=50` if you need to, but the default should suffice for most cases_).
- Update `gocloud.dev` dependency to v0.34 and explicitly set the new `NoTempDir` fileblob option to prevent the cross-device link error introduced with v0.33.
- Other minor Admin UI and docs improvements.
## v0.17.7
- Fixed the autogenerated `down` migrations to properly revert the old collection rules in case a change was made in `up` ([#3192](https://github.com/pocketbase/pocketbase/pull/3192); thanks @impact-merlinmarek).
_Existing `down` migrations can't be fixed but that should be ok as usually the `down` migrations are rarely used against prod environments since they can cause data loss and, while not ideal, the previous old behavior of always setting the rules to `null/nil` is safer than not updating the rules at all._
- Updated some Go deps.
## v0.17.6
- Fixed JSVM `require()` file path error when using Windows-style path delimiters ([#3163](https://github.com/pocketbase/pocketbase/issues/3163#issuecomment-1685034438)).
## v0.17.5
- Added quotes around the wrapped view query columns introduced with v0.17.4.
## v0.17.4
- Fixed Views record retrieval when numeric id is used ([#3110](https://github.com/pocketbase/pocketbase/issues/3110)).
_With this fix we also now properly recognize `CAST(... as TEXT)` and `CAST(... as BOOLEAN)` as `text` and `bool` fields._
- Fixed `relation` "Cascade delete" tooltip message ([#3098](https://github.com/pocketbase/pocketbase/issues/3098)).
- Fixed jsvm error message prefix on failed migrations ([#3103](https://github.com/pocketbase/pocketbase/pull/3103); thanks @nzhenev).
- Disabled the initial Admin UI admins counter cache when there are no initial admins to allow detecting externally created accounts (eg. with the `admin` command) ([#3106](https://github.com/pocketbase/pocketbase/issues/3106)).
- Downgraded `google/go-cloud` dependency to v0.32.0 until v0.34.0 is released to prevent the `os.TempDir` `cross-device link` errors as too many users complained about it.
## v0.17.3
- Fixed Docker `cross-device link` error when creating `pb_data` backups on a local mounted volume ([#3089](https://github.com/pocketbase/pocketbase/issues/3089)).
- Fixed the error messages for relation to views ([#3090](https://github.com/pocketbase/pocketbase/issues/3090)).
- Always reserve space for the scrollbar to reduce the layout shifts in the Admin UI records listing due to the deprecated `overflow: overlay`.
- Enabled lazy loading for the Admin UI thumb images.
## v0.17.2
- Soft-deprecated `$http.send({ data: object, ... })` in favour of `$http.send({ body: rawString, ... })`
to allow sending non-JSON body with the request ([#3058](https://github.com/pocketbase/pocketbase/discussions/3058)).
The existing `data` prop will still work, but it will be recommended to use `body` instead (_to send JSON you can use `JSON.stringify(...)` as body value_).
The existing `data` prop will still work, but it is recommended to use `body` instead (_to send JSON you can use `JSON.stringify(...)` as body value_).
- Added `core.RealtimeConnectEvent.IdleTimeout` field to allow specifying a different realtime idle timeout duration per client basis ([#3054](https://github.com/pocketbase/pocketbase/discussions/3054)).
@@ -696,7 +885,7 @@
_Note2: The old index (`"field.0":null`) and filename (`"field.filename.png":null`) based suffixed syntax for deleting files is still supported._
- ! Added support for multi-match/match-all request data and collection multi-valued fields (`select`, `relation`) conditions.
- ⚠️ Added support for multi-match/match-all request data and collection multi-valued fields (`select`, `relation`) conditions.
If you want a "at least one of" type of condition, you can prefix the operator with `?`.
```js
// for each someRelA.someRelB record require the "status" field to be "active"
@@ -776,7 +965,7 @@
## v0.10.3
- ! Renamed the metadata key `original_filename` to `original-filename` due to an S3 file upload error caused by the underscore character ([#1343](https://github.com/pocketbase/pocketbase/pull/1343); thanks @yuxiang-gao).
- ⚠️ Renamed the metadata key `original_filename` to `original-filename` due to an S3 file upload error caused by the underscore character ([#1343](https://github.com/pocketbase/pocketbase/pull/1343); thanks @yuxiang-gao).
- Fixed request verification docs api url ([#1332](https://github.com/pocketbase/pocketbase/pull/1332); thanks @JoyMajumdar2001)
@@ -812,7 +1001,7 @@
- Refactored the `core.app.Bootstrap()` to be called before starting the cobra commands ([#1267](https://github.com/pocketbase/pocketbase/discussions/1267)).
- ! Changed `pocketbase.NewWithConfig(config Config)` to `pocketbase.NewWithConfig(config *Config)` and added 4 new config settings:
- ⚠️ Changed `pocketbase.NewWithConfig(config Config)` to `pocketbase.NewWithConfig(config *Config)` and added 4 new config settings:
```go
DataMaxOpenConns int // default to core.DefaultDataMaxOpenConns
DataMaxIdleConns int // default to core.DefaultDataMaxIdleConns
@@ -822,9 +1011,9 @@
- Added new helper method `core.App.IsBootstrapped()` to check the current app bootstrap state.
- ! Changed `core.NewBaseApp(dir, encryptionEnv, isDebug)` to `NewBaseApp(config *BaseAppConfig)`.
- ⚠️ Changed `core.NewBaseApp(dir, encryptionEnv, isDebug)` to `NewBaseApp(config *BaseAppConfig)`.
- ! Removed `rest.UploadedFile` struct (see below `filesystem.File`).
- ⚠️ Removed `rest.UploadedFile` struct (see below `filesystem.File`).
- Added generic file resource struct that allows loading and uploading file content from
different sources (at the moment multipart/form-data requests and from the local filesystem).
+25
View File
@@ -11,6 +11,8 @@ import (
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/forms"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/tools/filesystem"
"github.com/pocketbase/pocketbase/tools/rest"
"github.com/pocketbase/pocketbase/tools/types"
"github.com/spf13/cast"
)
@@ -24,6 +26,7 @@ func bindBackupApi(app core.App, rg *echo.Group) {
subGroup := rg.Group("/backups", ActivityLogger(app))
subGroup.GET("", api.list, RequireAdminAuth())
subGroup.POST("", api.create, RequireAdminAuth())
subGroup.POST("/upload", api.upload, RequireAdminAuth())
subGroup.GET("/:key", api.download)
subGroup.DELETE("/:key", api.delete, RequireAdminAuth())
subGroup.POST("/:key/restore", api.restore, RequireAdminAuth())
@@ -88,6 +91,28 @@ func (api *backupApi) create(c echo.Context) error {
})
}
func (api *backupApi) upload(c echo.Context) error {
files, err := rest.FindUploadedFiles(c.Request(), "file")
if err != nil {
return NewBadRequestError("Missing or invalid uploaded file.", err)
}
form := forms.NewBackupUpload(api.app)
form.File = files[0]
return form.Submit(func(next forms.InterceptorNextFunc[*filesystem.File]) forms.InterceptorNextFunc[*filesystem.File] {
return func(file *filesystem.File) error {
if err := next(file); err != nil {
return NewBadRequestError("Failed to upload backup.", err)
}
// we don't retrieve the generated backup file because it may not be
// available yet due to the eventually consistent nature of some S3 providers
return c.NoContent(http.StatusNoContent)
}
})
}
func (api *backupApi) download(c echo.Context) error {
fileToken := c.QueryParam("token")
+148 -12
View File
@@ -1,7 +1,11 @@
package apis_test
import (
"archive/zip"
"bytes"
"context"
"io"
"mime/multipart"
"net/http"
"strings"
"testing"
@@ -85,7 +89,7 @@ func TestBackupsCreate(t *testing.T) {
Name: "unauthorized",
Method: http.MethodPost,
Url: "/api/backups",
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
},
ExpectedStatus: 401,
@@ -98,7 +102,7 @@ func TestBackupsCreate(t *testing.T) {
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyMjA4OTg1MjYxfQ.UwD8JvkbQtXpymT09d7J6fdA0aP9g4FJ1GPh_ggEkzc",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
},
ExpectedStatus: 401,
@@ -114,7 +118,7 @@ func TestBackupsCreate(t *testing.T) {
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
app.Cache().Set(core.CacheKeyActiveBackup, "")
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
},
ExpectedStatus: 400,
@@ -127,7 +131,7 @@ func TestBackupsCreate(t *testing.T) {
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
files, err := getBackupFiles(app)
if err != nil {
t.Fatal(err)
@@ -152,7 +156,7 @@ func TestBackupsCreate(t *testing.T) {
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
},
ExpectedStatus: 400,
@@ -169,7 +173,7 @@ func TestBackupsCreate(t *testing.T) {
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
files, err := getBackupFiles(app)
if err != nil {
t.Fatal(err)
@@ -193,6 +197,138 @@ func TestBackupsCreate(t *testing.T) {
}
}
func TestBackupsUpload(t *testing.T) {
// create dummy form data bodies
type body struct {
buffer io.Reader
contentType string
}
bodies := make([]body, 10)
for i := 0; i < 10; i++ {
func() {
zb := new(bytes.Buffer)
zw := zip.NewWriter(zb)
if err := zw.Close(); err != nil {
t.Fatal(err)
}
b := new(bytes.Buffer)
mw := multipart.NewWriter(b)
mfw, err := mw.CreateFormFile("file", "test")
if err != nil {
t.Fatal(err)
}
if _, err := io.Copy(mfw, zb); err != nil {
t.Fatal(err)
}
mw.Close()
bodies[i] = body{
buffer: b,
contentType: mw.FormDataContentType(),
}
}()
}
// ---
scenarios := []tests.ApiScenario{
{
Name: "unauthorized",
Method: http.MethodPost,
Url: "/api/backups/upload",
Body: bodies[0].buffer,
RequestHeaders: map[string]string{
"Content-Type": bodies[0].contentType,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
},
ExpectedStatus: 401,
ExpectedContent: []string{`"data":{}`},
},
{
Name: "authorized as auth record",
Method: http.MethodPost,
Url: "/api/backups/upload",
Body: bodies[1].buffer,
RequestHeaders: map[string]string{
"Content-Type": bodies[1].contentType,
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoUmVjb3JkIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyMjA4OTg1MjYxfQ.UwD8JvkbQtXpymT09d7J6fdA0aP9g4FJ1GPh_ggEkzc",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
},
ExpectedStatus: 401,
ExpectedContent: []string{`"data":{}`},
},
{
Name: "authorized as admin (missing file)",
Method: http.MethodPost,
Url: "/api/backups/upload",
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{`},
},
{
Name: "authorized as admin (existing backup name)",
Method: http.MethodPost,
Url: "/api/backups/upload",
Body: bodies[3].buffer,
RequestHeaders: map[string]string{
"Content-Type": bodies[3].contentType,
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
fsys, err := app.NewBackupsFilesystem()
if err != nil {
t.Fatal(err)
}
defer fsys.Close()
// create a dummy backup file to simulate existing backups
if err := fsys.Upload([]byte("123"), "test"); err != nil {
t.Fatal(err)
}
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
files, _ := getBackupFiles(app)
if total := len(files); total != 1 {
t.Fatalf("Expected %d backup file, got %d", 1, total)
}
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{"file":{`},
},
{
Name: "authorized as admin (valid file)",
Method: http.MethodPost,
Url: "/api/backups/upload",
Body: bodies[4].buffer,
RequestHeaders: map[string]string{
"Content-Type": bodies[4].contentType,
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
files, _ := getBackupFiles(app)
if total := len(files); total != 1 {
t.Fatalf("Expected %d backup file, got %d", 1, total)
}
},
ExpectedStatus: 204,
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
func TestBackupsDownload(t *testing.T) {
scenarios := []tests.ApiScenario{
{
@@ -371,7 +507,7 @@ func TestBackupsDelete(t *testing.T) {
t.Fatal(err)
}
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
noTestBackupFilesChanges(t, app)
},
ExpectedStatus: 401,
@@ -389,7 +525,7 @@ func TestBackupsDelete(t *testing.T) {
t.Fatal(err)
}
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
noTestBackupFilesChanges(t, app)
},
ExpectedStatus: 401,
@@ -407,7 +543,7 @@ func TestBackupsDelete(t *testing.T) {
t.Fatal(err)
}
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
noTestBackupFilesChanges(t, app)
},
ExpectedStatus: 400,
@@ -428,7 +564,7 @@ func TestBackupsDelete(t *testing.T) {
// mock active backup with the same name to delete
app.Cache().Set(core.CacheKeyActiveBackup, "test1.zip")
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
noTestBackupFilesChanges(t, app)
},
ExpectedStatus: 400,
@@ -449,7 +585,7 @@ func TestBackupsDelete(t *testing.T) {
// mock active backup with different name
app.Cache().Set(core.CacheKeyActiveBackup, "new.zip")
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
files, err := getBackupFiles(app)
if err != nil {
t.Fatal(err)
@@ -481,7 +617,7 @@ func TestBackupsDelete(t *testing.T) {
t.Fatal(err)
}
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
files, err := getBackupFiles(app)
if err != nil {
t.Fatal(err)
+15 -13
View File
@@ -207,15 +207,15 @@ func uiCacheControl() echo.MiddlewareFunc {
}
}
const totalAdminsCacheKey = "@totalAdmins"
const hasAdminsCacheKey = "@hasAdmins"
func updateTotalAdminsCache(app core.App) error {
func updateHasAdminsCache(app core.App) error {
total, err := app.Dao().TotalAdmins()
if err != nil {
return err
}
app.Cache().Set(totalAdminsCacheKey, total)
app.Cache().Set(hasAdminsCacheKey, total > 0)
return nil
}
@@ -223,12 +223,13 @@ func updateTotalAdminsCache(app core.App) error {
// installerRedirect redirects the user to the installer admin UI page
// when the application needs some preliminary configurations to be done.
func installerRedirect(app core.App) echo.MiddlewareFunc {
// keep totalAdminsCacheKey value up-to-date
// keep hasAdminsCacheKey value up-to-date
app.OnAdminAfterCreateRequest().Add(func(data *core.AdminCreateEvent) error {
return updateTotalAdminsCache(app)
return updateHasAdminsCache(app)
})
app.OnAdminAfterDeleteRequest().Add(func(data *core.AdminDeleteEvent) error {
return updateTotalAdminsCache(app)
return updateHasAdminsCache(app)
})
return func(next echo.HandlerFunc) echo.HandlerFunc {
@@ -239,23 +240,24 @@ func installerRedirect(app core.App) echo.MiddlewareFunc {
return next(c)
}
// load into cache (if not already)
if !app.Cache().Has(totalAdminsCacheKey) {
if err := updateTotalAdminsCache(app); err != nil {
hasAdmins := cast.ToBool(app.Cache().Get(hasAdminsCacheKey))
if !hasAdmins {
// update the cache to make sure that the admin wasn't created by another process
if err := updateHasAdminsCache(app); err != nil {
return err
}
hasAdmins = cast.ToBool(app.Cache().Get(hasAdminsCacheKey))
}
totalAdmins := cast.ToInt(app.Cache().Get(totalAdminsCacheKey))
_, hasInstallerParam := c.Request().URL.Query()["installer"]
if totalAdmins == 0 && !hasInstallerParam {
if !hasAdmins && !hasInstallerParam {
// redirect to the installer page
return c.Redirect(http.StatusTemporaryRedirect, "?installer#")
}
if totalAdmins != 0 && hasInstallerParam {
if hasAdmins && hasInstallerParam {
// clear the installer param
return c.Redirect(http.StatusTemporaryRedirect, "?")
}
+19 -101
View File
@@ -12,7 +12,6 @@ import (
"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/models/schema"
"github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/list"
)
@@ -47,7 +46,7 @@ func TestCollectionsList(t *testing.T) {
ExpectedContent: []string{
`"page":1`,
`"perPage":30`,
`"totalItems":10`,
`"totalItems":11`,
`"items":[{`,
`"id":"_pb_users_auth_"`,
`"id":"v851q4r790rhknl"`,
@@ -57,6 +56,7 @@ func TestCollectionsList(t *testing.T) {
`"id":"wzlqyes4orhoygb"`,
`"id":"4d1blo5cuycfaca"`,
`"id":"9n89pl5vkct6330"`,
`"id":"ib3m2700k5hlsjz"`,
`"type":"auth"`,
`"type":"base"`,
},
@@ -75,9 +75,9 @@ func TestCollectionsList(t *testing.T) {
ExpectedContent: []string{
`"page":2`,
`"perPage":2`,
`"totalItems":10`,
`"totalItems":11`,
`"items":[{`,
`"id":"kpv709sk2lqbqk8"`,
`"id":"v9gwnfh02gjq1q0"`,
`"id":"9n89pl5vkct6330"`,
},
ExpectedEvents: map[string]int{
@@ -245,7 +245,7 @@ func TestCollectionDelete(t *testing.T) {
"OnCollectionBeforeDeleteRequest": 1,
"OnCollectionAfterDeleteRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureDeletedFiles(app, "9n89pl5vkct6330")
},
},
@@ -264,7 +264,7 @@ func TestCollectionDelete(t *testing.T) {
"OnCollectionBeforeDeleteRequest": 1,
"OnCollectionAfterDeleteRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureDeletedFiles(app, "9n89pl5vkct6330")
},
},
@@ -400,7 +400,7 @@ func TestCollectionCreate(t *testing.T) {
`"name":"new"`,
`"type":"base"`,
`"system":false`,
`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
`"options":{}`,
},
ExpectedEvents: map[string]int{
@@ -424,7 +424,7 @@ func TestCollectionCreate(t *testing.T) {
`"name":"new"`,
`"type":"auth"`,
`"system":false`,
`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
`"schema":[{"system":false,"id":"12345789","name":"test","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
`"options":{"allowEmailAuth":false,"allowOAuth2Auth":false,"allowUsernameAuth":false,"exceptEmailDomains":null,"manageRule":null,"minPasswordLength":0,"onlyEmailDomains":null,"requireEmail":false}`,
},
ExpectedEvents: map[string]int{
@@ -693,7 +693,7 @@ func TestCollectionCreate(t *testing.T) {
"OnCollectionBeforeCreateRequest": 1,
"OnCollectionAfterCreateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
indexes, err := app.Dao().TableIndexes("new")
if err != nil {
t.Fatal(err)
@@ -823,7 +823,7 @@ func TestCollectionUpdate(t *testing.T) {
"OnCollectionBeforeUpdateRequest": 1,
"OnCollectionAfterUpdateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
// check if the record table was renamed
if !app.Dao().HasTable("new") {
t.Fatal("Couldn't find record table 'new'.")
@@ -959,88 +959,6 @@ func TestCollectionUpdate(t *testing.T) {
},
},
// rel field change displayFields propagation
// -----------------------------------------------------------
{
Name: "renaming a display field should also update the referenced displayFields value",
Method: http.MethodPatch,
Url: "/api/collections/demo3",
Body: strings.NewReader(`{
"schema":[
{
"id": "w5z2x0nq",
"type": "text",
"name": "title_change"
}
]
}`),
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
ExpectedStatus: 200,
ExpectedContent: []string{
`"name":"title_change"`,
},
ExpectedEvents: map[string]int{
"OnModelBeforeUpdate": 2,
"OnModelAfterUpdate": 2,
"OnCollectionBeforeUpdateRequest": 1,
"OnCollectionAfterUpdateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
collection, err := app.Dao().FindCollectionByNameOrId("demo4")
if err != nil {
t.Fatal(err)
}
relField := collection.Schema.GetFieldByName("rel_many_no_cascade_required")
options := relField.Options.(*schema.RelationOptions)
expectedDisplayFields := []string{"title_change", "id"}
if len(list.SubtractSlice(options.DisplayFields, expectedDisplayFields)) != 0 {
t.Fatalf("Expected displayFields %v, got %v", expectedDisplayFields, options.DisplayFields)
}
},
},
{
Name: "deleting a display field should also update the referenced displayFields value",
Method: http.MethodPatch,
Url: "/api/collections/demo3",
Body: strings.NewReader(`{
"schema":[
{
"type": "text",
"name": "new_field"
}
]
}`),
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
ExpectedStatus: 200,
ExpectedContent: []string{
`"name":"new_field"`,
},
ExpectedEvents: map[string]int{
"OnModelBeforeUpdate": 2,
"OnModelAfterUpdate": 2,
"OnCollectionBeforeUpdateRequest": 1,
"OnCollectionAfterUpdateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
collection, err := app.Dao().FindCollectionByNameOrId("demo4")
if err != nil {
t.Fatal(err)
}
relField := collection.Schema.GetFieldByName("rel_many_no_cascade_required")
options := relField.Options.(*schema.RelationOptions)
expectedDisplayFields := []string{"id"}
if len(list.SubtractSlice(options.DisplayFields, expectedDisplayFields)) != 0 {
t.Fatalf("Expected displayFields %v, got %v", expectedDisplayFields, options.DisplayFields)
}
},
},
// view
// -----------------------------------------------------------
{
@@ -1142,7 +1060,7 @@ func TestCollectionUpdate(t *testing.T) {
"OnCollectionBeforeUpdateRequest": 1,
"OnCollectionAfterUpdateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
indexes, err := app.Dao().TableIndexes("new")
if err != nil {
t.Fatal(err)
@@ -1164,7 +1082,7 @@ func TestCollectionUpdate(t *testing.T) {
}
func TestCollectionsImport(t *testing.T) {
totalCollections := 10
totalCollections := 11
scenarios := []tests.ApiScenario{
{
@@ -1197,7 +1115,7 @@ func TestCollectionsImport(t *testing.T) {
`"data":{`,
`"collections":{"code":"validation_required"`,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
collections := []*models.Collection{}
if err := app.Dao().CollectionQuery().All(&collections); err != nil {
t.Fatal(err)
@@ -1225,7 +1143,7 @@ func TestCollectionsImport(t *testing.T) {
"OnCollectionsBeforeImportRequest": 1,
"OnModelBeforeDelete": 4,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
collections := []*models.Collection{}
if err := app.Dao().CollectionQuery().All(&collections); err != nil {
t.Fatal(err)
@@ -1267,7 +1185,7 @@ func TestCollectionsImport(t *testing.T) {
"OnCollectionsBeforeImportRequest": 1,
"OnModelBeforeCreate": 2,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
collections := []*models.Collection{}
if err := app.Dao().CollectionQuery().All(&collections); err != nil {
t.Fatal(err)
@@ -1323,7 +1241,7 @@ func TestCollectionsImport(t *testing.T) {
"OnModelBeforeCreate": 3,
"OnModelAfterCreate": 3,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
collections := []*models.Collection{}
if err := app.Dao().CollectionQuery().All(&collections); err != nil {
t.Fatal(err)
@@ -1421,14 +1339,14 @@ func TestCollectionsImport(t *testing.T) {
ExpectedEvents: map[string]int{
"OnCollectionsAfterImportRequest": 1,
"OnCollectionsBeforeImportRequest": 1,
"OnModelBeforeDelete": 8,
"OnModelAfterDelete": 8,
"OnModelBeforeDelete": 9,
"OnModelAfterDelete": 9,
"OnModelBeforeUpdate": 2,
"OnModelAfterUpdate": 2,
"OnModelBeforeCreate": 1,
"OnModelAfterCreate": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
collections := []*models.Collection{}
if err := app.Dao().CollectionQuery().All(&collections); err != nil {
t.Fatal(err)
+5 -3
View File
@@ -287,8 +287,10 @@ func ActivityLogger(app core.App) echo.MiddlewareFunc {
return func(c echo.Context) error {
err := next(c)
logsMaxDays := app.Settings().Logs.MaxDays
// no logs retention
if app.Settings().Logs.MaxDays == 0 {
if logsMaxDays == 0 {
return err
}
@@ -348,8 +350,8 @@ func ActivityLogger(app core.App) echo.MiddlewareFunc {
lastLogsDeletedAt := cast.ToTime(app.Cache().Get("lastLogsDeletedAt"))
daysDiff := now.Sub(lastLogsDeletedAt).Hours() * 24
if daysDiff > float64(app.Settings().Logs.MaxDays) {
deleteErr := app.LogsDao().DeleteOldRequests(now.AddDate(0, 0, -1*app.Settings().Logs.MaxDays))
if daysDiff > float64(logsMaxDays) {
deleteErr := app.LogsDao().DeleteOldRequests(now.AddDate(0, 0, -1*logsMaxDays))
if deleteErr == nil {
app.Cache().Set("lastLogsDeletedAt", now)
} else if app.IsDebug() {
+8 -8
View File
@@ -34,7 +34,7 @@ func TestRealtimeConnect(t *testing.T) {
"OnRealtimeAfterMessageSend": 1,
"OnRealtimeDisconnectRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
if len(app.SubscriptionsBroker().Clients()) != 0 {
t.Errorf("Expected the subscribers to be removed after connection close, found %d", len(app.SubscriptionsBroker().Clients()))
}
@@ -58,7 +58,7 @@ func TestRealtimeConnect(t *testing.T) {
return nil
})
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
if len(app.SubscriptionsBroker().Clients()) != 0 {
t.Errorf("Expected the subscribers to be removed after connection close, found %d", len(app.SubscriptionsBroker().Clients()))
}
@@ -79,7 +79,7 @@ func TestRealtimeConnect(t *testing.T) {
return hook.StopPropagation
})
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
if len(app.SubscriptionsBroker().Clients()) != 0 {
t.Errorf("Expected the subscribers to be removed after connection close, found %d", len(app.SubscriptionsBroker().Clients()))
}
@@ -124,7 +124,7 @@ func TestRealtimeSubscribe(t *testing.T) {
client.Subscribe("test0")
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
if len(client.Subscriptions()) != 0 {
t.Errorf("Expected no subscriptions, got %v", client.Subscriptions())
}
@@ -145,7 +145,7 @@ func TestRealtimeSubscribe(t *testing.T) {
client.Subscribe("test0")
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
expectedSubs := []string{"test1", "test2"}
if len(expectedSubs) != len(client.Subscriptions()) {
t.Errorf("Expected subscriptions %v, got %v", expectedSubs, client.Subscriptions())
@@ -175,7 +175,7 @@ func TestRealtimeSubscribe(t *testing.T) {
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
admin, _ := client.Get(apis.ContextAdminKey).(*models.Admin)
if admin == nil {
t.Errorf("Expected admin auth model, got nil")
@@ -199,7 +199,7 @@ func TestRealtimeSubscribe(t *testing.T) {
BeforeTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
authRecord, _ := client.Get(apis.ContextAuthRecordKey).(*models.Record)
if authRecord == nil {
t.Errorf("Expected auth record model, got nil")
@@ -224,7 +224,7 @@ func TestRealtimeSubscribe(t *testing.T) {
app.SubscriptionsBroker().Register(client)
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
authRecord, _ := client.Get(apis.ContextAuthRecordKey).(*models.Record)
if authRecord == nil {
t.Errorf("Expected auth record model, got nil")
+2 -2
View File
@@ -1188,7 +1188,7 @@ func TestRecordAuthUnlinkExternalsAuth(t *testing.T) {
"OnRecordAfterUnlinkExternalAuthRequest": 1,
"OnRecordBeforeUnlinkExternalAuthRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
record, err := app.Dao().FindRecordById("users", "4q1xlclmfloku33")
if err != nil {
t.Fatal(err)
@@ -1234,7 +1234,7 @@ func TestRecordAuthUnlinkExternalsAuth(t *testing.T) {
"OnRecordAfterUnlinkExternalAuthRequest": 1,
"OnRecordBeforeUnlinkExternalAuthRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
record, err := app.Dao().FindRecordById("users", "4q1xlclmfloku33")
if err != nil {
t.Fatal(err)
+31 -5
View File
@@ -462,6 +462,22 @@ func TestRecordCrudList(t *testing.T) {
},
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
},
{
Name: "view collection with numeric ids",
Method: http.MethodGet,
Url: "/api/collections/numeric_id_view/records",
ExpectedStatus: 200,
ExpectedContent: []string{
`"page":1`,
`"perPage":30`,
`"totalPages":1`,
`"totalItems":2`,
`"items":[{`,
`"id":"1"`,
`"id":"2"`,
},
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
},
}
for _, scenario := range scenarios {
@@ -731,6 +747,16 @@ func TestRecordCrudView(t *testing.T) {
},
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
},
{
Name: "view record with numeric id",
Method: http.MethodGet,
Url: "/api/collections/numeric_id_view/records/1",
ExpectedStatus: 200,
ExpectedContent: []string{
`"id":"1"`,
},
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
},
}
for _, scenario := range scenarios {
@@ -877,7 +903,7 @@ func TestRecordCrudDelete(t *testing.T) {
"OnRecordAfterDeleteRequest": 1,
"OnRecordBeforeDeleteRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
ensureDeletedFiles(app, "_pb_users_auth_", "4q1xlclmfloku33")
// check if all the external auths records were deleted
@@ -964,7 +990,7 @@ func TestRecordCrudDelete(t *testing.T) {
"OnRecordBeforeDeleteRequest": 1,
"OnRecordAfterDeleteRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
recId := "84nmscqy84lsi1t"
rec, _ := app.Dao().FindRecordById("demo1", recId, nil)
if rec != nil {
@@ -2006,7 +2032,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"OnRecordAfterUpdateRequest": 1,
"OnRecordBeforeUpdateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
record, _ := app.Dao().FindRecordById("nologin", "phhq3wr65cap535")
if !record.ValidatePassword("12345678") {
t.Fatal("Password update failed.")
@@ -2049,7 +2075,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"OnRecordAfterUpdateRequest": 1,
"OnRecordBeforeUpdateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
record, _ := app.Dao().FindRecordById("users", "oap640cot4yru2s")
if !record.ValidatePassword("12345678") {
t.Fatal("Password update failed.")
@@ -2111,7 +2137,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"OnRecordAfterUpdateRequest": 1,
"OnRecordBeforeUpdateRequest": 1,
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
record, _ := app.Dao().FindRecordById("nologin", "dc49k6jgejn40h3")
if !record.ValidatePassword("123456789") {
t.Fatal("Password update failed.")
+70 -7
View File
@@ -11,11 +11,13 @@ import (
"time"
"github.com/fatih/color"
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/middleware"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/migrations"
"github.com/pocketbase/pocketbase/migrations/logs"
"github.com/pocketbase/pocketbase/tools/list"
"github.com/pocketbase/pocketbase/tools/migrate"
"golang.org/x/crypto/acme"
"golang.org/x/crypto/acme/autocert"
@@ -26,17 +28,35 @@ type ServeConfig struct {
// ShowStartBanner indicates whether to show or hide the server start console message.
ShowStartBanner bool
// HttpAddr is the HTTP server address to bind (eg. `127.0.0.1:80`).
// HttpAddr is the TCP address to listen for the HTTP server (eg. `127.0.0.1:80`).
HttpAddr string
// HttpsAddr is the HTTPS server address to bind (eg. `127.0.0.1:443`).
// HttpsAddr is the TCP address to listen for the HTTPS server (eg. `127.0.0.1:443`).
HttpsAddr string
// Optional domains list to use when issuing the TLS certificate.
//
// If not set, the host from the bound server address will be used.
//
// For convenience, for each "non-www" domain a "www" entry and
// redirect will be automatically added.
CertificateDomains []string
// AllowedOrigins is an optional list of CORS origins (default to "*").
AllowedOrigins []string
}
// Serve starts a new app web server.
//
// NB! The app should be bootstrapped before starting the web server.
//
// Example:
//
// app.Bootstrap()
// apis.Serve(app, apis.ServeConfig{
// HttpAddr: "127.0.0.1:8080",
// ShowStartBanner: false,
// })
func Serve(app core.App, config ServeConfig) (*http.Server, error) {
if len(config.AllowedOrigins) == 0 {
config.AllowedOrigins = []string{"*"}
@@ -75,16 +95,53 @@ func Serve(app core.App, config ServeConfig) (*http.Server, error) {
mainAddr = config.HttpsAddr
}
mainHost, _, _ := net.SplitHostPort(mainAddr)
var wwwRedirects []string
// extract the host names for the certificate host policy
hostNames := config.CertificateDomains
if len(hostNames) == 0 {
host, _, _ := net.SplitHostPort(mainAddr)
hostNames = append(hostNames, host)
}
for _, host := range hostNames {
if strings.HasPrefix(host, "www.") {
continue // explicitly set www host
}
wwwHost := "www." + host
if !list.ExistInSlice(wwwHost, hostNames) {
hostNames = append(hostNames, wwwHost)
wwwRedirects = append(wwwRedirects, wwwHost)
}
}
// implicit www->non-www redirect(s)
if len(wwwRedirects) > 0 {
router.Pre(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
host := c.Request().Host
if strings.HasPrefix(host, "www.") && list.ExistInSlice(host, wwwRedirects) {
return c.Redirect(
http.StatusTemporaryRedirect,
(c.Scheme() + "://" + host[4:] + c.Request().RequestURI),
)
}
return next(c)
}
})
}
certManager := &autocert.Manager{
Prompt: autocert.AcceptTOS,
Cache: autocert.DirCache(filepath.Join(app.DataDir(), ".autocert_cache")),
HostPolicy: autocert.HostWhitelist(mainHost, "www."+mainHost),
HostPolicy: autocert.HostWhitelist(hostNames...),
}
server := &http.Server{
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
GetCertificate: certManager.GetCertificate,
NextProtos: []string{acme.ALPNProto},
},
@@ -107,8 +164,14 @@ func Serve(app core.App, config ServeConfig) (*http.Server, error) {
if config.ShowStartBanner {
schema := "http"
addr := server.Addr
if config.HttpsAddr != "" {
schema = "https"
if len(config.CertificateDomains) > 0 {
addr = config.CertificateDomains[0]
}
}
date := new(strings.Builder)
@@ -118,12 +181,12 @@ func Serve(app core.App, config ServeConfig) (*http.Server, error) {
bold.Printf(
"%s Server started at %s\n",
strings.TrimSpace(date.String()),
color.CyanString("%s://%s", schema, server.Addr),
color.CyanString("%s://%s", schema, addr),
)
regular := color.New()
regular.Printf("├─ REST API: %s\n", color.CyanString("%s://%s/api/", schema, server.Addr))
regular.Printf("└─ Admin UI: %s\n", color.CyanString("%s://%s/_/", schema, server.Addr))
regular.Printf("├─ REST API: %s\n", color.CyanString("%s://%s/api/", schema, addr))
regular.Printf("└─ Admin UI: %s\n", color.CyanString("%s://%s/_/", schema, addr))
}
// try to gracefully shutdown the server on app termination
+3 -3
View File
@@ -400,7 +400,7 @@ func TestSettingsTestEmail(t *testing.T) {
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend != 1 {
t.Fatalf("[verification] Expected 1 sent email, got %d", app.TestMailer.TotalSend)
}
@@ -435,7 +435,7 @@ func TestSettingsTestEmail(t *testing.T) {
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend != 1 {
t.Fatalf("[password-reset] Expected 1 sent email, got %d", app.TestMailer.TotalSend)
}
@@ -470,7 +470,7 @@ func TestSettingsTestEmail(t *testing.T) {
RequestHeaders: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhZG1pbiIsImV4cCI6MjIwODk4NTI2MX0.M1m--VOqGyv0d23eeUc0r9xE8ZzHaYVmVFw1VZW6gT8",
},
AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) {
AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend != 1 {
t.Fatalf("[email-change] Expected 1 sent email, got %d", app.TestMailer.TotalSend)
}
+25 -9
View File
@@ -17,14 +17,30 @@ func NewServeCommand(app core.App, showStartBanner bool) *cobra.Command {
var httpsAddr string
command := &cobra.Command{
Use: "serve",
Short: "Starts the web server (default to 127.0.0.1:8090)",
Use: "serve [domain(s)]",
Args: cobra.ArbitraryArgs,
Short: "Starts the web server (default to 127.0.0.1:8090 if no domain is specified)",
Run: func(command *cobra.Command, args []string) {
// set default listener addresses if at least one domain is specified
if len(args) > 0 {
if httpAddr == "" {
httpAddr = "0.0.0.0:80"
}
if httpsAddr == "" {
httpsAddr = "0.0.0.0:443"
}
} else {
if httpAddr == "" {
httpAddr = "127.0.0.1:8090"
}
}
_, err := apis.Serve(app, apis.ServeConfig{
HttpAddr: httpAddr,
HttpsAddr: httpsAddr,
ShowStartBanner: showStartBanner,
AllowedOrigins: allowedOrigins,
HttpAddr: httpAddr,
HttpsAddr: httpsAddr,
ShowStartBanner: showStartBanner,
AllowedOrigins: allowedOrigins,
CertificateDomains: args,
})
if err != http.ErrServerClosed {
@@ -43,15 +59,15 @@ func NewServeCommand(app core.App, showStartBanner bool) *cobra.Command {
command.PersistentFlags().StringVar(
&httpAddr,
"http",
"127.0.0.1:8090",
"api HTTP server address",
"",
"TCP address to listen for the HTTP server\n(if domain args are specified - default to 0.0.0.0:80, otherwise - default to 127.0.0.1:8090)",
)
command.PersistentFlags().StringVar(
&httpsAddr,
"https",
"",
"api HTTPS server address (auto TLS via Let's Encrypt)\nthe incoming --http address traffic also will be redirected to this address",
"TCP address to listen for the HTTPS server\n(if domain args are specified - default to 0.0.0.0:443, otherwise - default to empty string, aka. no TLS)\nThe incoming HTTP traffic also will be auto redirected to the HTTPS version",
)
return command
+1 -1
View File
@@ -375,7 +375,6 @@ func (app *BaseApp) ResetBootstrapState() error {
app.dao = nil
app.logsDao = nil
app.settings = nil
return nil
}
@@ -471,6 +470,7 @@ func (app *BaseApp) NewMailClient() mailer.Mailer {
Password: app.Settings().Smtp.Password,
Tls: app.Settings().Smtp.Tls,
AuthMethod: app.Settings().Smtp.AuthMethod,
LocalName: app.Settings().Smtp.LocalName,
}
}
+43 -27
View File
@@ -17,6 +17,7 @@ import (
"github.com/pocketbase/pocketbase/tools/archive"
"github.com/pocketbase/pocketbase/tools/cron"
"github.com/pocketbase/pocketbase/tools/filesystem"
"github.com/pocketbase/pocketbase/tools/inflector"
"github.com/pocketbase/pocketbase/tools/osutils"
"github.com/pocketbase/pocketbase/tools/security"
)
@@ -46,27 +47,31 @@ func (app *BaseApp) CreateBackup(ctx context.Context, name string) error {
return errors.New("try again later - another backup/restore operation has already been started")
}
// auto generate backup name
if name == "" {
name = fmt.Sprintf(
"pb_backup_%s.zip",
time.Now().UTC().Format("20060102150405"),
)
name = app.generateBackupName("pb_backup_")
}
app.Cache().Set(CacheKeyActiveBackup, name)
defer app.Cache().Remove(CacheKeyActiveBackup)
// Archive pb_data in a temp directory, exluding the "backups" dir itself (if exist).
// root dir entries to exclude from the backup generation
exclude := []string{LocalBackupsDirName, LocalTempDirName}
// make sure that the special temp directory exists
// note: it needs to be inside the current pb_data to avoid "cross-device link" errors
localTempDir := filepath.Join(app.DataDir(), LocalTempDirName)
if err := os.MkdirAll(localTempDir, os.ModePerm); err != nil {
return fmt.Errorf("failed to create a temp dir: %w", err)
}
// Archive pb_data in a temp directory, exluding the "backups" and the temp dirs.
//
// Run in transaction to temporary block other writes (transactions uses the NonconcurrentDB connection).
// ---
tempPath := filepath.Join(os.TempDir(), "pb_backup_"+security.PseudorandomString(4))
tempPath := filepath.Join(localTempDir, "pb_backup_"+security.PseudorandomString(4))
createErr := app.Dao().RunInTransaction(func(txDao *daos.Dao) error {
if err := archive.Create(app.DataDir(), tempPath, LocalBackupsDirName); err != nil {
return err
}
return nil
// @todo consider experimenting with temp switching the readonly pragma after the db interface change
return archive.Create(app.DataDir(), tempPath, exclude...)
})
if createErr != nil {
return createErr
@@ -152,7 +157,15 @@ func (app *BaseApp) RestoreBackup(ctx context.Context, name string) error {
}
defer br.Close()
tempZip, err := os.CreateTemp(os.TempDir(), "pb_restore")
// make sure that the special temp directory exists
// note: it needs to be inside the current pb_data to avoid "cross-device link" errors
localTempDir := filepath.Join(app.DataDir(), LocalTempDirName)
if err := os.MkdirAll(localTempDir, os.ModePerm); err != nil {
return fmt.Errorf("failed to create a temp dir: %w", err)
}
// create a temp zip file from the blob.Reader and try to extract it
tempZip, err := os.CreateTemp(localTempDir, "pb_restore_zip")
if err != nil {
return err
}
@@ -162,13 +175,7 @@ func (app *BaseApp) RestoreBackup(ctx context.Context, name string) error {
return err
}
// make sure that the special temp directory
if err := os.MkdirAll(filepath.Join(app.DataDir(), LocalTempDirName), os.ModePerm); err != nil {
return fmt.Errorf("failed to create a temp dir: %w", err)
}
// note: it needs to be inside the current pb_data to avoid "cross-device link" errors
extractedDataDir := filepath.Join(app.DataDir(), LocalTempDirName, "pb_restore_"+security.PseudorandomString(4))
extractedDataDir := filepath.Join(localTempDir, "pb_restore_"+security.PseudorandomString(4))
defer os.RemoveAll(extractedDataDir)
if err := archive.Extract(tempZip.Name(), extractedDataDir); err != nil {
return err
@@ -192,7 +199,7 @@ func (app *BaseApp) RestoreBackup(ctx context.Context, name string) error {
// move the current pb_data content to a special temp location
// that will hold the old data between dirs replace
// (the temp dir will be automatically removed on the next app start)
oldTempDataDir := filepath.Join(app.DataDir(), LocalTempDirName, "old_pb_data_"+security.PseudorandomString(4))
oldTempDataDir := filepath.Join(localTempDir, "old_pb_data_"+security.PseudorandomString(4))
if err := osutils.MoveDirContent(app.DataDir(), oldTempDataDir, exclude...); err != nil {
return fmt.Errorf("failed to move the current pb_data content to a temp location: %w", err)
}
@@ -227,7 +234,6 @@ func (app *BaseApp) RestoreBackup(ctx context.Context, name string) error {
}
// initAutobackupHooks registers the autobackup app serve hooks.
// @todo add tests
func (app *BaseApp) initAutobackupHooks() error {
c := cron.New()
isServe := false
@@ -241,13 +247,9 @@ func (app *BaseApp) initAutobackupHooks() error {
}
c.Add("@autobackup", rawSchedule, func() {
autoPrefix := "@auto_pb_backup_"
const autoPrefix = "@auto_pb_backup_"
name := fmt.Sprintf(
"%s%s.zip",
autoPrefix,
time.Now().UTC().Format("20060102150405"),
)
name := app.generateBackupName(autoPrefix)
if err := app.CreateBackup(context.Background(), name); err != nil && app.IsDebug() {
// @todo replace after logs generalization
@@ -326,3 +328,17 @@ func (app *BaseApp) initAutobackupHooks() error {
return nil
}
func (app *BaseApp) generateBackupName(prefix string) string {
appName := inflector.Snakecase(app.Settings().Meta.AppName)
if len(appName) > 50 {
appName = appName[:50]
}
return fmt.Sprintf(
"%s%s_%s.zip",
prefix,
appName,
time.Now().UTC().Format("20060102150405"),
)
}
+7 -2
View File
@@ -19,6 +19,11 @@ func TestCreateBackup(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
// set some long app name with spaces and special characters
app.Settings().Meta.AppName = "test @! " + strings.Repeat("a", 100)
expectedAppNamePrefix := "test_" + strings.Repeat("a", 45)
// test pending error
app.Cache().Set(core.CacheKeyActiveBackup, "")
if err := app.CreateBackup(context.Background(), "test.zip"); err == nil {
@@ -49,8 +54,8 @@ func TestCreateBackup(t *testing.T) {
}
expectedFiles := []string{
`^pb_backup_\w+\.zip$`,
`^pb_backup_\w+\.zip.attrs$`,
`^pb_backup_` + expectedAppNamePrefix + `_\w+\.zip$`,
`^pb_backup_` + expectedAppNamePrefix + `_\w+\.zip.attrs$`,
"custom",
"custom.attrs",
}
-4
View File
@@ -118,10 +118,6 @@ func TestBaseAppBootstrap(t *testing.T) {
if app.logsDao != nil {
t.Fatalf("Expected app.logsDao to be nil, got %v.", app.logsDao)
}
if app.settings != nil {
t.Fatalf("Expected app.settings to be nil, got %v.", app.settings)
}
}
func TestBaseAppGetters(t *testing.T) {
+52
View File
@@ -378,6 +378,12 @@ func (dao *Dao) saveViewCollection(newCollection, oldCollection *models.Collecti
}
}
// wrap view query if necessary
query, err = txDao.normalizeViewQueryId(query)
if err != nil {
return fmt.Errorf("failed to normalize view query id: %w", err)
}
// (re)create the view
if err := txDao.SaveView(newCollection.Name, query); err != nil {
return err
@@ -389,6 +395,52 @@ func (dao *Dao) saveViewCollection(newCollection, oldCollection *models.Collecti
})
}
// @todo consider removing once custom id types are supported
//
// normalizeViewQueryId wraps (if necessary) the provided view query
// with a subselect to ensure that the id column is a text since
// currently we don't support non-string model ids
// (see https://github.com/pocketbase/pocketbase/issues/3110).
func (dao *Dao) normalizeViewQueryId(query string) (string, error) {
parsed, err := dao.parseQueryToFields(query)
if err != nil {
return "", err
}
needWrapping := true
idField := parsed[schema.FieldNameId]
if idField != nil && idField.field != nil &&
idField.field.Type != schema.FieldTypeJson &&
idField.field.Type != schema.FieldTypeNumber &&
idField.field.Type != schema.FieldTypeBool {
needWrapping = false
}
if !needWrapping {
return query, nil // no changes needed
}
// raw parse to preserve the columns order
rawParsed := new(identifiersParser)
if err := rawParsed.parse(query); err != nil {
return "", err
}
columns := make([]string, 0, len(rawParsed.columns))
for _, col := range rawParsed.columns {
if col.alias == schema.FieldNameId {
columns = append(columns, fmt.Sprintf("cast([[%s]] as text) [[%s]]", col.alias, col.alias))
} else {
columns = append(columns, "[["+col.alias+"]]")
}
}
query = fmt.Sprintf("SELECT %s FROM (%s)", strings.Join(columns, ","), query)
return query, nil
}
// resaveViewsWithChangedSchema updates all view collections with changed schemas.
func (dao *Dao) resaveViewsWithChangedSchema(excludeIds ...string) error {
collections, err := dao.FindCollectionsByType(models.CollectionTypeView)
+113 -3
View File
@@ -210,11 +210,12 @@ func TestDeleteCollection(t *testing.T) {
{colUnsaved, true},
{colReferenced, true},
{colSystem, true},
{colBase, true}, // depend on view1, view2 and view2
{colView1, true}, // view2 depend on it
{colView2, false},
{colView1, false}, // no longer has dependent collections
{colBase, false},
{colAuth, false}, // should delete also its related external auths
{colBase, false}, // no longer has dependent views
{colAuth, false}, // should delete also its related external auths
}
for i, s := range scenarios {
@@ -393,8 +394,117 @@ func TestSaveCollectionIndirectViewsUpdate(t *testing.T) {
}
}
func TestSaveCollectionViewWrapping(t *testing.T) {
viewName := "test_wrapping"
scenarios := []struct {
name string
query string
expected string
}{
{
"no wrapping - text field",
"select text as id, bool from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select text as id, bool from demo1)",
},
{
"no wrapping - id field",
"select text as id, bool from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select text as id, bool from demo1)",
},
{
"no wrapping - relation field",
"select rel_one as id, bool from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select rel_one as id, bool from demo1)",
},
{
"no wrapping - select field",
"select select_many as id, bool from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select select_many as id, bool from demo1)",
},
{
"no wrapping - email field",
"select email as id, bool from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select email as id, bool from demo1)",
},
{
"no wrapping - datetime field",
"select datetime as id, bool from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select datetime as id, bool from demo1)",
},
{
"no wrapping - url field",
"select url as id, bool from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select url as id, bool from demo1)",
},
{
"wrapping - bool field",
"select bool as id, text as txt, url from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (SELECT cast(`id` as text) `id`,`txt`,`url` FROM (select bool as id, text as txt, url from demo1))",
},
{
"wrapping - bool field (different order)",
"select text as txt, url, bool as id from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (SELECT `txt`,`url`,cast(`id` as text) `id` FROM (select text as txt, url, bool as id from demo1))",
},
{
"wrapping - json field",
"select json as id, text, url from demo1",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (SELECT cast(`id` as text) `id`,`text`,`url` FROM (select json as id, text, url from demo1))",
},
{
"wrapping - numeric id",
"select 1 as id",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (SELECT cast(`id` as text) `id` FROM (select 1 as id))",
},
{
"wrapping - expresion",
"select ('test') as id",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (SELECT cast(`id` as text) `id` FROM (select ('test') as id))",
},
{
"no wrapping - cast as text",
"select cast('test' as text) as id",
"CREATE VIEW `test_wrapping` AS SELECT * FROM (select cast('test' as text) as id)",
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
collection := &models.Collection{
Name: viewName,
Type: models.CollectionTypeView,
Options: types.JsonMap{
"query": s.query,
},
}
err := app.Dao().SaveCollection(collection)
if err != nil {
t.Fatal(err)
}
var sql string
rowErr := app.Dao().DB().NewQuery("SELECT sql FROM sqlite_master WHERE type='view' AND name={:name}").
Bind(dbx.Params{"name": viewName}).
Row(&sql)
if rowErr != nil {
t.Fatalf("Failed to retrieve view sql: %v", rowErr)
}
if sql != s.expected {
t.Fatalf("Expected query \n%v, \ngot \n%v", s.expected, sql)
}
})
}
}
func TestImportCollections(t *testing.T) {
totalCollections := 10
totalCollections := 11
scenarios := []struct {
name string
+25 -10
View File
@@ -252,23 +252,31 @@ func (dao *Dao) FindFirstRecordByData(
// FindRecordsByFilter returns limit number of records matching the
// provided string filter.
//
// NB! Use the last "params" argument to bind untrusted user variables!
//
// The sort argument is optional and can be empty string OR the same format
// used in the web APIs, eg. "-created,title".
//
// If the limit argument is <= 0, no limit is applied to the query and
// all matching records are returned.
//
// NB! Don't put untrusted user input in the filter string as it
// practically would allow the users to inject their own custom filter.
//
// Example:
//
// dao.FindRecordsByFilter("posts", "title ~ 'lorem ipsum' && visible = true", "-created", 10)
// dao.FindRecordsByFilter(
// "posts",
// "title ~ {:title} && visible = {:visible}",
// "-created",
// 10,
// 0,
// dbx.Params{"title": "lorem ipsum", "visible": true}
// )
func (dao *Dao) FindRecordsByFilter(
collectionNameOrId string,
filter string,
sort string,
limit int,
offset int,
params ...dbx.Params,
) ([]*models.Record, error) {
collection, err := dao.FindCollectionByNameOrId(collectionNameOrId)
if err != nil {
@@ -286,7 +294,7 @@ func (dao *Dao) FindRecordsByFilter(
true, // allow searching hidden/protected fields like "email"
)
expr, err := search.FilterData(filter).BuildExpr(resolver)
expr, err := search.FilterData(filter).BuildExpr(resolver, params...)
if err != nil || expr == nil {
return nil, errors.New("invalid or empty filter expression")
}
@@ -307,6 +315,10 @@ func (dao *Dao) FindRecordsByFilter(
resolver.UpdateQuery(q) // attaches any adhoc joins and aliases
// ---
if offset > 0 {
q.Offset(int64(offset))
}
if limit > 0 {
q.Limit(int64(limit))
}
@@ -322,14 +334,17 @@ func (dao *Dao) FindRecordsByFilter(
// FindFirstRecordByFilter returns the first available record matching the provided filter.
//
// NB! Don't put untrusted user input in the filter string as it
// practically would allow the users to inject their own custom filter.
// NB! Use the last params argument to bind untrusted user variables!
//
// Example:
//
// dao.FindFirstRecordByFilter("posts", "slug='test'")
func (dao *Dao) FindFirstRecordByFilter(collectionNameOrId string, filter string) (*models.Record, error) {
result, err := dao.FindRecordsByFilter(collectionNameOrId, filter, "", 1)
// dao.FindFirstRecordByFilter("posts", "slug={:slug} && status='public'", dbx.Params{"slug": "test"})
func (dao *Dao) FindFirstRecordByFilter(
collectionNameOrId string,
filter string,
params ...dbx.Params,
) (*models.Record, error) {
result, err := dao.FindRecordsByFilter(collectionNameOrId, filter, "", 1, 0, params...)
if err != nil {
return nil, err
}
-49
View File
@@ -10,7 +10,6 @@ import (
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/models/schema"
"github.com/pocketbase/pocketbase/tools/dbutils"
"github.com/pocketbase/pocketbase/tools/list"
"github.com/pocketbase/pocketbase/tools/security"
)
@@ -159,10 +158,6 @@ func (dao *Dao) SyncRecordTableSchema(newCollection *models.Collection, oldColle
return err
}
if err := txDao.syncRelationDisplayFieldsChanges(newCollection, renamedFieldNames, deletedFieldNames); err != nil {
return err
}
return txDao.createCollectionIndexes(newCollection)
})
}
@@ -294,50 +289,6 @@ func (dao *Dao) normalizeSingleVsMultipleFieldChanges(newCollection, oldCollecti
})
}
func (dao *Dao) syncRelationDisplayFieldsChanges(collection *models.Collection, renamedFieldNames map[string]string, deletedFieldNames []string) error {
if len(renamedFieldNames) == 0 && len(deletedFieldNames) == 0 {
return nil // nothing to sync
}
refs, err := dao.FindCollectionReferences(collection)
if err != nil {
return err
}
for refCollection, refFields := range refs {
for _, refField := range refFields {
options, _ := refField.Options.(*schema.RelationOptions)
if options == nil {
continue
}
// remove deleted (if any)
newDisplayFields := list.SubtractSlice(options.DisplayFields, deletedFieldNames)
for old, new := range renamedFieldNames {
for i, name := range newDisplayFields {
if name == old {
newDisplayFields[i] = new
}
}
}
// has changes
if len(list.SubtractSlice(options.DisplayFields, newDisplayFields)) > 0 {
options.DisplayFields = newDisplayFields
// direct collection save to prevent self-referencing
// recursion and unnecessary records table sync checks
if err := dao.Save(refCollection); err != nil {
return err
}
}
}
}
return nil
}
func (dao *Dao) dropCollectionIndex(collection *models.Collection) error {
if collection.IsView() {
return nil // views don't have indexes
+71 -28
View File
@@ -436,6 +436,8 @@ func TestFindRecordsByFilter(t *testing.T) {
filter string
sort string
limit int
offset int
params []dbx.Params
expectError bool
expectRecordIds []string
}{
@@ -445,6 +447,8 @@ func TestFindRecordsByFilter(t *testing.T) {
"id != ''",
"",
0,
0,
nil,
true,
nil,
},
@@ -454,6 +458,8 @@ func TestFindRecordsByFilter(t *testing.T) {
"",
"",
0,
0,
nil,
true,
nil,
},
@@ -463,6 +469,8 @@ func TestFindRecordsByFilter(t *testing.T) {
"someMissingField > 1",
"",
0,
0,
nil,
true,
nil,
},
@@ -472,6 +480,8 @@ func TestFindRecordsByFilter(t *testing.T) {
"id != ''",
"",
0,
0,
nil,
false,
[]string{
"llvuca81nly1qls",
@@ -485,6 +495,8 @@ func TestFindRecordsByFilter(t *testing.T) {
"id != '' && active=true",
"-created,title",
-1, // should behave the same as 0
0,
nil,
false,
[]string{
"0yxhwia2amd8gec",
@@ -492,47 +504,64 @@ func TestFindRecordsByFilter(t *testing.T) {
},
},
{
"with limit",
"with limit and offset",
"demo2",
"id != ''",
"title",
2,
1,
nil,
false,
[]string{
"achvryl401bhse3",
"0yxhwia2amd8gec",
},
},
{
"with placeholder params",
"demo2",
"active = {:active}",
"",
10,
0,
[]dbx.Params{{"active": false}},
false,
[]string{
"llvuca81nly1qls",
"achvryl401bhse3",
},
},
}
for _, s := range scenarios {
records, err := app.Dao().FindRecordsByFilter(
s.collectionIdOrName,
s.filter,
s.sort,
s.limit,
)
t.Run(s.name, func(t *testing.T) {
records, err := app.Dao().FindRecordsByFilter(
s.collectionIdOrName,
s.filter,
s.sort,
s.limit,
s.offset,
s.params...,
)
hasErr := err != nil
if hasErr != s.expectError {
t.Errorf("[%s] Expected hasErr to be %v, got %v (%v)", s.name, s.expectError, hasErr, err)
continue
}
if hasErr {
continue
}
if len(records) != len(s.expectRecordIds) {
t.Errorf("[%s] Expected %d records, got %d", s.name, len(s.expectRecordIds), len(records))
continue
}
for i, id := range s.expectRecordIds {
if id != records[i].Id {
t.Errorf("[%s] Expected record with id %q, got %q at index %d", s.name, id, records[i].Id, i)
hasErr := err != nil
if hasErr != s.expectError {
t.Fatalf("[%s] Expected hasErr to be %v, got %v (%v)", s.name, s.expectError, hasErr, err)
}
}
if hasErr {
return
}
if len(records) != len(s.expectRecordIds) {
t.Fatalf("[%s] Expected %d records, got %d", s.name, len(s.expectRecordIds), len(records))
}
for i, id := range s.expectRecordIds {
if id != records[i].Id {
t.Fatalf("[%s] Expected record with id %q, got %q at index %d", s.name, id, records[i].Id, i)
}
}
})
}
}
@@ -544,6 +573,7 @@ func TestFindFirstRecordByFilter(t *testing.T) {
name string
collectionIdOrName string
filter string
params []dbx.Params
expectError bool
expectRecordId string
}{
@@ -551,6 +581,7 @@ func TestFindFirstRecordByFilter(t *testing.T) {
"missing collection",
"missing",
"id != ''",
nil,
true,
"",
},
@@ -558,6 +589,7 @@ func TestFindFirstRecordByFilter(t *testing.T) {
"missing filter",
"demo2",
"",
nil,
true,
"",
},
@@ -565,6 +597,7 @@ func TestFindFirstRecordByFilter(t *testing.T) {
"invalid filter",
"demo2",
"someMissingField > 1",
nil,
true,
"",
},
@@ -572,6 +605,7 @@ func TestFindFirstRecordByFilter(t *testing.T) {
"valid filter but no matches",
"demo2",
"id = 'test'",
nil,
true,
"",
},
@@ -579,13 +613,22 @@ func TestFindFirstRecordByFilter(t *testing.T) {
"valid filter and multiple matches",
"demo2",
"id != ''",
nil,
false,
"llvuca81nly1qls",
},
{
"with placeholder params",
"demo2",
"active = {:active}",
[]dbx.Params{{"active": false}},
false,
"llvuca81nly1qls",
},
}
for _, s := range scenarios {
record, err := app.Dao().FindFirstRecordByFilter(s.collectionIdOrName, s.filter)
record, err := app.Dao().FindFirstRecordByFilter(s.collectionIdOrName, s.filter, s.params...)
hasErr := err != nil
if hasErr != s.expectError {
+36 -9
View File
@@ -235,6 +235,8 @@ func defaultViewField(name string) *schema.SchemaField {
}
}
var castRegex = regexp.MustCompile(`(?i)^cast\s*\(.*\s+as\s+(\w+)\s*\)$`)
func (dao *Dao) parseQueryToFields(selectQuery string) (map[string]*queryField, error) {
p := new(identifiersParser)
if err := p.parse(selectQuery); err != nil {
@@ -257,15 +259,8 @@ func (dao *Dao) parseQueryToFields(selectQuery string) (map[string]*queryField,
for _, col := range p.columns {
colLower := strings.ToLower(col.original)
// numeric expression cast
if strings.Contains(colLower, "(") &&
(strings.HasPrefix(colLower, "count(") ||
strings.HasPrefix(colLower, "total(") ||
strings.Contains(colLower, " as numeric") ||
strings.Contains(colLower, " as real") ||
strings.Contains(colLower, " as int") ||
strings.Contains(colLower, " as integer") ||
strings.Contains(colLower, " as decimal")) {
// numeric aggregations
if strings.HasPrefix(colLower, "count(") || strings.HasPrefix(colLower, "total(") {
result[col.alias] = &queryField{
field: &schema.SchemaField{
Name: col.alias,
@@ -275,6 +270,38 @@ func (dao *Dao) parseQueryToFields(selectQuery string) (map[string]*queryField,
continue
}
castMatch := castRegex.FindStringSubmatch(colLower)
// numeric casts
if len(castMatch) == 2 {
switch castMatch[1] {
case "real", "integer", "int", "decimal", "numeric":
result[col.alias] = &queryField{
field: &schema.SchemaField{
Name: col.alias,
Type: schema.FieldTypeNumber,
},
}
continue
case "text":
result[col.alias] = &queryField{
field: &schema.SchemaField{
Name: col.alias,
Type: schema.FieldTypeText,
},
}
continue
case "boolean", "bool":
result[col.alias] = &queryField{
field: &schema.SchemaField{
Name: col.alias,
Type: schema.FieldTypeBool,
},
}
continue
}
}
parts := strings.Split(col.original, ".")
var fieldName string
+7 -1
View File
@@ -330,7 +330,7 @@ func TestCreateViewSchema(t *testing.T) {
},
},
{
"query with numeric casts",
"query with casts",
`select
a.id,
count(a.id) count,
@@ -339,6 +339,9 @@ func TestCreateViewSchema(t *testing.T) {
cast(a.id as real) cast_real,
cast(a.id as decimal) cast_decimal,
cast(a.id as numeric) cast_numeric,
cast(a.id as text) cast_text,
cast(a.id as bool) cast_bool,
cast(a.id as boolean) cast_boolean,
avg(a.id) avg,
sum(a.id) sum,
total(a.id) total,
@@ -354,6 +357,9 @@ func TestCreateViewSchema(t *testing.T) {
"cast_real": schema.FieldTypeNumber,
"cast_decimal": schema.FieldTypeNumber,
"cast_numeric": schema.FieldTypeNumber,
"cast_text": schema.FieldTypeText,
"cast_bool": schema.FieldTypeBool,
"cast_boolean": schema.FieldTypeBool,
// json because they are nullable
"sum": schema.FieldTypeJson,
"avg": schema.FieldTypeJson,
+1 -1
View File
@@ -42,7 +42,7 @@ func main() {
app.RootCmd.PersistentFlags().IntVar(
&hooksPool,
"hooksPool",
50,
25,
"the total prewarm goja.Runtime instances for the JS app hooks execution",
)
+3 -3
View File
@@ -75,14 +75,14 @@ func (form *AdminPasswordResetRequest) Submit(interceptors ...InterceptorFunc[*m
return errors.New("You have already requested a password reset.")
}
// update last sent timestamp
admin.LastResetSentAt = types.NowDateTime()
return runInterceptors(admin, func(m *models.Admin) error {
if err := mails.SendAdminPasswordReset(form.app, m); err != nil {
return err
}
// update last sent timestamp
m.LastResetSentAt = types.NowDateTime()
return form.dao.SaveAdmin(m)
}, interceptors...)
}
+2 -2
View File
@@ -117,7 +117,7 @@ func TestAdminPasswordResetRequestInterceptors(t *testing.T) {
t.Fatalf("Expected interceptor2 to be called")
}
if interceptorLastResetSentAt.String() == admin.LastResetSentAt.String() {
t.Fatalf("Expected the form model to be filled before calling the interceptors")
if interceptorLastResetSentAt.String() != admin.LastResetSentAt.String() {
t.Fatalf("Expected the form model to NOT be filled before calling the interceptors")
}
}
+10 -10
View File
@@ -38,7 +38,7 @@ func TestBackupCreateValidateAndSubmit(t *testing.T) {
}
for _, s := range scenarios {
func() {
t.Run(s.name, func(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
@@ -56,47 +56,47 @@ func TestBackupCreateValidateAndSubmit(t *testing.T) {
// parse errors
errs, ok := result.(validation.Errors)
if !ok && result != nil {
t.Errorf("[%s] Failed to parse errors %v", s.name, result)
t.Fatalf("Failed to parse errors %v", result)
return
}
// check errors
if len(errs) > len(s.expectedErrors) {
t.Errorf("[%s] Expected error keys %v, got %v", s.name, s.expectedErrors, errs)
t.Fatalf("Expected error keys %v, got %v", s.expectedErrors, errs)
}
for _, k := range s.expectedErrors {
if _, ok := errs[k]; !ok {
t.Errorf("[%s] Missing expected error key %q in %v", s.name, k, errs)
t.Fatalf("Missing expected error key %q in %v", k, errs)
}
}
// retrieve all created backup files
files, err := fsys.List("")
if err != nil {
t.Errorf("[%s] Failed to retrieve backup files", s.name)
t.Fatal("Failed to retrieve backup files")
return
}
if result != nil {
if total := len(files); total != 0 {
t.Errorf("[%s] Didn't expected backup files, found %d", s.name, total)
t.Fatalf("Didn't expected backup files, found %d", total)
}
return
}
if total := len(files); total != 1 {
t.Errorf("[%s] Expected 1 backup file, got %d", s.name, total)
t.Fatalf("Expected 1 backup file, got %d", total)
return
}
if s.backupName == "" {
prefix := "pb_backup_"
if !strings.HasPrefix(files[0].Key, prefix) {
t.Errorf("[%s] Expected the backup file, to have prefix %q: %q", s.name, prefix, files[0].Key)
t.Fatalf("Expected the backup file, to have prefix %q: %q", prefix, files[0].Key)
}
} else if s.backupName != files[0].Key {
t.Errorf("[%s] Expected backup file %q, got %q", s.name, s.backupName, files[0].Key)
t.Fatalf("Expected backup file %q, got %q", s.backupName, files[0].Key)
}
}()
})
}
}
+85
View File
@@ -0,0 +1,85 @@
package forms
import (
"context"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/forms/validators"
"github.com/pocketbase/pocketbase/tools/filesystem"
)
// BackupUpload is a request form for uploading a new app backup.
type BackupUpload struct {
app core.App
ctx context.Context
File *filesystem.File `json:"file"`
}
// NewBackupUpload creates new BackupUpload request form.
func NewBackupUpload(app core.App) *BackupUpload {
return &BackupUpload{
app: app,
ctx: context.Background(),
}
}
// SetContext replaces the default form upload context with the provided one.
func (form *BackupUpload) SetContext(ctx context.Context) {
form.ctx = ctx
}
// Validate makes the form validatable by implementing [validation.Validatable] interface.
func (form *BackupUpload) Validate() error {
return validation.ValidateStruct(form,
validation.Field(
&form.File,
validation.Required,
validation.By(validators.UploadedFileMimeType([]string{"application/zip"})),
validation.By(form.checkUniqueName),
),
)
}
func (form *BackupUpload) checkUniqueName(value any) error {
v, _ := value.(*filesystem.File)
if v == nil {
return nil // nothing to check
}
fsys, err := form.app.NewBackupsFilesystem()
if err != nil {
return err
}
defer fsys.Close()
fsys.SetContext(form.ctx)
if exists, err := fsys.Exists(v.OriginalName); err != nil || exists {
return validation.NewError("validation_backup_name_exists", "Backup file with the specified name already exists.")
}
return nil
}
// Submit validates the form and upload the backup file.
//
// You can optionally provide a list of InterceptorFunc to further
// modify the form behavior before uploading the backup.
func (form *BackupUpload) Submit(interceptors ...InterceptorFunc[*filesystem.File]) error {
if err := form.Validate(); err != nil {
return err
}
return runInterceptors(form.File, func(file *filesystem.File) error {
fsys, err := form.app.NewBackupsFilesystem()
if err != nil {
return err
}
fsys.SetContext(form.ctx)
return fsys.UploadFile(file, file.OriginalName)
}, interceptors...)
}
+118
View File
@@ -0,0 +1,118 @@
package forms_test
import (
"archive/zip"
"bytes"
"testing"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/pocketbase/pocketbase/forms"
"github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/filesystem"
)
func TestBackupUploadValidateAndSubmit(t *testing.T) {
var zb bytes.Buffer
zw := zip.NewWriter(&zb)
if err := zw.Close(); err != nil {
t.Fatal(err)
}
f0, _ := filesystem.NewFileFromBytes([]byte("test"), "existing")
f1, _ := filesystem.NewFileFromBytes([]byte("456"), "nozip")
f2, _ := filesystem.NewFileFromBytes(zb.Bytes(), "existing")
f3, _ := filesystem.NewFileFromBytes(zb.Bytes(), "zip")
scenarios := []struct {
name string
file *filesystem.File
expectedErrors []string
}{
{
"missing file",
nil,
[]string{"file"},
},
{
"non-zip file",
f1,
[]string{"file"},
},
{
"zip file with non-unique name",
f2,
[]string{"file"},
},
{
"zip file with unique name",
f3,
[]string{},
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
fsys, err := app.NewBackupsFilesystem()
if err != nil {
t.Fatal(err)
}
defer fsys.Close()
// create a dummy backup file to simulate existing backups
if err := fsys.UploadFile(f0, f0.OriginalName); err != nil {
t.Fatal(err)
}
form := forms.NewBackupUpload(app)
form.File = s.file
result := form.Submit()
// parse errors
errs, ok := result.(validation.Errors)
if !ok && result != nil {
t.Fatalf("Failed to parse errors %v", result)
}
// check errors
if len(errs) > len(s.expectedErrors) {
t.Fatalf("Expected error keys %v, got %v", s.expectedErrors, errs)
}
for _, k := range s.expectedErrors {
if _, ok := errs[k]; !ok {
t.Fatalf("Missing expected error key %q in %v", k, errs)
}
}
expectedFiles := []*filesystem.File{f0}
if result == nil {
expectedFiles = append(expectedFiles, s.file)
}
// retrieve all uploaded backup files
files, err := fsys.List("")
if err != nil {
t.Fatal("Failed to retrieve backup files")
}
if len(files) != len(expectedFiles) {
t.Fatalf("Expected %d files, got %d", len(expectedFiles), len(files))
}
for _, ef := range expectedFiles {
exists := false
for _, f := range files {
if f.Key == ef.OriginalName {
exists = true
break
}
}
if !exists {
t.Fatalf("Missing expected backup file %v", ef.OriginalName)
}
}
})
}
}
+1 -23
View File
@@ -229,14 +229,6 @@ func (form *CollectionUpsert) ensureNoFieldsTypeChange(value any) error {
func (form *CollectionUpsert) checkRelationFields(value any) error {
v, _ := value.(schema.Schema)
systemDisplayFields := schema.BaseModelFieldNames()
systemDisplayFields = append(systemDisplayFields,
schema.FieldNameUsername,
schema.FieldNameEmail,
schema.FieldNameEmailVisibility,
schema.FieldNameVerified,
)
for i, field := range v.Fields() {
if field.Type != schema.FieldTypeRelation {
continue
@@ -289,25 +281,11 @@ func (form *CollectionUpsert) checkRelationFields(value any) error {
"options": validation.Errors{
"collectionId": validation.NewError(
"validation_field_non_view_base_relation_collection",
"Non view collections are now allowed to have a view relation.",
"Non view collections are not allowed to have a view relation.",
),
}},
}
}
// validate displayFields (if any)
for _, name := range options.DisplayFields {
if relCollection.Schema.GetFieldByName(name) == nil && !list.ExistInSlice(name, systemDisplayFields) {
return validation.Errors{fmt.Sprint(i): validation.Errors{
"options": validation.Errors{
"displayFields": validation.NewError(
"validation_field_invalid_relation_displayFields",
fmt.Sprintf("%q does not exist in the related %q collection.", name, relCollection.Name),
),
}},
}
}
}
}
return nil
+1 -20
View File
@@ -171,25 +171,6 @@ func TestCollectionUpsertValidateAndSubmit(t *testing.T) {
}`,
[]string{"schema"},
},
{
"create failure - missing relation display field",
"",
`{
"name": "test_new",
"type": "base",
"schema": [
{
"name":"test",
"type":"relation",
"options":{
"collectionId":"wsmn24bux7wo113",
"displayFields":["text", "missing"]
}
}
]
}`,
[]string{"schema"},
},
{
"create failure - check auth options validators",
"",
@@ -605,7 +586,7 @@ func TestCollectionUpsertValidateAndSubmit(t *testing.T) {
}
if form.Name != collection.Name {
t.Errorf("Expected Name %q, got %q", collection.Name, form.Name)
t.Fatalf("Expected Name %q, got %q", collection.Name, form.Name)
}
if form.Type != collection.Type {
+1 -1
View File
@@ -38,7 +38,7 @@ func TestCollectionsImportValidate(t *testing.T) {
}
func TestCollectionsImportSubmit(t *testing.T) {
totalCollections := 10
totalCollections := 11
scenarios := []struct {
name string
+3 -3
View File
@@ -78,14 +78,14 @@ func (form *RecordPasswordResetRequest) Submit(interceptors ...InterceptorFunc[*
return errors.New("You've already requested a password reset.")
}
// update last sent timestamp
authRecord.Set(schema.FieldNameLastResetSentAt, types.NowDateTime())
return runInterceptors(authRecord, func(m *models.Record) error {
if err := mails.SendRecordPasswordReset(form.app, m); err != nil {
return err
}
// update last sent timestamp
m.Set(schema.FieldNameLastResetSentAt, types.NowDateTime())
return form.dao.SaveRecord(m)
}, interceptors...)
}
+2 -2
View File
@@ -164,7 +164,7 @@ func TestRecordPasswordResetRequestInterceptors(t *testing.T) {
t.Fatalf("Expected interceptor2 to be called")
}
if interceptorLastResetSentAt.String() == authRecord.LastResetSentAt().String() {
t.Fatalf("Expected the form model to be filled before calling the interceptors")
if interceptorLastResetSentAt.String() != authRecord.LastResetSentAt().String() {
t.Fatalf("Expected the form model to NOT be filled before calling the interceptors")
}
}
+3 -3
View File
@@ -82,9 +82,6 @@ func (form *RecordVerificationRequest) Submit(interceptors ...InterceptorFunc[*m
if (now.Sub(lastVerificationSentAt)).Seconds() < form.resendThreshold {
return errors.New("A verification email was already sent.")
}
// update last sent timestamp
record.SetLastVerificationSentAt(types.NowDateTime())
}
return runInterceptors(record, func(m *models.Record) error {
@@ -96,6 +93,9 @@ func (form *RecordVerificationRequest) Submit(interceptors ...InterceptorFunc[*m
return err
}
// update last sent timestamp
m.SetLastVerificationSentAt(types.NowDateTime())
return form.dao.SaveRecord(m)
}, interceptors...)
}
+2 -2
View File
@@ -182,7 +182,7 @@ func TestRecordVerificationRequestInterceptors(t *testing.T) {
t.Fatalf("Expected interceptor2 to be called")
}
if interceptorLastVerificationSentAt.String() == authRecord.LastVerificationSentAt().String() {
t.Fatalf("Expected the form model to be filled before calling the interceptors")
if interceptorLastVerificationSentAt.String() != authRecord.LastVerificationSentAt().String() {
t.Fatalf("Expected the form model to NOT be filled before calling the interceptors")
}
}
+4
View File
@@ -158,6 +158,10 @@ func (validator *RecordDataValidator) checkNumberValue(field *schema.SchemaField
options, _ := field.Options.(*schema.NumberOptions)
if options.NoDecimal && val != float64(int64(val)) {
return validation.NewError("validation_no_decimal_constraint", "Decimal numbers are not allowed")
}
if options.Min != nil && val < *options.Min {
return validation.NewError("validation_min_number_constraint", fmt.Sprintf("Must be larger than %f", *options.Min))
}
+19
View File
@@ -180,6 +180,13 @@ func TestRecordDataValidatorValidateNumber(t *testing.T) {
Max: &max,
},
},
&schema.SchemaField{
Name: "field4",
Type: schema.FieldTypeNumber,
Options: &schema.NumberOptions{
NoDecimal: true,
},
},
)
if err := app.Dao().SaveCollection(collection); err != nil {
t.Fatal(err)
@@ -201,6 +208,7 @@ func TestRecordDataValidatorValidateNumber(t *testing.T) {
"field1": nil,
"field2": nil,
"field3": nil,
"field4": nil,
},
nil,
[]string{"field2"},
@@ -211,6 +219,7 @@ func TestRecordDataValidatorValidateNumber(t *testing.T) {
"field1": "invalid",
"field2": "invalid",
"field3": "invalid",
"field4": "invalid",
},
nil,
[]string{"field2"},
@@ -244,6 +253,15 @@ func TestRecordDataValidatorValidateNumber(t *testing.T) {
nil,
[]string{"field3"},
},
{
"(number) check NoDecimal",
map[string]any{
"field2": 1,
"field4": 456.789,
},
nil,
[]string{"field4"},
},
{
"(number) valid data (only required)",
map[string]any{
@@ -258,6 +276,7 @@ func TestRecordDataValidatorValidateNumber(t *testing.T) {
"field1": nil,
"field2": 123, // test value cast
"field3": max,
"field4": 456,
},
nil,
[]string{},
+40 -40
View File
@@ -4,11 +4,11 @@ go 1.18
require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/aws/aws-sdk-go v1.44.313
github.com/aws/aws-sdk-go v1.45.3
github.com/disintegration/imaging v1.6.2
github.com/domodwyer/mailyak/v3 v3.6.1
github.com/domodwyer/mailyak/v3 v3.6.2
github.com/dop251/goja v0.0.0-20230707174833-636fdf960de1
github.com/dop251/goja_nodejs v0.0.0-20230731184339-9ba67d720a81
github.com/dop251/goja_nodejs v0.0.0-20230821135201-94e508132562
github.com/fatih/color v1.15.0
github.com/fsnotify/fsnotify v1.6.0
github.com/gabriel-vasile/mimetype v1.4.2
@@ -17,46 +17,46 @@ require (
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/labstack/echo/v5 v5.0.0-20230722203903-ec5b858dab61
github.com/mattn/go-sqlite3 v1.14.17
github.com/pocketbase/dbx v1.10.0
github.com/pocketbase/dbx v1.10.1
github.com/pocketbase/tygoja v0.0.0-20230618203136-2f8d57768be1
github.com/spf13/cast v1.5.1
github.com/spf13/cobra v1.7.0
gocloud.dev v0.32.0
golang.org/x/crypto v0.11.0
golang.org/x/net v0.12.0
golang.org/x/oauth2 v0.10.0
gocloud.dev v0.34.0
golang.org/x/crypto v0.13.0
golang.org/x/net v0.15.0
golang.org/x/oauth2 v0.12.0
golang.org/x/sync v0.3.0
modernc.org/sqlite v1.24.0
modernc.org/sqlite v1.25.0
)
require (
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.20.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.31 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.30 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.75 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.13.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.21.0 // indirect
github.com/aws/smithy-go v1.14.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.21.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 // indirect
github.com/aws/aws-sdk-go-v2/config v1.18.39 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.13.37 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.83 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 // indirect
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect
github.com/aws/smithy-go v1.14.2 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/google/wire v0.5.0 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -70,26 +70,26 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/image v0.9.0 // indirect
golang.org/x/image v0.12.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/term v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.11.1 // indirect
golang.org/x/tools v0.13.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.134.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731193218-e0aa005b6bdf // indirect
google.golang.org/api v0.138.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/grpc v1.57.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/ccgo/v3 v3.16.14 // indirect
modernc.org/ccgo/v3 v3.16.15 // indirect
modernc.org/libc v1.24.1 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.6.0 // indirect
modernc.org/memory v1.7.1 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)
+86 -85
View File
@@ -1,6 +1,6 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q=
cloud.google.com/go/compute v1.22.0 h1:cB8R6FtUtT1TYGl5R3xuxnW6OUIc/DrT2aiR16TTG7Y=
cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y=
cloud.google.com/go/storage v1.31.0 h1:+S3LjjEN2zZ+L5hOwj4+1OkGCsLVe0NzpXKQ1pSdTCI=
@@ -12,46 +12,46 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDe
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.44.313 h1:u6EuNQqgAmi09GEZ5g/XGHLF0XV31WcdU5rnHyIBHBc=
github.com/aws/aws-sdk-go v1.44.313/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.20.0 h1:INUDpYLt4oiPOJl0XwZDK2OVAVf0Rzo+MGVTv9f+gy8=
github.com/aws/aws-sdk-go-v2 v1.20.0/go.mod h1:uWOr0m0jDsiWw8nnXiqZ+YG6LdvAlGYDLLf2NmHZoy4=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 h1:/MS8AzqYNAhhRNalOmxUvYs8VEbNGifTnzhPFdcRQkQ=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11/go.mod h1:va22++AdXht4ccO3kH2SHkHHYvZ2G9Utz+CXKmm2CaU=
github.com/aws/aws-sdk-go-v2/config v1.18.31 h1:CcacHsJjsPtHpe1MaopwPddUErmLnl+X77+7n4G2KkY=
github.com/aws/aws-sdk-go-v2/config v1.18.31/go.mod h1:pnSeuahFFvtScCHy0INXLxJ4N8H7KncD5u6A48bx3/8=
github.com/aws/aws-sdk-go-v2/credentials v1.13.30 h1:4pt4sI4OwXrrWUGuGr5NEb2g+4IBUB/I2BVj0t2Ak7Q=
github.com/aws/aws-sdk-go-v2/credentials v1.13.30/go.mod h1:Scpo/dGUdxAtRKsNCaXMXONnl3gvvugbXVldy5Fz2DQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 h1:X3H6+SU21x+76LRglk21dFRgMTJMa5QcpW+SqUf5BBg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7/go.mod h1:3we0V09SwcJBzNlnyovrR2wWJhWmVdqAsmVs4uronv8=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.75 h1:dKQyBQCZiu47cQ47UhwsVEr5TYu4YqoyAnue6qgybh0=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.75/go.mod h1:ZduPOCZCNBJ4anGPXD9oU+3tJgOmm9VdoBQuNHvYnFY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 h1:zr/gxAZkMcvP71ZhQOcvdm8ReLjFgIXnIn0fw5AM7mo=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37/go.mod h1:Pdn4j43v49Kk6+82spO3Tu5gSeQXRsxo56ePPQAvFiA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 h1:0HCMIkAkVY9KMgueD8tf4bRTUanzEYvhw7KkPXIMpO0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31/go.mod h1:fTJDMe8LOFYtqiFFFeHA+SVMAwqLhoq0kcInYoLa9Js=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 h1:+i1DOFrW3YZ3apE45tCal9+aDKK6kNEbW6Ib7e1nFxE=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38/go.mod h1:1/jLp0OgOaWIetycOmycW+vYTYgTZFPttJQRgsI1PoU=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 h1:U5yySdwt2HPo/pnQec04DImLzWORbeWML1fJiLkKruI=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0/go.mod h1:EhC/83j8/hL/UB1WmExo3gkElaja/KlmZM/gl1rTfjM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 h1:uAiiHnWihGP2rVp64fHwzLDrswGjEjsPszwRYMiYQPU=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12/go.mod h1:fUTHpOXqRQpXvEpDPSa3zxCc2fnpW6YnBoba+eQr+Bg=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 h1:kvN1jPHr9UffqqG3bSgZ8tx4+1zKVHz/Ktw/BwW6hX8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32/go.mod h1:QmMEM7es84EUkbYWcpnkx8i5EW2uERPfrTFeOch128Y=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 h1:auGDJ0aLZahF5SPvkJ6WcUuX7iQ7kyl2MamV7Tm8QBk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31/go.mod h1:3+lloe3sZuBQw1aBc5MyndvodzQlyqCZ7x1QPDHaWP4=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 h1:Wgjft9X4W5pMeuqgPCHIQtbZ87wsgom7S5F8obreg+c=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0/go.mod h1:FWNzS4+zcWAP05IF7TDYTY1ysZAzIvogxWaDT9p8fsA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.0 h1:Flb+Uw+ewvmbZiaXEl+aIs1HygnwztxZmhkCe1b+YQg=
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.0/go.mod h1:6SOWLiobcZZshbmECRTADIRYliPL0etqFSigauQEeT0=
github.com/aws/aws-sdk-go-v2/service/sso v1.13.0 h1:agnjK56/1jtGPehxV8QZ/AYHV++pEfl7CpYbWjHjBDc=
github.com/aws/aws-sdk-go-v2/service/sso v1.13.0/go.mod h1:TC9BubuFMVScIU+TLKamO6VZiYTkYoEHqlSQwAe2omw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.0 h1:g0Rr6COTBEaIG9TFQ0GmRkPWOGuDfySGSq2PlMcclrY=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.0/go.mod h1:XO/VcyoQ8nKyKfFW/3DMsRQXsfh/052tHTWmg3xBXRg=
github.com/aws/aws-sdk-go-v2/service/sts v1.21.0 h1:HI1YIL5Q9FtucxF5tcNpzCEyLnkeUcqg6xtOx8u09S4=
github.com/aws/aws-sdk-go-v2/service/sts v1.21.0/go.mod h1:G8SbvL0rFk4WOJroU8tKBczhsbhj2p/YY7qeJezJ3CI=
github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io=
github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/aws-sdk-go v1.45.3 h1:Q8BksXg2ZUu2dCbA62+UCEtfvqsW8EO4tzt2IVeYAws=
github.com/aws/aws-sdk-go v1.45.3/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc=
github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13/go.mod h1:gpAbvyDGQFozTEmlTFO8XcQKHzubdq0LzRyJpG6MiXM=
github.com/aws/aws-sdk-go-v2/config v1.18.39 h1:oPVyh6fuu/u4OiW4qcuQyEtk7U7uuNBmHmJSLg1AJsQ=
github.com/aws/aws-sdk-go-v2/config v1.18.39/go.mod h1:+NH/ZigdPckFpgB1TRcRuWCB/Kbbvkxc/iNAKTq5RhE=
github.com/aws/aws-sdk-go-v2/credentials v1.13.37 h1:BvEdm09+ZEh2XtN+PVHPcYwKY3wIeB6pw7vPRM4M9/U=
github.com/aws/aws-sdk-go-v2/credentials v1.13.37/go.mod h1:ACLrdkd4CLZyXOghZ8IYumQbcooAcp2jo/s2xsFH8IM=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.83 h1:wcluDLIQ0uYaxv0fCWQRimbXkPdTgWHUD21j1CzXEwc=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.83/go.mod h1:nGCBuon134gW67yAtxHKV73x+tAcY/xG4ZPNPDB1h/I=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 h1:6lJvvkQ9HmbHZ4h/IEwclwv2mrTW8Uq1SOB/kXy0mfw=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4/go.mod h1:1PrKYwxTM+zjpw9Y41KFtoJCQrJ34Z47Y4VgVbfndjo=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 h1:m0QTSI6pZYJTk5WSKx3fm5cNW/DCicVzULBgU/6IyD0=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14/go.mod h1:dDilntgHy9WnHXsh7dDtUPgHKEfTJIBUTHM8OWm0f/0=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 h1:eev2yZX7esGRjqRbnVk1UxMLw4CyVZDpZXRCcy75oQk=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36/go.mod h1:lGnOkH9NJATw0XEPcAknFBj3zzNTEGRHtSw+CwC1YTg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 h1:v0jkRigbSD6uOdwcaUQmgEwG1BkPfAPDqaeNt/29ghg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4/go.mod h1:LhTyt8J04LL+9cIt7pYJ5lbS/U98ZmXovLOR/4LUsk8=
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5 h1:A42xdtStObqy7NGvzZKpnyNXvoOmm+FENobZ0/ssHWk=
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5/go.mod h1:rDGMZA7f4pbmTtPOk5v5UM2lmX6UAbRnMDJeDvnH7AM=
github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 h1:2PylFCfKCEDv6PeSN09pC/VUiRd10wi1VfHG5FrW0/g=
github.com/aws/aws-sdk-go-v2/service/sso v1.13.6/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 h1:pSB560BbVj9ZlJZF4WYj5zsytWHWKxg+NgyGV4B2L58=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4=
github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ=
github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU=
github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ=
github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
@@ -71,16 +71,16 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/domodwyer/mailyak/v3 v3.6.1 h1:o3vjinPjPUpw/2Ng5N91JrlFDkoIKu4HTHw3U/CNemE=
github.com/domodwyer/mailyak/v3 v3.6.1/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCOBXMn8=
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk=
github.com/dop251/goja v0.0.0-20230531210528-d7324b2d74f7/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4=
github.com/dop251/goja v0.0.0-20230707174833-636fdf960de1 h1:sC/DYk3eEi5cKkpJX1vl+CpAM138dmuW7rutje9Eo4E=
github.com/dop251/goja v0.0.0-20230707174833-636fdf960de1/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4=
github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y=
github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM=
github.com/dop251/goja_nodejs v0.0.0-20230731184339-9ba67d720a81 h1:1e6KLyFnVS5BAENTnqll6IezpFqTDAmIsL0hkjBuMcY=
github.com/dop251/goja_nodejs v0.0.0-20230731184339-9ba67d720a81/go.mod h1:X2TOTJ+Uamd454RFp7ig2tmP3hQg0Z2Qk8gbVQmU0mk=
github.com/dop251/goja_nodejs v0.0.0-20230821135201-94e508132562 h1:ObbB2tzHWWAxzsG5futqeq2Ual2zYlo/+eMkSc5sn8w=
github.com/dop251/goja_nodejs v0.0.0-20230821135201-94e508132562/go.mod h1:X2TOTJ+Uamd454RFp7ig2tmP3hQg0Z2Qk8gbVQmU0mk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -120,6 +120,7 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -137,11 +138,11 @@ github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdf
github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
github.com/google/s2a-go v0.1.5 h1:8IYp3w9nysqv3JH+NJgXJzGbDHzLOTj43BmSkp+O7qg=
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM=
@@ -183,8 +184,8 @@ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyex
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pocketbase/dbx v1.10.0 h1:58VIT7r6T+BnVbYVosvGBsPjQEic3/VFRYGT823vWSQ=
github.com/pocketbase/dbx v1.10.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
github.com/pocketbase/dbx v1.10.1 h1:cw+vsyfCJD8YObOVeqb93YErnlxwYMkNZ4rwN0G0AaA=
github.com/pocketbase/dbx v1.10.1/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
github.com/pocketbase/tygoja v0.0.0-20230618203136-2f8d57768be1 h1:0FQXnhUhBeF/z6UDj9Zm8GQHFHJSUtqLr1h4/YXf3vc=
github.com/pocketbase/tygoja v0.0.0-20230618203136-2f8d57768be1/go.mod h1:dOJ+pCyqm/jRn5kO/TX598J0e5xGDcJAZerK5atCrKI=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@@ -215,17 +216,17 @@ github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
gocloud.dev v0.32.0 h1:jHf8WSkByuAuXcvFt04OiiQH+N0zaRtxI6iEph8Bq8Y=
gocloud.dev v0.32.0/go.mod h1:m/x/N9cRjDF5MD0i5TLFbKbqkGffl/qayXA9FcMT5Oc=
gocloud.dev v0.34.0 h1:LzlQY+4l2cMtuNfwT2ht4+fiXwWf/NmPTnXUlLmGif4=
gocloud.dev v0.34.0/go.mod h1:psKOachbnvY3DAOPbsFVmLIErwsbWPUG2H5i65D38vE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.9.0 h1:QrzfX26snvCM20hIhBwuHI/ThTg18b/+kcKdXHvnR+g=
golang.org/x/image v0.9.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0=
golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ=
golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -246,11 +247,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -274,15 +275,15 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -292,8 +293,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -305,26 +306,26 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.11.1 h1:ojD5zOW8+7dOGzdnNgersm8aPfcDjhMp12UfG93NIMc=
golang.org/x/tools v0.11.1/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.134.0 h1:ktL4Goua+UBgoP1eL1/60LwZJqa1sIzkLmvoR3hR6Gw=
google.golang.org/api v0.134.0/go.mod h1:sjRL3UnjTx5UqNQS9EWr9N8p7xbHpy1k0XGRLCf3Spk=
google.golang.org/api v0.138.0 h1:K/tVp05MxNVbHShRw9m7e9VJGdagNeTdMzqPH7AUqr0=
google.golang.org/api v0.138.0/go.mod h1:4xyob8CxC+0GChNBvEUAk8VBKNvYOTWM9T3v3UfRxuY=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e h1:xIXmWJ303kJCuogpj0bHq+dcjcZHU+XFyc1I0Yl9cRg=
google.golang.org/genproto/googleapis/api v0.0.0-20230717213848-3f92550aa753 h1:lCbbUxUDD+DiXx9Q6F/ttL0aAu7N2pz8XnmMm8ZW4NE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731193218-e0aa005b6bdf h1:guOdSPaeFgN+jEJwTo1dQ71hdBm+yKSCCKuTRkJzcVo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731193218-e0aa005b6bdf/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
@@ -362,22 +363,22 @@ lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/ccgo/v3 v3.16.14 h1:af6KNtFgsVmnDYrWk3PQCS9XT6BXe7o3ZFJKkIKvXNQ=
modernc.org/ccgo/v3 v3.16.14/go.mod h1:mPDSujUIaTNWQSG4eqKw+atqLOEbma6Ncsa94WbC9zo=
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/memory v1.7.1 h1:9J+2/GKTlV503mk3yv8QJ6oEpRCUrRy0ad8TXEPoV8M=
modernc.org/memory v1.7.1/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.24.0 h1:EsClRIWHGhLTCX44p+Ri/JLD+vFGo0QGjasg2/F9TlI=
modernc.org/sqlite v1.24.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+28
View File
@@ -0,0 +1,28 @@
package migrations
import (
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
"github.com/pocketbase/pocketbase/models"
)
// Resave all view collections to ensure that the proper id normalization is applied.
// (see https://github.com/pocketbase/pocketbase/issues/3110)
func init() {
AppMigrations.Register(func(db dbx.Builder) error {
dao := daos.New(db)
collections, err := dao.FindCollectionsByType(models.CollectionTypeView)
if err != nil {
return nil
}
for _, collection := range collections {
// ignore errors to allow users to adjust
// the view queries after app start
dao.SaveCollection(collection)
}
return nil
}, nil)
}
@@ -0,0 +1,62 @@
package migrations
import (
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/daos"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/models/schema"
)
// Copy the now deprecated RelationOptions.DisplayFields values from
// all relation fields and register its value as Presentable under
// the specific field in the related collection.
//
// If there is more than one relation to a single collection with explicitly
// set DisplayFields only one of the configuration will be copied.
func init() {
AppMigrations.Register(func(db dbx.Builder) error {
dao := daos.New(db)
collections := []*models.Collection{}
if err := dao.CollectionQuery().All(&collections); err != nil {
return err
}
indexedCollections := make(map[string]*models.Collection, len(collections))
for _, collection := range collections {
indexedCollections[collection.Id] = collection
}
for _, collection := range indexedCollections {
for _, f := range collection.Schema.Fields() {
if f.Type != schema.FieldTypeRelation {
continue
}
options, ok := f.Options.(*schema.RelationOptions)
if !ok || len(options.DisplayFields) == 0 {
continue
}
relCollection, ok := indexedCollections[options.CollectionId]
if !ok {
continue
}
for _, name := range options.DisplayFields {
relField := relCollection.Schema.GetFieldByName(name)
if relField != nil {
relField.Presentable = true
}
}
// only raw model save
if err := dao.Save(relCollection); err != nil {
return err
}
}
}
return nil
}, nil)
}
+30 -4
View File
@@ -132,6 +132,10 @@ type SchemaField struct {
Type string `form:"type" json:"type"`
Required bool `form:"required" json:"required"`
// Presentable indicates whether the field is suitable for
// visualization purposes (eg. in the Admin UI relation views).
Presentable bool `form:"presentable" json:"presentable"`
// Deprecated: This field is no-op and will be removed in future versions.
// Please use the collection.Indexes field to define a unique constraint.
Unique bool `form:"unique" json:"unique"`
@@ -452,21 +456,36 @@ func (o *TextOptions) checkRegex(value any) error {
// -------------------------------------------------------------------
type NumberOptions struct {
Min *float64 `form:"min" json:"min"`
Max *float64 `form:"max" json:"max"`
Min *float64 `form:"min" json:"min"`
Max *float64 `form:"max" json:"max"`
NoDecimal bool `form:"noDecimal" json:"noDecimal"`
}
func (o NumberOptions) Validate() error {
var maxRules []validation.Rule
if o.Min != nil && o.Max != nil {
maxRules = append(maxRules, validation.Min(*o.Min))
maxRules = append(maxRules, validation.Min(*o.Min), validation.By(o.checkNoDecimal))
}
return validation.ValidateStruct(&o,
validation.Field(&o.Min, validation.By(o.checkNoDecimal)),
validation.Field(&o.Max, maxRules...),
)
}
func (o *NumberOptions) checkNoDecimal(value any) error {
v, _ := value.(*float64)
if v == nil || !o.NoDecimal {
return nil // nothing to check
}
if *v != float64(int64(*v)) {
return validation.NewError("validation_no_decimal_constraint", "Decimal numbers are not allowed.")
}
return nil
}
// -------------------------------------------------------------------
type BoolOptions struct {
@@ -519,6 +538,12 @@ func (o UrlOptions) Validate() error {
// -------------------------------------------------------------------
type EditorOptions struct {
// ConvertUrls is usually used to instruct the editor whether to
// apply url conversion (eg. stripping the domain name in case the
// urls are using the same domain as the one where the editor is loaded).
//
// (see also https://www.tiny.cloud/docs/tinymce/6/url-handling/#convert_urls)
ConvertUrls bool `form:"convertUrls" json:"convertUrls"`
}
func (o EditorOptions) Validate() error {
@@ -645,7 +670,8 @@ type RelationOptions struct {
// If nil no limits are applied.
MaxSelect *int `form:"maxSelect" json:"maxSelect"`
// DisplayFields is optional slice of collection field names used for UI purposes.
// Deprecated: This field is no-op and will be removed in future versions.
// Instead use the individula SchemaField.Presentable option for each field in the relation collection.
DisplayFields []string `form:"displayFields" json:"displayFields"`
}
+66 -44
View File
@@ -129,19 +129,19 @@ func TestSchemaFieldColDefinition(t *testing.T) {
func TestSchemaFieldString(t *testing.T) {
f := schema.SchemaField{
Id: "abc",
Name: "test",
Type: schema.FieldTypeText,
Required: true,
Unique: false,
System: true,
Id: "abc",
Name: "test",
Type: schema.FieldTypeText,
Required: true,
Presentable: true,
System: true,
Options: &schema.TextOptions{
Pattern: "test",
},
}
result := f.String()
expected := `{"system":true,"id":"abc","name":"test","type":"text","required":true,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`
expected := `{"system":true,"id":"abc","name":"test","type":"text","required":true,"presentable":true,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`
if result != expected {
t.Errorf("Expected \n%v, got \n%v", expected, result)
@@ -156,19 +156,19 @@ func TestSchemaFieldMarshalJSON(t *testing.T) {
// empty
{
schema.SchemaField{},
`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
// without defined options
{
schema.SchemaField{
Id: "abc",
Name: "test",
Type: schema.FieldTypeText,
Required: true,
Unique: false,
System: true,
Id: "abc",
Name: "test",
Type: schema.FieldTypeText,
Required: true,
Presentable: true,
System: true,
},
`{"system":true,"id":"abc","name":"test","type":"text","required":true,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
`{"system":true,"id":"abc","name":"test","type":"text","required":true,"presentable":true,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
},
// with defined options
{
@@ -182,7 +182,7 @@ func TestSchemaFieldMarshalJSON(t *testing.T) {
Pattern: "test",
},
},
`{"system":true,"id":"","name":"test","type":"text","required":true,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
`{"system":true,"id":"","name":"test","type":"text","required":true,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
},
}
@@ -207,32 +207,32 @@ func TestSchemaFieldUnmarshalJSON(t *testing.T) {
{
nil,
true,
`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte{},
true,
`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte(`{"system": true}`),
true,
`{"system":true,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
`{"system":true,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte(`{"invalid"`),
true,
`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
[]byte(`{"type":"text","system":true}`),
false,
`{"system":true,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
`{"system":true,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
},
{
[]byte(`{"type":"text","options":{"pattern":"test"}}`),
false,
`{"system":false,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
},
}
@@ -470,72 +470,72 @@ func TestSchemaFieldInitOptions(t *testing.T) {
{
schema.SchemaField{},
true,
`{"system":false,"id":"","name":"","type":"","required":false,"unique":false,"options":null}`,
`{"system":false,"id":"","name":"","type":"","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
schema.SchemaField{Type: "unknown"},
true,
`{"system":false,"id":"","name":"","type":"unknown","required":false,"unique":false,"options":null}`,
`{"system":false,"id":"","name":"","type":"unknown","required":false,"presentable":false,"unique":false,"options":null}`,
},
{
schema.SchemaField{Type: schema.FieldTypeText},
false,
`{"system":false,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeNumber},
false,
`{"system":false,"id":"","name":"","type":"number","required":false,"unique":false,"options":{"min":null,"max":null}}`,
`{"system":false,"id":"","name":"","type":"number","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"noDecimal":false}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeBool},
false,
`{"system":false,"id":"","name":"","type":"bool","required":false,"unique":false,"options":{}}`,
`{"system":false,"id":"","name":"","type":"bool","required":false,"presentable":false,"unique":false,"options":{}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeEmail},
false,
`{"system":false,"id":"","name":"","type":"email","required":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
`{"system":false,"id":"","name":"","type":"email","required":false,"presentable":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeUrl},
false,
`{"system":false,"id":"","name":"","type":"url","required":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
`{"system":false,"id":"","name":"","type":"url","required":false,"presentable":false,"unique":false,"options":{"exceptDomains":null,"onlyDomains":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeEditor},
false,
`{"system":false,"id":"","name":"","type":"editor","required":false,"unique":false,"options":{}}`,
`{"system":false,"id":"","name":"","type":"editor","required":false,"presentable":false,"unique":false,"options":{"convertUrls":false}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeDate},
false,
`{"system":false,"id":"","name":"","type":"date","required":false,"unique":false,"options":{"min":"","max":""}}`,
`{"system":false,"id":"","name":"","type":"date","required":false,"presentable":false,"unique":false,"options":{"min":"","max":""}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeSelect},
false,
`{"system":false,"id":"","name":"","type":"select","required":false,"unique":false,"options":{"maxSelect":0,"values":null}}`,
`{"system":false,"id":"","name":"","type":"select","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"values":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeJson},
false,
`{"system":false,"id":"","name":"","type":"json","required":false,"unique":false,"options":{}}`,
`{"system":false,"id":"","name":"","type":"json","required":false,"presentable":false,"unique":false,"options":{}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeFile},
false,
`{"system":false,"id":"","name":"","type":"file","required":false,"unique":false,"options":{"maxSelect":0,"maxSize":0,"mimeTypes":null,"thumbs":null,"protected":false}}`,
`{"system":false,"id":"","name":"","type":"file","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"maxSize":0,"mimeTypes":null,"thumbs":null,"protected":false}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeRelation},
false,
`{"system":false,"id":"","name":"","type":"relation","required":false,"unique":false,"options":{"collectionId":"","cascadeDelete":false,"minSelect":null,"maxSelect":null,"displayFields":null}}`,
`{"system":false,"id":"","name":"","type":"relation","required":false,"presentable":false,"unique":false,"options":{"collectionId":"","cascadeDelete":false,"minSelect":null,"maxSelect":null,"displayFields":null}}`,
},
{
schema.SchemaField{Type: schema.FieldTypeUser},
false,
`{"system":false,"id":"","name":"","type":"user","required":false,"unique":false,"options":{"maxSelect":0,"cascadeDelete":false}}`,
`{"system":false,"id":"","name":"","type":"user","required":false,"presentable":false,"unique":false,"options":{"maxSelect":0,"cascadeDelete":false}}`,
},
{
schema.SchemaField{
@@ -543,7 +543,7 @@ func TestSchemaFieldInitOptions(t *testing.T) {
Options: &schema.TextOptions{Pattern: "test"},
},
false,
`{"system":false,"id":"","name":"","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
`{"system":false,"id":"","name":"","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}`,
},
}
@@ -1743,8 +1743,12 @@ func TestTextOptionsValidate(t *testing.T) {
}
func TestNumberOptionsValidate(t *testing.T) {
number1 := 10.0
number2 := 20.0
int1 := 10.0
int2 := 20.0
decimal1 := 10.5
decimal2 := 20.5
scenarios := []fieldOptionsScenario{
{
"empty",
@@ -1754,23 +1758,41 @@ func TestNumberOptionsValidate(t *testing.T) {
{
"max - without min",
schema.NumberOptions{
Max: &number1,
Max: &int1,
},
[]string{},
},
{
"max - failure with min",
schema.NumberOptions{
Min: &number2,
Max: &number1,
Min: &int2,
Max: &int1,
},
[]string{"max"},
},
{
"max - success with min",
schema.NumberOptions{
Min: &number1,
Max: &number2,
Min: &int1,
Max: &int2,
},
[]string{},
},
{
"NoDecimal range failure",
schema.NumberOptions{
Min: &decimal1,
Max: &decimal2,
NoDecimal: true,
},
[]string{"min", "max"},
},
{
"NoDecimal range success",
schema.NumberOptions{
Min: &int1,
Max: &int2,
NoDecimal: true,
},
[]string{},
},
+7 -7
View File
@@ -286,7 +286,7 @@ func TestSchemaMarshalJSON(t *testing.T) {
t.Fatal(err)
}
expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}},{"system":false,"id":"f2id","name":"test2","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`
expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}},{"system":false,"id":"f2id","name":"test2","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`
if string(result) != expected {
t.Fatalf("Expected %s, got %s", expected, string(result))
@@ -354,7 +354,7 @@ func TestSchemaValue(t *testing.T) {
if err != nil {
t.Fatal(err)
}
expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`
expected := `[{"system":false,"id":"f1id","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`
if v2 != expected {
t.Fatalf("Expected %v, got %v", expected, v2)
@@ -377,21 +377,21 @@ func TestSchemaScan(t *testing.T) {
{`[{}]`, true, `[]`},
// unknown field type
{
`[{"system":false,"id":"123","name":"test1","type":"unknown","required":false,"unique":false}]`,
`[{"system":false,"id":"123","name":"test1","type":"unknown","required":false,"presentable":false,"unique":false}]`,
true,
`[]`,
},
// without options
{
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false}]`,
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false}]`,
false,
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":""}}]`,
},
// with options
{
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
false,
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
`[{"system":false,"id":"123","name":"test1","type":"text","required":false,"presentable":false,"unique":false,"options":{"min":null,"max":null,"pattern":"test"}}]`,
},
}
+7
View File
@@ -371,6 +371,12 @@ type SmtpConfig struct {
// When set to false StartTLS command is send, leaving the server
// to decide whether to upgrade the connection or not.
Tls bool `form:"tls" json:"tls"`
// LocalName is optional domain name or IP address used for the
// EHLO/HELO exchange (if not explicitly set, defaults to "localhost").
//
// This is required only by some SMTP servers, such as Gmail SMTP-relay.
LocalName string `form:"localName" json:"localName"`
}
// Validate makes SmtpConfig validatable by implementing [validation.Validatable] interface.
@@ -393,6 +399,7 @@ func (c SmtpConfig) Validate() error {
// validation.When(c.Enabled, validation.Required),
validation.In(mailer.SmtpAuthLogin, mailer.SmtpAuthPlain),
),
validation.Field(&c.LocalName, is.Host),
)
}
+20
View File
@@ -477,6 +477,26 @@ func TestSmtpConfigValidate(t *testing.T) {
},
false,
},
// invalid ehlo/helo name
{
settings.SmtpConfig{
Enabled: true,
Host: "example.com",
Port: 100,
LocalName: "invalid!",
},
true,
},
// valid ehlo/helo name
{
settings.SmtpConfig{
Enabled: true,
Host: "example.com",
Port: 100,
LocalName: "example.com",
},
false,
},
}
for i, scenario := range scenarios {
+28 -1
View File
@@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
@@ -22,6 +23,7 @@ import (
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/daos"
"github.com/pocketbase/pocketbase/forms"
"github.com/pocketbase/pocketbase/mails"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/models/schema"
"github.com/pocketbase/pocketbase/tokens"
@@ -111,10 +113,14 @@ func cronBinds(app core.App, loader *goja.Runtime, executors *vmsPool) {
pr := goja.MustCompile("", "{("+handler+").apply(undefined)}", true)
err := scheduler.Add(jobId, cronExpr, func() {
executors.run(func(executor *goja.Runtime) error {
err := executors.run(func(executor *goja.Runtime) error {
_, err := executor.RunProgram(pr)
return err
})
if err != nil && app.IsDebug() {
fmt.Println("[cronAdd] failed to execute cron job " + jobId + ": " + err.Error())
}
})
if err != nil {
panic("[cronAdd] failed to register cron job " + jobId + ": " + err.Error())
@@ -415,6 +421,19 @@ func dbxBinds(vm *goja.Runtime) {
obj.Set("notBetween", dbx.NotBetween)
}
func mailsBinds(vm *goja.Runtime) {
obj := vm.NewObject()
vm.Set("$mails", obj)
// admin
obj.Set("sendAdminPasswordReset", mails.SendAdminPasswordReset)
// record
obj.Set("sendRecordPasswordReset", mails.SendRecordPasswordReset)
obj.Set("sendRecordVerification", mails.SendRecordVerification)
obj.Set("sendRecordChangeEmail", mails.SendRecordChangeEmail)
}
func tokensBinds(vm *goja.Runtime) {
obj := vm.NewObject()
vm.Set("$tokens", obj)
@@ -436,6 +455,14 @@ func securityBinds(vm *goja.Runtime) {
obj := vm.NewObject()
vm.Set("$security", obj)
// crypto
obj.Set("md5", security.MD5)
obj.Set("sha256", security.SHA256)
obj.Set("sha512", security.SHA512)
obj.Set("hs256", security.HS256)
obj.Set("hs512", security.HS512)
obj.Set("equal", security.Equal)
// random
obj.Set("randomString", security.RandomString)
obj.Set("randomStringWithAlphabet", security.RandomStringWithAlphabet)
+115 -19
View File
@@ -24,6 +24,7 @@ import (
"github.com/pocketbase/pocketbase/tools/filesystem"
"github.com/pocketbase/pocketbase/tools/mailer"
"github.com/pocketbase/pocketbase/tools/security"
"github.com/spf13/cast"
)
func testBindsCount(vm *goja.Runtime, namespace string, count int, t *testing.T) {
@@ -484,6 +485,60 @@ func TestDbxBinds(t *testing.T) {
}
}
func TestMailsBindsCount(t *testing.T) {
vm := goja.New()
mailsBinds(vm)
testBindsCount(vm, "$mails", 4, t)
}
func TestMailsBinds(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
admin, err := app.Dao().FindAdminByEmail("test@example.com")
if err != nil {
t.Fatal(err)
}
record, err := app.Dao().FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
vm := goja.New()
baseBinds(vm)
mailsBinds(vm)
vm.Set("$app", app)
vm.Set("admin", admin)
vm.Set("record", record)
_, vmErr := vm.RunString(`
$mails.sendAdminPasswordReset($app, admin);
if (!$app.testMailer.lastMessage.html.includes("/_/#/confirm-password-reset/")) {
throw new Error("Expected admin password reset email")
}
$mails.sendRecordPasswordReset($app, record);
if (!$app.testMailer.lastMessage.html.includes("/_/#/auth/confirm-password-reset/")) {
throw new Error("Expected record password reset email")
}
$mails.sendRecordVerification($app, record);
if (!$app.testMailer.lastMessage.html.includes("/_/#/auth/confirm-verification/")) {
throw new Error("Expected record verification email")
}
$mails.sendRecordChangeEmail($app, record, "new@example.com");
if (!$app.testMailer.lastMessage.html.includes("/_/#/auth/confirm-email-change/")) {
throw new Error("Expected record email change email")
}
`)
if vmErr != nil {
t.Fatal(vmErr)
}
}
func TestTokensBindsCount(t *testing.T) {
vm := goja.New()
tokensBinds(vm)
@@ -506,11 +561,11 @@ func TestTokensBinds(t *testing.T) {
}
vm := goja.New()
baseBinds(vm)
tokensBinds(vm)
vm.Set("$app", app)
vm.Set("admin", admin)
vm.Set("record", record)
baseBinds(vm)
tokensBinds(vm)
sceneraios := []struct {
js string
@@ -568,7 +623,44 @@ func TestSecurityBindsCount(t *testing.T) {
vm := goja.New()
securityBinds(vm)
testBindsCount(vm, "$security", 9, t)
testBindsCount(vm, "$security", 15, t)
}
func TestSecurityCryptoBinds(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
vm := goja.New()
baseBinds(vm)
securityBinds(vm)
sceneraios := []struct {
js string
expected string
}{
{`$security.md5("123")`, "202cb962ac59075b964b07152d234b70"},
{`$security.sha256("123")`, "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"},
{`$security.sha512("123")`, "3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2"},
{`$security.hs256("hello", "test")`, "f151ea24bda91a18e89b8bb5793ef324b2a02133cce15a28a719acbd2e58a986"},
{`$security.hs512("hello", "test")`, "44f280e11103e295c26cd61dd1cdd8178b531b860466867c13b1c37a26b6389f8af110efbe0bb0717b9d9c87f6fe1c97b3b1690936578890e5669abf279fe7fd"},
{`$security.equal("abc", "abc")`, "true"},
{`$security.equal("abc", "abcd")`, "false"},
}
for _, s := range sceneraios {
t.Run(s.js, func(t *testing.T) {
result, err := vm.RunString(s.js)
if err != nil {
t.Fatalf("Failed to execute js script, got %v", err)
}
v := cast.ToString(result.Export())
if v != s.expected {
t.Fatalf("Expected %v \ngot \n%v", s.expected, v)
}
})
}
}
func TestSecurityRandomStringBinds(t *testing.T) {
@@ -590,16 +682,18 @@ func TestSecurityRandomStringBinds(t *testing.T) {
}
for _, s := range sceneraios {
result, err := vm.RunString(s.js)
if err != nil {
t.Fatalf("[%s] Failed to execute js script, got %v", s.js, err)
}
t.Run(s.js, func(t *testing.T) {
result, err := vm.RunString(s.js)
if err != nil {
t.Fatalf("Failed to execute js script, got %v", err)
}
v, _ := result.Export().(string)
v, _ := result.Export().(string)
if len(v) != s.length {
t.Fatalf("[%s] Expected %d length string, \ngot \n%v", s.js, s.length, v)
}
if len(v) != s.length {
t.Fatalf("Expected %d length string, \ngot \n%v", s.length, v)
}
})
}
}
@@ -630,16 +724,18 @@ func TestSecurityJWTBinds(t *testing.T) {
}
for _, s := range sceneraios {
result, err := vm.RunString(s.js)
if err != nil {
t.Fatalf("[%s] Failed to execute js script, got %v", s.js, err)
}
t.Run(s.js, func(t *testing.T) {
result, err := vm.RunString(s.js)
if err != nil {
t.Fatalf("Failed to execute js script, got %v", err)
}
raw, _ := json.Marshal(result.Export())
raw, _ := json.Marshal(result.Export())
if string(raw) != s.expected {
t.Fatalf("[%s] Expected \n%s, \ngot \n%s", s.js, s.expected, raw)
}
if string(raw) != s.expected {
t.Fatalf("Expected \n%s, \ngot \n%s", s.expected, raw)
}
})
}
}
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -29,7 +29,7 @@ const heading = `
*
* ` + "```" + `js
* // prints "Hello world!" on every 30 minutes
* cronAdd("hello", "*\/30 * * * *", (c) => {
* cronAdd("hello", "*\/30 * * * *", () => {
* console.log("Hello world!")
* })
* ` + "```" + `
@@ -498,6 +498,12 @@ declare namespace $security {
let createJWT: security.newJWT
let encrypt: security.encrypt
let decrypt: security.decrypt
let hs256: security.hs256
let hs512: security.hs512
let equal: security.equal
let md5: security.md5
let sha256: security.sha256
let sha512: security.sha512
}
// -------------------------------------------------------------------
+7 -7
View File
@@ -127,7 +127,7 @@ func Register(app core.App, config Config) error {
})
if err := p.registerMigrations(); err != nil {
return fmt.Errorf("registerHooks: %w", err)
return fmt.Errorf("registerMigrations: %w", err)
}
if err := p.registerHooks(); err != nil {
@@ -161,12 +161,9 @@ func (p *plugin) registerMigrations() error {
dbxBinds(vm)
tokensBinds(vm)
securityBinds(vm)
// note: disallow for now and give the authors of custom SaaS offerings
// some time to adjust their code to avoid eventual security issues
//
// osBinds(vm)
// filepathBinds(vm)
// httpClientBinds(vm)
osBinds(vm)
filepathBinds(vm)
httpClientBinds(vm)
vm.Set("migrate", func(up, down func(db dbx.Builder) error) {
m.AppMigrations.Register(up, down, file)
@@ -236,6 +233,7 @@ func (p *plugin) registerHooks() error {
requireRegistry.Enable(vm)
console.Enable(vm)
process.Enable(vm)
baseBinds(vm)
dbxBinds(vm)
filesystemBinds(vm)
@@ -246,6 +244,8 @@ func (p *plugin) registerHooks() error {
httpClientBinds(vm)
formsBinds(vm)
apisBinds(vm)
mailsBinds(vm)
vm.Set("$app", p.app)
vm.Set("$template", templateRegistry)
vm.Set("__hooks", absHooksDir)
+42 -11
View File
@@ -381,8 +381,10 @@ migrate((db) => {
collection.name = "test456_update"
collection.type = "base"
collection.listRule = null
collection.deleteRule = "updated > 0 && @request.auth.id != ''"
collection.listRule = "@request.auth.id != ''"
collection.createRule = "id = \"nil_update\""
collection.updateRule = "id = \"2_update\""
collection.deleteRule = null
collection.options = {}
collection.indexes = [
"create index test1 on test456_update (f1_name)"
@@ -398,6 +400,7 @@ migrate((db) => {
"name": "f4_name",
"type": "text",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
@@ -413,10 +416,12 @@ migrate((db) => {
"name": "f2_name_new",
"type": "number",
"required": false,
"presentable": false,
"unique": true,
"options": {
"min": 10,
"max": null
"max": null,
"noDecimal": false
}
}))
@@ -428,7 +433,9 @@ migrate((db) => {
collection.name = "test456"
collection.type = "auth"
collection.listRule = "@request.auth.id != '' && created > 0"
collection.deleteRule = null
collection.createRule = null
collection.updateRule = "id = \"2\""
collection.deleteRule = "id = \"3\""
collection.options = {
"allowEmailAuth": false,
"allowOAuth2Auth": false,
@@ -450,6 +457,7 @@ migrate((db) => {
"name": "f3_name",
"type": "bool",
"required": false,
"presentable": false,
"unique": false,
"options": {}
}))
@@ -464,10 +472,12 @@ migrate((db) => {
"name": "f2_name",
"type": "number",
"required": false,
"presentable": false,
"unique": true,
"options": {
"min": 10,
"max": null
"max": null,
"noDecimal": false
}
}))
@@ -503,9 +513,13 @@ func init() {
collection.Type = "base"
collection.ListRule = nil
collection.ListRule = types.Pointer("@request.auth.id != ''")
collection.DeleteRule = types.Pointer("updated > 0 && @request.auth.id != ''")
collection.CreateRule = types.Pointer("id = \"nil_update\"")
collection.UpdateRule = types.Pointer("id = \"2_update\"")
collection.DeleteRule = nil
options := map[string]any{}
json.Unmarshal([]byte(` + "`" + `{}` + "`" + `), &options)
@@ -526,6 +540,7 @@ func init() {
"name": "f4_name",
"type": "text",
"required": false,
"presentable": false,
"unique": false,
"options": {
"min": null,
@@ -543,10 +558,12 @@ func init() {
"name": "f2_name_new",
"type": "number",
"required": false,
"presentable": false,
"unique": true,
"options": {
"min": 10,
"max": null
"max": null,
"noDecimal": false
}
}` + "`" + `), edit_f2_name_new)
collection.Schema.AddField(edit_f2_name_new)
@@ -566,7 +583,11 @@ func init() {
collection.ListRule = types.Pointer("@request.auth.id != '' && created > 0")
collection.DeleteRule = nil
collection.CreateRule = nil
collection.UpdateRule = types.Pointer("id = \"2\"")
collection.DeleteRule = types.Pointer("id = \"3\"")
options := map[string]any{}
json.Unmarshal([]byte(` + "`" + `{
@@ -593,6 +614,7 @@ func init() {
"name": "f3_name",
"type": "bool",
"required": false,
"presentable": false,
"unique": false,
"options": {}
}` + "`" + `), del_f3_name)
@@ -609,10 +631,12 @@ func init() {
"name": "f2_name",
"type": "number",
"required": false,
"presentable": false,
"unique": true,
"options": {
"min": 10,
"max": null
"max": null,
"noDecimal": false
}
}` + "`" + `), edit_f2_name_new)
collection.Schema.AddField(edit_f2_name_new)
@@ -645,6 +669,9 @@ func init() {
collection.Updated = collection.Created
collection.ListRule = types.Pointer("@request.auth.id != '' && created > 0")
collection.ViewRule = types.Pointer(`id = "1"`)
collection.UpdateRule = types.Pointer(`id = "2"`)
collection.CreateRule = nil
collection.DeleteRule = types.Pointer(`id = "3"`)
collection.Indexes = types.JsonArray[string]{"create index test1 on test456 (f1_name)"}
collection.SetOptions(models.CollectionAuthOptions{
ManageRule: types.Pointer("created > 0"),
@@ -683,7 +710,11 @@ func init() {
collection.Name = "test456_update"
collection.Type = models.CollectionTypeBase
collection.DeleteRule = types.Pointer(`updated > 0 && @request.auth.id != ''`)
collection.ListRule = nil
collection.ListRule = types.Pointer("@request.auth.id != ''")
collection.ViewRule = types.Pointer(`id = "1"`) // no change
collection.UpdateRule = types.Pointer(`id = "2_update"`)
collection.CreateRule = types.Pointer(`id = "nil_update"`)
collection.DeleteRule = nil
collection.Indexes = types.JsonArray[string]{
"create index test1 on test456_update (f1_name)",
}
+76 -60
View File
@@ -137,53 +137,61 @@ func (p *plugin) jsDiffTemplate(new *models.Collection, old *models.Collection)
// note: strconv.Quote is used because %q converts the rule operators in unicode char codes
// ---
formatRule := func(prop string, rule *string) string {
if rule == nil {
return fmt.Sprintf("%s.%s = null", varName, prop)
}
return fmt.Sprintf("%s.%s = %s", varName, prop, strconv.Quote(*rule))
}
if old.ListRule != new.ListRule {
if old.ListRule != nil && new.ListRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.listRule = null", varName))
downParts = append(downParts, fmt.Sprintf("%s.listRule = %s", varName, strconv.Quote(*old.ListRule)))
} else if old.ListRule == nil && new.ListRule != nil || *old.ListRule != *new.ListRule {
upParts = append(upParts, fmt.Sprintf("%s.listRule = %s", varName, strconv.Quote(*new.ListRule)))
downParts = append(downParts, fmt.Sprintf("%s.listRule = null", varName))
oldRule := formatRule("listRule", old.ListRule)
newRule := formatRule("listRule", new.ListRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.ViewRule != new.ViewRule {
if old.ViewRule != nil && new.ViewRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.viewRule = null", varName))
downParts = append(downParts, fmt.Sprintf("%s.viewRule = %s", varName, strconv.Quote(*old.ViewRule)))
} else if old.ViewRule == nil && new.ViewRule != nil || *old.ViewRule != *new.ViewRule {
upParts = append(upParts, fmt.Sprintf("%s.viewRule = %s", varName, strconv.Quote(*new.ViewRule)))
downParts = append(downParts, fmt.Sprintf("%s.viewRule = null", varName))
oldRule := formatRule("viewRule", old.ViewRule)
newRule := formatRule("viewRule", new.ViewRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.CreateRule != new.CreateRule {
if old.CreateRule != nil && new.CreateRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.createRule = null", varName))
downParts = append(downParts, fmt.Sprintf("%s.createRule = %s", varName, strconv.Quote(*old.CreateRule)))
} else if old.CreateRule == nil && new.CreateRule != nil || *old.CreateRule != *new.CreateRule {
upParts = append(upParts, fmt.Sprintf("%s.createRule = %s", varName, strconv.Quote(*new.CreateRule)))
downParts = append(downParts, fmt.Sprintf("%s.createRule = null", varName))
oldRule := formatRule("createRule", old.CreateRule)
newRule := formatRule("createRule", new.CreateRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.UpdateRule != new.UpdateRule {
if old.UpdateRule != nil && new.UpdateRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.updateRule = null", varName))
downParts = append(downParts, fmt.Sprintf("%s.updateRule = %s", varName, strconv.Quote(*old.UpdateRule)))
} else if old.UpdateRule == nil && new.UpdateRule != nil || *old.UpdateRule != *new.UpdateRule {
upParts = append(upParts, fmt.Sprintf("%s.updateRule = %s", varName, strconv.Quote(*new.UpdateRule)))
downParts = append(downParts, fmt.Sprintf("%s.updateRule = null", varName))
oldRule := formatRule("updateRule", old.UpdateRule)
newRule := formatRule("updateRule", new.UpdateRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.DeleteRule != new.DeleteRule {
if old.DeleteRule != nil && new.DeleteRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.deleteRule = null", varName))
downParts = append(downParts, fmt.Sprintf("%s.deleteRule = %s", varName, strconv.Quote(*old.DeleteRule)))
} else if old.DeleteRule == nil && new.DeleteRule != nil || *old.DeleteRule != *new.DeleteRule {
upParts = append(upParts, fmt.Sprintf("%s.deleteRule = %s", varName, strconv.Quote(*new.DeleteRule)))
downParts = append(downParts, fmt.Sprintf("%s.deleteRule = null", varName))
oldRule := formatRule("deleteRule", old.DeleteRule)
newRule := formatRule("deleteRule", new.DeleteRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
@@ -521,53 +529,61 @@ func (p *plugin) goDiffTemplate(new *models.Collection, old *models.Collection)
// note: strconv.Quote is used because %q converts the rule operators in unicode char codes
// ---
formatRule := func(prop string, rule *string) string {
if rule == nil {
return fmt.Sprintf("%s.%s = nil\n", varName, prop)
}
return fmt.Sprintf("%s.%s = types.Pointer(%s)\n", varName, prop, strconv.Quote(*rule))
}
if old.ListRule != new.ListRule {
if old.ListRule != nil && new.ListRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.ListRule = nil\n", varName))
downParts = append(downParts, fmt.Sprintf("%s.ListRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.ListRule)))
} else if old.ListRule == nil && new.ListRule != nil || *old.ListRule != *new.ListRule {
upParts = append(upParts, fmt.Sprintf("%s.ListRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.ListRule)))
downParts = append(downParts, fmt.Sprintf("%s.ListRule = nil\n", varName))
oldRule := formatRule("ListRule", old.ListRule)
newRule := formatRule("ListRule", new.ListRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.ViewRule != new.ViewRule {
if old.ViewRule != nil && new.ViewRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.ViewRule = nil\n", varName))
downParts = append(downParts, fmt.Sprintf("%s.ViewRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.ViewRule)))
} else if old.ViewRule == nil && new.ViewRule != nil || *old.ViewRule != *new.ViewRule {
upParts = append(upParts, fmt.Sprintf("%s.ViewRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.ViewRule)))
downParts = append(downParts, fmt.Sprintf("%s.ViewRule = nil\n", varName))
oldRule := formatRule("ViewRule", old.ViewRule)
newRule := formatRule("ViewRule", new.ViewRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.CreateRule != new.CreateRule {
if old.CreateRule != nil && new.CreateRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.CreateRule = nil\n", varName))
downParts = append(downParts, fmt.Sprintf("%s.CreateRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.CreateRule)))
} else if old.CreateRule == nil && new.CreateRule != nil || *old.CreateRule != *new.CreateRule {
upParts = append(upParts, fmt.Sprintf("%s.CreateRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.CreateRule)))
downParts = append(downParts, fmt.Sprintf("%s.CreateRule = nil\n", varName))
oldRule := formatRule("CreateRule", old.CreateRule)
newRule := formatRule("CreateRule", new.CreateRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.UpdateRule != new.UpdateRule {
if old.UpdateRule != nil && new.UpdateRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.UpdateRule = nil\n", varName))
downParts = append(downParts, fmt.Sprintf("%s.UpdateRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.UpdateRule)))
} else if old.UpdateRule == nil && new.UpdateRule != nil || *old.UpdateRule != *new.UpdateRule {
upParts = append(upParts, fmt.Sprintf("%s.UpdateRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.UpdateRule)))
downParts = append(downParts, fmt.Sprintf("%s.UpdateRule = nil\n", varName))
oldRule := formatRule("UpdateRule", old.UpdateRule)
newRule := formatRule("UpdateRule", new.UpdateRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
if old.DeleteRule != new.DeleteRule {
if old.DeleteRule != nil && new.DeleteRule == nil {
upParts = append(upParts, fmt.Sprintf("%s.DeleteRule = nil\n", varName))
downParts = append(downParts, fmt.Sprintf("%s.DeleteRule = types.Pointer(%s)\n", varName, strconv.Quote(*old.DeleteRule)))
} else if old.DeleteRule == nil && new.DeleteRule != nil || *old.DeleteRule != *new.DeleteRule {
upParts = append(upParts, fmt.Sprintf("%s.DeleteRule = types.Pointer(%s)\n", varName, strconv.Quote(*new.DeleteRule)))
downParts = append(downParts, fmt.Sprintf("%s.DeleteRule = nil\n", varName))
oldRule := formatRule("DeleteRule", old.DeleteRule)
newRule := formatRule("DeleteRule", new.DeleteRule)
if oldRule != newRule {
upParts = append(upParts, newRule)
downParts = append(downParts, oldRule)
}
}
+12 -11
View File
@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
@@ -37,9 +38,9 @@ type ApiScenario struct {
// test hooks
// ---
TestAppFactory func() (*TestApp, error)
TestAppFactory func(t *testing.T) *TestApp
BeforeTestFunc func(t *testing.T, app *TestApp, e *echo.Echo)
AfterTestFunc func(t *testing.T, app *TestApp, e *echo.Echo)
AfterTestFunc func(t *testing.T, app *TestApp, res *http.Response)
}
// Test executes the test scenario.
@@ -54,16 +55,17 @@ func (scenario *ApiScenario) Test(t *testing.T) {
func (scenario *ApiScenario) test(t *testing.T) {
var testApp *TestApp
var testAppErr error
if scenario.TestAppFactory != nil {
// @todo consider passing the testing instance to the factory and maybe remove the error from the declaration
// (see https://github.com/pocketbase/pocketbase/discussions/3025)
testApp, testAppErr = scenario.TestAppFactory()
testApp = scenario.TestAppFactory(t)
if testApp == nil {
t.Fatal("TestAppFactory must return a non-nill app instance")
}
} else {
var testAppErr error
testApp, testAppErr = NewTestApp()
}
if testAppErr != nil {
t.Fatalf("Failed to initialize the test app instance: %v", testAppErr)
if testAppErr != nil {
t.Fatalf("Failed to initialize the test app instance: %v", testAppErr)
}
}
defer testApp.Cleanup()
@@ -172,8 +174,7 @@ func (scenario *ApiScenario) test(t *testing.T) {
}
}
// @todo consider adding the response body to the AfterTestFunc args
if scenario.AfterTestFunc != nil {
scenario.AfterTestFunc(t, testApp, e)
scenario.AfterTestFunc(t, testApp, res)
}
}
Binary file not shown.
+6
View File
@@ -2,6 +2,7 @@ package archive
import (
"archive/zip"
"compress/flate"
"io"
"io/fs"
"os"
@@ -27,6 +28,11 @@ func Create(src string, dest string, skipPaths ...string) error {
zw := zip.NewWriter(zf)
defer zw.Close()
// register a custom Deflate compressor
zw.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
return flate.NewWriter(out, flate.BestSpeed)
})
if err := zipAddFS(zw, os.DirFS(src), skipPaths...); err != nil {
// try to cleanup at least the created zip file
os.Remove(dest)
+24 -3
View File
@@ -62,20 +62,41 @@ func (s *Schedule) IsDue(m *Moment) bool {
return true
}
var macros = map[string]string{
"@yearly": "0 0 1 1 *",
"@annually": "0 0 1 1 *",
"@monthly": "0 0 1 * *",
"@weekly": "0 0 * * 0",
"@daily": "0 0 * * *",
"@midnight": "0 0 * * *",
"@hourly": "0 * * * *",
}
// NewSchedule creates a new Schedule from a cron expression.
//
// A cron expression is consisted of 5 segments separated by space,
// A cron expression could be a macro OR 5 segments separated by space,
// representing: minute, hour, day of the month, month and day of the week.
//
// Each segment could be in the following formats:
// The following segment formats are supported:
// - wildcard: *
// - range: 1-30
// - step: */n or 1-30/n
// - list: 1,2,3,10-20/n
//
// The following macros are supported:
// - @yearly (or @annually)
// - @monthly
// - @weekly
// - @daily (or @midnight)
// - @hourly
func NewSchedule(cronExpr string) (*Schedule, error) {
if v, ok := macros[cronExpr]; ok {
cronExpr = v
}
segments := strings.Split(cronExpr, " ")
if len(segments) != 5 {
return nil, errors.New("invalid cron expression - must have exactly 5 space separated segments")
return nil, errors.New("invalid cron expression - must be a valid macro or to have exactly 5 space separated segments")
}
minutes, err := parseCronSegment(segments[0], 0, 59)
+37
View File
@@ -208,6 +208,43 @@ func TestNewSchedule(t *testing.T) {
false,
`{"minutes":{"0":{},"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"28":{},"29":{},"3":{},"30":{},"31":{},"32":{},"33":{},"34":{},"35":{},"36":{},"37":{},"38":{},"39":{},"4":{},"40":{},"41":{},"42":{},"43":{},"44":{},"45":{},"46":{},"47":{},"48":{},"49":{},"5":{},"50":{},"51":{},"52":{},"53":{},"54":{},"55":{},"56":{},"57":{},"58":{},"59":{},"6":{},"7":{},"8":{},"9":{}},"hours":{"0":{},"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"days":{"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"28":{},"29":{},"3":{},"30":{},"31":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"months":{"1":{},"10":{},"11":{},"12":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"daysOfWeek":{"1":{},"2":{},"4":{}}}`,
},
// macros
{
"@yearly",
false,
`{"minutes":{"0":{}},"hours":{"0":{}},"days":{"1":{}},"months":{"1":{}},"daysOfWeek":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{}}}`,
},
{
"@annually",
false,
`{"minutes":{"0":{}},"hours":{"0":{}},"days":{"1":{}},"months":{"1":{}},"daysOfWeek":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{}}}`,
},
{
"@monthly",
false,
`{"minutes":{"0":{}},"hours":{"0":{}},"days":{"1":{}},"months":{"1":{},"10":{},"11":{},"12":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"daysOfWeek":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{}}}`,
},
{
"@weekly",
false,
`{"minutes":{"0":{}},"hours":{"0":{}},"days":{"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"28":{},"29":{},"3":{},"30":{},"31":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"months":{"1":{},"10":{},"11":{},"12":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"daysOfWeek":{"0":{}}}`,
},
{
"@daily",
false,
`{"minutes":{"0":{}},"hours":{"0":{}},"days":{"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"28":{},"29":{},"3":{},"30":{},"31":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"months":{"1":{},"10":{},"11":{},"12":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"daysOfWeek":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{}}}`,
},
{
"@midnight",
false,
`{"minutes":{"0":{}},"hours":{"0":{}},"days":{"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"28":{},"29":{},"3":{},"30":{},"31":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"months":{"1":{},"10":{},"11":{},"12":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"daysOfWeek":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{}}}`,
},
{
"@hourly",
false,
`{"minutes":{"0":{}},"hours":{"0":{},"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"days":{"1":{},"10":{},"11":{},"12":{},"13":{},"14":{},"15":{},"16":{},"17":{},"18":{},"19":{},"2":{},"20":{},"21":{},"22":{},"23":{},"24":{},"25":{},"26":{},"27":{},"28":{},"29":{},"3":{},"30":{},"31":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"months":{"1":{},"10":{},"11":{},"12":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{},"8":{},"9":{}},"daysOfWeek":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{}}}`,
},
}
for _, s := range scenarios {
+3 -1
View File
@@ -74,7 +74,9 @@ func NewLocal(dirPath string) (*System, error) {
return nil, err
}
bucket, err := fileblob.OpenBucket(dirPath, nil)
bucket, err := fileblob.OpenBucket(dirPath, &fileblob.Options{
NoTempDir: true,
})
if err != nil {
return nil, err
}
+19 -6
View File
@@ -39,12 +39,21 @@ func NewSmtpClient(
// SmtpClient defines a SMTP mail client structure that implements
// `mailer.Mailer` interface.
type SmtpClient struct {
Host string
Port int
Username string
Password string
Tls bool
AuthMethod string // default to "PLAIN"
Host string
Port int
Username string
Password string
Tls bool
// SMTP auth method to use
// (if not explicitly set, defaults to "PLAIN")
AuthMethod string
// LocalName is optional domain name used for the EHLO/HELO exchange
// (if not explicitly set, defaults to "localhost").
//
// This is required only by some SMTP servers, such as Gmail SMTP-relay.
LocalName string
}
// Send implements `mailer.Mailer` interface.
@@ -71,6 +80,10 @@ func (c *SmtpClient) Send(m *Message) error {
yak = mailyak.New(fmt.Sprintf("%s:%d", c.Host, c.Port), smtpAuth)
}
if c.LocalName != "" {
yak.LocalName(c.LocalName)
}
if m.From.Name != "" {
yak.FromName(m.From.Name)
}
+22 -1
View File
@@ -5,6 +5,7 @@ import (
"strings"
"github.com/labstack/echo/v5"
"github.com/pocketbase/pocketbase/tools/list"
"github.com/pocketbase/pocketbase/tools/search"
)
@@ -25,8 +26,10 @@ func (s *Serializer) Serialize(c echo.Context, i any, indent string) error {
fieldsParam = "fields"
}
statusCode := c.Response().Status
param := c.QueryParam(fieldsParam)
if param == "" {
if param == "" || statusCode < 200 || statusCode > 299 {
return s.DefaultJSONSerializer.Serialize(c, i, indent)
}
@@ -92,6 +95,24 @@ func pickMapFields(data map[string]any, fields []string) {
return // nothing to pick
}
if list.ExistInSlice("*", fields) {
// append all missing root level data keys
for k := range data {
var exists bool
for _, f := range fields {
if strings.HasPrefix(f+".", k+".") {
exists = true
break
}
}
if !exists {
fields = append(fields, k)
}
}
}
DataLoop:
for k := range data {
matchingFields := make([]string, 0, len(fields))
+125 -17
View File
@@ -16,6 +16,7 @@ func TestSerialize(t *testing.T) {
scenarios := []struct {
name string
serializer rest.Serializer
statusCode int
data any
query string
expected string
@@ -23,6 +24,7 @@ func TestSerialize(t *testing.T) {
{
"empty query",
rest.Serializer{},
200,
map[string]any{"a": 1, "b": 2, "c": "test"},
"",
`{"a":1,"b":2,"c":"test"}`,
@@ -30,6 +32,7 @@ func TestSerialize(t *testing.T) {
{
"empty fields",
rest.Serializer{},
200,
map[string]any{"a": 1, "b": 2, "c": "test"},
"fields=",
`{"a":1,"b":2,"c":"test"}`,
@@ -37,6 +40,7 @@ func TestSerialize(t *testing.T) {
{
"missing fields",
rest.Serializer{},
200,
map[string]any{"a": 1, "b": 2, "c": "test"},
"fields=missing",
`{}`,
@@ -44,6 +48,7 @@ func TestSerialize(t *testing.T) {
{
"non map response",
rest.Serializer{},
200,
"test",
"fields=a,b,test",
`"test"`,
@@ -51,13 +56,39 @@ func TestSerialize(t *testing.T) {
{
"non slice of map response",
rest.Serializer{},
200,
[]any{"a", "b", "test"},
"fields=a,test",
`["a","b","test"]`,
},
{
"map with no matching field",
rest.Serializer{},
200,
map[string]any{"a": 1, "b": 2, "c": "test"},
"fields=missing", // test individual fields trim
`{}`,
},
{
">299 response",
rest.Serializer{},
300,
map[string]any{"a": 1, "b": 2, "c": "test"},
"fields=missing",
`{"a":1,"b":2,"c":"test"}`,
},
{
"<200 response",
rest.Serializer{},
199,
map[string]any{"a": 1, "b": 2, "c": "test"},
"fields=missing",
`{"a":1,"b":2,"c":"test"}`,
},
{
"map with existing and missing fields",
rest.Serializer{},
200,
map[string]any{"a": 1, "b": 2, "c": "test"},
"fields=a, c ,missing", // test individual fields trim
`{"a":1,"c":"test"}`,
@@ -65,6 +96,7 @@ func TestSerialize(t *testing.T) {
{
"custom fields param",
rest.Serializer{FieldsParam: "custom"},
200,
map[string]any{"a": 1, "b": 2, "c": "test"},
"custom=a, c ,missing", // test individual fields trim
`{"a":1,"c":"test"}`,
@@ -72,6 +104,7 @@ func TestSerialize(t *testing.T) {
{
"slice of maps with existing and missing fields",
rest.Serializer{},
200,
[]any{
map[string]any{"a": 11, "b": 11, "c": "test1"},
map[string]any{"a": 22, "b": 22, "c": "test2"},
@@ -82,6 +115,7 @@ func TestSerialize(t *testing.T) {
{
"nested fields with mixed map and any slices",
rest.Serializer{},
200,
map[string]any{
"a": 1,
"b": 2,
@@ -139,6 +173,7 @@ func TestSerialize(t *testing.T) {
{
"SearchResult",
rest.Serializer{},
200,
search.Result{
Page: 1,
PerPage: 10,
@@ -155,6 +190,7 @@ func TestSerialize(t *testing.T) {
{
"*SearchResult",
rest.Serializer{},
200,
&search.Result{
Page: 1,
PerPage: 10,
@@ -168,28 +204,100 @@ func TestSerialize(t *testing.T) {
"fields=a,c",
`{"items":[{"a":11,"c":"test1"},{"a":22,"c":"test2"}],"page":1,"perPage":10,"totalItems":20,"totalPages":30}`,
},
{
"root wildcard",
rest.Serializer{},
200,
&search.Result{
Page: 1,
PerPage: 10,
TotalItems: 20,
TotalPages: 30,
Items: []any{
map[string]any{"a": 11, "b": 11, "c": "test1"},
map[string]any{"a": 22, "b": 22, "c": "test2"},
},
},
"fields=*",
`{"items":[{"a":11,"b":11,"c":"test1"},{"a":22,"b":22,"c":"test2"}],"page":1,"perPage":10,"totalItems":20,"totalPages":30}`,
},
{
"root wildcard with nested exception",
rest.Serializer{},
200,
map[string]any{
"id": "123",
"title": "lorem",
"rel": map[string]any{
"id": "456",
"title": "rel_title",
},
},
"fields=*,rel.id",
`{"id":"123","rel":{"id":"456"},"title":"lorem"}`,
},
{
"sub wildcard",
rest.Serializer{},
200,
map[string]any{
"id": "123",
"title": "lorem",
"rel": map[string]any{
"id": "456",
"title": "rel_title",
"sub": map[string]any{
"id": "789",
"title": "sub_title",
},
},
},
"fields=id,rel.*",
`{"id":"123","rel":{"id":"456","sub":{"id":"789","title":"sub_title"},"title":"rel_title"}}`,
},
{
"sub wildcard with nested exception",
rest.Serializer{},
200,
map[string]any{
"id": "123",
"title": "lorem",
"rel": map[string]any{
"id": "456",
"title": "rel_title",
"sub": map[string]any{
"id": "789",
"title": "sub_title",
},
},
},
"fields=id,rel.*,rel.sub.id",
`{"id":"123","rel":{"id":"456","sub":{"id":"789"},"title":"rel_title"}}`,
},
}
for _, s := range scenarios {
e := echo.New()
req := httptest.NewRequest(http.MethodPost, "/", nil)
req.URL.RawQuery = s.query
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
t.Run(s.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/", nil)
req.URL.RawQuery = s.query
rec := httptest.NewRecorder()
if err := s.serializer.Serialize(c, s.data, ""); err != nil {
t.Errorf("[%s] Serialize failure: %v", s.name, err)
continue
}
e := echo.New()
c := e.NewContext(req, rec)
c.Response().Status = s.statusCode
rawBody, err := io.ReadAll(rec.Result().Body)
if err != nil {
t.Errorf("[%s] Failed to read request body: %v", s.name, err)
continue
}
if err := s.serializer.Serialize(c, s.data, ""); err != nil {
t.Fatalf("Serialize failure: %v", err)
}
if v := strings.TrimSpace(string(rawBody)); v != s.expected {
t.Fatalf("[%s] Expected body\n%v \ngot: \n%v", s.name, s.expected, v)
}
rawBody, err := io.ReadAll(rec.Result().Body)
if err != nil {
t.Fatalf("Failed to read request body: %v", err)
}
if v := strings.TrimSpace(string(rawBody)); v != s.expected {
t.Fatalf("Expected body\n%v \ngot: \n%v", s.expected, v)
}
})
}
}
+59 -19
View File
@@ -1,25 +1,29 @@
package search
import (
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"github.com/ganigeorgiev/fexpr"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/tools/security"
"github.com/pocketbase/pocketbase/tools/store"
"github.com/pocketbase/pocketbase/tools/types"
"github.com/spf13/cast"
)
// FilterData is a filter expression string following the `fexpr` package grammar.
//
// The filter string can also contain dbx placeholder parameters (eg. "title = {:name}"),
// that will be safely replaced and properly quoted inplace with the placeholderReplacements values.
//
// Example:
//
// var filter FilterData = "id = null || (name = 'test' && status = true)"
// var filter FilterData = "id = null || (name = 'test' && status = true) || (total >= {:min} && total <= {:max})"
// resolver := search.NewSimpleFieldResolver("id", "name", "status")
// expr, err := filter.BuildExpr(resolver)
// expr, err := filter.BuildExpr(resolver, dbx.Params{"min": 100, "max": 200})
type FilterData string
// parsedFilterData holds a cache with previously parsed filter data expressions
@@ -27,10 +31,41 @@ type FilterData string
var parsedFilterData = store.New(make(map[string][]fexpr.ExprGroup, 50))
// BuildExpr parses the current filter data and returns a new db WHERE expression.
func (f FilterData) BuildExpr(fieldResolver FieldResolver) (dbx.Expression, error) {
//
// The filter string can also contain dbx placeholder parameters (eg. "title = {:name}"),
// that will be safely replaced and properly quoted inplace with the placeholderReplacements values.
func (f FilterData) BuildExpr(
fieldResolver FieldResolver,
placeholderReplacements ...dbx.Params,
) (dbx.Expression, error) {
raw := string(f)
// replace the placeholder params in the raw string filter
for _, p := range placeholderReplacements {
for key, value := range p {
var replacement string
switch v := value.(type) {
case nil:
replacement = "null"
case bool, float64, float32, int, int64, int32, int16, int8, uint, uint64, uint32, uint16, uint8:
replacement = cast.ToString(v)
default:
replacement = cast.ToString(v)
// try to json serialize as fallback
if replacement == "" {
raw, _ := json.Marshal(v)
replacement = string(raw)
}
replacement = strconv.Quote(replacement)
}
raw = strings.ReplaceAll(raw, "{:"+key+"}", replacement)
}
}
if parsedFilterData.Has(raw) {
return f.build(parsedFilterData.Get(raw), fieldResolver)
return buildParsedFilterExpr(parsedFilterData.Get(raw), fieldResolver)
}
data, err := fexpr.Parse(raw)
if err != nil {
@@ -39,10 +74,10 @@ func (f FilterData) BuildExpr(fieldResolver FieldResolver) (dbx.Expression, erro
// store in cache
// (the limit size is arbitrary and it is there to prevent the cache growing too big)
parsedFilterData.SetIfLessThanLimit(raw, data, 500)
return f.build(data, fieldResolver)
return buildParsedFilterExpr(data, fieldResolver)
}
func (f FilterData) build(data []fexpr.ExprGroup, fieldResolver FieldResolver) (dbx.Expression, error) {
func buildParsedFilterExpr(data []fexpr.ExprGroup, fieldResolver FieldResolver) (dbx.Expression, error) {
if len(data) == 0 {
return nil, errors.New("empty filter expression")
}
@@ -55,11 +90,11 @@ func (f FilterData) build(data []fexpr.ExprGroup, fieldResolver FieldResolver) (
switch item := group.Item.(type) {
case fexpr.Expr:
expr, exprErr = f.resolveTokenizedExpr(item, fieldResolver)
expr, exprErr = resolveTokenizedExpr(item, fieldResolver)
case fexpr.ExprGroup:
expr, exprErr = f.build([]fexpr.ExprGroup{item}, fieldResolver)
expr, exprErr = buildParsedFilterExpr([]fexpr.ExprGroup{item}, fieldResolver)
case []fexpr.ExprGroup:
expr, exprErr = f.build(item, fieldResolver)
expr, exprErr = buildParsedFilterExpr(item, fieldResolver)
default:
exprErr = errors.New("unsupported expression item")
}
@@ -84,7 +119,7 @@ func (f FilterData) build(data []fexpr.ExprGroup, fieldResolver FieldResolver) (
return result, nil
}
func (f FilterData) resolveTokenizedExpr(expr fexpr.Expr, fieldResolver FieldResolver) (dbx.Expression, error) {
func resolveTokenizedExpr(expr fexpr.Expr, fieldResolver FieldResolver) (dbx.Expression, error) {
lResult, lErr := resolveToken(expr.Left, fieldResolver)
if lErr != nil || lResult.Identifier == "" {
return nil, fmt.Errorf("invalid left operand %q - %v", expr.Left.Literal, lErr)
@@ -95,10 +130,10 @@ func (f FilterData) resolveTokenizedExpr(expr fexpr.Expr, fieldResolver FieldRes
return nil, fmt.Errorf("invalid right operand %q - %v", expr.Right.Literal, rErr)
}
return buildExpr(lResult, expr.Op, rResult)
return buildResolversExpr(lResult, expr.Op, rResult)
}
func buildExpr(
func buildResolversExpr(
left *ResolverResult,
op fexpr.SignOp,
right *ResolverResult,
@@ -182,14 +217,19 @@ func buildExpr(
func resolveToken(token fexpr.Token, fieldResolver FieldResolver) (*ResolverResult, error) {
switch token.Type {
case fexpr.TokenIdentifier:
// current datetime constant
// check for macros
// ---
if token.Literal == "@now" {
if macroFunc, ok := identifierMacros[token.Literal]; ok {
placeholder := "t" + security.PseudorandomString(5)
macroValue, err := macroFunc()
if err != nil {
return nil, err
}
return &ResolverResult{
Identifier: "{:" + placeholder + "}",
Params: dbx.Params{placeholder: types.NowDateTime().String()},
Params: dbx.Params{placeholder: macroValue},
}, nil
}
@@ -469,7 +509,7 @@ func (e *manyVsManyExpr) Build(db *dbx.DB, params dbx.Params) string {
lAlias := "__ml" + security.PseudorandomString(5)
rAlias := "__mr" + security.PseudorandomString(5)
whereExpr, buildErr := buildExpr(
whereExpr, buildErr := buildResolversExpr(
&ResolverResult{
Identifier: "[[" + lAlias + ".multiMatchValue]]",
},
@@ -536,9 +576,9 @@ func (e *manyVsOneExpr) Build(db *dbx.DB, params dbx.Params) string {
var buildErr error
if e.inverse {
whereExpr, buildErr = buildExpr(r2, e.op, r1)
whereExpr, buildErr = buildResolversExpr(r2, e.op, r1)
} else {
whereExpr, buildErr = buildExpr(r1, e.op, r2)
whereExpr, buildErr = buildResolversExpr(r1, e.op, r2)
}
if buildErr != nil {
+128 -86
View File
@@ -1,15 +1,19 @@
package search_test
import (
"context"
"database/sql"
"regexp"
"strings"
"testing"
"time"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/tools/search"
)
func TestFilterDataBuildExpr(t *testing.T) {
resolver := search.NewSimpleFieldResolver("test1", "test2", "test3", "test4.sub")
resolver := search.NewSimpleFieldResolver("test1", "test2", "test3", `^test4.\w+$`)
scenarios := []struct {
name string
@@ -25,7 +29,10 @@ func TestFilterDataBuildExpr(t *testing.T) {
},
{
"invalid format",
"(test1 > 1", true, ""},
"(test1 > 1",
true,
"",
},
{
"invalid operator",
"test1 + 123",
@@ -42,11 +49,7 @@ func TestFilterDataBuildExpr(t *testing.T) {
"simple expression",
"test1 > 1",
false,
"^" +
regexp.QuoteMeta("[[test1]] > {:") +
".+" +
regexp.QuoteMeta("}") +
"$",
"[[test1]] > {:TEST}",
},
{
"empty string vs null",
@@ -58,135 +61,174 @@ func TestFilterDataBuildExpr(t *testing.T) {
"like with 2 columns",
"test1 ~ test2",
false,
"^" +
regexp.QuoteMeta("[[test1]] LIKE ('%' || [[test2]] || '%') ESCAPE '\\'") +
"$",
"[[test1]] LIKE ('%' || [[test2]] || '%') ESCAPE '\\'",
},
{
"like with right column operand",
"'lorem' ~ test1",
false,
"^" +
regexp.QuoteMeta("{:") +
".+" +
regexp.QuoteMeta("} LIKE ('%' || [[test1]] || '%') ESCAPE '\\'") +
"$",
"{:TEST} LIKE ('%' || [[test1]] || '%') ESCAPE '\\'",
},
{
"like with left column operand and text as right operand",
"test1 ~ 'lorem'",
false,
"^" +
regexp.QuoteMeta("[[test1]] LIKE {:") +
".+" +
regexp.QuoteMeta("} ESCAPE '\\'") +
"$",
"[[test1]] LIKE {:TEST} ESCAPE '\\'",
},
{
"not like with 2 columns",
"test1 !~ test2",
false,
"^" +
regexp.QuoteMeta("[[test1]] NOT LIKE ('%' || [[test2]] || '%') ESCAPE '\\'") +
"$",
"[[test1]] NOT LIKE ('%' || [[test2]] || '%') ESCAPE '\\'",
},
{
"not like with right column operand",
"'lorem' !~ test1",
false,
"^" +
regexp.QuoteMeta("{:") +
".+" +
regexp.QuoteMeta("} NOT LIKE ('%' || [[test1]] || '%') ESCAPE '\\'") +
"$",
"{:TEST} NOT LIKE ('%' || [[test1]] || '%') ESCAPE '\\'",
},
{
"like with left column operand and text as right operand",
"test1 !~ 'lorem'",
false,
"^" +
regexp.QuoteMeta("[[test1]] NOT LIKE {:") +
".+" +
regexp.QuoteMeta("} ESCAPE '\\'") +
"$",
"[[test1]] NOT LIKE {:TEST} ESCAPE '\\'",
},
{
"current datetime constant",
"test1 > @now",
"macros",
`
test4.1 > @now &&
test4.2 > @second &&
test4.3 > @minute &&
test4.4 > @hour &&
test4.5 > @day &&
test4.6 > @year &&
test4.7 > @month &&
test4.9 > @weekday &&
test4.9 > @todayStart &&
test4.10 > @todayEnd &&
test4.11 > @monthStart &&
test4.12 > @monthEnd &&
test4.13 > @yearStart &&
test4.14 > @yearEnd
`,
false,
"^" +
regexp.QuoteMeta("[[test1]] > {:") +
".+" +
regexp.QuoteMeta("}") +
"$",
"([[test4.1]] > {:TEST} AND [[test4.2]] > {:TEST} AND [[test4.3]] > {:TEST} AND [[test4.4]] > {:TEST} AND [[test4.5]] > {:TEST} AND [[test4.6]] > {:TEST} AND [[test4.7]] > {:TEST} AND [[test4.9]] > {:TEST} AND [[test4.9]] > {:TEST} AND [[test4.10]] > {:TEST} AND [[test4.11]] > {:TEST} AND [[test4.12]] > {:TEST} AND [[test4.13]] > {:TEST} AND [[test4.14]] > {:TEST})",
},
{
"complex expression",
"((test1 > 1) || (test2 != 2)) && test3 ~ '%%example' && test4.sub = null",
false,
"^" +
regexp.QuoteMeta("(([[test1]] > {:") +
".+" +
regexp.QuoteMeta("} OR [[test2]] != {:") +
".+" +
regexp.QuoteMeta("}) AND [[test3]] LIKE {:") +
".+" +
regexp.QuoteMeta("} ESCAPE '\\' AND ([[test4.sub]] = '' OR [[test4.sub]] IS NULL))") +
"$",
"(([[test1]] > {:TEST} OR [[test2]] != {:TEST}) AND [[test3]] LIKE {:TEST} ESCAPE '\\' AND ([[test4.sub]] = '' OR [[test4.sub]] IS NULL))",
},
{
"combination of special literals (null, true, false)",
"test1=true && test2 != false && null = test3 || null != test4.sub",
false,
"^" + regexp.QuoteMeta("([[test1]] = 1 AND [[test2]] != 0 AND ('' = [[test3]] OR [[test3]] IS NULL) OR ('' != [[test4.sub]] AND [[test4.sub]] IS NOT NULL))") + "$",
"([[test1]] = 1 AND [[test2]] != 0 AND ('' = [[test3]] OR [[test3]] IS NULL) OR ('' != [[test4.sub]] AND [[test4.sub]] IS NOT NULL))",
},
{
"all operators",
"(test1 = test2 || test2 != test3) && (test2 ~ 'example' || test2 !~ '%%abc') && 'switch1%%' ~ test1 && 'switch2' !~ test2 && test3 > 1 && test3 >= 0 && test3 <= 4 && 2 < 5",
false,
"^" +
regexp.QuoteMeta("((COALESCE([[test1]], '') = COALESCE([[test2]], '') OR COALESCE([[test2]], '') != COALESCE([[test3]], '')) AND ([[test2]] LIKE {:") +
".+" +
regexp.QuoteMeta("} ESCAPE '\\' OR [[test2]] NOT LIKE {:") +
".+" +
regexp.QuoteMeta("} ESCAPE '\\') AND {:") +
".+" +
regexp.QuoteMeta("} LIKE ('%' || [[test1]] || '%') ESCAPE '\\' AND {:") +
".+" +
regexp.QuoteMeta("} NOT LIKE ('%' || [[test2]] || '%') ESCAPE '\\' AND [[test3]] > {:") +
".+" +
regexp.QuoteMeta("} AND [[test3]] >= {:") +
".+" +
regexp.QuoteMeta("} AND [[test3]] <= {:") +
".+" +
regexp.QuoteMeta("} AND {:") +
".+" +
regexp.QuoteMeta("} < {:") +
".+" +
regexp.QuoteMeta("})") +
"$",
"((COALESCE([[test1]], '') = COALESCE([[test2]], '') OR COALESCE([[test2]], '') != COALESCE([[test3]], '')) AND ([[test2]] LIKE {:TEST} ESCAPE '\\' OR [[test2]] NOT LIKE {:TEST} ESCAPE '\\') AND {:TEST} LIKE ('%' || [[test1]] || '%') ESCAPE '\\' AND {:TEST} NOT LIKE ('%' || [[test2]] || '%') ESCAPE '\\' AND [[test3]] > {:TEST} AND [[test3]] >= {:TEST} AND [[test3]] <= {:TEST} AND {:TEST} < {:TEST})",
},
}
for _, s := range scenarios {
expr, err := s.filterData.BuildExpr(resolver)
t.Run(s.name, func(t *testing.T) {
expr, err := s.filterData.BuildExpr(resolver)
hasErr := err != nil
if hasErr != s.expectError {
t.Errorf("[%s] Expected hasErr %v, got %v (%v)", s.name, s.expectError, hasErr, err)
continue
}
hasErr := err != nil
if hasErr != s.expectError {
t.Fatalf("[%s] Expected hasErr %v, got %v (%v)", s.name, s.expectError, hasErr, err)
}
if hasErr {
continue
}
if hasErr {
return
}
dummyDB := &dbx.DB{}
rawSql := expr.Build(dummyDB, map[string]any{})
dummyDB := &dbx.DB{}
pattern := regexp.MustCompile(s.expectPattern)
if !pattern.MatchString(rawSql) {
t.Errorf("[%s] Pattern %v don't match with expression: \n%v", s.name, s.expectPattern, rawSql)
}
rawSql := expr.Build(dummyDB, dbx.Params{})
// replace TEST placeholder with .+ regex pattern
expectPattern := strings.ReplaceAll(
"^"+regexp.QuoteMeta(s.expectPattern)+"$",
"TEST",
`\w+`,
)
pattern := regexp.MustCompile(expectPattern)
if !pattern.MatchString(rawSql) {
t.Fatalf("[%s] Pattern %v don't match with expression: \n%v", s.name, expectPattern, rawSql)
}
})
}
}
func TestFilterDataBuildExprWithParams(t *testing.T) {
// create a dummy db
sqlDB, err := sql.Open("sqlite", "file::memory:?cache=shared")
if err != nil {
t.Fatal(err)
}
db := dbx.NewFromDB(sqlDB, "sqlite")
calledQueries := []string{}
db.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
calledQueries = append(calledQueries, sql)
}
db.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {
calledQueries = append(calledQueries, sql)
}
date, err := time.Parse("2006-01-02", "2023-01-01")
if err != nil {
t.Fatal(err)
}
resolver := search.NewSimpleFieldResolver(`^test\w+$`)
filter := search.FilterData(`
test1 = {:test1} ||
test2 = {:test2} ||
test3a = {:test3} ||
test3b = {:test3} ||
test4 = {:test4} ||
test5 = {:test5} ||
test6 = {:test6} ||
test7 = {:test7} ||
test8 = {:test8} ||
test9 = {:test9} ||
test10 = {:test10} ||
test11 = {:test11} ||
test12 = {:test12}
`)
replacements := []dbx.Params{
{"test1": true},
{"test2": false},
{"test3": 123.456},
{"test4": nil},
{"test5": "", "test6": "simple", "test7": `'single_quotes'`, "test8": `"double_quotes"`, "test9": `escape\"quote`},
{"test10": date},
{"test11": []string{"a", "b", `"quote`}},
{"test12": map[string]any{"a": 123, "b": `quote"`}},
}
expr, err := filter.BuildExpr(resolver, replacements...)
if err != nil {
t.Fatal(err)
}
db.Select().Where(expr).Build().Execute()
if len(calledQueries) != 1 {
t.Fatalf("Expected 1 query, got %d", len(calledQueries))
}
expectedQuery := `SELECT * WHERE ([[test1]] = 1 OR [[test2]] = 0 OR [[test3a]] = 123.456 OR [[test3b]] = 123.456 OR ([[test4]] = '' OR [[test4]] IS NULL) OR [[test5]] = '""' OR [[test6]] = 'simple' OR [[test7]] = '''single_quotes''' OR [[test8]] = '"double_quotes"' OR [[test9]] = 'escape\\"quote' OR [[test10]] = '2023-01-01 00:00:00 +0000 UTC' OR [[test11]] = '["a","b","\\"quote"]' OR [[test12]] = '{"a":123,"b":"quote\\""}')`
if expectedQuery != calledQueries[0] {
t.Fatalf("Expected query \n%s, \ngot \n%s", expectedQuery, calledQueries[0])
}
}
+115
View File
@@ -0,0 +1,115 @@
package search
import (
"fmt"
"time"
"github.com/pocketbase/pocketbase/tools/types"
)
// note: used primarily for the tests
var timeNow = func() time.Time {
return time.Now()
}
var identifierMacros = map[string]func() (any, error){
"@now": func() (any, error) {
today := timeNow().UTC()
d, err := types.ParseDateTime(today)
if err != nil {
return "", fmt.Errorf("@now: %w", err)
}
return d.String(), nil
},
"@second": func() (any, error) {
return int(timeNow().UTC().Second()), nil
},
"@minute": func() (any, error) {
return int(timeNow().UTC().Minute()), nil
},
"@hour": func() (any, error) {
return int(timeNow().UTC().Hour()), nil
},
"@day": func() (any, error) {
return int(timeNow().UTC().Day()), nil
},
"@month": func() (any, error) {
return int(timeNow().UTC().Month()), nil
},
"@weekday": func() (any, error) {
return int(timeNow().UTC().Weekday()), nil
},
"@year": func() (any, error) {
return int(timeNow().UTC().Year()), nil
},
"@todayStart": func() (any, error) {
today := timeNow().UTC()
start := time.Date(today.Year(), today.Month(), today.Day(), 0, 0, 0, 0, time.UTC)
d, err := types.ParseDateTime(start)
if err != nil {
return "", fmt.Errorf("@todayStart: %w", err)
}
return d.String(), nil
},
"@todayEnd": func() (any, error) {
today := timeNow().UTC()
start := time.Date(today.Year(), today.Month(), today.Day(), 23, 59, 59, 999999999, time.UTC)
d, err := types.ParseDateTime(start)
if err != nil {
return "", fmt.Errorf("@todayEnd: %w", err)
}
return d.String(), nil
},
"@monthStart": func() (any, error) {
today := timeNow().UTC()
start := time.Date(today.Year(), today.Month(), 1, 0, 0, 0, 0, time.UTC)
d, err := types.ParseDateTime(start)
if err != nil {
return "", fmt.Errorf("@monthStart: %w", err)
}
return d.String(), nil
},
"@monthEnd": func() (any, error) {
today := timeNow().UTC()
start := time.Date(today.Year(), today.Month(), 1, 23, 59, 59, 999999999, time.UTC)
end := start.AddDate(0, 1, -1)
d, err := types.ParseDateTime(end)
if err != nil {
return "", fmt.Errorf("@monthEnd: %w", err)
}
return d.String(), nil
},
"@yearStart": func() (any, error) {
today := timeNow().UTC()
start := time.Date(today.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
d, err := types.ParseDateTime(start)
if err != nil {
return "", fmt.Errorf("@yearStart: %w", err)
}
return d.String(), nil
},
"@yearEnd": func() (any, error) {
today := timeNow().UTC()
end := time.Date(today.Year(), 12, 31, 23, 59, 59, 999999999, time.UTC)
d, err := types.ParseDateTime(end)
if err != nil {
return "", fmt.Errorf("@yearEnd: %w", err)
}
return d.String(), nil
},
}
+56
View File
@@ -0,0 +1,56 @@
package search
import (
"testing"
"time"
)
func TestIdentifierMacros(t *testing.T) {
originalTimeNow := timeNow
timeNow = func() time.Time {
return time.Date(2023, 2, 3, 4, 5, 6, 7, time.UTC)
}
testMacros := map[string]any{
"@now": "2023-02-03 04:05:06.000Z",
"@second": 6,
"@minute": 5,
"@hour": 4,
"@day": 3,
"@month": 2,
"@weekday": 5,
"@year": 2023,
"@todayStart": "2023-02-03 00:00:00.000Z",
"@todayEnd": "2023-02-03 23:59:59.999Z",
"@monthStart": "2023-02-01 00:00:00.000Z",
"@monthEnd": "2023-02-28 23:59:59.999Z",
"@yearStart": "2023-01-01 00:00:00.000Z",
"@yearEnd": "2023-12-31 23:59:59.999Z",
}
if len(testMacros) != len(identifierMacros) {
t.Fatalf("Expected %d macros, got %d", len(testMacros), len(identifierMacros))
}
for key, expected := range testMacros {
t.Run(key, func(t *testing.T) {
macro, ok := identifierMacros[key]
if !ok {
t.Fatalf("Missing macro %s", key)
}
result, err := macro()
if err != nil {
t.Fatal(err)
}
if result != expected {
t.Fatalf("Expected %q, got %q", expected, result)
}
})
}
// restore
timeNow = originalTimeNow
}
+62
View File
@@ -0,0 +1,62 @@
package security
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"crypto/sha512"
"crypto/subtle"
"encoding/base64"
"fmt"
"strings"
)
// S256Challenge creates base64 encoded sha256 challenge string derived from code.
// The padding of the result base64 string is stripped per [RFC 7636].
//
// [RFC 7636]: https://datatracker.ietf.org/doc/html/rfc7636#section-4.2
func S256Challenge(code string) string {
h := sha256.New()
h.Write([]byte(code))
return strings.TrimRight(base64.URLEncoding.EncodeToString(h.Sum(nil)), "=")
}
// MD5 creates md5 hash from the provided plain text.
func MD5(text string) string {
h := md5.New()
h.Write([]byte(text))
return fmt.Sprintf("%x", h.Sum(nil))
}
// SHA256 creates sha256 hash as defined in FIPS 180-4 from the provided text.
func SHA256(text string) string {
h := sha256.New()
h.Write([]byte(text))
return fmt.Sprintf("%x", h.Sum(nil))
}
// SHA512 creates sha512 hash as defined in FIPS 180-4 from the provided text.
func SHA512(text string) string {
h := sha512.New()
h.Write([]byte(text))
return fmt.Sprintf("%x", h.Sum(nil))
}
// HS256 creates a HMAC hash with sha256 digest algorithm.
func HS256(text string, secret string) string {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(text))
return fmt.Sprintf("%x", h.Sum(nil))
}
// HS512 creates a HMAC hash with sha512 digest algorithm.
func HS512(text string, secret string) string {
h := hmac.New(sha512.New, []byte(secret))
h.Write([]byte(text))
return fmt.Sprintf("%x", h.Sum(nil))
}
// Equal compares two hash strings for equality without leaking timing information.
func Equal(hash1 string, hash2 string) bool {
return subtle.ConstantTimeCompare([]byte(hash1), []byte(hash2)) == 1
}
+156
View File
@@ -0,0 +1,156 @@
package security_test
import (
"fmt"
"testing"
"github.com/pocketbase/pocketbase/tools/security"
)
func TestS256Challenge(t *testing.T) {
scenarios := []struct {
code string
expected string
}{
{"", "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"},
{"123", "pmWkWSBCL51Bfkhn79xPuKBKHz__H6B-mY6G9_eieuM"},
}
for _, s := range scenarios {
t.Run(s.code, func(t *testing.T) {
result := security.S256Challenge(s.code)
if result != s.expected {
t.Fatalf("Expected %q, got %q", s.expected, result)
}
})
}
}
func TestMD5(t *testing.T) {
scenarios := []struct {
code string
expected string
}{
{"", "d41d8cd98f00b204e9800998ecf8427e"},
{"123", "202cb962ac59075b964b07152d234b70"},
}
for _, s := range scenarios {
t.Run(s.code, func(t *testing.T) {
result := security.MD5(s.code)
if result != s.expected {
t.Fatalf("Expected %v, got %v", s.expected, result)
}
})
}
}
func TestSHA256(t *testing.T) {
scenarios := []struct {
code string
expected string
}{
{"", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"},
{"123", "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"},
}
for _, s := range scenarios {
t.Run(s.code, func(t *testing.T) {
result := security.SHA256(s.code)
if result != s.expected {
t.Fatalf("Expected %v, got %v", s.expected, result)
}
})
}
}
func TestSHA512(t *testing.T) {
scenarios := []struct {
code string
expected string
}{
{"", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"},
{"123", "3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2"},
}
for _, s := range scenarios {
t.Run(s.code, func(t *testing.T) {
result := security.SHA512(s.code)
if result != s.expected {
t.Fatalf("Expected %v, got %v", s.expected, result)
}
})
}
}
func TestHS256(t *testing.T) {
scenarios := []struct {
text string
secret string
expected string
}{
{" ", "test", "9fb4e4a12d50728683a222b4fc466a69ee977332cfcdd6b9ebb44c7121dbd99f"},
{" ", "test2", "d792417a504716e22805d940125ec12e68e8cb18fc84674703bd96c59f1e1228"},
{"hello", "test", "f151ea24bda91a18e89b8bb5793ef324b2a02133cce15a28a719acbd2e58a986"},
{"hello", "test2", "16436e8dcbf3d7b5b0455573b27e6372699beb5bfe94e6a2a371b14b4ae068f4"},
}
for i, s := range scenarios {
t.Run(fmt.Sprintf("%d-%s", i, s.text), func(t *testing.T) {
result := security.HS256(s.text, s.secret)
if result != s.expected {
t.Fatalf("Expected \n%v, \ngot \n%v", s.expected, result)
}
})
}
}
func TestHS512(t *testing.T) {
scenarios := []struct {
text string
secret string
expected string
}{
{" ", "test", "eb3bdb0352c95c38880c1f645fc7e1d1332644f938f50de0d73876e42d6f302e599bb526531ba79940e8b314369aaef3675322d8d851f9fc6ea9ed121286d196"},
{" ", "test2", "8b69e84e9252af78ae8b1c4bed3c9f737f69a3df33064cfbefe76b36d19d1827285e543cdf066cdc8bd556cc0cd0e212d52e9c12a50cd16046181ff127f4cf7f"},
{"hello", "test", "44f280e11103e295c26cd61dd1cdd8178b531b860466867c13b1c37a26b6389f8af110efbe0bb0717b9d9c87f6fe1c97b3b1690936578890e5669abf279fe7fd"},
{"hello", "test2", "d7f10b1b66941b20817689b973ca9dfc971090e28cfb8becbddd6824569b323eca6a0cdf2c387aa41e15040007dca5a011dd4e4bb61cfd5011aa7354d866f6ef"},
}
for i, s := range scenarios {
t.Run(fmt.Sprintf("%d-%q", i, s.text), func(t *testing.T) {
result := security.HS512(s.text, s.secret)
if result != s.expected {
t.Fatalf("Expected \n%v, \ngot \n%v", s.expected, result)
}
})
}
}
func TestEqual(t *testing.T) {
scenarios := []struct {
hash1 string
hash2 string
expected bool
}{
{"", "", true},
{"abc", "abd", false},
{"abc", "abc", true},
}
for _, s := range scenarios {
t.Run(fmt.Sprintf("%qVS%q", s.hash1, s.hash2), func(t *testing.T) {
result := security.Equal(s.hash1, s.hash2)
if result != s.expected {
t.Fatalf("Expected %v, got %v", s.expected, result)
}
})
}
}
-12
View File
@@ -4,22 +4,10 @@ import (
"crypto/aes"
"crypto/cipher"
crand "crypto/rand"
"crypto/sha256"
"encoding/base64"
"io"
"strings"
)
// S256Challenge creates base64 encoded sha256 challenge string derived from code.
// The padding of the result base64 string is stripped per [RFC 7636].
//
// [RFC 7636]: https://datatracker.ietf.org/doc/html/rfc7636#section-4.2
func S256Challenge(code string) string {
h := sha256.New()
h.Write([]byte(code))
return strings.TrimRight(base64.URLEncoding.EncodeToString(h.Sum(nil)), "=")
}
// Encrypt encrypts data with key (must be valid 32 char aes key).
func Encrypt(data []byte, key string) (string, error) {
block, err := aes.NewCipher([]byte(key))
-18
View File
@@ -6,24 +6,6 @@ import (
"github.com/pocketbase/pocketbase/tools/security"
)
func TestS256Challenge(t *testing.T) {
scenarios := []struct {
code string
expected string
}{
{"", "47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU"},
{"123", "pmWkWSBCL51Bfkhn79xPuKBKHz__H6B-mY6G9_eieuM"},
}
for i, scenario := range scenarios {
result := security.S256Challenge(scenario.code)
if result != scenario.expected {
t.Errorf("(%d) Expected %q, got %q", i, scenario.expected, result)
}
}
}
func TestEncrypt(t *testing.T) {
scenarios := []struct {
data string
+1 -1
View File
@@ -9,4 +9,4 @@ PB_DOCS_URL = "https://pocketbase.io/docs/"
PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk"
PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk"
PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases"
PB_VERSION = "v0.17.2"
PB_VERSION = "v0.18.2"
-66
View File
@@ -1,66 +0,0 @@
import{S as $e,i as Se,s as ye,e as c,w,b as k,c as oe,f as h,g as d,h as a,m as se,x as G,N as we,P as Te,k as je,Q as Ae,n as Be,t as U,a as W,o as u,d as ae,T as Fe,C as Oe,p as Qe,r as V,u as Ne,M as He}from"./index-9e84ac8a.js";import{S as Ke}from"./SdkTabs-821a18db.js";import{F as qe}from"./FieldsQueryParam-664da4c8.js";function ve(n,l,o){const s=n.slice();return s[5]=l[o],s}function Ce(n,l,o){const s=n.slice();return s[5]=l[o],s}function Pe(n,l){let o,s=l[5].code+"",_,p,i,f;function m(){return l[4](l[5])}return{key:n,first:null,c(){o=c("button"),_=w(s),p=k(),h(o,"class","tab-item"),V(o,"active",l[1]===l[5].code),this.first=o},m(v,C){d(v,o,C),a(o,_),a(o,p),i||(f=Ne(o,"click",m),i=!0)},p(v,C){l=v,C&4&&s!==(s=l[5].code+"")&&G(_,s),C&6&&V(o,"active",l[1]===l[5].code)},d(v){v&&u(o),i=!1,f()}}}function Me(n,l){let o,s,_,p;return s=new He({props:{content:l[5].body}}),{key:n,first:null,c(){o=c("div"),oe(s.$$.fragment),_=k(),h(o,"class","tab-item"),V(o,"active",l[1]===l[5].code),this.first=o},m(i,f){d(i,o,f),se(s,o,null),a(o,_),p=!0},p(i,f){l=i;const m={};f&4&&(m.content=l[5].body),s.$set(m),(!p||f&6)&&V(o,"active",l[1]===l[5].code)},i(i){p||(U(s.$$.fragment,i),p=!0)},o(i){W(s.$$.fragment,i),p=!1},d(i){i&&u(o),ae(s)}}}function ze(n){var _e,be;let l,o,s=n[0].name+"",_,p,i,f,m,v,C,H=n[0].name+"",L,ne,E,P,I,j,J,M,K,ie,q,A,ce,Y,z=n[0].name+"",X,re,R,B,Z,$,x,de,ee,T,te,F,le,S,O,g=[],ue=new Map,fe,Q,b=[],me=new Map,y;P=new Ke({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[3]}');
...
const result = await pb.collection('${(_e=n[0])==null?void 0:_e.name}').listAuthMethods();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[3]}');
...
final result = await pb.collection('${(be=n[0])==null?void 0:be.name}').listAuthMethods();
`}}),T=new qe({});let D=n[2];const pe=e=>e[5].code;for(let e=0;e<D.length;e+=1){let t=Ce(n,D,e),r=pe(t);ue.set(r,g[e]=Pe(r,t))}let N=n[2];const he=e=>e[5].code;for(let e=0;e<N.length;e+=1){let t=ve(n,N,e),r=he(t);me.set(r,b[e]=Me(r,t))}return{c(){l=c("h3"),o=w("List auth methods ("),_=w(s),p=w(")"),i=k(),f=c("div"),m=c("p"),v=w("Returns a public list with all allowed "),C=c("strong"),L=w(H),ne=w(" authentication methods."),E=k(),oe(P.$$.fragment),I=k(),j=c("h6"),j.textContent="API details",J=k(),M=c("div"),K=c("strong"),K.textContent="GET",ie=k(),q=c("div"),A=c("p"),ce=w("/api/collections/"),Y=c("strong"),X=w(z),re=w("/auth-methods"),R=k(),B=c("div"),B.textContent="Query parameters",Z=k(),$=c("table"),x=c("thead"),x.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="50%">Description</th></tr>`,de=k(),ee=c("tbody"),oe(T.$$.fragment),te=k(),F=c("div"),F.textContent="Responses",le=k(),S=c("div"),O=c("div");for(let e=0;e<g.length;e+=1)g[e].c();fe=k(),Q=c("div");for(let e=0;e<b.length;e+=1)b[e].c();h(l,"class","m-b-sm"),h(f,"class","content txt-lg m-b-sm"),h(j,"class","m-b-xs"),h(K,"class","label label-primary"),h(q,"class","content"),h(M,"class","alert alert-info"),h(B,"class","section-title"),h($,"class","table-compact table-border m-b-base"),h(F,"class","section-title"),h(O,"class","tabs-header compact left"),h(Q,"class","tabs-content"),h(S,"class","tabs")},m(e,t){d(e,l,t),a(l,o),a(l,_),a(l,p),d(e,i,t),d(e,f,t),a(f,m),a(m,v),a(m,C),a(C,L),a(m,ne),d(e,E,t),se(P,e,t),d(e,I,t),d(e,j,t),d(e,J,t),d(e,M,t),a(M,K),a(M,ie),a(M,q),a(q,A),a(A,ce),a(A,Y),a(Y,X),a(A,re),d(e,R,t),d(e,B,t),d(e,Z,t),d(e,$,t),a($,x),a($,de),a($,ee),se(T,ee,null),d(e,te,t),d(e,F,t),d(e,le,t),d(e,S,t),a(S,O);for(let r=0;r<g.length;r+=1)g[r]&&g[r].m(O,null);a(S,fe),a(S,Q);for(let r=0;r<b.length;r+=1)b[r]&&b[r].m(Q,null);y=!0},p(e,[t]){var ke,ge;(!y||t&1)&&s!==(s=e[0].name+"")&&G(_,s),(!y||t&1)&&H!==(H=e[0].name+"")&&G(L,H);const r={};t&9&&(r.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
const result = await pb.collection('${(ke=e[0])==null?void 0:ke.name}').listAuthMethods();
`),t&9&&(r.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
final result = await pb.collection('${(ge=e[0])==null?void 0:ge.name}').listAuthMethods();
`),P.$set(r),(!y||t&1)&&z!==(z=e[0].name+"")&&G(X,z),t&6&&(D=e[2],g=we(g,t,pe,1,e,D,ue,O,Te,Pe,null,Ce)),t&6&&(N=e[2],je(),b=we(b,t,he,1,e,N,me,Q,Ae,Me,null,ve),Be())},i(e){if(!y){U(P.$$.fragment,e),U(T.$$.fragment,e);for(let t=0;t<N.length;t+=1)U(b[t]);y=!0}},o(e){W(P.$$.fragment,e),W(T.$$.fragment,e);for(let t=0;t<b.length;t+=1)W(b[t]);y=!1},d(e){e&&u(l),e&&u(i),e&&u(f),e&&u(E),ae(P,e),e&&u(I),e&&u(j),e&&u(J),e&&u(M),e&&u(R),e&&u(B),e&&u(Z),e&&u($),ae(T),e&&u(te),e&&u(F),e&&u(le),e&&u(S);for(let t=0;t<g.length;t+=1)g[t].d();for(let t=0;t<b.length;t+=1)b[t].d()}}}function De(n,l,o){let s,{collection:_=new Fe}=l,p=200,i=[];const f=m=>o(1,p=m.code);return n.$$set=m=>{"collection"in m&&o(0,_=m.collection)},o(3,s=Oe.getApiExampleUrl(Qe.baseUrl)),o(2,i=[{code:200,body:`
{
"usernamePassword": true,
"emailPassword": true,
"authProviders": [
{
"name": "github",
"state": "3Yd8jNkK_6PJG6hPWwBjLqKwse6Ejd",
"codeVerifier": "KxFDWz1B3fxscCDJ_9gHQhLuh__ie7",
"codeChallenge": "NM1oVexB6Q6QH8uPtOUfK7tq4pmu4Jz6lNDIwoxHZNE=",
"codeChallengeMethod": "S256",
"authUrl": "https://github.com/login/oauth/authorize?client_id=demo&code_challenge=NM1oVexB6Q6QH8uPtOUfK7tq4pmu4Jz6lNDIwoxHZNE%3D&code_challenge_method=S256&response_type=code&scope=user&state=3Yd8jNkK_6PJG6hPWwBjLqKwse6Ejd&redirect_uri="
},
{
"name": "gitlab",
"state": "NeQSbtO5cShr_mk5__3CUukiMnymeb",
"codeVerifier": "ahTFHOgua8mkvPAlIBGwCUJbWKR_xi",
"codeChallenge": "O-GATkTj4eXDCnfonsqGLCd6njvTixlpCMvy5kjgOOg=",
"codeChallengeMethod": "S256",
"authUrl": "https://gitlab.com/oauth/authorize?client_id=demo&code_challenge=O-GATkTj4eXDCnfonsqGLCd6njvTixlpCMvy5kjgOOg%3D&code_challenge_method=S256&response_type=code&scope=read_user&state=NeQSbtO5cShr_mk5__3CUukiMnymeb&redirect_uri="
},
{
"name": "google",
"state": "zB3ZPifV1TW2GMuvuFkamSXfSNkHPQ",
"codeVerifier": "t3CmO5VObGzdXqieakvR_fpjiW0zdO",
"codeChallenge": "KChwoQPKYlz2anAdqtgsSTdIo8hdwtc1fh2wHMwW2Yk=",
"codeChallengeMethod": "S256",
"authUrl": "https://accounts.google.com/o/oauth2/auth?client_id=demo&code_challenge=KChwoQPKYlz2anAdqtgsSTdIo8hdwtc1fh2wHMwW2Yk%3D&code_challenge_method=S256&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&state=zB3ZPifV1TW2GMuvuFkamSXfSNkHPQ&redirect_uri="
}
]
}
`}]),[_,p,i,s,f]}class Ve extends $e{constructor(l){super(),Se(this,l,De,ze,ye,{collection:0})}}export{Ve as default};
+64
View File
@@ -0,0 +1,64 @@
import{S as Se,i as ye,s as Te,O as G,e as c,w,b as k,c as se,f as p,g as d,h as a,m as ae,x as U,P as ve,Q as je,k as Ae,R as Be,n as Oe,t as W,a as V,o as u,d as ne,C as Fe,p as Qe,r as L,u as Ne,N as He}from"./index-f26826b5.js";import{S as Ke}from"./SdkTabs-37a2d588.js";import{F as qe}from"./FieldsQueryParam-e2795694.js";function Ce(n,l,o){const s=n.slice();return s[5]=l[o],s}function Pe(n,l,o){const s=n.slice();return s[5]=l[o],s}function $e(n,l){let o,s=l[5].code+"",_,f,i,h;function m(){return l[4](l[5])}return{key:n,first:null,c(){o=c("button"),_=w(s),f=k(),p(o,"class","tab-item"),L(o,"active",l[1]===l[5].code),this.first=o},m(v,C){d(v,o,C),a(o,_),a(o,f),i||(h=Ne(o,"click",m),i=!0)},p(v,C){l=v,C&4&&s!==(s=l[5].code+"")&&U(_,s),C&6&&L(o,"active",l[1]===l[5].code)},d(v){v&&u(o),i=!1,h()}}}function Me(n,l){let o,s,_,f;return s=new He({props:{content:l[5].body}}),{key:n,first:null,c(){o=c("div"),se(s.$$.fragment),_=k(),p(o,"class","tab-item"),L(o,"active",l[1]===l[5].code),this.first=o},m(i,h){d(i,o,h),ae(s,o,null),a(o,_),f=!0},p(i,h){l=i;const m={};h&4&&(m.content=l[5].body),s.$set(m),(!f||h&6)&&L(o,"active",l[1]===l[5].code)},i(i){f||(W(s.$$.fragment,i),f=!0)},o(i){V(s.$$.fragment,i),f=!1},d(i){i&&u(o),ne(s)}}}function ze(n){var be,ke;let l,o,s=n[0].name+"",_,f,i,h,m,v,C,H=n[0].name+"",E,ie,I,P,J,j,Y,$,K,ce,q,A,re,R,z=n[0].name+"",X,de,Z,B,x,M,ee,ue,te,T,le,O,oe,S,F,g=[],he=new Map,me,Q,b=[],fe=new Map,y;P=new Ke({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[3]}');
...
const result = await pb.collection('${(be=n[0])==null?void 0:be.name}').listAuthMethods();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[3]}');
...
final result = await pb.collection('${(ke=n[0])==null?void 0:ke.name}').listAuthMethods();
`}}),T=new qe({});let D=G(n[2]);const pe=e=>e[5].code;for(let e=0;e<D.length;e+=1){let t=Pe(n,D,e),r=pe(t);he.set(r,g[e]=$e(r,t))}let N=G(n[2]);const _e=e=>e[5].code;for(let e=0;e<N.length;e+=1){let t=Ce(n,N,e),r=_e(t);fe.set(r,b[e]=Me(r,t))}return{c(){l=c("h3"),o=w("List auth methods ("),_=w(s),f=w(")"),i=k(),h=c("div"),m=c("p"),v=w("Returns a public list with all allowed "),C=c("strong"),E=w(H),ie=w(" authentication methods."),I=k(),se(P.$$.fragment),J=k(),j=c("h6"),j.textContent="API details",Y=k(),$=c("div"),K=c("strong"),K.textContent="GET",ce=k(),q=c("div"),A=c("p"),re=w("/api/collections/"),R=c("strong"),X=w(z),de=w("/auth-methods"),Z=k(),B=c("div"),B.textContent="Query parameters",x=k(),M=c("table"),ee=c("thead"),ee.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',ue=k(),te=c("tbody"),se(T.$$.fragment),le=k(),O=c("div"),O.textContent="Responses",oe=k(),S=c("div"),F=c("div");for(let e=0;e<g.length;e+=1)g[e].c();me=k(),Q=c("div");for(let e=0;e<b.length;e+=1)b[e].c();p(l,"class","m-b-sm"),p(h,"class","content txt-lg m-b-sm"),p(j,"class","m-b-xs"),p(K,"class","label label-primary"),p(q,"class","content"),p($,"class","alert alert-info"),p(B,"class","section-title"),p(M,"class","table-compact table-border m-b-base"),p(O,"class","section-title"),p(F,"class","tabs-header compact combined left"),p(Q,"class","tabs-content"),p(S,"class","tabs")},m(e,t){d(e,l,t),a(l,o),a(l,_),a(l,f),d(e,i,t),d(e,h,t),a(h,m),a(m,v),a(m,C),a(C,E),a(m,ie),d(e,I,t),ae(P,e,t),d(e,J,t),d(e,j,t),d(e,Y,t),d(e,$,t),a($,K),a($,ce),a($,q),a(q,A),a(A,re),a(A,R),a(R,X),a(A,de),d(e,Z,t),d(e,B,t),d(e,x,t),d(e,M,t),a(M,ee),a(M,ue),a(M,te),ae(T,te,null),d(e,le,t),d(e,O,t),d(e,oe,t),d(e,S,t),a(S,F);for(let r=0;r<g.length;r+=1)g[r]&&g[r].m(F,null);a(S,me),a(S,Q);for(let r=0;r<b.length;r+=1)b[r]&&b[r].m(Q,null);y=!0},p(e,[t]){var ge,we;(!y||t&1)&&s!==(s=e[0].name+"")&&U(_,s),(!y||t&1)&&H!==(H=e[0].name+"")&&U(E,H);const r={};t&9&&(r.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
const result = await pb.collection('${(ge=e[0])==null?void 0:ge.name}').listAuthMethods();
`),t&9&&(r.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
final result = await pb.collection('${(we=e[0])==null?void 0:we.name}').listAuthMethods();
`),P.$set(r),(!y||t&1)&&z!==(z=e[0].name+"")&&U(X,z),t&6&&(D=G(e[2]),g=ve(g,t,pe,1,e,D,he,F,je,$e,null,Pe)),t&6&&(N=G(e[2]),Ae(),b=ve(b,t,_e,1,e,N,fe,Q,Be,Me,null,Ce),Oe())},i(e){if(!y){W(P.$$.fragment,e),W(T.$$.fragment,e);for(let t=0;t<N.length;t+=1)W(b[t]);y=!0}},o(e){V(P.$$.fragment,e),V(T.$$.fragment,e);for(let t=0;t<b.length;t+=1)V(b[t]);y=!1},d(e){e&&(u(l),u(i),u(h),u(I),u(J),u(j),u(Y),u($),u(Z),u(B),u(x),u(M),u(le),u(O),u(oe),u(S)),ne(P,e),ne(T);for(let t=0;t<g.length;t+=1)g[t].d();for(let t=0;t<b.length;t+=1)b[t].d()}}}function De(n,l,o){let s,{collection:_}=l,f=200,i=[];const h=m=>o(1,f=m.code);return n.$$set=m=>{"collection"in m&&o(0,_=m.collection)},o(3,s=Fe.getApiExampleUrl(Qe.baseUrl)),o(2,i=[{code:200,body:`
{
"usernamePassword": true,
"emailPassword": true,
"authProviders": [
{
"name": "github",
"state": "3Yd8jNkK_6PJG6hPWwBjLqKwse6Ejd",
"codeVerifier": "KxFDWz1B3fxscCDJ_9gHQhLuh__ie7",
"codeChallenge": "NM1oVexB6Q6QH8uPtOUfK7tq4pmu4Jz6lNDIwoxHZNE=",
"codeChallengeMethod": "S256",
"authUrl": "https://github.com/login/oauth/authorize?client_id=demo&code_challenge=NM1oVexB6Q6QH8uPtOUfK7tq4pmu4Jz6lNDIwoxHZNE%3D&code_challenge_method=S256&response_type=code&scope=user&state=3Yd8jNkK_6PJG6hPWwBjLqKwse6Ejd&redirect_uri="
},
{
"name": "gitlab",
"state": "NeQSbtO5cShr_mk5__3CUukiMnymeb",
"codeVerifier": "ahTFHOgua8mkvPAlIBGwCUJbWKR_xi",
"codeChallenge": "O-GATkTj4eXDCnfonsqGLCd6njvTixlpCMvy5kjgOOg=",
"codeChallengeMethod": "S256",
"authUrl": "https://gitlab.com/oauth/authorize?client_id=demo&code_challenge=O-GATkTj4eXDCnfonsqGLCd6njvTixlpCMvy5kjgOOg%3D&code_challenge_method=S256&response_type=code&scope=read_user&state=NeQSbtO5cShr_mk5__3CUukiMnymeb&redirect_uri="
},
{
"name": "google",
"state": "zB3ZPifV1TW2GMuvuFkamSXfSNkHPQ",
"codeVerifier": "t3CmO5VObGzdXqieakvR_fpjiW0zdO",
"codeChallenge": "KChwoQPKYlz2anAdqtgsSTdIo8hdwtc1fh2wHMwW2Yk=",
"codeChallengeMethod": "S256",
"authUrl": "https://accounts.google.com/o/oauth2/auth?client_id=demo&code_challenge=KChwoQPKYlz2anAdqtgsSTdIo8hdwtc1fh2wHMwW2Yk%3D&code_challenge_method=S256&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&state=zB3ZPifV1TW2GMuvuFkamSXfSNkHPQ&redirect_uri="
}
]
}
`}]),[_,f,i,s,h]}class Ve extends Se{constructor(l){super(),ye(this,l,De,ze,Te,{collection:0})}}export{Ve as default};
+79
View File
@@ -0,0 +1,79 @@
import{S as je,i as xe,s as Je,N as Ue,O as J,e as s,w as k,b as p,c as K,f as b,g as d,h as o,m as I,x as de,P as Ee,Q as Ke,k as Ie,R as We,n as Ge,t as N,a as V,o as u,d as W,C as Le,p as Xe,r as G,u as Ye}from"./index-f26826b5.js";import{S as Ze}from"./SdkTabs-37a2d588.js";import{F as et}from"./FieldsQueryParam-e2795694.js";function Ne(r,l,a){const n=r.slice();return n[5]=l[a],n}function Ve(r,l,a){const n=r.slice();return n[5]=l[a],n}function ze(r,l){let a,n=l[5].code+"",m,_,i,h;function g(){return l[4](l[5])}return{key:r,first:null,c(){a=s("button"),m=k(n),_=p(),b(a,"class","tab-item"),G(a,"active",l[1]===l[5].code),this.first=a},m(v,w){d(v,a,w),o(a,m),o(a,_),i||(h=Ye(a,"click",g),i=!0)},p(v,w){l=v,w&4&&n!==(n=l[5].code+"")&&de(m,n),w&6&&G(a,"active",l[1]===l[5].code)},d(v){v&&u(a),i=!1,h()}}}function Qe(r,l){let a,n,m,_;return n=new Ue({props:{content:l[5].body}}),{key:r,first:null,c(){a=s("div"),K(n.$$.fragment),m=p(),b(a,"class","tab-item"),G(a,"active",l[1]===l[5].code),this.first=a},m(i,h){d(i,a,h),I(n,a,null),o(a,m),_=!0},p(i,h){l=i;const g={};h&4&&(g.content=l[5].body),n.$set(g),(!_||h&6)&&G(a,"active",l[1]===l[5].code)},i(i){_||(N(n.$$.fragment,i),_=!0)},o(i){V(n.$$.fragment,i),_=!1},d(i){i&&u(a),W(n)}}}function tt(r){var De,Fe;let l,a,n=r[0].name+"",m,_,i,h,g,v,w,M,X,S,z,ue,Q,q,pe,Y,U=r[0].name+"",Z,he,fe,j,ee,D,te,T,oe,be,F,C,le,me,ae,_e,f,ke,R,ge,ve,$e,se,ye,ne,Se,we,Te,re,Ce,Pe,A,ie,O,ce,P,H,y=[],Re=new Map,Ae,E,$=[],Be=new Map,B;v=new Ze({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${r[3]}');
...
const authData = await pb.collection('${(De=r[0])==null?void 0:De.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${r[3]}');
...
final authData = await pb.collection('${(Fe=r[0])==null?void 0:Fe.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
`}}),R=new Ue({props:{content:"?expand=relField1,relField2.subRelField"}}),A=new et({});let x=J(r[2]);const Me=e=>e[5].code;for(let e=0;e<x.length;e+=1){let t=Ve(r,x,e),c=Me(t);Re.set(c,y[e]=ze(c,t))}let L=J(r[2]);const qe=e=>e[5].code;for(let e=0;e<L.length;e+=1){let t=Ne(r,L,e),c=qe(t);Be.set(c,$[e]=Qe(c,t))}return{c(){l=s("h3"),a=k("Auth refresh ("),m=k(n),_=k(")"),i=p(),h=s("div"),h.innerHTML=`<p>Returns a new auth response (token and record data) for an
<strong>already authenticated record</strong>.</p> <p><em>This method is usually called by users on page/screen reload to ensure that the previously stored
data in <code>pb.authStore</code> is still valid and up-to-date.</em></p>`,g=p(),K(v.$$.fragment),w=p(),M=s("h6"),M.textContent="API details",X=p(),S=s("div"),z=s("strong"),z.textContent="POST",ue=p(),Q=s("div"),q=s("p"),pe=k("/api/collections/"),Y=s("strong"),Z=k(U),he=k("/auth-refresh"),fe=p(),j=s("p"),j.innerHTML="Requires record <code>Authorization:TOKEN</code> header",ee=p(),D=s("div"),D.textContent="Query parameters",te=p(),T=s("table"),oe=s("thead"),oe.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',be=p(),F=s("tbody"),C=s("tr"),le=s("td"),le.textContent="expand",me=p(),ae=s("td"),ae.innerHTML='<span class="label">String</span>',_e=p(),f=s("td"),ke=k(`Auto expand record relations. Ex.:
`),K(R.$$.fragment),ge=k(`
Supports up to 6-levels depth nested relations expansion. `),ve=s("br"),$e=k(`
The expanded relations will be appended to the record under the
`),se=s("code"),se.textContent="expand",ye=k(" property (eg. "),ne=s("code"),ne.textContent='"expand": {"relField1": {...}, ...}',Se=k(`).
`),we=s("br"),Te=k(`
Only the relations to which the request user has permissions to `),re=s("strong"),re.textContent="view",Ce=k(" will be expanded."),Pe=p(),K(A.$$.fragment),ie=p(),O=s("div"),O.textContent="Responses",ce=p(),P=s("div"),H=s("div");for(let e=0;e<y.length;e+=1)y[e].c();Ae=p(),E=s("div");for(let e=0;e<$.length;e+=1)$[e].c();b(l,"class","m-b-sm"),b(h,"class","content txt-lg m-b-sm"),b(M,"class","m-b-xs"),b(z,"class","label label-primary"),b(Q,"class","content"),b(j,"class","txt-hint txt-sm txt-right"),b(S,"class","alert alert-success"),b(D,"class","section-title"),b(T,"class","table-compact table-border m-b-base"),b(O,"class","section-title"),b(H,"class","tabs-header compact combined left"),b(E,"class","tabs-content"),b(P,"class","tabs")},m(e,t){d(e,l,t),o(l,a),o(l,m),o(l,_),d(e,i,t),d(e,h,t),d(e,g,t),I(v,e,t),d(e,w,t),d(e,M,t),d(e,X,t),d(e,S,t),o(S,z),o(S,ue),o(S,Q),o(Q,q),o(q,pe),o(q,Y),o(Y,Z),o(q,he),o(S,fe),o(S,j),d(e,ee,t),d(e,D,t),d(e,te,t),d(e,T,t),o(T,oe),o(T,be),o(T,F),o(F,C),o(C,le),o(C,me),o(C,ae),o(C,_e),o(C,f),o(f,ke),I(R,f,null),o(f,ge),o(f,ve),o(f,$e),o(f,se),o(f,ye),o(f,ne),o(f,Se),o(f,we),o(f,Te),o(f,re),o(f,Ce),o(F,Pe),I(A,F,null),d(e,ie,t),d(e,O,t),d(e,ce,t),d(e,P,t),o(P,H);for(let c=0;c<y.length;c+=1)y[c]&&y[c].m(H,null);o(P,Ae),o(P,E);for(let c=0;c<$.length;c+=1)$[c]&&$[c].m(E,null);B=!0},p(e,[t]){var Oe,He;(!B||t&1)&&n!==(n=e[0].name+"")&&de(m,n);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
const authData = await pb.collection('${(Oe=e[0])==null?void 0:Oe.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
final authData = await pb.collection('${(He=e[0])==null?void 0:He.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
`),v.$set(c),(!B||t&1)&&U!==(U=e[0].name+"")&&de(Z,U),t&6&&(x=J(e[2]),y=Ee(y,t,Me,1,e,x,Re,H,Ke,ze,null,Ve)),t&6&&(L=J(e[2]),Ie(),$=Ee($,t,qe,1,e,L,Be,E,We,Qe,null,Ne),Ge())},i(e){if(!B){N(v.$$.fragment,e),N(R.$$.fragment,e),N(A.$$.fragment,e);for(let t=0;t<L.length;t+=1)N($[t]);B=!0}},o(e){V(v.$$.fragment,e),V(R.$$.fragment,e),V(A.$$.fragment,e);for(let t=0;t<$.length;t+=1)V($[t]);B=!1},d(e){e&&(u(l),u(i),u(h),u(g),u(w),u(M),u(X),u(S),u(ee),u(D),u(te),u(T),u(ie),u(O),u(ce),u(P)),W(v,e),W(R),W(A);for(let t=0;t<y.length;t+=1)y[t].d();for(let t=0;t<$.length;t+=1)$[t].d()}}}function ot(r,l,a){let n,{collection:m}=l,_=200,i=[];const h=g=>a(1,_=g.code);return r.$$set=g=>{"collection"in g&&a(0,m=g.collection)},r.$$.update=()=>{r.$$.dirty&1&&a(2,i=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:Le.dummyCollectionRecord(m)},null,2)},{code:401,body:`
{
"code": 401,
"message": "The request requires valid record authorization token to be set.",
"data": {}
}
`},{code:403,body:`
{
"code": 403,
"message": "The authorized record model is not allowed to perform this action.",
"data": {}
}
`},{code:404,body:`
{
"code": 404,
"message": "Missing auth record context.",
"data": {}
}
`}])},a(3,n=Le.getApiExampleUrl(Xe.baseUrl)),[m,_,i,n,h]}class nt extends je{constructor(l){super(),xe(this,l,ot,tt,Je,{collection:0})}}export{nt as default};
-82
View File
@@ -1,82 +0,0 @@
import{S as Ue,i as je,s as xe,M as Qe,e as s,w as k,b as p,c as J,f as b,g as d,h as o,m as K,x as ce,N as Oe,P as Je,k as Ke,Q as Ie,n as We,t as N,a as V,o as u,d as I,T as Ge,C as Ee,p as Xe,r as W,u as Ye}from"./index-9e84ac8a.js";import{S as Ze}from"./SdkTabs-821a18db.js";import{F as et}from"./FieldsQueryParam-664da4c8.js";function Le(r,l,a){const n=r.slice();return n[5]=l[a],n}function Ne(r,l,a){const n=r.slice();return n[5]=l[a],n}function Ve(r,l){let a,n=l[5].code+"",m,_,i,f;function v(){return l[4](l[5])}return{key:r,first:null,c(){a=s("button"),m=k(n),_=p(),b(a,"class","tab-item"),W(a,"active",l[1]===l[5].code),this.first=a},m($,w){d($,a,w),o(a,m),o(a,_),i||(f=Ye(a,"click",v),i=!0)},p($,w){l=$,w&4&&n!==(n=l[5].code+"")&&ce(m,n),w&6&&W(a,"active",l[1]===l[5].code)},d($){$&&u(a),i=!1,f()}}}function ze(r,l){let a,n,m,_;return n=new Qe({props:{content:l[5].body}}),{key:r,first:null,c(){a=s("div"),J(n.$$.fragment),m=p(),b(a,"class","tab-item"),W(a,"active",l[1]===l[5].code),this.first=a},m(i,f){d(i,a,f),K(n,a,null),o(a,m),_=!0},p(i,f){l=i;const v={};f&4&&(v.content=l[5].body),n.$set(v),(!_||f&6)&&W(a,"active",l[1]===l[5].code)},i(i){_||(N(n.$$.fragment,i),_=!0)},o(i){V(n.$$.fragment,i),_=!1},d(i){i&&u(a),I(n)}}}function tt(r){var qe,De;let l,a,n=r[0].name+"",m,_,i,f,v,$,w,B,G,S,z,de,Q,q,ue,X,U=r[0].name+"",Y,pe,fe,j,Z,D,ee,T,te,he,F,C,oe,be,le,me,h,_e,R,ke,ve,$e,ae,ge,se,ye,Se,we,ne,Te,Ce,M,re,H,ie,P,O,y=[],Pe=new Map,Re,E,g=[],Me=new Map,A;$=new Ze({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${r[3]}');
...
const authData = await pb.collection('${(qe=r[0])==null?void 0:qe.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${r[3]}');
...
final authData = await pb.collection('${(De=r[0])==null?void 0:De.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
`}}),R=new Qe({props:{content:"?expand=relField1,relField2.subRelField"}}),M=new et({});let x=r[2];const Ae=e=>e[5].code;for(let e=0;e<x.length;e+=1){let t=Ne(r,x,e),c=Ae(t);Pe.set(c,y[e]=Ve(c,t))}let L=r[2];const Be=e=>e[5].code;for(let e=0;e<L.length;e+=1){let t=Le(r,L,e),c=Be(t);Me.set(c,g[e]=ze(c,t))}return{c(){l=s("h3"),a=k("Auth refresh ("),m=k(n),_=k(")"),i=p(),f=s("div"),f.innerHTML=`<p>Returns a new auth response (token and record data) for an
<strong>already authenticated record</strong>.</p>
<p><em>This method is usually called by users on page/screen reload to ensure that the previously stored
data in <code>pb.authStore</code> is still valid and up-to-date.</em></p>`,v=p(),J($.$$.fragment),w=p(),B=s("h6"),B.textContent="API details",G=p(),S=s("div"),z=s("strong"),z.textContent="POST",de=p(),Q=s("div"),q=s("p"),ue=k("/api/collections/"),X=s("strong"),Y=k(U),pe=k("/auth-refresh"),fe=p(),j=s("p"),j.innerHTML="Requires record <code>Authorization:TOKEN</code> header",Z=p(),D=s("div"),D.textContent="Query parameters",ee=p(),T=s("table"),te=s("thead"),te.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="60%">Description</th></tr>`,he=p(),F=s("tbody"),C=s("tr"),oe=s("td"),oe.textContent="expand",be=p(),le=s("td"),le.innerHTML='<span class="label">String</span>',me=p(),h=s("td"),_e=k(`Auto expand record relations. Ex.:
`),J(R.$$.fragment),ke=k(`
Supports up to 6-levels depth nested relations expansion. `),ve=s("br"),$e=k(`
The expanded relations will be appended to the record under the
`),ae=s("code"),ae.textContent="expand",ge=k(" property (eg. "),se=s("code"),se.textContent='"expand": {"relField1": {...}, ...}',ye=k(`).
`),Se=s("br"),we=k(`
Only the relations to which the request user has permissions to `),ne=s("strong"),ne.textContent="view",Te=k(" will be expanded."),Ce=p(),J(M.$$.fragment),re=p(),H=s("div"),H.textContent="Responses",ie=p(),P=s("div"),O=s("div");for(let e=0;e<y.length;e+=1)y[e].c();Re=p(),E=s("div");for(let e=0;e<g.length;e+=1)g[e].c();b(l,"class","m-b-sm"),b(f,"class","content txt-lg m-b-sm"),b(B,"class","m-b-xs"),b(z,"class","label label-primary"),b(Q,"class","content"),b(j,"class","txt-hint txt-sm txt-right"),b(S,"class","alert alert-success"),b(D,"class","section-title"),b(T,"class","table-compact table-border m-b-base"),b(H,"class","section-title"),b(O,"class","tabs-header compact left"),b(E,"class","tabs-content"),b(P,"class","tabs")},m(e,t){d(e,l,t),o(l,a),o(l,m),o(l,_),d(e,i,t),d(e,f,t),d(e,v,t),K($,e,t),d(e,w,t),d(e,B,t),d(e,G,t),d(e,S,t),o(S,z),o(S,de),o(S,Q),o(Q,q),o(q,ue),o(q,X),o(X,Y),o(q,pe),o(S,fe),o(S,j),d(e,Z,t),d(e,D,t),d(e,ee,t),d(e,T,t),o(T,te),o(T,he),o(T,F),o(F,C),o(C,oe),o(C,be),o(C,le),o(C,me),o(C,h),o(h,_e),K(R,h,null),o(h,ke),o(h,ve),o(h,$e),o(h,ae),o(h,ge),o(h,se),o(h,ye),o(h,Se),o(h,we),o(h,ne),o(h,Te),o(F,Ce),K(M,F,null),d(e,re,t),d(e,H,t),d(e,ie,t),d(e,P,t),o(P,O);for(let c=0;c<y.length;c+=1)y[c]&&y[c].m(O,null);o(P,Re),o(P,E);for(let c=0;c<g.length;c+=1)g[c]&&g[c].m(E,null);A=!0},p(e,[t]){var Fe,He;(!A||t&1)&&n!==(n=e[0].name+"")&&ce(m,n);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
const authData = await pb.collection('${(Fe=e[0])==null?void 0:Fe.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
final authData = await pb.collection('${(He=e[0])==null?void 0:He.name}').authRefresh();
// after the above you can also access the refreshed auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
`),$.$set(c),(!A||t&1)&&U!==(U=e[0].name+"")&&ce(Y,U),t&6&&(x=e[2],y=Oe(y,t,Ae,1,e,x,Pe,O,Je,Ve,null,Ne)),t&6&&(L=e[2],Ke(),g=Oe(g,t,Be,1,e,L,Me,E,Ie,ze,null,Le),We())},i(e){if(!A){N($.$$.fragment,e),N(R.$$.fragment,e),N(M.$$.fragment,e);for(let t=0;t<L.length;t+=1)N(g[t]);A=!0}},o(e){V($.$$.fragment,e),V(R.$$.fragment,e),V(M.$$.fragment,e);for(let t=0;t<g.length;t+=1)V(g[t]);A=!1},d(e){e&&u(l),e&&u(i),e&&u(f),e&&u(v),I($,e),e&&u(w),e&&u(B),e&&u(G),e&&u(S),e&&u(Z),e&&u(D),e&&u(ee),e&&u(T),I(R),I(M),e&&u(re),e&&u(H),e&&u(ie),e&&u(P);for(let t=0;t<y.length;t+=1)y[t].d();for(let t=0;t<g.length;t+=1)g[t].d()}}}function ot(r,l,a){let n,{collection:m=new Ge}=l,_=200,i=[];const f=v=>a(1,_=v.code);return r.$$set=v=>{"collection"in v&&a(0,m=v.collection)},r.$$.update=()=>{r.$$.dirty&1&&a(2,i=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:Ee.dummyCollectionRecord(m)},null,2)},{code:401,body:`
{
"code": 401,
"message": "The request requires valid record authorization token to be set.",
"data": {}
}
`},{code:403,body:`
{
"code": 403,
"message": "The authorized record model is not allowed to perform this action.",
"data": {}
}
`},{code:404,body:`
{
"code": 404,
"message": "Missing auth record context.",
"data": {}
}
`}])},a(3,n=Ee.getApiExampleUrl(Xe.baseUrl)),[m,_,i,n,f]}class nt extends Ue{constructor(l){super(),je(this,l,ot,tt,xe,{collection:0})}}export{nt as default};
+117
View File
@@ -0,0 +1,117 @@
import{S as Le,i as Ee,s as Je,N as Ve,O as z,e as s,w as k,b as h,c as I,f as p,g as r,h as a,m as K,x as pe,P as We,Q as Ne,k as Qe,R as ze,n as Ie,t as V,a as L,o as c,d as G,C as Ue,p as Ke,r as X,u as Ge}from"./index-f26826b5.js";import{S as Xe}from"./SdkTabs-37a2d588.js";import{F as Ye}from"./FieldsQueryParam-e2795694.js";function Be(i,l,o){const n=i.slice();return n[5]=l[o],n}function Fe(i,l,o){const n=i.slice();return n[5]=l[o],n}function He(i,l){let o,n=l[5].code+"",f,g,d,b;function _(){return l[4](l[5])}return{key:i,first:null,c(){o=s("button"),f=k(n),g=h(),p(o,"class","tab-item"),X(o,"active",l[1]===l[5].code),this.first=o},m(v,A){r(v,o,A),a(o,f),a(o,g),d||(b=Ge(o,"click",_),d=!0)},p(v,A){l=v,A&4&&n!==(n=l[5].code+"")&&pe(f,n),A&6&&X(o,"active",l[1]===l[5].code)},d(v){v&&c(o),d=!1,b()}}}function je(i,l){let o,n,f,g;return n=new Ve({props:{content:l[5].body}}),{key:i,first:null,c(){o=s("div"),I(n.$$.fragment),f=h(),p(o,"class","tab-item"),X(o,"active",l[1]===l[5].code),this.first=o},m(d,b){r(d,o,b),K(n,o,null),a(o,f),g=!0},p(d,b){l=d;const _={};b&4&&(_.content=l[5].body),n.$set(_),(!g||b&6)&&X(o,"active",l[1]===l[5].code)},i(d){g||(V(n.$$.fragment,d),g=!0)},o(d){L(n.$$.fragment,d),g=!1},d(d){d&&c(o),G(n)}}}function Ze(i){let l,o,n=i[0].name+"",f,g,d,b,_,v,A,P,Y,S,E,be,J,R,me,Z,N=i[0].name+"",ee,fe,te,M,ae,x,le,W,oe,y,se,ge,U,$,ne,ke,ie,_e,m,ve,C,we,Oe,Ae,re,Se,ce,ye,$e,Te,de,Ce,qe,q,ue,B,he,T,F,O=[],De=new Map,Pe,H,w=[],Re=new Map,D;v=new Xe({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${i[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${i[3]}/api/oauth2-redirect as redirect url.
const authData = await pb.collection('users').authWithOAuth2({ provider: 'google' });
// OR authenticate with manual OAuth2 code exchange
// const authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
import 'package:url_launcher/url_launcher.dart';
final pb = PocketBase('${i[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${i[3]}/api/oauth2-redirect as redirect url.
final authData = await pb.collection('users').authWithOAuth2('google', (url) async {
await launchUrl(url);
});
// OR authenticate with manual OAuth2 code exchange
// final authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`}}),C=new Ve({props:{content:"?expand=relField1,relField2.subRelField"}}),q=new Ye({});let Q=z(i[2]);const Me=e=>e[5].code;for(let e=0;e<Q.length;e+=1){let t=Fe(i,Q,e),u=Me(t);De.set(u,O[e]=He(u,t))}let j=z(i[2]);const xe=e=>e[5].code;for(let e=0;e<j.length;e+=1){let t=Be(i,j,e),u=xe(t);Re.set(u,w[e]=je(u,t))}return{c(){l=s("h3"),o=k("Auth with OAuth2 ("),f=k(n),g=k(")"),d=h(),b=s("div"),b.innerHTML=`<p>Authenticate with an OAuth2 provider and returns a new auth token and record data.</p> <p>For more details please check the
<a href="https://pocketbase.io/docs/authentication/#oauth2-integration" target="_blank" rel="noopener noreferrer">OAuth2 integration documentation
</a>.</p>`,_=h(),I(v.$$.fragment),A=h(),P=s("h6"),P.textContent="API details",Y=h(),S=s("div"),E=s("strong"),E.textContent="POST",be=h(),J=s("div"),R=s("p"),me=k("/api/collections/"),Z=s("strong"),ee=k(N),fe=k("/auth-with-oauth2"),te=h(),M=s("div"),M.textContent="Body Parameters",ae=h(),x=s("table"),x.innerHTML=`<thead><tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr></thead> <tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>provider</span></div></td> <td><span class="label">String</span></td> <td>The name of the OAuth2 client provider (eg. &quot;google&quot;).</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>code</span></div></td> <td><span class="label">String</span></td> <td>The authorization code returned from the initial request.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>codeVerifier</span></div></td> <td><span class="label">String</span></td> <td>The code verifier sent with the initial request as part of the code_challenge.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>redirectUrl</span></div></td> <td><span class="label">String</span></td> <td>The redirect url sent with the initial request.</td></tr> <tr><td><div class="inline-flex"><span class="label label-warning">Optional</span> <span>createData</span></div></td> <td><span class="label">Object</span></td> <td><p>Optional data that will be used when creating the auth record on OAuth2 sign-up.</p> <p>The created auth record must comply with the same requirements and validations in the
regular <strong>create</strong> action.
<br/> <em>The data can only be in <code>json</code>, aka. <code>multipart/form-data</code> and files
upload currently are not supported during OAuth2 sign-ups.</em></p></td></tr></tbody>`,le=h(),W=s("div"),W.textContent="Query parameters",oe=h(),y=s("table"),se=s("thead"),se.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',ge=h(),U=s("tbody"),$=s("tr"),ne=s("td"),ne.textContent="expand",ke=h(),ie=s("td"),ie.innerHTML='<span class="label">String</span>',_e=h(),m=s("td"),ve=k(`Auto expand record relations. Ex.:
`),I(C.$$.fragment),we=k(`
Supports up to 6-levels depth nested relations expansion. `),Oe=s("br"),Ae=k(`
The expanded relations will be appended to the record under the
`),re=s("code"),re.textContent="expand",Se=k(" property (eg. "),ce=s("code"),ce.textContent='"expand": {"relField1": {...}, ...}',ye=k(`).
`),$e=s("br"),Te=k(`
Only the relations to which the request user has permissions to `),de=s("strong"),de.textContent="view",Ce=k(" will be expanded."),qe=h(),I(q.$$.fragment),ue=h(),B=s("div"),B.textContent="Responses",he=h(),T=s("div"),F=s("div");for(let e=0;e<O.length;e+=1)O[e].c();Pe=h(),H=s("div");for(let e=0;e<w.length;e+=1)w[e].c();p(l,"class","m-b-sm"),p(b,"class","content txt-lg m-b-sm"),p(P,"class","m-b-xs"),p(E,"class","label label-primary"),p(J,"class","content"),p(S,"class","alert alert-success"),p(M,"class","section-title"),p(x,"class","table-compact table-border m-b-base"),p(W,"class","section-title"),p(y,"class","table-compact table-border m-b-base"),p(B,"class","section-title"),p(F,"class","tabs-header compact combined left"),p(H,"class","tabs-content"),p(T,"class","tabs")},m(e,t){r(e,l,t),a(l,o),a(l,f),a(l,g),r(e,d,t),r(e,b,t),r(e,_,t),K(v,e,t),r(e,A,t),r(e,P,t),r(e,Y,t),r(e,S,t),a(S,E),a(S,be),a(S,J),a(J,R),a(R,me),a(R,Z),a(Z,ee),a(R,fe),r(e,te,t),r(e,M,t),r(e,ae,t),r(e,x,t),r(e,le,t),r(e,W,t),r(e,oe,t),r(e,y,t),a(y,se),a(y,ge),a(y,U),a(U,$),a($,ne),a($,ke),a($,ie),a($,_e),a($,m),a(m,ve),K(C,m,null),a(m,we),a(m,Oe),a(m,Ae),a(m,re),a(m,Se),a(m,ce),a(m,ye),a(m,$e),a(m,Te),a(m,de),a(m,Ce),a(U,qe),K(q,U,null),r(e,ue,t),r(e,B,t),r(e,he,t),r(e,T,t),a(T,F);for(let u=0;u<O.length;u+=1)O[u]&&O[u].m(F,null);a(T,Pe),a(T,H);for(let u=0;u<w.length;u+=1)w[u]&&w[u].m(H,null);D=!0},p(e,[t]){(!D||t&1)&&n!==(n=e[0].name+"")&&pe(f,n);const u={};t&8&&(u.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${e[3]}/api/oauth2-redirect as redirect url.
const authData = await pb.collection('users').authWithOAuth2({ provider: 'google' });
// OR authenticate with manual OAuth2 code exchange
// const authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`),t&8&&(u.dart=`
import 'package:pocketbase/pocketbase.dart';
import 'package:url_launcher/url_launcher.dart';
final pb = PocketBase('${e[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${e[3]}/api/oauth2-redirect as redirect url.
final authData = await pb.collection('users').authWithOAuth2('google', (url) async {
await launchUrl(url);
});
// OR authenticate with manual OAuth2 code exchange
// final authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`),v.$set(u),(!D||t&1)&&N!==(N=e[0].name+"")&&pe(ee,N),t&6&&(Q=z(e[2]),O=We(O,t,Me,1,e,Q,De,F,Ne,He,null,Fe)),t&6&&(j=z(e[2]),Qe(),w=We(w,t,xe,1,e,j,Re,H,ze,je,null,Be),Ie())},i(e){if(!D){V(v.$$.fragment,e),V(C.$$.fragment,e),V(q.$$.fragment,e);for(let t=0;t<j.length;t+=1)V(w[t]);D=!0}},o(e){L(v.$$.fragment,e),L(C.$$.fragment,e),L(q.$$.fragment,e);for(let t=0;t<w.length;t+=1)L(w[t]);D=!1},d(e){e&&(c(l),c(d),c(b),c(_),c(A),c(P),c(Y),c(S),c(te),c(M),c(ae),c(x),c(le),c(W),c(oe),c(y),c(ue),c(B),c(he),c(T)),G(v,e),G(C),G(q);for(let t=0;t<O.length;t+=1)O[t].d();for(let t=0;t<w.length;t+=1)w[t].d()}}}function et(i,l,o){let n,{collection:f}=l,g=200,d=[];const b=_=>o(1,g=_.code);return i.$$set=_=>{"collection"in _&&o(0,f=_.collection)},i.$$.update=()=>{i.$$.dirty&1&&o(2,d=[{code:200,body:JSON.stringify({token:"JWT_AUTH_TOKEN",record:Ue.dummyCollectionRecord(f),meta:{id:"abc123",name:"John Doe",username:"john.doe",email:"test@example.com",avatarUrl:"https://example.com/avatar.png",accessToken:"...",refreshToken:"...",rawUser:{}}},null,2)},{code:400,body:`
{
"code": 400,
"message": "An error occurred while submitting the form.",
"data": {
"provider": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}])},o(3,n=Ue.getApiExampleUrl(Ke.baseUrl)),[f,g,d,n,b]}class ot extends Le{constructor(l){super(),Ee(this,l,et,Ze,Je,{collection:0})}}export{ot as default};
-144
View File
@@ -1,144 +0,0 @@
import{S as Ve,i as Le,s as Ee,M as je,e as s,w as k,b as h,c as z,f as p,g as r,h as a,m as I,x as he,N as xe,P as Je,k as Ne,Q as Qe,n as ze,t as V,a as L,o as c,d as K,T as Ie,C as We,p as Ke,r as G,u as Ge}from"./index-9e84ac8a.js";import{S as Xe}from"./SdkTabs-821a18db.js";import{F as Ye}from"./FieldsQueryParam-664da4c8.js";function Ue(i,l,o){const n=i.slice();return n[5]=l[o],n}function Be(i,l,o){const n=i.slice();return n[5]=l[o],n}function Fe(i,l){let o,n=l[5].code+"",m,g,u,b;function _(){return l[4](l[5])}return{key:i,first:null,c(){o=s("button"),m=k(n),g=h(),p(o,"class","tab-item"),G(o,"active",l[1]===l[5].code),this.first=o},m(v,A){r(v,o,A),a(o,m),a(o,g),u||(b=Ge(o,"click",_),u=!0)},p(v,A){l=v,A&4&&n!==(n=l[5].code+"")&&he(m,n),A&6&&G(o,"active",l[1]===l[5].code)},d(v){v&&c(o),u=!1,b()}}}function He(i,l){let o,n,m,g;return n=new je({props:{content:l[5].body}}),{key:i,first:null,c(){o=s("div"),z(n.$$.fragment),m=h(),p(o,"class","tab-item"),G(o,"active",l[1]===l[5].code),this.first=o},m(u,b){r(u,o,b),I(n,o,null),a(o,m),g=!0},p(u,b){l=u;const _={};b&4&&(_.content=l[5].body),n.$set(_),(!g||b&6)&&G(o,"active",l[1]===l[5].code)},i(u){g||(V(n.$$.fragment,u),g=!0)},o(u){L(n.$$.fragment,u),g=!1},d(u){u&&c(o),K(n)}}}function Ze(i){let l,o,n=i[0].name+"",m,g,u,b,_,v,A,P,X,S,E,pe,J,M,be,Y,N=i[0].name+"",Z,fe,ee,R,te,x,ae,W,le,y,oe,me,U,$,se,ge,ne,ke,f,_e,C,ve,we,Oe,ie,Ae,re,Se,ye,$e,ce,Te,Ce,q,ue,B,de,T,F,O=[],qe=new Map,De,H,w=[],Pe=new Map,D;v=new Xe({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${i[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${i[3]}/api/oauth2-redirect as redirect url.
const authData = await pb.collection('users').authWithOAuth2({ provider: 'google' });
// OR authenticate with manual OAuth2 code exchange
// const authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
import 'package:url_launcher/url_launcher.dart';
final pb = PocketBase('${i[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${i[3]}/api/oauth2-redirect as redirect url.
final authData = await pb.collection('users').authWithOAuth2('google', (url) async {
await launchUrl(url);
});
// OR authenticate with manual OAuth2 code exchange
// final authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`}}),C=new je({props:{content:"?expand=relField1,relField2.subRelField"}}),q=new Ye({});let Q=i[2];const Me=e=>e[5].code;for(let e=0;e<Q.length;e+=1){let t=Be(i,Q,e),d=Me(t);qe.set(d,O[e]=Fe(d,t))}let j=i[2];const Re=e=>e[5].code;for(let e=0;e<j.length;e+=1){let t=Ue(i,j,e),d=Re(t);Pe.set(d,w[e]=He(d,t))}return{c(){l=s("h3"),o=k("Auth with OAuth2 ("),m=k(n),g=k(")"),u=h(),b=s("div"),b.innerHTML=`<p>Authenticate with an OAuth2 provider and returns a new auth token and record data.</p>
<p>For more details please check the
<a href="https://pocketbase.io/docs/authentication/#oauth2-integration" target="_blank" rel="noopener noreferrer">OAuth2 integration documentation
</a>.</p>`,_=h(),z(v.$$.fragment),A=h(),P=s("h6"),P.textContent="API details",X=h(),S=s("div"),E=s("strong"),E.textContent="POST",pe=h(),J=s("div"),M=s("p"),be=k("/api/collections/"),Y=s("strong"),Z=k(N),fe=k("/auth-with-oauth2"),ee=h(),R=s("div"),R.textContent="Body Parameters",te=h(),x=s("table"),x.innerHTML=`<thead><tr><th>Param</th>
<th>Type</th>
<th width="50%">Description</th></tr></thead>
<tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>provider</span></div></td>
<td><span class="label">String</span></td>
<td>The name of the OAuth2 client provider (eg. &quot;google&quot;).</td></tr>
<tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>code</span></div></td>
<td><span class="label">String</span></td>
<td>The authorization code returned from the initial request.</td></tr>
<tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>codeVerifier</span></div></td>
<td><span class="label">String</span></td>
<td>The code verifier sent with the initial request as part of the code_challenge.</td></tr>
<tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>redirectUrl</span></div></td>
<td><span class="label">String</span></td>
<td>The redirect url sent with the initial request.</td></tr>
<tr><td><div class="inline-flex"><span class="label label-warning">Optional</span>
<span>createData</span></div></td>
<td><span class="label">Object</span></td>
<td><p>Optional data that will be used when creating the auth record on OAuth2 sign-up.</p>
<p>The created auth record must comply with the same requirements and validations in the
regular <strong>create</strong> action.
<br/>
<em>The data can only be in <code>json</code>, aka. <code>multipart/form-data</code> and files
upload currently are not supported during OAuth2 sign-ups.</em></p></td></tr></tbody>`,ae=h(),W=s("div"),W.textContent="Query parameters",le=h(),y=s("table"),oe=s("thead"),oe.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="60%">Description</th></tr>`,me=h(),U=s("tbody"),$=s("tr"),se=s("td"),se.textContent="expand",ge=h(),ne=s("td"),ne.innerHTML='<span class="label">String</span>',ke=h(),f=s("td"),_e=k(`Auto expand record relations. Ex.:
`),z(C.$$.fragment),ve=k(`
Supports up to 6-levels depth nested relations expansion. `),we=s("br"),Oe=k(`
The expanded relations will be appended to the record under the
`),ie=s("code"),ie.textContent="expand",Ae=k(" property (eg. "),re=s("code"),re.textContent='"expand": {"relField1": {...}, ...}',Se=k(`).
`),ye=s("br"),$e=k(`
Only the relations to which the request user has permissions to `),ce=s("strong"),ce.textContent="view",Te=k(" will be expanded."),Ce=h(),z(q.$$.fragment),ue=h(),B=s("div"),B.textContent="Responses",de=h(),T=s("div"),F=s("div");for(let e=0;e<O.length;e+=1)O[e].c();De=h(),H=s("div");for(let e=0;e<w.length;e+=1)w[e].c();p(l,"class","m-b-sm"),p(b,"class","content txt-lg m-b-sm"),p(P,"class","m-b-xs"),p(E,"class","label label-primary"),p(J,"class","content"),p(S,"class","alert alert-success"),p(R,"class","section-title"),p(x,"class","table-compact table-border m-b-base"),p(W,"class","section-title"),p(y,"class","table-compact table-border m-b-base"),p(B,"class","section-title"),p(F,"class","tabs-header compact left"),p(H,"class","tabs-content"),p(T,"class","tabs")},m(e,t){r(e,l,t),a(l,o),a(l,m),a(l,g),r(e,u,t),r(e,b,t),r(e,_,t),I(v,e,t),r(e,A,t),r(e,P,t),r(e,X,t),r(e,S,t),a(S,E),a(S,pe),a(S,J),a(J,M),a(M,be),a(M,Y),a(Y,Z),a(M,fe),r(e,ee,t),r(e,R,t),r(e,te,t),r(e,x,t),r(e,ae,t),r(e,W,t),r(e,le,t),r(e,y,t),a(y,oe),a(y,me),a(y,U),a(U,$),a($,se),a($,ge),a($,ne),a($,ke),a($,f),a(f,_e),I(C,f,null),a(f,ve),a(f,we),a(f,Oe),a(f,ie),a(f,Ae),a(f,re),a(f,Se),a(f,ye),a(f,$e),a(f,ce),a(f,Te),a(U,Ce),I(q,U,null),r(e,ue,t),r(e,B,t),r(e,de,t),r(e,T,t),a(T,F);for(let d=0;d<O.length;d+=1)O[d]&&O[d].m(F,null);a(T,De),a(T,H);for(let d=0;d<w.length;d+=1)w[d]&&w[d].m(H,null);D=!0},p(e,[t]){(!D||t&1)&&n!==(n=e[0].name+"")&&he(m,n);const d={};t&8&&(d.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${e[3]}/api/oauth2-redirect as redirect url.
const authData = await pb.collection('users').authWithOAuth2({ provider: 'google' });
// OR authenticate with manual OAuth2 code exchange
// const authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`),t&8&&(d.dart=`
import 'package:pocketbase/pocketbase.dart';
import 'package:url_launcher/url_launcher.dart';
final pb = PocketBase('${e[3]}');
...
// OAuth2 authentication with a single realtime call.
//
// Make sure to register ${e[3]}/api/oauth2-redirect as redirect url.
final authData = await pb.collection('users').authWithOAuth2('google', (url) async {
await launchUrl(url);
});
// OR authenticate with manual OAuth2 code exchange
// final authData = await pb.collection('users').authWithOAuth2Code(...);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated model
pb.authStore.clear();
`),v.$set(d),(!D||t&1)&&N!==(N=e[0].name+"")&&he(Z,N),t&6&&(Q=e[2],O=xe(O,t,Me,1,e,Q,qe,F,Je,Fe,null,Be)),t&6&&(j=e[2],Ne(),w=xe(w,t,Re,1,e,j,Pe,H,Qe,He,null,Ue),ze())},i(e){if(!D){V(v.$$.fragment,e),V(C.$$.fragment,e),V(q.$$.fragment,e);for(let t=0;t<j.length;t+=1)V(w[t]);D=!0}},o(e){L(v.$$.fragment,e),L(C.$$.fragment,e),L(q.$$.fragment,e);for(let t=0;t<w.length;t+=1)L(w[t]);D=!1},d(e){e&&c(l),e&&c(u),e&&c(b),e&&c(_),K(v,e),e&&c(A),e&&c(P),e&&c(X),e&&c(S),e&&c(ee),e&&c(R),e&&c(te),e&&c(x),e&&c(ae),e&&c(W),e&&c(le),e&&c(y),K(C),K(q),e&&c(ue),e&&c(B),e&&c(de),e&&c(T);for(let t=0;t<O.length;t+=1)O[t].d();for(let t=0;t<w.length;t+=1)w[t].d()}}}function et(i,l,o){let n,{collection:m=new Ie}=l,g=200,u=[];const b=_=>o(1,g=_.code);return i.$$set=_=>{"collection"in _&&o(0,m=_.collection)},i.$$.update=()=>{i.$$.dirty&1&&o(2,u=[{code:200,body:JSON.stringify({token:"JWT_AUTH_TOKEN",record:We.dummyCollectionRecord(m),meta:{id:"abc123",name:"John Doe",username:"john.doe",email:"test@example.com",avatarUrl:"https://example.com/avatar.png",accessToken:"...",refreshToken:"...",rawUser:{}}},null,2)},{code:400,body:`
{
"code": 400,
"message": "An error occurred while submitting the form.",
"data": {
"provider": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}])},o(3,n=We.getApiExampleUrl(Ke.baseUrl)),[m,g,u,n,b]}class ot extends Ve{constructor(l){super(),Le(this,l,et,Ze,Ee,{collection:0})}}export{ot as default};
-106
View File
@@ -1,106 +0,0 @@
import{S as ve,i as ye,s as ge,M as we,e as s,w as f,b as d,c as ot,f as h,g as r,h as e,m as st,x as Ut,N as ue,P as $e,k as Pe,Q as Re,n as Ce,t as Z,a as x,o as c,d as nt,T as Te,C as fe,p as Ae,r as it,u as Oe}from"./index-9e84ac8a.js";import{S as Me}from"./SdkTabs-821a18db.js";import{F as Ue}from"./FieldsQueryParam-664da4c8.js";function pe(n,l,a){const i=n.slice();return i[8]=l[a],i}function be(n,l,a){const i=n.slice();return i[8]=l[a],i}function De(n){let l;return{c(){l=f("email")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function Ee(n){let l;return{c(){l=f("username")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function We(n){let l;return{c(){l=f("username/email")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function me(n){let l;return{c(){l=s("strong"),l.textContent="username"},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function he(n){let l;return{c(){l=f("or")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function _e(n){let l;return{c(){l=s("strong"),l.textContent="email"},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function ke(n,l){let a,i=l[8].code+"",S,m,p,u;function _(){return l[7](l[8])}return{key:n,first:null,c(){a=s("button"),S=f(i),m=d(),h(a,"class","tab-item"),it(a,"active",l[3]===l[8].code),this.first=a},m(R,C){r(R,a,C),e(a,S),e(a,m),p||(u=Oe(a,"click",_),p=!0)},p(R,C){l=R,C&16&&i!==(i=l[8].code+"")&&Ut(S,i),C&24&&it(a,"active",l[3]===l[8].code)},d(R){R&&c(a),p=!1,u()}}}function Se(n,l){let a,i,S,m;return i=new we({props:{content:l[8].body}}),{key:n,first:null,c(){a=s("div"),ot(i.$$.fragment),S=d(),h(a,"class","tab-item"),it(a,"active",l[3]===l[8].code),this.first=a},m(p,u){r(p,a,u),st(i,a,null),e(a,S),m=!0},p(p,u){l=p;const _={};u&16&&(_.content=l[8].body),i.$set(_),(!m||u&24)&&it(a,"active",l[3]===l[8].code)},i(p){m||(Z(i.$$.fragment,p),m=!0)},o(p){x(i.$$.fragment,p),m=!1},d(p){p&&c(a),nt(i)}}}function Le(n){var ie,re;let l,a,i=n[0].name+"",S,m,p,u,_,R,C,T,B,Dt,rt,O,ct,N,dt,M,tt,Et,et,I,Wt,ut,lt=n[0].name+"",ft,Lt,pt,V,bt,U,mt,Bt,Q,D,ht,qt,_t,Ft,$,Ht,kt,St,wt,Yt,vt,yt,j,gt,E,$t,Nt,J,W,Pt,It,Rt,Vt,k,Qt,q,jt,Jt,Kt,Ct,zt,Tt,Gt,Xt,Zt,At,xt,te,F,Ot,K,Mt,L,z,A=[],ee=new Map,le,G,w=[],ae=new Map,H;function oe(t,o){if(t[1]&&t[2])return We;if(t[1])return Ee;if(t[2])return De}let Y=oe(n),P=Y&&Y(n);O=new Me({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[6]}');
...
const authData = await pb.collection('${(ie=n[0])==null?void 0:ie.name}').authWithPassword(
'${n[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[6]}');
...
final authData = await pb.collection('${(re=n[0])==null?void 0:re.name}').authWithPassword(
'${n[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`}});let v=n[1]&&me(),y=n[1]&&n[2]&&he(),g=n[2]&&_e();q=new we({props:{content:"?expand=relField1,relField2.subRelField"}}),F=new Ue({});let at=n[4];const se=t=>t[8].code;for(let t=0;t<at.length;t+=1){let o=be(n,at,t),b=se(o);ee.set(b,A[t]=ke(b,o))}let X=n[4];const ne=t=>t[8].code;for(let t=0;t<X.length;t+=1){let o=pe(n,X,t),b=ne(o);ae.set(b,w[t]=Se(b,o))}return{c(){l=s("h3"),a=f("Auth with password ("),S=f(i),m=f(")"),p=d(),u=s("div"),_=s("p"),R=f(`Returns new auth token and account data by a combination of
`),C=s("strong"),P&&P.c(),T=f(`
and `),B=s("strong"),B.textContent="password",Dt=f("."),rt=d(),ot(O.$$.fragment),ct=d(),N=s("h6"),N.textContent="API details",dt=d(),M=s("div"),tt=s("strong"),tt.textContent="POST",Et=d(),et=s("div"),I=s("p"),Wt=f("/api/collections/"),ut=s("strong"),ft=f(lt),Lt=f("/auth-with-password"),pt=d(),V=s("div"),V.textContent="Body Parameters",bt=d(),U=s("table"),mt=s("thead"),mt.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="50%">Description</th></tr>`,Bt=d(),Q=s("tbody"),D=s("tr"),ht=s("td"),ht.innerHTML=`<div class="inline-flex"><span class="label label-success">Required</span>
<span>identity</span></div>`,qt=d(),_t=s("td"),_t.innerHTML='<span class="label">String</span>',Ft=d(),$=s("td"),Ht=f(`The
`),v&&v.c(),kt=d(),y&&y.c(),St=d(),g&&g.c(),wt=f(`
of the record to authenticate.`),Yt=d(),vt=s("tr"),vt.innerHTML=`<td><div class="inline-flex"><span class="label label-success">Required</span>
<span>password</span></div></td>
<td><span class="label">String</span></td>
<td>The auth record password.</td>`,yt=d(),j=s("div"),j.textContent="Query parameters",gt=d(),E=s("table"),$t=s("thead"),$t.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="60%">Description</th></tr>`,Nt=d(),J=s("tbody"),W=s("tr"),Pt=s("td"),Pt.textContent="expand",It=d(),Rt=s("td"),Rt.innerHTML='<span class="label">String</span>',Vt=d(),k=s("td"),Qt=f(`Auto expand record relations. Ex.:
`),ot(q.$$.fragment),jt=f(`
Supports up to 6-levels depth nested relations expansion. `),Jt=s("br"),Kt=f(`
The expanded relations will be appended to the record under the
`),Ct=s("code"),Ct.textContent="expand",zt=f(" property (eg. "),Tt=s("code"),Tt.textContent='"expand": {"relField1": {...}, ...}',Gt=f(`).
`),Xt=s("br"),Zt=f(`
Only the relations to which the request user has permissions to `),At=s("strong"),At.textContent="view",xt=f(" will be expanded."),te=d(),ot(F.$$.fragment),Ot=d(),K=s("div"),K.textContent="Responses",Mt=d(),L=s("div"),z=s("div");for(let t=0;t<A.length;t+=1)A[t].c();le=d(),G=s("div");for(let t=0;t<w.length;t+=1)w[t].c();h(l,"class","m-b-sm"),h(u,"class","content txt-lg m-b-sm"),h(N,"class","m-b-xs"),h(tt,"class","label label-primary"),h(et,"class","content"),h(M,"class","alert alert-success"),h(V,"class","section-title"),h(U,"class","table-compact table-border m-b-base"),h(j,"class","section-title"),h(E,"class","table-compact table-border m-b-base"),h(K,"class","section-title"),h(z,"class","tabs-header compact left"),h(G,"class","tabs-content"),h(L,"class","tabs")},m(t,o){r(t,l,o),e(l,a),e(l,S),e(l,m),r(t,p,o),r(t,u,o),e(u,_),e(_,R),e(_,C),P&&P.m(C,null),e(_,T),e(_,B),e(_,Dt),r(t,rt,o),st(O,t,o),r(t,ct,o),r(t,N,o),r(t,dt,o),r(t,M,o),e(M,tt),e(M,Et),e(M,et),e(et,I),e(I,Wt),e(I,ut),e(ut,ft),e(I,Lt),r(t,pt,o),r(t,V,o),r(t,bt,o),r(t,U,o),e(U,mt),e(U,Bt),e(U,Q),e(Q,D),e(D,ht),e(D,qt),e(D,_t),e(D,Ft),e(D,$),e($,Ht),v&&v.m($,null),e($,kt),y&&y.m($,null),e($,St),g&&g.m($,null),e($,wt),e(Q,Yt),e(Q,vt),r(t,yt,o),r(t,j,o),r(t,gt,o),r(t,E,o),e(E,$t),e(E,Nt),e(E,J),e(J,W),e(W,Pt),e(W,It),e(W,Rt),e(W,Vt),e(W,k),e(k,Qt),st(q,k,null),e(k,jt),e(k,Jt),e(k,Kt),e(k,Ct),e(k,zt),e(k,Tt),e(k,Gt),e(k,Xt),e(k,Zt),e(k,At),e(k,xt),e(J,te),st(F,J,null),r(t,Ot,o),r(t,K,o),r(t,Mt,o),r(t,L,o),e(L,z);for(let b=0;b<A.length;b+=1)A[b]&&A[b].m(z,null);e(L,le),e(L,G);for(let b=0;b<w.length;b+=1)w[b]&&w[b].m(G,null);H=!0},p(t,[o]){var ce,de;(!H||o&1)&&i!==(i=t[0].name+"")&&Ut(S,i),Y!==(Y=oe(t))&&(P&&P.d(1),P=Y&&Y(t),P&&(P.c(),P.m(C,null)));const b={};o&97&&(b.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${t[6]}');
...
const authData = await pb.collection('${(ce=t[0])==null?void 0:ce.name}').authWithPassword(
'${t[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`),o&97&&(b.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${t[6]}');
...
final authData = await pb.collection('${(de=t[0])==null?void 0:de.name}').authWithPassword(
'${t[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`),O.$set(b),(!H||o&1)&&lt!==(lt=t[0].name+"")&&Ut(ft,lt),t[1]?v||(v=me(),v.c(),v.m($,kt)):v&&(v.d(1),v=null),t[1]&&t[2]?y||(y=he(),y.c(),y.m($,St)):y&&(y.d(1),y=null),t[2]?g||(g=_e(),g.c(),g.m($,wt)):g&&(g.d(1),g=null),o&24&&(at=t[4],A=ue(A,o,se,1,t,at,ee,z,$e,ke,null,be)),o&24&&(X=t[4],Pe(),w=ue(w,o,ne,1,t,X,ae,G,Re,Se,null,pe),Ce())},i(t){if(!H){Z(O.$$.fragment,t),Z(q.$$.fragment,t),Z(F.$$.fragment,t);for(let o=0;o<X.length;o+=1)Z(w[o]);H=!0}},o(t){x(O.$$.fragment,t),x(q.$$.fragment,t),x(F.$$.fragment,t);for(let o=0;o<w.length;o+=1)x(w[o]);H=!1},d(t){t&&c(l),t&&c(p),t&&c(u),P&&P.d(),t&&c(rt),nt(O,t),t&&c(ct),t&&c(N),t&&c(dt),t&&c(M),t&&c(pt),t&&c(V),t&&c(bt),t&&c(U),v&&v.d(),y&&y.d(),g&&g.d(),t&&c(yt),t&&c(j),t&&c(gt),t&&c(E),nt(q),nt(F),t&&c(Ot),t&&c(K),t&&c(Mt),t&&c(L);for(let o=0;o<A.length;o+=1)A[o].d();for(let o=0;o<w.length;o+=1)w[o].d()}}}function Be(n,l,a){let i,S,m,p,{collection:u=new Te}=l,_=200,R=[];const C=T=>a(3,_=T.code);return n.$$set=T=>{"collection"in T&&a(0,u=T.collection)},n.$$.update=()=>{var T,B;n.$$.dirty&1&&a(2,S=(T=u==null?void 0:u.options)==null?void 0:T.allowEmailAuth),n.$$.dirty&1&&a(1,m=(B=u==null?void 0:u.options)==null?void 0:B.allowUsernameAuth),n.$$.dirty&6&&a(5,p=m&&S?"YOUR_USERNAME_OR_EMAIL":m?"YOUR_USERNAME":"YOUR_EMAIL"),n.$$.dirty&1&&a(4,R=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:fe.dummyCollectionRecord(u)},null,2)},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"identity": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}])},a(6,i=fe.getApiExampleUrl(Ae.baseUrl)),[u,m,S,_,R,p,i,C]}class Ye extends ve{constructor(l){super(),ye(this,l,Be,Le,ge,{collection:0})}}export{Ye as default};
+98
View File
@@ -0,0 +1,98 @@
import{S as we,i as ye,s as $e,N as ve,O as ot,e as n,w as p,b as d,c as nt,f as m,g as r,h as e,m as st,x as Dt,P as pe,Q as Pe,k as Re,R as Ce,n as Oe,t as Z,a as x,o as c,d as it,C as fe,p as Ae,r as rt,u as Te}from"./index-f26826b5.js";import{S as Ue}from"./SdkTabs-37a2d588.js";import{F as Me}from"./FieldsQueryParam-e2795694.js";function he(s,l,a){const i=s.slice();return i[8]=l[a],i}function be(s,l,a){const i=s.slice();return i[8]=l[a],i}function De(s){let l;return{c(){l=p("email")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function Ee(s){let l;return{c(){l=p("username")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function We(s){let l;return{c(){l=p("username/email")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function me(s){let l;return{c(){l=n("strong"),l.textContent="username"},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function _e(s){let l;return{c(){l=p("or")},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function ke(s){let l;return{c(){l=n("strong"),l.textContent="email"},m(a,i){r(a,l,i)},d(a){a&&c(l)}}}function ge(s,l){let a,i=l[8].code+"",g,b,f,u;function _(){return l[7](l[8])}return{key:s,first:null,c(){a=n("button"),g=p(i),b=d(),m(a,"class","tab-item"),rt(a,"active",l[3]===l[8].code),this.first=a},m(R,C){r(R,a,C),e(a,g),e(a,b),f||(u=Te(a,"click",_),f=!0)},p(R,C){l=R,C&16&&i!==(i=l[8].code+"")&&Dt(g,i),C&24&&rt(a,"active",l[3]===l[8].code)},d(R){R&&c(a),f=!1,u()}}}function Se(s,l){let a,i,g,b;return i=new ve({props:{content:l[8].body}}),{key:s,first:null,c(){a=n("div"),nt(i.$$.fragment),g=d(),m(a,"class","tab-item"),rt(a,"active",l[3]===l[8].code),this.first=a},m(f,u){r(f,a,u),st(i,a,null),e(a,g),b=!0},p(f,u){l=f;const _={};u&16&&(_.content=l[8].body),i.$set(_),(!b||u&24)&&rt(a,"active",l[3]===l[8].code)},i(f){b||(Z(i.$$.fragment,f),b=!0)},o(f){x(i.$$.fragment,f),b=!1},d(f){f&&c(a),it(i)}}}function Le(s){var re,ce;let l,a,i=s[0].name+"",g,b,f,u,_,R,C,O,B,Et,ct,T,dt,N,ut,U,tt,Wt,et,I,Lt,pt,lt=s[0].name+"",ft,Bt,ht,V,bt,M,mt,qt,Q,D,_t,Ft,kt,Ht,$,Yt,gt,St,vt,Nt,wt,yt,j,$t,E,Pt,It,J,W,Rt,Vt,Ct,Qt,k,jt,q,Jt,Kt,zt,Ot,Gt,At,Xt,Zt,xt,Tt,te,ee,F,Ut,K,Mt,L,z,A=[],le=new Map,ae,G,S=[],oe=new Map,H;function ne(t,o){if(t[1]&&t[2])return We;if(t[1])return Ee;if(t[2])return De}let Y=ne(s),P=Y&&Y(s);T=new Ue({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${s[6]}');
...
const authData = await pb.collection('${(re=s[0])==null?void 0:re.name}').authWithPassword(
'${s[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${s[6]}');
...
final authData = await pb.collection('${(ce=s[0])==null?void 0:ce.name}').authWithPassword(
'${s[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`}});let v=s[1]&&me(),w=s[1]&&s[2]&&_e(),y=s[2]&&ke();q=new ve({props:{content:"?expand=relField1,relField2.subRelField"}}),F=new Me({});let at=ot(s[4]);const se=t=>t[8].code;for(let t=0;t<at.length;t+=1){let o=be(s,at,t),h=se(o);le.set(h,A[t]=ge(h,o))}let X=ot(s[4]);const ie=t=>t[8].code;for(let t=0;t<X.length;t+=1){let o=he(s,X,t),h=ie(o);oe.set(h,S[t]=Se(h,o))}return{c(){l=n("h3"),a=p("Auth with password ("),g=p(i),b=p(")"),f=d(),u=n("div"),_=n("p"),R=p(`Returns new auth token and account data by a combination of
`),C=n("strong"),P&&P.c(),O=p(`
and `),B=n("strong"),B.textContent="password",Et=p("."),ct=d(),nt(T.$$.fragment),dt=d(),N=n("h6"),N.textContent="API details",ut=d(),U=n("div"),tt=n("strong"),tt.textContent="POST",Wt=d(),et=n("div"),I=n("p"),Lt=p("/api/collections/"),pt=n("strong"),ft=p(lt),Bt=p("/auth-with-password"),ht=d(),V=n("div"),V.textContent="Body Parameters",bt=d(),M=n("table"),mt=n("thead"),mt.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',qt=d(),Q=n("tbody"),D=n("tr"),_t=n("td"),_t.innerHTML='<div class="inline-flex"><span class="label label-success">Required</span> <span>identity</span></div>',Ft=d(),kt=n("td"),kt.innerHTML='<span class="label">String</span>',Ht=d(),$=n("td"),Yt=p(`The
`),v&&v.c(),gt=d(),w&&w.c(),St=d(),y&&y.c(),vt=p(`
of the record to authenticate.`),Nt=d(),wt=n("tr"),wt.innerHTML='<td><div class="inline-flex"><span class="label label-success">Required</span> <span>password</span></div></td> <td><span class="label">String</span></td> <td>The auth record password.</td>',yt=d(),j=n("div"),j.textContent="Query parameters",$t=d(),E=n("table"),Pt=n("thead"),Pt.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',It=d(),J=n("tbody"),W=n("tr"),Rt=n("td"),Rt.textContent="expand",Vt=d(),Ct=n("td"),Ct.innerHTML='<span class="label">String</span>',Qt=d(),k=n("td"),jt=p(`Auto expand record relations. Ex.:
`),nt(q.$$.fragment),Jt=p(`
Supports up to 6-levels depth nested relations expansion. `),Kt=n("br"),zt=p(`
The expanded relations will be appended to the record under the
`),Ot=n("code"),Ot.textContent="expand",Gt=p(" property (eg. "),At=n("code"),At.textContent='"expand": {"relField1": {...}, ...}',Xt=p(`).
`),Zt=n("br"),xt=p(`
Only the relations to which the request user has permissions to `),Tt=n("strong"),Tt.textContent="view",te=p(" will be expanded."),ee=d(),nt(F.$$.fragment),Ut=d(),K=n("div"),K.textContent="Responses",Mt=d(),L=n("div"),z=n("div");for(let t=0;t<A.length;t+=1)A[t].c();ae=d(),G=n("div");for(let t=0;t<S.length;t+=1)S[t].c();m(l,"class","m-b-sm"),m(u,"class","content txt-lg m-b-sm"),m(N,"class","m-b-xs"),m(tt,"class","label label-primary"),m(et,"class","content"),m(U,"class","alert alert-success"),m(V,"class","section-title"),m(M,"class","table-compact table-border m-b-base"),m(j,"class","section-title"),m(E,"class","table-compact table-border m-b-base"),m(K,"class","section-title"),m(z,"class","tabs-header compact combined left"),m(G,"class","tabs-content"),m(L,"class","tabs")},m(t,o){r(t,l,o),e(l,a),e(l,g),e(l,b),r(t,f,o),r(t,u,o),e(u,_),e(_,R),e(_,C),P&&P.m(C,null),e(_,O),e(_,B),e(_,Et),r(t,ct,o),st(T,t,o),r(t,dt,o),r(t,N,o),r(t,ut,o),r(t,U,o),e(U,tt),e(U,Wt),e(U,et),e(et,I),e(I,Lt),e(I,pt),e(pt,ft),e(I,Bt),r(t,ht,o),r(t,V,o),r(t,bt,o),r(t,M,o),e(M,mt),e(M,qt),e(M,Q),e(Q,D),e(D,_t),e(D,Ft),e(D,kt),e(D,Ht),e(D,$),e($,Yt),v&&v.m($,null),e($,gt),w&&w.m($,null),e($,St),y&&y.m($,null),e($,vt),e(Q,Nt),e(Q,wt),r(t,yt,o),r(t,j,o),r(t,$t,o),r(t,E,o),e(E,Pt),e(E,It),e(E,J),e(J,W),e(W,Rt),e(W,Vt),e(W,Ct),e(W,Qt),e(W,k),e(k,jt),st(q,k,null),e(k,Jt),e(k,Kt),e(k,zt),e(k,Ot),e(k,Gt),e(k,At),e(k,Xt),e(k,Zt),e(k,xt),e(k,Tt),e(k,te),e(J,ee),st(F,J,null),r(t,Ut,o),r(t,K,o),r(t,Mt,o),r(t,L,o),e(L,z);for(let h=0;h<A.length;h+=1)A[h]&&A[h].m(z,null);e(L,ae),e(L,G);for(let h=0;h<S.length;h+=1)S[h]&&S[h].m(G,null);H=!0},p(t,[o]){var de,ue;(!H||o&1)&&i!==(i=t[0].name+"")&&Dt(g,i),Y!==(Y=ne(t))&&(P&&P.d(1),P=Y&&Y(t),P&&(P.c(),P.m(C,null)));const h={};o&97&&(h.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${t[6]}');
...
const authData = await pb.collection('${(de=t[0])==null?void 0:de.name}').authWithPassword(
'${t[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
console.log(pb.authStore.isValid);
console.log(pb.authStore.token);
console.log(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`),o&97&&(h.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${t[6]}');
...
final authData = await pb.collection('${(ue=t[0])==null?void 0:ue.name}').authWithPassword(
'${t[5]}',
'YOUR_PASSWORD',
);
// after the above you can also access the auth data from the authStore
print(pb.authStore.isValid);
print(pb.authStore.token);
print(pb.authStore.model.id);
// "logout" the last authenticated account
pb.authStore.clear();
`),T.$set(h),(!H||o&1)&&lt!==(lt=t[0].name+"")&&Dt(ft,lt),t[1]?v||(v=me(),v.c(),v.m($,gt)):v&&(v.d(1),v=null),t[1]&&t[2]?w||(w=_e(),w.c(),w.m($,St)):w&&(w.d(1),w=null),t[2]?y||(y=ke(),y.c(),y.m($,vt)):y&&(y.d(1),y=null),o&24&&(at=ot(t[4]),A=pe(A,o,se,1,t,at,le,z,Pe,ge,null,be)),o&24&&(X=ot(t[4]),Re(),S=pe(S,o,ie,1,t,X,oe,G,Ce,Se,null,he),Oe())},i(t){if(!H){Z(T.$$.fragment,t),Z(q.$$.fragment,t),Z(F.$$.fragment,t);for(let o=0;o<X.length;o+=1)Z(S[o]);H=!0}},o(t){x(T.$$.fragment,t),x(q.$$.fragment,t),x(F.$$.fragment,t);for(let o=0;o<S.length;o+=1)x(S[o]);H=!1},d(t){t&&(c(l),c(f),c(u),c(ct),c(dt),c(N),c(ut),c(U),c(ht),c(V),c(bt),c(M),c(yt),c(j),c($t),c(E),c(Ut),c(K),c(Mt),c(L)),P&&P.d(),it(T,t),v&&v.d(),w&&w.d(),y&&y.d(),it(q),it(F);for(let o=0;o<A.length;o+=1)A[o].d();for(let o=0;o<S.length;o+=1)S[o].d()}}}function Be(s,l,a){let i,g,b,f,{collection:u}=l,_=200,R=[];const C=O=>a(3,_=O.code);return s.$$set=O=>{"collection"in O&&a(0,u=O.collection)},s.$$.update=()=>{var O,B;s.$$.dirty&1&&a(2,g=(O=u==null?void 0:u.options)==null?void 0:O.allowEmailAuth),s.$$.dirty&1&&a(1,b=(B=u==null?void 0:u.options)==null?void 0:B.allowUsernameAuth),s.$$.dirty&6&&a(5,f=b&&g?"YOUR_USERNAME_OR_EMAIL":b?"YOUR_USERNAME":"YOUR_EMAIL"),s.$$.dirty&1&&a(4,R=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:fe.dummyCollectionRecord(u)},null,2)},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"identity": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}])},a(6,i=fe.getApiExampleUrl(Ae.baseUrl)),[u,b,g,_,R,f,i,C]}class Ye extends we{constructor(l){super(),ye(this,l,Be,Le,$e,{collection:0})}}export{Ye as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+56
View File
@@ -0,0 +1,56 @@
import{S as $e,i as Pe,s as Se,O as Y,e as r,w as v,b as k,c as ge,f as b,g as d,h as o,m as ve,x as j,P as ue,Q as we,k as Oe,R as Re,n as Te,t as x,a as ee,o as m,d as Ce,C as ye,p as Ee,r as H,u as Be,N as qe}from"./index-f26826b5.js";import{S as Ae}from"./SdkTabs-37a2d588.js";function be(n,l,s){const a=n.slice();return a[5]=l[s],a}function _e(n,l,s){const a=n.slice();return a[5]=l[s],a}function he(n,l){let s,a=l[5].code+"",_,u,i,p;function f(){return l[4](l[5])}return{key:n,first:null,c(){s=r("button"),_=v(a),u=k(),b(s,"class","tab-item"),H(s,"active",l[1]===l[5].code),this.first=s},m(C,$){d(C,s,$),o(s,_),o(s,u),i||(p=Be(s,"click",f),i=!0)},p(C,$){l=C,$&4&&a!==(a=l[5].code+"")&&j(_,a),$&6&&H(s,"active",l[1]===l[5].code)},d(C){C&&m(s),i=!1,p()}}}function ke(n,l){let s,a,_,u;return a=new qe({props:{content:l[5].body}}),{key:n,first:null,c(){s=r("div"),ge(a.$$.fragment),_=k(),b(s,"class","tab-item"),H(s,"active",l[1]===l[5].code),this.first=s},m(i,p){d(i,s,p),ve(a,s,null),o(s,_),u=!0},p(i,p){l=i;const f={};p&4&&(f.content=l[5].body),a.$set(f),(!u||p&6)&&H(s,"active",l[1]===l[5].code)},i(i){u||(x(a.$$.fragment,i),u=!0)},o(i){ee(a.$$.fragment,i),u=!1},d(i){i&&m(s),Ce(a)}}}function Ue(n){var de,me;let l,s,a=n[0].name+"",_,u,i,p,f,C,$,D=n[0].name+"",F,te,I,P,L,R,Q,S,N,le,K,T,se,z,M=n[0].name+"",G,ae,J,y,V,E,X,B,Z,w,q,g=[],ne=new Map,oe,A,h=[],ie=new Map,O;P=new Ae({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[3]}');
...
await pb.collection('${(de=n[0])==null?void 0:de.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[3]}');
...
await pb.collection('${(me=n[0])==null?void 0:me.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`}});let W=Y(n[2]);const ce=e=>e[5].code;for(let e=0;e<W.length;e+=1){let t=_e(n,W,e),c=ce(t);ne.set(c,g[e]=he(c,t))}let U=Y(n[2]);const re=e=>e[5].code;for(let e=0;e<U.length;e+=1){let t=be(n,U,e),c=re(t);ie.set(c,h[e]=ke(c,t))}return{c(){l=r("h3"),s=v("Confirm email change ("),_=v(a),u=v(")"),i=k(),p=r("div"),f=r("p"),C=v("Confirms "),$=r("strong"),F=v(D),te=v(" email change request."),I=k(),ge(P.$$.fragment),L=k(),R=r("h6"),R.textContent="API details",Q=k(),S=r("div"),N=r("strong"),N.textContent="POST",le=k(),K=r("div"),T=r("p"),se=v("/api/collections/"),z=r("strong"),G=v(M),ae=v("/confirm-email-change"),J=k(),y=r("div"),y.textContent="Body Parameters",V=k(),E=r("table"),E.innerHTML='<thead><tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr></thead> <tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>token</span></div></td> <td><span class="label">String</span></td> <td>The token from the change email request email.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>password</span></div></td> <td><span class="label">String</span></td> <td>The account password to confirm the email change.</td></tr></tbody>',X=k(),B=r("div"),B.textContent="Responses",Z=k(),w=r("div"),q=r("div");for(let e=0;e<g.length;e+=1)g[e].c();oe=k(),A=r("div");for(let e=0;e<h.length;e+=1)h[e].c();b(l,"class","m-b-sm"),b(p,"class","content txt-lg m-b-sm"),b(R,"class","m-b-xs"),b(N,"class","label label-primary"),b(K,"class","content"),b(S,"class","alert alert-success"),b(y,"class","section-title"),b(E,"class","table-compact table-border m-b-base"),b(B,"class","section-title"),b(q,"class","tabs-header compact combined left"),b(A,"class","tabs-content"),b(w,"class","tabs")},m(e,t){d(e,l,t),o(l,s),o(l,_),o(l,u),d(e,i,t),d(e,p,t),o(p,f),o(f,C),o(f,$),o($,F),o(f,te),d(e,I,t),ve(P,e,t),d(e,L,t),d(e,R,t),d(e,Q,t),d(e,S,t),o(S,N),o(S,le),o(S,K),o(K,T),o(T,se),o(T,z),o(z,G),o(T,ae),d(e,J,t),d(e,y,t),d(e,V,t),d(e,E,t),d(e,X,t),d(e,B,t),d(e,Z,t),d(e,w,t),o(w,q);for(let c=0;c<g.length;c+=1)g[c]&&g[c].m(q,null);o(w,oe),o(w,A);for(let c=0;c<h.length;c+=1)h[c]&&h[c].m(A,null);O=!0},p(e,[t]){var pe,fe;(!O||t&1)&&a!==(a=e[0].name+"")&&j(_,a),(!O||t&1)&&D!==(D=e[0].name+"")&&j(F,D);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(pe=e[0])==null?void 0:pe.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(fe=e[0])==null?void 0:fe.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`),P.$set(c),(!O||t&1)&&M!==(M=e[0].name+"")&&j(G,M),t&6&&(W=Y(e[2]),g=ue(g,t,ce,1,e,W,ne,q,we,he,null,_e)),t&6&&(U=Y(e[2]),Oe(),h=ue(h,t,re,1,e,U,ie,A,Re,ke,null,be),Te())},i(e){if(!O){x(P.$$.fragment,e);for(let t=0;t<U.length;t+=1)x(h[t]);O=!0}},o(e){ee(P.$$.fragment,e);for(let t=0;t<h.length;t+=1)ee(h[t]);O=!1},d(e){e&&(m(l),m(i),m(p),m(I),m(L),m(R),m(Q),m(S),m(J),m(y),m(V),m(E),m(X),m(B),m(Z),m(w)),Ce(P,e);for(let t=0;t<g.length;t+=1)g[t].d();for(let t=0;t<h.length;t+=1)h[t].d()}}}function De(n,l,s){let a,{collection:_}=l,u=204,i=[];const p=f=>s(1,u=f.code);return n.$$set=f=>{"collection"in f&&s(0,_=f.collection)},s(3,a=ye.getApiExampleUrl(Ee.baseUrl)),s(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[_,u,i,a,p]}class Me extends $e{constructor(l){super(),Pe(this,l,De,Ue,Se,{collection:0})}}export{Me as default};
-66
View File
@@ -1,66 +0,0 @@
import{S as Ce,i as $e,s as we,e as r,w as g,b as h,c as he,f as b,g as f,h as n,m as ve,x as Y,N as pe,P as Pe,k as Se,Q as Oe,n as Te,t as Z,a as x,o as m,d as ge,T as Re,C as Ee,p as ye,r as j,u as Be,M as qe}from"./index-9e84ac8a.js";import{S as Ae}from"./SdkTabs-821a18db.js";function ue(o,l,s){const a=o.slice();return a[5]=l[s],a}function be(o,l,s){const a=o.slice();return a[5]=l[s],a}function _e(o,l){let s,a=l[5].code+"",_,u,i,d;function p(){return l[4](l[5])}return{key:o,first:null,c(){s=r("button"),_=g(a),u=h(),b(s,"class","tab-item"),j(s,"active",l[1]===l[5].code),this.first=s},m(C,$){f(C,s,$),n(s,_),n(s,u),i||(d=Be(s,"click",p),i=!0)},p(C,$){l=C,$&4&&a!==(a=l[5].code+"")&&Y(_,a),$&6&&j(s,"active",l[1]===l[5].code)},d(C){C&&m(s),i=!1,d()}}}function ke(o,l){let s,a,_,u;return a=new qe({props:{content:l[5].body}}),{key:o,first:null,c(){s=r("div"),he(a.$$.fragment),_=h(),b(s,"class","tab-item"),j(s,"active",l[1]===l[5].code),this.first=s},m(i,d){f(i,s,d),ve(a,s,null),n(s,_),u=!0},p(i,d){l=i;const p={};d&4&&(p.content=l[5].body),a.$set(p),(!u||d&6)&&j(s,"active",l[1]===l[5].code)},i(i){u||(Z(a.$$.fragment,i),u=!0)},o(i){x(a.$$.fragment,i),u=!1},d(i){i&&m(s),ge(a)}}}function Ue(o){var re,fe;let l,s,a=o[0].name+"",_,u,i,d,p,C,$,D=o[0].name+"",H,ee,F,w,I,T,L,P,M,te,N,R,le,Q,K=o[0].name+"",z,se,G,E,J,y,V,B,X,S,q,v=[],ae=new Map,oe,A,k=[],ne=new Map,O;w=new Ae({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[3]}');
...
await pb.collection('${(re=o[0])==null?void 0:re.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[3]}');
...
await pb.collection('${(fe=o[0])==null?void 0:fe.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`}});let W=o[2];const ie=e=>e[5].code;for(let e=0;e<W.length;e+=1){let t=be(o,W,e),c=ie(t);ae.set(c,v[e]=_e(c,t))}let U=o[2];const ce=e=>e[5].code;for(let e=0;e<U.length;e+=1){let t=ue(o,U,e),c=ce(t);ne.set(c,k[e]=ke(c,t))}return{c(){l=r("h3"),s=g("Confirm email change ("),_=g(a),u=g(")"),i=h(),d=r("div"),p=r("p"),C=g("Confirms "),$=r("strong"),H=g(D),ee=g(" email change request."),F=h(),he(w.$$.fragment),I=h(),T=r("h6"),T.textContent="API details",L=h(),P=r("div"),M=r("strong"),M.textContent="POST",te=h(),N=r("div"),R=r("p"),le=g("/api/collections/"),Q=r("strong"),z=g(K),se=g("/confirm-email-change"),G=h(),E=r("div"),E.textContent="Body Parameters",J=h(),y=r("table"),y.innerHTML=`<thead><tr><th>Param</th>
<th>Type</th>
<th width="50%">Description</th></tr></thead>
<tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>token</span></div></td>
<td><span class="label">String</span></td>
<td>The token from the change email request email.</td></tr>
<tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>password</span></div></td>
<td><span class="label">String</span></td>
<td>The account password to confirm the email change.</td></tr></tbody>`,V=h(),B=r("div"),B.textContent="Responses",X=h(),S=r("div"),q=r("div");for(let e=0;e<v.length;e+=1)v[e].c();oe=h(),A=r("div");for(let e=0;e<k.length;e+=1)k[e].c();b(l,"class","m-b-sm"),b(d,"class","content txt-lg m-b-sm"),b(T,"class","m-b-xs"),b(M,"class","label label-primary"),b(N,"class","content"),b(P,"class","alert alert-success"),b(E,"class","section-title"),b(y,"class","table-compact table-border m-b-base"),b(B,"class","section-title"),b(q,"class","tabs-header compact left"),b(A,"class","tabs-content"),b(S,"class","tabs")},m(e,t){f(e,l,t),n(l,s),n(l,_),n(l,u),f(e,i,t),f(e,d,t),n(d,p),n(p,C),n(p,$),n($,H),n(p,ee),f(e,F,t),ve(w,e,t),f(e,I,t),f(e,T,t),f(e,L,t),f(e,P,t),n(P,M),n(P,te),n(P,N),n(N,R),n(R,le),n(R,Q),n(Q,z),n(R,se),f(e,G,t),f(e,E,t),f(e,J,t),f(e,y,t),f(e,V,t),f(e,B,t),f(e,X,t),f(e,S,t),n(S,q);for(let c=0;c<v.length;c+=1)v[c]&&v[c].m(q,null);n(S,oe),n(S,A);for(let c=0;c<k.length;c+=1)k[c]&&k[c].m(A,null);O=!0},p(e,[t]){var me,de;(!O||t&1)&&a!==(a=e[0].name+"")&&Y(_,a),(!O||t&1)&&D!==(D=e[0].name+"")&&Y(H,D);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(me=e[0])==null?void 0:me.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(de=e[0])==null?void 0:de.name}').confirmEmailChange(
'TOKEN',
'YOUR_PASSWORD',
);
`),w.$set(c),(!O||t&1)&&K!==(K=e[0].name+"")&&Y(z,K),t&6&&(W=e[2],v=pe(v,t,ie,1,e,W,ae,q,Pe,_e,null,be)),t&6&&(U=e[2],Se(),k=pe(k,t,ce,1,e,U,ne,A,Oe,ke,null,ue),Te())},i(e){if(!O){Z(w.$$.fragment,e);for(let t=0;t<U.length;t+=1)Z(k[t]);O=!0}},o(e){x(w.$$.fragment,e);for(let t=0;t<k.length;t+=1)x(k[t]);O=!1},d(e){e&&m(l),e&&m(i),e&&m(d),e&&m(F),ge(w,e),e&&m(I),e&&m(T),e&&m(L),e&&m(P),e&&m(G),e&&m(E),e&&m(J),e&&m(y),e&&m(V),e&&m(B),e&&m(X),e&&m(S);for(let t=0;t<v.length;t+=1)v[t].d();for(let t=0;t<k.length;t+=1)k[t].d()}}}function De(o,l,s){let a,{collection:_=new Re}=l,u=204,i=[];const d=p=>s(1,u=p.code);return o.$$set=p=>{"collection"in p&&s(0,_=p.collection)},s(3,a=Ee.getApiExampleUrl(ye.baseUrl)),s(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[_,u,i,a,d]}class Ke extends Ce{constructor(l){super(),$e(this,l,De,Ue,we,{collection:0})}}export{Ke as default};
+61
View File
@@ -0,0 +1,61 @@
import{S as Re,i as Oe,s as Ce,O as K,e as r,w,b as h,c as ge,f as b,g as d,h as n,m as Pe,x as U,P as _e,Q as Ne,k as We,R as $e,n as Ee,t as ee,a as te,o as p,d as Se,C as ye,p as Ae,r as j,u as Te,N as De}from"./index-f26826b5.js";import{S as qe}from"./SdkTabs-37a2d588.js";function ke(o,s,l){const a=o.slice();return a[5]=s[l],a}function he(o,s,l){const a=o.slice();return a[5]=s[l],a}function ve(o,s){let l,a=s[5].code+"",_,u,i,f;function m(){return s[4](s[5])}return{key:o,first:null,c(){l=r("button"),_=w(a),u=h(),b(l,"class","tab-item"),j(l,"active",s[1]===s[5].code),this.first=l},m(g,P){d(g,l,P),n(l,_),n(l,u),i||(f=Te(l,"click",m),i=!0)},p(g,P){s=g,P&4&&a!==(a=s[5].code+"")&&U(_,a),P&6&&j(l,"active",s[1]===s[5].code)},d(g){g&&p(l),i=!1,f()}}}function we(o,s){let l,a,_,u;return a=new De({props:{content:s[5].body}}),{key:o,first:null,c(){l=r("div"),ge(a.$$.fragment),_=h(),b(l,"class","tab-item"),j(l,"active",s[1]===s[5].code),this.first=l},m(i,f){d(i,l,f),Pe(a,l,null),n(l,_),u=!0},p(i,f){s=i;const m={};f&4&&(m.content=s[5].body),a.$set(m),(!u||f&6)&&j(l,"active",s[1]===s[5].code)},i(i){u||(ee(a.$$.fragment,i),u=!0)},o(i){te(a.$$.fragment,i),u=!1},d(i){i&&p(l),Se(a)}}}function Be(o){var fe,me;let s,l,a=o[0].name+"",_,u,i,f,m,g,P,q=o[0].name+"",H,se,le,L,Q,S,z,N,G,R,B,ae,M,W,ne,J,F=o[0].name+"",V,oe,X,$,Y,E,Z,y,x,O,A,v=[],ie=new Map,ce,T,k=[],re=new Map,C;S=new qe({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[3]}');
...
await pb.collection('${(fe=o[0])==null?void 0:fe.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[3]}');
...
await pb.collection('${(me=o[0])==null?void 0:me.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`}});let I=K(o[2]);const de=e=>e[5].code;for(let e=0;e<I.length;e+=1){let t=he(o,I,e),c=de(t);ie.set(c,v[e]=ve(c,t))}let D=K(o[2]);const pe=e=>e[5].code;for(let e=0;e<D.length;e+=1){let t=ke(o,D,e),c=pe(t);re.set(c,k[e]=we(c,t))}return{c(){s=r("h3"),l=w("Confirm password reset ("),_=w(a),u=w(")"),i=h(),f=r("div"),m=r("p"),g=w("Confirms "),P=r("strong"),H=w(q),se=w(" password reset request and sets a new password."),le=h(),L=r("p"),L.textContent=`After this request all previously issued tokens for the specific record will be automatically
invalidated.`,Q=h(),ge(S.$$.fragment),z=h(),N=r("h6"),N.textContent="API details",G=h(),R=r("div"),B=r("strong"),B.textContent="POST",ae=h(),M=r("div"),W=r("p"),ne=w("/api/collections/"),J=r("strong"),V=w(F),oe=w("/confirm-password-reset"),X=h(),$=r("div"),$.textContent="Body Parameters",Y=h(),E=r("table"),E.innerHTML='<thead><tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr></thead> <tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>token</span></div></td> <td><span class="label">String</span></td> <td>The token from the password reset request email.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>password</span></div></td> <td><span class="label">String</span></td> <td>The new password to set.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>passwordConfirm</span></div></td> <td><span class="label">String</span></td> <td>The new password confirmation.</td></tr></tbody>',Z=h(),y=r("div"),y.textContent="Responses",x=h(),O=r("div"),A=r("div");for(let e=0;e<v.length;e+=1)v[e].c();ce=h(),T=r("div");for(let e=0;e<k.length;e+=1)k[e].c();b(s,"class","m-b-sm"),b(f,"class","content txt-lg m-b-sm"),b(N,"class","m-b-xs"),b(B,"class","label label-primary"),b(M,"class","content"),b(R,"class","alert alert-success"),b($,"class","section-title"),b(E,"class","table-compact table-border m-b-base"),b(y,"class","section-title"),b(A,"class","tabs-header compact combined left"),b(T,"class","tabs-content"),b(O,"class","tabs")},m(e,t){d(e,s,t),n(s,l),n(s,_),n(s,u),d(e,i,t),d(e,f,t),n(f,m),n(m,g),n(m,P),n(P,H),n(m,se),n(f,le),n(f,L),d(e,Q,t),Pe(S,e,t),d(e,z,t),d(e,N,t),d(e,G,t),d(e,R,t),n(R,B),n(R,ae),n(R,M),n(M,W),n(W,ne),n(W,J),n(J,V),n(W,oe),d(e,X,t),d(e,$,t),d(e,Y,t),d(e,E,t),d(e,Z,t),d(e,y,t),d(e,x,t),d(e,O,t),n(O,A);for(let c=0;c<v.length;c+=1)v[c]&&v[c].m(A,null);n(O,ce),n(O,T);for(let c=0;c<k.length;c+=1)k[c]&&k[c].m(T,null);C=!0},p(e,[t]){var ue,be;(!C||t&1)&&a!==(a=e[0].name+"")&&U(_,a),(!C||t&1)&&q!==(q=e[0].name+"")&&U(H,q);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(ue=e[0])==null?void 0:ue.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(be=e[0])==null?void 0:be.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`),S.$set(c),(!C||t&1)&&F!==(F=e[0].name+"")&&U(V,F),t&6&&(I=K(e[2]),v=_e(v,t,de,1,e,I,ie,A,Ne,ve,null,he)),t&6&&(D=K(e[2]),We(),k=_e(k,t,pe,1,e,D,re,T,$e,we,null,ke),Ee())},i(e){if(!C){ee(S.$$.fragment,e);for(let t=0;t<D.length;t+=1)ee(k[t]);C=!0}},o(e){te(S.$$.fragment,e);for(let t=0;t<k.length;t+=1)te(k[t]);C=!1},d(e){e&&(p(s),p(i),p(f),p(Q),p(z),p(N),p(G),p(R),p(X),p($),p(Y),p(E),p(Z),p(y),p(x),p(O)),Se(S,e);for(let t=0;t<v.length;t+=1)v[t].d();for(let t=0;t<k.length;t+=1)k[t].d()}}}function Me(o,s,l){let a,{collection:_}=s,u=204,i=[];const f=m=>l(1,u=m.code);return o.$$set=m=>{"collection"in m&&l(0,_=m.collection)},l(3,a=ye.getApiExampleUrl(Ae.baseUrl)),l(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[_,u,i,a,f]}class Ke extends Re{constructor(s){super(),Oe(this,s,Me,Be,Ce,{collection:0})}}export{Ke as default};
-74
View File
@@ -1,74 +0,0 @@
import{S as Se,i as he,s as Re,e as r,w as P,b as v,c as ve,f as b,g as d,h as n,m as we,x as K,N as me,P as Ne,k as Oe,Q as Ce,n as We,t as Z,a as x,o as f,d as Pe,T as $e,C as Ee,p as Te,r as U,u as ge,M as Ae}from"./index-9e84ac8a.js";import{S as De}from"./SdkTabs-821a18db.js";function ue(o,s,l){const a=o.slice();return a[5]=s[l],a}function be(o,s,l){const a=o.slice();return a[5]=s[l],a}function _e(o,s){let l,a=s[5].code+"",_,u,i,p;function m(){return s[4](s[5])}return{key:o,first:null,c(){l=r("button"),_=P(a),u=v(),b(l,"class","tab-item"),U(l,"active",s[1]===s[5].code),this.first=l},m(S,h){d(S,l,h),n(l,_),n(l,u),i||(p=ge(l,"click",m),i=!0)},p(S,h){s=S,h&4&&a!==(a=s[5].code+"")&&K(_,a),h&6&&U(l,"active",s[1]===s[5].code)},d(S){S&&f(l),i=!1,p()}}}function ke(o,s){let l,a,_,u;return a=new Ae({props:{content:s[5].body}}),{key:o,first:null,c(){l=r("div"),ve(a.$$.fragment),_=v(),b(l,"class","tab-item"),U(l,"active",s[1]===s[5].code),this.first=l},m(i,p){d(i,l,p),we(a,l,null),n(l,_),u=!0},p(i,p){s=i;const m={};p&4&&(m.content=s[5].body),a.$set(m),(!u||p&6)&&U(l,"active",s[1]===s[5].code)},i(i){u||(Z(a.$$.fragment,i),u=!0)},o(i){x(a.$$.fragment,i),u=!1},d(i){i&&f(l),Pe(a)}}}function ye(o){var re,de;let s,l,a=o[0].name+"",_,u,i,p,m,S,h,M=o[0].name+"",j,ee,H,R,L,W,Q,N,q,te,B,$,se,z,F=o[0].name+"",G,le,J,E,V,T,X,g,Y,O,A,w=[],ae=new Map,oe,D,k=[],ne=new Map,C;R=new De({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[3]}');
...
await pb.collection('${(re=o[0])==null?void 0:re.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[3]}');
...
await pb.collection('${(de=o[0])==null?void 0:de.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`}});let I=o[2];const ie=e=>e[5].code;for(let e=0;e<I.length;e+=1){let t=be(o,I,e),c=ie(t);ae.set(c,w[e]=_e(c,t))}let y=o[2];const ce=e=>e[5].code;for(let e=0;e<y.length;e+=1){let t=ue(o,y,e),c=ce(t);ne.set(c,k[e]=ke(c,t))}return{c(){s=r("h3"),l=P("Confirm password reset ("),_=P(a),u=P(")"),i=v(),p=r("div"),m=r("p"),S=P("Confirms "),h=r("strong"),j=P(M),ee=P(" password reset request and sets a new password."),H=v(),ve(R.$$.fragment),L=v(),W=r("h6"),W.textContent="API details",Q=v(),N=r("div"),q=r("strong"),q.textContent="POST",te=v(),B=r("div"),$=r("p"),se=P("/api/collections/"),z=r("strong"),G=P(F),le=P("/confirm-password-reset"),J=v(),E=r("div"),E.textContent="Body Parameters",V=v(),T=r("table"),T.innerHTML=`<thead><tr><th>Param</th>
<th>Type</th>
<th width="50%">Description</th></tr></thead>
<tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>token</span></div></td>
<td><span class="label">String</span></td>
<td>The token from the password reset request email.</td></tr>
<tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>password</span></div></td>
<td><span class="label">String</span></td>
<td>The new password to set.</td></tr>
<tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>passwordConfirm</span></div></td>
<td><span class="label">String</span></td>
<td>The new password confirmation.</td></tr></tbody>`,X=v(),g=r("div"),g.textContent="Responses",Y=v(),O=r("div"),A=r("div");for(let e=0;e<w.length;e+=1)w[e].c();oe=v(),D=r("div");for(let e=0;e<k.length;e+=1)k[e].c();b(s,"class","m-b-sm"),b(p,"class","content txt-lg m-b-sm"),b(W,"class","m-b-xs"),b(q,"class","label label-primary"),b(B,"class","content"),b(N,"class","alert alert-success"),b(E,"class","section-title"),b(T,"class","table-compact table-border m-b-base"),b(g,"class","section-title"),b(A,"class","tabs-header compact left"),b(D,"class","tabs-content"),b(O,"class","tabs")},m(e,t){d(e,s,t),n(s,l),n(s,_),n(s,u),d(e,i,t),d(e,p,t),n(p,m),n(m,S),n(m,h),n(h,j),n(m,ee),d(e,H,t),we(R,e,t),d(e,L,t),d(e,W,t),d(e,Q,t),d(e,N,t),n(N,q),n(N,te),n(N,B),n(B,$),n($,se),n($,z),n(z,G),n($,le),d(e,J,t),d(e,E,t),d(e,V,t),d(e,T,t),d(e,X,t),d(e,g,t),d(e,Y,t),d(e,O,t),n(O,A);for(let c=0;c<w.length;c+=1)w[c]&&w[c].m(A,null);n(O,oe),n(O,D);for(let c=0;c<k.length;c+=1)k[c]&&k[c].m(D,null);C=!0},p(e,[t]){var fe,pe;(!C||t&1)&&a!==(a=e[0].name+"")&&K(_,a),(!C||t&1)&&M!==(M=e[0].name+"")&&K(j,M);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(fe=e[0])==null?void 0:fe.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(pe=e[0])==null?void 0:pe.name}').confirmPasswordReset(
'TOKEN',
'NEW_PASSWORD',
'NEW_PASSWORD_CONFIRM',
);
`),R.$set(c),(!C||t&1)&&F!==(F=e[0].name+"")&&K(G,F),t&6&&(I=e[2],w=me(w,t,ie,1,e,I,ae,A,Ne,_e,null,be)),t&6&&(y=e[2],Oe(),k=me(k,t,ce,1,e,y,ne,D,Ce,ke,null,ue),We())},i(e){if(!C){Z(R.$$.fragment,e);for(let t=0;t<y.length;t+=1)Z(k[t]);C=!0}},o(e){x(R.$$.fragment,e);for(let t=0;t<k.length;t+=1)x(k[t]);C=!1},d(e){e&&f(s),e&&f(i),e&&f(p),e&&f(H),Pe(R,e),e&&f(L),e&&f(W),e&&f(Q),e&&f(N),e&&f(J),e&&f(E),e&&f(V),e&&f(T),e&&f(X),e&&f(g),e&&f(Y),e&&f(O);for(let t=0;t<w.length;t+=1)w[t].d();for(let t=0;t<k.length;t+=1)k[t].d()}}}function Me(o,s,l){let a,{collection:_=new $e}=s,u=204,i=[];const p=m=>l(1,u=m.code);return o.$$set=m=>{"collection"in m&&l(0,_=m.collection)},l(3,a=Ee.getApiExampleUrl(Te.baseUrl)),l(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[_,u,i,a,p]}class Fe extends Se{constructor(s){super(),he(this,s,Me,ye,Re,{collection:0})}}export{Fe as default};
+56
View File
@@ -0,0 +1,56 @@
import{S as Se,i as Te,s as Be,O as D,e as r,w as g,b as k,c as ye,f as h,g as f,h as n,m as Ce,x as H,P as ke,Q as Re,k as qe,R as Oe,n as Ee,t as x,a as ee,o as d,d as Pe,C as Ne,p as Ve,r as F,u as Ke,N as Me}from"./index-f26826b5.js";import{S as Ae}from"./SdkTabs-37a2d588.js";function ve(o,l,s){const a=o.slice();return a[5]=l[s],a}function ge(o,l,s){const a=o.slice();return a[5]=l[s],a}function we(o,l){let s,a=l[5].code+"",b,m,i,p;function u(){return l[4](l[5])}return{key:o,first:null,c(){s=r("button"),b=g(a),m=k(),h(s,"class","tab-item"),F(s,"active",l[1]===l[5].code),this.first=s},m(w,$){f(w,s,$),n(s,b),n(s,m),i||(p=Ke(s,"click",u),i=!0)},p(w,$){l=w,$&4&&a!==(a=l[5].code+"")&&H(b,a),$&6&&F(s,"active",l[1]===l[5].code)},d(w){w&&d(s),i=!1,p()}}}function $e(o,l){let s,a,b,m;return a=new Me({props:{content:l[5].body}}),{key:o,first:null,c(){s=r("div"),ye(a.$$.fragment),b=k(),h(s,"class","tab-item"),F(s,"active",l[1]===l[5].code),this.first=s},m(i,p){f(i,s,p),Ce(a,s,null),n(s,b),m=!0},p(i,p){l=i;const u={};p&4&&(u.content=l[5].body),a.$set(u),(!m||p&6)&&F(s,"active",l[1]===l[5].code)},i(i){m||(x(a.$$.fragment,i),m=!0)},o(i){ee(a.$$.fragment,i),m=!1},d(i){i&&d(s),Pe(a)}}}function Ue(o){var fe,de,pe,ue;let l,s,a=o[0].name+"",b,m,i,p,u,w,$,K=o[0].name+"",I,te,L,y,Q,T,z,C,M,le,A,B,se,G,U=o[0].name+"",J,ae,W,R,X,q,Y,O,Z,P,E,v=[],oe=new Map,ne,N,_=[],ie=new Map,S;y=new Ae({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[3]}');
...
await pb.collection('${(fe=o[0])==null?void 0:fe.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(de=o[0])==null?void 0:de.name}').authRefresh();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[3]}');
...
await pb.collection('${(pe=o[0])==null?void 0:pe.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(ue=o[0])==null?void 0:ue.name}').authRefresh();
`}});let j=D(o[2]);const ce=e=>e[5].code;for(let e=0;e<j.length;e+=1){let t=ge(o,j,e),c=ce(t);oe.set(c,v[e]=we(c,t))}let V=D(o[2]);const re=e=>e[5].code;for(let e=0;e<V.length;e+=1){let t=ve(o,V,e),c=re(t);ie.set(c,_[e]=$e(c,t))}return{c(){l=r("h3"),s=g("Confirm verification ("),b=g(a),m=g(")"),i=k(),p=r("div"),u=r("p"),w=g("Confirms "),$=r("strong"),I=g(K),te=g(" account verification request."),L=k(),ye(y.$$.fragment),Q=k(),T=r("h6"),T.textContent="API details",z=k(),C=r("div"),M=r("strong"),M.textContent="POST",le=k(),A=r("div"),B=r("p"),se=g("/api/collections/"),G=r("strong"),J=g(U),ae=g("/confirm-verification"),W=k(),R=r("div"),R.textContent="Body Parameters",X=k(),q=r("table"),q.innerHTML='<thead><tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr></thead> <tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>token</span></div></td> <td><span class="label">String</span></td> <td>The token from the verification request email.</td></tr></tbody>',Y=k(),O=r("div"),O.textContent="Responses",Z=k(),P=r("div"),E=r("div");for(let e=0;e<v.length;e+=1)v[e].c();ne=k(),N=r("div");for(let e=0;e<_.length;e+=1)_[e].c();h(l,"class","m-b-sm"),h(p,"class","content txt-lg m-b-sm"),h(T,"class","m-b-xs"),h(M,"class","label label-primary"),h(A,"class","content"),h(C,"class","alert alert-success"),h(R,"class","section-title"),h(q,"class","table-compact table-border m-b-base"),h(O,"class","section-title"),h(E,"class","tabs-header compact combined left"),h(N,"class","tabs-content"),h(P,"class","tabs")},m(e,t){f(e,l,t),n(l,s),n(l,b),n(l,m),f(e,i,t),f(e,p,t),n(p,u),n(u,w),n(u,$),n($,I),n(u,te),f(e,L,t),Ce(y,e,t),f(e,Q,t),f(e,T,t),f(e,z,t),f(e,C,t),n(C,M),n(C,le),n(C,A),n(A,B),n(B,se),n(B,G),n(G,J),n(B,ae),f(e,W,t),f(e,R,t),f(e,X,t),f(e,q,t),f(e,Y,t),f(e,O,t),f(e,Z,t),f(e,P,t),n(P,E);for(let c=0;c<v.length;c+=1)v[c]&&v[c].m(E,null);n(P,ne),n(P,N);for(let c=0;c<_.length;c+=1)_[c]&&_[c].m(N,null);S=!0},p(e,[t]){var me,he,be,_e;(!S||t&1)&&a!==(a=e[0].name+"")&&H(b,a),(!S||t&1)&&K!==(K=e[0].name+"")&&H(I,K);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(me=e[0])==null?void 0:me.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(he=e[0])==null?void 0:he.name}').authRefresh();
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(be=e[0])==null?void 0:be.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(_e=e[0])==null?void 0:_e.name}').authRefresh();
`),y.$set(c),(!S||t&1)&&U!==(U=e[0].name+"")&&H(J,U),t&6&&(j=D(e[2]),v=ke(v,t,ce,1,e,j,oe,E,Re,we,null,ge)),t&6&&(V=D(e[2]),qe(),_=ke(_,t,re,1,e,V,ie,N,Oe,$e,null,ve),Ee())},i(e){if(!S){x(y.$$.fragment,e);for(let t=0;t<V.length;t+=1)x(_[t]);S=!0}},o(e){ee(y.$$.fragment,e);for(let t=0;t<_.length;t+=1)ee(_[t]);S=!1},d(e){e&&(d(l),d(i),d(p),d(L),d(Q),d(T),d(z),d(C),d(W),d(R),d(X),d(q),d(Y),d(O),d(Z),d(P)),Pe(y,e);for(let t=0;t<v.length;t+=1)v[t].d();for(let t=0;t<_.length;t+=1)_[t].d()}}}function je(o,l,s){let a,{collection:b}=l,m=204,i=[];const p=u=>s(1,m=u.code);return o.$$set=u=>{"collection"in u&&s(0,b=u.collection)},s(3,a=Ne.getApiExampleUrl(Ve.baseUrl)),s(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[b,m,i,a,p]}class Fe extends Se{constructor(l){super(),Te(this,l,je,Ue,Be,{collection:0})}}export{Fe as default};
-62
View File
@@ -1,62 +0,0 @@
import{S as Pe,i as Te,s as Se,e as r,w,b as k,c as ge,f as b,g as f,h as i,m as ye,x as D,N as _e,P as Be,k as qe,Q as Re,n as Ee,t as Z,a as x,o as p,d as Ce,T as Me,C as Ne,p as Oe,r as H,u as Ve,M as Ke}from"./index-9e84ac8a.js";import{S as Ae}from"./SdkTabs-821a18db.js";function ke(a,l,s){const o=a.slice();return o[5]=l[s],o}function ve(a,l,s){const o=a.slice();return o[5]=l[s],o}function we(a,l){let s,o=l[5].code+"",h,d,n,u;function m(){return l[4](l[5])}return{key:a,first:null,c(){s=r("button"),h=w(o),d=k(),b(s,"class","tab-item"),H(s,"active",l[1]===l[5].code),this.first=s},m($,g){f($,s,g),i(s,h),i(s,d),n||(u=Ve(s,"click",m),n=!0)},p($,g){l=$,g&4&&o!==(o=l[5].code+"")&&D(h,o),g&6&&H(s,"active",l[1]===l[5].code)},d($){$&&p(s),n=!1,u()}}}function $e(a,l){let s,o,h,d;return o=new Ke({props:{content:l[5].body}}),{key:a,first:null,c(){s=r("div"),ge(o.$$.fragment),h=k(),b(s,"class","tab-item"),H(s,"active",l[1]===l[5].code),this.first=s},m(n,u){f(n,s,u),ye(o,s,null),i(s,h),d=!0},p(n,u){l=n;const m={};u&4&&(m.content=l[5].body),o.$set(m),(!d||u&6)&&H(s,"active",l[1]===l[5].code)},i(n){d||(Z(o.$$.fragment,n),d=!0)},o(n){x(o.$$.fragment,n),d=!1},d(n){n&&p(s),Ce(o)}}}function Ue(a){var re,fe,pe,ue;let l,s,o=a[0].name+"",h,d,n,u,m,$,g,V=a[0].name+"",F,ee,I,y,L,S,Q,C,K,te,A,B,le,z,U=a[0].name+"",G,se,J,q,W,R,X,E,Y,P,M,v=[],oe=new Map,ae,N,_=[],ie=new Map,T;y=new Ae({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${a[3]}');
...
await pb.collection('${(re=a[0])==null?void 0:re.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(fe=a[0])==null?void 0:fe.name}').authRefresh();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${a[3]}');
...
await pb.collection('${(pe=a[0])==null?void 0:pe.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(ue=a[0])==null?void 0:ue.name}').authRefresh();
`}});let j=a[2];const ne=e=>e[5].code;for(let e=0;e<j.length;e+=1){let t=ve(a,j,e),c=ne(t);oe.set(c,v[e]=we(c,t))}let O=a[2];const ce=e=>e[5].code;for(let e=0;e<O.length;e+=1){let t=ke(a,O,e),c=ce(t);ie.set(c,_[e]=$e(c,t))}return{c(){l=r("h3"),s=w("Confirm verification ("),h=w(o),d=w(")"),n=k(),u=r("div"),m=r("p"),$=w("Confirms "),g=r("strong"),F=w(V),ee=w(" account verification request."),I=k(),ge(y.$$.fragment),L=k(),S=r("h6"),S.textContent="API details",Q=k(),C=r("div"),K=r("strong"),K.textContent="POST",te=k(),A=r("div"),B=r("p"),le=w("/api/collections/"),z=r("strong"),G=w(U),se=w("/confirm-verification"),J=k(),q=r("div"),q.textContent="Body Parameters",W=k(),R=r("table"),R.innerHTML=`<thead><tr><th>Param</th>
<th>Type</th>
<th width="50%">Description</th></tr></thead>
<tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span>
<span>token</span></div></td>
<td><span class="label">String</span></td>
<td>The token from the verification request email.</td></tr></tbody>`,X=k(),E=r("div"),E.textContent="Responses",Y=k(),P=r("div"),M=r("div");for(let e=0;e<v.length;e+=1)v[e].c();ae=k(),N=r("div");for(let e=0;e<_.length;e+=1)_[e].c();b(l,"class","m-b-sm"),b(u,"class","content txt-lg m-b-sm"),b(S,"class","m-b-xs"),b(K,"class","label label-primary"),b(A,"class","content"),b(C,"class","alert alert-success"),b(q,"class","section-title"),b(R,"class","table-compact table-border m-b-base"),b(E,"class","section-title"),b(M,"class","tabs-header compact left"),b(N,"class","tabs-content"),b(P,"class","tabs")},m(e,t){f(e,l,t),i(l,s),i(l,h),i(l,d),f(e,n,t),f(e,u,t),i(u,m),i(m,$),i(m,g),i(g,F),i(m,ee),f(e,I,t),ye(y,e,t),f(e,L,t),f(e,S,t),f(e,Q,t),f(e,C,t),i(C,K),i(C,te),i(C,A),i(A,B),i(B,le),i(B,z),i(z,G),i(B,se),f(e,J,t),f(e,q,t),f(e,W,t),f(e,R,t),f(e,X,t),f(e,E,t),f(e,Y,t),f(e,P,t),i(P,M);for(let c=0;c<v.length;c+=1)v[c]&&v[c].m(M,null);i(P,ae),i(P,N);for(let c=0;c<_.length;c+=1)_[c]&&_[c].m(N,null);T=!0},p(e,[t]){var me,de,be,he;(!T||t&1)&&o!==(o=e[0].name+"")&&D(h,o),(!T||t&1)&&V!==(V=e[0].name+"")&&D(F,V);const c={};t&9&&(c.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(me=e[0])==null?void 0:me.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(de=e[0])==null?void 0:de.name}').authRefresh();
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(be=e[0])==null?void 0:be.name}').confirmVerification('TOKEN');
// optionally refresh the previous authStore state with the latest record changes
await pb.collection('${(he=e[0])==null?void 0:he.name}').authRefresh();
`),y.$set(c),(!T||t&1)&&U!==(U=e[0].name+"")&&D(G,U),t&6&&(j=e[2],v=_e(v,t,ne,1,e,j,oe,M,Be,we,null,ve)),t&6&&(O=e[2],qe(),_=_e(_,t,ce,1,e,O,ie,N,Re,$e,null,ke),Ee())},i(e){if(!T){Z(y.$$.fragment,e);for(let t=0;t<O.length;t+=1)Z(_[t]);T=!0}},o(e){x(y.$$.fragment,e);for(let t=0;t<_.length;t+=1)x(_[t]);T=!1},d(e){e&&p(l),e&&p(n),e&&p(u),e&&p(I),Ce(y,e),e&&p(L),e&&p(S),e&&p(Q),e&&p(C),e&&p(J),e&&p(q),e&&p(W),e&&p(R),e&&p(X),e&&p(E),e&&p(Y),e&&p(P);for(let t=0;t<v.length;t+=1)v[t].d();for(let t=0;t<_.length;t+=1)_[t].d()}}}function je(a,l,s){let o,{collection:h=new Me}=l,d=204,n=[];const u=m=>s(1,d=m.code);return a.$$set=m=>{"collection"in m&&s(0,h=m.collection)},s(3,o=Ne.getApiExampleUrl(Oe.baseUrl)),s(2,n=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[h,d,n,o,u]}class Fe extends Pe{constructor(l){super(),Te(this,l,je,Ue,Se,{collection:0})}}export{Fe as default};
+92
View File
@@ -0,0 +1,92 @@
import{S as qt,i as Ot,s as Mt,C as Q,O as ne,N as Tt,e as i,w as _,b as u,c as _e,f as v,g as r,h as n,m as he,x,P as Be,Q as ht,k as Ht,R as Lt,n as Pt,t as ue,a as fe,o as d,d as ke,p as Ft,r as ye,u as Rt,y as ae}from"./index-f26826b5.js";import{S as At}from"./SdkTabs-37a2d588.js";import{F as Bt}from"./FieldsQueryParam-e2795694.js";function kt(o,e,t){const a=o.slice();return a[8]=e[t],a}function yt(o,e,t){const a=o.slice();return a[8]=e[t],a}function vt(o,e,t){const a=o.slice();return a[13]=e[t],a}function gt(o){let e;return{c(){e=i("p"),e.innerHTML="Requires admin <code>Authorization:TOKEN</code> header",v(e,"class","txt-hint txt-sm txt-right")},m(t,a){r(t,e,a)},d(t){t&&d(e)}}}function wt(o){let e,t,a,f,m,c,p,y,S,T,w,H,D,E,P,I,j,B,$,N,q,g,b;function O(h,C){var ee,K;return(K=(ee=h[0])==null?void 0:ee.options)!=null&&K.requireEmail?Dt:jt}let z=O(o),F=z(o);return{c(){e=i("tr"),e.innerHTML='<td colspan="3" class="txt-hint">Auth fields</td>',t=u(),a=i("tr"),a.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span> <span>username</span></div></td> <td><span class="label">String</span></td> <td>The username of the auth record.
<br/>
If not set, it will be auto generated.</td>`,f=u(),m=i("tr"),c=i("td"),p=i("div"),F.c(),y=u(),S=i("span"),S.textContent="email",T=u(),w=i("td"),w.innerHTML='<span class="label">String</span>',H=u(),D=i("td"),D.textContent="Auth record email address.",E=u(),P=i("tr"),P.innerHTML='<td><div class="inline-flex"><span class="label label-warning">Optional</span> <span>emailVisibility</span></div></td> <td><span class="label">Boolean</span></td> <td>Whether to show/hide the auth record email when fetching the record data.</td>',I=u(),j=i("tr"),j.innerHTML='<td><div class="inline-flex"><span class="label label-success">Required</span> <span>password</span></div></td> <td><span class="label">String</span></td> <td>Auth record password.</td>',B=u(),$=i("tr"),$.innerHTML='<td><div class="inline-flex"><span class="label label-success">Required</span> <span>passwordConfirm</span></div></td> <td><span class="label">String</span></td> <td>Auth record password confirmation.</td>',N=u(),q=i("tr"),q.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span> <span>verified</span></div></td> <td><span class="label">Boolean</span></td> <td>Indicates whether the auth record is verified or not.
<br/>
This field can be set only by admins or auth records with &quot;Manage&quot; access.</td>`,g=u(),b=i("tr"),b.innerHTML='<td colspan="3" class="txt-hint">Schema fields</td>',v(p,"class","inline-flex")},m(h,C){r(h,e,C),r(h,t,C),r(h,a,C),r(h,f,C),r(h,m,C),n(m,c),n(c,p),F.m(p,null),n(p,y),n(p,S),n(m,T),n(m,w),n(m,H),n(m,D),r(h,E,C),r(h,P,C),r(h,I,C),r(h,j,C),r(h,B,C),r(h,$,C),r(h,N,C),r(h,q,C),r(h,g,C),r(h,b,C)},p(h,C){z!==(z=O(h))&&(F.d(1),F=z(h),F&&(F.c(),F.m(p,y)))},d(h){h&&(d(e),d(t),d(a),d(f),d(m),d(E),d(P),d(I),d(j),d(B),d($),d(N),d(q),d(g),d(b)),F.d()}}}function jt(o){let e;return{c(){e=i("span"),e.textContent="Optional",v(e,"class","label label-warning")},m(t,a){r(t,e,a)},d(t){t&&d(e)}}}function Dt(o){let e;return{c(){e=i("span"),e.textContent="Required",v(e,"class","label label-success")},m(t,a){r(t,e,a)},d(t){t&&d(e)}}}function Nt(o){let e;return{c(){e=i("span"),e.textContent="Optional",v(e,"class","label label-warning")},m(t,a){r(t,e,a)},d(t){t&&d(e)}}}function Vt(o){let e;return{c(){e=i("span"),e.textContent="Required",v(e,"class","label label-success")},m(t,a){r(t,e,a)},d(t){t&&d(e)}}}function Jt(o){var m;let e,t=((m=o[13].options)==null?void 0:m.maxSelect)===1?"id":"ids",a,f;return{c(){e=_("Relation record "),a=_(t),f=_(".")},m(c,p){r(c,e,p),r(c,a,p),r(c,f,p)},p(c,p){var y;p&1&&t!==(t=((y=c[13].options)==null?void 0:y.maxSelect)===1?"id":"ids")&&x(a,t)},d(c){c&&(d(e),d(a),d(f))}}}function Et(o){let e,t,a,f,m;return{c(){e=_("File object."),t=i("br"),a=_(`
Set to `),f=i("code"),f.textContent="null",m=_(" to delete already uploaded file(s).")},m(c,p){r(c,e,p),r(c,t,p),r(c,a,p),r(c,f,p),r(c,m,p)},p:ae,d(c){c&&(d(e),d(t),d(a),d(f),d(m))}}}function It(o){let e;return{c(){e=_("URL address.")},m(t,a){r(t,e,a)},p:ae,d(t){t&&d(e)}}}function Ut(o){let e;return{c(){e=_("Email address.")},m(t,a){r(t,e,a)},p:ae,d(t){t&&d(e)}}}function Qt(o){let e;return{c(){e=_("JSON array or object.")},m(t,a){r(t,e,a)},p:ae,d(t){t&&d(e)}}}function zt(o){let e;return{c(){e=_("Number value.")},m(t,a){r(t,e,a)},p:ae,d(t){t&&d(e)}}}function Kt(o){let e;return{c(){e=_("Plain text value.")},m(t,a){r(t,e,a)},p:ae,d(t){t&&d(e)}}}function $t(o,e){let t,a,f,m,c,p=e[13].name+"",y,S,T,w,H=Q.getFieldValueType(e[13])+"",D,E,P,I;function j(b,O){return b[13].required?Vt:Nt}let B=j(e),$=B(e);function N(b,O){if(b[13].type==="text")return Kt;if(b[13].type==="number")return zt;if(b[13].type==="json")return Qt;if(b[13].type==="email")return Ut;if(b[13].type==="url")return It;if(b[13].type==="file")return Et;if(b[13].type==="relation")return Jt}let q=N(e),g=q&&q(e);return{key:o,first:null,c(){t=i("tr"),a=i("td"),f=i("div"),$.c(),m=u(),c=i("span"),y=_(p),S=u(),T=i("td"),w=i("span"),D=_(H),E=u(),P=i("td"),g&&g.c(),I=u(),v(f,"class","inline-flex"),v(w,"class","label"),this.first=t},m(b,O){r(b,t,O),n(t,a),n(a,f),$.m(f,null),n(f,m),n(f,c),n(c,y),n(t,S),n(t,T),n(T,w),n(w,D),n(t,E),n(t,P),g&&g.m(P,null),n(t,I)},p(b,O){e=b,B!==(B=j(e))&&($.d(1),$=B(e),$&&($.c(),$.m(f,m))),O&1&&p!==(p=e[13].name+"")&&x(y,p),O&1&&H!==(H=Q.getFieldValueType(e[13])+"")&&x(D,H),q===(q=N(e))&&g?g.p(e,O):(g&&g.d(1),g=q&&q(e),g&&(g.c(),g.m(P,null)))},d(b){b&&d(t),$.d(),g&&g.d()}}}function Ct(o,e){let t,a=e[8].code+"",f,m,c,p;function y(){return e[7](e[8])}return{key:o,first:null,c(){t=i("button"),f=_(a),m=u(),v(t,"class","tab-item"),ye(t,"active",e[2]===e[8].code),this.first=t},m(S,T){r(S,t,T),n(t,f),n(t,m),c||(p=Rt(t,"click",y),c=!0)},p(S,T){e=S,T&8&&a!==(a=e[8].code+"")&&x(f,a),T&12&&ye(t,"active",e[2]===e[8].code)},d(S){S&&d(t),c=!1,p()}}}function St(o,e){let t,a,f,m;return a=new Tt({props:{content:e[8].body}}),{key:o,first:null,c(){t=i("div"),_e(a.$$.fragment),f=u(),v(t,"class","tab-item"),ye(t,"active",e[2]===e[8].code),this.first=t},m(c,p){r(c,t,p),he(a,t,null),n(t,f),m=!0},p(c,p){e=c;const y={};p&8&&(y.content=e[8].body),a.$set(y),(!m||p&12)&&ye(t,"active",e[2]===e[8].code)},i(c){m||(ue(a.$$.fragment,c),m=!0)},o(c){fe(a.$$.fragment,c),m=!1},d(c){c&&d(t),ke(a)}}}function Wt(o){var ot,rt,dt,ct,pt;let e,t,a=o[0].name+"",f,m,c,p,y,S,T,w=o[0].name+"",H,D,E,P,I,j,B,$,N,q,g,b,O,z,F,h,C,ee,K=o[0].name+"",ve,je,De,ge,se,we,W,$e,Ne,U,Ce,Ve,Se,V=[],Je=new Map,Te,ie,qe,Y,Oe,Ee,oe,G,Me,Ie,He,Ue,M,Qe,te,ze,Ke,We,Le,Ye,Pe,Ge,Xe,Ze,Fe,xe,et,le,Re,re,Ae,X,de,J=[],tt=new Map,lt,ce,R=[],nt=new Map,Z;$=new At({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[5]}');
...
// example create data
const data = ${JSON.stringify(Object.assign({},o[4],Q.dummyCollectionSchemaData(o[0])),null,4)};
const record = await pb.collection('${(ot=o[0])==null?void 0:ot.name}').create(data);
`+(o[1]?`
// (optional) send an email verification request
await pb.collection('${(rt=o[0])==null?void 0:rt.name}').requestVerification('test@example.com');
`:""),dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[5]}');
...
// example create body
final body = <String, dynamic>${JSON.stringify(Object.assign({},o[4],Q.dummyCollectionSchemaData(o[0])),null,2)};
final record = await pb.collection('${(dt=o[0])==null?void 0:dt.name}').create(body: body);
`+(o[1]?`
// (optional) send an email verification request
await pb.collection('${(ct=o[0])==null?void 0:ct.name}').requestVerification('test@example.com');
`:"")}});let A=o[6]&&gt(),L=o[1]&&wt(o),me=ne((pt=o[0])==null?void 0:pt.schema);const at=l=>l[13].name;for(let l=0;l<me.length;l+=1){let s=vt(o,me,l),k=at(s);Je.set(k,V[l]=$t(k,s))}te=new Tt({props:{content:"?expand=relField1,relField2.subRelField"}}),le=new Bt({});let be=ne(o[3]);const st=l=>l[8].code;for(let l=0;l<be.length;l+=1){let s=yt(o,be,l),k=st(s);tt.set(k,J[l]=Ct(k,s))}let pe=ne(o[3]);const it=l=>l[8].code;for(let l=0;l<pe.length;l+=1){let s=kt(o,pe,l),k=it(s);nt.set(k,R[l]=St(k,s))}return{c(){e=i("h3"),t=_("Create ("),f=_(a),m=_(")"),c=u(),p=i("div"),y=i("p"),S=_("Create a new "),T=i("strong"),H=_(w),D=_(" record."),E=u(),P=i("p"),P.innerHTML=`Body parameters could be sent as <code>application/json</code> or
<code>multipart/form-data</code>.`,I=u(),j=i("p"),j.innerHTML=`File upload is supported only via <code>multipart/form-data</code>.
<br/>
For more info and examples you could check the detailed
<a href="https://pocketbase.io/docs/files-handling/" target="_blank" rel="noopener noreferrer">Files upload and handling docs
</a>.`,B=u(),_e($.$$.fragment),N=u(),q=i("h6"),q.textContent="API details",g=u(),b=i("div"),O=i("strong"),O.textContent="POST",z=u(),F=i("div"),h=i("p"),C=_("/api/collections/"),ee=i("strong"),ve=_(K),je=_("/records"),De=u(),A&&A.c(),ge=u(),se=i("div"),se.textContent="Body Parameters",we=u(),W=i("table"),$e=i("thead"),$e.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',Ne=u(),U=i("tbody"),Ce=i("tr"),Ce.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span> <span>id</span></div></td> <td><span class="label">String</span></td> <td><strong>15 characters string</strong> to store as record ID.
<br/>
If not set, it will be auto generated.</td>`,Ve=u(),L&&L.c(),Se=u();for(let l=0;l<V.length;l+=1)V[l].c();Te=u(),ie=i("div"),ie.textContent="Query parameters",qe=u(),Y=i("table"),Oe=i("thead"),Oe.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',Ee=u(),oe=i("tbody"),G=i("tr"),Me=i("td"),Me.textContent="expand",Ie=u(),He=i("td"),He.innerHTML='<span class="label">String</span>',Ue=u(),M=i("td"),Qe=_(`Auto expand relations when returning the created record. Ex.:
`),_e(te.$$.fragment),ze=_(`
Supports up to 6-levels depth nested relations expansion. `),Ke=i("br"),We=_(`
The expanded relations will be appended to the record under the
`),Le=i("code"),Le.textContent="expand",Ye=_(" property (eg. "),Pe=i("code"),Pe.textContent='"expand": {"relField1": {...}, ...}',Ge=_(`).
`),Xe=i("br"),Ze=_(`
Only the relations to which the request user has permissions to `),Fe=i("strong"),Fe.textContent="view",xe=_(" will be expanded."),et=u(),_e(le.$$.fragment),Re=u(),re=i("div"),re.textContent="Responses",Ae=u(),X=i("div"),de=i("div");for(let l=0;l<J.length;l+=1)J[l].c();lt=u(),ce=i("div");for(let l=0;l<R.length;l+=1)R[l].c();v(e,"class","m-b-sm"),v(p,"class","content txt-lg m-b-sm"),v(q,"class","m-b-xs"),v(O,"class","label label-primary"),v(F,"class","content"),v(b,"class","alert alert-success"),v(se,"class","section-title"),v(W,"class","table-compact table-border m-b-base"),v(ie,"class","section-title"),v(Y,"class","table-compact table-border m-b-base"),v(re,"class","section-title"),v(de,"class","tabs-header compact combined left"),v(ce,"class","tabs-content"),v(X,"class","tabs")},m(l,s){r(l,e,s),n(e,t),n(e,f),n(e,m),r(l,c,s),r(l,p,s),n(p,y),n(y,S),n(y,T),n(T,H),n(y,D),n(p,E),n(p,P),n(p,I),n(p,j),r(l,B,s),he($,l,s),r(l,N,s),r(l,q,s),r(l,g,s),r(l,b,s),n(b,O),n(b,z),n(b,F),n(F,h),n(h,C),n(h,ee),n(ee,ve),n(h,je),n(b,De),A&&A.m(b,null),r(l,ge,s),r(l,se,s),r(l,we,s),r(l,W,s),n(W,$e),n(W,Ne),n(W,U),n(U,Ce),n(U,Ve),L&&L.m(U,null),n(U,Se);for(let k=0;k<V.length;k+=1)V[k]&&V[k].m(U,null);r(l,Te,s),r(l,ie,s),r(l,qe,s),r(l,Y,s),n(Y,Oe),n(Y,Ee),n(Y,oe),n(oe,G),n(G,Me),n(G,Ie),n(G,He),n(G,Ue),n(G,M),n(M,Qe),he(te,M,null),n(M,ze),n(M,Ke),n(M,We),n(M,Le),n(M,Ye),n(M,Pe),n(M,Ge),n(M,Xe),n(M,Ze),n(M,Fe),n(M,xe),n(oe,et),he(le,oe,null),r(l,Re,s),r(l,re,s),r(l,Ae,s),r(l,X,s),n(X,de);for(let k=0;k<J.length;k+=1)J[k]&&J[k].m(de,null);n(X,lt),n(X,ce);for(let k=0;k<R.length;k+=1)R[k]&&R[k].m(ce,null);Z=!0},p(l,[s]){var ut,ft,mt,bt,_t;(!Z||s&1)&&a!==(a=l[0].name+"")&&x(f,a),(!Z||s&1)&&w!==(w=l[0].name+"")&&x(H,w);const k={};s&51&&(k.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${l[5]}');
...
// example create data
const data = ${JSON.stringify(Object.assign({},l[4],Q.dummyCollectionSchemaData(l[0])),null,4)};
const record = await pb.collection('${(ut=l[0])==null?void 0:ut.name}').create(data);
`+(l[1]?`
// (optional) send an email verification request
await pb.collection('${(ft=l[0])==null?void 0:ft.name}').requestVerification('test@example.com');
`:"")),s&51&&(k.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${l[5]}');
...
// example create body
final body = <String, dynamic>${JSON.stringify(Object.assign({},l[4],Q.dummyCollectionSchemaData(l[0])),null,2)};
final record = await pb.collection('${(mt=l[0])==null?void 0:mt.name}').create(body: body);
`+(l[1]?`
// (optional) send an email verification request
await pb.collection('${(bt=l[0])==null?void 0:bt.name}').requestVerification('test@example.com');
`:"")),$.$set(k),(!Z||s&1)&&K!==(K=l[0].name+"")&&x(ve,K),l[6]?A||(A=gt(),A.c(),A.m(b,null)):A&&(A.d(1),A=null),l[1]?L?L.p(l,s):(L=wt(l),L.c(),L.m(U,Se)):L&&(L.d(1),L=null),s&1&&(me=ne((_t=l[0])==null?void 0:_t.schema),V=Be(V,s,at,1,l,me,Je,U,ht,$t,null,vt)),s&12&&(be=ne(l[3]),J=Be(J,s,st,1,l,be,tt,de,ht,Ct,null,yt)),s&12&&(pe=ne(l[3]),Ht(),R=Be(R,s,it,1,l,pe,nt,ce,Lt,St,null,kt),Pt())},i(l){if(!Z){ue($.$$.fragment,l),ue(te.$$.fragment,l),ue(le.$$.fragment,l);for(let s=0;s<pe.length;s+=1)ue(R[s]);Z=!0}},o(l){fe($.$$.fragment,l),fe(te.$$.fragment,l),fe(le.$$.fragment,l);for(let s=0;s<R.length;s+=1)fe(R[s]);Z=!1},d(l){l&&(d(e),d(c),d(p),d(B),d(N),d(q),d(g),d(b),d(ge),d(se),d(we),d(W),d(Te),d(ie),d(qe),d(Y),d(Re),d(re),d(Ae),d(X)),ke($,l),A&&A.d(),L&&L.d();for(let s=0;s<V.length;s+=1)V[s].d();ke(te),ke(le);for(let s=0;s<J.length;s+=1)J[s].d();for(let s=0;s<R.length;s+=1)R[s].d()}}}function Yt(o,e,t){let a,f,m,{collection:c}=e,p=200,y=[],S={};const T=w=>t(2,p=w.code);return o.$$set=w=>{"collection"in w&&t(0,c=w.collection)},o.$$.update=()=>{var w,H;o.$$.dirty&1&&t(1,a=c.type==="auth"),o.$$.dirty&1&&t(6,f=(c==null?void 0:c.createRule)===null),o.$$.dirty&1&&t(3,y=[{code:200,body:JSON.stringify(Q.dummyCollectionRecord(c),null,2)},{code:400,body:`
{
"code": 400,
"message": "Failed to create record.",
"data": {
"${(H=(w=c==null?void 0:c.schema)==null?void 0:w[0])==null?void 0:H.name}": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`},{code:403,body:`
{
"code": 403,
"message": "You are not allowed to perform this request.",
"data": {}
}
`}]),o.$$.dirty&2&&(a?t(4,S={username:"test_username",email:"test@example.com",emailVisibility:!0,password:"12345678",passwordConfirm:"12345678"}):t(4,S={}))},t(5,m=Q.getApiExampleUrl(Ft.baseUrl)),[c,a,p,y,S,m,f,T]}class xt extends qt{constructor(e){super(),Ot(this,e,Yt,Wt,Mt,{collection:0})}}export{xt as default};
-114
View File
@@ -1,114 +0,0 @@
import{S as Pt,i as gt,s as Ft,C as Q,M as Lt,e as a,w as k,b as m,c as be,f as h,g as r,h as n,m as _e,x,N as Be,P as $t,k as Bt,Q as Rt,n as jt,t as fe,a as pe,o as d,d as ke,T as Dt,p as Nt,r as ye,u as Vt,y as ne}from"./index-9e84ac8a.js";import{S as Jt}from"./SdkTabs-821a18db.js";import{F as Et}from"./FieldsQueryParam-664da4c8.js";function Ct(o,e,l){const s=o.slice();return s[7]=e[l],s}function St(o,e,l){const s=o.slice();return s[7]=e[l],s}function Tt(o,e,l){const s=o.slice();return s[12]=e[l],s}function qt(o){let e;return{c(){e=a("p"),e.innerHTML="Requires admin <code>Authorization:TOKEN</code> header",h(e,"class","txt-hint txt-sm txt-right")},m(l,s){r(l,e,s)},d(l){l&&d(e)}}}function Mt(o){let e,l,s,b,p,c,f,v,T,w,M,R,D,E,L,I,j,B,C,N,q,$,_;function O(u,S){var ee,K;return(K=(ee=u[0])==null?void 0:ee.options)!=null&&K.requireEmail?Ut:It}let z=O(o),P=z(o);return{c(){e=a("tr"),e.innerHTML='<td colspan="3" class="txt-hint">Auth fields</td>',l=m(),s=a("tr"),s.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span>
<span>username</span></div></td>
<td><span class="label">String</span></td>
<td>The username of the auth record.
<br/>
If not set, it will be auto generated.</td>`,b=m(),p=a("tr"),c=a("td"),f=a("div"),P.c(),v=m(),T=a("span"),T.textContent="email",w=m(),M=a("td"),M.innerHTML='<span class="label">String</span>',R=m(),D=a("td"),D.textContent="Auth record email address.",E=m(),L=a("tr"),L.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span>
<span>emailVisibility</span></div></td>
<td><span class="label">Boolean</span></td>
<td>Whether to show/hide the auth record email when fetching the record data.</td>`,I=m(),j=a("tr"),j.innerHTML=`<td><div class="inline-flex"><span class="label label-success">Required</span>
<span>password</span></div></td>
<td><span class="label">String</span></td>
<td>Auth record password.</td>`,B=m(),C=a("tr"),C.innerHTML=`<td><div class="inline-flex"><span class="label label-success">Required</span>
<span>passwordConfirm</span></div></td>
<td><span class="label">String</span></td>
<td>Auth record password confirmation.</td>`,N=m(),q=a("tr"),q.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span>
<span>verified</span></div></td>
<td><span class="label">Boolean</span></td>
<td>Indicates whether the auth record is verified or not.
<br/>
This field can be set only by admins or auth records with &quot;Manage&quot; access.</td>`,$=m(),_=a("tr"),_.innerHTML='<td colspan="3" class="txt-hint">Schema fields</td>',h(f,"class","inline-flex")},m(u,S){r(u,e,S),r(u,l,S),r(u,s,S),r(u,b,S),r(u,p,S),n(p,c),n(c,f),P.m(f,null),n(f,v),n(f,T),n(p,w),n(p,M),n(p,R),n(p,D),r(u,E,S),r(u,L,S),r(u,I,S),r(u,j,S),r(u,B,S),r(u,C,S),r(u,N,S),r(u,q,S),r(u,$,S),r(u,_,S)},p(u,S){z!==(z=O(u))&&(P.d(1),P=z(u),P&&(P.c(),P.m(f,v)))},d(u){u&&d(e),u&&d(l),u&&d(s),u&&d(b),u&&d(p),P.d(),u&&d(E),u&&d(L),u&&d(I),u&&d(j),u&&d(B),u&&d(C),u&&d(N),u&&d(q),u&&d($),u&&d(_)}}}function It(o){let e;return{c(){e=a("span"),e.textContent="Optional",h(e,"class","label label-warning")},m(l,s){r(l,e,s)},d(l){l&&d(e)}}}function Ut(o){let e;return{c(){e=a("span"),e.textContent="Required",h(e,"class","label label-success")},m(l,s){r(l,e,s)},d(l){l&&d(e)}}}function Qt(o){let e;return{c(){e=a("span"),e.textContent="Optional",h(e,"class","label label-warning")},m(l,s){r(l,e,s)},d(l){l&&d(e)}}}function zt(o){let e;return{c(){e=a("span"),e.textContent="Required",h(e,"class","label label-success")},m(l,s){r(l,e,s)},d(l){l&&d(e)}}}function Kt(o){var p;let e,l=((p=o[12].options)==null?void 0:p.maxSelect)===1?"id":"ids",s,b;return{c(){e=k("Relation record "),s=k(l),b=k(".")},m(c,f){r(c,e,f),r(c,s,f),r(c,b,f)},p(c,f){var v;f&1&&l!==(l=((v=c[12].options)==null?void 0:v.maxSelect)===1?"id":"ids")&&x(s,l)},d(c){c&&d(e),c&&d(s),c&&d(b)}}}function Wt(o){let e,l,s,b,p;return{c(){e=k("File object."),l=a("br"),s=k(`
Set to `),b=a("code"),b.textContent="null",p=k(" to delete already uploaded file(s).")},m(c,f){r(c,e,f),r(c,l,f),r(c,s,f),r(c,b,f),r(c,p,f)},p:ne,d(c){c&&d(e),c&&d(l),c&&d(s),c&&d(b),c&&d(p)}}}function Yt(o){let e;return{c(){e=k("URL address.")},m(l,s){r(l,e,s)},p:ne,d(l){l&&d(e)}}}function Gt(o){let e;return{c(){e=k("Email address.")},m(l,s){r(l,e,s)},p:ne,d(l){l&&d(e)}}}function Xt(o){let e;return{c(){e=k("JSON array or object.")},m(l,s){r(l,e,s)},p:ne,d(l){l&&d(e)}}}function Zt(o){let e;return{c(){e=k("Number value.")},m(l,s){r(l,e,s)},p:ne,d(l){l&&d(e)}}}function xt(o){let e;return{c(){e=k("Plain text value.")},m(l,s){r(l,e,s)},p:ne,d(l){l&&d(e)}}}function Ot(o,e){let l,s,b,p,c,f=e[12].name+"",v,T,w,M,R=Q.getFieldValueType(e[12])+"",D,E,L,I;function j(_,O){return _[12].required?zt:Qt}let B=j(e),C=B(e);function N(_,O){if(_[12].type==="text")return xt;if(_[12].type==="number")return Zt;if(_[12].type==="json")return Xt;if(_[12].type==="email")return Gt;if(_[12].type==="url")return Yt;if(_[12].type==="file")return Wt;if(_[12].type==="relation")return Kt}let q=N(e),$=q&&q(e);return{key:o,first:null,c(){l=a("tr"),s=a("td"),b=a("div"),C.c(),p=m(),c=a("span"),v=k(f),T=m(),w=a("td"),M=a("span"),D=k(R),E=m(),L=a("td"),$&&$.c(),I=m(),h(b,"class","inline-flex"),h(M,"class","label"),this.first=l},m(_,O){r(_,l,O),n(l,s),n(s,b),C.m(b,null),n(b,p),n(b,c),n(c,v),n(l,T),n(l,w),n(w,M),n(M,D),n(l,E),n(l,L),$&&$.m(L,null),n(l,I)},p(_,O){e=_,B!==(B=j(e))&&(C.d(1),C=B(e),C&&(C.c(),C.m(b,p))),O&1&&f!==(f=e[12].name+"")&&x(v,f),O&1&&R!==(R=Q.getFieldValueType(e[12])+"")&&x(D,R),q===(q=N(e))&&$?$.p(e,O):($&&$.d(1),$=q&&q(e),$&&($.c(),$.m(L,null)))},d(_){_&&d(l),C.d(),$&&$.d()}}}function At(o,e){let l,s=e[7].code+"",b,p,c,f;function v(){return e[6](e[7])}return{key:o,first:null,c(){l=a("button"),b=k(s),p=m(),h(l,"class","tab-item"),ye(l,"active",e[1]===e[7].code),this.first=l},m(T,w){r(T,l,w),n(l,b),n(l,p),c||(f=Vt(l,"click",v),c=!0)},p(T,w){e=T,w&4&&s!==(s=e[7].code+"")&&x(b,s),w&6&&ye(l,"active",e[1]===e[7].code)},d(T){T&&d(l),c=!1,f()}}}function Ht(o,e){let l,s,b,p;return s=new Lt({props:{content:e[7].body}}),{key:o,first:null,c(){l=a("div"),be(s.$$.fragment),b=m(),h(l,"class","tab-item"),ye(l,"active",e[1]===e[7].code),this.first=l},m(c,f){r(c,l,f),_e(s,l,null),n(l,b),p=!0},p(c,f){e=c;const v={};f&4&&(v.content=e[7].body),s.$set(v),(!p||f&6)&&ye(l,"active",e[1]===e[7].code)},i(c){p||(fe(s.$$.fragment,c),p=!0)},o(c){pe(s.$$.fragment,c),p=!1},d(c){c&&d(l),ke(s)}}}function el(o){var at,ot,rt,dt,ct,ft,pt,ut;let e,l,s=o[0].name+"",b,p,c,f,v,T,w,M=o[0].name+"",R,D,E,L,I,j,B,C,N,q,$,_,O,z,P,u,S,ee,K=o[0].name+"",ve,Re,je,he,se,we,W,$e,De,U,Ce,Ne,Se,V=[],Ve=new Map,Te,ie,qe,Y,Me,Je,ae,G,Oe,Ee,Ae,Ie,A,Ue,te,Qe,ze,Ke,He,We,Le,Ye,Ge,Xe,Pe,Ze,xe,le,ge,oe,Fe,X,re,J=[],et=new Map,tt,de,g=[],lt=new Map,Z;C=new Jt({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[4]}');
...
// example create data
const data = ${JSON.stringify(Object.assign({},o[3],Q.dummyCollectionSchemaData(o[0])),null,4)};
const record = await pb.collection('${(at=o[0])==null?void 0:at.name}').create(data);
`+((ot=o[0])!=null&&ot.isAuth?`
// (optional) send an email verification request
await pb.collection('${(rt=o[0])==null?void 0:rt.name}').requestVerification('test@example.com');
`:""),dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[4]}');
...
// example create body
final body = <String, dynamic>${JSON.stringify(Object.assign({},o[3],Q.dummyCollectionSchemaData(o[0])),null,2)};
final record = await pb.collection('${(dt=o[0])==null?void 0:dt.name}').create(body: body);
`+((ct=o[0])!=null&&ct.isAuth?`
// (optional) send an email verification request
await pb.collection('${(ft=o[0])==null?void 0:ft.name}').requestVerification('test@example.com');
`:"")}});let F=o[5]&&qt(),H=((pt=o[0])==null?void 0:pt.isAuth)&&Mt(o),ue=(ut=o[0])==null?void 0:ut.schema;const nt=t=>t[12].name;for(let t=0;t<ue.length;t+=1){let i=Tt(o,ue,t),y=nt(i);Ve.set(y,V[t]=Ot(y,i))}te=new Lt({props:{content:"?expand=relField1,relField2.subRelField"}}),le=new Et({});let me=o[2];const st=t=>t[7].code;for(let t=0;t<me.length;t+=1){let i=St(o,me,t),y=st(i);et.set(y,J[t]=At(y,i))}let ce=o[2];const it=t=>t[7].code;for(let t=0;t<ce.length;t+=1){let i=Ct(o,ce,t),y=it(i);lt.set(y,g[t]=Ht(y,i))}return{c(){e=a("h3"),l=k("Create ("),b=k(s),p=k(")"),c=m(),f=a("div"),v=a("p"),T=k("Create a new "),w=a("strong"),R=k(M),D=k(" record."),E=m(),L=a("p"),L.innerHTML=`Body parameters could be sent as <code>application/json</code> or
<code>multipart/form-data</code>.`,I=m(),j=a("p"),j.innerHTML=`File upload is supported only via <code>multipart/form-data</code>.
<br/>
For more info and examples you could check the detailed
<a href="https://pocketbase.io/docs/files-handling/" target="_blank" rel="noopener noreferrer">Files upload and handling docs
</a>.`,B=m(),be(C.$$.fragment),N=m(),q=a("h6"),q.textContent="API details",$=m(),_=a("div"),O=a("strong"),O.textContent="POST",z=m(),P=a("div"),u=a("p"),S=k("/api/collections/"),ee=a("strong"),ve=k(K),Re=k("/records"),je=m(),F&&F.c(),he=m(),se=a("div"),se.textContent="Body Parameters",we=m(),W=a("table"),$e=a("thead"),$e.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="50%">Description</th></tr>`,De=m(),U=a("tbody"),Ce=a("tr"),Ce.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span>
<span>id</span></div></td>
<td><span class="label">String</span></td>
<td><strong>15 characters string</strong> to store as record ID.
<br/>
If not set, it will be auto generated.</td>`,Ne=m(),H&&H.c(),Se=m();for(let t=0;t<V.length;t+=1)V[t].c();Te=m(),ie=a("div"),ie.textContent="Query parameters",qe=m(),Y=a("table"),Me=a("thead"),Me.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="60%">Description</th></tr>`,Je=m(),ae=a("tbody"),G=a("tr"),Oe=a("td"),Oe.textContent="expand",Ee=m(),Ae=a("td"),Ae.innerHTML='<span class="label">String</span>',Ie=m(),A=a("td"),Ue=k(`Auto expand relations when returning the created record. Ex.:
`),be(te.$$.fragment),Qe=k(`
Supports up to 6-levels depth nested relations expansion. `),ze=a("br"),Ke=k(`
The expanded relations will be appended to the record under the
`),He=a("code"),He.textContent="expand",We=k(" property (eg. "),Le=a("code"),Le.textContent='"expand": {"relField1": {...}, ...}',Ye=k(`).
`),Ge=a("br"),Xe=k(`
Only the relations to which the request user has permissions to `),Pe=a("strong"),Pe.textContent="view",Ze=k(" will be expanded."),xe=m(),be(le.$$.fragment),ge=m(),oe=a("div"),oe.textContent="Responses",Fe=m(),X=a("div"),re=a("div");for(let t=0;t<J.length;t+=1)J[t].c();tt=m(),de=a("div");for(let t=0;t<g.length;t+=1)g[t].c();h(e,"class","m-b-sm"),h(f,"class","content txt-lg m-b-sm"),h(q,"class","m-b-xs"),h(O,"class","label label-primary"),h(P,"class","content"),h(_,"class","alert alert-success"),h(se,"class","section-title"),h(W,"class","table-compact table-border m-b-base"),h(ie,"class","section-title"),h(Y,"class","table-compact table-border m-b-base"),h(oe,"class","section-title"),h(re,"class","tabs-header compact left"),h(de,"class","tabs-content"),h(X,"class","tabs")},m(t,i){r(t,e,i),n(e,l),n(e,b),n(e,p),r(t,c,i),r(t,f,i),n(f,v),n(v,T),n(v,w),n(w,R),n(v,D),n(f,E),n(f,L),n(f,I),n(f,j),r(t,B,i),_e(C,t,i),r(t,N,i),r(t,q,i),r(t,$,i),r(t,_,i),n(_,O),n(_,z),n(_,P),n(P,u),n(u,S),n(u,ee),n(ee,ve),n(u,Re),n(_,je),F&&F.m(_,null),r(t,he,i),r(t,se,i),r(t,we,i),r(t,W,i),n(W,$e),n(W,De),n(W,U),n(U,Ce),n(U,Ne),H&&H.m(U,null),n(U,Se);for(let y=0;y<V.length;y+=1)V[y]&&V[y].m(U,null);r(t,Te,i),r(t,ie,i),r(t,qe,i),r(t,Y,i),n(Y,Me),n(Y,Je),n(Y,ae),n(ae,G),n(G,Oe),n(G,Ee),n(G,Ae),n(G,Ie),n(G,A),n(A,Ue),_e(te,A,null),n(A,Qe),n(A,ze),n(A,Ke),n(A,He),n(A,We),n(A,Le),n(A,Ye),n(A,Ge),n(A,Xe),n(A,Pe),n(A,Ze),n(ae,xe),_e(le,ae,null),r(t,ge,i),r(t,oe,i),r(t,Fe,i),r(t,X,i),n(X,re);for(let y=0;y<J.length;y+=1)J[y]&&J[y].m(re,null);n(X,tt),n(X,de);for(let y=0;y<g.length;y+=1)g[y]&&g[y].m(de,null);Z=!0},p(t,[i]){var mt,bt,_t,kt,yt,vt,ht,wt;(!Z||i&1)&&s!==(s=t[0].name+"")&&x(b,s),(!Z||i&1)&&M!==(M=t[0].name+"")&&x(R,M);const y={};i&25&&(y.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${t[4]}');
...
// example create data
const data = ${JSON.stringify(Object.assign({},t[3],Q.dummyCollectionSchemaData(t[0])),null,4)};
const record = await pb.collection('${(mt=t[0])==null?void 0:mt.name}').create(data);
`+((bt=t[0])!=null&&bt.isAuth?`
// (optional) send an email verification request
await pb.collection('${(_t=t[0])==null?void 0:_t.name}').requestVerification('test@example.com');
`:"")),i&25&&(y.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${t[4]}');
...
// example create body
final body = <String, dynamic>${JSON.stringify(Object.assign({},t[3],Q.dummyCollectionSchemaData(t[0])),null,2)};
final record = await pb.collection('${(kt=t[0])==null?void 0:kt.name}').create(body: body);
`+((yt=t[0])!=null&&yt.isAuth?`
// (optional) send an email verification request
await pb.collection('${(vt=t[0])==null?void 0:vt.name}').requestVerification('test@example.com');
`:"")),C.$set(y),(!Z||i&1)&&K!==(K=t[0].name+"")&&x(ve,K),t[5]?F||(F=qt(),F.c(),F.m(_,null)):F&&(F.d(1),F=null),(ht=t[0])!=null&&ht.isAuth?H?H.p(t,i):(H=Mt(t),H.c(),H.m(U,Se)):H&&(H.d(1),H=null),i&1&&(ue=(wt=t[0])==null?void 0:wt.schema,V=Be(V,i,nt,1,t,ue,Ve,U,$t,Ot,null,Tt)),i&6&&(me=t[2],J=Be(J,i,st,1,t,me,et,re,$t,At,null,St)),i&6&&(ce=t[2],Bt(),g=Be(g,i,it,1,t,ce,lt,de,Rt,Ht,null,Ct),jt())},i(t){if(!Z){fe(C.$$.fragment,t),fe(te.$$.fragment,t),fe(le.$$.fragment,t);for(let i=0;i<ce.length;i+=1)fe(g[i]);Z=!0}},o(t){pe(C.$$.fragment,t),pe(te.$$.fragment,t),pe(le.$$.fragment,t);for(let i=0;i<g.length;i+=1)pe(g[i]);Z=!1},d(t){t&&d(e),t&&d(c),t&&d(f),t&&d(B),ke(C,t),t&&d(N),t&&d(q),t&&d($),t&&d(_),F&&F.d(),t&&d(he),t&&d(se),t&&d(we),t&&d(W),H&&H.d();for(let i=0;i<V.length;i+=1)V[i].d();t&&d(Te),t&&d(ie),t&&d(qe),t&&d(Y),ke(te),ke(le),t&&d(ge),t&&d(oe),t&&d(Fe),t&&d(X);for(let i=0;i<J.length;i+=1)J[i].d();for(let i=0;i<g.length;i+=1)g[i].d()}}}function tl(o,e,l){let s,b,{collection:p=new Dt}=e,c=200,f=[],v={};const T=w=>l(1,c=w.code);return o.$$set=w=>{"collection"in w&&l(0,p=w.collection)},o.$$.update=()=>{var w,M;o.$$.dirty&1&&l(5,s=(p==null?void 0:p.createRule)===null),o.$$.dirty&1&&l(2,f=[{code:200,body:JSON.stringify(Q.dummyCollectionRecord(p),null,2)},{code:400,body:`
{
"code": 400,
"message": "Failed to create record.",
"data": {
"${(M=(w=p==null?void 0:p.schema)==null?void 0:w[0])==null?void 0:M.name}": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`},{code:403,body:`
{
"code": 403,
"message": "You are not allowed to perform this request.",
"data": {}
}
`}]),o.$$.dirty&1&&(p.$isAuth?l(3,v={username:"test_username",email:"test@example.com",emailVisibility:!0,password:"12345678",passwordConfirm:"12345678"}):l(3,v={}))},l(4,b=Q.getApiExampleUrl(Nt.baseUrl)),[p,c,f,v,b,s,T]}class il extends Pt{constructor(e){super(),gt(this,e,tl,el,Ft,{collection:0})}}export{il as default};
+53
View File
@@ -0,0 +1,53 @@
import{S as Re,i as Pe,s as Ee,O as j,e as c,w as y,b as k,c as De,f as m,g as p,h as i,m as Ce,x as ee,P as he,Q as Oe,k as Te,R as Be,n as Ie,t as te,a as le,o as u,d as we,C as Ae,p as Me,r as N,u as Se,N as qe}from"./index-f26826b5.js";import{S as He}from"./SdkTabs-37a2d588.js";function ke(a,l,s){const o=a.slice();return o[6]=l[s],o}function ge(a,l,s){const o=a.slice();return o[6]=l[s],o}function ve(a){let l;return{c(){l=c("p"),l.innerHTML="Requires admin <code>Authorization:TOKEN</code> header",m(l,"class","txt-hint txt-sm txt-right")},m(s,o){p(s,l,o)},d(s){s&&u(l)}}}function ye(a,l){let s,o,h;function d(){return l[5](l[6])}return{key:a,first:null,c(){s=c("button"),s.textContent=`${l[6].code} `,m(s,"class","tab-item"),N(s,"active",l[2]===l[6].code),this.first=s},m(n,r){p(n,s,r),o||(h=Se(s,"click",d),o=!0)},p(n,r){l=n,r&20&&N(s,"active",l[2]===l[6].code)},d(n){n&&u(s),o=!1,h()}}}function $e(a,l){let s,o,h,d;return o=new qe({props:{content:l[6].body}}),{key:a,first:null,c(){s=c("div"),De(o.$$.fragment),h=k(),m(s,"class","tab-item"),N(s,"active",l[2]===l[6].code),this.first=s},m(n,r){p(n,s,r),Ce(o,s,null),i(s,h),d=!0},p(n,r){l=n,(!d||r&20)&&N(s,"active",l[2]===l[6].code)},i(n){d||(te(o.$$.fragment,n),d=!0)},o(n){le(o.$$.fragment,n),d=!1},d(n){n&&u(s),we(o)}}}function Le(a){var ue,me;let l,s,o=a[0].name+"",h,d,n,r,$,D,z,S=a[0].name+"",F,se,K,C,Q,E,G,g,q,ae,H,P,oe,J,L=a[0].name+"",V,ne,W,ie,X,O,Y,T,Z,B,x,w,I,v=[],ce=new Map,de,A,b=[],re=new Map,R;C=new He({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${a[3]}');
...
await pb.collection('${(ue=a[0])==null?void 0:ue.name}').delete('RECORD_ID');
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${a[3]}');
...
await pb.collection('${(me=a[0])==null?void 0:me.name}').delete('RECORD_ID');
`}});let _=a[1]&&ve(),U=j(a[4]);const fe=e=>e[6].code;for(let e=0;e<U.length;e+=1){let t=ge(a,U,e),f=fe(t);ce.set(f,v[e]=ye(f,t))}let M=j(a[4]);const pe=e=>e[6].code;for(let e=0;e<M.length;e+=1){let t=ke(a,M,e),f=pe(t);re.set(f,b[e]=$e(f,t))}return{c(){l=c("h3"),s=y("Delete ("),h=y(o),d=y(")"),n=k(),r=c("div"),$=c("p"),D=y("Delete a single "),z=c("strong"),F=y(S),se=y(" record."),K=k(),De(C.$$.fragment),Q=k(),E=c("h6"),E.textContent="API details",G=k(),g=c("div"),q=c("strong"),q.textContent="DELETE",ae=k(),H=c("div"),P=c("p"),oe=y("/api/collections/"),J=c("strong"),V=y(L),ne=y("/records/"),W=c("strong"),W.textContent=":id",ie=k(),_&&_.c(),X=k(),O=c("div"),O.textContent="Path parameters",Y=k(),T=c("table"),T.innerHTML='<thead><tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr></thead> <tbody><tr><td>id</td> <td><span class="label">String</span></td> <td>ID of the record to delete.</td></tr></tbody>',Z=k(),B=c("div"),B.textContent="Responses",x=k(),w=c("div"),I=c("div");for(let e=0;e<v.length;e+=1)v[e].c();de=k(),A=c("div");for(let e=0;e<b.length;e+=1)b[e].c();m(l,"class","m-b-sm"),m(r,"class","content txt-lg m-b-sm"),m(E,"class","m-b-xs"),m(q,"class","label label-primary"),m(H,"class","content"),m(g,"class","alert alert-danger"),m(O,"class","section-title"),m(T,"class","table-compact table-border m-b-base"),m(B,"class","section-title"),m(I,"class","tabs-header compact combined left"),m(A,"class","tabs-content"),m(w,"class","tabs")},m(e,t){p(e,l,t),i(l,s),i(l,h),i(l,d),p(e,n,t),p(e,r,t),i(r,$),i($,D),i($,z),i(z,F),i($,se),p(e,K,t),Ce(C,e,t),p(e,Q,t),p(e,E,t),p(e,G,t),p(e,g,t),i(g,q),i(g,ae),i(g,H),i(H,P),i(P,oe),i(P,J),i(J,V),i(P,ne),i(P,W),i(g,ie),_&&_.m(g,null),p(e,X,t),p(e,O,t),p(e,Y,t),p(e,T,t),p(e,Z,t),p(e,B,t),p(e,x,t),p(e,w,t),i(w,I);for(let f=0;f<v.length;f+=1)v[f]&&v[f].m(I,null);i(w,de),i(w,A);for(let f=0;f<b.length;f+=1)b[f]&&b[f].m(A,null);R=!0},p(e,[t]){var be,_e;(!R||t&1)&&o!==(o=e[0].name+"")&&ee(h,o),(!R||t&1)&&S!==(S=e[0].name+"")&&ee(F,S);const f={};t&9&&(f.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(be=e[0])==null?void 0:be.name}').delete('RECORD_ID');
`),t&9&&(f.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(_e=e[0])==null?void 0:_e.name}').delete('RECORD_ID');
`),C.$set(f),(!R||t&1)&&L!==(L=e[0].name+"")&&ee(V,L),e[1]?_||(_=ve(),_.c(),_.m(g,null)):_&&(_.d(1),_=null),t&20&&(U=j(e[4]),v=he(v,t,fe,1,e,U,ce,I,Oe,ye,null,ge)),t&20&&(M=j(e[4]),Te(),b=he(b,t,pe,1,e,M,re,A,Be,$e,null,ke),Ie())},i(e){if(!R){te(C.$$.fragment,e);for(let t=0;t<M.length;t+=1)te(b[t]);R=!0}},o(e){le(C.$$.fragment,e);for(let t=0;t<b.length;t+=1)le(b[t]);R=!1},d(e){e&&(u(l),u(n),u(r),u(K),u(Q),u(E),u(G),u(g),u(X),u(O),u(Y),u(T),u(Z),u(B),u(x),u(w)),we(C,e),_&&_.d();for(let t=0;t<v.length;t+=1)v[t].d();for(let t=0;t<b.length;t+=1)b[t].d()}}}function Ue(a,l,s){let o,h,{collection:d}=l,n=204,r=[];const $=D=>s(2,n=D.code);return a.$$set=D=>{"collection"in D&&s(0,d=D.collection)},a.$$.update=()=>{a.$$.dirty&1&&s(1,o=(d==null?void 0:d.deleteRule)===null),a.$$.dirty&3&&d!=null&&d.id&&(r.push({code:204,body:`
null
`}),r.push({code:400,body:`
{
"code": 400,
"message": "Failed to delete record. Make sure that the record is not part of a required relation reference.",
"data": {}
}
`}),o&&r.push({code:403,body:`
{
"code": 403,
"message": "Only admins can access this action.",
"data": {}
}
`}),r.push({code:404,body:`
{
"code": 404,
"message": "The requested resource wasn't found.",
"data": {}
}
`}))},s(3,h=Ae.getApiExampleUrl(Me.baseUrl)),[d,o,n,h,r,$]}class ze extends Re{constructor(l){super(),Pe(this,l,Ue,Le,Ee,{collection:0})}}export{ze as default};
-58
View File
@@ -1,58 +0,0 @@
import{S as Ce,i as Re,s as Pe,e as c,w as $,b as h,c as $e,f as m,g as f,h as n,m as we,x,N as _e,P as Ee,k as Te,Q as Be,n as Oe,t as ee,a as te,o as u,d as ge,T as Ie,C as Me,p as Ae,r as N,u as Se,M as qe}from"./index-9e84ac8a.js";import{S as He}from"./SdkTabs-821a18db.js";function ke(o,l,s){const a=o.slice();return a[6]=l[s],a}function he(o,l,s){const a=o.slice();return a[6]=l[s],a}function ve(o){let l;return{c(){l=c("p"),l.innerHTML="Requires admin <code>Authorization:TOKEN</code> header",m(l,"class","txt-hint txt-sm txt-right")},m(s,a){f(s,l,a)},d(s){s&&u(l)}}}function ye(o,l){let s,a=l[6].code+"",v,i,r,p;function w(){return l[5](l[6])}return{key:o,first:null,c(){s=c("button"),v=$(a),i=h(),m(s,"class","tab-item"),N(s,"active",l[2]===l[6].code),this.first=s},m(b,g){f(b,s,g),n(s,v),n(s,i),r||(p=Se(s,"click",w),r=!0)},p(b,g){l=b,g&20&&N(s,"active",l[2]===l[6].code)},d(b){b&&u(s),r=!1,p()}}}function De(o,l){let s,a,v,i;return a=new qe({props:{content:l[6].body}}),{key:o,first:null,c(){s=c("div"),$e(a.$$.fragment),v=h(),m(s,"class","tab-item"),N(s,"active",l[2]===l[6].code),this.first=s},m(r,p){f(r,s,p),we(a,s,null),n(s,v),i=!0},p(r,p){l=r,(!i||p&20)&&N(s,"active",l[2]===l[6].code)},i(r){i||(ee(a.$$.fragment,r),i=!0)},o(r){te(a.$$.fragment,r),i=!1},d(r){r&&u(s),ge(a)}}}function Le(o){var ue,pe;let l,s,a=o[0].name+"",v,i,r,p,w,b,g,q=o[0].name+"",z,le,F,C,K,T,Q,y,H,se,L,E,oe,G,U=o[0].name+"",J,ae,V,ne,W,B,X,O,Y,I,Z,R,M,D=[],ie=new Map,re,A,_=[],ce=new Map,P;C=new He({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[3]}');
...
await pb.collection('${(ue=o[0])==null?void 0:ue.name}').delete('RECORD_ID');
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[3]}');
...
await pb.collection('${(pe=o[0])==null?void 0:pe.name}').delete('RECORD_ID');
`}});let k=o[1]&&ve(),j=o[4];const de=e=>e[6].code;for(let e=0;e<j.length;e+=1){let t=he(o,j,e),d=de(t);ie.set(d,D[e]=ye(d,t))}let S=o[4];const fe=e=>e[6].code;for(let e=0;e<S.length;e+=1){let t=ke(o,S,e),d=fe(t);ce.set(d,_[e]=De(d,t))}return{c(){l=c("h3"),s=$("Delete ("),v=$(a),i=$(")"),r=h(),p=c("div"),w=c("p"),b=$("Delete a single "),g=c("strong"),z=$(q),le=$(" record."),F=h(),$e(C.$$.fragment),K=h(),T=c("h6"),T.textContent="API details",Q=h(),y=c("div"),H=c("strong"),H.textContent="DELETE",se=h(),L=c("div"),E=c("p"),oe=$("/api/collections/"),G=c("strong"),J=$(U),ae=$("/records/"),V=c("strong"),V.textContent=":id",ne=h(),k&&k.c(),W=h(),B=c("div"),B.textContent="Path parameters",X=h(),O=c("table"),O.innerHTML=`<thead><tr><th>Param</th>
<th>Type</th>
<th width="60%">Description</th></tr></thead>
<tbody><tr><td>id</td>
<td><span class="label">String</span></td>
<td>ID of the record to delete.</td></tr></tbody>`,Y=h(),I=c("div"),I.textContent="Responses",Z=h(),R=c("div"),M=c("div");for(let e=0;e<D.length;e+=1)D[e].c();re=h(),A=c("div");for(let e=0;e<_.length;e+=1)_[e].c();m(l,"class","m-b-sm"),m(p,"class","content txt-lg m-b-sm"),m(T,"class","m-b-xs"),m(H,"class","label label-primary"),m(L,"class","content"),m(y,"class","alert alert-danger"),m(B,"class","section-title"),m(O,"class","table-compact table-border m-b-base"),m(I,"class","section-title"),m(M,"class","tabs-header compact left"),m(A,"class","tabs-content"),m(R,"class","tabs")},m(e,t){f(e,l,t),n(l,s),n(l,v),n(l,i),f(e,r,t),f(e,p,t),n(p,w),n(w,b),n(w,g),n(g,z),n(w,le),f(e,F,t),we(C,e,t),f(e,K,t),f(e,T,t),f(e,Q,t),f(e,y,t),n(y,H),n(y,se),n(y,L),n(L,E),n(E,oe),n(E,G),n(G,J),n(E,ae),n(E,V),n(y,ne),k&&k.m(y,null),f(e,W,t),f(e,B,t),f(e,X,t),f(e,O,t),f(e,Y,t),f(e,I,t),f(e,Z,t),f(e,R,t),n(R,M);for(let d=0;d<D.length;d+=1)D[d]&&D[d].m(M,null);n(R,re),n(R,A);for(let d=0;d<_.length;d+=1)_[d]&&_[d].m(A,null);P=!0},p(e,[t]){var me,be;(!P||t&1)&&a!==(a=e[0].name+"")&&x(v,a),(!P||t&1)&&q!==(q=e[0].name+"")&&x(z,q);const d={};t&9&&(d.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
await pb.collection('${(me=e[0])==null?void 0:me.name}').delete('RECORD_ID');
`),t&9&&(d.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
await pb.collection('${(be=e[0])==null?void 0:be.name}').delete('RECORD_ID');
`),C.$set(d),(!P||t&1)&&U!==(U=e[0].name+"")&&x(J,U),e[1]?k||(k=ve(),k.c(),k.m(y,null)):k&&(k.d(1),k=null),t&20&&(j=e[4],D=_e(D,t,de,1,e,j,ie,M,Ee,ye,null,he)),t&20&&(S=e[4],Te(),_=_e(_,t,fe,1,e,S,ce,A,Be,De,null,ke),Oe())},i(e){if(!P){ee(C.$$.fragment,e);for(let t=0;t<S.length;t+=1)ee(_[t]);P=!0}},o(e){te(C.$$.fragment,e);for(let t=0;t<_.length;t+=1)te(_[t]);P=!1},d(e){e&&u(l),e&&u(r),e&&u(p),e&&u(F),ge(C,e),e&&u(K),e&&u(T),e&&u(Q),e&&u(y),k&&k.d(),e&&u(W),e&&u(B),e&&u(X),e&&u(O),e&&u(Y),e&&u(I),e&&u(Z),e&&u(R);for(let t=0;t<D.length;t+=1)D[t].d();for(let t=0;t<_.length;t+=1)_[t].d()}}}function Ue(o,l,s){let a,v,{collection:i=new Ie}=l,r=204,p=[];const w=b=>s(2,r=b.code);return o.$$set=b=>{"collection"in b&&s(0,i=b.collection)},o.$$.update=()=>{o.$$.dirty&1&&s(1,a=(i==null?void 0:i.deleteRule)===null),o.$$.dirty&3&&i!=null&&i.id&&(p.push({code:204,body:`
null
`}),p.push({code:400,body:`
{
"code": 400,
"message": "Failed to delete record. Make sure that the record is not part of a required relation reference.",
"data": {}
}
`}),a&&p.push({code:403,body:`
{
"code": 403,
"message": "Only admins can access this action.",
"data": {}
}
`}),p.push({code:404,body:`
{
"code": 404,
"message": "The requested resource wasn't found.",
"data": {}
}
`}))},s(3,v=Me.getApiExampleUrl(Ae.baseUrl)),[i,a,r,v,p,w]}class ze extends Ce{constructor(l){super(),Re(this,l,Ue,Le,Pe,{collection:0})}}export{ze as default};
-6
View File
@@ -1,6 +0,0 @@
import{S as d,i as n,s as i,e as l,g as o,y as s,o as p}from"./index-9e84ac8a.js";function c(a){let e;return{c(){e=l("tr"),e.innerHTML=`<td id="query-page">fields</td>
<td><span class="label">String</span></td>
<td>Comma separated string of the fields to return in the JSON response
<em>(by default returns all fields)</em>. For example:
<br/>
<code>?fields=id,expand.relField.id,expand.relField.created</code></td>`},m(t,r){o(t,e,r)},p:s,i:s,o:s,d(t){t&&p(e)}}}class f extends d{constructor(e){super(),n(this,e,null,c,i,{})}}export{f as F};
+3
View File
@@ -0,0 +1,3 @@
import{S as d,i as n,s as i,e as l,g as o,y as s,o as p}from"./index-f26826b5.js";function c(a){let e;return{c(){e=l("tr"),e.innerHTML=`<td id="query-page">fields</td> <td><span class="label">String</span></td> <td>Comma separated string of the fields to return in the JSON response
<em>(by default returns all fields)</em>. For example:
<br/> <code>?fields=id,expand.relField.id,expand.relField.created</code></td>`},m(t,r){o(t,e,r)},p:s,i:s,o:s,d(t){t&&p(e)}}}class f extends d{constructor(e){super(),n(this,e,null,c,i,{})}}export{f as F};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+141
View File
@@ -0,0 +1,141 @@
import{S as Ze,i as tl,s as el,e,b as s,E as sl,f as a,g as u,u as ll,y as Ue,o as m,w as _,h as t,N as Fe,O as te,c as ee,m as le,x as ke,P as je,Q as nl,k as ol,R as al,n as il,t as Bt,a as Gt,d as se,T as rl,C as ve,p as cl,r as Le}from"./index-f26826b5.js";import{S as dl}from"./SdkTabs-37a2d588.js";function pl(d){let n,o,i;return{c(){n=e("span"),n.textContent="Show details",o=s(),i=e("i"),a(n,"class","txt"),a(i,"class","ri-arrow-down-s-line")},m(f,h){u(f,n,h),u(f,o,h),u(f,i,h)},d(f){f&&(m(n),m(o),m(i))}}}function fl(d){let n,o,i;return{c(){n=e("span"),n.textContent="Hide details",o=s(),i=e("i"),a(n,"class","txt"),a(i,"class","ri-arrow-up-s-line")},m(f,h){u(f,n,h),u(f,o,h),u(f,i,h)},d(f){f&&(m(n),m(o),m(i))}}}function ze(d){let n,o,i,f,h,r,b,C,$,g,p,Z,Ct,Ut,E,jt,M,it,S,tt,ne,G,U,oe,rt,$t,et,kt,ae,ct,dt,lt,N,zt,yt,y,st,vt,Jt,Ft,j,nt,Lt,Kt,At,F,pt,Tt,ie,ft,re,D,Pt,ot,St,O,ut,ce,z,Ot,Qt,Rt,de,q,Vt,J,mt,pe,I,fe,B,ue,P,Et,K,ht,me,bt,he,w,Nt,at,qt,be,Ht,Wt,Q,gt,ge,Mt,_e,_t,xe,V,xt,we,wt,Xt,W,Yt,L,X,R,Dt,Ce,Y,v,It;return{c(){n=e("p"),n.innerHTML=`The syntax basically follows the format
<code><span class="txt-success">OPERAND</span> <span class="txt-danger">OPERATOR</span> <span class="txt-success">OPERAND</span></code>, where:`,o=s(),i=e("ul"),f=e("li"),f.innerHTML=`<code class="txt-success">OPERAND</code> - could be any of the above field literal, string (single
or double quoted), number, null, true, false`,h=s(),r=e("li"),b=e("code"),b.textContent="OPERATOR",C=_(` - is one of:
`),$=e("br"),g=s(),p=e("ul"),Z=e("li"),Ct=e("code"),Ct.textContent="=",Ut=s(),E=e("span"),E.textContent="Equal",jt=s(),M=e("li"),it=e("code"),it.textContent="!=",S=s(),tt=e("span"),tt.textContent="NOT equal",ne=s(),G=e("li"),U=e("code"),U.textContent=">",oe=s(),rt=e("span"),rt.textContent="Greater than",$t=s(),et=e("li"),kt=e("code"),kt.textContent=">=",ae=s(),ct=e("span"),ct.textContent="Greater than or equal",dt=s(),lt=e("li"),N=e("code"),N.textContent="<",zt=s(),yt=e("span"),yt.textContent="Less than",y=s(),st=e("li"),vt=e("code"),vt.textContent="<=",Jt=s(),Ft=e("span"),Ft.textContent="Less than or equal",j=s(),nt=e("li"),Lt=e("code"),Lt.textContent="~",Kt=s(),At=e("span"),At.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,F=s(),pt=e("li"),Tt=e("code"),Tt.textContent="!~",ie=s(),ft=e("span"),ft.textContent=`NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,re=s(),D=e("li"),Pt=e("code"),Pt.textContent="?=",ot=s(),St=e("em"),St.textContent="Any/At least one of",O=s(),ut=e("span"),ut.textContent="Equal",ce=s(),z=e("li"),Ot=e("code"),Ot.textContent="?!=",Qt=s(),Rt=e("em"),Rt.textContent="Any/At least one of",de=s(),q=e("span"),q.textContent="NOT equal",Vt=s(),J=e("li"),mt=e("code"),mt.textContent="?>",pe=s(),I=e("em"),I.textContent="Any/At least one of",fe=s(),B=e("span"),B.textContent="Greater than",ue=s(),P=e("li"),Et=e("code"),Et.textContent="?>=",K=s(),ht=e("em"),ht.textContent="Any/At least one of",me=s(),bt=e("span"),bt.textContent="Greater than or equal",he=s(),w=e("li"),Nt=e("code"),Nt.textContent="?<",at=s(),qt=e("em"),qt.textContent="Any/At least one of",be=s(),Ht=e("span"),Ht.textContent="Less than",Wt=s(),Q=e("li"),gt=e("code"),gt.textContent="?<=",ge=s(),Mt=e("em"),Mt.textContent="Any/At least one of",_e=s(),_t=e("span"),_t.textContent="Less than or equal",xe=s(),V=e("li"),xt=e("code"),xt.textContent="?~",we=s(),wt=e("em"),wt.textContent="Any/At least one of",Xt=s(),W=e("span"),W.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,Yt=s(),L=e("li"),X=e("code"),X.textContent="?!~",R=s(),Dt=e("em"),Dt.textContent="Any/At least one of",Ce=s(),Y=e("span"),Y.textContent=`NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,v=s(),It=e("p"),It.innerHTML=`To group and combine several expressions you could use brackets
<code>(...)</code>, <code>&amp;&amp;</code> (AND) and <code>||</code> (OR) tokens.`,a(b,"class","txt-danger"),a(Ct,"class","filter-op svelte-1w7s5nw"),a(E,"class","txt"),a(it,"class","filter-op svelte-1w7s5nw"),a(tt,"class","txt"),a(U,"class","filter-op svelte-1w7s5nw"),a(rt,"class","txt"),a(kt,"class","filter-op svelte-1w7s5nw"),a(ct,"class","txt"),a(N,"class","filter-op svelte-1w7s5nw"),a(yt,"class","txt"),a(vt,"class","filter-op svelte-1w7s5nw"),a(Ft,"class","txt"),a(Lt,"class","filter-op svelte-1w7s5nw"),a(At,"class","txt"),a(Tt,"class","filter-op svelte-1w7s5nw"),a(ft,"class","txt"),a(Pt,"class","filter-op svelte-1w7s5nw"),a(St,"class","txt-hint"),a(ut,"class","txt"),a(Ot,"class","filter-op svelte-1w7s5nw"),a(Rt,"class","txt-hint"),a(q,"class","txt"),a(mt,"class","filter-op svelte-1w7s5nw"),a(I,"class","txt-hint"),a(B,"class","txt"),a(Et,"class","filter-op svelte-1w7s5nw"),a(ht,"class","txt-hint"),a(bt,"class","txt"),a(Nt,"class","filter-op svelte-1w7s5nw"),a(qt,"class","txt-hint"),a(Ht,"class","txt"),a(gt,"class","filter-op svelte-1w7s5nw"),a(Mt,"class","txt-hint"),a(_t,"class","txt"),a(xt,"class","filter-op svelte-1w7s5nw"),a(wt,"class","txt-hint"),a(W,"class","txt"),a(X,"class","filter-op svelte-1w7s5nw"),a(Dt,"class","txt-hint"),a(Y,"class","txt")},m(A,k){u(A,n,k),u(A,o,k),u(A,i,k),t(i,f),t(i,h),t(i,r),t(r,b),t(r,C),t(r,$),t(r,g),t(r,p),t(p,Z),t(Z,Ct),t(Z,Ut),t(Z,E),t(p,jt),t(p,M),t(M,it),t(M,S),t(M,tt),t(p,ne),t(p,G),t(G,U),t(G,oe),t(G,rt),t(p,$t),t(p,et),t(et,kt),t(et,ae),t(et,ct),t(p,dt),t(p,lt),t(lt,N),t(lt,zt),t(lt,yt),t(p,y),t(p,st),t(st,vt),t(st,Jt),t(st,Ft),t(p,j),t(p,nt),t(nt,Lt),t(nt,Kt),t(nt,At),t(p,F),t(p,pt),t(pt,Tt),t(pt,ie),t(pt,ft),t(p,re),t(p,D),t(D,Pt),t(D,ot),t(D,St),t(D,O),t(D,ut),t(p,ce),t(p,z),t(z,Ot),t(z,Qt),t(z,Rt),t(z,de),t(z,q),t(p,Vt),t(p,J),t(J,mt),t(J,pe),t(J,I),t(J,fe),t(J,B),t(p,ue),t(p,P),t(P,Et),t(P,K),t(P,ht),t(P,me),t(P,bt),t(p,he),t(p,w),t(w,Nt),t(w,at),t(w,qt),t(w,be),t(w,Ht),t(p,Wt),t(p,Q),t(Q,gt),t(Q,ge),t(Q,Mt),t(Q,_e),t(Q,_t),t(p,xe),t(p,V),t(V,xt),t(V,we),t(V,wt),t(V,Xt),t(V,W),t(p,Yt),t(p,L),t(L,X),t(L,R),t(L,Dt),t(L,Ce),t(L,Y),u(A,v,k),u(A,It,k)},d(A){A&&(m(n),m(o),m(i),m(v),m(It))}}}function ul(d){let n,o,i,f,h;function r(g,p){return g[0]?fl:pl}let b=r(d),C=b(d),$=d[0]&&ze();return{c(){n=e("button"),C.c(),o=s(),$&&$.c(),i=sl(),a(n,"class","btn btn-sm btn-secondary m-t-10")},m(g,p){u(g,n,p),C.m(n,null),u(g,o,p),$&&$.m(g,p),u(g,i,p),f||(h=ll(n,"click",d[1]),f=!0)},p(g,[p]){b!==(b=r(g))&&(C.d(1),C=b(g),C&&(C.c(),C.m(n,null))),g[0]?$||($=ze(),$.c(),$.m(i.parentNode,i)):$&&($.d(1),$=null)},i:Ue,o:Ue,d(g){g&&(m(n),m(o),m(i)),C.d(),$&&$.d(g),f=!1,h()}}}function ml(d,n,o){let i=!1;function f(){o(0,i=!i)}return[i,f]}class hl extends Ze{constructor(n){super(),tl(this,n,ml,ul,el,{})}}function Je(d,n,o){const i=d.slice();return i[7]=n[o],i}function Ke(d,n,o){const i=d.slice();return i[7]=n[o],i}function Qe(d,n,o){const i=d.slice();return i[12]=n[o],i[14]=o,i}function Ve(d){let n;return{c(){n=e("p"),n.innerHTML="Requires admin <code>Authorization:TOKEN</code> header",a(n,"class","txt-hint txt-sm txt-right")},m(o,i){u(o,n,i)},d(o){o&&m(n)}}}function We(d){let n,o=d[12]+"",i,f=d[14]<d[4].length-1?", ":"",h;return{c(){n=e("code"),i=_(o),h=_(f)},m(r,b){u(r,n,b),t(n,i),u(r,h,b)},p(r,b){b&16&&o!==(o=r[12]+"")&&ke(i,o),b&16&&f!==(f=r[14]<r[4].length-1?", ":"")&&ke(h,f)},d(r){r&&(m(n),m(h))}}}function Xe(d,n){let o,i,f;function h(){return n[6](n[7])}return{key:d,first:null,c(){o=e("button"),o.textContent=`${n[7].code} `,a(o,"type","button"),a(o,"class","tab-item"),Le(o,"active",n[2]===n[7].code),this.first=o},m(r,b){u(r,o,b),i||(f=ll(o,"click",h),i=!0)},p(r,b){n=r,b&36&&Le(o,"active",n[2]===n[7].code)},d(r){r&&m(o),i=!1,f()}}}function Ye(d,n){let o,i,f,h;return i=new Fe({props:{content:n[7].body}}),{key:d,first:null,c(){o=e("div"),ee(i.$$.fragment),f=s(),a(o,"class","tab-item"),Le(o,"active",n[2]===n[7].code),this.first=o},m(r,b){u(r,o,b),le(i,o,null),t(o,f),h=!0},p(r,b){n=r,(!h||b&36)&&Le(o,"active",n[2]===n[7].code)},i(r){h||(Bt(i.$$.fragment,r),h=!0)},o(r){Gt(i.$$.fragment,r),h=!1},d(r){r&&m(o),se(i)}}}function bl(d){var Pe,Se,Oe,Re,Ee,Ne;let n,o,i=d[0].name+"",f,h,r,b,C,$,g,p=d[0].name+"",Z,Ct,Ut,E,jt,M,it,S,tt,ne,G,U,oe,rt,$t=d[0].name+"",et,kt,ae,ct,dt,lt,N,zt,yt,y,st,vt,Jt,Ft,j,nt,Lt,Kt,At,F,pt,Tt,ie,ft,re,D,Pt,ot,St,O,ut,ce,z,Ot,Qt,Rt,de,q,Vt,J,mt,pe,I,fe,B,ue,P,Et,K,ht,me,bt,he,w,Nt,at,qt,be,Ht,Wt,Q,gt,ge,Mt,_e,_t,xe,V,xt,we,wt,Xt,W,Yt,L,X,R=[],Dt=new Map,Ce,Y,v=[],It=new Map,A;E=new dl({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${d[3]}');
...
// fetch a paginated records list
const resultList = await pb.collection('${(Pe=d[0])==null?void 0:Pe.name}').getList(1, 50, {
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
});
// you can also fetch all records at once via getFullList
const records = await pb.collection('${(Se=d[0])==null?void 0:Se.name}').getFullList({
sort: '-created',
});
// or fetch only the first record that matches the specified filter
const record = await pb.collection('${(Oe=d[0])==null?void 0:Oe.name}').getFirstListItem('someField="test"', {
expand: 'relField1,relField2.subRelField',
});
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${d[3]}');
...
// fetch a paginated records list
final resultList = await pb.collection('${(Re=d[0])==null?void 0:Re.name}').getList(
page: 1,
perPage: 50,
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
);
// you can also fetch all records at once via getFullList
final records = await pb.collection('${(Ee=d[0])==null?void 0:Ee.name}').getFullList(
sort: '-created',
);
// or fetch only the first record that matches the specified filter
final record = await pb.collection('${(Ne=d[0])==null?void 0:Ne.name}').getFirstListItem(
'someField="test"',
expand: 'relField1,relField2.subRelField',
);
`}});let k=d[1]&&Ve();ot=new Fe({props:{content:`
// DESC by created and ASC by id
?sort=-created,id
`}});let Zt=te(d[4]),T=[];for(let l=0;l<Zt.length;l+=1)T[l]=We(Qe(d,Zt,l));B=new Fe({props:{content:`
?filter=(id='abc' && created>'2022-01-01')
`}}),P=new hl({}),at=new Fe({props:{content:"?expand=relField1,relField2.subRelField"}});let ye=te(d[5]);const Ae=l=>l[7].code;for(let l=0;l<ye.length;l+=1){let c=Ke(d,ye,l),x=Ae(c);Dt.set(x,R[l]=Xe(x,c))}let $e=te(d[5]);const Te=l=>l[7].code;for(let l=0;l<$e.length;l+=1){let c=Je(d,$e,l),x=Te(c);It.set(x,v[l]=Ye(x,c))}return{c(){n=e("h3"),o=_("List/Search ("),f=_(i),h=_(")"),r=s(),b=e("div"),C=e("p"),$=_("Fetch a paginated "),g=e("strong"),Z=_(p),Ct=_(" records list, supporting sorting and filtering."),Ut=s(),ee(E.$$.fragment),jt=s(),M=e("h6"),M.textContent="API details",it=s(),S=e("div"),tt=e("strong"),tt.textContent="GET",ne=s(),G=e("div"),U=e("p"),oe=_("/api/collections/"),rt=e("strong"),et=_($t),kt=_("/records"),ae=s(),k&&k.c(),ct=s(),dt=e("div"),dt.textContent="Query parameters",lt=s(),N=e("table"),zt=e("thead"),zt.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',yt=s(),y=e("tbody"),st=e("tr"),st.innerHTML='<td>page</td> <td><span class="label">Number</span></td> <td>The page (aka. offset) of the paginated list (default to 1).</td>',vt=s(),Jt=e("tr"),Jt.innerHTML='<td>perPage</td> <td><span class="label">Number</span></td> <td>Specify the max returned records per page (default to 30).</td>',Ft=s(),j=e("tr"),nt=e("td"),nt.textContent="sort",Lt=s(),Kt=e("td"),Kt.innerHTML='<span class="label">String</span>',At=s(),F=e("td"),pt=_("Specify the records order attribute(s). "),Tt=e("br"),ie=_(`
Add `),ft=e("code"),ft.textContent="-",re=_(" / "),D=e("code"),D.textContent="+",Pt=_(` (default) in front of the attribute for DESC / ASC order.
Ex.:
`),ee(ot.$$.fragment),St=s(),O=e("p"),ut=e("strong"),ut.textContent="Supported record sort fields:",ce=s(),z=e("br"),Ot=s(),Qt=e("code"),Qt.textContent="@random",Rt=_(`,
`);for(let l=0;l<T.length;l+=1)T[l].c();de=s(),q=e("tr"),Vt=e("td"),Vt.textContent="filter",J=s(),mt=e("td"),mt.innerHTML='<span class="label">String</span>',pe=s(),I=e("td"),fe=_(`Filter the returned records. Ex.:
`),ee(B.$$.fragment),ue=s(),ee(P.$$.fragment),Et=s(),K=e("tr"),ht=e("td"),ht.textContent="expand",me=s(),bt=e("td"),bt.innerHTML='<span class="label">String</span>',he=s(),w=e("td"),Nt=_(`Auto expand record relations. Ex.:
`),ee(at.$$.fragment),qt=_(`
Supports up to 6-levels depth nested relations expansion. `),be=e("br"),Ht=_(`
The expanded relations will be appended to each individual record under the
`),Wt=e("code"),Wt.textContent="expand",Q=_(" property (eg. "),gt=e("code"),gt.textContent='"expand": {"relField1": {...}, ...}',ge=_(`).
`),Mt=e("br"),_e=_(`
Only the relations to which the request user has permissions to `),_t=e("strong"),_t.textContent="view",xe=_(" will be expanded."),V=s(),xt=e("tr"),xt.innerHTML=`<td id="query-page">fields</td> <td><span class="label">String</span></td> <td>Comma separated string of the fields to return in the JSON response
<em>(by default returns all fields)</em>.
<br/>
Use <code>*</code> to target all keys from the specific depth level.
<br/>
For example: <code>?fields=*,expand.author.name</code></td>`,we=s(),wt=e("tr"),wt.innerHTML=`<td id="query-page">skipTotal</td> <td><span class="label">Boolean</span></td> <td>If it is set the total counts query will be skipped and the response fields
<code>totalItems</code> and <code>totalPages</code> will have <code>-1</code> value.
<br/>
This could drastically speed up the search queries when the total counters are not needed or cursor
based pagination is used.
<br/>
For optimization purposes, it is set by default for the
<code>getFirstListItem()</code>
and
<code>getFullList()</code> SDKs methods.</td>`,Xt=s(),W=e("div"),W.textContent="Responses",Yt=s(),L=e("div"),X=e("div");for(let l=0;l<R.length;l+=1)R[l].c();Ce=s(),Y=e("div");for(let l=0;l<v.length;l+=1)v[l].c();a(n,"class","m-b-sm"),a(b,"class","content txt-lg m-b-sm"),a(M,"class","m-b-xs"),a(tt,"class","label label-primary"),a(G,"class","content"),a(S,"class","alert alert-info"),a(dt,"class","section-title"),a(N,"class","table-compact table-border m-b-base"),a(W,"class","section-title"),a(X,"class","tabs-header compact combined left"),a(Y,"class","tabs-content"),a(L,"class","tabs")},m(l,c){u(l,n,c),t(n,o),t(n,f),t(n,h),u(l,r,c),u(l,b,c),t(b,C),t(C,$),t(C,g),t(g,Z),t(C,Ct),u(l,Ut,c),le(E,l,c),u(l,jt,c),u(l,M,c),u(l,it,c),u(l,S,c),t(S,tt),t(S,ne),t(S,G),t(G,U),t(U,oe),t(U,rt),t(rt,et),t(U,kt),t(S,ae),k&&k.m(S,null),u(l,ct,c),u(l,dt,c),u(l,lt,c),u(l,N,c),t(N,zt),t(N,yt),t(N,y),t(y,st),t(y,vt),t(y,Jt),t(y,Ft),t(y,j),t(j,nt),t(j,Lt),t(j,Kt),t(j,At),t(j,F),t(F,pt),t(F,Tt),t(F,ie),t(F,ft),t(F,re),t(F,D),t(F,Pt),le(ot,F,null),t(F,St),t(F,O),t(O,ut),t(O,ce),t(O,z),t(O,Ot),t(O,Qt),t(O,Rt);for(let x=0;x<T.length;x+=1)T[x]&&T[x].m(O,null);t(y,de),t(y,q),t(q,Vt),t(q,J),t(q,mt),t(q,pe),t(q,I),t(I,fe),le(B,I,null),t(I,ue),le(P,I,null),t(y,Et),t(y,K),t(K,ht),t(K,me),t(K,bt),t(K,he),t(K,w),t(w,Nt),le(at,w,null),t(w,qt),t(w,be),t(w,Ht),t(w,Wt),t(w,Q),t(w,gt),t(w,ge),t(w,Mt),t(w,_e),t(w,_t),t(w,xe),t(y,V),t(y,xt),t(y,we),t(y,wt),u(l,Xt,c),u(l,W,c),u(l,Yt,c),u(l,L,c),t(L,X);for(let x=0;x<R.length;x+=1)R[x]&&R[x].m(X,null);t(L,Ce),t(L,Y);for(let x=0;x<v.length;x+=1)v[x]&&v[x].m(Y,null);A=!0},p(l,[c]){var qe,He,Me,De,Ie,Be;(!A||c&1)&&i!==(i=l[0].name+"")&&ke(f,i),(!A||c&1)&&p!==(p=l[0].name+"")&&ke(Z,p);const x={};if(c&9&&(x.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${l[3]}');
...
// fetch a paginated records list
const resultList = await pb.collection('${(qe=l[0])==null?void 0:qe.name}').getList(1, 50, {
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
});
// you can also fetch all records at once via getFullList
const records = await pb.collection('${(He=l[0])==null?void 0:He.name}').getFullList({
sort: '-created',
});
// or fetch only the first record that matches the specified filter
const record = await pb.collection('${(Me=l[0])==null?void 0:Me.name}').getFirstListItem('someField="test"', {
expand: 'relField1,relField2.subRelField',
});
`),c&9&&(x.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${l[3]}');
...
// fetch a paginated records list
final resultList = await pb.collection('${(De=l[0])==null?void 0:De.name}').getList(
page: 1,
perPage: 50,
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
);
// you can also fetch all records at once via getFullList
final records = await pb.collection('${(Ie=l[0])==null?void 0:Ie.name}').getFullList(
sort: '-created',
);
// or fetch only the first record that matches the specified filter
final record = await pb.collection('${(Be=l[0])==null?void 0:Be.name}').getFirstListItem(
'someField="test"',
expand: 'relField1,relField2.subRelField',
);
`),E.$set(x),(!A||c&1)&&$t!==($t=l[0].name+"")&&ke(et,$t),l[1]?k||(k=Ve(),k.c(),k.m(S,null)):k&&(k.d(1),k=null),c&16){Zt=te(l[4]);let H;for(H=0;H<Zt.length;H+=1){const Ge=Qe(l,Zt,H);T[H]?T[H].p(Ge,c):(T[H]=We(Ge),T[H].c(),T[H].m(O,null))}for(;H<T.length;H+=1)T[H].d(1);T.length=Zt.length}c&36&&(ye=te(l[5]),R=je(R,c,Ae,1,l,ye,Dt,X,nl,Xe,null,Ke)),c&36&&($e=te(l[5]),ol(),v=je(v,c,Te,1,l,$e,It,Y,al,Ye,null,Je),il())},i(l){if(!A){Bt(E.$$.fragment,l),Bt(ot.$$.fragment,l),Bt(B.$$.fragment,l),Bt(P.$$.fragment,l),Bt(at.$$.fragment,l);for(let c=0;c<$e.length;c+=1)Bt(v[c]);A=!0}},o(l){Gt(E.$$.fragment,l),Gt(ot.$$.fragment,l),Gt(B.$$.fragment,l),Gt(P.$$.fragment,l),Gt(at.$$.fragment,l);for(let c=0;c<v.length;c+=1)Gt(v[c]);A=!1},d(l){l&&(m(n),m(r),m(b),m(Ut),m(jt),m(M),m(it),m(S),m(ct),m(dt),m(lt),m(N),m(Xt),m(W),m(Yt),m(L)),se(E,l),k&&k.d(),se(ot),rl(T,l),se(B),se(P),se(at);for(let c=0;c<R.length;c+=1)R[c].d();for(let c=0;c<v.length;c+=1)v[c].d()}}}function gl(d,n,o){let i,f,h,{collection:r}=n,b=200,C=[];const $=g=>o(2,b=g.code);return d.$$set=g=>{"collection"in g&&o(0,r=g.collection)},d.$$.update=()=>{d.$$.dirty&1&&o(4,i=ve.getAllCollectionIdentifiers(r)),d.$$.dirty&1&&o(1,f=(r==null?void 0:r.listRule)===null),d.$$.dirty&3&&r!=null&&r.id&&(C.push({code:200,body:JSON.stringify({page:1,perPage:30,totalPages:1,totalItems:2,items:[ve.dummyCollectionRecord(r),ve.dummyCollectionRecord(r)]},null,2)}),C.push({code:400,body:`
{
"code": 400,
"message": "Something went wrong while processing your request. Invalid filter.",
"data": {}
}
`}),f&&C.push({code:403,body:`
{
"code": 403,
"message": "Only admins can access this action.",
"data": {}
}
`}))},o(3,h=ve.getApiExampleUrl(cl.baseUrl)),[r,f,b,h,i,C,$]}class wl extends Ze{constructor(n){super(),tl(this,n,gl,bl,el,{collection:0})}}export{wl as default};
-149
View File
@@ -1,149 +0,0 @@
import{S as Ye,i as Ze,s as tl,e,b as s,E as ll,f as i,g as u,u as el,y as Ge,o as m,w as x,h as t,M as ve,c as te,m as ee,x as $e,N as Ue,P as sl,k as nl,Q as ol,n as il,t as Bt,a as Gt,d as le,R as al,T as rl,C as ye,p as cl,r as Fe}from"./index-9e84ac8a.js";import{S as dl}from"./SdkTabs-821a18db.js";function fl(c){let n,o,a;return{c(){n=e("span"),n.textContent="Show details",o=s(),a=e("i"),i(n,"class","txt"),i(a,"class","ri-arrow-down-s-line")},m(p,b){u(p,n,b),u(p,o,b),u(p,a,b)},d(p){p&&m(n),p&&m(o),p&&m(a)}}}function pl(c){let n,o,a;return{c(){n=e("span"),n.textContent="Hide details",o=s(),a=e("i"),i(n,"class","txt"),i(a,"class","ri-arrow-up-s-line")},m(p,b){u(p,n,b),u(p,o,b),u(p,a,b)},d(p){p&&m(n),p&&m(o),p&&m(a)}}}function je(c){let n,o,a,p,b,d,h,g,w,_,f,Z,Ct,Ut,E,jt,H,at,S,tt,se,G,U,ne,rt,$t,et,kt,oe,ct,dt,lt,N,zt,yt,v,st,vt,Jt,Ft,j,nt,Lt,Kt,At,L,ft,Tt,ie,pt,ae,D,Pt,ot,St,R,ut,re,z,Rt,Qt,Ot,ce,q,Vt,J,mt,de,I,fe,B,pe,P,Et,K,bt,ue,ht,me,$,Nt,it,qt,be,Mt,Wt,Q,_t,he,Ht,_e,wt,we,V,xt,xe,gt,Xt,W,Yt,A,X,O,Dt,ge,Y,F,It;return{c(){n=e("p"),n.innerHTML=`The syntax basically follows the format
<code><span class="txt-success">OPERAND</span>
<span class="txt-danger">OPERATOR</span>
<span class="txt-success">OPERAND</span></code>, where:`,o=s(),a=e("ul"),p=e("li"),p.innerHTML=`<code class="txt-success">OPERAND</code> - could be any of the above field literal, string (single
or double quoted), number, null, true, false`,b=s(),d=e("li"),h=e("code"),h.textContent="OPERATOR",g=x(` - is one of:
`),w=e("br"),_=s(),f=e("ul"),Z=e("li"),Ct=e("code"),Ct.textContent="=",Ut=s(),E=e("span"),E.textContent="Equal",jt=s(),H=e("li"),at=e("code"),at.textContent="!=",S=s(),tt=e("span"),tt.textContent="NOT equal",se=s(),G=e("li"),U=e("code"),U.textContent=">",ne=s(),rt=e("span"),rt.textContent="Greater than",$t=s(),et=e("li"),kt=e("code"),kt.textContent=">=",oe=s(),ct=e("span"),ct.textContent="Greater than or equal",dt=s(),lt=e("li"),N=e("code"),N.textContent="<",zt=s(),yt=e("span"),yt.textContent="Less than",v=s(),st=e("li"),vt=e("code"),vt.textContent="<=",Jt=s(),Ft=e("span"),Ft.textContent="Less than or equal",j=s(),nt=e("li"),Lt=e("code"),Lt.textContent="~",Kt=s(),At=e("span"),At.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,L=s(),ft=e("li"),Tt=e("code"),Tt.textContent="!~",ie=s(),pt=e("span"),pt.textContent=`NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,ae=s(),D=e("li"),Pt=e("code"),Pt.textContent="?=",ot=s(),St=e("em"),St.textContent="Any/At least one of",R=s(),ut=e("span"),ut.textContent="Equal",re=s(),z=e("li"),Rt=e("code"),Rt.textContent="?!=",Qt=s(),Ot=e("em"),Ot.textContent="Any/At least one of",ce=s(),q=e("span"),q.textContent="NOT equal",Vt=s(),J=e("li"),mt=e("code"),mt.textContent="?>",de=s(),I=e("em"),I.textContent="Any/At least one of",fe=s(),B=e("span"),B.textContent="Greater than",pe=s(),P=e("li"),Et=e("code"),Et.textContent="?>=",K=s(),bt=e("em"),bt.textContent="Any/At least one of",ue=s(),ht=e("span"),ht.textContent="Greater than or equal",me=s(),$=e("li"),Nt=e("code"),Nt.textContent="?<",it=s(),qt=e("em"),qt.textContent="Any/At least one of",be=s(),Mt=e("span"),Mt.textContent="Less than",Wt=s(),Q=e("li"),_t=e("code"),_t.textContent="?<=",he=s(),Ht=e("em"),Ht.textContent="Any/At least one of",_e=s(),wt=e("span"),wt.textContent="Less than or equal",we=s(),V=e("li"),xt=e("code"),xt.textContent="?~",xe=s(),gt=e("em"),gt.textContent="Any/At least one of",Xt=s(),W=e("span"),W.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,Yt=s(),A=e("li"),X=e("code"),X.textContent="?!~",O=s(),Dt=e("em"),Dt.textContent="Any/At least one of",ge=s(),Y=e("span"),Y.textContent=`NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,F=s(),It=e("p"),It.innerHTML=`To group and combine several expressions you could use brackets
<code>(...)</code>, <code>&amp;&amp;</code> (AND) and <code>||</code> (OR) tokens.`,i(h,"class","txt-danger"),i(Ct,"class","filter-op svelte-1w7s5nw"),i(E,"class","txt"),i(at,"class","filter-op svelte-1w7s5nw"),i(tt,"class","txt"),i(U,"class","filter-op svelte-1w7s5nw"),i(rt,"class","txt"),i(kt,"class","filter-op svelte-1w7s5nw"),i(ct,"class","txt"),i(N,"class","filter-op svelte-1w7s5nw"),i(yt,"class","txt"),i(vt,"class","filter-op svelte-1w7s5nw"),i(Ft,"class","txt"),i(Lt,"class","filter-op svelte-1w7s5nw"),i(At,"class","txt"),i(Tt,"class","filter-op svelte-1w7s5nw"),i(pt,"class","txt"),i(Pt,"class","filter-op svelte-1w7s5nw"),i(St,"class","txt-hint"),i(ut,"class","txt"),i(Rt,"class","filter-op svelte-1w7s5nw"),i(Ot,"class","txt-hint"),i(q,"class","txt"),i(mt,"class","filter-op svelte-1w7s5nw"),i(I,"class","txt-hint"),i(B,"class","txt"),i(Et,"class","filter-op svelte-1w7s5nw"),i(bt,"class","txt-hint"),i(ht,"class","txt"),i(Nt,"class","filter-op svelte-1w7s5nw"),i(qt,"class","txt-hint"),i(Mt,"class","txt"),i(_t,"class","filter-op svelte-1w7s5nw"),i(Ht,"class","txt-hint"),i(wt,"class","txt"),i(xt,"class","filter-op svelte-1w7s5nw"),i(gt,"class","txt-hint"),i(W,"class","txt"),i(X,"class","filter-op svelte-1w7s5nw"),i(Dt,"class","txt-hint"),i(Y,"class","txt")},m(k,y){u(k,n,y),u(k,o,y),u(k,a,y),t(a,p),t(a,b),t(a,d),t(d,h),t(d,g),t(d,w),t(d,_),t(d,f),t(f,Z),t(Z,Ct),t(Z,Ut),t(Z,E),t(f,jt),t(f,H),t(H,at),t(H,S),t(H,tt),t(f,se),t(f,G),t(G,U),t(G,ne),t(G,rt),t(f,$t),t(f,et),t(et,kt),t(et,oe),t(et,ct),t(f,dt),t(f,lt),t(lt,N),t(lt,zt),t(lt,yt),t(f,v),t(f,st),t(st,vt),t(st,Jt),t(st,Ft),t(f,j),t(f,nt),t(nt,Lt),t(nt,Kt),t(nt,At),t(f,L),t(f,ft),t(ft,Tt),t(ft,ie),t(ft,pt),t(f,ae),t(f,D),t(D,Pt),t(D,ot),t(D,St),t(D,R),t(D,ut),t(f,re),t(f,z),t(z,Rt),t(z,Qt),t(z,Ot),t(z,ce),t(z,q),t(f,Vt),t(f,J),t(J,mt),t(J,de),t(J,I),t(J,fe),t(J,B),t(f,pe),t(f,P),t(P,Et),t(P,K),t(P,bt),t(P,ue),t(P,ht),t(f,me),t(f,$),t($,Nt),t($,it),t($,qt),t($,be),t($,Mt),t(f,Wt),t(f,Q),t(Q,_t),t(Q,he),t(Q,Ht),t(Q,_e),t(Q,wt),t(f,we),t(f,V),t(V,xt),t(V,xe),t(V,gt),t(V,Xt),t(V,W),t(f,Yt),t(f,A),t(A,X),t(A,O),t(A,Dt),t(A,ge),t(A,Y),u(k,F,y),u(k,It,y)},d(k){k&&m(n),k&&m(o),k&&m(a),k&&m(F),k&&m(It)}}}function ul(c){let n,o,a,p,b;function d(_,f){return _[0]?pl:fl}let h=d(c),g=h(c),w=c[0]&&je();return{c(){n=e("button"),g.c(),o=s(),w&&w.c(),a=ll(),i(n,"class","btn btn-sm btn-secondary m-t-10")},m(_,f){u(_,n,f),g.m(n,null),u(_,o,f),w&&w.m(_,f),u(_,a,f),p||(b=el(n,"click",c[1]),p=!0)},p(_,[f]){h!==(h=d(_))&&(g.d(1),g=h(_),g&&(g.c(),g.m(n,null))),_[0]?w||(w=je(),w.c(),w.m(a.parentNode,a)):w&&(w.d(1),w=null)},i:Ge,o:Ge,d(_){_&&m(n),g.d(),_&&m(o),w&&w.d(_),_&&m(a),p=!1,b()}}}function ml(c,n,o){let a=!1;function p(){o(0,a=!a)}return[a,p]}class bl extends Ye{constructor(n){super(),Ze(this,n,ml,ul,tl,{})}}function ze(c,n,o){const a=c.slice();return a[7]=n[o],a}function Je(c,n,o){const a=c.slice();return a[7]=n[o],a}function Ke(c,n,o){const a=c.slice();return a[12]=n[o],a[14]=o,a}function Qe(c){let n;return{c(){n=e("p"),n.innerHTML="Requires admin <code>Authorization:TOKEN</code> header",i(n,"class","txt-hint txt-sm txt-right")},m(o,a){u(o,n,a)},d(o){o&&m(n)}}}function Ve(c){let n,o=c[12]+"",a,p=c[14]<c[4].length-1?", ":"",b;return{c(){n=e("code"),a=x(o),b=x(p)},m(d,h){u(d,n,h),t(n,a),u(d,b,h)},p(d,h){h&16&&o!==(o=d[12]+"")&&$e(a,o),h&16&&p!==(p=d[14]<d[4].length-1?", ":"")&&$e(b,p)},d(d){d&&m(n),d&&m(b)}}}function We(c,n){let o,a=n[7].code+"",p,b,d,h;function g(){return n[6](n[7])}return{key:c,first:null,c(){o=e("button"),p=x(a),b=s(),i(o,"type","button"),i(o,"class","tab-item"),Fe(o,"active",n[2]===n[7].code),this.first=o},m(w,_){u(w,o,_),t(o,p),t(o,b),d||(h=el(o,"click",g),d=!0)},p(w,_){n=w,_&36&&Fe(o,"active",n[2]===n[7].code)},d(w){w&&m(o),d=!1,h()}}}function Xe(c,n){let o,a,p,b;return a=new ve({props:{content:n[7].body}}),{key:c,first:null,c(){o=e("div"),te(a.$$.fragment),p=s(),i(o,"class","tab-item"),Fe(o,"active",n[2]===n[7].code),this.first=o},m(d,h){u(d,o,h),ee(a,o,null),t(o,p),b=!0},p(d,h){n=d,(!b||h&36)&&Fe(o,"active",n[2]===n[7].code)},i(d){b||(Bt(a.$$.fragment,d),b=!0)},o(d){Gt(a.$$.fragment,d),b=!1},d(d){d&&m(o),le(a)}}}function hl(c){var Te,Pe,Se,Re,Oe,Ee;let n,o,a=c[0].name+"",p,b,d,h,g,w,_,f=c[0].name+"",Z,Ct,Ut,E,jt,H,at,S,tt,se,G,U,ne,rt,$t=c[0].name+"",et,kt,oe,ct,dt,lt,N,zt,yt,v,st,vt,Jt,Ft,j,nt,Lt,Kt,At,L,ft,Tt,ie,pt,ae,D,Pt,ot,St,R,ut,re,z,Rt,Qt,Ot,ce,q,Vt,J,mt,de,I,fe,B,pe,P,Et,K,bt,ue,ht,me,$,Nt,it,qt,be,Mt,Wt,Q,_t,he,Ht,_e,wt,we,V,xt,xe,gt,Xt,W,Yt,A,X,O=[],Dt=new Map,ge,Y,F=[],It=new Map,k;E=new dl({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${c[3]}');
...
// fetch a paginated records list
const resultList = await pb.collection('${(Te=c[0])==null?void 0:Te.name}').getList(1, 50, {
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
});
// you can also fetch all records at once via getFullList
const records = await pb.collection('${(Pe=c[0])==null?void 0:Pe.name}').getFullList({
sort: '-created',
});
// or fetch only the first record that matches the specified filter
const record = await pb.collection('${(Se=c[0])==null?void 0:Se.name}').getFirstListItem('someField="test"', {
expand: 'relField1,relField2.subRelField',
});
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${c[3]}');
...
// fetch a paginated records list
final resultList = await pb.collection('${(Re=c[0])==null?void 0:Re.name}').getList(
page: 1,
perPage: 50,
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
);
// you can also fetch all records at once via getFullList
final records = await pb.collection('${(Oe=c[0])==null?void 0:Oe.name}').getFullList(
sort: '-created',
);
// or fetch only the first record that matches the specified filter
final record = await pb.collection('${(Ee=c[0])==null?void 0:Ee.name}').getFirstListItem(
'someField="test"',
expand: 'relField1,relField2.subRelField',
);
`}});let y=c[1]&&Qe();ot=new ve({props:{content:`
// DESC by created and ASC by id
?sort=-created,id
`}});let Zt=c[4],T=[];for(let l=0;l<Zt.length;l+=1)T[l]=Ve(Ke(c,Zt,l));B=new ve({props:{content:`
?filter=(id='abc' && created>'2022-01-01')
`}}),P=new bl({}),it=new ve({props:{content:"?expand=relField1,relField2.subRelField"}});let ke=c[5];const Le=l=>l[7].code;for(let l=0;l<ke.length;l+=1){let r=Je(c,ke,l),C=Le(r);Dt.set(C,O[l]=We(C,r))}let Ce=c[5];const Ae=l=>l[7].code;for(let l=0;l<Ce.length;l+=1){let r=ze(c,Ce,l),C=Ae(r);It.set(C,F[l]=Xe(C,r))}return{c(){n=e("h3"),o=x("List/Search ("),p=x(a),b=x(")"),d=s(),h=e("div"),g=e("p"),w=x("Fetch a paginated "),_=e("strong"),Z=x(f),Ct=x(" records list, supporting sorting and filtering."),Ut=s(),te(E.$$.fragment),jt=s(),H=e("h6"),H.textContent="API details",at=s(),S=e("div"),tt=e("strong"),tt.textContent="GET",se=s(),G=e("div"),U=e("p"),ne=x("/api/collections/"),rt=e("strong"),et=x($t),kt=x("/records"),oe=s(),y&&y.c(),ct=s(),dt=e("div"),dt.textContent="Query parameters",lt=s(),N=e("table"),zt=e("thead"),zt.innerHTML=`<tr><th>Param</th>
<th>Type</th>
<th width="60%">Description</th></tr>`,yt=s(),v=e("tbody"),st=e("tr"),st.innerHTML=`<td>page</td>
<td><span class="label">Number</span></td>
<td>The page (aka. offset) of the paginated list (default to 1).</td>`,vt=s(),Jt=e("tr"),Jt.innerHTML=`<td>perPage</td>
<td><span class="label">Number</span></td>
<td>Specify the max returned records per page (default to 30).</td>`,Ft=s(),j=e("tr"),nt=e("td"),nt.textContent="sort",Lt=s(),Kt=e("td"),Kt.innerHTML='<span class="label">String</span>',At=s(),L=e("td"),ft=x("Specify the records order attribute(s). "),Tt=e("br"),ie=x(`
Add `),pt=e("code"),pt.textContent="-",ae=x(" / "),D=e("code"),D.textContent="+",Pt=x(` (default) in front of the attribute for DESC / ASC order.
Ex.:
`),te(ot.$$.fragment),St=s(),R=e("p"),ut=e("strong"),ut.textContent="Supported record sort fields:",re=s(),z=e("br"),Rt=s(),Qt=e("code"),Qt.textContent="@random",Ot=x(`,
`);for(let l=0;l<T.length;l+=1)T[l].c();ce=s(),q=e("tr"),Vt=e("td"),Vt.textContent="filter",J=s(),mt=e("td"),mt.innerHTML='<span class="label">String</span>',de=s(),I=e("td"),fe=x(`Filter the returned records. Ex.:
`),te(B.$$.fragment),pe=s(),te(P.$$.fragment),Et=s(),K=e("tr"),bt=e("td"),bt.textContent="expand",ue=s(),ht=e("td"),ht.innerHTML='<span class="label">String</span>',me=s(),$=e("td"),Nt=x(`Auto expand record relations. Ex.:
`),te(it.$$.fragment),qt=x(`
Supports up to 6-levels depth nested relations expansion. `),be=e("br"),Mt=x(`
The expanded relations will be appended to each individual record under the
`),Wt=e("code"),Wt.textContent="expand",Q=x(" property (eg. "),_t=e("code"),_t.textContent='"expand": {"relField1": {...}, ...}',he=x(`).
`),Ht=e("br"),_e=x(`
Only the relations to which the request user has permissions to `),wt=e("strong"),wt.textContent="view",we=x(" will be expanded."),V=s(),xt=e("tr"),xt.innerHTML=`<td id="query-page">fields</td>
<td><span class="label">String</span></td>
<td>Comma separated string of the fields to return in the JSON response
<em>(by default returns all fields)</em>.</td>`,xe=s(),gt=e("tr"),gt.innerHTML=`<td id="query-page">skipTotal</td>
<td><span class="label">Boolean</span></td>
<td>If it is set the total counts query will be skipped and the response fields
<code>totalItems</code> and <code>totalPages</code> will have <code>-1</code> value.
<br/>
This could drastically speed up the search queries when the total counters are not needed or cursor
based pagination is used.
<br/>
For optimization purposes, it is set by default for the
<code>getFirstListItem()</code>
and
<code>getFullList()</code> SDKs methods.</td>`,Xt=s(),W=e("div"),W.textContent="Responses",Yt=s(),A=e("div"),X=e("div");for(let l=0;l<O.length;l+=1)O[l].c();ge=s(),Y=e("div");for(let l=0;l<F.length;l+=1)F[l].c();i(n,"class","m-b-sm"),i(h,"class","content txt-lg m-b-sm"),i(H,"class","m-b-xs"),i(tt,"class","label label-primary"),i(G,"class","content"),i(S,"class","alert alert-info"),i(dt,"class","section-title"),i(N,"class","table-compact table-border m-b-base"),i(W,"class","section-title"),i(X,"class","tabs-header compact left"),i(Y,"class","tabs-content"),i(A,"class","tabs")},m(l,r){u(l,n,r),t(n,o),t(n,p),t(n,b),u(l,d,r),u(l,h,r),t(h,g),t(g,w),t(g,_),t(_,Z),t(g,Ct),u(l,Ut,r),ee(E,l,r),u(l,jt,r),u(l,H,r),u(l,at,r),u(l,S,r),t(S,tt),t(S,se),t(S,G),t(G,U),t(U,ne),t(U,rt),t(rt,et),t(U,kt),t(S,oe),y&&y.m(S,null),u(l,ct,r),u(l,dt,r),u(l,lt,r),u(l,N,r),t(N,zt),t(N,yt),t(N,v),t(v,st),t(v,vt),t(v,Jt),t(v,Ft),t(v,j),t(j,nt),t(j,Lt),t(j,Kt),t(j,At),t(j,L),t(L,ft),t(L,Tt),t(L,ie),t(L,pt),t(L,ae),t(L,D),t(L,Pt),ee(ot,L,null),t(L,St),t(L,R),t(R,ut),t(R,re),t(R,z),t(R,Rt),t(R,Qt),t(R,Ot);for(let C=0;C<T.length;C+=1)T[C]&&T[C].m(R,null);t(v,ce),t(v,q),t(q,Vt),t(q,J),t(q,mt),t(q,de),t(q,I),t(I,fe),ee(B,I,null),t(I,pe),ee(P,I,null),t(v,Et),t(v,K),t(K,bt),t(K,ue),t(K,ht),t(K,me),t(K,$),t($,Nt),ee(it,$,null),t($,qt),t($,be),t($,Mt),t($,Wt),t($,Q),t($,_t),t($,he),t($,Ht),t($,_e),t($,wt),t($,we),t(v,V),t(v,xt),t(v,xe),t(v,gt),u(l,Xt,r),u(l,W,r),u(l,Yt,r),u(l,A,r),t(A,X);for(let C=0;C<O.length;C+=1)O[C]&&O[C].m(X,null);t(A,ge),t(A,Y);for(let C=0;C<F.length;C+=1)F[C]&&F[C].m(Y,null);k=!0},p(l,[r]){var Ne,qe,Me,He,De,Ie;(!k||r&1)&&a!==(a=l[0].name+"")&&$e(p,a),(!k||r&1)&&f!==(f=l[0].name+"")&&$e(Z,f);const C={};if(r&9&&(C.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${l[3]}');
...
// fetch a paginated records list
const resultList = await pb.collection('${(Ne=l[0])==null?void 0:Ne.name}').getList(1, 50, {
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
});
// you can also fetch all records at once via getFullList
const records = await pb.collection('${(qe=l[0])==null?void 0:qe.name}').getFullList({
sort: '-created',
});
// or fetch only the first record that matches the specified filter
const record = await pb.collection('${(Me=l[0])==null?void 0:Me.name}').getFirstListItem('someField="test"', {
expand: 'relField1,relField2.subRelField',
});
`),r&9&&(C.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${l[3]}');
...
// fetch a paginated records list
final resultList = await pb.collection('${(He=l[0])==null?void 0:He.name}').getList(
page: 1,
perPage: 50,
filter: 'created >= "2022-01-01 00:00:00" && someField1 != someField2',
);
// you can also fetch all records at once via getFullList
final records = await pb.collection('${(De=l[0])==null?void 0:De.name}').getFullList(
sort: '-created',
);
// or fetch only the first record that matches the specified filter
final record = await pb.collection('${(Ie=l[0])==null?void 0:Ie.name}').getFirstListItem(
'someField="test"',
expand: 'relField1,relField2.subRelField',
);
`),E.$set(C),(!k||r&1)&&$t!==($t=l[0].name+"")&&$e(et,$t),l[1]?y||(y=Qe(),y.c(),y.m(S,null)):y&&(y.d(1),y=null),r&16){Zt=l[4];let M;for(M=0;M<Zt.length;M+=1){const Be=Ke(l,Zt,M);T[M]?T[M].p(Be,r):(T[M]=Ve(Be),T[M].c(),T[M].m(R,null))}for(;M<T.length;M+=1)T[M].d(1);T.length=Zt.length}r&36&&(ke=l[5],O=Ue(O,r,Le,1,l,ke,Dt,X,sl,We,null,Je)),r&36&&(Ce=l[5],nl(),F=Ue(F,r,Ae,1,l,Ce,It,Y,ol,Xe,null,ze),il())},i(l){if(!k){Bt(E.$$.fragment,l),Bt(ot.$$.fragment,l),Bt(B.$$.fragment,l),Bt(P.$$.fragment,l),Bt(it.$$.fragment,l);for(let r=0;r<Ce.length;r+=1)Bt(F[r]);k=!0}},o(l){Gt(E.$$.fragment,l),Gt(ot.$$.fragment,l),Gt(B.$$.fragment,l),Gt(P.$$.fragment,l),Gt(it.$$.fragment,l);for(let r=0;r<F.length;r+=1)Gt(F[r]);k=!1},d(l){l&&m(n),l&&m(d),l&&m(h),l&&m(Ut),le(E,l),l&&m(jt),l&&m(H),l&&m(at),l&&m(S),y&&y.d(),l&&m(ct),l&&m(dt),l&&m(lt),l&&m(N),le(ot),al(T,l),le(B),le(P),le(it),l&&m(Xt),l&&m(W),l&&m(Yt),l&&m(A);for(let r=0;r<O.length;r+=1)O[r].d();for(let r=0;r<F.length;r+=1)F[r].d()}}}function _l(c,n,o){let a,p,b,{collection:d=new rl}=n,h=200,g=[];const w=_=>o(2,h=_.code);return c.$$set=_=>{"collection"in _&&o(0,d=_.collection)},c.$$.update=()=>{c.$$.dirty&1&&o(4,a=ye.getAllCollectionIdentifiers(d)),c.$$.dirty&1&&o(1,p=(d==null?void 0:d.listRule)===null),c.$$.dirty&3&&d!=null&&d.id&&(g.push({code:200,body:JSON.stringify({page:1,perPage:30,totalPages:1,totalItems:2,items:[ye.dummyCollectionRecord(d),ye.dummyCollectionRecord(d)]},null,2)}),g.push({code:400,body:`
{
"code": 400,
"message": "Something went wrong while processing your request. Invalid filter.",
"data": {}
}
`}),p&&g.push({code:403,body:`
{
"code": 403,
"message": "Only admins can access this action.",
"data": {}
}
`}))},o(3,b=ye.getApiExampleUrl(cl.baseUrl)),[d,p,h,b,a,g,w]}class gl extends Ye{constructor(n){super(),Ze(this,n,_l,hl,tl,{collection:0})}}export{gl as default};

Some files were not shown because too many files have changed in this diff Show More