Compare commits

...
Author SHA1 Message Date
Gani Georgiev 4adc4b28d2 updated changelog 2024-11-14 17:19:27 +02:00
Gani Georgiev c5554e22e0 refresh the old collections in the UI import on successful import submission 2024-11-14 16:48:41 +02:00
Gani Georgiev 846136dcfb restored mfa ErrNoRows check 2024-11-13 20:24:52 +02:00
Gani Georgiev bc378d33f6 updated go deps 2024-11-13 20:15:15 +02:00
Gani Georgiev cc833ad643 updated mfa defaults and errors check 2024-11-13 20:14:27 +02:00
Gani Georgiev 396aa0f97c always load the full record on record view 2024-11-13 19:55:33 +02:00
Gani Georgiev 9f606bdeca otp changes - added sentTo field, allow e.Record to be nil when requesting OTP, etc. 2024-11-13 18:34:43 +02:00
Gani Georgiev 10a5c685ab removed the dynamic dashboard path option as it could complicate unnecessary too many things (oauth2 redirects, default email templates, etc.) 2024-11-12 12:32:26 +02:00
Gani Georgiev 1ca90e5e8b fixed typo 2024-11-11 16:24:46 +02:00
Gani Georgiev db57572a54 lowered the max field id and name length limit to 100 2024-11-11 16:18:24 +02:00
Gani Georgiev 0af8f3cc66 updated go deps 2024-11-11 16:04:40 +02:00
Gani Georgievandtigawanna 438ecd88a0 [#5829] added WakaTime OAuth2 provider
Co-authored-by: tigawanna <denniskinuthiawaweru@gmail.com>
2024-11-11 16:03:46 +02:00
Gani Georgiev 45628a919f added search filter and sort limits 2024-11-11 14:58:43 +02:00
Gani Georgiev fc133d8665 fixed settings test and error typo 2024-11-11 14:25:21 +02:00
Gani Georgiev 5e6d4d2126 added rate limit helpers for future use 2024-11-11 14:24:54 +02:00
Gani Georgiev c38e7c36a6 added throttling on too many failed search attempts 2024-11-11 14:24:38 +02:00
Gani Georgiev a89960db71 aligned struct fields 2024-11-11 00:04:22 +02:00
Gani Georgiev 7119ff4716 renamed local field var 2024-11-11 00:03:25 +02:00
Gani Georgiev 339399b0a4 updated otp manual rate limiter 2024-11-09 12:24:46 +02:00
Gani Georgiev 9cb6adab4d added superuser otp command 2024-11-08 18:04:22 +02:00
Gani Georgiev f6aef4471d added RateLimitRule.Audience field 2024-11-08 18:04:13 +02:00
Gani Georgiev 0e56521e8a fixed rc10 migration 2024-11-08 09:43:57 +02:00
Gani Georgiev 4f8f320280 updated changelog 2024-11-07 14:15:56 +02:00
Gani GeorgievandPedro Costa 0daa584461 [#5588] replaced deprecated Instagram Basic Display provider with a new Instagram Login
Co-authored-by: Pedro Costa <550684+pnmcosta@users.noreply.github.com>
2024-11-07 13:51:21 +02:00
Gani Georgiev 57f615a58c added default users collection rules 2024-11-07 13:24:08 +02:00
Gani Georgiev 1bd0baf328 updated v0.22.x changelog 2024-11-07 13:00:29 +02:00
Gani Georgiev 6694215909 updated changelog 2024-11-06 20:25:34 +02:00
Gani Georgiev 241a81e1fc updated installer note 2024-11-06 20:06:34 +02:00
Gani Georgiev bed45beb13 updated comments and pass the dashboard path into the installer 2024-11-06 19:19:16 +02:00
Gani Georgiev e4cd6810ab always register the installer hooks in case the superuser is created by a console command 2024-11-06 14:23:16 +02:00
Gani Georgiev f38700982c removed RequestEvent.UnsafeRealIP 2024-11-05 21:49:45 +02:00
Gani Georgiev 9506669095 refactored installer and removed RequireSuperuserAuthOnlyIfAny 2024-11-05 21:12:17 +02:00
Gani Georgiev 4f67dba6cb [#5800] skip default loadAuthToken middleware if e.Auth is already set 2024-11-05 09:08:52 +02:00
Gani Georgiev 47354f5aa9 updated jsvm types 2024-11-05 00:16:20 +02:00
Gani Georgiev 2f35ef29fe [#5797] fixed JSVM types errors 2024-11-05 00:06:48 +02:00
Gani Georgiev 755149c915 [#5793] added subscriptions.Broker.TotalClients() method 2024-11-04 19:19:06 +02:00
Gani Georgiev f9a2d6c6ae updated ui/dist 2024-11-04 19:08:21 +02:00
Gani Georgiev 9e70c77736 added migration to normalize the system collection and field ids 2024-11-04 19:03:33 +02:00
Gani Georgiev b3d88349d7 updated superusers test tokens with the new id 2024-11-04 15:48:28 +02:00
Gani Georgiev 8d0e4a0460 restore crc32 checksum for the colelction and field ids 2024-11-04 10:51:32 +02:00
134 changed files with 6723 additions and 5549 deletions
+68
View File
@@ -1,3 +1,69 @@
## v0.23.0-rc13
> [!CAUTION]
> **This is a prerelease intended for test and experimental purposes only!**
- Added WakaTime OAuth2 provider ([#5829](https://github.com/pocketbase/pocketbase/pull/5829); thanks @tigawanna).
- Added `superuser otp EMAIL` command as fallback for generating superuser OTPs from the command line in case OTP has been enabled for the `_superusers` but the SMTP server has deliverability issues.
- ⚠️ Changed `OnRecordRequestOTPRequest` hook to be triggered even if there is no record matching the email (aka. `e.Record` could be `nil`), allowing you to manually create a new user with the OTP request and assigning it to `e.Record`.
- Added new `sentTo` system field to the `_otps` collection (it is managed programmatically or by superusers; it could be anything - email, phone, messanger app id, etc.).
By default when the OTP is submitted via email it is automatically populated with the user email address (via the `OnMailerRecordOTPSend` hook's finalizer).
This allow us on valid `auth-with-otp` request to automatically mark the user email as verified.
- Added `RateLimitRule.Audience` optional field for restricting a rate limit rule for `"@guest"`-only, `"@auth"`-only, `""`-any (default).
- Added default max limits for the expressions count and length of the search filter and sort params.
_This is just an extra measure mostly for the case when the filter and sort parameters are resolved outside of the request context since the request size limits won't apply._
- Other minor changes (better error in case of duplicated rate limit rule, fixed typos, changed field id and name length validator to max 100, updated Go deps, etc.).
## v0.23.0-rc12
> [!CAUTION]
> **This is a prerelease intended for test and experimental purposes only!**
- Fixed validation error caused by the id change in v0.23.0-rc10 migration ([#5820](https://github.com/pocketbase/pocketbase/discussions/5820)).
## v0.23.0-rc11
> [!CAUTION]
> **This is a prerelease intended for test and experimental purposes only!**
- Fixed JSVM types errors ([#5797](https://github.com/pocketbase/pocketbase/issues/5797)).
- Skip the default `loadAuthToken` middleware if `e.Auth` is already loaded ([#5800](https://github.com/pocketbase/pocketbase/discussions/5800)).
- Restored the API rules for the default initial "users" collection migration to be the same as in <= v0.22.x.
- ⚠️ Replaced the old Instagram provider with a new one that is compatible with the new Instagram Login APIs ([#5588](https://github.com/pocketbase/pocketbase/pull/5588); thanks @pnmcosta).
_The provider key is `instagram2` to prevent conflicts with existing linked users._
- ⚠️ Changes regarding the first superuser creation based on [#5814](https://github.com/pocketbase/pocketbase/discussions/5814).
- ⚠️ Removed `apis.RequireSuperuserAuthOnlyIfAny()` middleware.
- ⚠️ Removed `RequestEvent.UnsafeRealIP()` to prevent misuse and confusion with `RequestEvent.RealIP()` (_the latter is considered safer because it checks the trusted proxy headers settings_).
## v0.23.0-rc10
> [!CAUTION]
> **This is a prerelease intended for test and experimental purposes only!**
- Restore the CRC32 checksum autogeneration for the collection/field ids in order to maintain deterministic default identifier value and minimize conflicts between custom migrations and full collections snapshots.
_There is a system migration that will attempt to normalize existing system collections ids, but if you already migrated to v0.23.0-rc and have generated a full collections snapshot migration, you have to delete it and regenerate a new one._
- Change the behavior of the default generated collections snapshot migration to act as "extend" instead of "replace" to prevent accidental data deletion.
_I think this would be rare but if you want the old behaviour you can edit the generated snapshot file and replace the second argument (`deleteMissing`) of `App.ImportCollection/App.ImportCollectionsByMarshaledJSON` from `false` to `true`._
- Added `app.SubscriptionsBroker().TotalClients()` helper method to return the total registered realtime clients ([#5793](https://github.com/pocketbase/pocketbase/issues/5793)).
## v0.23.0-rc9
> [!CAUTION]
@@ -299,6 +365,8 @@ For upgrading to PocketBase v0.23.0, please refer to:
- New `POST /api/collections/{collection}/impersonate/{id}` endpoint.
- ⚠️ Removed `/api/admins/*` endpoints because admins are converted to `_superusers` auth collection records.
- ⚠️ Previously when uploading new files to a multiple `file` field, new files were automatically appended to the existing field values.
This behaviour has changed with v0.23+ and for consistency with the other multi-valued fields when uploading new files they will replace the old ones. If you want to prepend or append new files to an existing multiple `file` field value you can use the `+` prefix or suffix:
```js
+14
View File
@@ -2,6 +2,20 @@
> For the most recent versions, please refer to [CHANGELOG.md](./CHANGELOG.md)
---
## v0.22.24
- Delete new uploaded record files in case of DB persist error ([#5845](https://github.com/pocketbase/pocketbase/issues/5845)).
## v0.22.23
- Updated the hooks watcher to account for the case when hooksDir is a symlink ([#5789](https://github.com/pocketbase/pocketbase/issues/5789)).
- _(Backported from v0.23.0-rc)_ Registered a default `http.Server.ErrorLog` handler to report general server connection errors as app Debug level logs (e.g. invalid TLS handshakes caused by bots trying to access your server via its IP or other similar errors).
- Other minor fixes (updated npm dev deps to fix the vulnerabilities warning, added more user friendly realtime topic length error, regenerated JSVM types, etc.)
## v0.22.22
- Added deprecation log in case Instagram OAuth2 is used (_related to [#5652](https://github.com/pocketbase/pocketbase/discussions/5652)_).
+2 -2
View File
@@ -18,10 +18,10 @@ func bindBackupApi(app core.App, rg *router.RouterGroup[*core.RequestEvent]) {
sub := rg.Group("/backups")
sub.GET("", backupsList).Bind(RequireSuperuserAuth())
sub.POST("", backupCreate).Bind(RequireSuperuserAuth())
sub.POST("/upload", backupUpload).Bind(RequireSuperuserAuthOnlyIfAny())
sub.POST("/upload", backupUpload).Bind(RequireSuperuserAuth())
sub.GET("/{key}", backupDownload) // relies on superuser file token
sub.DELETE("/{key}", backupDelete).Bind(RequireSuperuserAuth())
sub.POST("/{key}/restore", backupRestore).Bind(RequireSuperuserAuthOnlyIfAny())
sub.POST("/{key}/restore", backupRestore).Bind(RequireSuperuserAuth())
}
type backupFileInfo struct {
+21 -64
View File
@@ -53,7 +53,7 @@ func TestBackupsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/backups",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{`[]`},
@@ -64,7 +64,7 @@ func TestBackupsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/backups",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -120,7 +120,7 @@ func TestBackupsCreate(t *testing.T) {
Method: http.MethodPost,
URL: "/api/backups",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.Store().Set(core.StoreKeyActiveBackup, "")
@@ -137,7 +137,7 @@ func TestBackupsCreate(t *testing.T) {
Method: http.MethodPost,
URL: "/api/backups",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
files, err := getBackupFiles(app)
@@ -166,7 +166,7 @@ func TestBackupsCreate(t *testing.T) {
URL: "/api/backups",
Body: strings.NewReader(`{"name":"!test.zip"}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
@@ -184,7 +184,7 @@ func TestBackupsCreate(t *testing.T) {
URL: "/api/backups",
Body: strings.NewReader(`{"name":"test.zip"}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
files, err := getBackupFiles(app)
@@ -289,7 +289,7 @@ func TestBackupUpload(t *testing.T) {
Method: http.MethodPost,
URL: "/api/backups/upload",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
ensureNoBackups(t, app)
@@ -305,7 +305,7 @@ func TestBackupUpload(t *testing.T) {
Body: bodies[3].buffer,
Headers: map[string]string{
"Content-Type": bodies[3].contentType,
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
fsys, err := app.NewBackupsFilesystem()
@@ -335,31 +335,7 @@ func TestBackupUpload(t *testing.T) {
Body: bodies[4].buffer,
Headers: map[string]string{
"Content-Type": bodies[4].contentType,
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
},
AfterTestFunc: func(t testing.TB, 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,
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "unauthorized with 0 superusers (valid file)",
Method: http.MethodPost,
URL: "/api/backups/upload",
Body: bodies[5].buffer,
Headers: map[string]string{
"Content-Type": bodies[5].contentType,
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
// delete all superusers
_, err := app.DB().NewQuery("DELETE FROM {{" + core.CollectionNameSuperusers + "}}").Execute()
if err != nil {
t.Fatal(err)
}
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
files, _ := getBackupFiles(app)
@@ -415,7 +391,7 @@ func TestBackupsDownload(t *testing.T) {
Method: http.MethodGet,
URL: "/api/backups/test1.zip",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -468,7 +444,7 @@ func TestBackupsDownload(t *testing.T) {
{
Name: "with valid superuser auth token",
Method: http.MethodGet,
URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
t.Fatal(err)
@@ -481,7 +457,7 @@ func TestBackupsDownload(t *testing.T) {
{
Name: "with expired superuser file token",
Method: http.MethodGet,
URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MTY0MDk5MTY2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJfcGJjXzMzMjM4NjYzMzkifQ.hTNDzikwJdcoWrLnRnp7xbaifZ2vuYZ0oOYRHtJfnk4",
URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MTY0MDk5MTY2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.nqqtqpPhxU0045F4XP_ruAkzAidYBc5oPy9ErN3XBq0",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
t.Fatal(err)
@@ -494,7 +470,7 @@ func TestBackupsDownload(t *testing.T) {
{
Name: "with valid superuser file token but missing backup name",
Method: http.MethodGet,
URL: "/api/backups/missing?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJfcGJjXzMzMjM4NjYzMzkifQ.C8m3aRZNOxUDhMiuZuDTRIIjRl7wsOyzoxs8EjvKNgY",
URL: "/api/backups/missing?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
t.Fatal(err)
@@ -507,7 +483,7 @@ func TestBackupsDownload(t *testing.T) {
{
Name: "with valid superuser file token",
Method: http.MethodGet,
URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJfcGJjXzMzMjM4NjYzMzkifQ.C8m3aRZNOxUDhMiuZuDTRIIjRl7wsOyzoxs8EjvKNgY",
URL: "/api/backups/test1.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
t.Fatal(err)
@@ -524,7 +500,7 @@ func TestBackupsDownload(t *testing.T) {
{
Name: "with valid superuser file token and backup name with escaped char",
Method: http.MethodGet,
URL: "/api/backups/%40test4.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJfcGJjXzMzMjM4NjYzMzkifQ.C8m3aRZNOxUDhMiuZuDTRIIjRl7wsOyzoxs8EjvKNgY",
URL: "/api/backups/%40test4.zip?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
t.Fatal(err)
@@ -601,7 +577,7 @@ func TestBackupsDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/backups/missing.zip",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -620,7 +596,7 @@ func TestBackupsDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/backups/test1.zip",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -642,7 +618,7 @@ func TestBackupsDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/backups/test1.zip",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -678,7 +654,7 @@ func TestBackupsDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/backups/%40test4.zip",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -751,7 +727,7 @@ func TestBackupsRestore(t *testing.T) {
Method: http.MethodPost,
URL: "/api/backups/missing.zip/restore",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -767,7 +743,7 @@ func TestBackupsRestore(t *testing.T) {
Method: http.MethodPost,
URL: "/api/backups/test1.zip/restore",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := createTestBackups(app); err != nil {
@@ -780,25 +756,6 @@ func TestBackupsRestore(t *testing.T) {
ExpectedContent: []string{`"data":{}`},
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "unauthorized with no superusers (checks only access)",
Method: http.MethodPost,
URL: "/api/backups/missing.zip/restore",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
// delete all superusers
_, err := app.DB().NewQuery("DELETE FROM {{" + core.CollectionNameSuperusers + "}}").Execute()
if err != nil {
t.Fatal(err)
}
if err := createTestBackups(app); err != nil {
t.Fatal(err)
}
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
ExpectedEvents: map[string]int{"*": 0},
},
}
for _, scenario := range scenarios {
+10 -10
View File
@@ -360,8 +360,8 @@ func TestBatchRequest(t *testing.T) {
Method: http.MethodPost,
URL: "/api/batch",
Headers: map[string]string{
// test@example.com, superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
// test@example.com, _superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: strings.NewReader(`{
"requests": [
@@ -431,8 +431,8 @@ func TestBatchRequest(t *testing.T) {
Method: http.MethodPost,
URL: "/api/batch",
Headers: map[string]string{
// test@example.com, superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
// test@example.com, _superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: strings.NewReader(`{
"requests": [
@@ -494,8 +494,8 @@ func TestBatchRequest(t *testing.T) {
]
}`),
Headers: map[string]string{
// test@example.com, superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
// test@example.com, _superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.Settings().Batch.Timeout = 1
@@ -620,8 +620,8 @@ func TestBatchRequest(t *testing.T) {
Method: http.MethodPost,
URL: "/api/batch",
Headers: map[string]string{
// test@example.com, superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
// test@example.com, _superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: strings.NewReader(`{
"requests": [
@@ -667,8 +667,8 @@ func TestBatchRequest(t *testing.T) {
Method: http.MethodPost,
URL: "/api/batch",
Headers: map[string]string{
// test@example.com, superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
// test@example.com, _superusers
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: strings.NewReader(`{
"requests": [
+4 -4
View File
@@ -40,7 +40,7 @@ func TestCollectionsImport(t *testing.T) {
URL: "/api/collections/import",
Body: strings.NewReader(`{"collections":[]}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -79,7 +79,7 @@ func TestCollectionsImport(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -145,7 +145,7 @@ func TestCollectionsImport(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
@@ -199,7 +199,7 @@ func TestCollectionsImport(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
+46 -46
View File
@@ -42,7 +42,7 @@ func TestCollectionsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -80,7 +80,7 @@ func TestCollectionsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections?page=2&perPage=2&sort=-created",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -100,7 +100,7 @@ func TestCollectionsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections?filter=invalidfield~'demo2'",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -111,7 +111,7 @@ func TestCollectionsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections?filter=name~'demo'",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -165,7 +165,7 @@ func TestCollectionView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/missing",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
@@ -176,7 +176,7 @@ func TestCollectionView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/demo1",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -193,7 +193,7 @@ func TestCollectionView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/wsmn24bux7wo113",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -249,7 +249,7 @@ func TestCollectionDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/missing",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
@@ -260,7 +260,7 @@ func TestCollectionDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/demo5",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Delay: 100 * time.Millisecond,
ExpectedStatus: 204,
@@ -283,7 +283,7 @@ func TestCollectionDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/9n89pl5vkct6330",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Delay: 100 * time.Millisecond,
ExpectedStatus: 204,
@@ -306,7 +306,7 @@ func TestCollectionDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/" + core.CollectionNameMFAs,
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -326,7 +326,7 @@ func TestCollectionDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/demo2",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -346,7 +346,7 @@ func TestCollectionDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/view2",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
@@ -365,7 +365,7 @@ func TestCollectionDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/view2",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.OnCollectionDeleteRequest().BindFunc(func(e *core.CollectionRequestEvent) error {
@@ -416,7 +416,7 @@ func TestCollectionCreate(t *testing.T) {
URL: "/api/collections",
Body: strings.NewReader(``),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -443,7 +443,7 @@ func TestCollectionCreate(t *testing.T) {
URL: "/api/collections",
Body: strings.NewReader(`{"name":"demo1","type":"base","fields":[{"type":"text","name":""}]}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -469,7 +469,7 @@ func TestCollectionCreate(t *testing.T) {
URL: "/api/collections",
Body: strings.NewReader(`{"name":"new","type":"base","fields":[{"type":"text","id":"12345789","name":"test"}]}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -507,7 +507,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -567,7 +567,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -603,7 +603,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -636,7 +636,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -661,7 +661,7 @@ func TestCollectionCreate(t *testing.T) {
URL: "/api/collections",
Body: strings.NewReader(`{"name":"new","type":"base"}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.OnCollectionCreateRequest().BindFunc(func(e *core.CollectionRequestEvent) error {
@@ -689,7 +689,7 @@ func TestCollectionCreate(t *testing.T) {
"viewQuery":"invalid"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -718,7 +718,7 @@ func TestCollectionCreate(t *testing.T) {
"viewQuery": "select 1 as id from ` + core.CollectionNameSuperusers + `"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -758,7 +758,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -793,7 +793,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
demo1, err := app.FindCollectionByNameOrId("demo1")
@@ -835,7 +835,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -870,7 +870,7 @@ func TestCollectionCreate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -945,7 +945,7 @@ func TestCollectionUpdate(t *testing.T) {
URL: "/api/collections/missing",
Body: strings.NewReader(`{}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
@@ -957,7 +957,7 @@ func TestCollectionUpdate(t *testing.T) {
URL: "/api/collections/demo1",
Body: strings.NewReader(`{}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -983,7 +983,7 @@ func TestCollectionUpdate(t *testing.T) {
URL: "/api/collections/demo1",
Body: strings.NewReader(`{}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.OnCollectionUpdateRequest().BindFunc(func(e *core.CollectionRequestEvent) error {
@@ -1006,7 +1006,7 @@ func TestCollectionUpdate(t *testing.T) {
"type":"auth"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1031,7 +1031,7 @@ func TestCollectionUpdate(t *testing.T) {
URL: "/api/collections/demo1",
Body: strings.NewReader(`{"name":"new"}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1073,7 +1073,7 @@ func TestCollectionUpdate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1109,7 +1109,7 @@ func TestCollectionUpdate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1135,7 +1135,7 @@ func TestCollectionUpdate(t *testing.T) {
"passwordAuth":{"identityFields": ["missing"]}
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1165,7 +1165,7 @@ func TestCollectionUpdate(t *testing.T) {
"viewQuery":"invalid"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1193,7 +1193,7 @@ func TestCollectionUpdate(t *testing.T) {
"viewQuery": "select 2 as id, created, updated, email from ` + core.CollectionNameSuperusers + `"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1232,7 +1232,7 @@ func TestCollectionUpdate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1261,7 +1261,7 @@ func TestCollectionUpdate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
demo1, err := app.FindCollectionByNameOrId("demo1")
@@ -1301,7 +1301,7 @@ func TestCollectionUpdate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1332,7 +1332,7 @@ func TestCollectionUpdate(t *testing.T) {
]
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1405,7 +1405,7 @@ func TestCollectionScaffolds(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/meta/scaffolds",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1457,7 +1457,7 @@ func TestCollectionTruncate(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/demo5/truncate",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
@@ -1475,7 +1475,7 @@ func TestCollectionTruncate(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/demo3/truncate",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -1500,7 +1500,7 @@ func TestCollectionTruncate(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/view2/truncate",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
-137
View File
@@ -1,137 +0,0 @@
package apis
import (
"fmt"
"net/http"
"regexp"
"strings"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/router"
)
const installerParam = "pbinstal"
var wildcardPlaceholderRegex = regexp.MustCompile(`/{.+\.\.\.}$`)
func stripWildcard(pattern string) string {
return wildcardPlaceholderRegex.ReplaceAllString(pattern, "")
}
// installerRedirect redirects the user to the installer dashboard UI page
// when the application needs some preliminary configurations to be done.
func installerRedirect(app core.App, cpPath string) func(*core.RequestEvent) error {
// note: to avoid locks contention it is not concurrent safe but it
// is expected to be updated only once during initialization
var hasSuperuser bool
// strip named wildcard
cpPath = stripWildcard(cpPath)
updateHasSuperuser := func(app core.App) error {
total, err := app.CountRecords(core.CollectionNameSuperusers)
if err != nil {
return err
}
hasSuperuser = total > 0
return nil
}
// load initial state on app init
app.OnBootstrap().BindFunc(func(e *core.BootstrapEvent) error {
err := e.Next()
if err != nil {
return err
}
err = updateHasSuperuser(e.App)
if err != nil {
return fmt.Errorf("failed to check for existing superuser: %w", err)
}
return nil
})
// update on superuser create
app.OnRecordCreateRequest(core.CollectionNameSuperusers).BindFunc(func(e *core.RecordRequestEvent) error {
err := e.Next()
if err != nil {
return err
}
if !hasSuperuser {
hasSuperuser = true
}
return nil
})
return func(e *core.RequestEvent) error {
if hasSuperuser {
return e.Next()
}
isAPI := strings.HasPrefix(e.Request.URL.Path, "/api/")
isControlPanel := strings.HasPrefix(e.Request.URL.Path, cpPath)
wildcard := e.Request.PathValue(StaticWildcardParam)
// skip redirect checks for API and non-root level dashboard index.html requests (css, images, etc.)
if isAPI || (isControlPanel && wildcard != "" && wildcard != router.IndexPage) {
return e.Next()
}
// check again in case the superuser was created by some other process
if err := updateHasSuperuser(e.App); err != nil {
return err
}
if hasSuperuser {
return e.Next()
}
_, hasInstallerParam := e.Request.URL.Query()[installerParam]
// redirect to the installer page
if !hasInstallerParam {
return e.Redirect(http.StatusTemporaryRedirect, cpPath+"?"+installerParam+"#")
}
return e.Next()
}
}
// dashboardRemoveInstallerParam redirects to a non-installer
// query param in case there is already a superuser created.
//
// Note: intended to be registered only for the dashboard route
// to prevent excessive checks for every other route in installerRedirect.
func dashboardRemoveInstallerParam() func(*core.RequestEvent) error {
return func(e *core.RequestEvent) error {
_, hasInstallerParam := e.Request.URL.Query()[installerParam]
if !hasInstallerParam {
return e.Next() // nothing to remove
}
// clear installer param
total, _ := e.App.CountRecords(core.CollectionNameSuperusers)
if total > 0 {
return e.Redirect(http.StatusTemporaryRedirect, "?")
}
return e.Next()
}
}
// dashboardCacheControl adds default Cache-Control header for all
// dashboard UI resources (ignoring the root index.html path)
func dashboardCacheControl() func(*core.RequestEvent) error {
return func(e *core.RequestEvent) error {
if e.Request.PathValue(StaticWildcardParam) != "" {
e.Response.Header().Set("Cache-Control", "max-age=1209600, stale-while-revalidate=86400")
}
return e.Next()
}
}
+4 -4
View File
@@ -49,7 +49,7 @@ func TestFileToken(t *testing.T) {
Method: http.MethodPost,
URL: "/api/files/token",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -65,7 +65,7 @@ func TestFileToken(t *testing.T) {
Method: http.MethodPost,
URL: "/api/files/token",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.OnFileTokenRequest().BindFunc(func(e *core.FileTokenRequestEvent) error {
@@ -273,7 +273,7 @@ func TestFileDownload(t *testing.T) {
{
Name: "protected file - superuser with expired file token",
Method: http.MethodGet,
URL: "/api/files/demo1/al1h9ijdeojtsjy/300_Jsjq7RdBgA.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MTY0MDk5MTY2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJfcGJjXzMzMjM4NjYzMzkifQ.hTNDzikwJdcoWrLnRnp7xbaifZ2vuYZ0oOYRHtJfnk4",
URL: "/api/files/demo1/al1h9ijdeojtsjy/300_Jsjq7RdBgA.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MTY0MDk5MTY2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.nqqtqpPhxU0045F4XP_ruAkzAidYBc5oPy9ErN3XBq0",
ExpectedStatus: 404,
ExpectedContent: []string{`"data":{}`},
ExpectedEvents: map[string]int{"*": 0},
@@ -281,7 +281,7 @@ func TestFileDownload(t *testing.T) {
{
Name: "protected file - superuser with valid file token",
Method: http.MethodGet,
URL: "/api/files/demo1/al1h9ijdeojtsjy/300_Jsjq7RdBgA.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJfcGJjXzMzMjM4NjYzMzkifQ.C8m3aRZNOxUDhMiuZuDTRIIjRl7wsOyzoxs8EjvKNgY",
URL: "/api/files/demo1/al1h9ijdeojtsjy/300_Jsjq7RdBgA.png?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc",
ExpectedStatus: 200,
ExpectedContent: []string{"PNG"},
ExpectedEvents: map[string]int{
+1 -1
View File
@@ -51,7 +51,7 @@ func TestHealthAPI(t *testing.T) {
Method: http.MethodGet,
URL: "/api/health",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
+94
View File
@@ -0,0 +1,94 @@
package apis
import (
"database/sql"
"errors"
"fmt"
"os"
"os/exec"
"runtime"
"strings"
"time"
"github.com/fatih/color"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/security"
)
// @todo consider combining with the installer specific hooks after refactoring cmd
func loadInstaller(app core.App, dashboardURL string) error {
if !needInstallerSuperuser(app) {
return nil
}
installerRecord, err := findOrCreateInstallerSuperuser(app)
if err != nil {
return err
}
token, err := installerRecord.NewStaticAuthToken(30 * time.Minute)
if err != nil {
return err
}
// launch url (ignore errors and always print a help text as fallback)
url := fmt.Sprintf("%s/#/pbinstal/%s", strings.TrimRight(dashboardURL, "/"), token)
_ = launchURL(url)
color.Magenta("\n(!) Launch the URL below in the browser if it hasn't been open already to create your first superuser account:")
color.New(color.Bold).Add(color.FgCyan).Println(url)
color.New(color.FgHiBlack, color.Italic).Printf("(you can also create your first superuser by running: %s superuser upsert EMAIL PASS)\n\n", os.Args[0])
return nil
}
func needInstallerSuperuser(app core.App) bool {
total, err := app.CountRecords(core.CollectionNameSuperusers, dbx.Not(dbx.HashExp{
"email": core.DefaultInstallerEmail,
}))
return err == nil && total == 0
}
func findOrCreateInstallerSuperuser(app core.App) (*core.Record, error) {
col, err := app.FindCachedCollectionByNameOrId(core.CollectionNameSuperusers)
if err != nil {
return nil, err
}
record, err := app.FindAuthRecordByEmail(col, core.DefaultInstallerEmail)
if err != nil {
if !errors.Is(err, sql.ErrNoRows) {
return nil, err
}
record = core.NewRecord(col)
record.SetEmail(core.DefaultInstallerEmail)
record.SetPassword(security.RandomString(30))
err = app.Save(record)
if err != nil {
return nil, err
}
}
return record, nil
}
func launchURL(url string) error {
if err := is.URL.Validate(url); err != nil {
return err
}
switch runtime.GOOS {
case "darwin":
return exec.Command("open", url).Start()
case "windows":
// not sure if this is the best command but seems to be the most reliable based on the comments in
// https://stackoverflow.com/questions/3739327/launching-a-website-via-the-windows-commandline#answer-49115945
return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
default: // linux, freebsd, etc.
return exec.Command("xdg-open", url).Start()
}
}
+6 -6
View File
@@ -36,7 +36,7 @@ func TestLogsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/logs",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubLogsData(app); err != nil {
@@ -59,7 +59,7 @@ func TestLogsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/logs?filter=data.status>200",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubLogsData(app); err != nil {
@@ -111,7 +111,7 @@ func TestLogView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/logs/missing1-9f38-44fb-bf82-c8f53b310d91",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubLogsData(app); err != nil {
@@ -127,7 +127,7 @@ func TestLogView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/logs/873f2133-9f38-44fb-bf82-c8f53b310d91",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubLogsData(app); err != nil {
@@ -175,7 +175,7 @@ func TestLogsStats(t *testing.T) {
Method: http.MethodGet,
URL: "/api/logs/stats",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubLogsData(app); err != nil {
@@ -192,7 +192,7 @@ func TestLogsStats(t *testing.T) {
Method: http.MethodGet,
URL: "/api/logs/stats?filter=data.status>200",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubLogsData(app); err != nil {
+9 -36
View File
@@ -48,7 +48,6 @@ const (
DefaultRequireGuestOnlyMiddlewareId = "pbRequireGuestOnly"
DefaultRequireAuthMiddlewareId = "pbRequireAuth"
DefaultRequireSuperuserAuthMiddlewareId = "pbRequireSuperuserAuth"
DefaultRequireSuperuserAuthOnlyIfAnyMiddlewareId = "pbRequireSuperuserAuthOnlyIfAny"
DefaultRequireSuperuserOrOwnerAuthMiddlewareId = "pbRequireSuperuserOrOwnerAuth"
DefaultRequireSameCollectionContextAuthMiddlewareId = "pbRequireSameCollectionContextAuth"
)
@@ -110,31 +109,6 @@ func RequireSuperuserAuth() *hook.Handler[*core.RequestEvent] {
}
}
// RequireSuperuserAuthOnlyIfAny middleware requires a request to have
// a valid superuser Authorization header ONLY if the application has
// at least 1 existing superuser.
func RequireSuperuserAuthOnlyIfAny() *hook.Handler[*core.RequestEvent] {
return &hook.Handler[*core.RequestEvent]{
Id: DefaultRequireSuperuserAuthOnlyIfAnyMiddlewareId,
Func: func(e *core.RequestEvent) error {
if e.HasSuperuserAuth() {
return e.Next()
}
totalSuperusers, err := e.App.CountRecords(core.CollectionNameSuperusers)
if err != nil {
return e.InternalServerError("Failed to fetch superusers info.", err)
}
if totalSuperusers == 0 {
return e.Next()
}
return requireAuth(core.CollectionNameSuperusers)(e)
},
}
}
// RequireSuperuserOrOwnerAuth middleware requires a request to have
// a valid superuser or regular record owner Authorization header set.
//
@@ -196,7 +170,9 @@ func RequireSameCollectionContextAuth(collectionPathParam string) *hook.Handler[
// loadAuthToken attempts to load the auth context based on the "Authorization: TOKEN" header value.
//
// This middleware does nothing in case of missing, invalid or expired token.
// This middleware does nothing in case of:
// - missing, invalid or expired token
// - e.Auth is already loaded by another middleware
//
// This middleware is registered by default for all routes.
//
@@ -207,6 +183,11 @@ func loadAuthToken() *hook.Handler[*core.RequestEvent] {
Id: DefaultLoadAuthTokenMiddlewareId,
Priority: DefaultLoadAuthTokenMiddlewarePriority,
Func: func(e *core.RequestEvent) error {
// already loaded by another middleware
if e.Auth != nil {
return e.Next()
}
token := getAuthTokenFromRequest(e)
if token == "" {
return e.Next()
@@ -416,17 +397,9 @@ func logRequest(event *core.RequestEvent, err error) {
}
if event.App.Settings().Logs.LogIP {
var userIP string
if len(event.App.Settings().TrustedProxy.Headers) > 0 {
userIP = event.RealIP()
} else {
// fallback to the legacy behavior (it is "safe" since it is only for log purposes)
userIP = cutStr(event.UnsafeRealIP(), 50)
}
attrs = append(
attrs,
slog.String("userIP", userIP),
slog.String("userIP", event.RealIP()),
slog.String("remoteIP", event.RemoteIP()),
)
}
+45 -1
View File
@@ -104,8 +104,43 @@ func checkCollectionRateLimit(e *core.RequestEvent, collection *core.Collection,
// -------------------------------------------------------------------
// @todo consider exporting as RateLimit helper?
// @todo consider exporting as helper?
//
//nolint:unused
func isClientRateLimited(e *core.RequestEvent, rtId string) bool {
rateLimiters, ok := e.App.Store().Get(rateLimitersStoreKey).(*store.Store[*rateLimiter])
if !ok || rateLimiters == nil {
return false
}
rt, ok := rateLimiters.GetOk(rtId)
if !ok || rt == nil {
return false
}
client, ok := rt.getClient(e.RealIP())
if !ok || client == nil {
return false
}
return client.available <= 0 && time.Now().Unix()-client.lastConsume < client.interval
}
// @todo consider exporting as helper?
func checkRateLimit(e *core.RequestEvent, rtId string, rule core.RateLimitRule) error {
switch rule.Audience {
case core.RateLimitRuleAudienceAll:
// valid for both guest and regular users
case core.RateLimitRuleAudienceGuest:
if e.Auth != nil {
return nil
}
case core.RateLimitRuleAudienceAuth:
if e.Auth == nil {
return nil
}
}
rateLimiters := e.App.Store().GetOrSet(rateLimitersStoreKey, func() any {
return initRateLimitersStore(e.App)
}).(*store.Store[*rateLimiter])
@@ -199,6 +234,15 @@ type rateLimiter struct {
sync.RWMutex
}
//nolint:unused
func (rt *rateLimiter) getClient(key string) (*fixedWindow, bool) {
rt.RLock()
client, ok := rt.clients[key]
rt.RUnlock()
return client, ok
}
func (rt *rateLimiter) isAllowed(key string) bool {
// lock only reads to minimize locks contention
rt.RLock()
+76 -20
View File
@@ -31,6 +31,18 @@ func TestDefaultRateLimitMiddleware(t *testing.T) {
MaxRequests: 1,
Duration: 1,
},
{
Label: "/rate/guest",
MaxRequests: 1,
Duration: 1,
Audience: core.RateLimitRuleAudienceGuest,
},
{
Label: "/rate/auth",
MaxRequests: 1,
Duration: 1,
Audience: core.RateLimitRuleAudienceAuth,
},
}
pbRouter, err := apis.NewRouter(app)
@@ -48,6 +60,12 @@ func TestDefaultRateLimitMiddleware(t *testing.T) {
pbRouter.GET("/rate/b", func(e *core.RequestEvent) error {
return e.String(200, "b")
})
pbRouter.GET("/rate/guest", func(e *core.RequestEvent) error {
return e.String(200, "guest")
})
pbRouter.GET("/rate/auth", func(e *core.RequestEvent) error {
return e.String(200, "auth")
})
mux, err := pbRouter.BuildMux()
if err != nil {
@@ -57,30 +75,53 @@ func TestDefaultRateLimitMiddleware(t *testing.T) {
scenarios := []struct {
url string
wait float64
authenticated bool
expectedStatus int
}{
{"/norate", 0, 200},
{"/norate", 0, 200},
{"/norate", 0, 200},
{"/norate", 0, 200},
{"/norate", 0, 200},
{"/norate", 0, false, 200},
{"/norate", 0, false, 200},
{"/norate", 0, false, 200},
{"/norate", 0, false, 200},
{"/norate", 0, false, 200},
{"/rate/a", 0, 200},
{"/rate/a", 0, 200},
{"/rate/a", 0, 429},
{"/rate/a", 0, 429},
{"/rate/a", 1.1, 200},
{"/rate/a", 0, 200},
{"/rate/a", 0, 429},
{"/rate/a", 0, false, 200},
{"/rate/a", 0, false, 200},
{"/rate/a", 0, false, 429},
{"/rate/a", 0, false, 429},
{"/rate/a", 1.1, false, 200},
{"/rate/a", 0, false, 200},
{"/rate/a", 0, false, 429},
{"/rate/b", 0, 200},
{"/rate/b", 0, 200},
{"/rate/b", 0, 200},
{"/rate/b", 0, 429},
{"/rate/b", 1.1, 200},
{"/rate/b", 0, 200},
{"/rate/b", 0, 200},
{"/rate/b", 0, 429},
{"/rate/b", 0, false, 200},
{"/rate/b", 0, false, 200},
{"/rate/b", 0, false, 200},
{"/rate/b", 0, false, 429},
{"/rate/b", 1.1, false, 200},
{"/rate/b", 0, false, 200},
{"/rate/b", 0, false, 200},
{"/rate/b", 0, false, 429},
// "auth" with guest (should be ignored)
{"/rate/auth", 0, false, 200},
{"/rate/auth", 0, false, 200},
{"/rate/auth", 0, false, 200},
{"/rate/auth", 0, false, 200},
// "auth" rule with regular user
{"/rate/auth", 0, true, 200},
{"/rate/auth", 0, true, 429},
{"/rate/auth", 0, true, 429},
// "guest" with guest
{"/rate/guest", 0, false, 200},
{"/rate/guest", 0, false, 429},
{"/rate/guest", 0, false, 429},
// "guest" rule with regular user (should be ignored)
{"/rate/guest", 0, true, 200},
{"/rate/guest", 0, true, 200},
{"/rate/guest", 0, true, 200},
{"/rate/guest", 0, true, 200},
}
for _, s := range scenarios {
@@ -91,6 +132,21 @@ func TestDefaultRateLimitMiddleware(t *testing.T) {
rec := httptest.NewRecorder()
req := httptest.NewRequest("GET", s.url, nil)
if s.authenticated {
auth, err := app.FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
token, err := auth.NewAuthToken()
if err != nil {
t.Fatal(err)
}
req.Header.Add("Authorization", token)
}
mux.ServeHTTP(rec, req)
result := rec.Result()
+9 -98
View File
@@ -75,7 +75,7 @@ func TestRequireGuestOnly(t *testing.T) {
Method: http.MethodGet,
URL: "/my/test",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: beforeTestFunc,
ExpectedStatus: 400,
@@ -148,7 +148,7 @@ func TestRequireAuth(t *testing.T) {
Method: http.MethodGet,
URL: "/my/test",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJfcGJjXzMzMjM4NjYzMzkifQ.C8m3aRZNOxUDhMiuZuDTRIIjRl7wsOyzoxs8EjvKNgY",
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsImV4cCI6MjUyNDYwNDQ2MSwidHlwZSI6ImZpbGUiLCJjb2xsZWN0aW9uSWQiOiJwYmNfMzE0MjYzNTgyMyJ9.Lupz541xRvrktwkrl55p5pPCF77T69ZRsohsIcb2dxc",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
@@ -197,7 +197,7 @@ func TestRequireAuth(t *testing.T) {
URL: "/my/test",
Headers: map[string]string{
// superuser
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
@@ -214,7 +214,7 @@ func TestRequireAuth(t *testing.T) {
URL: "/my/test",
Headers: map[string]string{
// superuser
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
@@ -253,7 +253,7 @@ func TestRequireSuperuserAuth(t *testing.T) {
Method: http.MethodGet,
URL: "/my/test",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoxNjQwOTkxNjYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.a668tes0bS6FU-OOlXMoRrdd57a_oldIPd5b0Gv_RYw",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjE2NDA5OTE2NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.0pDcBPGDpL2Khh76ivlRi7ugiLBSYvasct3qpHV3rfs",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
@@ -285,7 +285,7 @@ func TestRequireSuperuserAuth(t *testing.T) {
Method: http.MethodGet,
URL: "/my/test",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
@@ -302,95 +302,6 @@ func TestRequireSuperuserAuth(t *testing.T) {
}
}
func TestRequireSuperuserAuthOnlyIfAny(t *testing.T) {
t.Parallel()
scenarios := []tests.ApiScenario{
{
Name: "guest (while having at least 1 existing superuser)",
Method: http.MethodGet,
URL: "/my/test",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
return e.String(200, "test123")
}).Bind(apis.RequireSuperuserAuthOnlyIfAny())
},
ExpectedStatus: 401,
ExpectedContent: []string{`"data":{}`},
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "guest (while having 0 existing superusers)",
Method: http.MethodGet,
URL: "/my/test",
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
// delete all superusers
_, err := app.DB().NewQuery("DELETE FROM {{" + core.CollectionNameSuperusers + "}}").Execute()
if err != nil {
t.Fatal(err)
}
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
return e.String(200, "test123")
}).Bind(apis.RequireSuperuserAuthOnlyIfAny())
},
ExpectedStatus: 200,
ExpectedContent: []string{"test123"},
},
{
Name: "expired/invalid token",
Method: http.MethodGet,
URL: "/my/test",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoxNjQwOTkxNjYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.a668tes0bS6FU-OOlXMoRrdd57a_oldIPd5b0Gv_RYw",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
return e.String(200, "test123")
}).Bind(apis.RequireSuperuserAuthOnlyIfAny())
},
ExpectedStatus: 401,
ExpectedContent: []string{`"data":{}`},
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "valid regular user token",
Method: http.MethodGet,
URL: "/my/test",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6IjRxMXhsY2xtZmxva3UzMyIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiX3VzZXJzX2F1dGhfIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.ZT3F0Z3iM-xbGgSG3LEKiEzHrPHr8t8IuHLZGGNuxLo",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
return e.String(200, "test123")
}).Bind(apis.RequireSuperuserAuthOnlyIfAny())
},
ExpectedStatus: 403,
ExpectedContent: []string{`"data":{}`},
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "valid superuser auth token",
Method: http.MethodGet,
URL: "/my/test",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test", func(e *core.RequestEvent) error {
return e.String(200, "test123")
}).Bind(apis.RequireSuperuserAuthOnlyIfAny())
},
ExpectedStatus: 200,
ExpectedContent: []string{"test123"},
},
}
for _, scenario := range scenarios {
scenario.Test(t)
}
}
func TestRequireSuperuserOrOwnerAuth(t *testing.T) {
t.Parallel()
@@ -413,7 +324,7 @@ func TestRequireSuperuserOrOwnerAuth(t *testing.T) {
Method: http.MethodGet,
URL: "/my/test/4q1xlclmfloku33",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoxNjQwOTkxNjYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.a668tes0bS6FU-OOlXMoRrdd57a_oldIPd5b0Gv_RYw",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjE2NDA5OTE2NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.0pDcBPGDpL2Khh76ivlRi7ugiLBSYvasct3qpHV3rfs",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test/{id}", func(e *core.RequestEvent) error {
@@ -491,7 +402,7 @@ func TestRequireSuperuserOrOwnerAuth(t *testing.T) {
Method: http.MethodGet,
URL: "/my/test/4q1xlclmfloku33",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test/{id}", func(e *core.RequestEvent) error {
@@ -609,7 +520,7 @@ func TestRequireSameCollectionContextAuth(t *testing.T) {
Method: http.MethodGet,
URL: "/my/test/_pb_users_auth_",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
e.Router.GET("/my/test/{collection}", func(e *core.RequestEvent) error {
+1 -1
View File
@@ -286,7 +286,7 @@ func TestRealtimeSubscribe(t *testing.T) {
URL: "/api/realtime",
Body: strings.NewReader(`{"clientId":"` + client.Id() + `","subscriptions":["test1", "test2"]}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
@@ -49,7 +49,7 @@ func TestRecordRequestEmailChange(t *testing.T) {
URL: "/api/collections/users/request-email-change",
Body: strings.NewReader(`{"newEmail":"change@example.com"}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 403,
ExpectedContent: []string{`"data":{}`},
+3 -3
View File
@@ -47,7 +47,7 @@ func TestRecordAuthImpersonate(t *testing.T) {
Method: http.MethodPost,
URL: "/api/collections/users/impersonate/4q1xlclmfloku33",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -71,7 +71,7 @@ func TestRecordAuthImpersonate(t *testing.T) {
Method: http.MethodPost,
URL: "/api/collections/users/impersonate/4q1xlclmfloku33",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: strings.NewReader(`{"duration":-1}`),
ExpectedStatus: 400,
@@ -86,7 +86,7 @@ func TestRecordAuthImpersonate(t *testing.T) {
Method: http.MethodPost,
URL: "/api/collections/users/impersonate/4q1xlclmfloku33",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: strings.NewReader(`{"duration":100}`),
ExpectedStatus: 200,
+18 -9
View File
@@ -1,6 +1,7 @@
package apis
import (
"database/sql"
"errors"
"fmt"
"net/http"
@@ -32,12 +33,10 @@ func recordRequestOTP(e *core.RequestEvent) error {
}
record, err := e.App.FindAuthRecordByEmail(collection, form.Email)
if err != nil {
// eagerly write a dummy 200 response as a very rudimentary user emails enumeration protection
e.JSON(http.StatusOK, map[string]string{
"otpId": core.GenerateDefaultRandomId(),
})
return fmt.Errorf("failed to fetch %s record with email %s: %w", collection.Name, form.Email, err)
// ignore not found errors to allow custom record find implementations
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return e.InternalServerError("", err)
}
event := new(core.RecordCreateOTPRequestEvent)
@@ -46,7 +45,18 @@ func recordRequestOTP(e *core.RequestEvent) error {
event.Collection = collection
event.Record = record
originalApp := e.App
return e.App.OnRecordRequestOTPRequest().Trigger(event, func(e *core.RecordCreateOTPRequestEvent) error {
if e.Record == nil {
// write a dummy 200 response as a very rudimentary user emails enumeration protection
e.JSON(http.StatusOK, map[string]string{
"otpId": core.GenerateDefaultRandomId(),
})
return fmt.Errorf("failed to fetch %s record with email %s: %w", collection.Name, form.Email, err)
}
var otp *core.OTP
// limit the new OTP creations for a single user
@@ -90,11 +100,10 @@ func recordRequestOTP(e *core.RequestEvent) error {
// send OTP email
// (in the background as a very basic timing attacks and emails enumeration protection)
// ---
app := e.App
routine.FireAndForget(func() {
err = mails.SendRecordOTP(app, e.Record, otp.Id, e.Password)
err = mails.SendRecordOTP(originalApp, e.Record, otp.Id, e.Password)
if err != nil {
app.Logger().Error("Failed to send OTP email", "error", errors.Join(err, e.App.Delete(otp)))
originalApp.Logger().Error("Failed to send OTP email", "error", errors.Join(err, originalApp.Delete(otp)))
}
})
}
+63 -3
View File
@@ -86,7 +86,10 @@ func TestRecordRequestOTP(t *testing.T) {
ExpectedContent: []string{
`"otpId":"`, // some fake random generated string
},
ExpectedEvents: map[string]int{"*": 0},
ExpectedEvents: map[string]int{
"*": 0,
"OnRecordRequestOTPRequest": 1,
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend() != 0 {
t.Fatalf("Expected zero emails, got %d", app.TestMailer.TotalSend())
@@ -137,6 +140,57 @@ func TestRecordRequestOTP(t *testing.T) {
"OnModelCreate": 1,
"OnModelCreateExecute": 1,
"OnModelAfterCreateSuccess": 1,
"OnModelValidate": 2, // + 1 for the OTP update after the email send
"OnRecordCreate": 1,
"OnRecordCreateExecute": 1,
"OnRecordAfterCreateSuccess": 1,
"OnRecordValidate": 2,
// OTP update
"OnModelUpdate": 1,
"OnModelUpdateExecute": 1,
"OnModelAfterUpdateSuccess": 1,
"OnRecordUpdate": 1,
"OnRecordUpdateExecute": 1,
"OnRecordAfterUpdateSuccess": 1,
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend() != 1 {
t.Fatalf("Expected 1 email, got %d", app.TestMailer.TotalSend())
}
// ensure that sentTo is set
otps, err := app.FindRecordsByFilter(core.CollectionNameOTPs, "sentTo='test@example.com'", "", 0, 0)
if err != nil || len(otps) != 1 {
t.Fatalf("Expected to find 1 OTP with sentTo %q, found %d", "test@example.com", len(otps))
}
},
},
{
Name: "existing auth record with intercepted email (with < 9 non-expired)",
Method: http.MethodPost,
URL: "/api/collections/users/request-otp",
Body: strings.NewReader(`{"email":"test@example.com"}`),
Delay: 100 * time.Millisecond,
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
// prevent email sent
app.OnMailerRecordOTPSend("users").BindFunc(func(e *core.MailerRecordEvent) error {
return nil
})
},
ExpectedStatus: 200,
ExpectedContent: []string{
`"otpId":"`,
},
NotExpectedContent: []string{
`"otpId":"otp_`,
},
ExpectedEvents: map[string]int{
"*": 0,
"OnRecordRequestOTPRequest": 1,
"OnMailerRecordOTPSend": 1,
"OnModelCreate": 1,
"OnModelCreateExecute": 1,
"OnModelAfterCreateSuccess": 1,
"OnModelValidate": 1,
"OnRecordCreate": 1,
"OnRecordCreateExecute": 1,
@@ -144,8 +198,14 @@ func TestRecordRequestOTP(t *testing.T) {
"OnRecordValidate": 1,
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend() != 1 {
t.Fatalf("Expected 1 email, got %d", app.TestMailer.TotalSend())
if app.TestMailer.TotalSend() != 0 {
t.Fatalf("Expected 0 emails, got %d", app.TestMailer.TotalSend())
}
// ensure that there is no OTP with user email as sentTo
otps, err := app.FindRecordsByFilter(core.CollectionNameOTPs, "sentTo='test@example.com'", "", 0, 0)
if err != nil || len(otps) != 0 {
t.Fatalf("Expected to find 0 OTPs with sentTo %q, found %d", "test@example.com", len(otps))
}
},
},
+1 -1
View File
@@ -26,7 +26,7 @@ func TestRecordAuthRefresh(t *testing.T) {
Method: http.MethodPost,
URL: "/api/collections/users/auth-refresh",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 403,
ExpectedContent: []string{`"data":{}`},
+21 -11
View File
@@ -51,8 +51,8 @@ func recordAuthWithOTP(e *core.RequestEvent) error {
return e.BadRequestError("Invalid or expired OTP", fmt.Errorf("missing auth record: %w", err))
}
// since otps are usually simple digit numbers we enforce an extra rate limit rule to prevent enumerations
err = checkRateLimit(e, "@pb_otp_"+event.OTP.Id+event.Record.Id, core.RateLimitRule{MaxRequests: 4, Duration: 180})
// since otps are usually simple digit numbers, enforce an extra rate limit rule as basic enumaration protection
err = checkRateLimit(e, "@pb_otp_"+event.Record.Id, core.RateLimitRule{MaxRequests: 5, Duration: 180})
if err != nil {
return e.TooManyRequestsError("Too many attempts, please try again later with a new OTP.", nil)
}
@@ -63,23 +63,33 @@ func recordAuthWithOTP(e *core.RequestEvent) error {
// ---
return e.App.OnRecordAuthWithOTPRequest().Trigger(event, func(e *core.RecordAuthWithOTPRequestEvent) error {
// update the user email verified state in case the OTP originate from an email address matching the current record one
//
// note: don't wait for success auth response (it could fail because of MFA) and because we already validated the OTP above
otpSentTo := e.OTP.SentTo()
if !e.Record.Verified() && otpSentTo != "" && e.Record.Email() == otpSentTo {
e.Record.SetVerified(true)
err = e.App.Save(e.Record)
if err != nil {
e.App.Logger().Error("Failed to update record verified state after successful OTP validation",
"error", err,
"otpId", e.OTP.Id,
"recordId", e.Record.Id,
)
}
}
err = RecordAuthResponse(e.RequestEvent, e.Record, core.MFAMethodOTP, nil)
if err != nil {
return err
}
// try to delete the used otp
if e.OTP != nil {
err = e.App.Delete(e.OTP)
if err != nil {
e.App.Logger().Error("Failed to delete used OTP", "error", err, "otpId", e.OTP.Id)
}
err = e.App.Delete(e.OTP)
if err != nil {
e.App.Logger().Error("Failed to delete used OTP", "error", err, "otpId", e.OTP.Id)
}
// note: we don't update the user verified state the same way as in the password reset confirmation
// at the moment because it is not clear whether the otp confirmation came from the user email
// (e.g. it could be from an sms or some other channel)
return nil
})
}
+116 -7
View File
@@ -190,7 +190,7 @@ func TestRecordAuthWithOTP(t *testing.T) {
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "valid otp with valid password",
Name: "valid otp with valid password (enabled MFA)",
Method: http.MethodPost,
URL: "/api/collections/users/auth-with-otp",
Body: strings.NewReader(`{
@@ -236,7 +236,7 @@ func TestRecordAuthWithOTP(t *testing.T) {
},
},
{
Name: "valid otp with valid password (disabled MFA)",
Name: "valid otp with valid password and empty sentTo (disabled MFA)",
Method: http.MethodPost,
URL: "/api/collections/users/auth-with-otp",
Body: strings.NewReader(`{
@@ -249,8 +249,15 @@ func TestRecordAuthWithOTP(t *testing.T) {
t.Fatal(err)
}
// ensure that the user is unverified
user.SetVerified(false)
if err = app.Save(user); err != nil {
t.Fatal(err)
}
// disable MFA
user.Collection().MFA.Enabled = false
if err := app.Save(user.Collection()); err != nil {
if err = app.Save(user.Collection()); err != nil {
t.Fatal(err)
}
@@ -297,6 +304,106 @@ func TestRecordAuthWithOTP(t *testing.T) {
"OnRecordDeleteExecute": 1,
"OnRecordAfterDeleteSuccess": 1,
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
user, err := app.FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
if user.Verified() {
t.Fatal("Expected the user to remain unverified because sentTo != email")
}
},
},
{
Name: "valid otp with valid password and nonempty sentTo=email (disabled MFA)",
Method: http.MethodPost,
URL: "/api/collections/users/auth-with-otp",
Body: strings.NewReader(`{
"otpId":"` + strings.Repeat("a", 15) + `",
"password":"123456"
}`),
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
user, err := app.FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
// ensure that the user is unverified
user.SetVerified(false)
if err = app.Save(user); err != nil {
t.Fatal(err)
}
// disable MFA
user.Collection().MFA.Enabled = false
if err = app.Save(user.Collection()); err != nil {
t.Fatal(err)
}
otp := core.NewOTP(app)
otp.Id = strings.Repeat("a", 15)
otp.SetCollectionRef(user.Collection().Id)
otp.SetRecordRef(user.Id)
otp.SetPassword("123456")
otp.SetSentTo(user.Email())
if err := app.Save(otp); err != nil {
t.Fatal(err)
}
},
ExpectedStatus: 200,
ExpectedContent: []string{
`"token":"`,
`"record":{`,
`"email":"test@example.com"`,
},
NotExpectedContent: []string{
`"meta":`,
// hidden fields
`"tokenKey"`,
`"password"`,
},
ExpectedEvents: map[string]int{
"*": 0,
"OnRecordAuthWithOTPRequest": 1,
"OnRecordAuthRequest": 1,
"OnRecordEnrich": 1,
// ---
"OnModelValidate": 2, // +1 because of the verified user update
// authOrigin create
"OnModelCreate": 1,
"OnModelCreateExecute": 1,
"OnModelAfterCreateSuccess": 1,
// OTP delete
"OnModelDelete": 1,
"OnModelDeleteExecute": 1,
"OnModelAfterDeleteSuccess": 1,
// user verified update
"OnModelUpdate": 1,
"OnModelUpdateExecute": 1,
"OnModelAfterUpdateSuccess": 1,
// ---
"OnRecordValidate": 2,
"OnRecordCreate": 1,
"OnRecordCreateExecute": 1,
"OnRecordAfterCreateSuccess": 1,
"OnRecordDelete": 1,
"OnRecordDeleteExecute": 1,
"OnRecordAfterDeleteSuccess": 1,
"OnRecordUpdate": 1,
"OnRecordUpdateExecute": 1,
"OnRecordAfterUpdateSuccess": 1,
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
user, err := app.FindAuthRecordByEmail("users", "test@example.com")
if err != nil {
t.Fatal(err)
}
if !user.Verified() {
t.Fatal("Expected the user to be marked as verified")
}
},
},
// rate limit checks
@@ -387,11 +494,13 @@ func TestRecordAuthWithOTPManualRateLimiterCheck(t *testing.T) {
}{
{otpAId, "12345", 400},
{otpAId, "12345", 400},
{otpAId, "12345", 400},
{otpAId, "12345", 400},
{otpAId, "123456", 429},
{otpBId, "12345", 400},
{otpBId, "123456", 200},
{otpBId, "12345", 400},
{otpBId, "12345", 400},
{otpAId, "12345", 429},
{otpAId, "123456", 429}, // reject even if it is correct
{otpAId, "123456", 429},
{otpBId, "123456", 429},
}
for _, s := range scenarios {
+39 -12
View File
@@ -1,10 +1,13 @@
package apis
import (
cryptoRand "crypto/rand"
"errors"
"fmt"
"math/big"
"net/http"
"strings"
"time"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
@@ -86,10 +89,44 @@ func recordsList(e *core.RequestEvent) error {
return firstApiError(err, e.InternalServerError("Failed to enrich records", err))
}
// Add a randomized throttle in case of too many empty search filter attempts.
//
// This is just for extra precaution since security researches raised concern regarding the possibity of eventual
// timing attacks because the List API rule acts also as filter and executes in a single run with the client-side filters.
// This is by design and it is an accepted tradeoff between performance, usability and correctness.
//
// While technically the below doesn't fully guarantee protection against filter timing attacks, in practice combined with the network latency it makes them even less feasible.
// A properly configured rate limiter or individual fields Hidden checks are better suited if you are really concerned about eventual information disclosure by side-channel attacks.
//
// In all cases it doesn't really matter that much because it doesn't affect the builtin PocketBase security sensitive fields (e.g. password and tokenKey) since they
// are not client-side filterable and in the few places where they need to be compared against an external value, a constant time check is used.
if !e.HasSuperuserAuth() &&
(collection.ListRule != nil && *collection.ListRule != "") &&
(requestInfo.Query["filter"] != "") &&
len(e.Records) == 0 &&
checkRateLimit(e.RequestEvent, "@pb_list_timing_check_"+collection.Id, listTimingRateLimitRule) != nil {
e.App.Logger().Debug("Randomized throttle because of too many failed searches", "collectionId", collection.Id)
randomizedThrottle(100)
}
return e.JSON(http.StatusOK, e.Result)
})
}
var listTimingRateLimitRule = core.RateLimitRule{MaxRequests: 3, Duration: 3}
func randomizedThrottle(softMax int64) {
var timeout int64
randRange, err := cryptoRand.Int(cryptoRand.Reader, big.NewInt(softMax))
if err == nil {
timeout = randRange.Int64()
} else {
timeout = softMax
}
time.Sleep(time.Duration(timeout) * time.Millisecond)
}
func recordView(e *core.RequestEvent) error {
collection, err := e.App.FindCachedCollectionByNameOrId(e.Request.PathValue("collection"))
if err != nil || collection == nil {
@@ -169,17 +206,7 @@ func recordCreate(optFinalizer func(data any) error) func(e *core.RequestEvent)
}
hasSuperuserAuth := requestInfo.HasSuperuserAuth()
canSkipRuleCheck := hasSuperuserAuth
// special case for the first superuser creation
// ---
if !canSkipRuleCheck && collection.Name == core.CollectionNameSuperusers {
total, totalErr := e.App.CountRecords(core.CollectionNameSuperusers)
canSkipRuleCheck = totalErr == nil && total == 0
}
// ---
if !canSkipRuleCheck && collection.CreateRule == nil {
if !hasSuperuserAuth && collection.CreateRule == nil {
return e.ForbiddenError("Only superusers can perform this action.", nil)
}
@@ -212,7 +239,7 @@ func recordCreate(optFinalizer func(data any) error) func(e *core.RequestEvent)
form.SetRecord(e.Record)
// temporary save the record and check it against the create and manage rules
if !canSkipRuleCheck && e.Collection.CreateRule != nil {
if !hasSuperuserAuth && e.Collection.CreateRule != nil {
// temporary grant manager access level
form.GrantManagerAccess()
+2 -2
View File
@@ -218,7 +218,7 @@ func TestRecordCrudAuthOriginCreate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameAuthOrigins + "/records",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
ExpectedContent: []string{
@@ -284,7 +284,7 @@ func TestRecordCrudAuthOriginUpdate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameAuthOrigins + "/records/9r2j0m74260ur8i",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
ExpectedContent: []string{
+2 -2
View File
@@ -219,7 +219,7 @@ func TestRecordCrudExternalAuthCreate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameExternalAuths + "/records",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
ExpectedContent: []string{
@@ -286,7 +286,7 @@ func TestRecordCrudExternalAuthUpdate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameExternalAuths + "/records/dlmflokuq1xl342",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
ExpectedContent: []string{
+3 -3
View File
@@ -214,7 +214,7 @@ func TestRecordCrudMFADelete(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameMFAs + "/records/user1_0",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubMFARecords(app); err != nil {
@@ -290,7 +290,7 @@ func TestRecordCrudMFACreate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameMFAs + "/records",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
@@ -371,7 +371,7 @@ func TestRecordCrudMFAUpdate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameMFAs + "/records/user1_0",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
+3 -3
View File
@@ -214,7 +214,7 @@ func TestRecordCrudOTPDelete(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameOTPs + "/records/user1_0",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
if err := tests.StubOTPRecords(app); err != nil {
@@ -290,7 +290,7 @@ func TestRecordCrudOTPCreate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameOTPs + "/records",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
@@ -371,7 +371,7 @@ func TestRecordCrudOTPUpdate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameOTPs + "/records/user1_0",
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
+6 -41
View File
@@ -40,7 +40,7 @@ func TestRecordCrudSuperuserList(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameSuperusers + "/records",
Headers: map[string]string{
// _superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -93,7 +93,7 @@ func TestRecordCrudSuperuserView(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameSuperusers + "/records/sywbhecnh46rhm0",
Headers: map[string]string{
// _superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -142,7 +142,7 @@ func TestRecordCrudSuperuserDelete(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameSuperusers + "/records/sbmbsdb40jyxf7h",
Headers: map[string]string{
// _superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
@@ -162,7 +162,7 @@ func TestRecordCrudSuperuserDelete(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameSuperusers + "/records/sywbhecnh46rhm0",
Headers: map[string]string{
// _superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
// delete all other superusers
@@ -229,48 +229,13 @@ func TestRecordCrudSuperuserCreate(t *testing.T) {
ExpectedContent: []string{`"data":{}`},
ExpectedEvents: map[string]int{"*": 0},
},
{
Name: "guest creating first superuser",
Method: http.MethodPost,
URL: "/api/collections/" + core.CollectionNameSuperusers + "/records",
Body: body(),
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
// delete all superusers
_, err := app.DB().NewQuery("DELETE FROM {{" + core.CollectionNameSuperusers + "}}").Execute()
if err != nil {
t.Fatal(err)
}
},
ExpectedContent: []string{
`"collectionName":"_superusers"`,
`"verified":true`,
},
NotExpectedContent: []string{
// because the action has no auth the email field shouldn't be returned if emailVisibility is not set
`"email"`,
},
ExpectedStatus: 200,
ExpectedEvents: map[string]int{
"*": 0,
"OnRecordCreateRequest": 1,
"OnRecordEnrich": 1,
"OnModelCreate": 1,
"OnModelCreateExecute": 1,
"OnModelAfterCreateSuccess": 1,
"OnModelValidate": 1,
"OnRecordCreate": 1,
"OnRecordCreateExecute": 1,
"OnRecordAfterCreateSuccess": 1,
"OnRecordValidate": 1,
},
},
{
Name: "superusers auth",
Method: http.MethodPost,
URL: "/api/collections/" + core.CollectionNameSuperusers + "/records",
Headers: map[string]string{
// _superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
ExpectedContent: []string{
@@ -339,7 +304,7 @@ func TestRecordCrudSuperuserUpdate(t *testing.T) {
URL: "/api/collections/" + core.CollectionNameSuperusers + "/records/sywbhecnh46rhm0",
Headers: map[string]string{
// _superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Body: body(),
ExpectedContent: []string{
+31 -31
View File
@@ -121,7 +121,7 @@ func TestRecordCrudList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/demo1/records",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -145,7 +145,7 @@ func TestRecordCrudList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/demo1/records?filter=text~'test'&sort=-bool",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -167,7 +167,7 @@ func TestRecordCrudList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/demo1/records?filter=invalid~'test'",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -178,7 +178,7 @@ func TestRecordCrudList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/demo1/records?expand=rel_one,rel_many.rel,missing&perPage=2&sort=created",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -420,7 +420,7 @@ func TestRecordCrudList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/nologin/records",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -698,7 +698,7 @@ func TestRecordCrudView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/demo1/records/imy661ixudk5izi",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -738,7 +738,7 @@ func TestRecordCrudView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/demo1/records/al1h9ijdeojtsjy?expand=rel_one,rel_many.rel,missing&perPage=2&sort=created",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -833,7 +833,7 @@ func TestRecordCrudView(t *testing.T) {
Method: http.MethodGet,
URL: "/api/collections/nologin/records/oos036e9xvqeexy",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1090,7 +1090,7 @@ func TestRecordCrudDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/clients/records/o1y0dd0spd786md",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
@@ -1109,7 +1109,7 @@ func TestRecordCrudDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/clients/records/o1y0dd0spd786md",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
app.OnRecordDeleteRequest().BindFunc(func(e *core.RecordRequestEvent) error {
@@ -1197,7 +1197,7 @@ func TestRecordCrudDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/demo3/records/7nwo8tuiatetxdm",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -1223,7 +1223,7 @@ func TestRecordCrudDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/demo3/records/1tmknxy2868d869",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 204,
ExpectedEvents: map[string]int{
@@ -1248,7 +1248,7 @@ func TestRecordCrudDelete(t *testing.T) {
Method: http.MethodDelete,
URL: "/api/collections/users/records/oap640cot4yru2s",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
Delay: 100 * time.Millisecond,
ExpectedStatus: 204,
@@ -1544,7 +1544,7 @@ func TestRecordCrudCreate(t *testing.T) {
"rel_many_cascade":"lcl9d87w22ml6jy"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1585,7 +1585,7 @@ func TestRecordCrudCreate(t *testing.T) {
Body: formData,
Headers: map[string]string{
"Content-Type": mp.FormDataContentType(),
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1720,7 +1720,7 @@ func TestRecordCrudCreate(t *testing.T) {
"title": "test"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1746,7 +1746,7 @@ func TestRecordCrudCreate(t *testing.T) {
"title": "test"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1772,7 +1772,7 @@ func TestRecordCrudCreate(t *testing.T) {
"title": "test"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1802,7 +1802,7 @@ func TestRecordCrudCreate(t *testing.T) {
"title": "test"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -1834,7 +1834,7 @@ func TestRecordCrudCreate(t *testing.T) {
"passwordConfirm":"1234567890"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1916,7 +1916,7 @@ func TestRecordCrudCreate(t *testing.T) {
"username":"Users75657"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -1943,7 +1943,7 @@ func TestRecordCrudCreate(t *testing.T) {
"rel":"invalid"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -2025,7 +2025,7 @@ func TestRecordCrudCreate(t *testing.T) {
"verified":true
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -2169,7 +2169,7 @@ func TestRecordCrudCreate(t *testing.T) {
}`),
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
col, err := app.FindCollectionByNameOrId("demo3")
@@ -2578,7 +2578,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"rel_many_cascade":"lcl9d87w22ml6jy"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -2619,7 +2619,7 @@ func TestRecordCrudUpdate(t *testing.T) {
Body: formData,
Headers: map[string]string{
"Content-Type": mp.FormDataContentType(),
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -2726,7 +2726,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"id": "mk5fmymtx4wspra"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -2829,7 +2829,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"verified":false
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -2857,7 +2857,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"rel":"invalid"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -3013,7 +3013,7 @@ func TestRecordCrudUpdate(t *testing.T) {
"verified":false
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -3251,7 +3251,7 @@ func TestRecordCrudUpdate(t *testing.T) {
}`),
Headers: map[string]string{
// superusers, test@example.com
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
col, err := app.FindCollectionByNameOrId("demo3")
+9 -9
View File
@@ -122,7 +122,8 @@ func recordAuthResponse(e *core.RequestEvent, authRecord *core.Record, token str
})
}
// wantsMFA checks whether to enable MFA for the specified auth record based on its MFA rule.
// wantsMFA checks whether to enable MFA for the specified auth record based on its MFA rule
// (note: returns true even in case of an error as a safer default).
func wantsMFA(e *core.RequestEvent, record *core.Record) (bool, error) {
rule := record.Collection().MFA.Rule
if rule == "" {
@@ -131,7 +132,7 @@ func wantsMFA(e *core.RequestEvent, record *core.Record) (bool, error) {
requestInfo, err := e.RequestInfo()
if err != nil {
return false, err
return true, err
}
var exists bool
@@ -144,13 +145,13 @@ func wantsMFA(e *core.RequestEvent, record *core.Record) (bool, error) {
resolver := core.NewRecordFieldResolver(e.App, record.Collection(), requestInfo, true)
expr, err := search.FilterData(rule).BuildExpr(resolver)
if err != nil {
return false, err
return true, err
}
resolver.UpdateQuery(query)
err = query.AndWhere(expr).Limit(1).Row(&exists)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return false, err
return true, err
}
return exists, nil
@@ -166,11 +167,10 @@ func checkMFA(e *core.RequestEvent, authRecord *core.Record, currentAuthMethod s
}
ok, err := wantsMFA(e, authRecord)
if err != nil {
return "", e.BadRequestError("Failed to authenticate.", fmt.Errorf("MFA rule failure: %w", err))
}
if !ok {
if err != nil {
return "", e.BadRequestError("Failed to authenticate.", fmt.Errorf("MFA rule failure: %w", err))
}
return "", nil // no mfa needed for this auth record
}
@@ -214,7 +214,7 @@ func checkMFA(e *core.RequestEvent, authRecord *core.Record, currentAuthMethod s
}
if err != nil || mfa.HasExpired(authRecord.Collection().MFA.DurationTime()) {
deleteMFA()
return "", firstApiError(err, e.BadRequestError("Invalid or expired MFA session.", err))
return "", e.BadRequestError("Invalid or expired MFA session.", err)
}
if mfa.RecordRef() != authRecord.Id || mfa.CollectionRef() != authRecord.Collection().Id {
+29 -30
View File
@@ -4,6 +4,7 @@ import (
"context"
"crypto/tls"
"errors"
"fmt"
"log"
"net"
"net/http"
@@ -26,12 +27,6 @@ type ServeConfig struct {
// ShowStartBanner indicates whether to show or hide the server start console message.
ShowStartBanner bool
// DashboardPath specifies the route path to the superusers dashboard interface
// (default to "/_/{path...}").
//
// Note: Must include the "{path...}" wildcard parameter.
DashboardPath string
// HttpAddr is the TCP address to listen for the HTTP server (eg. "127.0.0.1:80").
HttpAddr string
@@ -66,12 +61,6 @@ func Serve(app core.App, config ServeConfig) error {
config.AllowedOrigins = []string{"*"}
}
if config.DashboardPath == "" {
config.DashboardPath = "/_/{path...}"
} else if !strings.HasSuffix(config.DashboardPath, "{path...}") {
return errors.New("invalid dashboard path - missing {path...} wildcard")
}
// ensure that the latest migrations are applied before starting the server
err := app.RunAllMigrations()
if err != nil {
@@ -88,11 +77,14 @@ func Serve(app core.App, config ServeConfig) error {
AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
}))
pbRouter.BindFunc(installerRedirect(app, config.DashboardPath))
pbRouter.GET(config.DashboardPath, Static(ui.DistDirFS, false)).
BindFunc(dashboardRemoveInstallerParam()).
BindFunc(dashboardCacheControl()).
pbRouter.GET("/_/{path...}", Static(ui.DistDirFS, false)).
BindFunc(func(e *core.RequestEvent) error {
// ingore root path
if e.Request.PathValue(StaticWildcardParam) != "" {
e.Response.Header().Set("Cache-Control", "max-age=1209600, stale-while-revalidate=86400")
}
return e.Next()
}).
Bind(Gzip())
// start http server
@@ -240,18 +232,18 @@ func Serve(app core.App, config ServeConfig) error {
return errors.New("The OnServe finalizer wasn't invoked. Did you forget to call the ServeEvent.Next() method?")
}
if config.ShowStartBanner {
schema := "http"
addr := server.Addr
if config.HttpsAddr != "" {
schema = "https"
if len(config.CertificateDomains) > 0 {
addr = config.CertificateDomains[0]
}
schema := "http"
addr := server.Addr
if config.HttpsAddr != "" {
schema = "https"
if len(config.CertificateDomains) > 0 {
addr = config.CertificateDomains[0]
}
}
baseURL := fmt.Sprintf("%s://%s", schema, addr)
dashboardURL := fmt.Sprintf("%s/_", baseURL)
if config.ShowStartBanner {
date := new(strings.Builder)
log.New(date, "", log.LstdFlags).Print()
@@ -259,14 +251,21 @@ func Serve(app core.App, config ServeConfig) error {
bold.Printf(
"%s Server started at %s\n",
strings.TrimSpace(date.String()),
color.CyanString("%s://%s", schema, addr),
color.CyanString("%s", baseURL),
)
regular := color.New()
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))
regular.Printf("├─ REST API: %s\n", color.CyanString("%s/api/", baseURL))
regular.Printf("└─ Dashboard: %s\n", color.CyanString("%s/", dashboardURL))
}
go func() {
installerErr := loadInstaller(app, dashboardURL)
if installerErr != nil {
app.Logger().Warn("Failed to initialize installer", "error", installerErr)
}
}()
var serveErr error
if config.HttpsAddr != "" {
if config.HttpAddr != "" {
+17 -17
View File
@@ -42,7 +42,7 @@ func TestSettingsList(t *testing.T) {
Method: http.MethodGet,
URL: "/api/settings",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -102,7 +102,7 @@ func TestSettingsSet(t *testing.T) {
URL: "/api/settings",
Body: strings.NewReader(``),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -129,7 +129,7 @@ func TestSettingsSet(t *testing.T) {
URL: "/api/settings",
Body: strings.NewReader(`{"meta":{"appName":""}}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -150,7 +150,7 @@ func TestSettingsSet(t *testing.T) {
URL: "/api/settings",
Body: strings.NewReader(validData),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
@@ -211,7 +211,7 @@ func TestSettingsTestS3(t *testing.T) {
Method: http.MethodPost,
URL: "/api/settings/test/s3",
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -226,7 +226,7 @@ func TestSettingsTestS3(t *testing.T) {
URL: "/api/settings/test/s3",
Body: strings.NewReader(`{"filesystem":"invalid"}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -241,7 +241,7 @@ func TestSettingsTestS3(t *testing.T) {
URL: "/api/settings/test/s3",
Body: strings.NewReader(`{"filesystem":"storage"}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -293,7 +293,7 @@ func TestSettingsTestEmail(t *testing.T) {
URL: "/api/settings/test/email",
Body: strings.NewReader(`{`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -305,7 +305,7 @@ func TestSettingsTestEmail(t *testing.T) {
URL: "/api/settings/test/email",
Body: strings.NewReader(`{}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -323,7 +323,7 @@ func TestSettingsTestEmail(t *testing.T) {
"email": "test@example.com"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend() != 1 {
@@ -359,7 +359,7 @@ func TestSettingsTestEmail(t *testing.T) {
"email": "test@example.com"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend() != 1 {
@@ -395,7 +395,7 @@ func TestSettingsTestEmail(t *testing.T) {
"email": "test@example.com"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend() != 1 {
@@ -431,7 +431,7 @@ func TestSettingsTestEmail(t *testing.T) {
"email": "test@example.com"
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
AfterTestFunc: func(t testing.TB, app *tests.TestApp, res *http.Response) {
if app.TestMailer.TotalSend() != 1 {
@@ -511,7 +511,7 @@ func TestGenerateAppleClientSecret(t *testing.T) {
URL: "/api/settings/apple/generate-client-secret",
Body: strings.NewReader(`{`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{`"data":{}`},
@@ -523,7 +523,7 @@ func TestGenerateAppleClientSecret(t *testing.T) {
URL: "/api/settings/apple/generate-client-secret",
Body: strings.NewReader(`{}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -547,7 +547,7 @@ func TestGenerateAppleClientSecret(t *testing.T) {
"duration": -1
}`),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 400,
ExpectedContent: []string{
@@ -571,7 +571,7 @@ func TestGenerateAppleClientSecret(t *testing.T) {
"duration": 1
}`, privatePem)),
Headers: map[string]string{
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoiX3BiY18zMzIzODY2MzM5IiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.v_bMAygr6hXPwD2DpPrFpNQ7dd68Q3pGstmYAsvNBJg",
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6InN5d2JoZWNuaDQ2cmhtMCIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoicGJjXzMxNDI2MzU4MjMiLCJleHAiOjI1MjQ2MDQ0NjEsInJlZnJlc2hhYmxlIjp0cnVlfQ.UXgO3j-0BumcugrFjbd7j0M4MQvbrLggLlcu_YNGjoY",
},
ExpectedStatus: 200,
ExpectedContent: []string{
-9
View File
@@ -15,7 +15,6 @@ func NewServeCommand(app core.App, showStartBanner bool) *cobra.Command {
var allowedOrigins []string
var httpAddr string
var httpsAddr string
var dashboardPath string
command := &cobra.Command{
Use: "serve [domain(s)]",
@@ -40,7 +39,6 @@ func NewServeCommand(app core.App, showStartBanner bool) *cobra.Command {
err := apis.Serve(app, apis.ServeConfig{
HttpAddr: httpAddr,
HttpsAddr: httpsAddr,
DashboardPath: dashboardPath,
ShowStartBanner: showStartBanner,
AllowedOrigins: allowedOrigins,
CertificateDomains: args,
@@ -75,12 +73,5 @@ func NewServeCommand(app core.App, showStartBanner bool) *cobra.Command {
"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",
)
command.PersistentFlags().StringVar(
&dashboardPath,
"dashboard",
"/_/{path...}",
"The route path to the superusers dashboard; must include the '{path...}' wildcard parameter",
)
return command
}
+51 -6
View File
@@ -7,21 +7,23 @@ import (
"github.com/fatih/color"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/security"
"github.com/spf13/cobra"
)
// NewSuperuserCommand creates and returns new command for managing
// superuser accounts (create, update, delete).
// superuser accounts (create, update, upsert, delete).
func NewSuperuserCommand(app core.App) *cobra.Command {
command := &cobra.Command{
Use: "superuser",
Short: "Manages superuser accounts",
Short: "Manage superusers",
}
command.AddCommand(superuserUpsertCommand(app))
command.AddCommand(superuserCreateCommand(app))
command.AddCommand(superuserUpdateCommand(app))
command.AddCommand(superuserDeleteCommand(app))
command.AddCommand(superuserOTPCommand(app))
return command
}
@@ -30,7 +32,7 @@ func superuserUpsertCommand(app core.App) *cobra.Command {
command := &cobra.Command{
Use: "upsert",
Example: "superuser upsert test@example.com 1234567890",
Short: "Creates, or updates if email exists, a single superuser account",
Short: "Creates, or updates if email exists, a single superuser",
SilenceUsage: true,
RunE: func(command *cobra.Command, args []string) error {
if len(args) != 2 {
@@ -70,7 +72,7 @@ func superuserCreateCommand(app core.App) *cobra.Command {
command := &cobra.Command{
Use: "create",
Example: "superuser create test@example.com 1234567890",
Short: "Creates a new superuser account",
Short: "Creates a new superuser",
SilenceUsage: true,
RunE: func(command *cobra.Command, args []string) error {
if len(args) != 2 {
@@ -106,7 +108,7 @@ func superuserUpdateCommand(app core.App) *cobra.Command {
command := &cobra.Command{
Use: "update",
Example: "superuser update test@example.com 1234567890",
Short: "Changes the password of a single superuser account",
Short: "Changes the password of a single superuser",
SilenceUsage: true,
RunE: func(command *cobra.Command, args []string) error {
if len(args) != 2 {
@@ -140,7 +142,7 @@ func superuserDeleteCommand(app core.App) *cobra.Command {
command := &cobra.Command{
Use: "delete",
Example: "superuser delete test@example.com",
Short: "Deletes an existing superuser account",
Short: "Deletes an existing superuser",
SilenceUsage: true,
RunE: func(command *cobra.Command, args []string) error {
if len(args) == 0 || args[0] == "" || is.EmailFormat.Validate(args[0]) != nil {
@@ -164,3 +166,46 @@ func superuserDeleteCommand(app core.App) *cobra.Command {
return command
}
func superuserOTPCommand(app core.App) *cobra.Command {
command := &cobra.Command{
Use: "otp",
Example: "superuser otp test@example.com",
Short: "Creates a new OTP for the specified superuser",
SilenceUsage: true,
RunE: func(command *cobra.Command, args []string) error {
if len(args) == 0 || args[0] == "" || is.EmailFormat.Validate(args[0]) != nil {
return errors.New("Invalid or missing email address.")
}
superuser, err := app.FindAuthRecordByEmail(core.CollectionNameSuperusers, args[0])
if err != nil {
return fmt.Errorf("Superuser with email %q doesn't exist.", args[0])
}
if !superuser.Collection().OTP.Enabled {
return errors.New("OTP is not enabled for the _superusers collection.")
}
pass := security.RandomStringWithAlphabet(superuser.Collection().OTP.Length, "1234567890")
otp := core.NewOTP(app)
otp.SetCollectionRef(superuser.Collection().Id)
otp.SetRecordRef(superuser.Id)
otp.SetPassword(pass)
err = app.Save(otp)
if err != nil {
return fmt.Errorf("Failed to create OTP: %w", err)
}
color.New(color.BgGreen, color.FgBlack).Printf("Successfully created OTP for superuser %q:", superuser.Email())
color.Green("\n├─ Id: %s", otp.Id)
color.Green("├─ Pass: %s", pass)
color.Green("└─ Valid: %ds\n\n", superuser.Collection().OTP.Duration)
return nil
},
}
return command
}
+93
View File
@@ -308,3 +308,96 @@ func TestSuperuserDeleteCommand(t *testing.T) {
})
}
}
func TestSuperuserOTPCommand(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
superusersCollection, err := app.FindCollectionByNameOrId(core.CollectionNameSuperusers)
if err != nil {
t.Fatal(err)
}
// remove all existing otps
otps, err := app.FindAllOTPsByCollection(superusersCollection)
if err != nil {
t.Fatal(err)
}
for _, otp := range otps {
err = app.Delete(otp)
if err != nil {
t.Fatal(err)
}
}
scenarios := []struct {
name string
email string
enabled bool
expectError bool
}{
{
"empty email",
"",
true,
true,
},
{
"invalid email",
"invalid",
true,
true,
},
{
"nonexisting superuser",
"test_missing@example.com",
true,
true,
},
{
"existing superuser",
"test@example.com",
true,
false,
},
{
"existing superuser with disabled OTP",
"test@example.com",
false,
true,
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
command := cmd.NewSuperuserCommand(app)
command.SetArgs([]string{"otp", s.email})
superusersCollection.OTP.Enabled = s.enabled
if err = app.SaveNoValidate(superusersCollection); err != nil {
t.Fatal(err)
}
err := command.Execute()
hasErr := err != nil
if s.expectError != hasErr {
t.Fatalf("Expected hasErr %v, got %v (%v)", s.expectError, hasErr, err)
}
if hasErr {
return
}
superuser, err := app.FindAuthRecordByEmail(superusersCollection, s.email)
if err != nil {
t.Fatal(err)
}
otps, _ := app.FindAllOTPsByRecord(superuser)
if total := len(otps); total != 1 {
t.Fatalf("Expected 1 OTP, got %d", total)
}
})
}
}
+3
View File
@@ -1361,6 +1361,9 @@ type App interface {
// OnRecordRequestOTPRequest hook is triggered on each Record
// request OTP API request.
//
// [RecordCreateOTPRequestEvent.Record] could be nil if no matching identity is found, allowing
// you to manually create or locate a different Record model (by reassigning [RecordCreateOTPRequestEvent.Record]).
//
// If the optional "tags" list (Collection ids or names) is specified,
// then all event handlers registered via the created hook will be
// triggered and called only if their event data origin matches the tags.
+8
View File
@@ -2,6 +2,7 @@ package core_test
import (
"context"
"database/sql"
"log/slog"
"os"
"testing"
@@ -9,6 +10,7 @@ import (
_ "unsafe"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tests"
"github.com/pocketbase/pocketbase/tools/logger"
@@ -351,6 +353,12 @@ func TestBaseAppRefreshSettingsLoggerMinLevelEnabled(t *testing.T) {
t.Fatal(err)
}
// silence query logs
app.DB().(*dbx.DB).ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {}
app.DB().(*dbx.DB).QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {}
app.NonconcurrentDB().(*dbx.DB).ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {}
app.NonconcurrentDB().(*dbx.DB).QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {}
handler, ok := app.Logger().Handler().(*logger.BatchHandler)
if !ok {
t.Fatalf("Expected BatchHandler, got %v", app.Logger().Handler())
+69 -29
View File
@@ -3,8 +3,10 @@ package core
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/tools/dbutils"
"github.com/pocketbase/pocketbase/tools/hook"
"github.com/pocketbase/pocketbase/tools/security"
@@ -309,6 +311,7 @@ type baseCollection struct {
BaseModel
disableIntegrityChecks bool
autogeneratedId string
ListRule *string `db:"listRule" json:"listRule" form:"listRule"`
ViewRule *string `db:"viewRule" json:"viewRule" form:"viewRule"`
@@ -364,6 +367,7 @@ func NewBaseCollection(name string, optId ...string) *Collection {
m.Name = name
m.Type = CollectionTypeBase
// @todo consider removing once inferred composite literals are supported
if len(optId) > 0 {
m.Id = optId[0]
}
@@ -383,6 +387,7 @@ func NewViewCollection(name string, optId ...string) *Collection {
m.Name = name
m.Type = CollectionTypeView
// @todo consider removing once inferred composite literals are supported
if len(optId) > 0 {
m.Id = optId[0]
}
@@ -402,6 +407,7 @@ func NewAuthCollection(name string, optId ...string) *Collection {
m.Name = name
m.Type = CollectionTypeAuth
// @todo consider removing once inferred composite literals are supported
if len(optId) > 0 {
m.Id = optId[0]
}
@@ -482,12 +488,13 @@ func (m *Collection) UnmarshalJSON(b []byte) error {
minimal := &struct {
Type string `json:"type"`
Name string `json:"name"`
Id string `json:"id"`
}{}
if err := json.Unmarshal(b, minimal); err != nil {
return err
}
blank := NewCollection(minimal.Type, minimal.Name)
blank := NewCollection(minimal.Type, minimal.Name, minimal.Id)
*m = *blank
}
@@ -689,49 +696,82 @@ func onCollectionDeleteExecute(e *CollectionEvent) error {
// save hook
// -------------------------------------------------------------------
func (c *Collection) initDefaultId() {
if c.Id != "" {
return // already set
}
func (c *Collection) idChecksum() string {
return "pbc_" + crc32Checksum(c.Type+c.Name)
}
if c.System && c.Name != "" {
// for system collections we use crc32 checksum for consistency because they cannot be renamed
c.Id = "pbc_" + crc32Checksum(c.Name)
} else {
c.Id = "pbc_" + security.RandomStringWithAlphabet(11, DefaultIdAlphabet)
func (c *Collection) initDefaultId() {
if c.Id == "" {
c.Id = c.idChecksum()
c.autogeneratedId = c.Id
}
}
func (c *Collection) savePrepare() error {
if c.Type == "" {
c.Type = CollectionTypeBase
func (c *Collection) updateGeneratedIdIfExists(app App) {
if !c.IsNew() ||
// the id was explicitly cleared
c.Id == "" ||
// the id was manually set
c.Id != c.autogeneratedId {
return
}
if c.IsNew() {
c.initDefaultId()
c.Created = types.NowDateTime()
// generate an up-to-date checksum
newId := c.idChecksum()
// add a number to the current id (if already exists)
for i := 2; i < 1000; i++ {
var exists bool
_ = app.CollectionQuery().Select("(1)").AndWhere(dbx.HashExp{"id": newId}).Limit(1).Row(&exists)
if !exists {
break
}
newId = c.idChecksum() + strconv.Itoa(i)
}
c.Updated = types.NowDateTime()
// recreate the fields list to ensure that all normalizations
// like default field id are applied
c.Fields = NewFieldsList(c.Fields...)
c.initDefaultFields()
if c.IsAuth() {
c.unsetMissingOAuth2MappedFields()
// no change
if c.Id == newId {
return
}
return nil
// replace the old id in the index names (if any)
for i, idx := range c.Indexes {
parsed := dbutils.ParseIndex(idx)
original := parsed.IndexName
parsed.IndexName = strings.ReplaceAll(parsed.IndexName, c.Id, newId)
if parsed.IndexName != original {
c.Indexes[i] = parsed.Build()
}
}
// update model id
c.Id = newId
}
func onCollectionSave(e *CollectionEvent) error {
if err := e.Collection.savePrepare(); err != nil {
return err
if e.Collection.Type == "" {
e.Collection.Type = CollectionTypeBase
}
if e.Collection.IsNew() {
e.Collection.initDefaultId()
e.Collection.Created = types.NowDateTime()
}
e.Collection.Updated = types.NowDateTime()
// recreate the fields list to ensure that all normalizations
// like default field id are applied
e.Collection.Fields = NewFieldsList(e.Collection.Fields...)
e.Collection.initDefaultFields()
if e.Collection.IsAuth() {
e.Collection.unsetMissingOAuth2MappedFields()
}
e.Collection.updateGeneratedIdIfExists(e.App)
return e.Next()
}
+4
View File
@@ -65,6 +65,10 @@ type optionsValidator interface {
}
func (validator *collectionValidator) run() error {
if validator.original.IsNew() {
validator.new.updateGeneratedIdIfExists(validator.app)
}
// generate fields from the query (overwriting any explicit user defined fields)
if validator.new.IsView() {
validator.new.Fields, _ = validator.app.CreateViewFields(validator.new.ViewQuery)
+2 -2
View File
@@ -191,7 +191,7 @@ func DefaultFieldIdValidationRule(value any) error {
rules := []validation.Rule{
validation.Required,
validation.Length(1, 255),
validation.Length(1, 100),
}
for _, r := range rules {
@@ -217,7 +217,7 @@ func DefaultFieldNameValidationRule(value any) error {
rules := []validation.Rule{
validation.Required,
validation.Length(1, 255),
validation.Length(1, 100),
validation.Match(fieldNameRegex),
validation.NotIn(excludeNames...),
validation.By(checkForVia),
+3 -3
View File
@@ -739,14 +739,14 @@ func (f *FileField) toSliceValue(raw any) []any {
}
func (f *FileField) uniqueFiles(files []any) []any {
existing := make(map[string]struct{}, len(files))
found := make(map[string]struct{}, len(files))
result := make([]any, 0, len(files))
for _, fv := range files {
name := f.getFileName(fv)
if _, ok := existing[name]; !ok {
if _, ok := found[name]; !ok {
result = append(result, fv)
existing[name] = struct{}{}
found[name] = struct{}{}
}
}
+4 -4
View File
@@ -91,7 +91,7 @@ func testDefaultFieldIdValidation(t *testing.T, fieldType string) {
"invalid length",
func() core.Field {
f := core.Fields[fieldType]()
f.SetId(strings.Repeat("a", 256))
f.SetId(strings.Repeat("a", 101))
return f
},
true,
@@ -100,7 +100,7 @@ func testDefaultFieldIdValidation(t *testing.T, fieldType string) {
"valid length",
func() core.Field {
f := core.Fields[fieldType]()
f.SetId(strings.Repeat("a", 255))
f.SetId(strings.Repeat("a", 100))
return f
},
false,
@@ -142,7 +142,7 @@ func testDefaultFieldNameValidation(t *testing.T, fieldType string) {
"invalid length",
func() core.Field {
f := core.Fields[fieldType]()
f.SetName(strings.Repeat("a", 256))
f.SetName(strings.Repeat("a", 101))
return f
},
true,
@@ -151,7 +151,7 @@ func testDefaultFieldNameValidation(t *testing.T, fieldType string) {
"valid length",
func() core.Field {
f := core.Fields[fieldType]()
f.SetName(strings.Repeat("a", 255))
f.SetName(strings.Repeat("a", 100))
return f
},
false,
+10 -8
View File
@@ -4,8 +4,7 @@ import (
"database/sql/driver"
"encoding/json"
"fmt"
"github.com/pocketbase/pocketbase/tools/security"
"strconv"
)
// NewFieldsList creates a new FieldsList instance with the provided fields.
@@ -171,12 +170,16 @@ func (l *FieldsList) add(newField Field) {
// set default id
if newFieldId == "" {
replaceByName = true
if newField.GetSystem() && newField.GetName() != "" {
// for system fields we use crc32 checksum for consistency because they cannot be renamed
newFieldId = newField.Type() + crc32Checksum(newField.GetName())
} else {
newFieldId = newField.Type() + security.RandomString(7)
baseId := newField.Type() + crc32Checksum(newField.GetName())
newFieldId = baseId
for i := 2; i < 1000; i++ {
if l.GetById(newFieldId) == nil {
break // already unique
}
newFieldId = baseId + strconv.Itoa(i)
}
newField.SetId(newFieldId)
}
// replace existing
@@ -196,7 +199,6 @@ func (l *FieldsList) add(newField Field) {
}
// add new field
newField.SetId(newFieldId)
*l = append(fields, newField)
}
+9
View File
@@ -2,10 +2,13 @@ package core
import (
"context"
"database/sql"
"log/slog"
"os"
"testing"
"time"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/tools/list"
"github.com/pocketbase/pocketbase/tools/logger"
)
@@ -51,6 +54,12 @@ func TestBaseAppLoggerLevelDevPrint(t *testing.T) {
t.Fatal(err)
}
// silence query logs
app.DB().(*dbx.DB).ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {}
app.DB().(*dbx.DB).QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {}
app.NonconcurrentDB().(*dbx.DB).ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {}
app.NonconcurrentDB().(*dbx.DB).QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {}
app.Settings().Logs.MinLevel = testLogLevel
if err := app.Save(app.Settings()); err != nil {
t.Fatal(err)
+14
View File
@@ -85,6 +85,20 @@ func (m *OTP) SetRecordRef(recordId string) {
m.Set("recordRef", recordId)
}
// SentTo returns the "sentTo" record field value.
//
// It could be any string value (email, phone, message app id, etc.)
// and usually is used as part of the auth flow to update the verified
// user state in case for example the sentTo value matches with the user record email.
func (m *OTP) SentTo() string {
return m.GetString("sentTo")
}
// SetSentTo updates the "sentTo" record field value.
func (m *OTP) SetSentTo(val string) {
m.Set("sentTo", val)
}
// Created returns the "created" record field value.
func (m *OTP) Created() types.DateTime {
return m.GetDateTime("created")
+24
View File
@@ -85,6 +85,30 @@ func TestOTPCollectionRef(t *testing.T) {
}
}
func TestOTPSentTo(t *testing.T) {
t.Parallel()
app, _ := tests.NewTestApp()
defer app.Cleanup()
otp := core.NewOTP(app)
testValues := []string{"test_1", "test2", ""}
for i, testValue := range testValues {
t.Run(fmt.Sprintf("%d_%q", i, testValue), func(t *testing.T) {
otp.SetSentTo(testValue)
if v := otp.SentTo(); v != testValue {
t.Fatalf("Expected getter %q, got %q", testValue, v)
}
if v := otp.GetString("sentTo"); v != testValue {
t.Fatalf("Expected field value %q, got %q", testValue, v)
}
})
}
}
func TestOTPCreated(t *testing.T) {
t.Parallel()
+39 -1
View File
@@ -1,6 +1,8 @@
package core
import (
"database/sql"
"errors"
"fmt"
"github.com/pocketbase/pocketbase/tools/hook"
@@ -9,6 +11,10 @@ import (
const CollectionNameSuperusers = "_superusers"
// DefaultInstallerEmail is the default superuser email address
// for the initial autogenerated superuser account.
const DefaultInstallerEmail = "__pbinstaller@example.com"
func (app *BaseApp) registerSuperuserHooks() {
app.OnRecordDelete(CollectionNameSuperusers).Bind(&hook.Handler[*RecordEvent]{
Id: "pbSuperusersRecordDelete",
@@ -39,13 +45,45 @@ func (app *BaseApp) registerSuperuserHooks() {
Id: "pbSuperusersRecordSaveExec",
Func: func(e *RecordEvent) error {
e.Record.SetVerified(true) // always mark superusers as verified
return e.Next()
if err := e.Next(); err != nil {
return err
}
// ensure that the installer superuser is deleted
if e.Type == ModelEventTypeCreate && e.Record.Email() != DefaultInstallerEmail {
record, err := app.FindAuthRecordByEmail(CollectionNameSuperusers, DefaultInstallerEmail)
if errors.Is(err, sql.ErrNoRows) {
// already deleted
} else if err != nil {
e.App.Logger().Warn("Failed to fetch installer superuser", "error", err)
} else {
err = e.App.Delete(record)
if err != nil {
e.App.Logger().Warn("Failed to delete installer superuser", "error", err)
}
}
}
return nil
},
Priority: -99,
}
app.OnRecordCreateExecute(CollectionNameSuperusers).Bind(recordSaveHandler)
app.OnRecordUpdateExecute(CollectionNameSuperusers).Bind(recordSaveHandler)
// prevent sending password reset emails to the installer address
app.OnMailerRecordPasswordResetSend(CollectionNameSuperusers).Bind(&hook.Handler[*MailerRecordEvent]{
Id: "pbSuperusersInstallerPasswordReset",
Func: func(e *MailerRecordEvent) error {
if e.Record.Email() == DefaultInstallerEmail {
return errors.New("cannot reset the password for the installer superuser")
}
return e.Next()
},
})
collectionSaveHandler := &hook.Handler[*CollectionEvent]{
Id: "pbSuperusersCollectionSaveExec",
Func: func(e *CollectionEvent) error {
+34 -9
View File
@@ -123,10 +123,10 @@ type settings struct {
Backups BackupsConfig `form:"backups" json:"backups"`
S3 S3Config `form:"s3" json:"s3"`
Meta MetaConfig `form:"meta" json:"meta"`
Logs LogsConfig `form:"logs" json:"logs"`
Batch BatchConfig `form:"batch" json:"batch"`
RateLimits RateLimitsConfig `form:"rateLimits" json:"rateLimits"`
TrustedProxy TrustedProxyConfig `form:"trustedProxy" json:"trustedProxy"`
Batch BatchConfig `form:"batch" json:"batch"`
Logs LogsConfig `form:"logs" json:"logs"`
}
// Settings defines the PocketBase app settings.
@@ -617,19 +617,28 @@ func checkUniqueRuleLabel(value any) error {
return validators.ErrUnsupportedValueType
}
labels := make(map[string]struct{}, len(rules))
existing := make([]string, 0, len(rules))
for i, rule := range rules {
_, ok := labels[rule.Label]
if ok {
fullKey := rule.Label + "@@" + rule.Audience
var conflicts bool
for _, key := range existing {
if strings.HasPrefix(key, fullKey) || strings.HasPrefix(fullKey, key) {
conflicts = true
break
}
}
if conflicts {
return validation.Errors{
strconv.Itoa(i): validation.Errors{
"label": validation.NewError("validation_duplicated_rate_limit_tag", "Rate limit tag with label "+rule.Label+" already exists.").
"label": validation.NewError("validation_conflicting_rate_limit_rule", "Rate limit rule configuration with label "+rule.Label+" already exists or conflicts with another rule.").
SetParams(map[string]any{"label": rule.Label}),
},
}
} else {
labels[rule.Label] = struct{}{}
existing = append(existing, fullKey)
}
}
@@ -638,6 +647,13 @@ func checkUniqueRuleLabel(value any) error {
var rateLimitRuleLabelRegex = regexp.MustCompile(`^(\w+\ \/[\w\/-]*|\/[\w\/-]*|^\w+\:\w+|\*\:\w+|\w+)$`)
// The allowed RateLimitRule.Audience values
const (
RateLimitRuleAudienceAll = ""
RateLimitRuleAudienceGuest = "@guest"
RateLimitRuleAudienceAuth = "@auth"
)
type RateLimitRule struct {
// Label is the identifier of the current rule.
//
@@ -652,12 +668,18 @@ type RateLimitRule struct {
// - POST /api/collections/
Label string `form:"label" json:"label"`
// MaxRequests is the max allowed number of requests per Duration.
MaxRequests int `form:"maxRequests" json:"maxRequests"`
// Audience specifies the auth group the rule should apply for:
// - "" - both guests and authenticated users (default)
// - "guest" - only for guests
// - "auth" - only for authenticated users
Audience string `form:"audience" json:"audience"`
// Duration specifies the interval (in seconds) per which to reset
// the counted/accumulated rate limiter tokens.
Duration int64 `form:"duration" json:"duration"`
// MaxRequests is the max allowed number of requests per Duration.
MaxRequests int `form:"maxRequests" json:"maxRequests"`
}
// Validate makes RateLimitRule validatable by implementing [validation.Validatable] interface.
@@ -666,6 +688,9 @@ func (c RateLimitRule) Validate() error {
validation.Field(&c.Label, validation.Required, validation.Match(rateLimitRuleLabelRegex)),
validation.Field(&c.MaxRequests, validation.Required, validation.Min(1)),
validation.Field(&c.Duration, validation.Required, validation.Min(1)),
validation.Field(&c.Audience,
validation.In(RateLimitRuleAudienceAll, RateLimitRuleAudienceGuest, RateLimitRuleAudienceAuth),
),
)
}
+113 -2
View File
@@ -106,7 +106,7 @@ func TestSettingsMarshalJSON(t *testing.T) {
}
rawStr := string(raw)
expected := `{"smtp":{"enabled":false,"port":0,"host":"","username":"abc","authMethod":"","tls":false,"localName":""},"backups":{"cron":"","cronMaxKeep":0,"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false}},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false},"meta":{"appName":"test123","appURL":"","senderName":"","senderAddress":"","hideControls":false},"logs":{"maxDays":0,"minLevel":0,"logIP":false,"logAuthId":false},"batch":{"enabled":false,"maxRequests":0,"timeout":0,"maxBodySize":0},"rateLimits":{"rules":[],"enabled":false},"trustedProxy":{"headers":[],"useLeftmostIP":false}}`
expected := `{"smtp":{"enabled":false,"port":0,"host":"","username":"abc","authMethod":"","tls":false,"localName":""},"backups":{"cron":"","cronMaxKeep":0,"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false}},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","forcePathStyle":false},"meta":{"appName":"test123","appURL":"","senderName":"","senderAddress":"","hideControls":false},"rateLimits":{"rules":[],"enabled":false},"trustedProxy":{"headers":[],"useLeftmostIP":false},"batch":{"enabled":false,"maxRequests":0,"timeout":0,"maxBodySize":0},"logs":{"maxDays":0,"minLevel":0,"logIP":false,"logAuthId":false}}`
if rawStr != expected {
t.Fatalf("Expected\n%v\ngot\n%v", expected, rawStr)
@@ -539,6 +539,86 @@ func TestRateLimitsConfigValidate(t *testing.T) {
},
[]string{},
},
{
"duplicated rules with the same audience",
core.RateLimitsConfig{
Enabled: true,
Rules: []core.RateLimitRule{
{
Label: "/a",
Duration: 1,
MaxRequests: 2,
},
{
Label: "/a",
Duration: 2,
MaxRequests: 3,
},
},
},
[]string{"rules"},
},
{
"duplicated rule with conflicting audience (A)",
core.RateLimitsConfig{
Enabled: true,
Rules: []core.RateLimitRule{
{
Label: "/a",
Duration: 1,
MaxRequests: 2,
},
{
Label: "/a",
Duration: 1,
MaxRequests: 2,
Audience: core.RateLimitRuleAudienceGuest,
},
},
},
[]string{"rules"},
},
{
"duplicated rule with conflicting audience (B)",
core.RateLimitsConfig{
Enabled: true,
Rules: []core.RateLimitRule{
{
Label: "/a",
Duration: 1,
MaxRequests: 2,
Audience: core.RateLimitRuleAudienceAuth,
},
{
Label: "/a",
Duration: 1,
MaxRequests: 2,
},
},
},
[]string{"rules"},
},
{
"duplicated rule with non-conflicting audience",
core.RateLimitsConfig{
Enabled: true,
Rules: []core.RateLimitRule{
{
Label: "/a",
Duration: 1,
MaxRequests: 2,
Audience: core.RateLimitRuleAudienceAuth,
},
{
Label: "/a",
Duration: 1,
MaxRequests: 2,
Audience: core.RateLimitRuleAudienceGuest,
},
},
},
[]string{},
},
}
for _, s := range scenarios {
@@ -611,8 +691,9 @@ func TestRateLimitRuleValidate(t *testing.T) {
Label: "@abc",
Duration: -1,
MaxRequests: -1,
Audience: "invalid",
},
[]string{"label", "duration", "maxRequests"},
[]string{"label", "duration", "maxRequests", "audience"},
},
{
"valid data (name)",
@@ -659,6 +740,36 @@ func TestRateLimitRuleValidate(t *testing.T) {
},
[]string{},
},
{
"invalid audience",
core.RateLimitRule{
Label: "/a/b/",
Duration: 1,
MaxRequests: 1,
Audience: "invalid",
},
[]string{"audience"},
},
{
"valid audience - " + core.RateLimitRuleAudienceGuest,
core.RateLimitRule{
Label: "POST /a/b/",
Duration: 1,
MaxRequests: 1,
Audience: core.RateLimitRuleAudienceGuest,
},
[]string{},
},
{
"valid audience - " + core.RateLimitRuleAudienceAuth,
core.RateLimitRule{
Label: "POST /a/b/",
Duration: 1,
MaxRequests: 1,
Audience: core.RateLimitRuleAudienceAuth,
},
[]string{},
},
}
for _, s := range scenarios {
+32 -32
View File
@@ -4,56 +4,56 @@ go 1.23
require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/aws/aws-sdk-go-v2 v1.32.2
github.com/aws/aws-sdk-go-v2/config v1.28.0
github.com/aws/aws-sdk-go-v2/credentials v1.17.41
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0
github.com/aws/aws-sdk-go-v2 v1.32.4
github.com/aws/aws-sdk-go-v2/config v1.28.3
github.com/aws/aws-sdk-go-v2/credentials v1.17.44
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3
github.com/aws/smithy-go v1.22.0
github.com/disintegration/imaging v1.6.2
github.com/domodwyer/mailyak/v3 v3.6.2
github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3
github.com/dop251/goja_nodejs v0.0.0-20240728170619-29b559befffc
github.com/fatih/color v1.17.0
github.com/fatih/color v1.18.0
github.com/fsnotify/fsnotify v1.7.0
github.com/gabriel-vasile/mimetype v1.4.6
github.com/ganigeorgiev/fexpr v0.4.1
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang-jwt/jwt/v4 v4.5.1
github.com/pocketbase/dbx v1.10.1
github.com/pocketbase/tygoja v0.0.0-20241015175937-d6ff411a0f75
github.com/spf13/cast v1.7.0
github.com/spf13/cobra v1.8.1
gocloud.dev v0.40.0
golang.org/x/crypto v0.28.0
golang.org/x/net v0.30.0
golang.org/x/oauth2 v0.23.0
golang.org/x/sync v0.8.0
golang.org/x/crypto v0.29.0
golang.org/x/net v0.31.0
golang.org/x/oauth2 v0.24.0
golang.org/x/sync v0.9.0
modernc.org/sqlite v1.33.1
)
require (
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/googleapis/gax-go/v2 v2.14.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
@@ -65,17 +65,17 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.8.2 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/image v0.21.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/term v0.25.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/tools v0.26.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/image v0.22.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/term v0.26.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.27.0 // indirect
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
google.golang.org/api v0.201.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/grpc v1.67.1 // indirect
google.golang.org/api v0.205.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113154021-e0fbfb71d213 // indirect
google.golang.org/grpc v1.68.0 // indirect
google.golang.org/protobuf v1.35.1 // indirect
modernc.org/gc/v3 v3.0.0-20241004144649-1aea3fae8852 // indirect
modernc.org/libc v1.61.0 // indirect
+72 -72
View File
@@ -1,10 +1,10 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE=
cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U=
cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8=
cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
cloud.google.com/go/auth v0.10.1 h1:TnK46qldSfHWt2a0b/hciaiVJsmDXWy9FqyUan0uYiI=
cloud.google.com/go/auth v0.10.1/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI=
cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk=
cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8=
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
cloud.google.com/go/iam v1.1.13 h1:7zWBXG9ERbMLrzQBRhFliAV+kjcRToDTgQT3CTwYyv4=
@@ -25,42 +25,42 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI=
github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE=
github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0DfJUEQuqPild8jRGmSFmBgvydr0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA=
github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ=
github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc=
github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8=
github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33 h1:X+4YY5kZRI/cOoSMVMGTqFXHAMg1bvvay7IBcqHpybQ=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.33/go.mod h1:DPynzu+cn92k5UQ6tZhX+wfTB4ah6QDU/NgdHqatmvk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60=
github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM=
github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4=
github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU=
github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37 h1:jHKR76E81sZvz1+x1vYYrHMxphG5LFBJPhSqEr4CLlE=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.37/go.mod h1:iMkyPkmoJWQKzSOtaX+8oEJxAuqr7s8laxcqGDSHeII=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21 h1:7edmS3VOBDhK00b/MwGtGglCm7hhwNYnjJs/PgFdMQE=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.21/go.mod h1:Q9o5h4HoIWG8XfzxqiuK/CGUbepCJ8uTlaE3bAbxytQ=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23 h1:1SZBDiRzzs3sNhOMVApyWPduWYGAX0imGy06XiBnCAM=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.23/go.mod h1:i9TkxgbZmHVh2S0La6CAXtnyFhlCX/pJ0JsOvBAS6Mk=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2 h1:4FMHqLfk0efmTqhXVRL5xYRqlEBNBiRI7N6w4jsEdd4=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.2/go.mod h1:LWoqeWlK9OZeJxsROW2RqrSPvQHKTpp69r/iDjwsSaw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2 h1:t7iUP9+4wdc5lt3E41huP+GvQZJD38WLsgVp4iOtAjg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.2/go.mod h1:/niFCtmuQNxqx9v8WAPq5qh7EH25U4BF6tjoyq9bObM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0 h1:xA6XhTF7PE89BCNHJbQi8VvPzcgMtmGC5dr8S8N7lHk=
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.0/go.mod h1:cB6oAuus7YXRZhWCc1wIwPywwZ1XwweNp2TVAEGYeB8=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4 h1:aaPpoG15S2qHkWm4KlEyF01zovK1nW4BBbyXuHNSE90=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.4/go.mod h1:eD9gS2EARTKgGr/W5xwgY/ik9z/zqpW+m/xOQbVxrMk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4 h1:E5ZAVOmI2apR8ADb72Q63KqwwwdW1XcMeXIlrZ1Psjg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.4/go.mod h1:wezzqVUOVVdk+2Z/JzQT4NxAU0NbhRe5W8pIE72jsWI=
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3 h1:neNOYJl72bHrz9ikAEED4VqWyND/Po0DnEx64RW6YM4=
github.com/aws/aws-sdk-go-v2/service/s3 v1.66.3/go.mod h1:TMhLIyRIyoGVlaEMAt+ITMbwskSTpcGsCPDq91/ihY0=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40=
github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU=
github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8=
github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM=
github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@@ -88,8 +88,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
@@ -111,8 +111,8 @@ github.com/go-sourcemap/sourcemap v2.1.4+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@@ -149,8 +149,8 @@ github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o=
github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
@@ -223,20 +223,20 @@ gocloud.dev v0.40.0/go.mod h1:drz+VyYNBvrMTW0KZiBAYEdl8lbNZx+OQ7oQvdrFmSQ=
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.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
golang.org/x/image v0.22.0 h1:UtK5yLUzilVrkjMAZAZ34DXGpASN8i8pj8g+O+yd10g=
golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4=
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=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -247,17 +247,17 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
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=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -269,19 +269,19 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
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=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -291,33 +291,33 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
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.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
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-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0=
google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4=
google.golang.org/api v0.205.0 h1:LFaxkAIpDb/GsrWV20dMMo5MR0h8UARTbn24LmD+0Pg=
google.golang.org/api v0.205.0/go.mod h1:NrK1EMqO8Xk6l6QwRAmrXXg2v6dzukhlOyvkYtnvUuc=
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/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-20241007155032-5fefd90f89a9 h1:nFS3IivktIU5Mk6KQa+v6RKkHUpdQpphqGNLxqNnbEk=
google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:tEzYTYZxbmVNOu0OAFH9HzdJtLn6h4Aj89zzlBCdHms=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU=
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4=
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g=
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113154021-e0fbfb71d213 h1:L+WcQXqkyf5MX6g7AudgYEuJjmYbqSRkTmJqGfAPw+Y=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241113154021-e0fbfb71d213/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
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=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+40 -1
View File
@@ -40,6 +40,8 @@ func SendRecordAuthAlert(app core.App, authRecord *core.Record) error {
}
// SendRecordOTP sends OTP email to the specified auth record.
//
// This method will also update the "sentTo" field of the related OTP record to the mail sent To address (if the OTP exists and not already assigned).
func SendRecordOTP(app core.App, authRecord *core.Record, otpId string, pass string) error {
mailClient := app.NewMailClient()
@@ -72,7 +74,44 @@ func SendRecordOTP(app core.App, authRecord *core.Record, otpId string, pass str
}
return app.OnMailerRecordOTPSend().Trigger(event, func(e *core.MailerRecordEvent) error {
return e.Mailer.Send(e.Message)
err := e.Mailer.Send(e.Message)
if err != nil {
return err
}
var toAddress string
if len(e.Message.To) > 0 {
toAddress = e.Message.To[0].Address
}
if toAddress == "" {
return nil
}
otp, err := e.App.FindOTPById(otpId)
if err != nil {
e.App.Logger().Error(
"Failed to find OTP to update its sentTo field",
"error", err,
"otpId", otpId,
)
return nil
}
if otp.SentTo() != "" {
return nil // was already sent to another target
}
otp.SetSentTo(toAddress)
if err = e.App.Save(otp); err != nil {
e.App.Logger().Error(
"Failed to update OTP sentTo field",
"error", err,
"otpId", otpId,
"to", toAddress,
)
}
return nil
})
}
+19 -6
View File
@@ -118,7 +118,7 @@ func createParamsTable(txApp core.App) error {
}
func createMFAsCollection(txApp core.App) error {
col := core.NewBaseCollection(core.CollectionNameMFAs, "_pbc"+core.CollectionNameMFAs)
col := core.NewBaseCollection(core.CollectionNameMFAs)
col.System = true
ownerRule := "@request.auth.id != '' && recordRef = @request.auth.id && collectionRef = @request.auth.collectionId"
@@ -157,7 +157,7 @@ func createMFAsCollection(txApp core.App) error {
}
func createOTPsCollection(txApp core.App) error {
col := core.NewBaseCollection(core.CollectionNameOTPs, "_pbc"+core.CollectionNameOTPs)
col := core.NewBaseCollection(core.CollectionNameOTPs)
col.System = true
ownerRule := "@request.auth.id != '' && recordRef = @request.auth.id && collectionRef = @request.auth.collectionId"
@@ -179,7 +179,12 @@ func createOTPsCollection(txApp core.App) error {
System: true,
Hidden: true,
Required: true,
Cost: 8, // low cost for better performce and because it is not critical
Cost: 8, // low cost for better performance and because it is not critical
})
col.Fields.Add(&core.TextField{
Name: "sentTo",
System: true,
Hidden: true,
})
col.Fields.Add(&core.AutodateField{
Name: "created",
@@ -198,7 +203,7 @@ func createOTPsCollection(txApp core.App) error {
}
func createAuthOriginsCollection(txApp core.App) error {
col := core.NewBaseCollection(core.CollectionNameAuthOrigins, "_pbc"+core.CollectionNameAuthOrigins)
col := core.NewBaseCollection(core.CollectionNameAuthOrigins)
col.System = true
ownerRule := "@request.auth.id != '' && recordRef = @request.auth.id && collectionRef = @request.auth.collectionId"
@@ -238,7 +243,7 @@ func createAuthOriginsCollection(txApp core.App) error {
}
func createExternalAuthsCollection(txApp core.App) error {
col := core.NewBaseCollection(core.CollectionNameExternalAuths, "_pbc"+core.CollectionNameExternalAuths)
col := core.NewBaseCollection(core.CollectionNameExternalAuths)
col.System = true
ownerRule := "@request.auth.id != '' && recordRef = @request.auth.id && collectionRef = @request.auth.collectionId"
@@ -284,7 +289,7 @@ func createExternalAuthsCollection(txApp core.App) error {
}
func createSuperusersCollection(txApp core.App) error {
superusers := core.NewAuthCollection(core.CollectionNameSuperusers, "_pbc"+core.CollectionNameSuperusers)
superusers := core.NewAuthCollection(core.CollectionNameSuperusers)
superusers.System = true
superusers.Fields.Add(&core.EmailField{
Name: "email",
@@ -309,6 +314,14 @@ func createSuperusersCollection(txApp core.App) error {
func createUsersCollection(txApp core.App) error {
users := core.NewAuthCollection("users", "_pb_users_auth_")
ownerRule := "id = @request.auth.id"
users.ListRule = types.Pointer(ownerRule)
users.ViewRule = types.Pointer(ownerRule)
users.CreateRule = types.Pointer("")
users.UpdateRule = types.Pointer(ownerRule)
users.DeleteRule = types.Pointer(ownerRule)
users.Fields.Add(&core.TextField{
Name: "name",
Max: 255,
+145
View File
@@ -0,0 +1,145 @@
package migrations
import (
"hash/crc32"
"strconv"
"github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
)
// note: this migration will be deleted in future version
func collectionIdChecksum(c *core.Collection) string {
return "pbc_" + strconv.Itoa(int(crc32.ChecksumIEEE([]byte(c.Type+c.Name))))
}
func fieldIdChecksum(f core.Field) string {
return f.Type() + strconv.Itoa(int(crc32.ChecksumIEEE([]byte(f.GetName()))))
}
// normalize system collection and field ids
func init() {
core.SystemMigrations.Register(func(txApp core.App) error {
collections := []*core.Collection{}
err := txApp.CollectionQuery().
AndWhere(dbx.In(
"name",
core.CollectionNameMFAs,
core.CollectionNameOTPs,
core.CollectionNameExternalAuths,
core.CollectionNameAuthOrigins,
core.CollectionNameSuperusers,
)).
All(&collections)
if err != nil {
return err
}
for _, c := range collections {
var needUpdate bool
references, err := txApp.FindCollectionReferences(c, c.Id)
if err != nil {
return err
}
authOrigins, err := txApp.FindAllAuthOriginsByCollection(c)
if err != nil {
return err
}
mfas, err := txApp.FindAllMFAsByCollection(c)
if err != nil {
return err
}
otps, err := txApp.FindAllOTPsByCollection(c)
if err != nil {
return err
}
originalId := c.Id
// normalize collection id
if checksum := collectionIdChecksum(c); c.Id != checksum {
c.Id = checksum
needUpdate = true
}
// normalize system fields
for _, f := range c.Fields {
if !f.GetSystem() {
continue
}
if checksum := fieldIdChecksum(f); f.GetId() != checksum {
f.SetId(checksum)
needUpdate = true
}
}
if !needUpdate {
continue
}
rawExport, err := c.DBExport(txApp)
if err != nil {
return err
}
_, err = txApp.DB().Update("_collections", rawExport, dbx.HashExp{"id": originalId}).Execute()
if err != nil {
return err
}
// make sure that the cached collection id is also updated
cached, err := txApp.FindCachedCollectionByNameOrId(c.Name)
if err != nil {
return err
}
cached.Id = c.Id
// update collection references
for refCollection, fields := range references {
for _, f := range fields {
relationField, ok := f.(*core.RelationField)
if !ok || relationField.CollectionId == originalId {
continue
}
relationField.CollectionId = c.Id
}
if err = txApp.SaveNoValidate(refCollection); err != nil {
return err
}
}
// update mfas references
for _, item := range mfas {
item.SetCollectionRef(c.Id)
if err = txApp.SaveNoValidate(item); err != nil {
return err
}
}
// update otps references
for _, item := range otps {
item.SetCollectionRef(c.Id)
if err = txApp.SaveNoValidate(item); err != nil {
return err
}
}
// update authOrigins references
for _, item := range authOrigins {
item.SetCollectionRef(c.Id)
if err = txApp.SaveNoValidate(item); err != nil {
return err
}
}
}
return nil
}, nil)
}
+30
View File
@@ -0,0 +1,30 @@
package migrations
import (
"github.com/pocketbase/pocketbase/core"
)
// note: this migration will be deleted in future version
// add new OTP sentTo text field (if not already)
func init() {
core.SystemMigrations.Register(func(txApp core.App) error {
otpCollection, err := txApp.FindCollectionByNameOrId(core.CollectionNameOTPs)
if err != nil {
return err
}
field := otpCollection.Fields.GetByName("sentTo")
if field != nil {
return nil // already exists
}
otpCollection.Fields.Add(&core.TextField{
Name: "sentTo",
System: true,
Hidden: true,
})
return txApp.Save(otpCollection)
}, nil)
}
-1
View File
@@ -728,7 +728,6 @@ func apisBinds(vm *goja.Runtime) {
obj.Set("requireGuestOnly", apis.RequireGuestOnly)
obj.Set("requireAuth", apis.RequireAuth)
obj.Set("requireSuperuserAuth", apis.RequireSuperuserAuth)
obj.Set("requireSuperuserAuthOnlyIfAny", apis.RequireSuperuserAuthOnlyIfAny)
obj.Set("requireSuperuserOrOwnerAuth", apis.RequireSuperuserOrOwnerAuth)
obj.Set("skipSuccessActivityLog", apis.SkipSuccessActivityLog)
obj.Set("gzip", apis.Gzip)
+1 -1
View File
@@ -998,7 +998,7 @@ func TestApisBindsCount(t *testing.T) {
apisBinds(vm)
testBindsCount(vm, "this", 8, t)
testBindsCount(vm, "$apis", 12, t)
testBindsCount(vm, "$apis", 11, t)
}
func TestApisBindsApiError(t *testing.T) {
File diff suppressed because it is too large Load Diff
+10 -6
View File
@@ -104,7 +104,7 @@ declare function routerAdd(
*
* @group PocketBase
*/
declare function routerUse(...middlewares: Array<string|((e: core.RequestEvent) => void)|Middleware): void;
declare function routerUse(...middlewares: Array<string|((e: core.RequestEvent) => void)|Middleware>): void;
// -------------------------------------------------------------------
// baseBinds
@@ -527,7 +527,6 @@ declare class Command implements cobra.Command {
constructor(cmd?: Partial<cobra.Command>)
}
interface RequestInfo extends core.RequestInfo{} // merge
/**
* RequestInfo defines a single core.RequestInfo instance, usually used
* as part of various filter checks.
@@ -550,8 +549,10 @@ interface RequestInfo extends core.RequestInfo{} // merge
*
* @group PocketBase
*/
declare class RequestInfo implements core.RequestInfo {
constructor(info?: Partial<core.RequestInfo>)
declare const RequestInfo: {
new(info?: Partial<core.RequestInfo>): core.RequestInfo
// note: declare as "newable" const due to conflict with the RequestInfo TS node type
}
/**
@@ -845,7 +846,11 @@ declare namespace $os {
*/
export let cmd: exec.command
export let args: os.args
/**
* Args hold the command-line arguments, starting with the program name.
*/
export let args: Array<string>
export let exit: os.exit
export let getenv: os.getenv
export let dirFS: os.dirFS
@@ -993,7 +998,6 @@ declare namespace $apis {
let requireGuestOnly: apis.requireGuestOnly
let requireAuth: apis.requireAuth
let requireSuperuserAuth: apis.requireSuperuserAuth
let requireSuperuserAuthOnlyIfAny: apis.requireSuperuserAuthOnlyIfAny
let requireSuperuserOrOwnerAuth: apis.requireSuperuserOrOwnerAuth
let skipSuccessActivityLog: apis.skipSuccessActivityLog
let gzip: apis.gzip
+2 -2
View File
@@ -62,7 +62,7 @@ func (p *plugin) jsSnapshotTemplate(collections []*core.Collection) (string, err
const template = jsTypesDirective + `migrate((app) => {
const snapshot = %s;
return app.importCollections(snapshot, true);
return app.importCollections(snapshot, false);
}, (app) => {
return null;
})
@@ -348,7 +348,7 @@ func init() {
m.Register(func(app core.App) error {
jsonData := ` + "`%s`" + `
return app.ImportCollectionsByMarshaledJSON([]byte(jsonData), true)
return app.ImportCollectionsByMarshaledJSON([]byte(jsonData), false)
}, func(app core.App) error {
return nil
})
+1 -1
View File
@@ -141,7 +141,7 @@ func NewWithConfig(config Config) *PocketBase {
}
// Start starts the application, aka. registers the default system
// commands (serve, migrate, version) and executes pb.RootCmd.
// commands (serve, superuser, version) and executes pb.RootCmd.
func (pb *PocketBase) Start() error {
// register system commands
pb.RootCmd.AddCommand(cmd.NewSuperuserCommand(pb))
Binary file not shown.
+10 -1
View File
@@ -7,7 +7,7 @@ import (
)
func TestProvidersCount(t *testing.T) {
expected := 27
expected := 28
if total := len(auth.Providers); total != expected {
t.Fatalf("Expected %d providers, got %d", expected, total)
@@ -269,4 +269,13 @@ func TestNewProviderByName(t *testing.T) {
if _, ok := p.(*auth.Monday); !ok {
t.Error("Expected to be instance of *auth.Monday")
}
// wakatime
p, err = auth.NewProviderByName(auth.NameWakatime)
if err != nil {
t.Errorf("Expected nil, got error %v", err)
}
if _, ok := p.(*auth.Wakatime); !ok {
t.Error("Expected to be instance of *auth.Wakatime")
}
}
+21 -11
View File
@@ -6,7 +6,6 @@ import (
"github.com/pocketbase/pocketbase/tools/types"
"golang.org/x/oauth2"
"golang.org/x/oauth2/instagram"
)
func init() {
@@ -16,9 +15,9 @@ func init() {
var _ Provider = (*Instagram)(nil)
// NameInstagram is the unique name of the Instagram provider.
const NameInstagram string = "instagram"
const NameInstagram string = "instagram2" // "2" suffix to avoid conflicts with the old deprecated version
// Instagram allows authentication via Instagram OAuth2.
// Instagram allows authentication via Instagram Login OAuth2.
type Instagram struct {
BaseProvider
}
@@ -29,16 +28,16 @@ func NewInstagramProvider() *Instagram {
ctx: context.Background(),
displayName: "Instagram",
pkce: true,
scopes: []string{"user_profile"},
authURL: instagram.Endpoint.AuthURL,
tokenURL: instagram.Endpoint.TokenURL,
userInfoURL: "https://graph.instagram.com/me?fields=id,username,account_type",
scopes: []string{"instagram_business_basic"},
authURL: "https://www.instagram.com/oauth/authorize",
tokenURL: "https://api.instagram.com/oauth/access_token",
userInfoURL: "https://graph.instagram.com/me?fields=id,username,account_type,user_id,name,profile_picture_url,followers_count,follows_count,media_count",
}}
}
// FetchAuthUser returns an AuthUser instance based on the Instagram's user api.
// FetchAuthUser returns an AuthUser instance based on the Instagram Login user api response.
//
// API reference: https://developers.facebook.com/docs/instagram-basic-display-api/reference/user#fields
// API reference: https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/get-started#fields
func (p *Instagram) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserInfo(token)
if err != nil {
@@ -50,9 +49,18 @@ func (p *Instagram) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
return nil, err
}
// include list of granted permissions to RawUser's payload
if _, ok := rawUser["permissions"]; !ok {
if permissions := token.Extra("permissions"); permissions != nil {
rawUser["permissions"] = permissions
}
}
extracted := struct {
Id string `json:"id"`
Username string `json:"username"`
Id string `json:"user_id"`
Name string `json:"name"`
Username string `json:"username"`
AvatarURL string `json:"profile_picture_url"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
return nil, err
@@ -61,6 +69,8 @@ func (p *Instagram) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
user := &AuthUser{
Id: extracted.Id,
Username: extracted.Username,
Name: extracted.Name,
AvatarURL: extracted.AvatarURL,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
+90
View File
@@ -0,0 +1,90 @@
package auth
import (
"context"
"encoding/json"
"github.com/pocketbase/pocketbase/tools/types"
"golang.org/x/oauth2"
)
func init() {
Providers[NameWakatime] = wrapFactory(NewWakatimeProvider)
}
var _ Provider = (*Wakatime)(nil)
// NameWakatime is the unique name of the Wakatime provider.
const NameWakatime = "wakatime"
// Wakatime is an auth provider for Wakatime.
type Wakatime struct {
BaseProvider
}
// NewWakatimeProvider creates a new Wakatime provider instance with some defaults.
func NewWakatimeProvider() *Wakatime {
return &Wakatime{BaseProvider{
ctx: context.Background(),
displayName: "WakaTime",
pkce: true,
scopes: []string{"email"},
authURL: "https://wakatime.com/oauth/authorize",
tokenURL: "https://wakatime.com/oauth/token",
userInfoURL: "https://wakatime.com/api/v1/users/current",
}}
}
// FetchAuthUser returns an AuthUser instance based on the Wakatime's user API.
//
// API reference: https://wakatime.com/developers#users
func (p *Wakatime) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
data, err := p.FetchRawUserInfo(token)
if err != nil {
return nil, err
}
rawUser := map[string]any{}
if err := json.Unmarshal(data, &rawUser); err != nil {
return nil, err
}
extracted := struct {
Data struct {
Id string `json:"id"`
DisplayName string `json:"display_name"`
Username string `json:"username"`
Email string `json:"email"`
Photo string `json:"photo"`
IsPhotoPublic bool `json:"photo_public"`
IsEmailConfirmed bool `json:"is_email_confirmed"`
} `json:"data"`
}{}
if err := json.Unmarshal(data, &extracted); err != nil {
return nil, err
}
user := &AuthUser{
Id: extracted.Data.Id,
Name: extracted.Data.DisplayName,
Username: extracted.Data.Username,
RawUser: rawUser,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
}
// note: we don't check for is_email_public field because PocketBase
// has its own emailVisibility flag which is false by default
if extracted.Data.IsEmailConfirmed {
user.Email = extracted.Data.Email
}
if extracted.Data.IsPhotoPublic {
user.AvatarURL = extracted.Data.Photo
}
user.Expiry, _ = types.ParseDateTime(token.Expiry)
return user, nil
}
-31
View File
@@ -96,37 +96,6 @@ func (e *Event) RemoteIP() string {
return parsed.StringExpanded()
}
// UnsafeRealIP returns the "real" client IP from common proxy headers
// OR fallbacks to the RemoteIP if none is found.
//
// NB! The returned IP value could be anything and it shouldn't be trusted if not behind a trusted reverse proxy!
func (e *Event) UnsafeRealIP() string {
if ip := e.Request.Header.Get("CF-Connecting-IP"); ip != "" {
return ip
}
if ip := e.Request.Header.Get("Fly-Client-IP"); ip != "" {
return ip
}
if ip := e.Request.Header.Get("X-Real-IP"); ip != "" {
return ip
}
if ipsList := e.Request.Header.Get("X-Forwarded-For"); ipsList != "" {
// extract the first non-empty leftmost-ish ip
ips := strings.Split(ipsList, ",")
for _, ip := range ips {
ip = strings.TrimSpace(ip)
if ip != "" {
return ip
}
}
}
return e.RemoteIP()
}
// FindUploadedFiles extracts all form files of "key" from a http request
// and returns a slice with filesystem.File instances (if any).
func (e *Event) FindUploadedFiles(key string) ([]*filesystem.File, error) {
-59
View File
@@ -219,65 +219,6 @@ func TestEventRemoteIP(t *testing.T) {
}
}
func TestEventUnsafeRealIP(t *testing.T) {
t.Parallel()
scenarios := []struct {
headers map[string]string
expected string
}{
{nil, "1.2.3.4"},
{
map[string]string{"CF-Connecting-IP": "test"},
"test",
},
{
map[string]string{"Fly-Client-IP": "test"},
"test",
},
{
map[string]string{"X-Real-IP": "test"},
"test",
},
{
map[string]string{"X-Forwarded-For": "test1,test2,test3"},
"test1",
},
}
for i, s := range scenarios {
keys := make([]string, 0, len(s.headers))
for h := range s.headers {
keys = append(keys, h)
}
testName := strings.Join(keys, "_")
if testName == "" {
testName = "no_headers" + strconv.Itoa(i)
}
t.Run(testName, func(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, "/", nil)
if err != nil {
t.Fatal(err)
}
req.RemoteAddr = "1.2.3.4:80" // fallback
for k, v := range s.headers {
req.Header.Set(k, v)
}
event := router.Event{Request: req}
ip := event.UnsafeRealIP()
if ip != s.expected {
t.Fatalf("Expected IP %q, got %q", s.expected, ip)
}
})
}
}
func TestFindUploadedFiles(t *testing.T) {
scenarios := []struct {
filename string
+31 -8
View File
@@ -34,9 +34,24 @@ var parsedFilterData = store.New(make(map[string][]fexpr.ExprGroup, 50))
//
// 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.
//
// The parsed expressions are limited up to DefaultFilterExprLimit.
// Use [FilterData.BuildExprWithLimit] if you want to set a custom limit.
func (f FilterData) BuildExpr(
fieldResolver FieldResolver,
placeholderReplacements ...dbx.Params,
) (dbx.Expression, error) {
return f.BuildExprWithLimit(fieldResolver, DefaultFilterExprLimit, placeholderReplacements...)
}
// BuildExpr parses the current filter data and returns a new db WHERE expression.
//
// 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) BuildExprWithLimit(
fieldResolver FieldResolver,
maxExpressions int,
placeholderReplacements ...dbx.Params,
) (dbx.Expression, error) {
raw := string(f)
@@ -64,8 +79,10 @@ func (f FilterData) BuildExpr(
}
}
if data, ok := parsedFilterData.GetOk(raw); ok {
return buildParsedFilterExpr(data, fieldResolver)
cacheKey := raw + "/" + strconv.Itoa(maxExpressions)
if data, ok := parsedFilterData.GetOk(cacheKey); ok {
return buildParsedFilterExpr(data, fieldResolver, &maxExpressions)
}
data, err := fexpr.Parse(raw)
@@ -82,14 +99,14 @@ func (f FilterData) BuildExpr(
// store in cache
// (the limit size is arbitrary and it is there to prevent the cache growing too big)
parsedFilterData.SetIfLessThanLimit(raw, data, 500)
parsedFilterData.SetIfLessThanLimit(cacheKey, data, 500)
return buildParsedFilterExpr(data, fieldResolver)
return buildParsedFilterExpr(data, fieldResolver, &maxExpressions)
}
func buildParsedFilterExpr(data []fexpr.ExprGroup, fieldResolver FieldResolver) (dbx.Expression, error) {
func buildParsedFilterExpr(data []fexpr.ExprGroup, fieldResolver FieldResolver, maxExpressions *int) (dbx.Expression, error) {
if len(data) == 0 {
return nil, errors.New("empty filter expression")
return nil, fexpr.ErrEmpty
}
result := &concatExpr{separator: " "}
@@ -100,11 +117,17 @@ func buildParsedFilterExpr(data []fexpr.ExprGroup, fieldResolver FieldResolver)
switch item := group.Item.(type) {
case fexpr.Expr:
if *maxExpressions <= 0 {
return nil, ErrFilterExprLimit
}
*maxExpressions--
expr, exprErr = resolveTokenizedExpr(item, fieldResolver)
case fexpr.ExprGroup:
expr, exprErr = buildParsedFilterExpr([]fexpr.ExprGroup{item}, fieldResolver)
expr, exprErr = buildParsedFilterExpr([]fexpr.ExprGroup{item}, fieldResolver, maxExpressions)
case []fexpr.ExprGroup:
expr, exprErr = buildParsedFilterExpr(item, fieldResolver)
expr, exprErr = buildParsedFilterExpr(item, fieldResolver, maxExpressions)
default:
exprErr = errors.New("unsupported expression item")
}
+30
View File
@@ -3,6 +3,7 @@ package search_test
import (
"context"
"database/sql"
"fmt"
"regexp"
"strings"
"testing"
@@ -239,6 +240,35 @@ func TestFilterDataBuildExprWithParams(t *testing.T) {
}
}
func TestFilterDataBuildExprWithLimit(t *testing.T) {
resolver := search.NewSimpleFieldResolver(`^\w+$`)
scenarios := []struct {
limit int
filter search.FilterData
expectError bool
}{
{1, "1 = 1", false},
{0, "1 = 1", true}, // new cache entry should be created
{2, "1 = 1 || 1 = 1", false},
{1, "1 = 1 || 1 = 1", true},
{3, "1 = 1 || 1 = 1", false},
{6, "(1=1 || 1=1) && (1=1 || (1=1 || 1=1)) && (1=1)", false},
{5, "(1=1 || 1=1) && (1=1 || (1=1 || 1=1)) && (1=1)", true},
}
for i, s := range scenarios {
t.Run(fmt.Sprintf("limit_%d:%d", i, s.limit), func(t *testing.T) {
_, err := s.filter.BuildExprWithLimit(resolver, s.limit)
hasErr := err != nil
if hasErr != s.expectError {
t.Fatalf("Expected hasErr %v, got %v", s.expectError, hasErr)
}
})
}
}
func TestLikeParamsWrapping(t *testing.T) {
// create a dummy db
sqlDB, err := sql.Open("sqlite", "file::memory:?cache=shared")
+72 -24
View File
@@ -12,15 +12,36 @@ import (
"golang.org/x/sync/errgroup"
)
// DefaultPerPage specifies the default returned search result items.
const DefaultPerPage int = 30
const (
// DefaultPerPage specifies the default number of returned search result items.
DefaultPerPage int = 30
// @todo consider making it configurable
//
// MaxPerPage specifies the maximum allowed search result items returned in a single page.
const MaxPerPage int = 1000
// DefaultFilterExprLimit specifies the default filter expressions limit.
DefaultFilterExprLimit int = 200
// url search query params
// DefaultSortExprLimit specifies the default sort expressions limit.
DefaultSortExprLimit int = 8
// MaxPerPage specifies the max allowed search result items returned in a single page.
MaxPerPage int = 1000
// MaxFilterLength specifies the max allowed individual search filter parsable length.
MaxFilterLength int = 3500
// MaxSortFieldLength specifies the max allowed individual sort field parsable length.
MaxSortFieldLength int = 255
)
// Common search errors.
var (
ErrEmptyQuery = errors.New("search query is not set")
ErrSortExprLimit = errors.New("max sort expressions limit reached")
ErrFilterExprLimit = errors.New("max filter expressions limit reached")
ErrFilterLengthLimit = errors.New("max filter length limit reached")
ErrSortFieldLengthLimit = errors.New("max sort field length limit reached")
)
// URL search query params
const (
PageQueryParam string = "page"
PerPageQueryParam string = "perPage"
@@ -40,17 +61,19 @@ type Result struct {
// Provider represents a single configured search provider instance.
type Provider struct {
fieldResolver FieldResolver
query *dbx.SelectQuery
countCol string
sort []SortField
filter []FilterData
page int
perPage int
skipTotal bool
fieldResolver FieldResolver
query *dbx.SelectQuery
countCol string
sort []SortField
filter []FilterData
page int
perPage int
skipTotal bool
maxFilterExprLimit int
maxSortExprLimit int
}
// NewProvider creates and returns a new search provider.
// NewProvider initializes and returns a new search provider.
//
// Example:
//
@@ -63,15 +86,31 @@ type Provider struct {
// ParseAndExec("page=2&filter=id>0&sort=-email", &models)
func NewProvider(fieldResolver FieldResolver) *Provider {
return &Provider{
fieldResolver: fieldResolver,
countCol: "id",
page: 1,
perPage: DefaultPerPage,
sort: []SortField{},
filter: []FilterData{},
fieldResolver: fieldResolver,
countCol: "id",
page: 1,
perPage: DefaultPerPage,
sort: []SortField{},
filter: []FilterData{},
maxFilterExprLimit: DefaultFilterExprLimit,
maxSortExprLimit: DefaultSortExprLimit,
}
}
// MaxFilterExpressions changes the default max allowed filter expressions.
//
// Note that currently the limit is applied individually for each separate filter.
func (s *Provider) MaxFilterExprLimit(max int) *Provider {
s.maxFilterExprLimit = max
return s
}
// MaxSortExpressions changes the default max allowed sort expressions.
func (s *Provider) MaxSortExprLimit(max int) *Provider {
s.maxSortExprLimit = max
return s
}
// Query sets the base query that will be used to fetch the search items.
func (s *Provider) Query(query *dbx.SelectQuery) *Provider {
s.query = query
@@ -188,7 +227,7 @@ func (s *Provider) Parse(urlQuery string) error {
// the provided `items` slice with the found models.
func (s *Provider) Exec(items any) (*Result, error) {
if s.query == nil {
return nil, errors.New("query is not set")
return nil, ErrEmptyQuery
}
// shallow clone the provider's query
@@ -196,7 +235,10 @@ func (s *Provider) Exec(items any) (*Result, error) {
// build filters
for _, f := range s.filter {
expr, err := f.BuildExpr(s.fieldResolver)
if len(f) > MaxFilterLength {
return nil, ErrFilterLengthLimit
}
expr, err := f.BuildExprWithLimit(s.fieldResolver, s.maxFilterExprLimit)
if err != nil {
return nil, err
}
@@ -206,7 +248,13 @@ func (s *Provider) Exec(items any) (*Result, error) {
}
// apply sorting
if len(s.sort) > s.maxSortExprLimit {
return nil, ErrSortExprLimit
}
for _, sortField := range s.sort {
if len(sortField.Name) > MaxSortFieldLength {
return nil, ErrSortFieldLengthLimit
}
expr, err := sortField.BuildExpr(s.fieldResolver)
if err != nil {
return nil, err
+185 -1
View File
@@ -6,6 +6,8 @@ import (
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"testing"
"time"
@@ -25,6 +27,46 @@ func TestNewProvider(t *testing.T) {
if p.perPage != DefaultPerPage {
t.Fatalf("Expected perPage %d, got %d", DefaultPerPage, p.perPage)
}
if p.maxFilterExprLimit != DefaultFilterExprLimit {
t.Fatalf("Expected maxFilterExprLimit %d, got %d", DefaultFilterExprLimit, p.maxFilterExprLimit)
}
if p.maxSortExprLimit != DefaultSortExprLimit {
t.Fatalf("Expected maxSortExprLimit %d, got %d", DefaultSortExprLimit, p.maxSortExprLimit)
}
}
func TestMaxFilterExprLimit(t *testing.T) {
p := NewProvider(&testFieldResolver{})
testVals := []int{0, -10, 10}
for _, val := range testVals {
t.Run("max_"+strconv.Itoa(val), func(t *testing.T) {
p.MaxFilterExprLimit(val)
if p.maxFilterExprLimit != val {
t.Fatalf("Expected maxFilterExprLimit to change to %d, got %d", val, p.maxFilterExprLimit)
}
})
}
}
func TestMaxSortExprLimit(t *testing.T) {
p := NewProvider(&testFieldResolver{})
testVals := []int{0, -10, 10}
for _, val := range testVals {
t.Run("max_"+strconv.Itoa(val), func(t *testing.T) {
p.MaxSortExprLimit(val)
if p.maxSortExprLimit != val {
t.Fatalf("Expected maxSortExprLimit to change to %d, got %d", val, p.maxSortExprLimit)
}
})
}
}
func TestProviderQuery(t *testing.T) {
@@ -428,6 +470,141 @@ func TestProviderExecNonEmptyQuery(t *testing.T) {
}
}
func TestProviderFilterAndSortLimits(t *testing.T) {
testDB, err := createTestDB()
if err != nil {
t.Fatal(err)
}
defer testDB.Close()
query := testDB.Select("*").
From("test").
Where(dbx.Not(dbx.HashExp{"test1": nil})).
OrderBy("test1 ASC")
scenarios := []struct {
name string
filter []FilterData
sort []SortField
maxFilterExprLimit int
maxSortExprLimit int
expectError bool
}{
// filter
{
"<= max filter length",
[]FilterData{
"1=2",
FilterData("1='" + strings.Repeat("a", MaxFilterLength-4) + "'"),
},
[]SortField{},
1,
0,
false,
},
{
"> max filter length",
[]FilterData{
"1=2",
FilterData("1='" + strings.Repeat("a", MaxFilterLength-3) + "'"),
},
[]SortField{},
1,
0,
true,
},
{
"<= max filter exprs",
[]FilterData{
"1=2",
"(1=1 || 1=1) && (1=1 || (1=1 || 1=1)) && (1=1)",
},
[]SortField{},
6,
0,
false,
},
{
"> max filter exprs",
[]FilterData{
"1=2",
"(1=1 || 1=1) && (1=1 || (1=1 || 1=1)) && (1=1)",
},
[]SortField{},
5,
0,
true,
},
// sort
{
"<= max sort field length",
[]FilterData{},
[]SortField{
{"id", SortAsc},
{"test1", SortDesc},
{strings.Repeat("a", MaxSortFieldLength), SortDesc},
},
0,
10,
false,
},
{
"> max sort field length",
[]FilterData{},
[]SortField{
{"id", SortAsc},
{"test1", SortDesc},
{strings.Repeat("b", MaxSortFieldLength+1), SortDesc},
},
0,
10,
true,
},
{
"<= max sort exprs",
[]FilterData{},
[]SortField{
{"id", SortAsc},
{"test1", SortDesc},
},
0,
2,
false,
},
{
"> max sort exprs",
[]FilterData{},
[]SortField{
{"id", SortAsc},
{"test1", SortDesc},
},
0,
1,
true,
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
testResolver := &testFieldResolver{}
p := NewProvider(testResolver).
Query(query).
Sort(s.sort).
Filter(s.filter).
MaxFilterExprLimit(s.maxFilterExprLimit).
MaxSortExprLimit(s.maxSortExprLimit)
_, err := p.Exec(&[]testTableStruct{})
hasErr := err != nil
if hasErr != s.expectError {
t.Fatalf("Expected hasErr %v, got %v", s.expectError, hasErr)
}
})
}
}
func TestProviderParseAndExec(t *testing.T) {
testDB, err := createTestDB()
if err != nil {
@@ -577,7 +754,14 @@ func createTestDB() (*testDB, error) {
}
db := testDB{DB: dbx.NewFromDB(sqlDB, "sqlite")}
db.CreateTable("test", map[string]string{"id": "int default 0", "test1": "int default 0", "test2": "text default ''", "test3": "text default ''"}).Execute()
db.CreateTable("test", map[string]string{
"id": "int default 0",
"test1": "int default 0",
"test2": "text default ''",
"test3": "text default ''",
strings.Repeat("a", MaxSortFieldLength): "text default ''",
strings.Repeat("b", MaxSortFieldLength+1): "text default ''",
}).Execute()
db.Insert("test", dbx.Params{"id": 1, "test1": 1, "test2": "test2.1"}).Execute()
db.Insert("test", dbx.Params{"id": 2, "test1": 2, "test2": "test2.2"}).Execute()
db.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
+5
View File
@@ -30,6 +30,11 @@ func (b *Broker) ChunkedClients(chunkSize int) [][]Client {
return list.ToChunks(b.store.Values(), chunkSize)
}
// TotalClients returns the total number of registered clients.
func (b *Broker) TotalClients() int {
return b.store.Length()
}
// ClientById finds a registered client by its id.
//
// Returns non-nil error when client with clientId is not registered.
+15
View File
@@ -62,6 +62,21 @@ func TestChunkedClients(t *testing.T) {
}
}
func TestTotalClients(t *testing.T) {
b := subscriptions.NewBroker()
if total := b.TotalClients(); total != 0 {
t.Fatalf("Expected no clients, got %d", total)
}
b.Register(subscriptions.NewDefaultClient())
b.Register(subscriptions.NewDefaultClient())
if total := b.TotalClients(); total != 2 {
t.Fatalf("Expected %d clients, got %d", 2, total)
}
}
func TestClientById(t *testing.T) {
b := subscriptions.NewBroker()
+1 -2
View File
@@ -1,6 +1,5 @@
# all environments should start with 'PB_' prefix
PB_BACKEND_URL = "../"
PB_INSTALLER_PARAM = "pbinstal"
PB_MFA_DOCS = "https://pocketbase.io/docs/authentication/#multi-factor-authentication"
PB_OAUTH2_EXAMPLE = "https://pocketbase.io/docs/authentication/#authenticate-with-oauth2"
PB_RULES_SYNTAX_DOCS = "https://pocketbase.io/docs/api-rules-and-filters/"
@@ -10,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.23.0-rc9"
PB_VERSION = "v0.23.0-rc13"
+39
View File
@@ -0,0 +1,39 @@
import{S as Be,i as Ce,s as Te,U as Le,W as I,f as c,y as w,h as k,c as ae,j as h,l as d,n as a,m as ne,G as Q,X as $e,Y as Se,D as Ue,Z as je,E as De,t as J,a as N,u,d as ie,p as oe,I as Ee,k as O,o as Re,V as qe}from"./index-DGnuRrBU.js";import{F as Fe}from"./FieldsQueryParam-DeLgGM_S.js";function we(n,s,l){const o=n.slice();return o[8]=s[l],o}function Me(n,s,l){const o=n.slice();return o[8]=s[l],o}function Ae(n,s){let l,o=s[8].code+"",p,b,i,f;function m(){return s[6](s[8])}return{key:n,first:null,c(){l=c("button"),p=w(o),b=k(),h(l,"class","tab-item"),O(l,"active",s[1]===s[8].code),this.first=l},m(v,y){d(v,l,y),a(l,p),a(l,b),i||(f=Re(l,"click",m),i=!0)},p(v,y){s=v,y&4&&o!==(o=s[8].code+"")&&Q(p,o),y&6&&O(l,"active",s[1]===s[8].code)},d(v){v&&u(l),i=!1,f()}}}function Pe(n,s){let l,o,p,b;return o=new qe({props:{content:s[8].body}}),{key:n,first:null,c(){l=c("div"),ae(o.$$.fragment),p=k(),h(l,"class","tab-item"),O(l,"active",s[1]===s[8].code),this.first=l},m(i,f){d(i,l,f),ne(o,l,null),a(l,p),b=!0},p(i,f){s=i;const m={};f&4&&(m.content=s[8].body),o.$set(m),(!b||f&6)&&O(l,"active",s[1]===s[8].code)},i(i){b||(J(o.$$.fragment,i),b=!0)},o(i){N(o.$$.fragment,i),b=!1},d(i){i&&u(l),ie(o)}}}function Ge(n){var ke,ge;let s,l,o=n[0].name+"",p,b,i,f,m,v,y,g=n[0].name+"",V,ce,W,M,X,L,Y,A,q,re,F,S,de,Z,G=n[0].name+"",z,ue,K,U,x,P,ee,fe,te,T,le,j,se,B,D,$=[],me=new Map,pe,E,_=[],be=new Map,C;M=new Le({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[3]}');
...
const result = await pb.collection('${(ke=n[0])==null?void 0:ke.name}').listAuthMethods();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[3]}');
...
final result = await pb.collection('${(ge=n[0])==null?void 0:ge.name}').listAuthMethods();
`}}),T=new Fe({});let H=I(n[2]);const he=e=>e[8].code;for(let e=0;e<H.length;e+=1){let t=Me(n,H,e),r=he(t);me.set(r,$[e]=Ae(r,t))}let R=I(n[2]);const _e=e=>e[8].code;for(let e=0;e<R.length;e+=1){let t=we(n,R,e),r=_e(t);be.set(r,_[e]=Pe(r,t))}return{c(){s=c("h3"),l=w("List auth methods ("),p=w(o),b=w(")"),i=k(),f=c("div"),m=c("p"),v=w("Returns a public list with all allowed "),y=c("strong"),V=w(g),ce=w(" authentication methods."),W=k(),ae(M.$$.fragment),X=k(),L=c("h6"),L.textContent="API details",Y=k(),A=c("div"),q=c("strong"),q.textContent="GET",re=k(),F=c("div"),S=c("p"),de=w("/api/collections/"),Z=c("strong"),z=w(G),ue=w("/auth-methods"),K=k(),U=c("div"),U.textContent="Query parameters",x=k(),P=c("table"),ee=c("thead"),ee.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',fe=k(),te=c("tbody"),ae(T.$$.fragment),le=k(),j=c("div"),j.textContent="Responses",se=k(),B=c("div"),D=c("div");for(let e=0;e<$.length;e+=1)$[e].c();pe=k(),E=c("div");for(let e=0;e<_.length;e+=1)_[e].c();h(s,"class","m-b-sm"),h(f,"class","content txt-lg m-b-sm"),h(L,"class","m-b-xs"),h(q,"class","label label-primary"),h(F,"class","content"),h(A,"class","alert alert-info"),h(U,"class","section-title"),h(P,"class","table-compact table-border m-b-base"),h(j,"class","section-title"),h(D,"class","tabs-header compact combined left"),h(E,"class","tabs-content"),h(B,"class","tabs")},m(e,t){d(e,s,t),a(s,l),a(s,p),a(s,b),d(e,i,t),d(e,f,t),a(f,m),a(m,v),a(m,y),a(y,V),a(m,ce),d(e,W,t),ne(M,e,t),d(e,X,t),d(e,L,t),d(e,Y,t),d(e,A,t),a(A,q),a(A,re),a(A,F),a(F,S),a(S,de),a(S,Z),a(Z,z),a(S,ue),d(e,K,t),d(e,U,t),d(e,x,t),d(e,P,t),a(P,ee),a(P,fe),a(P,te),ne(T,te,null),d(e,le,t),d(e,j,t),d(e,se,t),d(e,B,t),a(B,D);for(let r=0;r<$.length;r+=1)$[r]&&$[r].m(D,null);a(B,pe),a(B,E);for(let r=0;r<_.length;r+=1)_[r]&&_[r].m(E,null);C=!0},p(e,[t]){var ve,ye;(!C||t&1)&&o!==(o=e[0].name+"")&&Q(p,o),(!C||t&1)&&g!==(g=e[0].name+"")&&Q(V,g);const r={};t&9&&(r.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
const result = await pb.collection('${(ve=e[0])==null?void 0:ve.name}').listAuthMethods();
`),t&9&&(r.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
final result = await pb.collection('${(ye=e[0])==null?void 0:ye.name}').listAuthMethods();
`),M.$set(r),(!C||t&1)&&G!==(G=e[0].name+"")&&Q(z,G),t&6&&(H=I(e[2]),$=$e($,t,he,1,e,H,me,D,Se,Ae,null,Me)),t&6&&(R=I(e[2]),Ue(),_=$e(_,t,_e,1,e,R,be,E,je,Pe,null,we),De())},i(e){if(!C){J(M.$$.fragment,e),J(T.$$.fragment,e);for(let t=0;t<R.length;t+=1)J(_[t]);C=!0}},o(e){N(M.$$.fragment,e),N(T.$$.fragment,e);for(let t=0;t<_.length;t+=1)N(_[t]);C=!1},d(e){e&&(u(s),u(i),u(f),u(W),u(X),u(L),u(Y),u(A),u(K),u(U),u(x),u(P),u(le),u(j),u(se),u(B)),ie(M,e),ie(T);for(let t=0;t<$.length;t+=1)$[t].d();for(let t=0;t<_.length;t+=1)_[t].d()}}}function He(n,s,l){let o,{collection:p}=s,b=200,i=[],f={},m=!1;v();async function v(){l(5,m=!0);try{l(4,f=await oe.collection(p.name).listAuthMethods())}catch(g){oe.error(g)}l(5,m=!1)}const y=g=>l(1,b=g.code);return n.$$set=g=>{"collection"in g&&l(0,p=g.collection)},n.$$.update=()=>{n.$$.dirty&48&&l(2,i=[{code:200,body:m?"...":JSON.stringify(f,null,2)},{code:404,body:`
{
"code": 404,
"message": "Missing collection context.",
"data": {}
}
`}])},l(3,o=Ee.getApiExampleUrl(oe.baseURL)),[p,b,i,o,f,m,y]}class Je extends Be{constructor(s){super(),Ce(this,s,He,Ge,Te,{collection:0})}}export{Je as default};
-39
View File
@@ -1,39 +0,0 @@
import{S as Ce,i as Be,s as Te,Q as Le,T as G,e as c,w as $,b as k,c as ae,f as h,g as d,h as a,m as ne,x as I,U as ye,V as Re,k as Se,W as Ue,n as Qe,t as J,a as N,o as u,d as ie,p as oe,C as je,r as O,u as qe,R as De}from"./index-Co7n6kj7.js";import{F as Ee}from"./FieldsQueryParam-DH-ZC4qv.js";function $e(n,s,l){const o=n.slice();return o[8]=s[l],o}function Me(n,s,l){const o=n.slice();return o[8]=s[l],o}function Ae(n,s){let l,o=s[8].code+"",p,b,i,f;function m(){return s[6](s[8])}return{key:n,first:null,c(){l=c("button"),p=$(o),b=k(),h(l,"class","tab-item"),O(l,"active",s[1]===s[8].code),this.first=l},m(v,w){d(v,l,w),a(l,p),a(l,b),i||(f=qe(l,"click",m),i=!0)},p(v,w){s=v,w&4&&o!==(o=s[8].code+"")&&I(p,o),w&6&&O(l,"active",s[1]===s[8].code)},d(v){v&&u(l),i=!1,f()}}}function Pe(n,s){let l,o,p,b;return o=new De({props:{content:s[8].body}}),{key:n,first:null,c(){l=c("div"),ae(o.$$.fragment),p=k(),h(l,"class","tab-item"),O(l,"active",s[1]===s[8].code),this.first=l},m(i,f){d(i,l,f),ne(o,l,null),a(l,p),b=!0},p(i,f){s=i;const m={};f&4&&(m.content=s[8].body),o.$set(m),(!b||f&6)&&O(l,"active",s[1]===s[8].code)},i(i){b||(J(o.$$.fragment,i),b=!0)},o(i){N(o.$$.fragment,i),b=!1},d(i){i&&u(l),ie(o)}}}function Fe(n){var ke,ge;let s,l,o=n[0].name+"",p,b,i,f,m,v,w,g=n[0].name+"",V,ce,W,M,z,L,K,A,D,re,E,R,de,X,F=n[0].name+"",Y,ue,Z,S,x,P,ee,fe,te,T,le,U,se,C,Q,y=[],me=new Map,pe,j,_=[],be=new Map,B;M=new Le({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[3]}');
...
const result = await pb.collection('${(ke=n[0])==null?void 0:ke.name}').listAuthMethods();
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[3]}');
...
final result = await pb.collection('${(ge=n[0])==null?void 0:ge.name}').listAuthMethods();
`}}),T=new Ee({});let H=G(n[2]);const he=e=>e[8].code;for(let e=0;e<H.length;e+=1){let t=Me(n,H,e),r=he(t);me.set(r,y[e]=Ae(r,t))}let q=G(n[2]);const _e=e=>e[8].code;for(let e=0;e<q.length;e+=1){let t=$e(n,q,e),r=_e(t);be.set(r,_[e]=Pe(r,t))}return{c(){s=c("h3"),l=$("List auth methods ("),p=$(o),b=$(")"),i=k(),f=c("div"),m=c("p"),v=$("Returns a public list with all allowed "),w=c("strong"),V=$(g),ce=$(" authentication methods."),W=k(),ae(M.$$.fragment),z=k(),L=c("h6"),L.textContent="API details",K=k(),A=c("div"),D=c("strong"),D.textContent="GET",re=k(),E=c("div"),R=c("p"),de=$("/api/collections/"),X=c("strong"),Y=$(F),ue=$("/auth-methods"),Z=k(),S=c("div"),S.textContent="Query parameters",x=k(),P=c("table"),ee=c("thead"),ee.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',fe=k(),te=c("tbody"),ae(T.$$.fragment),le=k(),U=c("div"),U.textContent="Responses",se=k(),C=c("div"),Q=c("div");for(let e=0;e<y.length;e+=1)y[e].c();pe=k(),j=c("div");for(let e=0;e<_.length;e+=1)_[e].c();h(s,"class","m-b-sm"),h(f,"class","content txt-lg m-b-sm"),h(L,"class","m-b-xs"),h(D,"class","label label-primary"),h(E,"class","content"),h(A,"class","alert alert-info"),h(S,"class","section-title"),h(P,"class","table-compact table-border m-b-base"),h(U,"class","section-title"),h(Q,"class","tabs-header compact combined left"),h(j,"class","tabs-content"),h(C,"class","tabs")},m(e,t){d(e,s,t),a(s,l),a(s,p),a(s,b),d(e,i,t),d(e,f,t),a(f,m),a(m,v),a(m,w),a(w,V),a(m,ce),d(e,W,t),ne(M,e,t),d(e,z,t),d(e,L,t),d(e,K,t),d(e,A,t),a(A,D),a(A,re),a(A,E),a(E,R),a(R,de),a(R,X),a(X,Y),a(R,ue),d(e,Z,t),d(e,S,t),d(e,x,t),d(e,P,t),a(P,ee),a(P,fe),a(P,te),ne(T,te,null),d(e,le,t),d(e,U,t),d(e,se,t),d(e,C,t),a(C,Q);for(let r=0;r<y.length;r+=1)y[r]&&y[r].m(Q,null);a(C,pe),a(C,j);for(let r=0;r<_.length;r+=1)_[r]&&_[r].m(j,null);B=!0},p(e,[t]){var ve,we;(!B||t&1)&&o!==(o=e[0].name+"")&&I(p,o),(!B||t&1)&&g!==(g=e[0].name+"")&&I(V,g);const r={};t&9&&(r.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
...
const result = await pb.collection('${(ve=e[0])==null?void 0:ve.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();
`),M.$set(r),(!B||t&1)&&F!==(F=e[0].name+"")&&I(Y,F),t&6&&(H=G(e[2]),y=ye(y,t,he,1,e,H,me,Q,Re,Ae,null,Me)),t&6&&(q=G(e[2]),Se(),_=ye(_,t,_e,1,e,q,be,j,Ue,Pe,null,$e),Qe())},i(e){if(!B){J(M.$$.fragment,e),J(T.$$.fragment,e);for(let t=0;t<q.length;t+=1)J(_[t]);B=!0}},o(e){N(M.$$.fragment,e),N(T.$$.fragment,e);for(let t=0;t<_.length;t+=1)N(_[t]);B=!1},d(e){e&&(u(s),u(i),u(f),u(W),u(z),u(L),u(K),u(A),u(Z),u(S),u(x),u(P),u(le),u(U),u(se),u(C)),ie(M,e),ie(T);for(let t=0;t<y.length;t+=1)y[t].d();for(let t=0;t<_.length;t+=1)_[t].d()}}}function He(n,s,l){let o,{collection:p}=s,b=200,i=[],f={},m=!1;v();async function v(){l(5,m=!0);try{l(4,f=await oe.collection(p.name).listAuthMethods())}catch(g){oe.error(g)}l(5,m=!1)}const w=g=>l(1,b=g.code);return n.$$set=g=>{"collection"in g&&l(0,p=g.collection)},n.$$.update=()=>{n.$$.dirty&48&&l(2,i=[{code:200,body:m?"...":JSON.stringify(f,null,2)},{code:404,body:`
{
"code": 404,
"message": "Missing collection context.",
"data": {}
}
`}])},l(3,o=je.getApiExampleUrl(oe.baseURL)),[p,b,i,o,f,m,w]}class Je extends Ce{constructor(s){super(),Be(this,s,He,Fe,Te,{collection:0})}}export{Je as default};
-79
View File
@@ -1,79 +0,0 @@
import{S as Qe,i as je,s as Je,Q as Ke,R as Ne,T 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 W,x as de,U as Oe,V as We,k as Ie,W as Ge,n as Xe,t as E,a as U,o as u,d as I,C as Ve,p as Ye,r as G,u as Ze}from"./index-Co7n6kj7.js";import{F as et}from"./FieldsQueryParam-DH-ZC4qv.js";function Ee(r,a,l){const n=r.slice();return n[5]=a[l],n}function Ue(r,a,l){const n=r.slice();return n[5]=a[l],n}function xe(r,a){let l,n=a[5].code+"",m,_,i,h;function g(){return a[4](a[5])}return{key:r,first:null,c(){l=s("button"),m=k(n),_=p(),b(l,"class","tab-item"),G(l,"active",a[1]===a[5].code),this.first=l},m(v,w){d(v,l,w),o(l,m),o(l,_),i||(h=Ze(l,"click",g),i=!0)},p(v,w){a=v,w&4&&n!==(n=a[5].code+"")&&de(m,n),w&6&&G(l,"active",a[1]===a[5].code)},d(v){v&&u(l),i=!1,h()}}}function ze(r,a){let l,n,m,_;return n=new Ne({props:{content:a[5].body}}),{key:r,first:null,c(){l=s("div"),K(n.$$.fragment),m=p(),b(l,"class","tab-item"),G(l,"active",a[1]===a[5].code),this.first=l},m(i,h){d(i,l,h),W(n,l,null),o(l,m),_=!0},p(i,h){a=i;const g={};h&4&&(g.content=a[5].body),n.$set(g),(!_||h&6)&&G(l,"active",a[1]===a[5].code)},i(i){_||(E(n.$$.fragment,i),_=!0)},o(i){U(n.$$.fragment,i),_=!1},d(i){i&&u(l),I(n)}}}function tt(r){var De,Fe;let a,l,n=r[0].name+"",m,_,i,h,g,v,w,M,X,S,x,ue,z,q,pe,Y,N=r[0].name+"",Z,he,fe,Q,ee,D,te,T,oe,be,F,C,ae,me,le,_e,f,ke,P,ge,ve,$e,se,ye,ne,Se,we,Te,re,Ce,Re,A,ie,H,ce,R,L,y=[],Pe=new Map,Ae,O,$=[],Be=new Map,B;v=new Ke({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.record.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.record.id);
`}}),P=new Ne({props:{content:"?expand=relField1,relField2.subRelField"}}),A=new et({props:{prefix:"record."}});let j=J(r[2]);const Me=e=>e[5].code;for(let e=0;e<j.length;e+=1){let t=Ue(r,j,e),c=Me(t);Pe.set(c,y[e]=xe(c,t))}let V=J(r[2]);const qe=e=>e[5].code;for(let e=0;e<V.length;e+=1){let t=Ee(r,V,e),c=qe(t);Be.set(c,$[e]=ze(c,t))}return{c(){a=s("h3"),l=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>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.</p>`,g=p(),K(v.$$.fragment),w=p(),M=s("h6"),M.textContent="API details",X=p(),S=s("div"),x=s("strong"),x.textContent="POST",ue=p(),z=s("div"),q=s("p"),pe=k("/api/collections/"),Y=s("strong"),Z=k(N),he=k("/auth-refresh"),fe=p(),Q=s("p"),Q.innerHTML="Requires <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"),ae=s("td"),ae.textContent="expand",me=p(),le=s("td"),le.innerHTML='<span class="label">String</span>',_e=p(),f=s("td"),ke=k(`Auto expand record relations. Ex.:
`),K(P.$$.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."),Re=p(),K(A.$$.fragment),ie=p(),H=s("div"),H.textContent="Responses",ce=p(),R=s("div"),L=s("div");for(let e=0;e<y.length;e+=1)y[e].c();Ae=p(),O=s("div");for(let e=0;e<$.length;e+=1)$[e].c();b(a,"class","m-b-sm"),b(h,"class","content txt-lg m-b-sm"),b(M,"class","m-b-xs"),b(x,"class","label label-primary"),b(z,"class","content"),b(Q,"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(L,"class","tabs-header compact combined left"),b(O,"class","tabs-content"),b(R,"class","tabs")},m(e,t){d(e,a,t),o(a,l),o(a,m),o(a,_),d(e,i,t),d(e,h,t),d(e,g,t),W(v,e,t),d(e,w,t),d(e,M,t),d(e,X,t),d(e,S,t),o(S,x),o(S,ue),o(S,z),o(z,q),o(q,pe),o(q,Y),o(Y,Z),o(q,he),o(S,fe),o(S,Q),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,ae),o(C,me),o(C,le),o(C,_e),o(C,f),o(f,ke),W(P,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,Re),W(A,F,null),d(e,ie,t),d(e,H,t),d(e,ce,t),d(e,R,t),o(R,L);for(let c=0;c<y.length;c+=1)y[c]&&y[c].m(L,null);o(R,Ae),o(R,O);for(let c=0;c<$.length;c+=1)$[c]&&$[c].m(O,null);B=!0},p(e,[t]){var He,Le;(!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('${(He=e[0])==null?void 0:He.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.record.id);
`),t&9&&(c.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${e[3]}');
...
final authData = await pb.collection('${(Le=e[0])==null?void 0:Le.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.record.id);
`),v.$set(c),(!B||t&1)&&N!==(N=e[0].name+"")&&de(Z,N),t&6&&(j=J(e[2]),y=Oe(y,t,Me,1,e,j,Pe,L,We,xe,null,Ue)),t&6&&(V=J(e[2]),Ie(),$=Oe($,t,qe,1,e,V,Be,O,Ge,ze,null,Ee),Xe())},i(e){if(!B){E(v.$$.fragment,e),E(P.$$.fragment,e),E(A.$$.fragment,e);for(let t=0;t<V.length;t+=1)E($[t]);B=!0}},o(e){U(v.$$.fragment,e),U(P.$$.fragment,e),U(A.$$.fragment,e);for(let t=0;t<$.length;t+=1)U($[t]);B=!1},d(e){e&&(u(a),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(H),u(ce),u(R)),I(v,e),I(P),I(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,a,l){let n,{collection:m}=a,_=200,i=[];const h=g=>l(1,_=g.code);return r.$$set=g=>{"collection"in g&&l(0,m=g.collection)},r.$$.update=()=>{r.$$.dirty&1&&l(2,i=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:Ve.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": {}
}
`}])},l(3,n=Ve.getApiExampleUrl(Ye.baseURL)),[m,_,i,n,h]}class st extends Qe{constructor(a){super(),je(this,a,ot,tt,Je,{collection:0})}}export{st as default};
+79
View File
@@ -0,0 +1,79 @@
import{S as xe,i as Ie,s as Je,U as Ke,V as Ne,W as J,f as s,y as k,h as p,c as K,j as b,l as d,n as o,m as Q,G as de,X as Le,Y as Qe,D as We,Z as Ge,E as Xe,t as V,a as U,u,d as W,I as Oe,p as Ye,k as G,o as Ze}from"./index-DGnuRrBU.js";import{F as et}from"./FieldsQueryParam-DeLgGM_S.js";function Ve(r,a,l){const n=r.slice();return n[5]=a[l],n}function Ue(r,a,l){const n=r.slice();return n[5]=a[l],n}function je(r,a){let l,n=a[5].code+"",m,_,i,h;function g(){return a[4](a[5])}return{key:r,first:null,c(){l=s("button"),m=k(n),_=p(),b(l,"class","tab-item"),G(l,"active",a[1]===a[5].code),this.first=l},m(v,w){d(v,l,w),o(l,m),o(l,_),i||(h=Ze(l,"click",g),i=!0)},p(v,w){a=v,w&4&&n!==(n=a[5].code+"")&&de(m,n),w&6&&G(l,"active",a[1]===a[5].code)},d(v){v&&u(l),i=!1,h()}}}function ze(r,a){let l,n,m,_;return n=new Ne({props:{content:a[5].body}}),{key:r,first:null,c(){l=s("div"),K(n.$$.fragment),m=p(),b(l,"class","tab-item"),G(l,"active",a[1]===a[5].code),this.first=l},m(i,h){d(i,l,h),Q(n,l,null),o(l,m),_=!0},p(i,h){a=i;const g={};h&4&&(g.content=a[5].body),n.$set(g),(!_||h&6)&&G(l,"active",a[1]===a[5].code)},i(i){_||(V(n.$$.fragment,i),_=!0)},o(i){U(n.$$.fragment,i),_=!1},d(i){i&&u(l),W(n)}}}function tt(r){var qe,Fe;let a,l,n=r[0].name+"",m,_,i,h,g,v,w,D,X,S,j,ue,z,M,pe,Y,N=r[0].name+"",Z,he,fe,x,ee,q,te,T,oe,be,F,C,ae,me,le,_e,f,ke,P,ge,ve,ye,se,$e,ne,Se,we,Te,re,Ce,Re,A,ie,E,ce,R,H,$=[],Pe=new Map,Ae,L,y=[],Be=new Map,B;v=new Ke({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.record.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.record.id);
`}}),P=new Ne({props:{content:"?expand=relField1,relField2.subRelField"}}),A=new et({props:{prefix:"record."}});let I=J(r[2]);const De=e=>e[5].code;for(let e=0;e<I.length;e+=1){let t=Ue(r,I,e),c=De(t);Pe.set(c,$[e]=je(c,t))}let O=J(r[2]);const Me=e=>e[5].code;for(let e=0;e<O.length;e+=1){let t=Ve(r,O,e),c=Me(t);Be.set(c,y[e]=ze(c,t))}return{c(){a=s("h3"),l=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>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.</p>`,g=p(),K(v.$$.fragment),w=p(),D=s("h6"),D.textContent="API details",X=p(),S=s("div"),j=s("strong"),j.textContent="POST",ue=p(),z=s("div"),M=s("p"),pe=k("/api/collections/"),Y=s("strong"),Z=k(N),he=k("/auth-refresh"),fe=p(),x=s("p"),x.innerHTML="Requires <code>Authorization:TOKEN</code> header",ee=p(),q=s("div"),q.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"),ae=s("td"),ae.textContent="expand",me=p(),le=s("td"),le.innerHTML='<span class="label">String</span>',_e=p(),f=s("td"),ke=k(`Auto expand record relations. Ex.:
`),K(P.$$.fragment),ge=k(`
Supports up to 6-levels depth nested relations expansion. `),ve=s("br"),ye=k(`
The expanded relations will be appended to the record under the
`),se=s("code"),se.textContent="expand",$e=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."),Re=p(),K(A.$$.fragment),ie=p(),E=s("div"),E.textContent="Responses",ce=p(),R=s("div"),H=s("div");for(let e=0;e<$.length;e+=1)$[e].c();Ae=p(),L=s("div");for(let e=0;e<y.length;e+=1)y[e].c();b(a,"class","m-b-sm"),b(h,"class","content txt-lg m-b-sm"),b(D,"class","m-b-xs"),b(j,"class","label label-primary"),b(z,"class","content"),b(x,"class","txt-hint txt-sm txt-right"),b(S,"class","alert alert-success"),b(q,"class","section-title"),b(T,"class","table-compact table-border m-b-base"),b(E,"class","section-title"),b(H,"class","tabs-header compact combined left"),b(L,"class","tabs-content"),b(R,"class","tabs")},m(e,t){d(e,a,t),o(a,l),o(a,m),o(a,_),d(e,i,t),d(e,h,t),d(e,g,t),Q(v,e,t),d(e,w,t),d(e,D,t),d(e,X,t),d(e,S,t),o(S,j),o(S,ue),o(S,z),o(z,M),o(M,pe),o(M,Y),o(Y,Z),o(M,he),o(S,fe),o(S,x),d(e,ee,t),d(e,q,t),d(e,te,t),d(e,T,t),o(T,oe),o(T,be),o(T,F),o(F,C),o(C,ae),o(C,me),o(C,le),o(C,_e),o(C,f),o(f,ke),Q(P,f,null),o(f,ge),o(f,ve),o(f,ye),o(f,se),o(f,$e),o(f,ne),o(f,Se),o(f,we),o(f,Te),o(f,re),o(f,Ce),o(F,Re),Q(A,F,null),d(e,ie,t),d(e,E,t),d(e,ce,t),d(e,R,t),o(R,H);for(let c=0;c<$.length;c+=1)$[c]&&$[c].m(H,null);o(R,Ae),o(R,L);for(let c=0;c<y.length;c+=1)y[c]&&y[c].m(L,null);B=!0},p(e,[t]){var Ee,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('${(Ee=e[0])==null?void 0:Ee.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.record.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.record.id);
`),v.$set(c),(!B||t&1)&&N!==(N=e[0].name+"")&&de(Z,N),t&6&&(I=J(e[2]),$=Le($,t,De,1,e,I,Pe,H,Qe,je,null,Ue)),t&6&&(O=J(e[2]),We(),y=Le(y,t,Me,1,e,O,Be,L,Ge,ze,null,Ve),Xe())},i(e){if(!B){V(v.$$.fragment,e),V(P.$$.fragment,e),V(A.$$.fragment,e);for(let t=0;t<O.length;t+=1)V(y[t]);B=!0}},o(e){U(v.$$.fragment,e),U(P.$$.fragment,e),U(A.$$.fragment,e);for(let t=0;t<y.length;t+=1)U(y[t]);B=!1},d(e){e&&(u(a),u(i),u(h),u(g),u(w),u(D),u(X),u(S),u(ee),u(q),u(te),u(T),u(ie),u(E),u(ce),u(R)),W(v,e),W(P),W(A);for(let t=0;t<$.length;t+=1)$[t].d();for(let t=0;t<y.length;t+=1)y[t].d()}}}function ot(r,a,l){let n,{collection:m}=a,_=200,i=[];const h=g=>l(1,_=g.code);return r.$$set=g=>{"collection"in g&&l(0,m=g.collection)},r.$$.update=()=>{r.$$.dirty&1&&l(2,i=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:Oe.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": {}
}
`}])},l(3,n=Oe.getApiExampleUrl(Ye.baseURL)),[m,_,i,n,h]}class st extends xe{constructor(a){super(),Ie(this,a,ot,tt,Je,{collection:0})}}export{st as default};
@@ -1,4 +1,4 @@
import{S as xe,i as Ee,s as Je,Q as Qe,R as je,T as z,e as o,w as k,b as h,c as I,f as p,g as r,h as a,m as K,x as pe,U as Ue,V as Ne,k as ze,W as Ie,n as Ke,t as j,a as x,o as c,d as G,C as Be,p as Ge,r as X,u as Xe}from"./index-Co7n6kj7.js";import{F as Ye}from"./FieldsQueryParam-DH-ZC4qv.js";function Fe(s,l,n){const i=s.slice();return i[5]=l[n],i}function Le(s,l,n){const i=s.slice();return i[5]=l[n],i}function He(s,l){let n,i=l[5].code+"",f,g,d,b;function _(){return l[4](l[5])}return{key:s,first:null,c(){n=o("button"),f=k(i),g=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(v,O){r(v,n,O),a(n,f),a(n,g),d||(b=Xe(n,"click",_),d=!0)},p(v,O){l=v,O&4&&i!==(i=l[5].code+"")&&pe(f,i),O&6&&X(n,"active",l[1]===l[5].code)},d(v){v&&c(n),d=!1,b()}}}function Ve(s,l){let n,i,f,g;return i=new je({props:{content:l[5].body}}),{key:s,first:null,c(){n=o("div"),I(i.$$.fragment),f=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(d,b){r(d,n,b),K(i,n,null),a(n,f),g=!0},p(d,b){l=d;const _={};b&4&&(_.content=l[5].body),i.$set(_),(!g||b&6)&&X(n,"active",l[1]===l[5].code)},i(d){g||(j(i.$$.fragment,d),g=!0)},o(d){x(i.$$.fragment,d),g=!1},d(d){d&&c(n),G(i)}}}function Ze(s){let l,n,i=s[0].name+"",f,g,d,b,_,v,O,D,Y,A,E,be,J,P,me,Z,Q=s[0].name+"",ee,fe,te,M,ae,W,le,U,ne,y,oe,ge,B,S,se,ke,ie,_e,m,ve,C,we,$e,Oe,re,Ae,ce,ye,Se,Te,de,Ce,qe,q,ue,F,he,T,L,$=[],Re=new Map,De,H,w=[],Pe=new Map,R;v=new Qe({props:{js:`
import{S as Ee,i as Je,s as xe,U as Ie,V as Ve,W as Q,f as o,y as k,h,c as z,j as p,l as r,n as a,m as G,G as pe,X as Ue,Y as Ne,D as Qe,Z as ze,E as Ge,t as V,a as E,u as c,d as K,I as Be,p as Ke,k as X,o as Xe}from"./index-DGnuRrBU.js";import{F as Ye}from"./FieldsQueryParam-DeLgGM_S.js";function Fe(s,l,n){const i=s.slice();return i[5]=l[n],i}function Le(s,l,n){const i=s.slice();return i[5]=l[n],i}function je(s,l){let n,i=l[5].code+"",f,g,d,b;function _(){return l[4](l[5])}return{key:s,first:null,c(){n=o("button"),f=k(i),g=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(v,O){r(v,n,O),a(n,f),a(n,g),d||(b=Xe(n,"click",_),d=!0)},p(v,O){l=v,O&4&&i!==(i=l[5].code+"")&&pe(f,i),O&6&&X(n,"active",l[1]===l[5].code)},d(v){v&&c(n),d=!1,b()}}}function He(s,l){let n,i,f,g;return i=new Ve({props:{content:l[5].body}}),{key:s,first:null,c(){n=o("div"),z(i.$$.fragment),f=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(d,b){r(d,n,b),G(i,n,null),a(n,f),g=!0},p(d,b){l=d;const _={};b&4&&(_.content=l[5].body),i.$set(_),(!g||b&6)&&X(n,"active",l[1]===l[5].code)},i(d){g||(V(i.$$.fragment,d),g=!0)},o(d){E(i.$$.fragment,d),g=!1},d(d){d&&c(n),K(i)}}}function Ze(s){let l,n,i=s[0].name+"",f,g,d,b,_,v,O,R,Y,y,J,be,x,P,me,Z,I=s[0].name+"",ee,fe,te,M,ae,W,le,U,ne,A,oe,ge,B,S,se,ke,ie,_e,m,ve,C,we,$e,Oe,re,ye,ce,Ae,Se,Te,de,Ce,qe,q,ue,F,he,T,L,$=[],De=new Map,Re,j,w=[],Pe=new Map,D;v=new Ie({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${s[3]}');
@@ -45,18 +45,18 @@ import{S as xe,i as Ee,s as Je,Q as Qe,R as je,T as z,e as o,w as k,b as h,c as
// "logout"
pb.authStore.clear();
`}}),C=new je({props:{content:"?expand=relField1,relField2.subRelField"}}),q=new Ye({props:{prefix:"record."}});let N=z(s[2]);const Me=e=>e[5].code;for(let e=0;e<N.length;e+=1){let t=Le(s,N,e),u=Me(t);Re.set(u,$[e]=He(u,t))}let V=z(s[2]);const We=e=>e[5].code;for(let e=0;e<V.length;e+=1){let t=Fe(s,V,e),u=We(t);Pe.set(u,w[e]=Ve(u,t))}return{c(){l=o("h3"),n=k("Auth with OAuth2 ("),f=k(i),g=k(")"),d=h(),b=o("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
`}}),C=new Ve({props:{content:"?expand=relField1,relField2.subRelField"}}),q=new Ye({props:{prefix:"record."}});let N=Q(s[2]);const Me=e=>e[5].code;for(let e=0;e<N.length;e+=1){let t=Le(s,N,e),u=Me(t);De.set(u,$[e]=je(u,t))}let H=Q(s[2]);const We=e=>e[5].code;for(let e=0;e<H.length;e+=1){let t=Fe(s,H,e),u=We(t);Pe.set(u,w[e]=He(u,t))}return{c(){l=o("h3"),n=k("Auth with OAuth2 ("),f=k(i),g=k(")"),d=h(),b=o("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/#authenticate-with-oauth2" target="_blank" rel="noopener noreferrer">OAuth2 integration documentation
</a>.</p>`,_=h(),I(v.$$.fragment),O=h(),D=o("h6"),D.textContent="API details",Y=h(),A=o("div"),E=o("strong"),E.textContent="POST",be=h(),J=o("div"),P=o("p"),me=k("/api/collections/"),Z=o("strong"),ee=k(Q),fe=k("/auth-with-oauth2"),te=h(),M=o("div"),M.textContent="Body Parameters",ae=h(),W=o("table"),W.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
</a>.</p>`,_=h(),z(v.$$.fragment),O=h(),R=o("h6"),R.textContent="API details",Y=h(),y=o("div"),J=o("strong"),J.textContent="POST",be=h(),x=o("div"),P=o("p"),me=k("/api/collections/"),Z=o("strong"),ee=k(I),fe=k("/auth-with-oauth2"),te=h(),M=o("div"),M.textContent="Body Parameters",ae=h(),W=o("table"),W.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(),U=o("div"),U.textContent="Query parameters",ne=h(),y=o("table"),oe=o("thead"),oe.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',ge=h(),B=o("tbody"),S=o("tr"),se=o("td"),se.textContent="expand",ke=h(),ie=o("td"),ie.innerHTML='<span class="label">String</span>',_e=h(),m=o("td"),ve=k(`Auto expand record relations. Ex.:
`),I(C.$$.fragment),we=k(`
upload currently are not supported during OAuth2 sign-ups.</em></p></td></tr></tbody>`,le=h(),U=o("div"),U.textContent="Query parameters",ne=h(),A=o("table"),oe=o("thead"),oe.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',ge=h(),B=o("tbody"),S=o("tr"),se=o("td"),se.textContent="expand",ke=h(),ie=o("td"),ie.innerHTML='<span class="label">String</span>',_e=h(),m=o("td"),ve=k(`Auto expand record relations. Ex.:
`),z(C.$$.fragment),we=k(`
Supports up to 6-levels depth nested relations expansion. `),$e=o("br"),Oe=k(`
The expanded relations will be appended to the record under the
`),re=o("code"),re.textContent="expand",Ae=k(" property (eg. "),ce=o("code"),ce.textContent='"expand": {"relField1": {...}, ...}',ye=k(`).
`),re=o("code"),re.textContent="expand",ye=k(" property (eg. "),ce=o("code"),ce.textContent='"expand": {"relField1": {...}, ...}',Ae=k(`).
`),Se=o("br"),Te=k(`
Only the relations to which the request user has permissions to `),de=o("strong"),de.textContent="view",Ce=k(" will be expanded."),qe=h(),I(q.$$.fragment),ue=h(),F=o("div"),F.textContent="Responses",he=h(),T=o("div"),L=o("div");for(let e=0;e<$.length;e+=1)$[e].c();De=h(),H=o("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(D,"class","m-b-xs"),p(E,"class","label label-primary"),p(J,"class","content"),p(A,"class","alert alert-success"),p(M,"class","section-title"),p(W,"class","table-compact table-border m-b-base"),p(U,"class","section-title"),p(y,"class","table-compact table-border m-b-base"),p(F,"class","section-title"),p(L,"class","tabs-header compact combined left"),p(H,"class","tabs-content"),p(T,"class","tabs")},m(e,t){r(e,l,t),a(l,n),a(l,f),a(l,g),r(e,d,t),r(e,b,t),r(e,_,t),K(v,e,t),r(e,O,t),r(e,D,t),r(e,Y,t),r(e,A,t),a(A,E),a(A,be),a(A,J),a(J,P),a(P,me),a(P,Z),a(Z,ee),a(P,fe),r(e,te,t),r(e,M,t),r(e,ae,t),r(e,W,t),r(e,le,t),r(e,U,t),r(e,ne,t),r(e,y,t),a(y,oe),a(y,ge),a(y,B),a(B,S),a(S,se),a(S,ke),a(S,ie),a(S,_e),a(S,m),a(m,ve),K(C,m,null),a(m,we),a(m,$e),a(m,Oe),a(m,re),a(m,Ae),a(m,ce),a(m,ye),a(m,Se),a(m,Te),a(m,de),a(m,Ce),a(B,qe),K(q,B,null),r(e,ue,t),r(e,F,t),r(e,he,t),r(e,T,t),a(T,L);for(let u=0;u<$.length;u+=1)$[u]&&$[u].m(L,null);a(T,De),a(T,H);for(let u=0;u<w.length;u+=1)w[u]&&w[u].m(H,null);R=!0},p(e,[t]){(!R||t&1)&&i!==(i=e[0].name+"")&&pe(f,i);const u={};t&9&&(u.js=`
Only the relations to which the request user has permissions to `),de=o("strong"),de.textContent="view",Ce=k(" will be expanded."),qe=h(),z(q.$$.fragment),ue=h(),F=o("div"),F.textContent="Responses",he=h(),T=o("div"),L=o("div");for(let e=0;e<$.length;e+=1)$[e].c();Re=h(),j=o("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(R,"class","m-b-xs"),p(J,"class","label label-primary"),p(x,"class","content"),p(y,"class","alert alert-success"),p(M,"class","section-title"),p(W,"class","table-compact table-border m-b-base"),p(U,"class","section-title"),p(A,"class","table-compact table-border m-b-base"),p(F,"class","section-title"),p(L,"class","tabs-header compact combined left"),p(j,"class","tabs-content"),p(T,"class","tabs")},m(e,t){r(e,l,t),a(l,n),a(l,f),a(l,g),r(e,d,t),r(e,b,t),r(e,_,t),G(v,e,t),r(e,O,t),r(e,R,t),r(e,Y,t),r(e,y,t),a(y,J),a(y,be),a(y,x),a(x,P),a(P,me),a(P,Z),a(Z,ee),a(P,fe),r(e,te,t),r(e,M,t),r(e,ae,t),r(e,W,t),r(e,le,t),r(e,U,t),r(e,ne,t),r(e,A,t),a(A,oe),a(A,ge),a(A,B),a(B,S),a(S,se),a(S,ke),a(S,ie),a(S,_e),a(S,m),a(m,ve),G(C,m,null),a(m,we),a(m,$e),a(m,Oe),a(m,re),a(m,ye),a(m,ce),a(m,Ae),a(m,Se),a(m,Te),a(m,de),a(m,Ce),a(B,qe),G(q,B,null),r(e,ue,t),r(e,F,t),r(e,he,t),r(e,T,t),a(T,L);for(let u=0;u<$.length;u+=1)$[u]&&$[u].m(L,null);a(T,Re),a(T,j);for(let u=0;u<w.length;u+=1)w[u]&&w[u].m(j,null);D=!0},p(e,[t]){(!D||t&1)&&i!==(i=e[0].name+"")&&pe(f,i);const u={};t&9&&(u.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[3]}');
@@ -103,7 +103,7 @@ import{S as xe,i as Ee,s as Je,Q as Qe,R as je,T as z,e as o,w as k,b as h,c as
// "logout"
pb.authStore.clear();
`),v.$set(u),(!R||t&1)&&Q!==(Q=e[0].name+"")&&pe(ee,Q),t&6&&(N=z(e[2]),$=Ue($,t,Me,1,e,N,Re,L,Ne,He,null,Le)),t&6&&(V=z(e[2]),ze(),w=Ue(w,t,We,1,e,V,Pe,H,Ie,Ve,null,Fe),Ke())},i(e){if(!R){j(v.$$.fragment,e),j(C.$$.fragment,e),j(q.$$.fragment,e);for(let t=0;t<V.length;t+=1)j(w[t]);R=!0}},o(e){x(v.$$.fragment,e),x(C.$$.fragment,e),x(q.$$.fragment,e);for(let t=0;t<w.length;t+=1)x(w[t]);R=!1},d(e){e&&(c(l),c(d),c(b),c(_),c(O),c(D),c(Y),c(A),c(te),c(M),c(ae),c(W),c(le),c(U),c(ne),c(y),c(ue),c(F),c(he),c(T)),G(v,e),G(C),G(q);for(let t=0;t<$.length;t+=1)$[t].d();for(let t=0;t<w.length;t+=1)w[t].d()}}}function et(s,l,n){let i,{collection:f}=l,g=200,d=[];const b=_=>n(1,g=_.code);return s.$$set=_=>{"collection"in _&&n(0,f=_.collection)},s.$$.update=()=>{s.$$.dirty&1&&n(2,d=[{code:200,body:JSON.stringify({token:"JWT_AUTH_TOKEN",record:Be.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:`
`),v.$set(u),(!D||t&1)&&I!==(I=e[0].name+"")&&pe(ee,I),t&6&&(N=Q(e[2]),$=Ue($,t,Me,1,e,N,De,L,Ne,je,null,Le)),t&6&&(H=Q(e[2]),Qe(),w=Ue(w,t,We,1,e,H,Pe,j,ze,He,null,Fe),Ge())},i(e){if(!D){V(v.$$.fragment,e),V(C.$$.fragment,e),V(q.$$.fragment,e);for(let t=0;t<H.length;t+=1)V(w[t]);D=!0}},o(e){E(v.$$.fragment,e),E(C.$$.fragment,e),E(q.$$.fragment,e);for(let t=0;t<w.length;t+=1)E(w[t]);D=!1},d(e){e&&(c(l),c(d),c(b),c(_),c(O),c(R),c(Y),c(y),c(te),c(M),c(ae),c(W),c(le),c(U),c(ne),c(A),c(ue),c(F),c(he),c(T)),K(v,e),K(C),K(q);for(let t=0;t<$.length;t+=1)$[t].d();for(let t=0;t<w.length;t+=1)w[t].d()}}}function et(s,l,n){let i,{collection:f}=l,g=200,d=[];const b=_=>n(1,g=_.code);return s.$$set=_=>{"collection"in _&&n(0,f=_.collection)},s.$$.update=()=>{s.$$.dirty&1&&n(2,d=[{code:200,body:JSON.stringify({token:"JWT_AUTH_TOKEN",record:Be.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.",
@@ -114,4 +114,4 @@ import{S as xe,i as Ee,s as Je,Q as Qe,R as je,T as z,e as o,w as k,b as h,c as
}
}
}
`}])},n(3,i=Be.getApiExampleUrl(Ge.baseURL)),[f,g,d,i,b]}class lt extends xe{constructor(l){super(),Ee(this,l,et,Ze,Je,{collection:0})}}export{lt as default};
`}])},n(3,i=Be.getApiExampleUrl(Ke.baseURL)),[f,g,d,i,b]}class lt extends Ee{constructor(l){super(),Je(this,l,et,Ze,xe,{collection:0})}}export{lt as default};
@@ -1,4 +1,4 @@
import{S as ee,i as te,s as le,T as U,e as p,b as S,w as V,f as g,g as b,h,x as z,U as G,V as ge,k as Z,W as ke,n as x,t as L,a as N,o as _,C as oe,r as Y,u as ae,R as we,c as K,m as Q,d as X,Q as $e,X as se,p as Te,Y as ne}from"./index-Co7n6kj7.js";function ie(s,t,e){const a=s.slice();return a[4]=t[e],a}function ce(s,t,e){const a=s.slice();return a[4]=t[e],a}function re(s,t){let e,a=t[4].code+"",d,c,r,n;function u(){return t[3](t[4])}return{key:s,first:null,c(){e=p("button"),d=V(a),c=S(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(m,q){b(m,e,q),h(e,d),h(e,c),r||(n=ae(e,"click",u),r=!0)},p(m,q){t=m,q&4&&a!==(a=t[4].code+"")&&z(d,a),q&6&&Y(e,"active",t[1]===t[4].code)},d(m){m&&_(e),r=!1,n()}}}function de(s,t){let e,a,d,c;return a=new we({props:{content:t[4].body}}),{key:s,first:null,c(){e=p("div"),K(a.$$.fragment),d=S(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(r,n){b(r,e,n),Q(a,e,null),h(e,d),c=!0},p(r,n){t=r;const u={};n&4&&(u.content=t[4].body),a.$set(u),(!c||n&6)&&Y(e,"active",t[1]===t[4].code)},i(r){c||(L(a.$$.fragment,r),c=!0)},o(r){N(a.$$.fragment,r),c=!1},d(r){r&&_(e),X(a)}}}function Pe(s){let t,e,a,d,c,r,n,u=s[0].name+"",m,q,M,C,B,A,H,R,W,y,P,w=[],$=new Map,E,D,k=[],J=new Map,I,i=U(s[2]);const v=l=>l[4].code;for(let l=0;l<i.length;l+=1){let o=ce(s,i,l),f=v(o);$.set(f,w[l]=re(f,o))}let O=U(s[2]);const j=l=>l[4].code;for(let l=0;l<O.length;l+=1){let o=ie(s,O,l),f=j(o);J.set(f,k[l]=de(f,o))}return{c(){t=p("div"),e=p("strong"),e.textContent="POST",a=S(),d=p("div"),c=p("p"),r=V("/api/collections/"),n=p("strong"),m=V(u),q=V("/auth-with-otp"),M=S(),C=p("div"),C.textContent="Body Parameters",B=S(),A=p("table"),A.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>otpId</span></div></td> <td><span class="label">String</span></td> <td>The id of the OTP request.</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 one-time password.</td></tr></tbody>',H=S(),R=p("div"),R.textContent="Responses",W=S(),y=p("div"),P=p("div");for(let l=0;l<w.length;l+=1)w[l].c();E=S(),D=p("div");for(let l=0;l<k.length;l+=1)k[l].c();g(e,"class","label label-primary"),g(d,"class","content"),g(t,"class","alert alert-success"),g(C,"class","section-title"),g(A,"class","table-compact table-border m-b-base"),g(R,"class","section-title"),g(P,"class","tabs-header compact combined left"),g(D,"class","tabs-content"),g(y,"class","tabs")},m(l,o){b(l,t,o),h(t,e),h(t,a),h(t,d),h(d,c),h(c,r),h(c,n),h(n,m),h(c,q),b(l,M,o),b(l,C,o),b(l,B,o),b(l,A,o),b(l,H,o),b(l,R,o),b(l,W,o),b(l,y,o),h(y,P);for(let f=0;f<w.length;f+=1)w[f]&&w[f].m(P,null);h(y,E),h(y,D);for(let f=0;f<k.length;f+=1)k[f]&&k[f].m(D,null);I=!0},p(l,[o]){(!I||o&1)&&u!==(u=l[0].name+"")&&z(m,u),o&6&&(i=U(l[2]),w=G(w,o,v,1,l,i,$,P,ge,re,null,ce)),o&6&&(O=U(l[2]),Z(),k=G(k,o,j,1,l,O,J,D,ke,de,null,ie),x())},i(l){if(!I){for(let o=0;o<O.length;o+=1)L(k[o]);I=!0}},o(l){for(let o=0;o<k.length;o+=1)N(k[o]);I=!1},d(l){l&&(_(t),_(M),_(C),_(B),_(A),_(H),_(R),_(W),_(y));for(let o=0;o<w.length;o+=1)w[o].d();for(let o=0;o<k.length;o+=1)k[o].d()}}}function Oe(s,t,e){let{collection:a}=t,d=200,c=[];const r=n=>e(1,d=n.code);return s.$$set=n=>{"collection"in n&&e(0,a=n.collection)},s.$$.update=()=>{s.$$.dirty&1&&e(2,c=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:oe.dummyCollectionRecord(a)},null,2)},{code:400,body:`
import{S as ee,i as te,s as le,W as U,f as p,h as y,y as V,j as g,l as b,n as h,G as Z,X as z,Y as ge,D as Q,Z as ke,E as x,t as L,a as N,u as _,I as oe,k as Y,o as ae,V as we,c as G,m as K,d as X,U as $e,_ as se,p as Te,$ as ne}from"./index-DGnuRrBU.js";function ie(s,t,e){const a=s.slice();return a[4]=t[e],a}function ce(s,t,e){const a=s.slice();return a[4]=t[e],a}function re(s,t){let e,a=t[4].code+"",d,c,r,n;function u(){return t[3](t[4])}return{key:s,first:null,c(){e=p("button"),d=V(a),c=y(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(m,q){b(m,e,q),h(e,d),h(e,c),r||(n=ae(e,"click",u),r=!0)},p(m,q){t=m,q&4&&a!==(a=t[4].code+"")&&Z(d,a),q&6&&Y(e,"active",t[1]===t[4].code)},d(m){m&&_(e),r=!1,n()}}}function de(s,t){let e,a,d,c;return a=new we({props:{content:t[4].body}}),{key:s,first:null,c(){e=p("div"),G(a.$$.fragment),d=y(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(r,n){b(r,e,n),K(a,e,null),h(e,d),c=!0},p(r,n){t=r;const u={};n&4&&(u.content=t[4].body),a.$set(u),(!c||n&6)&&Y(e,"active",t[1]===t[4].code)},i(r){c||(L(a.$$.fragment,r),c=!0)},o(r){N(a.$$.fragment,r),c=!1},d(r){r&&_(e),X(a)}}}function Pe(s){let t,e,a,d,c,r,n,u=s[0].name+"",m,q,M,C,B,A,H,R,W,S,P,w=[],$=new Map,J,D,k=[],j=new Map,I,i=U(s[2]);const v=l=>l[4].code;for(let l=0;l<i.length;l+=1){let o=ce(s,i,l),f=v(o);$.set(f,w[l]=re(f,o))}let O=U(s[2]);const E=l=>l[4].code;for(let l=0;l<O.length;l+=1){let o=ie(s,O,l),f=E(o);j.set(f,k[l]=de(f,o))}return{c(){t=p("div"),e=p("strong"),e.textContent="POST",a=y(),d=p("div"),c=p("p"),r=V("/api/collections/"),n=p("strong"),m=V(u),q=V("/auth-with-otp"),M=y(),C=p("div"),C.textContent="Body Parameters",B=y(),A=p("table"),A.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>otpId</span></div></td> <td><span class="label">String</span></td> <td>The id of the OTP request.</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 one-time password.</td></tr></tbody>',H=y(),R=p("div"),R.textContent="Responses",W=y(),S=p("div"),P=p("div");for(let l=0;l<w.length;l+=1)w[l].c();J=y(),D=p("div");for(let l=0;l<k.length;l+=1)k[l].c();g(e,"class","label label-primary"),g(d,"class","content"),g(t,"class","alert alert-success"),g(C,"class","section-title"),g(A,"class","table-compact table-border m-b-base"),g(R,"class","section-title"),g(P,"class","tabs-header compact combined left"),g(D,"class","tabs-content"),g(S,"class","tabs")},m(l,o){b(l,t,o),h(t,e),h(t,a),h(t,d),h(d,c),h(c,r),h(c,n),h(n,m),h(c,q),b(l,M,o),b(l,C,o),b(l,B,o),b(l,A,o),b(l,H,o),b(l,R,o),b(l,W,o),b(l,S,o),h(S,P);for(let f=0;f<w.length;f+=1)w[f]&&w[f].m(P,null);h(S,J),h(S,D);for(let f=0;f<k.length;f+=1)k[f]&&k[f].m(D,null);I=!0},p(l,[o]){(!I||o&1)&&u!==(u=l[0].name+"")&&Z(m,u),o&6&&(i=U(l[2]),w=z(w,o,v,1,l,i,$,P,ge,re,null,ce)),o&6&&(O=U(l[2]),Q(),k=z(k,o,E,1,l,O,j,D,ke,de,null,ie),x())},i(l){if(!I){for(let o=0;o<O.length;o+=1)L(k[o]);I=!0}},o(l){for(let o=0;o<k.length;o+=1)N(k[o]);I=!1},d(l){l&&(_(t),_(M),_(C),_(B),_(A),_(H),_(R),_(W),_(S));for(let o=0;o<w.length;o+=1)w[o].d();for(let o=0;o<k.length;o+=1)k[o].d()}}}function Oe(s,t,e){let{collection:a}=t,d=200,c=[];const r=n=>e(1,d=n.code);return s.$$set=n=>{"collection"in n&&e(0,a=n.collection)},s.$$.update=()=>{s.$$.dirty&1&&e(2,c=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:oe.dummyCollectionRecord(a)},null,2)},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
@@ -9,7 +9,7 @@ import{S as ee,i as te,s as le,T as U,e as p,b as S,w as V,f as g,g as b,h,x as
}
}
}
`}])},[a,d,c,r]}class Se extends ee{constructor(t){super(),te(this,t,Oe,Pe,le,{collection:0})}}function ue(s,t,e){const a=s.slice();return a[4]=t[e],a}function he(s,t,e){const a=s.slice();return a[4]=t[e],a}function pe(s,t){let e,a=t[4].code+"",d,c,r,n;function u(){return t[3](t[4])}return{key:s,first:null,c(){e=p("button"),d=V(a),c=S(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(m,q){b(m,e,q),h(e,d),h(e,c),r||(n=ae(e,"click",u),r=!0)},p(m,q){t=m,q&4&&a!==(a=t[4].code+"")&&z(d,a),q&6&&Y(e,"active",t[1]===t[4].code)},d(m){m&&_(e),r=!1,n()}}}function fe(s,t){let e,a,d,c;return a=new we({props:{content:t[4].body}}),{key:s,first:null,c(){e=p("div"),K(a.$$.fragment),d=S(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(r,n){b(r,e,n),Q(a,e,null),h(e,d),c=!0},p(r,n){t=r;const u={};n&4&&(u.content=t[4].body),a.$set(u),(!c||n&6)&&Y(e,"active",t[1]===t[4].code)},i(r){c||(L(a.$$.fragment,r),c=!0)},o(r){N(a.$$.fragment,r),c=!1},d(r){r&&_(e),X(a)}}}function ye(s){let t,e,a,d,c,r,n,u=s[0].name+"",m,q,M,C,B,A,H,R,W,y,P,w=[],$=new Map,E,D,k=[],J=new Map,I,i=U(s[2]);const v=l=>l[4].code;for(let l=0;l<i.length;l+=1){let o=he(s,i,l),f=v(o);$.set(f,w[l]=pe(f,o))}let O=U(s[2]);const j=l=>l[4].code;for(let l=0;l<O.length;l+=1){let o=ue(s,O,l),f=j(o);J.set(f,k[l]=fe(f,o))}return{c(){t=p("div"),e=p("strong"),e.textContent="POST",a=S(),d=p("div"),c=p("p"),r=V("/api/collections/"),n=p("strong"),m=V(u),q=V("/request-otp"),M=S(),C=p("div"),C.textContent="Body Parameters",B=S(),A=p("table"),A.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>email</span></div></td> <td><span class="label">String</span></td> <td>The auth record email address to send the OTP request (if exists).</td></tr></tbody>',H=S(),R=p("div"),R.textContent="Responses",W=S(),y=p("div"),P=p("div");for(let l=0;l<w.length;l+=1)w[l].c();E=S(),D=p("div");for(let l=0;l<k.length;l+=1)k[l].c();g(e,"class","label label-primary"),g(d,"class","content"),g(t,"class","alert alert-success"),g(C,"class","section-title"),g(A,"class","table-compact table-border m-b-base"),g(R,"class","section-title"),g(P,"class","tabs-header compact combined left"),g(D,"class","tabs-content"),g(y,"class","tabs")},m(l,o){b(l,t,o),h(t,e),h(t,a),h(t,d),h(d,c),h(c,r),h(c,n),h(n,m),h(c,q),b(l,M,o),b(l,C,o),b(l,B,o),b(l,A,o),b(l,H,o),b(l,R,o),b(l,W,o),b(l,y,o),h(y,P);for(let f=0;f<w.length;f+=1)w[f]&&w[f].m(P,null);h(y,E),h(y,D);for(let f=0;f<k.length;f+=1)k[f]&&k[f].m(D,null);I=!0},p(l,[o]){(!I||o&1)&&u!==(u=l[0].name+"")&&z(m,u),o&6&&(i=U(l[2]),w=G(w,o,v,1,l,i,$,P,ge,pe,null,he)),o&6&&(O=U(l[2]),Z(),k=G(k,o,j,1,l,O,J,D,ke,fe,null,ue),x())},i(l){if(!I){for(let o=0;o<O.length;o+=1)L(k[o]);I=!0}},o(l){for(let o=0;o<k.length;o+=1)N(k[o]);I=!1},d(l){l&&(_(t),_(M),_(C),_(B),_(A),_(H),_(R),_(W),_(y));for(let o=0;o<w.length;o+=1)w[o].d();for(let o=0;o<k.length;o+=1)k[o].d()}}}function qe(s,t,e){let{collection:a}=t,d=200,c=[];const r=n=>e(1,d=n.code);return s.$$set=n=>{"collection"in n&&e(0,a=n.collection)},e(2,c=[{code:200,body:JSON.stringify({otpId:oe.randomString(15)},null,2)},{code:400,body:`
`}])},[a,d,c,r]}class ye extends ee{constructor(t){super(),te(this,t,Oe,Pe,le,{collection:0})}}function ue(s,t,e){const a=s.slice();return a[4]=t[e],a}function he(s,t,e){const a=s.slice();return a[4]=t[e],a}function pe(s,t){let e,a=t[4].code+"",d,c,r,n;function u(){return t[3](t[4])}return{key:s,first:null,c(){e=p("button"),d=V(a),c=y(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(m,q){b(m,e,q),h(e,d),h(e,c),r||(n=ae(e,"click",u),r=!0)},p(m,q){t=m,q&4&&a!==(a=t[4].code+"")&&Z(d,a),q&6&&Y(e,"active",t[1]===t[4].code)},d(m){m&&_(e),r=!1,n()}}}function fe(s,t){let e,a,d,c;return a=new we({props:{content:t[4].body}}),{key:s,first:null,c(){e=p("div"),G(a.$$.fragment),d=y(),g(e,"class","tab-item"),Y(e,"active",t[1]===t[4].code),this.first=e},m(r,n){b(r,e,n),K(a,e,null),h(e,d),c=!0},p(r,n){t=r;const u={};n&4&&(u.content=t[4].body),a.$set(u),(!c||n&6)&&Y(e,"active",t[1]===t[4].code)},i(r){c||(L(a.$$.fragment,r),c=!0)},o(r){N(a.$$.fragment,r),c=!1},d(r){r&&_(e),X(a)}}}function Se(s){let t,e,a,d,c,r,n,u=s[0].name+"",m,q,M,C,B,A,H,R,W,S,P,w=[],$=new Map,J,D,k=[],j=new Map,I,i=U(s[2]);const v=l=>l[4].code;for(let l=0;l<i.length;l+=1){let o=he(s,i,l),f=v(o);$.set(f,w[l]=pe(f,o))}let O=U(s[2]);const E=l=>l[4].code;for(let l=0;l<O.length;l+=1){let o=ue(s,O,l),f=E(o);j.set(f,k[l]=fe(f,o))}return{c(){t=p("div"),e=p("strong"),e.textContent="POST",a=y(),d=p("div"),c=p("p"),r=V("/api/collections/"),n=p("strong"),m=V(u),q=V("/request-otp"),M=y(),C=p("div"),C.textContent="Body Parameters",B=y(),A=p("table"),A.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>email</span></div></td> <td><span class="label">String</span></td> <td>The auth record email address to send the OTP request (if exists).</td></tr></tbody>',H=y(),R=p("div"),R.textContent="Responses",W=y(),S=p("div"),P=p("div");for(let l=0;l<w.length;l+=1)w[l].c();J=y(),D=p("div");for(let l=0;l<k.length;l+=1)k[l].c();g(e,"class","label label-primary"),g(d,"class","content"),g(t,"class","alert alert-success"),g(C,"class","section-title"),g(A,"class","table-compact table-border m-b-base"),g(R,"class","section-title"),g(P,"class","tabs-header compact combined left"),g(D,"class","tabs-content"),g(S,"class","tabs")},m(l,o){b(l,t,o),h(t,e),h(t,a),h(t,d),h(d,c),h(c,r),h(c,n),h(n,m),h(c,q),b(l,M,o),b(l,C,o),b(l,B,o),b(l,A,o),b(l,H,o),b(l,R,o),b(l,W,o),b(l,S,o),h(S,P);for(let f=0;f<w.length;f+=1)w[f]&&w[f].m(P,null);h(S,J),h(S,D);for(let f=0;f<k.length;f+=1)k[f]&&k[f].m(D,null);I=!0},p(l,[o]){(!I||o&1)&&u!==(u=l[0].name+"")&&Z(m,u),o&6&&(i=U(l[2]),w=z(w,o,v,1,l,i,$,P,ge,pe,null,he)),o&6&&(O=U(l[2]),Q(),k=z(k,o,E,1,l,O,j,D,ke,fe,null,ue),x())},i(l){if(!I){for(let o=0;o<O.length;o+=1)L(k[o]);I=!0}},o(l){for(let o=0;o<k.length;o+=1)N(k[o]);I=!1},d(l){l&&(_(t),_(M),_(C),_(B),_(A),_(H),_(R),_(W),_(S));for(let o=0;o<w.length;o+=1)w[o].d();for(let o=0;o<k.length;o+=1)k[o].d()}}}function qe(s,t,e){let{collection:a}=t,d=200,c=[];const r=n=>e(1,d=n.code);return s.$$set=n=>{"collection"in n&&e(0,a=n.collection)},e(2,c=[{code:200,body:JSON.stringify({otpId:oe.randomString(15)},null,2)},{code:400,body:`
{
"code": 400,
"message": "An error occurred while validating the submitted data.",
@@ -26,7 +26,7 @@ import{S as ee,i as te,s as le,T as U,e as p,b as S,w as V,f as g,g as b,h,x as
"message": "You've send too many OTP requests, please try again later.",
"data": {}
}
`}]),[a,d,c,r]}class Ae extends ee{constructor(t){super(),te(this,t,qe,ye,le,{collection:0})}}function me(s,t,e){const a=s.slice();return a[5]=t[e],a[7]=e,a}function be(s,t,e){const a=s.slice();return a[5]=t[e],a[7]=e,a}function _e(s){let t,e,a,d,c;function r(){return s[4](s[7])}return{c(){t=p("button"),e=p("div"),e.textContent=`${s[5].title}`,a=S(),g(e,"class","txt"),g(t,"class","tab-item"),Y(t,"active",s[1]==s[7])},m(n,u){b(n,t,u),h(t,e),h(t,a),d||(c=ae(t,"click",r),d=!0)},p(n,u){s=n,u&2&&Y(t,"active",s[1]==s[7])},d(n){n&&_(t),d=!1,c()}}}function ve(s){let t,e,a,d;var c=s[5].component;function r(n,u){return{props:{collection:n[0]}}}return c&&(e=ne(c,r(s))),{c(){t=p("div"),e&&K(e.$$.fragment),a=S(),g(t,"class","tab-item"),Y(t,"active",s[1]==s[7])},m(n,u){b(n,t,u),e&&Q(e,t,null),h(t,a),d=!0},p(n,u){if(c!==(c=n[5].component)){if(e){Z();const m=e;N(m.$$.fragment,1,0,()=>{X(m,1)}),x()}c?(e=ne(c,r(n)),K(e.$$.fragment),L(e.$$.fragment,1),Q(e,t,a)):e=null}else if(c){const m={};u&1&&(m.collection=n[0]),e.$set(m)}(!d||u&2)&&Y(t,"active",n[1]==n[7])},i(n){d||(e&&L(e.$$.fragment,n),d=!0)},o(n){e&&N(e.$$.fragment,n),d=!1},d(n){n&&_(t),e&&X(e)}}}function Re(s){var D,k,J,I;let t,e,a=s[0].name+"",d,c,r,n,u,m,q,M,C,B,A,H,R,W;m=new $e({props:{js:`
`}]),[a,d,c,r]}class Ae extends ee{constructor(t){super(),te(this,t,qe,Se,le,{collection:0})}}function me(s,t,e){const a=s.slice();return a[5]=t[e],a[7]=e,a}function be(s,t,e){const a=s.slice();return a[5]=t[e],a[7]=e,a}function _e(s){let t,e,a,d,c;function r(){return s[4](s[7])}return{c(){t=p("button"),e=p("div"),e.textContent=`${s[5].title}`,a=y(),g(e,"class","txt"),g(t,"class","tab-item"),Y(t,"active",s[1]==s[7])},m(n,u){b(n,t,u),h(t,e),h(t,a),d||(c=ae(t,"click",r),d=!0)},p(n,u){s=n,u&2&&Y(t,"active",s[1]==s[7])},d(n){n&&_(t),d=!1,c()}}}function ve(s){let t,e,a,d;var c=s[5].component;function r(n,u){return{props:{collection:n[0]}}}return c&&(e=ne(c,r(s))),{c(){t=p("div"),e&&G(e.$$.fragment),a=y(),g(t,"class","tab-item"),Y(t,"active",s[1]==s[7])},m(n,u){b(n,t,u),e&&K(e,t,null),h(t,a),d=!0},p(n,u){if(c!==(c=n[5].component)){if(e){Q();const m=e;N(m.$$.fragment,1,0,()=>{X(m,1)}),x()}c?(e=ne(c,r(n)),G(e.$$.fragment),L(e.$$.fragment,1),K(e,t,a)):e=null}else if(c){const m={};u&1&&(m.collection=n[0]),e.$set(m)}(!d||u&2)&&Y(t,"active",n[1]==n[7])},i(n){d||(e&&L(e.$$.fragment,n),d=!0)},o(n){e&&N(e.$$.fragment,n),d=!1},d(n){n&&_(t),e&&X(e)}}}function Re(s){var D,k,j,I;let t,e,a=s[0].name+"",d,c,r,n,u,m,q,M,C,B,A,H,R,W;m=new $e({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${s[2]}');
@@ -59,7 +59,7 @@ import{S as ee,i as te,s as le,T as U,e as p,b as S,w as V,f as g,g as b,h,x as
...
// send OTP email to the provided auth record
final req = await pb.collection('${(J=s[0])==null?void 0:J.name}').requestOTP('test@example.com');
final req = await pb.collection('${(j=s[0])==null?void 0:j.name}').requestOTP('test@example.com');
// ... show a screen/popup to enter the password from the email ...
@@ -76,8 +76,8 @@ import{S as ee,i as te,s as le,T as U,e as p,b as S,w as V,f as g,g as b,h,x as
// "logout"
pb.authStore.clear();
`}});let y=U(s[3]),P=[];for(let i=0;i<y.length;i+=1)P[i]=_e(be(s,y,i));let w=U(s[3]),$=[];for(let i=0;i<w.length;i+=1)$[i]=ve(me(s,w,i));const E=i=>N($[i],1,1,()=>{$[i]=null});return{c(){t=p("h3"),e=V("Auth with OTP ("),d=V(a),c=V(")"),r=S(),n=p("div"),n.innerHTML=`<p>Authenticate with an one-time password (OTP).</p> <p>Note that when requesting an OTP we return an <code>otpId</code> even if a user with the provided email
doesn&#39;t exist as a very basic enumeration protection.</p>`,u=S(),K(m.$$.fragment),q=S(),M=p("h6"),M.textContent="API details",C=S(),B=p("div"),A=p("div");for(let i=0;i<P.length;i+=1)P[i].c();H=S(),R=p("div");for(let i=0;i<$.length;i+=1)$[i].c();g(t,"class","m-b-sm"),g(n,"class","content txt-lg m-b-sm"),g(M,"class","m-b-xs"),g(A,"class","tabs-header compact"),g(R,"class","tabs-content"),g(B,"class","tabs")},m(i,v){b(i,t,v),h(t,e),h(t,d),h(t,c),b(i,r,v),b(i,n,v),b(i,u,v),Q(m,i,v),b(i,q,v),b(i,M,v),b(i,C,v),b(i,B,v),h(B,A);for(let O=0;O<P.length;O+=1)P[O]&&P[O].m(A,null);h(B,H),h(B,R);for(let O=0;O<$.length;O+=1)$[O]&&$[O].m(R,null);W=!0},p(i,[v]){var j,l,o,f;(!W||v&1)&&a!==(a=i[0].name+"")&&z(d,a);const O={};if(v&5&&(O.js=`
`}});let S=U(s[3]),P=[];for(let i=0;i<S.length;i+=1)P[i]=_e(be(s,S,i));let w=U(s[3]),$=[];for(let i=0;i<w.length;i+=1)$[i]=ve(me(s,w,i));const J=i=>N($[i],1,1,()=>{$[i]=null});return{c(){t=p("h3"),e=V("Auth with OTP ("),d=V(a),c=V(")"),r=y(),n=p("div"),n.innerHTML=`<p>Authenticate with an one-time password (OTP).</p> <p>Note that when requesting an OTP we return an <code>otpId</code> even if a user with the provided email
doesn&#39;t exist as a very basic enumeration protection.</p>`,u=y(),G(m.$$.fragment),q=y(),M=p("h6"),M.textContent="API details",C=y(),B=p("div"),A=p("div");for(let i=0;i<P.length;i+=1)P[i].c();H=y(),R=p("div");for(let i=0;i<$.length;i+=1)$[i].c();g(t,"class","m-b-sm"),g(n,"class","content txt-lg m-b-sm"),g(M,"class","m-b-xs"),g(A,"class","tabs-header compact"),g(R,"class","tabs-content"),g(B,"class","tabs")},m(i,v){b(i,t,v),h(t,e),h(t,d),h(t,c),b(i,r,v),b(i,n,v),b(i,u,v),K(m,i,v),b(i,q,v),b(i,M,v),b(i,C,v),b(i,B,v),h(B,A);for(let O=0;O<P.length;O+=1)P[O]&&P[O].m(A,null);h(B,H),h(B,R);for(let O=0;O<$.length;O+=1)$[O]&&$[O].m(R,null);W=!0},p(i,[v]){var E,l,o,f;(!W||v&1)&&a!==(a=i[0].name+"")&&Z(d,a);const O={};if(v&5&&(O.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${i[2]}');
@@ -85,7 +85,7 @@ import{S as ee,i as te,s as le,T as U,e as p,b as S,w as V,f as g,g as b,h,x as
...
// send OTP email to the provided auth record
const req = await pb.collection('${(j=i[0])==null?void 0:j.name}').requestOTP('test@example.com');
const req = await pb.collection('${(E=i[0])==null?void 0:E.name}').requestOTP('test@example.com');
// ... show a screen/popup to enter the password from the email ...
@@ -127,4 +127,4 @@ import{S as ee,i as te,s as le,T as U,e as p,b as S,w as V,f as g,g as b,h,x as
// "logout"
pb.authStore.clear();
`),m.$set(O),v&10){y=U(i[3]);let T;for(T=0;T<y.length;T+=1){const F=be(i,y,T);P[T]?P[T].p(F,v):(P[T]=_e(F),P[T].c(),P[T].m(A,null))}for(;T<P.length;T+=1)P[T].d(1);P.length=y.length}if(v&11){w=U(i[3]);let T;for(T=0;T<w.length;T+=1){const F=me(i,w,T);$[T]?($[T].p(F,v),L($[T],1)):($[T]=ve(F),$[T].c(),L($[T],1),$[T].m(R,null))}for(Z(),T=w.length;T<$.length;T+=1)E(T);x()}},i(i){if(!W){L(m.$$.fragment,i);for(let v=0;v<w.length;v+=1)L($[v]);W=!0}},o(i){N(m.$$.fragment,i),$=$.filter(Boolean);for(let v=0;v<$.length;v+=1)N($[v]);W=!1},d(i){i&&(_(t),_(r),_(n),_(u),_(q),_(M),_(C),_(B)),X(m,i),se(P,i),se($,i)}}}function Ce(s,t,e){let a,{collection:d}=t;const c=[{title:"OTP Request",component:Ae},{title:"OTP Auth",component:Se}];let r=0;const n=u=>e(1,r=u);return s.$$set=u=>{"collection"in u&&e(0,d=u.collection)},e(2,a=oe.getApiExampleUrl(Te.baseURL)),[d,r,a,c,n]}class De extends ee{constructor(t){super(),te(this,t,Ce,Re,le,{collection:0})}}export{De as default};
`),m.$set(O),v&10){S=U(i[3]);let T;for(T=0;T<S.length;T+=1){const F=be(i,S,T);P[T]?P[T].p(F,v):(P[T]=_e(F),P[T].c(),P[T].m(A,null))}for(;T<P.length;T+=1)P[T].d(1);P.length=S.length}if(v&11){w=U(i[3]);let T;for(T=0;T<w.length;T+=1){const F=me(i,w,T);$[T]?($[T].p(F,v),L($[T],1)):($[T]=ve(F),$[T].c(),L($[T],1),$[T].m(R,null))}for(Q(),T=w.length;T<$.length;T+=1)J(T);x()}},i(i){if(!W){L(m.$$.fragment,i);for(let v=0;v<w.length;v+=1)L($[v]);W=!0}},o(i){N(m.$$.fragment,i),$=$.filter(Boolean);for(let v=0;v<$.length;v+=1)N($[v]);W=!1},d(i){i&&(_(t),_(r),_(n),_(u),_(q),_(M),_(C),_(B)),X(m,i),se(P,i),se($,i)}}}function Ce(s,t,e){let a,{collection:d}=t;const c=[{title:"OTP Request",component:Ae},{title:"OTP Auth",component:ye}];let r=0;const n=u=>e(1,r=u);return s.$$set=u=>{"collection"in u&&e(0,d=u.collection)},e(2,a=oe.getApiExampleUrl(Te.baseURL)),[d,r,a,c,n]}class De extends ee{constructor(t){super(),te(this,t,Ce,Re,le,{collection:0})}}export{De as default};
@@ -1,4 +1,4 @@
import{S as kt,i as gt,s as vt,Q as St,T as L,R as _t,e as s,w as f,b as u,c as ae,f as k,g as c,h as t,m as oe,x as G,U as ct,V as wt,k as yt,W as $t,n as Pt,t as X,a as z,o as d,d as se,X as Rt,C as dt,p as Ct,r as ne,u as Tt}from"./index-Co7n6kj7.js";import{F as Ot}from"./FieldsQueryParam-DH-ZC4qv.js";function pt(i,o,a){const n=i.slice();return n[7]=o[a],n}function ut(i,o,a){const n=i.slice();return n[7]=o[a],n}function ht(i,o,a){const n=i.slice();return n[12]=o[a],n[14]=a,n}function At(i){let o;return{c(){o=f("or")},m(a,n){c(a,o,n)},d(a){a&&d(o)}}}function bt(i){let o,a,n=i[12]+"",m,b=i[14]>0&&At();return{c(){b&&b.c(),o=u(),a=s("strong"),m=f(n)},m(r,h){b&&b.m(r,h),c(r,o,h),c(r,a,h),t(a,m)},p(r,h){h&2&&n!==(n=r[12]+"")&&G(m,n)},d(r){r&&(d(o),d(a)),b&&b.d(r)}}}function ft(i,o){let a,n=o[7].code+"",m,b,r,h;function g(){return o[6](o[7])}return{key:i,first:null,c(){a=s("button"),m=f(n),b=u(),k(a,"class","tab-item"),ne(a,"active",o[2]===o[7].code),this.first=a},m($,_){c($,a,_),t(a,m),t(a,b),r||(h=Tt(a,"click",g),r=!0)},p($,_){o=$,_&8&&n!==(n=o[7].code+"")&&G(m,n),_&12&&ne(a,"active",o[2]===o[7].code)},d($){$&&d(a),r=!1,h()}}}function mt(i,o){let a,n,m,b;return n=new _t({props:{content:o[7].body}}),{key:i,first:null,c(){a=s("div"),ae(n.$$.fragment),m=u(),k(a,"class","tab-item"),ne(a,"active",o[2]===o[7].code),this.first=a},m(r,h){c(r,a,h),oe(n,a,null),t(a,m),b=!0},p(r,h){o=r;const g={};h&8&&(g.content=o[7].body),n.$set(g),(!b||h&12)&&ne(a,"active",o[2]===o[7].code)},i(r){b||(X(n.$$.fragment,r),b=!0)},o(r){z(n.$$.fragment,r),b=!1},d(r){r&&d(a),se(n)}}}function Dt(i){var ot,st;let o,a,n=i[0].name+"",m,b,r,h,g,$,_,Z=i[1].join("/")+"",ie,De,re,We,ce,R,de,q,pe,C,x,Ue,ee,H,Fe,ue,te=i[0].name+"",he,Me,be,j,fe,T,me,Be,V,O,_e,Le,ke,qe,Y,ge,He,ve,Se,E,we,A,ye,je,N,D,$e,Ve,Pe,Ye,v,Ee,F,Ne,Qe,Ie,Re,Je,Ce,Ke,Xe,ze,Te,Ge,Ze,M,Oe,Q,Ae,W,I,P=[],xe=new Map,et,J,w=[],tt=new Map,U;R=new St({props:{js:`
import{S as kt,i as gt,s as vt,U as St,W as L,V as _t,f as s,y as f,h as u,c as ae,j as k,l as c,n as t,m as oe,G as Z,X as ct,Y as wt,D as yt,Z as $t,E as Pt,t as K,a as X,u as d,d as se,_ as Rt,I as dt,p as Ct,k as ne,o as Ot}from"./index-DGnuRrBU.js";import{F as Tt}from"./FieldsQueryParam-DeLgGM_S.js";function pt(i,o,a){const n=i.slice();return n[7]=o[a],n}function ut(i,o,a){const n=i.slice();return n[7]=o[a],n}function ht(i,o,a){const n=i.slice();return n[12]=o[a],n[14]=a,n}function At(i){let o;return{c(){o=f("or")},m(a,n){c(a,o,n)},d(a){a&&d(o)}}}function bt(i){let o,a,n=i[12]+"",m,b=i[14]>0&&At();return{c(){b&&b.c(),o=u(),a=s("strong"),m=f(n)},m(r,h){b&&b.m(r,h),c(r,o,h),c(r,a,h),t(a,m)},p(r,h){h&2&&n!==(n=r[12]+"")&&Z(m,n)},d(r){r&&(d(o),d(a)),b&&b.d(r)}}}function ft(i,o){let a,n=o[7].code+"",m,b,r,h;function g(){return o[6](o[7])}return{key:i,first:null,c(){a=s("button"),m=f(n),b=u(),k(a,"class","tab-item"),ne(a,"active",o[2]===o[7].code),this.first=a},m($,_){c($,a,_),t(a,m),t(a,b),r||(h=Ot(a,"click",g),r=!0)},p($,_){o=$,_&8&&n!==(n=o[7].code+"")&&Z(m,n),_&12&&ne(a,"active",o[2]===o[7].code)},d($){$&&d(a),r=!1,h()}}}function mt(i,o){let a,n,m,b;return n=new _t({props:{content:o[7].body}}),{key:i,first:null,c(){a=s("div"),ae(n.$$.fragment),m=u(),k(a,"class","tab-item"),ne(a,"active",o[2]===o[7].code),this.first=a},m(r,h){c(r,a,h),oe(n,a,null),t(a,m),b=!0},p(r,h){o=r;const g={};h&8&&(g.content=o[7].body),n.$set(g),(!b||h&12)&&ne(a,"active",o[2]===o[7].code)},i(r){b||(K(n.$$.fragment,r),b=!0)},o(r){X(n.$$.fragment,r),b=!1},d(r){r&&d(a),se(n)}}}function Dt(i){var ot,st;let o,a,n=i[0].name+"",m,b,r,h,g,$,_,z=i[1].join("/")+"",ie,De,re,We,ce,R,de,q,pe,C,x,Ue,ee,H,Fe,ue,te=i[0].name+"",he,Me,be,j,fe,O,me,Be,Y,T,_e,Le,ke,qe,E,ge,He,ve,Se,V,we,A,ye,je,N,D,$e,Ye,Pe,Ee,v,Ve,F,Ne,Ie,Je,Re,Qe,Ce,Ge,Ke,Xe,Oe,Ze,ze,M,Te,I,Ae,W,J,P=[],xe=new Map,et,Q,w=[],tt=new Map,U;R=new St({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${i[5]}');
@@ -36,15 +36,15 @@ import{S as kt,i as gt,s as vt,Q as St,T as L,R as _t,e as s,w as f,b as u,c as
// "logout"
pb.authStore.clear();
`}});let B=L(i[1]),S=[];for(let e=0;e<B.length;e+=1)S[e]=bt(ht(i,B,e));F=new _t({props:{content:"?expand=relField1,relField2.subRelField"}}),M=new Ot({props:{prefix:"record."}});let le=L(i[3]);const lt=e=>e[7].code;for(let e=0;e<le.length;e+=1){let l=ut(i,le,e),p=lt(l);xe.set(p,P[e]=ft(p,l))}let K=L(i[3]);const at=e=>e[7].code;for(let e=0;e<K.length;e+=1){let l=pt(i,K,e),p=at(l);tt.set(p,w[e]=mt(p,l))}return{c(){o=s("h3"),a=f("Auth with password ("),m=f(n),b=f(")"),r=u(),h=s("div"),g=s("p"),$=f(`Authenticate with combination of
`),_=s("strong"),ie=f(Z),De=f(" and "),re=s("strong"),re.textContent="password",We=f("."),ce=u(),ae(R.$$.fragment),de=u(),q=s("h6"),q.textContent="API details",pe=u(),C=s("div"),x=s("strong"),x.textContent="POST",Ue=u(),ee=s("div"),H=s("p"),Fe=f("/api/collections/"),ue=s("strong"),he=f(te),Me=f("/auth-with-password"),be=u(),j=s("div"),j.textContent="Body Parameters",fe=u(),T=s("table"),me=s("thead"),me.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',Be=u(),V=s("tbody"),O=s("tr"),_e=s("td"),_e.innerHTML='<div class="inline-flex"><span class="label label-success">Required</span> <span>identity</span></div>',Le=u(),ke=s("td"),ke.innerHTML='<span class="label">String</span>',qe=u(),Y=s("td");for(let e=0;e<S.length;e+=1)S[e].c();ge=f(`
of the record to authenticate.`),He=u(),ve=s("tr"),ve.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>',Se=u(),E=s("div"),E.textContent="Query parameters",we=u(),A=s("table"),ye=s("thead"),ye.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',je=u(),N=s("tbody"),D=s("tr"),$e=s("td"),$e.textContent="expand",Ve=u(),Pe=s("td"),Pe.innerHTML='<span class="label">String</span>',Ye=u(),v=s("td"),Ee=f(`Auto expand record relations. Ex.:
`}});let B=L(i[1]),S=[];for(let e=0;e<B.length;e+=1)S[e]=bt(ht(i,B,e));F=new _t({props:{content:"?expand=relField1,relField2.subRelField"}}),M=new Tt({props:{prefix:"record."}});let le=L(i[3]);const lt=e=>e[7].code;for(let e=0;e<le.length;e+=1){let l=ut(i,le,e),p=lt(l);xe.set(p,P[e]=ft(p,l))}let G=L(i[3]);const at=e=>e[7].code;for(let e=0;e<G.length;e+=1){let l=pt(i,G,e),p=at(l);tt.set(p,w[e]=mt(p,l))}return{c(){o=s("h3"),a=f("Auth with password ("),m=f(n),b=f(")"),r=u(),h=s("div"),g=s("p"),$=f(`Authenticate with combination of
`),_=s("strong"),ie=f(z),De=f(" and "),re=s("strong"),re.textContent="password",We=f("."),ce=u(),ae(R.$$.fragment),de=u(),q=s("h6"),q.textContent="API details",pe=u(),C=s("div"),x=s("strong"),x.textContent="POST",Ue=u(),ee=s("div"),H=s("p"),Fe=f("/api/collections/"),ue=s("strong"),he=f(te),Me=f("/auth-with-password"),be=u(),j=s("div"),j.textContent="Body Parameters",fe=u(),O=s("table"),me=s("thead"),me.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',Be=u(),Y=s("tbody"),T=s("tr"),_e=s("td"),_e.innerHTML='<div class="inline-flex"><span class="label label-success">Required</span> <span>identity</span></div>',Le=u(),ke=s("td"),ke.innerHTML='<span class="label">String</span>',qe=u(),E=s("td");for(let e=0;e<S.length;e+=1)S[e].c();ge=f(`
of the record to authenticate.`),He=u(),ve=s("tr"),ve.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>',Se=u(),V=s("div"),V.textContent="Query parameters",we=u(),A=s("table"),ye=s("thead"),ye.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',je=u(),N=s("tbody"),D=s("tr"),$e=s("td"),$e.textContent="expand",Ye=u(),Pe=s("td"),Pe.innerHTML='<span class="label">String</span>',Ee=u(),v=s("td"),Ve=f(`Auto expand record relations. Ex.:
`),ae(F.$$.fragment),Ne=f(`
Supports up to 6-levels depth nested relations expansion. `),Qe=s("br"),Ie=f(`
Supports up to 6-levels depth nested relations expansion. `),Ie=s("br"),Je=f(`
The expanded relations will be appended to the record under the
`),Re=s("code"),Re.textContent="expand",Je=f(" property (eg. "),Ce=s("code"),Ce.textContent='"expand": {"relField1": {...}, ...}',Ke=f(`).
`),Xe=s("br"),ze=f(`
Only the relations to which the request user has permissions to `),Te=s("strong"),Te.textContent="view",Ge=f(" will be expanded."),Ze=u(),ae(M.$$.fragment),Oe=u(),Q=s("div"),Q.textContent="Responses",Ae=u(),W=s("div"),I=s("div");for(let e=0;e<P.length;e+=1)P[e].c();et=u(),J=s("div");for(let e=0;e<w.length;e+=1)w[e].c();k(o,"class","m-b-sm"),k(h,"class","content txt-lg m-b-sm"),k(q,"class","m-b-xs"),k(x,"class","label label-primary"),k(ee,"class","content"),k(C,"class","alert alert-success"),k(j,"class","section-title"),k(T,"class","table-compact table-border m-b-base"),k(E,"class","section-title"),k(A,"class","table-compact table-border m-b-base"),k(Q,"class","section-title"),k(I,"class","tabs-header compact combined left"),k(J,"class","tabs-content"),k(W,"class","tabs")},m(e,l){c(e,o,l),t(o,a),t(o,m),t(o,b),c(e,r,l),c(e,h,l),t(h,g),t(g,$),t(g,_),t(_,ie),t(g,De),t(g,re),t(g,We),c(e,ce,l),oe(R,e,l),c(e,de,l),c(e,q,l),c(e,pe,l),c(e,C,l),t(C,x),t(C,Ue),t(C,ee),t(ee,H),t(H,Fe),t(H,ue),t(ue,he),t(H,Me),c(e,be,l),c(e,j,l),c(e,fe,l),c(e,T,l),t(T,me),t(T,Be),t(T,V),t(V,O),t(O,_e),t(O,Le),t(O,ke),t(O,qe),t(O,Y);for(let p=0;p<S.length;p+=1)S[p]&&S[p].m(Y,null);t(Y,ge),t(V,He),t(V,ve),c(e,Se,l),c(e,E,l),c(e,we,l),c(e,A,l),t(A,ye),t(A,je),t(A,N),t(N,D),t(D,$e),t(D,Ve),t(D,Pe),t(D,Ye),t(D,v),t(v,Ee),oe(F,v,null),t(v,Ne),t(v,Qe),t(v,Ie),t(v,Re),t(v,Je),t(v,Ce),t(v,Ke),t(v,Xe),t(v,ze),t(v,Te),t(v,Ge),t(N,Ze),oe(M,N,null),c(e,Oe,l),c(e,Q,l),c(e,Ae,l),c(e,W,l),t(W,I);for(let p=0;p<P.length;p+=1)P[p]&&P[p].m(I,null);t(W,et),t(W,J);for(let p=0;p<w.length;p+=1)w[p]&&w[p].m(J,null);U=!0},p(e,[l]){var nt,it;(!U||l&1)&&n!==(n=e[0].name+"")&&G(m,n),(!U||l&2)&&Z!==(Z=e[1].join("/")+"")&&G(ie,Z);const p={};if(l&49&&(p.js=`
`),Re=s("code"),Re.textContent="expand",Qe=f(" property (eg. "),Ce=s("code"),Ce.textContent='"expand": {"relField1": {...}, ...}',Ge=f(`).
`),Ke=s("br"),Xe=f(`
Only the relations to which the request user has permissions to `),Oe=s("strong"),Oe.textContent="view",Ze=f(" will be expanded."),ze=u(),ae(M.$$.fragment),Te=u(),I=s("div"),I.textContent="Responses",Ae=u(),W=s("div"),J=s("div");for(let e=0;e<P.length;e+=1)P[e].c();et=u(),Q=s("div");for(let e=0;e<w.length;e+=1)w[e].c();k(o,"class","m-b-sm"),k(h,"class","content txt-lg m-b-sm"),k(q,"class","m-b-xs"),k(x,"class","label label-primary"),k(ee,"class","content"),k(C,"class","alert alert-success"),k(j,"class","section-title"),k(O,"class","table-compact table-border m-b-base"),k(V,"class","section-title"),k(A,"class","table-compact table-border m-b-base"),k(I,"class","section-title"),k(J,"class","tabs-header compact combined left"),k(Q,"class","tabs-content"),k(W,"class","tabs")},m(e,l){c(e,o,l),t(o,a),t(o,m),t(o,b),c(e,r,l),c(e,h,l),t(h,g),t(g,$),t(g,_),t(_,ie),t(g,De),t(g,re),t(g,We),c(e,ce,l),oe(R,e,l),c(e,de,l),c(e,q,l),c(e,pe,l),c(e,C,l),t(C,x),t(C,Ue),t(C,ee),t(ee,H),t(H,Fe),t(H,ue),t(ue,he),t(H,Me),c(e,be,l),c(e,j,l),c(e,fe,l),c(e,O,l),t(O,me),t(O,Be),t(O,Y),t(Y,T),t(T,_e),t(T,Le),t(T,ke),t(T,qe),t(T,E);for(let p=0;p<S.length;p+=1)S[p]&&S[p].m(E,null);t(E,ge),t(Y,He),t(Y,ve),c(e,Se,l),c(e,V,l),c(e,we,l),c(e,A,l),t(A,ye),t(A,je),t(A,N),t(N,D),t(D,$e),t(D,Ye),t(D,Pe),t(D,Ee),t(D,v),t(v,Ve),oe(F,v,null),t(v,Ne),t(v,Ie),t(v,Je),t(v,Re),t(v,Qe),t(v,Ce),t(v,Ge),t(v,Ke),t(v,Xe),t(v,Oe),t(v,Ze),t(N,ze),oe(M,N,null),c(e,Te,l),c(e,I,l),c(e,Ae,l),c(e,W,l),t(W,J);for(let p=0;p<P.length;p+=1)P[p]&&P[p].m(J,null);t(W,et),t(W,Q);for(let p=0;p<w.length;p+=1)w[p]&&w[p].m(Q,null);U=!0},p(e,[l]){var nt,it;(!U||l&1)&&n!==(n=e[0].name+"")&&Z(m,n),(!U||l&2)&&z!==(z=e[1].join("/")+"")&&Z(ie,z);const p={};if(l&49&&(p.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[5]}');
@@ -82,7 +82,7 @@ import{S as kt,i as gt,s as vt,Q as St,T as L,R as _t,e as s,w as f,b as u,c as
// "logout"
pb.authStore.clear();
`),R.$set(p),(!U||l&1)&&te!==(te=e[0].name+"")&&G(he,te),l&2){B=L(e[1]);let y;for(y=0;y<B.length;y+=1){const rt=ht(e,B,y);S[y]?S[y].p(rt,l):(S[y]=bt(rt),S[y].c(),S[y].m(Y,ge))}for(;y<S.length;y+=1)S[y].d(1);S.length=B.length}l&12&&(le=L(e[3]),P=ct(P,l,lt,1,e,le,xe,I,wt,ft,null,ut)),l&12&&(K=L(e[3]),yt(),w=ct(w,l,at,1,e,K,tt,J,$t,mt,null,pt),Pt())},i(e){if(!U){X(R.$$.fragment,e),X(F.$$.fragment,e),X(M.$$.fragment,e);for(let l=0;l<K.length;l+=1)X(w[l]);U=!0}},o(e){z(R.$$.fragment,e),z(F.$$.fragment,e),z(M.$$.fragment,e);for(let l=0;l<w.length;l+=1)z(w[l]);U=!1},d(e){e&&(d(o),d(r),d(h),d(ce),d(de),d(q),d(pe),d(C),d(be),d(j),d(fe),d(T),d(Se),d(E),d(we),d(A),d(Oe),d(Q),d(Ae),d(W)),se(R,e),Rt(S,e),se(F),se(M);for(let l=0;l<P.length;l+=1)P[l].d();for(let l=0;l<w.length;l+=1)w[l].d()}}}function Wt(i,o,a){let n,m,b,{collection:r}=o,h=200,g=[];const $=_=>a(2,h=_.code);return i.$$set=_=>{"collection"in _&&a(0,r=_.collection)},i.$$.update=()=>{var _;i.$$.dirty&1&&a(1,m=((_=r==null?void 0:r.passwordAuth)==null?void 0:_.identityFields)||[]),i.$$.dirty&2&&a(4,b=m.length==0?"NONE":"YOUR_"+m.join("_OR_").toUpperCase()),i.$$.dirty&1&&a(3,g=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:dt.dummyCollectionRecord(r)},null,2)},{code:400,body:`
`),R.$set(p),(!U||l&1)&&te!==(te=e[0].name+"")&&Z(he,te),l&2){B=L(e[1]);let y;for(y=0;y<B.length;y+=1){const rt=ht(e,B,y);S[y]?S[y].p(rt,l):(S[y]=bt(rt),S[y].c(),S[y].m(E,ge))}for(;y<S.length;y+=1)S[y].d(1);S.length=B.length}l&12&&(le=L(e[3]),P=ct(P,l,lt,1,e,le,xe,J,wt,ft,null,ut)),l&12&&(G=L(e[3]),yt(),w=ct(w,l,at,1,e,G,tt,Q,$t,mt,null,pt),Pt())},i(e){if(!U){K(R.$$.fragment,e),K(F.$$.fragment,e),K(M.$$.fragment,e);for(let l=0;l<G.length;l+=1)K(w[l]);U=!0}},o(e){X(R.$$.fragment,e),X(F.$$.fragment,e),X(M.$$.fragment,e);for(let l=0;l<w.length;l+=1)X(w[l]);U=!1},d(e){e&&(d(o),d(r),d(h),d(ce),d(de),d(q),d(pe),d(C),d(be),d(j),d(fe),d(O),d(Se),d(V),d(we),d(A),d(Te),d(I),d(Ae),d(W)),se(R,e),Rt(S,e),se(F),se(M);for(let l=0;l<P.length;l+=1)P[l].d();for(let l=0;l<w.length;l+=1)w[l].d()}}}function Wt(i,o,a){let n,m,b,{collection:r}=o,h=200,g=[];const $=_=>a(2,h=_.code);return i.$$set=_=>{"collection"in _&&a(0,r=_.collection)},i.$$.update=()=>{var _;i.$$.dirty&1&&a(1,m=((_=r==null?void 0:r.passwordAuth)==null?void 0:_.identityFields)||[]),i.$$.dirty&2&&a(4,b=m.length==0?"NONE":"YOUR_"+m.join("_OR_").toUpperCase()),i.$$.dirty&1&&a(3,g=[{code:200,body:JSON.stringify({token:"JWT_TOKEN",record:dt.dummyCollectionRecord(r)},null,2)},{code:400,body:`
{
"code": 400,
"message": "Failed to authenticate.",
@@ -1,4 +1,4 @@
import{S as It,i as Lt,s as jt,Q as At,R as Ht,T as Y,e as o,w as _,b as i,c as Re,f as b,g as d,h as t,m as Te,j as Mt,l as Nt,x as Ut,U as Pt,V as zt,k as Jt,W as Wt,n as Kt,t as Z,a as x,o as u,d as Pe,C as Ft,p as Gt,r as ee,u as Qt}from"./index-Co7n6kj7.js";function Bt(a,s,n){const c=a.slice();return c[6]=s[n],c}function Ot(a,s,n){const c=a.slice();return c[6]=s[n],c}function Et(a,s){let n,c,y;function h(){return s[5](s[6])}return{key:a,first:null,c(){n=o("button"),n.textContent=`${s[6].code} `,b(n,"class","tab-item"),ee(n,"active",s[1]===s[6].code),this.first=n},m(r,f){d(r,n,f),c||(y=Qt(n,"click",h),c=!0)},p(r,f){s=r,f&10&&ee(n,"active",s[1]===s[6].code)},d(r){r&&u(n),c=!1,y()}}}function St(a,s){let n,c,y,h;return c=new Ht({props:{content:s[6].body}}),{key:a,first:null,c(){n=o("div"),Re(c.$$.fragment),y=i(),b(n,"class","tab-item"),ee(n,"active",s[1]===s[6].code),this.first=n},m(r,f){d(r,n,f),Te(c,n,null),t(n,y),h=!0},p(r,f){s=r,(!h||f&10)&&ee(n,"active",s[1]===s[6].code)},i(r){h||(Z(c.$$.fragment,r),h=!0)},o(r){x(c.$$.fragment,r),h=!1},d(r){r&&u(n),Pe(c)}}}function Vt(a){var pt,mt,bt,ft,ht,_t,yt,kt;let s,n,c=a[0].name+"",y,h,r,f,F,g,U,Fe,P,B,Be,O,Oe,Ee,te,le,w,oe,E,ae,S,se,H,ne,z,ie,q,ce,Se,re,I,J,He,k,W,Ie,de,Le,D,K,je,ue,Ae,G,Me,pe,Ne,v,Ue,me,ze,Je,We,Q,Ke,V,Ge,be,Qe,fe,Ve,he,Xe,p,_e,Ye,ye,Ze,ke,xe,$e,et,ge,tt,Ce,lt,ot,at,De,st,R,ve,L,we,T,j,C=[],nt=new Map,it,A,$=[],ct=new Map,M,qe,rt;w=new At({props:{js:`
import{S as Ht,i as Lt,s as jt,U as At,V as St,W as Z,f as o,y as _,h as i,c as Re,j as b,l as d,n as t,m as Te,B as Mt,C as Nt,G as Ut,X as Pt,Y as zt,D as Jt,Z as Wt,E as Gt,t as Q,a as x,u,d as Pe,I as Ft,p as Kt,k as ee,o as Vt}from"./index-DGnuRrBU.js";function Bt(a,s,n){const c=a.slice();return c[6]=s[n],c}function Et(a,s,n){const c=a.slice();return c[6]=s[n],c}function Ot(a,s){let n,c,y;function h(){return s[5](s[6])}return{key:a,first:null,c(){n=o("button"),n.textContent=`${s[6].code} `,b(n,"class","tab-item"),ee(n,"active",s[1]===s[6].code),this.first=n},m(r,f){d(r,n,f),c||(y=Vt(n,"click",h),c=!0)},p(r,f){s=r,f&10&&ee(n,"active",s[1]===s[6].code)},d(r){r&&u(n),c=!1,y()}}}function It(a,s){let n,c,y,h;return c=new St({props:{content:s[6].body}}),{key:a,first:null,c(){n=o("div"),Re(c.$$.fragment),y=i(),b(n,"class","tab-item"),ee(n,"active",s[1]===s[6].code),this.first=n},m(r,f){d(r,n,f),Te(c,n,null),t(n,y),h=!0},p(r,f){s=r,(!h||f&10)&&ee(n,"active",s[1]===s[6].code)},i(r){h||(Q(c.$$.fragment,r),h=!0)},o(r){x(c.$$.fragment,r),h=!1},d(r){r&&u(n),Pe(c)}}}function Xt(a){var pt,mt,bt,ft,ht,_t,yt,kt;let s,n,c=a[0].name+"",y,h,r,f,F,g,U,Fe,P,B,Be,E,Ee,Oe,te,le,w,oe,O,ae,I,se,S,ne,z,ie,q,ce,Ie,re,H,J,Se,k,W,He,de,Le,D,G,je,ue,Ae,K,Me,pe,Ne,v,Ue,me,ze,Je,We,V,Ge,X,Ke,be,Ve,fe,Xe,he,Ye,p,_e,Ze,ye,Qe,ke,xe,$e,et,ge,tt,Ce,lt,ot,at,De,st,R,ve,L,we,T,j,C=[],nt=new Map,it,A,$=[],ct=new Map,M,qe,rt;w=new At({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${a[2]}');
@@ -28,7 +28,7 @@ import{S as It,i as Lt,s as jt,Q as At,R as Ht,T as Y,e as o,w as _,b as i,c as
batch.collection('${(kt=a[0])==null?void 0:kt.name}').upsert(body: { ... });
final result = await batch.send();
`}}),R=new Ht({props:{language:"javascript",content:`
`}}),R=new St({props:{language:"javascript",content:`
const formData = new FormData();
formData.append("@jsonPayload", JSON.stringify({
@@ -51,18 +51,18 @@ import{S as It,i as Lt,s as jt,Q as At,R as Ht,T as Y,e as o,w as _,b as i,c as
// file for the second request
formData.append("requests.1.someFileField", new File(...))
`}});let X=Y(a[3]);const dt=e=>e[6].code;for(let e=0;e<X.length;e+=1){let l=Ot(a,X,e),m=dt(l);nt.set(m,C[e]=Et(m,l))}let N=Y(a[3]);const ut=e=>e[6].code;for(let e=0;e<N.length;e+=1){let l=Bt(a,N,e),m=ut(l);ct.set(m,$[e]=St(m,l))}return{c(){s=o("h3"),n=_("Batch create/update/upsert/delete ("),y=_(c),h=_(")"),r=i(),f=o("div"),f.innerHTML="<p>Batch and transactional create/update/upsert/delete of multiple records in a single request.</p>",F=i(),g=o("div"),U=o("div"),U.innerHTML='<i class="ri-error-warning-line"></i>',Fe=i(),P=o("div"),B=o("p"),Be=_(`The batch Web API need to be explicitly enabled and configured from the
`),O=o("a"),O.textContent="Dashboard settings",Oe=_("."),Ee=i(),te=o("p"),te.textContent=`Because this endpoint process the requests in a single transaction, it could degrade the
`}});let Y=Z(a[3]);const dt=e=>e[6].code;for(let e=0;e<Y.length;e+=1){let l=Et(a,Y,e),m=dt(l);nt.set(m,C[e]=Ot(m,l))}let N=Z(a[3]);const ut=e=>e[6].code;for(let e=0;e<N.length;e+=1){let l=Bt(a,N,e),m=ut(l);ct.set(m,$[e]=It(m,l))}return{c(){s=o("h3"),n=_("Batch create/update/upsert/delete ("),y=_(c),h=_(")"),r=i(),f=o("div"),f.innerHTML="<p>Batch and transactional create/update/upsert/delete of multiple records in a single request.</p>",F=i(),g=o("div"),U=o("div"),U.innerHTML='<i class="ri-error-warning-line"></i>',Fe=i(),P=o("div"),B=o("p"),Be=_(`The batch Web API need to be explicitly enabled and configured from the
`),E=o("a"),E.textContent="Dashboard settings",Ee=_("."),Oe=i(),te=o("p"),te.textContent=`Because this endpoint process the requests in a single transaction, it could degrade the
performance of your application if not used with proper care and configuration (e.g. too large
allowed execution timeout, large body size limit, etc.).`,le=i(),Re(w.$$.fragment),oe=i(),E=o("h6"),E.textContent="API details",ae=i(),S=o("div"),S.innerHTML='<strong class="label label-primary">POST</strong> <div class="content">/api/batch</div>',se=i(),H=o("div"),H.textContent="Body Parameters",ne=i(),z=o("p"),z.innerHTML=`Body parameters could be sent as <em>application/json</em> or <em>multipart/form-data</em>.
allowed execution timeout, large body size limit, etc.).`,le=i(),Re(w.$$.fragment),oe=i(),O=o("h6"),O.textContent="API details",ae=i(),I=o("div"),I.innerHTML='<strong class="label label-primary">POST</strong> <div class="content">/api/batch</div>',se=i(),S=o("div"),S.textContent="Body Parameters",ne=i(),z=o("p"),z.innerHTML=`Body parameters could be sent as <em>application/json</em> or <em>multipart/form-data</em>.
<br/>
File upload is supported only via <em>multipart/form-data</em> (see below for more details).`,ie=i(),q=o("table"),ce=o("thead"),ce.innerHTML='<tr><th>Param</th> <th width="80%">Description</th></tr>',Se=i(),re=o("tbody"),I=o("tr"),J=o("td"),J.innerHTML='<div class="flex txt-nowrap"><span class="label label-success">Required</span> <span>requests</span></div>',He=i(),k=o("td"),W=o("span"),W.textContent="Array<Request>",Ie=_(` - List of the requests to process.
File upload is supported only via <em>multipart/form-data</em> (see below for more details).`,ie=i(),q=o("table"),ce=o("thead"),ce.innerHTML='<tr><th>Param</th> <th width="80%">Description</th></tr>',Ie=i(),re=o("tbody"),H=o("tr"),J=o("td"),J.innerHTML='<div class="flex txt-nowrap"><span class="label label-success">Required</span> <span>requests</span></div>',Se=i(),k=o("td"),W=o("span"),W.textContent="Array<Request>",He=_(` - List of the requests to process.
`),de=o("p"),de.textContent="The supported batch request actions are:",Le=i(),D=o("ul"),K=o("li"),je=_("record create - "),ue=o("code"),ue.textContent="POST /api/collections/{collection}/records",Ae=i(),G=o("li"),Me=_(`record update -
`),pe=o("code"),pe.textContent="PATCH /api/collections/{collection}/records/{id}",Ne=i(),v=o("li"),Ue=_("record upsert - "),me=o("code"),me.textContent="PUT /api/collections/{collection}/records",ze=i(),Je=o("br"),We=i(),Q=o("small"),Q.innerHTML='(the body must have <code class="txt-sm">id</code> field)',Ke=i(),V=o("li"),Ge=_(`record delete -
`),be=o("code"),be.textContent="DELETE /api/collections/{collection}/records/{id}",Qe=i(),fe=o("p"),fe.textContent="Each batch Request element have the following properties:",Ve=i(),he=o("ul"),he.innerHTML=`<li><code>url path</code> <em>(could include query parameters)</em></li> <li><code>method</code> <em>(GET, POST, PUT, PATCH, DELETE)</em></li> <li><code>headers</code> <br/> <em>(if the <code>POST /api/batch</code> call has <code>Authorization</code> header it
is forwarded to all batch requests automatically)</em></li> <li><code>body</code></li>`,Xe=i(),p=o("p"),_e=o("strong"),_e.textContent="NB!",Ye=_(` When the batch request is send as
`),ye=o("code"),ye.textContent="multipart/form-data",Ze=_(`, the regular batch action fields are expected to be
`),de=o("p"),de.textContent="The supported batch request actions are:",Le=i(),D=o("ul"),G=o("li"),je=_("record create - "),ue=o("code"),ue.textContent="POST /api/collections/{collection}/records",Ae=i(),K=o("li"),Me=_(`record update -
`),pe=o("code"),pe.textContent="PATCH /api/collections/{collection}/records/{id}",Ne=i(),v=o("li"),Ue=_("record upsert - "),me=o("code"),me.textContent="PUT /api/collections/{collection}/records",ze=i(),Je=o("br"),We=i(),V=o("small"),V.innerHTML='(the body must have <code class="txt-sm">id</code> field)',Ge=i(),X=o("li"),Ke=_(`record delete -
`),be=o("code"),be.textContent="DELETE /api/collections/{collection}/records/{id}",Ve=i(),fe=o("p"),fe.textContent="Each batch Request element have the following properties:",Xe=i(),he=o("ul"),he.innerHTML=`<li><code>url path</code> <em>(could include query parameters)</em></li> <li><code>method</code> <em>(GET, POST, PUT, PATCH, DELETE)</em></li> <li><code>headers</code> <br/> <em>(if the <code>POST /api/batch</code> call has <code>Authorization</code> header it
is forwarded to all batch requests automatically)</em></li> <li><code>body</code></li>`,Ye=i(),p=o("p"),_e=o("strong"),_e.textContent="NB!",Ze=_(` When the batch request is send as
`),ye=o("code"),ye.textContent="multipart/form-data",Qe=_(`, the regular batch action fields are expected to be
submitted as serailized json under the `),ke=o("code"),ke.textContent="@jsonPayload",xe=_(` field and file keys need
to follow the pattern `),$e=o("code"),$e.textContent="requests.N.fileField",et=_(` or
`),ge=o("code"),ge.textContent="requests[N].fileField",tt=i(),Ce=o("em"),Ce.textContent=`(this is usually handled transparently by the SDKs when their specific object notation
@@ -71,7 +71,7 @@ import{S as It,i as Lt,s as jt,Q as At,R as Ht,T as Y,e as o,w as _,b as i,c as
`),ot=o("br"),at=_(`
If you don't use the SDKs or prefer manually to construct the `),De=o("code"),De.textContent="FormData",st=_(`
body, then it could look something like:
`),Re(R.$$.fragment),ve=i(),L=o("div"),L.textContent="Responses",we=i(),T=o("div"),j=o("div");for(let e=0;e<C.length;e+=1)C[e].c();it=i(),A=o("div");for(let e=0;e<$.length;e+=1)$[e].c();b(s,"class","m-b-sm"),b(f,"class","content txt-lg m-b-sm"),b(U,"class","icon"),b(O,"href","/settings"),b(P,"class","content"),b(g,"class","alert alert-warning"),b(E,"class","m-b-xs"),b(S,"class","api-route alert alert-success"),b(H,"class","section-title"),b(J,"valign","top"),b(W,"class","label"),b(Q,"class","txt-hint"),b(q,"class","table-compact table-border m-t-xs m-b-base"),b(L,"class","section-title"),b(j,"class","tabs-header compact combined left"),b(A,"class","tabs-content"),b(T,"class","tabs")},m(e,l){d(e,s,l),t(s,n),t(s,y),t(s,h),d(e,r,l),d(e,f,l),d(e,F,l),d(e,g,l),t(g,U),t(g,Fe),t(g,P),t(P,B),t(B,Be),t(B,O),t(B,Oe),t(P,Ee),t(P,te),d(e,le,l),Te(w,e,l),d(e,oe,l),d(e,E,l),d(e,ae,l),d(e,S,l),d(e,se,l),d(e,H,l),d(e,ne,l),d(e,z,l),d(e,ie,l),d(e,q,l),t(q,ce),t(q,Se),t(q,re),t(re,I),t(I,J),t(I,He),t(I,k),t(k,W),t(k,Ie),t(k,de),t(k,Le),t(k,D),t(D,K),t(K,je),t(K,ue),t(D,Ae),t(D,G),t(G,Me),t(G,pe),t(D,Ne),t(D,v),t(v,Ue),t(v,me),t(v,ze),t(v,Je),t(v,We),t(v,Q),t(D,Ke),t(D,V),t(V,Ge),t(V,be),t(k,Qe),t(k,fe),t(k,Ve),t(k,he),t(k,Xe),t(k,p),t(p,_e),t(p,Ye),t(p,ye),t(p,Ze),t(p,ke),t(p,xe),t(p,$e),t(p,et),t(p,ge),t(p,tt),t(p,Ce),t(p,lt),t(p,ot),t(p,at),t(p,De),t(p,st),Te(R,p,null),d(e,ve,l),d(e,L,l),d(e,we,l),d(e,T,l),t(T,j);for(let m=0;m<C.length;m+=1)C[m]&&C[m].m(j,null);t(T,it),t(T,A);for(let m=0;m<$.length;m+=1)$[m]&&$[m].m(A,null);M=!0,qe||(rt=Mt(Nt.call(null,O)),qe=!0)},p(e,[l]){var gt,Ct,Dt,vt,wt,qt,Rt,Tt;(!M||l&1)&&c!==(c=e[0].name+"")&&Ut(y,c);const m={};l&5&&(m.js=`
`),Re(R.$$.fragment),ve=i(),L=o("div"),L.textContent="Responses",we=i(),T=o("div"),j=o("div");for(let e=0;e<C.length;e+=1)C[e].c();it=i(),A=o("div");for(let e=0;e<$.length;e+=1)$[e].c();b(s,"class","m-b-sm"),b(f,"class","content txt-lg m-b-sm"),b(U,"class","icon"),b(E,"href","/settings"),b(P,"class","content"),b(g,"class","alert alert-warning"),b(O,"class","m-b-xs"),b(I,"class","api-route alert alert-success"),b(S,"class","section-title"),b(J,"valign","top"),b(W,"class","label"),b(V,"class","txt-hint"),b(q,"class","table-compact table-border m-t-xs m-b-base"),b(L,"class","section-title"),b(j,"class","tabs-header compact combined left"),b(A,"class","tabs-content"),b(T,"class","tabs")},m(e,l){d(e,s,l),t(s,n),t(s,y),t(s,h),d(e,r,l),d(e,f,l),d(e,F,l),d(e,g,l),t(g,U),t(g,Fe),t(g,P),t(P,B),t(B,Be),t(B,E),t(B,Ee),t(P,Oe),t(P,te),d(e,le,l),Te(w,e,l),d(e,oe,l),d(e,O,l),d(e,ae,l),d(e,I,l),d(e,se,l),d(e,S,l),d(e,ne,l),d(e,z,l),d(e,ie,l),d(e,q,l),t(q,ce),t(q,Ie),t(q,re),t(re,H),t(H,J),t(H,Se),t(H,k),t(k,W),t(k,He),t(k,de),t(k,Le),t(k,D),t(D,G),t(G,je),t(G,ue),t(D,Ae),t(D,K),t(K,Me),t(K,pe),t(D,Ne),t(D,v),t(v,Ue),t(v,me),t(v,ze),t(v,Je),t(v,We),t(v,V),t(D,Ge),t(D,X),t(X,Ke),t(X,be),t(k,Ve),t(k,fe),t(k,Xe),t(k,he),t(k,Ye),t(k,p),t(p,_e),t(p,Ze),t(p,ye),t(p,Qe),t(p,ke),t(p,xe),t(p,$e),t(p,et),t(p,ge),t(p,tt),t(p,Ce),t(p,lt),t(p,ot),t(p,at),t(p,De),t(p,st),Te(R,p,null),d(e,ve,l),d(e,L,l),d(e,we,l),d(e,T,l),t(T,j);for(let m=0;m<C.length;m+=1)C[m]&&C[m].m(j,null);t(T,it),t(T,A);for(let m=0;m<$.length;m+=1)$[m]&&$[m].m(A,null);M=!0,qe||(rt=Mt(Nt.call(null,E)),qe=!0)},p(e,[l]){var gt,Ct,Dt,vt,wt,qt,Rt,Tt;(!M||l&1)&&c!==(c=e[0].name+"")&&Ut(y,c);const m={};l&5&&(m.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${e[2]}');
@@ -124,7 +124,7 @@ import{S as It,i as Lt,s as jt,Q as At,R as Ht,T as Y,e as o,w as _,b as i,c as
// file for the second request
formData.append("requests.1.someFileField", new File(...))
`),R.$set($t),l&10&&(X=Y(e[3]),C=Pt(C,l,dt,1,e,X,nt,j,zt,Et,null,Ot)),l&10&&(N=Y(e[3]),Jt(),$=Pt($,l,ut,1,e,N,ct,A,Wt,St,null,Bt),Kt())},i(e){if(!M){Z(w.$$.fragment,e),Z(R.$$.fragment,e);for(let l=0;l<N.length;l+=1)Z($[l]);M=!0}},o(e){x(w.$$.fragment,e),x(R.$$.fragment,e);for(let l=0;l<$.length;l+=1)x($[l]);M=!1},d(e){e&&(u(s),u(r),u(f),u(F),u(g),u(le),u(oe),u(E),u(ae),u(S),u(se),u(H),u(ne),u(z),u(ie),u(q),u(ve),u(L),u(we),u(T)),Pe(w,e),Pe(R);for(let l=0;l<C.length;l+=1)C[l].d();for(let l=0;l<$.length;l+=1)$[l].d();qe=!1,rt()}}}function Xt(a,s,n){let c,y,{collection:h}=s,r=200,f=[];const F=g=>n(1,r=g.code);return a.$$set=g=>{"collection"in g&&n(0,h=g.collection)},a.$$.update=()=>{a.$$.dirty&1&&n(4,y=Ft.dummyCollectionRecord(h)),a.$$.dirty&17&&h!=null&&h.id&&(f.push({code:200,body:JSON.stringify([y,Object.assign({},y,{id:y+"2"})],null,2)}),f.push({code:400,body:`
`),R.$set($t),l&10&&(Y=Z(e[3]),C=Pt(C,l,dt,1,e,Y,nt,j,zt,Ot,null,Et)),l&10&&(N=Z(e[3]),Jt(),$=Pt($,l,ut,1,e,N,ct,A,Wt,It,null,Bt),Gt())},i(e){if(!M){Q(w.$$.fragment,e),Q(R.$$.fragment,e);for(let l=0;l<N.length;l+=1)Q($[l]);M=!0}},o(e){x(w.$$.fragment,e),x(R.$$.fragment,e);for(let l=0;l<$.length;l+=1)x($[l]);M=!1},d(e){e&&(u(s),u(r),u(f),u(F),u(g),u(le),u(oe),u(O),u(ae),u(I),u(se),u(S),u(ne),u(z),u(ie),u(q),u(ve),u(L),u(we),u(T)),Pe(w,e),Pe(R);for(let l=0;l<C.length;l+=1)C[l].d();for(let l=0;l<$.length;l+=1)$[l].d();qe=!1,rt()}}}function Yt(a,s,n){let c,y,{collection:h}=s,r=200,f=[];const F=g=>n(1,r=g.code);return a.$$set=g=>{"collection"in g&&n(0,h=g.collection)},a.$$.update=()=>{a.$$.dirty&1&&n(4,y=Ft.dummyCollectionRecord(h)),a.$$.dirty&17&&h!=null&&h.id&&(f.push({code:200,body:JSON.stringify([y,Object.assign({},y,{id:y+"2"})],null,2)}),f.push({code:400,body:`
{
"status": 400,
"message": "Batch transaction failed.",
@@ -154,4 +154,4 @@ import{S as It,i as Lt,s as jt,Q as At,R as Ht,T as Y,e as o,w as _,b as i,c as
"message": "Batch requests are not allowed.",
"data": {}
}
`}))},n(2,c=Ft.getApiExampleUrl(Gt.baseURL)),[h,r,c,f,y,F]}class Zt extends It{constructor(s){super(),Lt(this,s,Xt,Vt,jt,{collection:0})}}export{Zt as default};
`}))},n(2,c=Ft.getApiExampleUrl(Kt.baseURL)),[h,r,c,f,y,F]}class Qt extends Ht{constructor(s){super(),Lt(this,s,Yt,Xt,jt,{collection:0})}}export{Qt as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,9 +1,9 @@
import{S as $t,i as qt,s as Tt,Q as St,C as ee,T as ue,R as Ct,e as s,w as _,b as p,c as $e,f as w,g as r,h as i,m as qe,x as oe,U as Ve,V as pt,k as Ot,W as Mt,n as Pt,t as ye,a as ve,o as d,d as Te,p as Ft,r as Se,u as Lt,y as we,E as Ht}from"./index-Co7n6kj7.js";import{F as Rt}from"./FieldsQueryParam-DH-ZC4qv.js";function mt(a,e,t){const l=a.slice();return l[10]=e[t],l}function bt(a,e,t){const l=a.slice();return l[10]=e[t],l}function _t(a,e,t){const l=a.slice();return l[15]=e[t],l}function kt(a){let e;return{c(){e=s("p"),e.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",w(e,"class","txt-hint txt-sm txt-right")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function ht(a){let e,t,l,u,c,f,b,m,$,h,g,B,S,O,R,M,U,J,T,W,P,q,k,F,te,K,I,re,Y,x,G;function fe(y,C){var V,z,H;return C&1&&(f=null),f==null&&(f=!!((H=(z=(V=y[0])==null?void 0:V.fields)==null?void 0:z.find(xt))!=null&&H.required)),f?Bt:At}let le=fe(a,-1),E=le(a);function X(y,C){var V,z,H;return C&1&&(U=null),U==null&&(U=!!((H=(z=(V=y[0])==null?void 0:V.fields)==null?void 0:z.find(Yt))!=null&&H.required)),U?Vt:jt}let Z=X(a,-1),L=Z(a);return{c(){e=s("tr"),e.innerHTML='<td colspan="3" class="txt-hint txt-bold">Auth specific fields</td>',t=p(),l=s("tr"),u=s("td"),c=s("div"),E.c(),b=p(),m=s("span"),m.textContent="email",$=p(),h=s("td"),h.innerHTML='<span class="label">String</span>',g=p(),B=s("td"),B.textContent="Auth record email address.",S=p(),O=s("tr"),R=s("td"),M=s("div"),L.c(),J=p(),T=s("span"),T.textContent="emailVisibility",W=p(),P=s("td"),P.innerHTML='<span class="label">Boolean</span>',q=p(),k=s("td"),k.textContent="Whether to show/hide the auth record email when fetching the record data.",F=p(),te=s("tr"),te.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>',K=p(),I=s("tr"),I.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>',re=p(),Y=s("tr"),Y.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.
import{S as $t,i as qt,s as St,U as Tt,I as ee,W as ue,V as Ct,f as s,y as _,h as p,c as $e,j as w,l as r,n as i,m as qe,G as oe,X as Ve,Y as pt,D as Ot,Z as Mt,E as Pt,t as ye,a as ve,u as d,d as Se,p as Ft,k as Te,o as Ht,H as we,K as Lt}from"./index-DGnuRrBU.js";import{F as Rt}from"./FieldsQueryParam-DeLgGM_S.js";function mt(a,e,t){const l=a.slice();return l[10]=e[t],l}function bt(a,e,t){const l=a.slice();return l[10]=e[t],l}function _t(a,e,t){const l=a.slice();return l[15]=e[t],l}function kt(a){let e;return{c(){e=s("p"),e.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",w(e,"class","txt-hint txt-sm txt-right")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function ht(a){let e,t,l,u,c,f,b,m,$,h,g,A,T,O,R,M,U,J,S,Q,P,q,k,F,te,Y,I,re,z,G,X;function fe(y,C){var V,W,L;return C&1&&(f=null),f==null&&(f=!!((L=(W=(V=y[0])==null?void 0:V.fields)==null?void 0:W.find(Gt))!=null&&L.required)),f?At:jt}let le=fe(a,-1),E=le(a);function Z(y,C){var V,W,L;return C&1&&(U=null),U==null&&(U=!!((L=(W=(V=y[0])==null?void 0:V.fields)==null?void 0:W.find(zt))!=null&&L.required)),U?Vt:Bt}let x=Z(a,-1),H=x(a);return{c(){e=s("tr"),e.innerHTML='<td colspan="3" class="txt-hint txt-bold">Auth specific fields</td>',t=p(),l=s("tr"),u=s("td"),c=s("div"),E.c(),b=p(),m=s("span"),m.textContent="email",$=p(),h=s("td"),h.innerHTML='<span class="label">String</span>',g=p(),A=s("td"),A.textContent="Auth record email address.",T=p(),O=s("tr"),R=s("td"),M=s("div"),H.c(),J=p(),S=s("span"),S.textContent="emailVisibility",Q=p(),P=s("td"),P.innerHTML='<span class="label">Boolean</span>',q=p(),k=s("td"),k.textContent="Whether to show/hide the auth record email when fetching the record data.",F=p(),te=s("tr"),te.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>',Y=p(),I=s("tr"),I.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>',re=p(),z=s("tr"),z.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 superusers or auth records with &quot;Manage&quot; access.</td>`,x=p(),G=s("tr"),G.innerHTML='<td colspan="3" class="txt-hint txt-bold">Other fields</td>',w(c,"class","inline-flex"),w(M,"class","inline-flex")},m(y,C){r(y,e,C),r(y,t,C),r(y,l,C),i(l,u),i(u,c),E.m(c,null),i(c,b),i(c,m),i(l,$),i(l,h),i(l,g),i(l,B),r(y,S,C),r(y,O,C),i(O,R),i(R,M),L.m(M,null),i(M,J),i(M,T),i(O,W),i(O,P),i(O,q),i(O,k),r(y,F,C),r(y,te,C),r(y,K,C),r(y,I,C),r(y,re,C),r(y,Y,C),r(y,x,C),r(y,G,C)},p(y,C){le!==(le=fe(y,C))&&(E.d(1),E=le(y),E&&(E.c(),E.m(c,b))),Z!==(Z=X(y,C))&&(L.d(1),L=Z(y),L&&(L.c(),L.m(M,J)))},d(y){y&&(d(e),d(t),d(l),d(S),d(O),d(F),d(te),d(K),d(I),d(re),d(Y),d(x),d(G)),E.d(),L.d()}}}function At(a){let e;return{c(){e=s("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Bt(a){let e;return{c(){e=s("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function jt(a){let e;return{c(){e=s("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Vt(a){let e;return{c(){e=s("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Nt(a){let e;return{c(){e=s("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Dt(a){let e;return{c(){e=s("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Jt(a){let e,t=a[15].maxSelect===1?"id":"ids",l,u;return{c(){e=_("Relation record "),l=_(t),u=_(".")},m(c,f){r(c,e,f),r(c,l,f),r(c,u,f)},p(c,f){f&64&&t!==(t=c[15].maxSelect===1?"id":"ids")&&oe(l,t)},d(c){c&&(d(e),d(l),d(u))}}}function Et(a){let e,t,l,u,c,f,b,m,$;return{c(){e=_("File object."),t=s("br"),l=_(`
This field can be set only by superusers or auth records with &quot;Manage&quot; access.</td>`,G=p(),X=s("tr"),X.innerHTML='<td colspan="3" class="txt-hint txt-bold">Other fields</td>',w(c,"class","inline-flex"),w(M,"class","inline-flex")},m(y,C){r(y,e,C),r(y,t,C),r(y,l,C),i(l,u),i(u,c),E.m(c,null),i(c,b),i(c,m),i(l,$),i(l,h),i(l,g),i(l,A),r(y,T,C),r(y,O,C),i(O,R),i(R,M),H.m(M,null),i(M,J),i(M,S),i(O,Q),i(O,P),i(O,q),i(O,k),r(y,F,C),r(y,te,C),r(y,Y,C),r(y,I,C),r(y,re,C),r(y,z,C),r(y,G,C),r(y,X,C)},p(y,C){le!==(le=fe(y,C))&&(E.d(1),E=le(y),E&&(E.c(),E.m(c,b))),x!==(x=Z(y,C))&&(H.d(1),H=x(y),H&&(H.c(),H.m(M,J)))},d(y){y&&(d(e),d(t),d(l),d(T),d(O),d(F),d(te),d(Y),d(I),d(re),d(z),d(G),d(X)),E.d(),H.d()}}}function jt(a){let e;return{c(){e=s("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function At(a){let e;return{c(){e=s("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Bt(a){let e;return{c(){e=s("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Vt(a){let e;return{c(){e=s("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Dt(a){let e;return{c(){e=s("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Nt(a){let e;return{c(){e=s("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function Jt(a){let e,t=a[15].maxSelect===1?"id":"ids",l,u;return{c(){e=_("Relation record "),l=_(t),u=_(".")},m(c,f){r(c,e,f),r(c,l,f),r(c,u,f)},p(c,f){f&64&&t!==(t=c[15].maxSelect===1?"id":"ids")&&oe(l,t)},d(c){c&&(d(e),d(l),d(u))}}}function Et(a){let e,t,l,u,c,f,b,m,$;return{c(){e=_("File object."),t=s("br"),l=_(`
Set to empty value (`),u=s("code"),u.textContent="null",c=_(", "),f=s("code"),f.textContent='""',b=_(" or "),m=s("code"),m.textContent="[]",$=_(`) to delete
already uploaded file(s).`)},m(h,g){r(h,e,g),r(h,t,g),r(h,l,g),r(h,u,g),r(h,c,g),r(h,f,g),r(h,b,g),r(h,m,g),r(h,$,g)},p:we,d(h){h&&(d(e),d(t),d(l),d(u),d(c),d(f),d(b),d(m),d($))}}}function Ut(a){let e;return{c(){e=_("URL address.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function It(a){let e;return{c(){e=_("Email address.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function Qt(a){let e;return{c(){e=_("JSON array or object.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function Wt(a){let e;return{c(){e=_("Number value.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function zt(a){let e,t,l=a[15].autogeneratePattern&&yt();return{c(){e=_(`Plain text value.
`),l&&l.c(),t=Ht()},m(u,c){r(u,e,c),l&&l.m(u,c),r(u,t,c)},p(u,c){u[15].autogeneratePattern?l||(l=yt(),l.c(),l.m(t.parentNode,t)):l&&(l.d(1),l=null)},d(u){u&&(d(e),d(t)),l&&l.d(u)}}}function yt(a){let e;return{c(){e=_("It is autogenerated if not set.")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function vt(a,e){let t,l,u,c,f,b=e[15].name+"",m,$,h,g,B=ee.getFieldValueType(e[15])+"",S,O,R,M;function U(k,F){return!k[15].required||k[15].type=="text"&&k[15].autogeneratePattern?Dt:Nt}let J=U(e),T=J(e);function W(k,F){if(k[15].type==="text")return zt;if(k[15].type==="number")return Wt;if(k[15].type==="json")return Qt;if(k[15].type==="email")return It;if(k[15].type==="url")return Ut;if(k[15].type==="file")return Et;if(k[15].type==="relation")return Jt}let P=W(e),q=P&&P(e);return{key:a,first:null,c(){t=s("tr"),l=s("td"),u=s("div"),T.c(),c=p(),f=s("span"),m=_(b),$=p(),h=s("td"),g=s("span"),S=_(B),O=p(),R=s("td"),q&&q.c(),M=p(),w(u,"class","inline-flex"),w(g,"class","label"),this.first=t},m(k,F){r(k,t,F),i(t,l),i(l,u),T.m(u,null),i(u,c),i(u,f),i(f,m),i(t,$),i(t,h),i(h,g),i(g,S),i(t,O),i(t,R),q&&q.m(R,null),i(t,M)},p(k,F){e=k,J!==(J=U(e))&&(T.d(1),T=J(e),T&&(T.c(),T.m(u,c))),F&64&&b!==(b=e[15].name+"")&&oe(m,b),F&64&&B!==(B=ee.getFieldValueType(e[15])+"")&&oe(S,B),P===(P=W(e))&&q?q.p(e,F):(q&&q.d(1),q=P&&P(e),q&&(q.c(),q.m(R,null)))},d(k){k&&d(t),T.d(),q&&q.d()}}}function wt(a,e){let t,l=e[10].code+"",u,c,f,b;function m(){return e[9](e[10])}return{key:a,first:null,c(){t=s("button"),u=_(l),c=p(),w(t,"class","tab-item"),Se(t,"active",e[2]===e[10].code),this.first=t},m($,h){r($,t,h),i(t,u),i(t,c),f||(b=Lt(t,"click",m),f=!0)},p($,h){e=$,h&8&&l!==(l=e[10].code+"")&&oe(u,l),h&12&&Se(t,"active",e[2]===e[10].code)},d($){$&&d(t),f=!1,b()}}}function gt(a,e){let t,l,u,c;return l=new Ct({props:{content:e[10].body}}),{key:a,first:null,c(){t=s("div"),$e(l.$$.fragment),u=p(),w(t,"class","tab-item"),Se(t,"active",e[2]===e[10].code),this.first=t},m(f,b){r(f,t,b),qe(l,t,null),i(t,u),c=!0},p(f,b){e=f;const m={};b&8&&(m.content=e[10].body),l.$set(m),(!c||b&12)&&Se(t,"active",e[2]===e[10].code)},i(f){c||(ye(l.$$.fragment,f),c=!0)},o(f){ve(l.$$.fragment,f),c=!1},d(f){f&&d(t),Te(l)}}}function Kt(a){var at,st,ot,rt;let e,t,l=a[0].name+"",u,c,f,b,m,$,h,g=a[0].name+"",B,S,O,R,M,U,J,T,W,P,q,k,F,te,K,I,re,Y,x=a[0].name+"",G,fe,le,E,X,Z,L,y,C,V,z,H=[],Ne=new Map,Oe,pe,Me,ne,Pe,De,me,ie,Fe,Je,Le,Ee,A,Ue,de,Ie,Qe,We,He,ze,Re,Ke,Ye,xe,Ae,Ge,Xe,ce,Be,be,je,ae,_e,Q=[],Ze=new Map,et,ke,N=[],tt=new Map,se;T=new St({props:{js:`
already uploaded file(s).`)},m(h,g){r(h,e,g),r(h,t,g),r(h,l,g),r(h,u,g),r(h,c,g),r(h,f,g),r(h,b,g),r(h,m,g),r(h,$,g)},p:we,d(h){h&&(d(e),d(t),d(l),d(u),d(c),d(f),d(b),d(m),d($))}}}function Ut(a){let e;return{c(){e=_("URL address.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function It(a){let e;return{c(){e=_("Email address.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function Kt(a){let e;return{c(){e=_("JSON array or object.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function Qt(a){let e;return{c(){e=_("Number value.")},m(t,l){r(t,e,l)},p:we,d(t){t&&d(e)}}}function Wt(a){let e,t,l=a[15].autogeneratePattern&&yt();return{c(){e=_(`Plain text value.
`),l&&l.c(),t=Lt()},m(u,c){r(u,e,c),l&&l.m(u,c),r(u,t,c)},p(u,c){u[15].autogeneratePattern?l||(l=yt(),l.c(),l.m(t.parentNode,t)):l&&(l.d(1),l=null)},d(u){u&&(d(e),d(t)),l&&l.d(u)}}}function yt(a){let e;return{c(){e=_("It is autogenerated if not set.")},m(t,l){r(t,e,l)},d(t){t&&d(e)}}}function vt(a,e){let t,l,u,c,f,b=e[15].name+"",m,$,h,g,A=ee.getFieldValueType(e[15])+"",T,O,R,M;function U(k,F){return!k[15].required||k[15].type=="text"&&k[15].autogeneratePattern?Nt:Dt}let J=U(e),S=J(e);function Q(k,F){if(k[15].type==="text")return Wt;if(k[15].type==="number")return Qt;if(k[15].type==="json")return Kt;if(k[15].type==="email")return It;if(k[15].type==="url")return Ut;if(k[15].type==="file")return Et;if(k[15].type==="relation")return Jt}let P=Q(e),q=P&&P(e);return{key:a,first:null,c(){t=s("tr"),l=s("td"),u=s("div"),S.c(),c=p(),f=s("span"),m=_(b),$=p(),h=s("td"),g=s("span"),T=_(A),O=p(),R=s("td"),q&&q.c(),M=p(),w(u,"class","inline-flex"),w(g,"class","label"),this.first=t},m(k,F){r(k,t,F),i(t,l),i(l,u),S.m(u,null),i(u,c),i(u,f),i(f,m),i(t,$),i(t,h),i(h,g),i(g,T),i(t,O),i(t,R),q&&q.m(R,null),i(t,M)},p(k,F){e=k,J!==(J=U(e))&&(S.d(1),S=J(e),S&&(S.c(),S.m(u,c))),F&64&&b!==(b=e[15].name+"")&&oe(m,b),F&64&&A!==(A=ee.getFieldValueType(e[15])+"")&&oe(T,A),P===(P=Q(e))&&q?q.p(e,F):(q&&q.d(1),q=P&&P(e),q&&(q.c(),q.m(R,null)))},d(k){k&&d(t),S.d(),q&&q.d()}}}function wt(a,e){let t,l=e[10].code+"",u,c,f,b;function m(){return e[9](e[10])}return{key:a,first:null,c(){t=s("button"),u=_(l),c=p(),w(t,"class","tab-item"),Te(t,"active",e[2]===e[10].code),this.first=t},m($,h){r($,t,h),i(t,u),i(t,c),f||(b=Ht(t,"click",m),f=!0)},p($,h){e=$,h&8&&l!==(l=e[10].code+"")&&oe(u,l),h&12&&Te(t,"active",e[2]===e[10].code)},d($){$&&d(t),f=!1,b()}}}function gt(a,e){let t,l,u,c;return l=new Ct({props:{content:e[10].body}}),{key:a,first:null,c(){t=s("div"),$e(l.$$.fragment),u=p(),w(t,"class","tab-item"),Te(t,"active",e[2]===e[10].code),this.first=t},m(f,b){r(f,t,b),qe(l,t,null),i(t,u),c=!0},p(f,b){e=f;const m={};b&8&&(m.content=e[10].body),l.$set(m),(!c||b&12)&&Te(t,"active",e[2]===e[10].code)},i(f){c||(ye(l.$$.fragment,f),c=!0)},o(f){ve(l.$$.fragment,f),c=!1},d(f){f&&d(t),Se(l)}}}function Yt(a){var at,st,ot,rt;let e,t,l=a[0].name+"",u,c,f,b,m,$,h,g=a[0].name+"",A,T,O,R,M,U,J,S,Q,P,q,k,F,te,Y,I,re,z,G=a[0].name+"",X,fe,le,E,Z,x,H,y,C,V,W,L=[],De=new Map,Oe,pe,Me,ne,Pe,Ne,me,ie,Fe,Je,He,Ee,j,Ue,de,Ie,Ke,Qe,Le,We,Re,Ye,ze,Ge,je,Xe,Ze,ce,Ae,be,Be,ae,_e,K=[],xe=new Map,et,ke,D=[],tt=new Map,se;S=new Tt({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${a[5]}');
@@ -31,18 +31,18 @@ final record = await pb.collection('${(ot=a[0])==null?void 0:ot.name}').create(b
`+(a[1]?`
// (optional) send an email verification request
await pb.collection('${(rt=a[0])==null?void 0:rt.name}').requestVerification('test@example.com');
`:"")}});let D=a[7]&&kt(),j=a[1]&&ht(a),ge=ue(a[6]);const lt=n=>n[15].name;for(let n=0;n<ge.length;n+=1){let o=_t(a,ge,n),v=lt(o);Ne.set(v,H[n]=vt(v,o))}de=new Ct({props:{content:"?expand=relField1,relField2.subRelField"}}),ce=new Rt({});let Ce=ue(a[3]);const nt=n=>n[10].code;for(let n=0;n<Ce.length;n+=1){let o=bt(a,Ce,n),v=nt(o);Ze.set(v,Q[n]=wt(v,o))}let he=ue(a[3]);const it=n=>n[10].code;for(let n=0;n<he.length;n+=1){let o=mt(a,he,n),v=it(o);tt.set(v,N[n]=gt(v,o))}return{c(){e=s("h3"),t=_("Create ("),u=_(l),c=_(")"),f=p(),b=s("div"),m=s("p"),$=_("Create a new "),h=s("strong"),B=_(g),S=_(" record."),O=p(),R=s("p"),R.innerHTML=`Body parameters could be sent as <code>application/json</code> or
`:"")}});let N=a[7]&&kt(),B=a[1]&&ht(a),ge=ue(a[6]);const lt=n=>n[15].name;for(let n=0;n<ge.length;n+=1){let o=_t(a,ge,n),v=lt(o);De.set(v,L[n]=vt(v,o))}de=new Ct({props:{content:"?expand=relField1,relField2.subRelField"}}),ce=new Rt({});let Ce=ue(a[3]);const nt=n=>n[10].code;for(let n=0;n<Ce.length;n+=1){let o=bt(a,Ce,n),v=nt(o);xe.set(v,K[n]=wt(v,o))}let he=ue(a[3]);const it=n=>n[10].code;for(let n=0;n<he.length;n+=1){let o=mt(a,he,n),v=it(o);tt.set(v,D[n]=gt(v,o))}return{c(){e=s("h3"),t=_("Create ("),u=_(l),c=_(")"),f=p(),b=s("div"),m=s("p"),$=_("Create a new "),h=s("strong"),A=_(g),T=_(" record."),O=p(),R=s("p"),R.innerHTML=`Body parameters could be sent as <code>application/json</code> or
<code>multipart/form-data</code>.`,M=p(),U=s("p"),U.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>.`,J=p(),$e(T.$$.fragment),W=p(),P=s("h6"),P.textContent="API details",q=p(),k=s("div"),F=s("strong"),F.textContent="POST",te=p(),K=s("div"),I=s("p"),re=_("/api/collections/"),Y=s("strong"),G=_(x),fe=_("/records"),le=p(),D&&D.c(),E=p(),X=s("div"),X.textContent="Body Parameters",Z=p(),L=s("table"),y=s("thead"),y.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',C=p(),V=s("tbody"),j&&j.c(),z=p();for(let n=0;n<H.length;n+=1)H[n].c();Oe=p(),pe=s("div"),pe.textContent="Query parameters",Me=p(),ne=s("table"),Pe=s("thead"),Pe.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',De=p(),me=s("tbody"),ie=s("tr"),Fe=s("td"),Fe.textContent="expand",Je=p(),Le=s("td"),Le.innerHTML='<span class="label">String</span>',Ee=p(),A=s("td"),Ue=_(`Auto expand relations when returning the created record. Ex.:
</a>.`,J=p(),$e(S.$$.fragment),Q=p(),P=s("h6"),P.textContent="API details",q=p(),k=s("div"),F=s("strong"),F.textContent="POST",te=p(),Y=s("div"),I=s("p"),re=_("/api/collections/"),z=s("strong"),X=_(G),fe=_("/records"),le=p(),N&&N.c(),E=p(),Z=s("div"),Z.textContent="Body Parameters",x=p(),H=s("table"),y=s("thead"),y.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr>',C=p(),V=s("tbody"),B&&B.c(),W=p();for(let n=0;n<L.length;n+=1)L[n].c();Oe=p(),pe=s("div"),pe.textContent="Query parameters",Me=p(),ne=s("table"),Pe=s("thead"),Pe.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',Ne=p(),me=s("tbody"),ie=s("tr"),Fe=s("td"),Fe.textContent="expand",Je=p(),He=s("td"),He.innerHTML='<span class="label">String</span>',Ee=p(),j=s("td"),Ue=_(`Auto expand relations when returning the created record. Ex.:
`),$e(de.$$.fragment),Ie=_(`
Supports up to 6-levels depth nested relations expansion. `),Qe=s("br"),We=_(`
Supports up to 6-levels depth nested relations expansion. `),Ke=s("br"),Qe=_(`
The expanded relations will be appended to the record under the
`),He=s("code"),He.textContent="expand",ze=_(" property (eg. "),Re=s("code"),Re.textContent='"expand": {"relField1": {...}, ...}',Ke=_(`).
`),Ye=s("br"),xe=_(`
Only the relations to which the request user has permissions to `),Ae=s("strong"),Ae.textContent="view",Ge=_(" will be expanded."),Xe=p(),$e(ce.$$.fragment),Be=p(),be=s("div"),be.textContent="Responses",je=p(),ae=s("div"),_e=s("div");for(let n=0;n<Q.length;n+=1)Q[n].c();et=p(),ke=s("div");for(let n=0;n<N.length;n+=1)N[n].c();w(e,"class","m-b-sm"),w(b,"class","content txt-lg m-b-sm"),w(P,"class","m-b-xs"),w(F,"class","label label-primary"),w(K,"class","content"),w(k,"class","alert alert-success"),w(X,"class","section-title"),w(L,"class","table-compact table-border m-b-base"),w(pe,"class","section-title"),w(ne,"class","table-compact table-border m-b-base"),w(be,"class","section-title"),w(_e,"class","tabs-header compact combined left"),w(ke,"class","tabs-content"),w(ae,"class","tabs")},m(n,o){r(n,e,o),i(e,t),i(e,u),i(e,c),r(n,f,o),r(n,b,o),i(b,m),i(m,$),i(m,h),i(h,B),i(m,S),i(b,O),i(b,R),i(b,M),i(b,U),r(n,J,o),qe(T,n,o),r(n,W,o),r(n,P,o),r(n,q,o),r(n,k,o),i(k,F),i(k,te),i(k,K),i(K,I),i(I,re),i(I,Y),i(Y,G),i(I,fe),i(k,le),D&&D.m(k,null),r(n,E,o),r(n,X,o),r(n,Z,o),r(n,L,o),i(L,y),i(L,C),i(L,V),j&&j.m(V,null),i(V,z);for(let v=0;v<H.length;v+=1)H[v]&&H[v].m(V,null);r(n,Oe,o),r(n,pe,o),r(n,Me,o),r(n,ne,o),i(ne,Pe),i(ne,De),i(ne,me),i(me,ie),i(ie,Fe),i(ie,Je),i(ie,Le),i(ie,Ee),i(ie,A),i(A,Ue),qe(de,A,null),i(A,Ie),i(A,Qe),i(A,We),i(A,He),i(A,ze),i(A,Re),i(A,Ke),i(A,Ye),i(A,xe),i(A,Ae),i(A,Ge),i(me,Xe),qe(ce,me,null),r(n,Be,o),r(n,be,o),r(n,je,o),r(n,ae,o),i(ae,_e);for(let v=0;v<Q.length;v+=1)Q[v]&&Q[v].m(_e,null);i(ae,et),i(ae,ke);for(let v=0;v<N.length;v+=1)N[v]&&N[v].m(ke,null);se=!0},p(n,[o]){var dt,ct,ut,ft;(!se||o&1)&&l!==(l=n[0].name+"")&&oe(u,l),(!se||o&1)&&g!==(g=n[0].name+"")&&oe(B,g);const v={};o&51&&(v.js=`
`),Le=s("code"),Le.textContent="expand",We=_(" property (eg. "),Re=s("code"),Re.textContent='"expand": {"relField1": {...}, ...}',Ye=_(`).
`),ze=s("br"),Ge=_(`
Only the relations to which the request user has permissions to `),je=s("strong"),je.textContent="view",Xe=_(" will be expanded."),Ze=p(),$e(ce.$$.fragment),Ae=p(),be=s("div"),be.textContent="Responses",Be=p(),ae=s("div"),_e=s("div");for(let n=0;n<K.length;n+=1)K[n].c();et=p(),ke=s("div");for(let n=0;n<D.length;n+=1)D[n].c();w(e,"class","m-b-sm"),w(b,"class","content txt-lg m-b-sm"),w(P,"class","m-b-xs"),w(F,"class","label label-primary"),w(Y,"class","content"),w(k,"class","alert alert-success"),w(Z,"class","section-title"),w(H,"class","table-compact table-border m-b-base"),w(pe,"class","section-title"),w(ne,"class","table-compact table-border m-b-base"),w(be,"class","section-title"),w(_e,"class","tabs-header compact combined left"),w(ke,"class","tabs-content"),w(ae,"class","tabs")},m(n,o){r(n,e,o),i(e,t),i(e,u),i(e,c),r(n,f,o),r(n,b,o),i(b,m),i(m,$),i(m,h),i(h,A),i(m,T),i(b,O),i(b,R),i(b,M),i(b,U),r(n,J,o),qe(S,n,o),r(n,Q,o),r(n,P,o),r(n,q,o),r(n,k,o),i(k,F),i(k,te),i(k,Y),i(Y,I),i(I,re),i(I,z),i(z,X),i(I,fe),i(k,le),N&&N.m(k,null),r(n,E,o),r(n,Z,o),r(n,x,o),r(n,H,o),i(H,y),i(H,C),i(H,V),B&&B.m(V,null),i(V,W);for(let v=0;v<L.length;v+=1)L[v]&&L[v].m(V,null);r(n,Oe,o),r(n,pe,o),r(n,Me,o),r(n,ne,o),i(ne,Pe),i(ne,Ne),i(ne,me),i(me,ie),i(ie,Fe),i(ie,Je),i(ie,He),i(ie,Ee),i(ie,j),i(j,Ue),qe(de,j,null),i(j,Ie),i(j,Ke),i(j,Qe),i(j,Le),i(j,We),i(j,Re),i(j,Ye),i(j,ze),i(j,Ge),i(j,je),i(j,Xe),i(me,Ze),qe(ce,me,null),r(n,Ae,o),r(n,be,o),r(n,Be,o),r(n,ae,o),i(ae,_e);for(let v=0;v<K.length;v+=1)K[v]&&K[v].m(_e,null);i(ae,et),i(ae,ke);for(let v=0;v<D.length;v+=1)D[v]&&D[v].m(ke,null);se=!0},p(n,[o]){var dt,ct,ut,ft;(!se||o&1)&&l!==(l=n[0].name+"")&&oe(u,l),(!se||o&1)&&g!==(g=n[0].name+"")&&oe(A,g);const v={};o&51&&(v.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[5]}');
@@ -70,7 +70,7 @@ final record = await pb.collection('${(ut=n[0])==null?void 0:ut.name}').create(b
`+(n[1]?`
// (optional) send an email verification request
await pb.collection('${(ft=n[0])==null?void 0:ft.name}').requestVerification('test@example.com');
`:"")),T.$set(v),(!se||o&1)&&x!==(x=n[0].name+"")&&oe(G,x),n[7]?D||(D=kt(),D.c(),D.m(k,null)):D&&(D.d(1),D=null),n[1]?j?j.p(n,o):(j=ht(n),j.c(),j.m(V,z)):j&&(j.d(1),j=null),o&64&&(ge=ue(n[6]),H=Ve(H,o,lt,1,n,ge,Ne,V,pt,vt,null,_t)),o&12&&(Ce=ue(n[3]),Q=Ve(Q,o,nt,1,n,Ce,Ze,_e,pt,wt,null,bt)),o&12&&(he=ue(n[3]),Ot(),N=Ve(N,o,it,1,n,he,tt,ke,Mt,gt,null,mt),Pt())},i(n){if(!se){ye(T.$$.fragment,n),ye(de.$$.fragment,n),ye(ce.$$.fragment,n);for(let o=0;o<he.length;o+=1)ye(N[o]);se=!0}},o(n){ve(T.$$.fragment,n),ve(de.$$.fragment,n),ve(ce.$$.fragment,n);for(let o=0;o<N.length;o+=1)ve(N[o]);se=!1},d(n){n&&(d(e),d(f),d(b),d(J),d(W),d(P),d(q),d(k),d(E),d(X),d(Z),d(L),d(Oe),d(pe),d(Me),d(ne),d(Be),d(be),d(je),d(ae)),Te(T,n),D&&D.d(),j&&j.d();for(let o=0;o<H.length;o+=1)H[o].d();Te(de),Te(ce);for(let o=0;o<Q.length;o+=1)Q[o].d();for(let o=0;o<N.length;o+=1)N[o].d()}}}const Yt=a=>a.name=="emailVisibility",xt=a=>a.name=="email";function Gt(a,e,t){let l,u,c,f,b,{collection:m}=e,$=200,h=[],g={};const B=S=>t(2,$=S.code);return a.$$set=S=>{"collection"in S&&t(0,m=S.collection)},a.$$.update=()=>{var S,O,R;a.$$.dirty&1&&t(1,l=m.type==="auth"),a.$$.dirty&1&&t(7,u=(m==null?void 0:m.createRule)===null),a.$$.dirty&2&&t(8,c=l?["password","verified","email","emailVisibility"]:[]),a.$$.dirty&257&&t(6,f=((S=m==null?void 0:m.fields)==null?void 0:S.filter(M=>!M.hidden&&M.type!="autodate"&&!c.includes(M.name)))||[]),a.$$.dirty&1&&t(3,h=[{code:200,body:JSON.stringify(ee.dummyCollectionRecord(m),null,2)},{code:400,body:`
`:"")),S.$set(v),(!se||o&1)&&G!==(G=n[0].name+"")&&oe(X,G),n[7]?N||(N=kt(),N.c(),N.m(k,null)):N&&(N.d(1),N=null),n[1]?B?B.p(n,o):(B=ht(n),B.c(),B.m(V,W)):B&&(B.d(1),B=null),o&64&&(ge=ue(n[6]),L=Ve(L,o,lt,1,n,ge,De,V,pt,vt,null,_t)),o&12&&(Ce=ue(n[3]),K=Ve(K,o,nt,1,n,Ce,xe,_e,pt,wt,null,bt)),o&12&&(he=ue(n[3]),Ot(),D=Ve(D,o,it,1,n,he,tt,ke,Mt,gt,null,mt),Pt())},i(n){if(!se){ye(S.$$.fragment,n),ye(de.$$.fragment,n),ye(ce.$$.fragment,n);for(let o=0;o<he.length;o+=1)ye(D[o]);se=!0}},o(n){ve(S.$$.fragment,n),ve(de.$$.fragment,n),ve(ce.$$.fragment,n);for(let o=0;o<D.length;o+=1)ve(D[o]);se=!1},d(n){n&&(d(e),d(f),d(b),d(J),d(Q),d(P),d(q),d(k),d(E),d(Z),d(x),d(H),d(Oe),d(pe),d(Me),d(ne),d(Ae),d(be),d(Be),d(ae)),Se(S,n),N&&N.d(),B&&B.d();for(let o=0;o<L.length;o+=1)L[o].d();Se(de),Se(ce);for(let o=0;o<K.length;o+=1)K[o].d();for(let o=0;o<D.length;o+=1)D[o].d()}}}const zt=a=>a.name=="emailVisibility",Gt=a=>a.name=="email";function Xt(a,e,t){let l,u,c,f,b,{collection:m}=e,$=200,h=[],g={};const A=T=>t(2,$=T.code);return a.$$set=T=>{"collection"in T&&t(0,m=T.collection)},a.$$.update=()=>{var T,O,R;a.$$.dirty&1&&t(1,l=m.type==="auth"),a.$$.dirty&1&&t(7,u=(m==null?void 0:m.createRule)===null),a.$$.dirty&2&&t(8,c=l?["password","verified","email","emailVisibility"]:[]),a.$$.dirty&257&&t(6,f=((T=m==null?void 0:m.fields)==null?void 0:T.filter(M=>!M.hidden&&M.type!="autodate"&&!c.includes(M.name)))||[]),a.$$.dirty&1&&t(3,h=[{code:200,body:JSON.stringify(ee.dummyCollectionRecord(m),null,2)},{code:400,body:`
{
"code": 400,
"message": "Failed to create record.",
@@ -87,4 +87,4 @@ await pb.collection('${(ft=n[0])==null?void 0:ft.name}').requestVerification('te
"message": "You are not allowed to perform this request.",
"data": {}
}
`}]),a.$$.dirty&2&&(l?t(4,g={password:"12345678",passwordConfirm:"12345678"}):t(4,g={}))},t(5,b=ee.getApiExampleUrl(Ft.baseURL)),[m,l,$,h,g,b,f,u,c,B]}class el extends $t{constructor(e){super(),qt(this,e,Gt,Kt,Tt,{collection:0})}}export{el as default};
`}]),a.$$.dirty&2&&(l?t(4,g={password:"12345678",passwordConfirm:"12345678"}):t(4,g={}))},t(5,b=ee.getApiExampleUrl(Ft.baseURL)),[m,l,$,h,g,b,f,u,c,A]}class el extends $t{constructor(e){super(),qt(this,e,Xt,Yt,St,{collection:0})}}export{el as default};
+53
View File
@@ -0,0 +1,53 @@
import{S as Re,i as Ee,s as Pe,U as Te,W as H,f as c,y,h as k,c as $e,j as m,l as p,n as i,m as Ce,G as ee,X as he,Y as Be,D as Ie,Z as Oe,E as Ae,t as te,a as le,u as f,d as we,I as Me,p as qe,k as z,o as Le,V as Se}from"./index-DGnuRrBU.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 superuser <code>Authorization:TOKEN</code> header",m(l,"class","txt-hint txt-sm txt-right")},m(s,o){p(s,l,o)},d(s){s&&f(l)}}}function ye(a,l){let s,o,h;function r(){return l[5](l[6])}return{key:a,first:null,c(){s=c("button"),s.textContent=`${l[6].code} `,m(s,"class","tab-item"),z(s,"active",l[2]===l[6].code),this.first=s},m(n,d){p(n,s,d),o||(h=Le(s,"click",r),o=!0)},p(n,d){l=n,d&20&&z(s,"active",l[2]===l[6].code)},d(n){n&&f(s),o=!1,h()}}}function De(a,l){let s,o,h,r;return o=new Se({props:{content:l[6].body}}),{key:a,first:null,c(){s=c("div"),$e(o.$$.fragment),h=k(),m(s,"class","tab-item"),z(s,"active",l[2]===l[6].code),this.first=s},m(n,d){p(n,s,d),Ce(o,s,null),i(s,h),r=!0},p(n,d){l=n,(!r||d&20)&&z(s,"active",l[2]===l[6].code)},i(n){r||(te(o.$$.fragment,n),r=!0)},o(n){le(o.$$.fragment,n),r=!1},d(n){n&&f(s),we(o)}}}function Ue(a){var fe,me;let l,s,o=a[0].name+"",h,r,n,d,D,$,F,q=a[0].name+"",G,se,K,C,N,P,V,g,L,ae,S,E,oe,W,U=a[0].name+"",X,ne,Y,ie,Z,T,J,B,Q,I,x,w,O,v=[],ce=new Map,re,A,b=[],de=new Map,R;C=new Te({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${a[3]}');
...
await pb.collection('${(fe=a[0])==null?void 0:fe.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(),j=H(a[4]);const ue=e=>e[6].code;for(let e=0;e<j.length;e+=1){let t=ge(a,j,e),u=ue(t);ce.set(u,v[e]=ye(u,t))}let M=H(a[4]);const pe=e=>e[6].code;for(let e=0;e<M.length;e+=1){let t=ke(a,M,e),u=pe(t);de.set(u,b[e]=De(u,t))}return{c(){l=c("h3"),s=y("Delete ("),h=y(o),r=y(")"),n=k(),d=c("div"),D=c("p"),$=y("Delete a single "),F=c("strong"),G=y(q),se=y(" record."),K=k(),$e(C.$$.fragment),N=k(),P=c("h6"),P.textContent="API details",V=k(),g=c("div"),L=c("strong"),L.textContent="DELETE",ae=k(),S=c("div"),E=c("p"),oe=y("/api/collections/"),W=c("strong"),X=y(U),ne=y("/records/"),Y=c("strong"),Y.textContent=":id",ie=k(),_&&_.c(),Z=k(),T=c("div"),T.textContent="Path parameters",J=k(),B=c("table"),B.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>',Q=k(),I=c("div"),I.textContent="Responses",x=k(),w=c("div"),O=c("div");for(let e=0;e<v.length;e+=1)v[e].c();re=k(),A=c("div");for(let e=0;e<b.length;e+=1)b[e].c();m(l,"class","m-b-sm"),m(d,"class","content txt-lg m-b-sm"),m(P,"class","m-b-xs"),m(L,"class","label label-primary"),m(S,"class","content"),m(g,"class","alert alert-danger"),m(T,"class","section-title"),m(B,"class","table-compact table-border m-b-base"),m(I,"class","section-title"),m(O,"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,r),p(e,n,t),p(e,d,t),i(d,D),i(D,$),i(D,F),i(F,G),i(D,se),p(e,K,t),Ce(C,e,t),p(e,N,t),p(e,P,t),p(e,V,t),p(e,g,t),i(g,L),i(g,ae),i(g,S),i(S,E),i(E,oe),i(E,W),i(W,X),i(E,ne),i(E,Y),i(g,ie),_&&_.m(g,null),p(e,Z,t),p(e,T,t),p(e,J,t),p(e,B,t),p(e,Q,t),p(e,I,t),p(e,x,t),p(e,w,t),i(w,O);for(let u=0;u<v.length;u+=1)v[u]&&v[u].m(O,null);i(w,re),i(w,A);for(let u=0;u<b.length;u+=1)b[u]&&b[u].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)&&q!==(q=e[0].name+"")&&ee(G,q);const u={};t&9&&(u.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&&(u.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(u),(!R||t&1)&&U!==(U=e[0].name+"")&&ee(X,U),e[1]?_||(_=ve(),_.c(),_.m(g,null)):_&&(_.d(1),_=null),t&20&&(j=H(e[4]),v=he(v,t,ue,1,e,j,ce,O,Be,ye,null,ge)),t&20&&(M=H(e[4]),Ie(),b=he(b,t,pe,1,e,M,de,A,Oe,De,null,ke),Ae())},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&&(f(l),f(n),f(d),f(K),f(N),f(P),f(V),f(g),f(Z),f(T),f(J),f(B),f(Q),f(I),f(x),f(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 je(a,l,s){let o,h,{collection:r}=l,n=204,d=[];const D=$=>s(2,n=$.code);return a.$$set=$=>{"collection"in $&&s(0,r=$.collection)},a.$$.update=()=>{a.$$.dirty&1&&s(1,o=(r==null?void 0:r.deleteRule)===null),a.$$.dirty&3&&r!=null&&r.id&&(d.push({code:204,body:`
null
`}),d.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&&d.push({code:403,body:`
{
"code": 403,
"message": "Only superusers can access this action.",
"data": {}
}
`}),d.push({code:404,body:`
{
"code": 404,
"message": "The requested resource wasn't found.",
"data": {}
}
`}))},s(3,h=Me.getApiExampleUrl(qe.baseURL)),[r,o,n,h,d,D]}class ze extends Re{constructor(l){super(),Ee(this,l,je,Ue,Pe,{collection:0})}}export{ze as default};
-53
View File
@@ -1,53 +0,0 @@
import{S as Re,i as Ee,s as Pe,Q as Te,T 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,U as he,V as Be,k as Oe,W as Ie,n as Ae,t as te,a as le,o as f,d as we,C as Me,p as qe,r as z,u as Le,R as Se}from"./index-Co7n6kj7.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 superuser <code>Authorization:TOKEN</code> header",m(l,"class","txt-hint txt-sm txt-right")},m(s,o){p(s,l,o)},d(s){s&&f(l)}}}function ye(a,l){let s,o,h;function r(){return l[5](l[6])}return{key:a,first:null,c(){s=c("button"),s.textContent=`${l[6].code} `,m(s,"class","tab-item"),z(s,"active",l[2]===l[6].code),this.first=s},m(n,d){p(n,s,d),o||(h=Le(s,"click",r),o=!0)},p(n,d){l=n,d&20&&z(s,"active",l[2]===l[6].code)},d(n){n&&f(s),o=!1,h()}}}function $e(a,l){let s,o,h,r;return o=new Se({props:{content:l[6].body}}),{key:a,first:null,c(){s=c("div"),De(o.$$.fragment),h=k(),m(s,"class","tab-item"),z(s,"active",l[2]===l[6].code),this.first=s},m(n,d){p(n,s,d),Ce(o,s,null),i(s,h),r=!0},p(n,d){l=n,(!r||d&20)&&z(s,"active",l[2]===l[6].code)},i(n){r||(te(o.$$.fragment,n),r=!0)},o(n){le(o.$$.fragment,n),r=!1},d(n){n&&f(s),we(o)}}}function Ue(a){var fe,me;let l,s,o=a[0].name+"",h,r,n,d,$,D,F,q=a[0].name+"",K,se,N,C,Q,P,V,g,L,ae,S,E,oe,W,U=a[0].name+"",G,ne,J,ie,X,T,Y,B,Z,O,x,w,I,v=[],ce=new Map,re,A,b=[],de=new Map,R;C=new Te({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${a[3]}');
...
await pb.collection('${(fe=a[0])==null?void 0:fe.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(),H=j(a[4]);const ue=e=>e[6].code;for(let e=0;e<H.length;e+=1){let t=ge(a,H,e),u=ue(t);ce.set(u,v[e]=ye(u,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),u=pe(t);de.set(u,b[e]=$e(u,t))}return{c(){l=c("h3"),s=y("Delete ("),h=y(o),r=y(")"),n=k(),d=c("div"),$=c("p"),D=y("Delete a single "),F=c("strong"),K=y(q),se=y(" record."),N=k(),De(C.$$.fragment),Q=k(),P=c("h6"),P.textContent="API details",V=k(),g=c("div"),L=c("strong"),L.textContent="DELETE",ae=k(),S=c("div"),E=c("p"),oe=y("/api/collections/"),W=c("strong"),G=y(U),ne=y("/records/"),J=c("strong"),J.textContent=":id",ie=k(),_&&_.c(),X=k(),T=c("div"),T.textContent="Path parameters",Y=k(),B=c("table"),B.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(),O=c("div"),O.textContent="Responses",x=k(),w=c("div"),I=c("div");for(let e=0;e<v.length;e+=1)v[e].c();re=k(),A=c("div");for(let e=0;e<b.length;e+=1)b[e].c();m(l,"class","m-b-sm"),m(d,"class","content txt-lg m-b-sm"),m(P,"class","m-b-xs"),m(L,"class","label label-primary"),m(S,"class","content"),m(g,"class","alert alert-danger"),m(T,"class","section-title"),m(B,"class","table-compact table-border m-b-base"),m(O,"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,r),p(e,n,t),p(e,d,t),i(d,$),i($,D),i($,F),i(F,K),i($,se),p(e,N,t),Ce(C,e,t),p(e,Q,t),p(e,P,t),p(e,V,t),p(e,g,t),i(g,L),i(g,ae),i(g,S),i(S,E),i(E,oe),i(E,W),i(W,G),i(E,ne),i(E,J),i(g,ie),_&&_.m(g,null),p(e,X,t),p(e,T,t),p(e,Y,t),p(e,B,t),p(e,Z,t),p(e,O,t),p(e,x,t),p(e,w,t),i(w,I);for(let u=0;u<v.length;u+=1)v[u]&&v[u].m(I,null);i(w,re),i(w,A);for(let u=0;u<b.length;u+=1)b[u]&&b[u].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)&&q!==(q=e[0].name+"")&&ee(K,q);const u={};t&9&&(u.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&&(u.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(u),(!R||t&1)&&U!==(U=e[0].name+"")&&ee(G,U),e[1]?_||(_=ve(),_.c(),_.m(g,null)):_&&(_.d(1),_=null),t&20&&(H=j(e[4]),v=he(v,t,ue,1,e,H,ce,I,Be,ye,null,ge)),t&20&&(M=j(e[4]),Oe(),b=he(b,t,pe,1,e,M,de,A,Ie,$e,null,ke),Ae())},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&&(f(l),f(n),f(d),f(N),f(Q),f(P),f(V),f(g),f(X),f(T),f(Y),f(B),f(Z),f(O),f(x),f(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 He(a,l,s){let o,h,{collection:r}=l,n=204,d=[];const $=D=>s(2,n=D.code);return a.$$set=D=>{"collection"in D&&s(0,r=D.collection)},a.$$.update=()=>{a.$$.dirty&1&&s(1,o=(r==null?void 0:r.deleteRule)===null),a.$$.dirty&3&&r!=null&&r.id&&(d.push({code:204,body:`
null
`}),d.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&&d.push({code:403,body:`
{
"code": 403,
"message": "Only superusers can access this action.",
"data": {}
}
`}),d.push({code:404,body:`
{
"code": 404,
"message": "The requested resource wasn't found.",
"data": {}
}
`}))},s(3,h=Me.getApiExampleUrl(qe.baseURL)),[r,o,n,h,d,$]}class ze extends Re{constructor(l){super(),Ee(this,l,He,Ue,Pe,{collection:0})}}export{ze as default};
+120
View File
@@ -0,0 +1,120 @@
import{S as se,i as oe,s as ie,W as G,f as p,h as C,y as U,j as b,l as g,n as u,G as J,X as le,Y as Re,D as ne,Z as Se,E as ae,t as X,a as Z,u as v,k as K,o as ce,V as Oe,c as x,m as ee,d as te,U as Me,_ as _e,I as Be,p as De,$ as be}from"./index-DGnuRrBU.js";function ge(n,e,t){const l=n.slice();return l[4]=e[t],l}function ve(n,e,t){const l=n.slice();return l[4]=e[t],l}function ke(n,e){let t,l=e[4].code+"",d,i,r,a;function m(){return e[3](e[4])}return{key:n,first:null,c(){t=p("button"),d=U(l),i=C(),b(t,"class","tab-item"),K(t,"active",e[1]===e[4].code),this.first=t},m(k,A){g(k,t,A),u(t,d),u(t,i),r||(a=ce(t,"click",m),r=!0)},p(k,A){e=k,A&4&&l!==(l=e[4].code+"")&&J(d,l),A&6&&K(t,"active",e[1]===e[4].code)},d(k){k&&v(t),r=!1,a()}}}function $e(n,e){let t,l,d,i;return l=new Oe({props:{content:e[4].body}}),{key:n,first:null,c(){t=p("div"),x(l.$$.fragment),d=C(),b(t,"class","tab-item"),K(t,"active",e[1]===e[4].code),this.first=t},m(r,a){g(r,t,a),ee(l,t,null),u(t,d),i=!0},p(r,a){e=r;const m={};a&4&&(m.content=e[4].body),l.$set(m),(!i||a&6)&&K(t,"active",e[1]===e[4].code)},i(r){i||(X(l.$$.fragment,r),i=!0)},o(r){Z(l.$$.fragment,r),i=!1},d(r){r&&v(t),te(l)}}}function Ne(n){let e,t,l,d,i,r,a,m=n[0].name+"",k,A,Y,H,V,L,j,B,D,S,N,T=[],O=new Map,P,z,q=[],W=new Map,w,E=G(n[2]);const M=c=>c[4].code;for(let c=0;c<E.length;c+=1){let f=ve(n,E,c),s=M(f);O.set(s,T[c]=ke(s,f))}let _=G(n[2]);const F=c=>c[4].code;for(let c=0;c<_.length;c+=1){let f=ge(n,_,c),s=F(f);W.set(s,q[c]=$e(s,f))}return{c(){e=p("div"),t=p("strong"),t.textContent="POST",l=C(),d=p("div"),i=p("p"),r=U("/api/collections/"),a=p("strong"),k=U(m),A=U("/confirm-email-change"),Y=C(),H=p("div"),H.textContent="Body Parameters",V=C(),L=p("table"),L.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>',j=C(),B=p("div"),B.textContent="Responses",D=C(),S=p("div"),N=p("div");for(let c=0;c<T.length;c+=1)T[c].c();P=C(),z=p("div");for(let c=0;c<q.length;c+=1)q[c].c();b(t,"class","label label-primary"),b(d,"class","content"),b(e,"class","alert alert-success"),b(H,"class","section-title"),b(L,"class","table-compact table-border m-b-base"),b(B,"class","section-title"),b(N,"class","tabs-header compact combined left"),b(z,"class","tabs-content"),b(S,"class","tabs")},m(c,f){g(c,e,f),u(e,t),u(e,l),u(e,d),u(d,i),u(i,r),u(i,a),u(a,k),u(i,A),g(c,Y,f),g(c,H,f),g(c,V,f),g(c,L,f),g(c,j,f),g(c,B,f),g(c,D,f),g(c,S,f),u(S,N);for(let s=0;s<T.length;s+=1)T[s]&&T[s].m(N,null);u(S,P),u(S,z);for(let s=0;s<q.length;s+=1)q[s]&&q[s].m(z,null);w=!0},p(c,[f]){(!w||f&1)&&m!==(m=c[0].name+"")&&J(k,m),f&6&&(E=G(c[2]),T=le(T,f,M,1,c,E,O,N,Re,ke,null,ve)),f&6&&(_=G(c[2]),ne(),q=le(q,f,F,1,c,_,W,z,Se,$e,null,ge),ae())},i(c){if(!w){for(let f=0;f<_.length;f+=1)X(q[f]);w=!0}},o(c){for(let f=0;f<q.length;f+=1)Z(q[f]);w=!1},d(c){c&&(v(e),v(Y),v(H),v(V),v(L),v(j),v(B),v(D),v(S));for(let f=0;f<T.length;f+=1)T[f].d();for(let f=0;f<q.length;f+=1)q[f].d()}}}function We(n,e,t){let{collection:l}=e,d=204,i=[];const r=a=>t(1,d=a.code);return n.$$set=a=>{"collection"in a&&t(0,l=a.collection)},t(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "An error occurred while validating the submitted data.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[l,d,i,r]}class He extends se{constructor(e){super(),oe(this,e,We,Ne,ie,{collection:0})}}function we(n,e,t){const l=n.slice();return l[4]=e[t],l}function ye(n,e,t){const l=n.slice();return l[4]=e[t],l}function Ce(n,e){let t,l=e[4].code+"",d,i,r,a;function m(){return e[3](e[4])}return{key:n,first:null,c(){t=p("button"),d=U(l),i=C(),b(t,"class","tab-item"),K(t,"active",e[1]===e[4].code),this.first=t},m(k,A){g(k,t,A),u(t,d),u(t,i),r||(a=ce(t,"click",m),r=!0)},p(k,A){e=k,A&4&&l!==(l=e[4].code+"")&&J(d,l),A&6&&K(t,"active",e[1]===e[4].code)},d(k){k&&v(t),r=!1,a()}}}function Ee(n,e){let t,l,d,i;return l=new Oe({props:{content:e[4].body}}),{key:n,first:null,c(){t=p("div"),x(l.$$.fragment),d=C(),b(t,"class","tab-item"),K(t,"active",e[1]===e[4].code),this.first=t},m(r,a){g(r,t,a),ee(l,t,null),u(t,d),i=!0},p(r,a){e=r;const m={};a&4&&(m.content=e[4].body),l.$set(m),(!i||a&6)&&K(t,"active",e[1]===e[4].code)},i(r){i||(X(l.$$.fragment,r),i=!0)},o(r){Z(l.$$.fragment,r),i=!1},d(r){r&&v(t),te(l)}}}function Le(n){let e,t,l,d,i,r,a,m=n[0].name+"",k,A,Y,H,V,L,j,B,D,S,N,T,O,P=[],z=new Map,q,W,w=[],E=new Map,M,_=G(n[2]);const F=s=>s[4].code;for(let s=0;s<_.length;s+=1){let h=ye(n,_,s),R=F(h);z.set(R,P[s]=Ce(R,h))}let c=G(n[2]);const f=s=>s[4].code;for(let s=0;s<c.length;s+=1){let h=we(n,c,s),R=f(h);E.set(R,w[s]=Ee(R,h))}return{c(){e=p("div"),t=p("strong"),t.textContent="POST",l=C(),d=p("div"),i=p("p"),r=U("/api/collections/"),a=p("strong"),k=U(m),A=U("/request-email-change"),Y=C(),H=p("p"),H.innerHTML="Requires <code>Authorization:TOKEN</code>",V=C(),L=p("div"),L.textContent="Body Parameters",j=C(),B=p("table"),B.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>newEmail</span></div></td> <td><span class="label">String</span></td> <td>The new email address to send the change email request.</td></tr></tbody>',D=C(),S=p("div"),S.textContent="Responses",N=C(),T=p("div"),O=p("div");for(let s=0;s<P.length;s+=1)P[s].c();q=C(),W=p("div");for(let s=0;s<w.length;s+=1)w[s].c();b(t,"class","label label-primary"),b(d,"class","content"),b(H,"class","txt-hint txt-sm txt-right"),b(e,"class","alert alert-success"),b(L,"class","section-title"),b(B,"class","table-compact table-border m-b-base"),b(S,"class","section-title"),b(O,"class","tabs-header compact combined left"),b(W,"class","tabs-content"),b(T,"class","tabs")},m(s,h){g(s,e,h),u(e,t),u(e,l),u(e,d),u(d,i),u(i,r),u(i,a),u(a,k),u(i,A),u(e,Y),u(e,H),g(s,V,h),g(s,L,h),g(s,j,h),g(s,B,h),g(s,D,h),g(s,S,h),g(s,N,h),g(s,T,h),u(T,O);for(let R=0;R<P.length;R+=1)P[R]&&P[R].m(O,null);u(T,q),u(T,W);for(let R=0;R<w.length;R+=1)w[R]&&w[R].m(W,null);M=!0},p(s,[h]){(!M||h&1)&&m!==(m=s[0].name+"")&&J(k,m),h&6&&(_=G(s[2]),P=le(P,h,F,1,s,_,z,O,Re,Ce,null,ye)),h&6&&(c=G(s[2]),ne(),w=le(w,h,f,1,s,c,E,W,Se,Ee,null,we),ae())},i(s){if(!M){for(let h=0;h<c.length;h+=1)X(w[h]);M=!0}},o(s){for(let h=0;h<w.length;h+=1)Z(w[h]);M=!1},d(s){s&&(v(e),v(V),v(L),v(j),v(B),v(D),v(S),v(N),v(T));for(let h=0;h<P.length;h+=1)P[h].d();for(let h=0;h<w.length;h+=1)w[h].d()}}}function Ue(n,e,t){let{collection:l}=e,d=204,i=[];const r=a=>t(1,d=a.code);return n.$$set=a=>{"collection"in a&&t(0,l=a.collection)},t(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "An error occurred while validating the submitted data.",
"data": {
"newEmail": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`},{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": {}
}
`}]),[l,d,i,r]}class Ie extends se{constructor(e){super(),oe(this,e,Ue,Le,ie,{collection:0})}}function Te(n,e,t){const l=n.slice();return l[5]=e[t],l[7]=t,l}function qe(n,e,t){const l=n.slice();return l[5]=e[t],l[7]=t,l}function Ae(n){let e,t,l,d,i;function r(){return n[4](n[7])}return{c(){e=p("button"),t=p("div"),t.textContent=`${n[5].title}`,l=C(),b(t,"class","txt"),b(e,"class","tab-item"),K(e,"active",n[1]==n[7])},m(a,m){g(a,e,m),u(e,t),u(e,l),d||(i=ce(e,"click",r),d=!0)},p(a,m){n=a,m&2&&K(e,"active",n[1]==n[7])},d(a){a&&v(e),d=!1,i()}}}function Pe(n){let e,t,l,d;var i=n[5].component;function r(a,m){return{props:{collection:a[0]}}}return i&&(t=be(i,r(n))),{c(){e=p("div"),t&&x(t.$$.fragment),l=C(),b(e,"class","tab-item"),K(e,"active",n[1]==n[7])},m(a,m){g(a,e,m),t&&ee(t,e,null),u(e,l),d=!0},p(a,m){if(i!==(i=a[5].component)){if(t){ne();const k=t;Z(k.$$.fragment,1,0,()=>{te(k,1)}),ae()}i?(t=be(i,r(a)),x(t.$$.fragment),X(t.$$.fragment,1),ee(t,e,l)):t=null}else if(i){const k={};m&1&&(k.collection=a[0]),t.$set(k)}(!d||m&2)&&K(e,"active",a[1]==a[7])},i(a){d||(t&&X(t.$$.fragment,a),d=!0)},o(a){t&&Z(t.$$.fragment,a),d=!1},d(a){a&&v(e),t&&te(t)}}}function Ge(n){var c,f,s,h,R,re;let e,t,l=n[0].name+"",d,i,r,a,m,k,A,Y=n[0].name+"",H,V,L,j,B,D,S,N,T,O,P,z,q,W;D=new Me({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[2]}');
...
await pb.collection('${(c=n[0])==null?void 0:c.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(f=n[0])==null?void 0:f.name}').requestEmailChange('new@example.com');
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(s=n[0])==null?void 0:s.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[2]}');
...
await pb.collection('${(h=n[0])==null?void 0:h.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(R=n[0])==null?void 0:R.name}').requestEmailChange('new@example.com');
...
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(re=n[0])==null?void 0:re.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`}});let w=G(n[3]),E=[];for(let o=0;o<w.length;o+=1)E[o]=Ae(qe(n,w,o));let M=G(n[3]),_=[];for(let o=0;o<M.length;o+=1)_[o]=Pe(Te(n,M,o));const F=o=>Z(_[o],1,1,()=>{_[o]=null});return{c(){e=p("h3"),t=U("Email change ("),d=U(l),i=U(")"),r=C(),a=p("div"),m=p("p"),k=U("Sends "),A=p("strong"),H=U(Y),V=U(" email change request."),L=C(),j=p("p"),j.textContent=`On successful email change all previously issued auth tokens for the specific record will be
automatically invalidated.`,B=C(),x(D.$$.fragment),S=C(),N=p("h6"),N.textContent="API details",T=C(),O=p("div"),P=p("div");for(let o=0;o<E.length;o+=1)E[o].c();z=C(),q=p("div");for(let o=0;o<_.length;o+=1)_[o].c();b(e,"class","m-b-sm"),b(a,"class","content txt-lg m-b-sm"),b(N,"class","m-b-xs"),b(P,"class","tabs-header compact"),b(q,"class","tabs-content"),b(O,"class","tabs")},m(o,y){g(o,e,y),u(e,t),u(e,d),u(e,i),g(o,r,y),g(o,a,y),u(a,m),u(m,k),u(m,A),u(A,H),u(m,V),u(a,L),u(a,j),g(o,B,y),ee(D,o,y),g(o,S,y),g(o,N,y),g(o,T,y),g(o,O,y),u(O,P);for(let I=0;I<E.length;I+=1)E[I]&&E[I].m(P,null);u(O,z),u(O,q);for(let I=0;I<_.length;I+=1)_[I]&&_[I].m(q,null);W=!0},p(o,[y]){var de,ue,fe,me,he,pe;(!W||y&1)&&l!==(l=o[0].name+"")&&J(d,l),(!W||y&1)&&Y!==(Y=o[0].name+"")&&J(H,Y);const I={};if(y&5&&(I.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[2]}');
...
await pb.collection('${(de=o[0])==null?void 0:de.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(ue=o[0])==null?void 0:ue.name}').requestEmailChange('new@example.com');
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(fe=o[0])==null?void 0:fe.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`),y&5&&(I.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[2]}');
...
await pb.collection('${(me=o[0])==null?void 0:me.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(he=o[0])==null?void 0:he.name}').requestEmailChange('new@example.com');
...
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(pe=o[0])==null?void 0:pe.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`),D.$set(I),y&10){w=G(o[3]);let $;for($=0;$<w.length;$+=1){const Q=qe(o,w,$);E[$]?E[$].p(Q,y):(E[$]=Ae(Q),E[$].c(),E[$].m(P,null))}for(;$<E.length;$+=1)E[$].d(1);E.length=w.length}if(y&11){M=G(o[3]);let $;for($=0;$<M.length;$+=1){const Q=Te(o,M,$);_[$]?(_[$].p(Q,y),X(_[$],1)):(_[$]=Pe(Q),_[$].c(),X(_[$],1),_[$].m(q,null))}for(ne(),$=M.length;$<_.length;$+=1)F($);ae()}},i(o){if(!W){X(D.$$.fragment,o);for(let y=0;y<M.length;y+=1)X(_[y]);W=!0}},o(o){Z(D.$$.fragment,o),_=_.filter(Boolean);for(let y=0;y<_.length;y+=1)Z(_[y]);W=!1},d(o){o&&(v(e),v(r),v(a),v(B),v(S),v(N),v(T),v(O)),te(D,o),_e(E,o),_e(_,o)}}}function Ke(n,e,t){let l,{collection:d}=e;const i=[{title:"Request email change",component:Ie},{title:"Confirm email change",component:He}];let r=0;const a=m=>t(1,r=m);return n.$$set=m=>{"collection"in m&&t(0,d=m.collection)},t(2,l=Be.getApiExampleUrl(De.baseURL)),[d,r,l,i,a]}class je extends se{constructor(e){super(),oe(this,e,Ke,Ge,ie,{collection:0})}}export{je as default};
-120
View File
@@ -1,120 +0,0 @@
import{S as se,i as oe,s as ie,T as K,e as p,b as y,w as U,f as b,g,h as u,x as J,U as le,V as Re,k as ne,W as Se,n as ae,t as V,a as X,o as v,r as Y,u as ce,R as Oe,c as x,m as ee,d as te,Q as Me,X as _e,C as Be,p as De,Y as be}from"./index-Co7n6kj7.js";function ge(n,e,t){const l=n.slice();return l[4]=e[t],l}function ve(n,e,t){const l=n.slice();return l[4]=e[t],l}function ke(n,e){let t,l=e[4].code+"",d,i,r,a;function m(){return e[3](e[4])}return{key:n,first:null,c(){t=p("button"),d=U(l),i=y(),b(t,"class","tab-item"),Y(t,"active",e[1]===e[4].code),this.first=t},m(k,A){g(k,t,A),u(t,d),u(t,i),r||(a=ce(t,"click",m),r=!0)},p(k,A){e=k,A&4&&l!==(l=e[4].code+"")&&J(d,l),A&6&&Y(t,"active",e[1]===e[4].code)},d(k){k&&v(t),r=!1,a()}}}function $e(n,e){let t,l,d,i;return l=new Oe({props:{content:e[4].body}}),{key:n,first:null,c(){t=p("div"),x(l.$$.fragment),d=y(),b(t,"class","tab-item"),Y(t,"active",e[1]===e[4].code),this.first=t},m(r,a){g(r,t,a),ee(l,t,null),u(t,d),i=!0},p(r,a){e=r;const m={};a&4&&(m.content=e[4].body),l.$set(m),(!i||a&6)&&Y(t,"active",e[1]===e[4].code)},i(r){i||(V(l.$$.fragment,r),i=!0)},o(r){X(l.$$.fragment,r),i=!1},d(r){r&&v(t),te(l)}}}function Ne(n){let e,t,l,d,i,r,a,m=n[0].name+"",k,A,G,H,Q,L,z,B,D,S,N,T=[],O=new Map,P,j,q=[],W=new Map,w,E=K(n[2]);const M=c=>c[4].code;for(let c=0;c<E.length;c+=1){let f=ve(n,E,c),s=M(f);O.set(s,T[c]=ke(s,f))}let _=K(n[2]);const F=c=>c[4].code;for(let c=0;c<_.length;c+=1){let f=ge(n,_,c),s=F(f);W.set(s,q[c]=$e(s,f))}return{c(){e=p("div"),t=p("strong"),t.textContent="POST",l=y(),d=p("div"),i=p("p"),r=U("/api/collections/"),a=p("strong"),k=U(m),A=U("/confirm-email-change"),G=y(),H=p("div"),H.textContent="Body Parameters",Q=y(),L=p("table"),L.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>',z=y(),B=p("div"),B.textContent="Responses",D=y(),S=p("div"),N=p("div");for(let c=0;c<T.length;c+=1)T[c].c();P=y(),j=p("div");for(let c=0;c<q.length;c+=1)q[c].c();b(t,"class","label label-primary"),b(d,"class","content"),b(e,"class","alert alert-success"),b(H,"class","section-title"),b(L,"class","table-compact table-border m-b-base"),b(B,"class","section-title"),b(N,"class","tabs-header compact combined left"),b(j,"class","tabs-content"),b(S,"class","tabs")},m(c,f){g(c,e,f),u(e,t),u(e,l),u(e,d),u(d,i),u(i,r),u(i,a),u(a,k),u(i,A),g(c,G,f),g(c,H,f),g(c,Q,f),g(c,L,f),g(c,z,f),g(c,B,f),g(c,D,f),g(c,S,f),u(S,N);for(let s=0;s<T.length;s+=1)T[s]&&T[s].m(N,null);u(S,P),u(S,j);for(let s=0;s<q.length;s+=1)q[s]&&q[s].m(j,null);w=!0},p(c,[f]){(!w||f&1)&&m!==(m=c[0].name+"")&&J(k,m),f&6&&(E=K(c[2]),T=le(T,f,M,1,c,E,O,N,Re,ke,null,ve)),f&6&&(_=K(c[2]),ne(),q=le(q,f,F,1,c,_,W,j,Se,$e,null,ge),ae())},i(c){if(!w){for(let f=0;f<_.length;f+=1)V(q[f]);w=!0}},o(c){for(let f=0;f<q.length;f+=1)X(q[f]);w=!1},d(c){c&&(v(e),v(G),v(H),v(Q),v(L),v(z),v(B),v(D),v(S));for(let f=0;f<T.length;f+=1)T[f].d();for(let f=0;f<q.length;f+=1)q[f].d()}}}function We(n,e,t){let{collection:l}=e,d=204,i=[];const r=a=>t(1,d=a.code);return n.$$set=a=>{"collection"in a&&t(0,l=a.collection)},t(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "An error occurred while validating the submitted data.",
"data": {
"token": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`}]),[l,d,i,r]}class He extends se{constructor(e){super(),oe(this,e,We,Ne,ie,{collection:0})}}function we(n,e,t){const l=n.slice();return l[4]=e[t],l}function Ce(n,e,t){const l=n.slice();return l[4]=e[t],l}function ye(n,e){let t,l=e[4].code+"",d,i,r,a;function m(){return e[3](e[4])}return{key:n,first:null,c(){t=p("button"),d=U(l),i=y(),b(t,"class","tab-item"),Y(t,"active",e[1]===e[4].code),this.first=t},m(k,A){g(k,t,A),u(t,d),u(t,i),r||(a=ce(t,"click",m),r=!0)},p(k,A){e=k,A&4&&l!==(l=e[4].code+"")&&J(d,l),A&6&&Y(t,"active",e[1]===e[4].code)},d(k){k&&v(t),r=!1,a()}}}function Ee(n,e){let t,l,d,i;return l=new Oe({props:{content:e[4].body}}),{key:n,first:null,c(){t=p("div"),x(l.$$.fragment),d=y(),b(t,"class","tab-item"),Y(t,"active",e[1]===e[4].code),this.first=t},m(r,a){g(r,t,a),ee(l,t,null),u(t,d),i=!0},p(r,a){e=r;const m={};a&4&&(m.content=e[4].body),l.$set(m),(!i||a&6)&&Y(t,"active",e[1]===e[4].code)},i(r){i||(V(l.$$.fragment,r),i=!0)},o(r){X(l.$$.fragment,r),i=!1},d(r){r&&v(t),te(l)}}}function Le(n){let e,t,l,d,i,r,a,m=n[0].name+"",k,A,G,H,Q,L,z,B,D,S,N,T,O,P=[],j=new Map,q,W,w=[],E=new Map,M,_=K(n[2]);const F=s=>s[4].code;for(let s=0;s<_.length;s+=1){let h=Ce(n,_,s),R=F(h);j.set(R,P[s]=ye(R,h))}let c=K(n[2]);const f=s=>s[4].code;for(let s=0;s<c.length;s+=1){let h=we(n,c,s),R=f(h);E.set(R,w[s]=Ee(R,h))}return{c(){e=p("div"),t=p("strong"),t.textContent="POST",l=y(),d=p("div"),i=p("p"),r=U("/api/collections/"),a=p("strong"),k=U(m),A=U("/request-email-change"),G=y(),H=p("p"),H.innerHTML="Requires <code>Authorization:TOKEN</code>",Q=y(),L=p("div"),L.textContent="Body Parameters",z=y(),B=p("table"),B.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>newEmail</span></div></td> <td><span class="label">String</span></td> <td>The new email address to send the change email request.</td></tr></tbody>',D=y(),S=p("div"),S.textContent="Responses",N=y(),T=p("div"),O=p("div");for(let s=0;s<P.length;s+=1)P[s].c();q=y(),W=p("div");for(let s=0;s<w.length;s+=1)w[s].c();b(t,"class","label label-primary"),b(d,"class","content"),b(H,"class","txt-hint txt-sm txt-right"),b(e,"class","alert alert-success"),b(L,"class","section-title"),b(B,"class","table-compact table-border m-b-base"),b(S,"class","section-title"),b(O,"class","tabs-header compact combined left"),b(W,"class","tabs-content"),b(T,"class","tabs")},m(s,h){g(s,e,h),u(e,t),u(e,l),u(e,d),u(d,i),u(i,r),u(i,a),u(a,k),u(i,A),u(e,G),u(e,H),g(s,Q,h),g(s,L,h),g(s,z,h),g(s,B,h),g(s,D,h),g(s,S,h),g(s,N,h),g(s,T,h),u(T,O);for(let R=0;R<P.length;R+=1)P[R]&&P[R].m(O,null);u(T,q),u(T,W);for(let R=0;R<w.length;R+=1)w[R]&&w[R].m(W,null);M=!0},p(s,[h]){(!M||h&1)&&m!==(m=s[0].name+"")&&J(k,m),h&6&&(_=K(s[2]),P=le(P,h,F,1,s,_,j,O,Re,ye,null,Ce)),h&6&&(c=K(s[2]),ne(),w=le(w,h,f,1,s,c,E,W,Se,Ee,null,we),ae())},i(s){if(!M){for(let h=0;h<c.length;h+=1)V(w[h]);M=!0}},o(s){for(let h=0;h<w.length;h+=1)X(w[h]);M=!1},d(s){s&&(v(e),v(Q),v(L),v(z),v(B),v(D),v(S),v(N),v(T));for(let h=0;h<P.length;h+=1)P[h].d();for(let h=0;h<w.length;h+=1)w[h].d()}}}function Ue(n,e,t){let{collection:l}=e,d=204,i=[];const r=a=>t(1,d=a.code);return n.$$set=a=>{"collection"in a&&t(0,l=a.collection)},t(2,i=[{code:204,body:"null"},{code:400,body:`
{
"code": 400,
"message": "An error occurred while validating the submitted data.",
"data": {
"newEmail": {
"code": "validation_required",
"message": "Missing required value."
}
}
}
`},{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": {}
}
`}]),[l,d,i,r]}class Ie extends se{constructor(e){super(),oe(this,e,Ue,Le,ie,{collection:0})}}function Te(n,e,t){const l=n.slice();return l[5]=e[t],l[7]=t,l}function qe(n,e,t){const l=n.slice();return l[5]=e[t],l[7]=t,l}function Ae(n){let e,t,l,d,i;function r(){return n[4](n[7])}return{c(){e=p("button"),t=p("div"),t.textContent=`${n[5].title}`,l=y(),b(t,"class","txt"),b(e,"class","tab-item"),Y(e,"active",n[1]==n[7])},m(a,m){g(a,e,m),u(e,t),u(e,l),d||(i=ce(e,"click",r),d=!0)},p(a,m){n=a,m&2&&Y(e,"active",n[1]==n[7])},d(a){a&&v(e),d=!1,i()}}}function Pe(n){let e,t,l,d;var i=n[5].component;function r(a,m){return{props:{collection:a[0]}}}return i&&(t=be(i,r(n))),{c(){e=p("div"),t&&x(t.$$.fragment),l=y(),b(e,"class","tab-item"),Y(e,"active",n[1]==n[7])},m(a,m){g(a,e,m),t&&ee(t,e,null),u(e,l),d=!0},p(a,m){if(i!==(i=a[5].component)){if(t){ne();const k=t;X(k.$$.fragment,1,0,()=>{te(k,1)}),ae()}i?(t=be(i,r(a)),x(t.$$.fragment),V(t.$$.fragment,1),ee(t,e,l)):t=null}else if(i){const k={};m&1&&(k.collection=a[0]),t.$set(k)}(!d||m&2)&&Y(e,"active",a[1]==a[7])},i(a){d||(t&&V(t.$$.fragment,a),d=!0)},o(a){t&&X(t.$$.fragment,a),d=!1},d(a){a&&v(e),t&&te(t)}}}function Ke(n){var c,f,s,h,R,re;let e,t,l=n[0].name+"",d,i,r,a,m,k,A,G=n[0].name+"",H,Q,L,z,B,D,S,N,T,O,P,j,q,W;D=new Me({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${n[2]}');
...
await pb.collection('${(c=n[0])==null?void 0:c.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(f=n[0])==null?void 0:f.name}').requestEmailChange('new@example.com');
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(s=n[0])==null?void 0:s.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`,dart:`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${n[2]}');
...
await pb.collection('${(h=n[0])==null?void 0:h.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(R=n[0])==null?void 0:R.name}').requestEmailChange('new@example.com');
...
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(re=n[0])==null?void 0:re.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`}});let w=K(n[3]),E=[];for(let o=0;o<w.length;o+=1)E[o]=Ae(qe(n,w,o));let M=K(n[3]),_=[];for(let o=0;o<M.length;o+=1)_[o]=Pe(Te(n,M,o));const F=o=>X(_[o],1,1,()=>{_[o]=null});return{c(){e=p("h3"),t=U("Email change ("),d=U(l),i=U(")"),r=y(),a=p("div"),m=p("p"),k=U("Sends "),A=p("strong"),H=U(G),Q=U(" email change request."),L=y(),z=p("p"),z.textContent=`On successful email change all previously issued auth tokens for the specific record will be
automatically invalidated.`,B=y(),x(D.$$.fragment),S=y(),N=p("h6"),N.textContent="API details",T=y(),O=p("div"),P=p("div");for(let o=0;o<E.length;o+=1)E[o].c();j=y(),q=p("div");for(let o=0;o<_.length;o+=1)_[o].c();b(e,"class","m-b-sm"),b(a,"class","content txt-lg m-b-sm"),b(N,"class","m-b-xs"),b(P,"class","tabs-header compact"),b(q,"class","tabs-content"),b(O,"class","tabs")},m(o,C){g(o,e,C),u(e,t),u(e,d),u(e,i),g(o,r,C),g(o,a,C),u(a,m),u(m,k),u(m,A),u(A,H),u(m,Q),u(a,L),u(a,z),g(o,B,C),ee(D,o,C),g(o,S,C),g(o,N,C),g(o,T,C),g(o,O,C),u(O,P);for(let I=0;I<E.length;I+=1)E[I]&&E[I].m(P,null);u(O,j),u(O,q);for(let I=0;I<_.length;I+=1)_[I]&&_[I].m(q,null);W=!0},p(o,[C]){var de,ue,fe,me,he,pe;(!W||C&1)&&l!==(l=o[0].name+"")&&J(d,l),(!W||C&1)&&G!==(G=o[0].name+"")&&J(H,G);const I={};if(C&5&&(I.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${o[2]}');
...
await pb.collection('${(de=o[0])==null?void 0:de.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(ue=o[0])==null?void 0:ue.name}').requestEmailChange('new@example.com');
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(fe=o[0])==null?void 0:fe.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`),C&5&&(I.dart=`
import 'package:pocketbase/pocketbase.dart';
final pb = PocketBase('${o[2]}');
...
await pb.collection('${(me=o[0])==null?void 0:me.name}').authWithPassword('test@example.com', '1234567890');
await pb.collection('${(he=o[0])==null?void 0:he.name}').requestEmailChange('new@example.com');
...
// ---
// (optional) in your custom confirmation page:
// ---
// note: after this call all previously issued auth tokens are invalidated
await pb.collection('${(pe=o[0])==null?void 0:pe.name}').confirmEmailChange(
'EMAIL_CHANGE_TOKEN',
'YOUR_PASSWORD',
);
`),D.$set(I),C&10){w=K(o[3]);let $;for($=0;$<w.length;$+=1){const Z=qe(o,w,$);E[$]?E[$].p(Z,C):(E[$]=Ae(Z),E[$].c(),E[$].m(P,null))}for(;$<E.length;$+=1)E[$].d(1);E.length=w.length}if(C&11){M=K(o[3]);let $;for($=0;$<M.length;$+=1){const Z=Te(o,M,$);_[$]?(_[$].p(Z,C),V(_[$],1)):(_[$]=Pe(Z),_[$].c(),V(_[$],1),_[$].m(q,null))}for(ne(),$=M.length;$<_.length;$+=1)F($);ae()}},i(o){if(!W){V(D.$$.fragment,o);for(let C=0;C<M.length;C+=1)V(_[C]);W=!0}},o(o){X(D.$$.fragment,o),_=_.filter(Boolean);for(let C=0;C<_.length;C+=1)X(_[C]);W=!1},d(o){o&&(v(e),v(r),v(a),v(B),v(S),v(N),v(T),v(O)),te(D,o),_e(E,o),_e(_,o)}}}function Ye(n,e,t){let l,{collection:d}=e;const i=[{title:"Request email change",component:Ie},{title:"Confirm email change",component:He}];let r=0;const a=m=>t(1,r=m);return n.$$set=m=>{"collection"in m&&t(0,d=m.collection)},t(2,l=Be.getApiExampleUrl(De.baseURL)),[d,r,l,i,a]}class ze extends se{constructor(e){super(),oe(this,e,Ye,Ke,ie,{collection:0})}}export{ze as default};
-7
View File
@@ -1,7 +0,0 @@
import{S as J,i as N,s as O,R as P,e as t,b as c,w as i,c as Q,f as j,g as z,h as e,m as A,x as D,t as G,a as K,o as U,d as V}from"./index-Co7n6kj7.js";function W(f){let n,o,u,d,v,s,p,w,h,y,r,F,_,S,b,E,C,a,$,L,q,H,M,R,m,T,k,B,x;return r=new P({props:{content:"?fields=*,"+f[0]+"expand.relField.name"}}),{c(){n=t("tr"),o=t("td"),o.textContent="fields",u=c(),d=t("td"),d.innerHTML='<span class="label">String</span>',v=c(),s=t("td"),p=t("p"),w=i(`Comma separated string of the fields to return in the JSON response
`),h=t("em"),h.textContent="(by default returns all fields)",y=i(`. Ex.:
`),Q(r.$$.fragment),F=c(),_=t("p"),_.innerHTML="<code>*</code> targets all keys from the specific depth level.",S=c(),b=t("p"),b.textContent="In addition, the following field modifiers are also supported:",E=c(),C=t("ul"),a=t("li"),$=t("code"),$.textContent=":excerpt(maxLength, withEllipsis?)",L=c(),q=t("br"),H=i(`
Returns a short plain text version of the field string value.
`),M=t("br"),R=i(`
Ex.:
`),m=t("code"),T=i("?fields=*,"),k=i(f[0]),B=i("description:excerpt(200,true)"),j(o,"id","query-page")},m(l,g){z(l,n,g),e(n,o),e(n,u),e(n,d),e(n,v),e(n,s),e(s,p),e(p,w),e(p,h),e(p,y),A(r,p,null),e(s,F),e(s,_),e(s,S),e(s,b),e(s,E),e(s,C),e(C,a),e(a,$),e(a,L),e(a,q),e(a,H),e(a,M),e(a,R),e(a,m),e(m,T),e(m,k),e(m,B),x=!0},p(l,[g]){const I={};g&1&&(I.content="?fields=*,"+l[0]+"expand.relField.name"),r.$set(I),(!x||g&1)&&D(k,l[0])},i(l){x||(G(r.$$.fragment,l),x=!0)},o(l){K(r.$$.fragment,l),x=!1},d(l){l&&U(n),V(r)}}}function X(f,n,o){let{prefix:u=""}=n;return f.$$set=d=>{"prefix"in d&&o(0,u=d.prefix)},[u]}class Z extends J{constructor(n){super(),N(this,n,X,W,O,{prefix:0})}}export{Z as F};
+7
View File
@@ -0,0 +1,7 @@
import{S as I,i as J,s as N,V as O,f as t,h as c,y as i,c as P,j as Q,l as R,n as e,m as V,G as z,t as A,a as D,u as K,d as U}from"./index-DGnuRrBU.js";function W(f){let n,o,u,d,k,s,p,v,g,F,r,S,_,w,b,E,C,a,$,L,q,H,M,T,m,j,y,B,x;return r=new O({props:{content:"?fields=*,"+f[0]+"expand.relField.name"}}),{c(){n=t("tr"),o=t("td"),o.textContent="fields",u=c(),d=t("td"),d.innerHTML='<span class="label">String</span>',k=c(),s=t("td"),p=t("p"),v=i(`Comma separated string of the fields to return in the JSON response
`),g=t("em"),g.textContent="(by default returns all fields)",F=i(`. Ex.:
`),P(r.$$.fragment),S=c(),_=t("p"),_.innerHTML="<code>*</code> targets all keys from the specific depth level.",w=c(),b=t("p"),b.textContent="In addition, the following field modifiers are also supported:",E=c(),C=t("ul"),a=t("li"),$=t("code"),$.textContent=":excerpt(maxLength, withEllipsis?)",L=c(),q=t("br"),H=i(`
Returns a short plain text version of the field string value.
`),M=t("br"),T=i(`
Ex.:
`),m=t("code"),j=i("?fields=*,"),y=i(f[0]),B=i("description:excerpt(200,true)"),Q(o,"id","query-page")},m(l,h){R(l,n,h),e(n,o),e(n,u),e(n,d),e(n,k),e(n,s),e(s,p),e(p,v),e(p,g),e(p,F),V(r,p,null),e(s,S),e(s,_),e(s,w),e(s,b),e(s,E),e(s,C),e(C,a),e(a,$),e(a,L),e(a,q),e(a,H),e(a,M),e(a,T),e(a,m),e(m,j),e(m,y),e(m,B),x=!0},p(l,[h]){const G={};h&1&&(G.content="?fields=*,"+l[0]+"expand.relField.name"),r.$set(G),(!x||h&1)&&z(y,l[0])},i(l){x||(A(r.$$.fragment,l),x=!0)},o(l){D(r.$$.fragment,l),x=!1},d(l){l&&K(n),U(r)}}}function X(f,n,o){let{prefix:u=""}=n;return f.$$set=d=>{"prefix"in d&&o(0,u=d.prefix)},[u]}class Z extends I{constructor(n){super(),J(this,n,X,W,N,{prefix:0})}}export{Z as F};
File diff suppressed because one or more lines are too long
@@ -1,12 +1,12 @@
import{S as Ze,i as tl,s as el,e,b as s,E as sl,f as a,g as m,u as ll,y as Ue,o as h,w as g,h as t,Q as nl,R as ve,T as se,c as Ut,m as jt,x as ke,U as je,V as ol,k as al,W as il,n as rl,t as $t,a as Ct,d as Qt,X as cl,C as Le,p as dl,r as Fe}from"./index-Co7n6kj7.js";import{F as pl}from"./FieldsQueryParam-DH-ZC4qv.js";function fl(r){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,b){m(f,n,b),m(f,o,b),m(f,i,b)},d(f){f&&(h(n),h(o),h(i))}}}function ul(r){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,b){m(f,n,b),m(f,o,b),m(f,i,b)},d(f){f&&(h(n),h(o),h(i))}}}function Qe(r){let n,o,i,f,b,p,u,C,_,$,d,tt,kt,zt,S,Kt,H,rt,R,et,ne,U,j,oe,ct,yt,lt,vt,ae,dt,pt,st,N,Jt,Ft,y,nt,Lt,Vt,At,Q,ot,Tt,Wt,Pt,F,ft,Rt,ie,ut,re,M,Ot,at,Et,O,mt,ce,z,St,Xt,Nt,de,q,Yt,K,ht,pe,I,fe,B,ue,P,qt,J,bt,me,gt,he,x,Dt,it,Ht,be,Mt,Zt,V,_t,ge,It,_e,wt,we,W,G,xe,xt,te,X,ee,L,Y,E,Bt,$e,Z,v,Gt;return{c(){n=e("p"),n.innerHTML=`The syntax basically follows the format
import{S as Ze,i as tl,s as el,f as e,h as s,K as sl,j as a,l as m,o as ll,H as je,u as h,y as g,n as t,U as nl,V as ve,W as se,c as jt,m as Ut,G as ke,X as Ue,Y as ol,D as al,Z as il,E as rl,t as $t,a as Ct,d as Kt,_ as cl,I as Le,p as dl,k as Fe}from"./index-DGnuRrBU.js";import{F as pl}from"./FieldsQueryParam-DeLgGM_S.js";function fl(r){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,b){m(f,n,b),m(f,o,b),m(f,i,b)},d(f){f&&(h(n),h(o),h(i))}}}function ul(r){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,b){m(f,n,b),m(f,o,b),m(f,i,b)},d(f){f&&(h(n),h(o),h(i))}}}function Ke(r){let n,o,i,f,b,p,u,C,_,$,d,tt,kt,zt,S,Qt,H,rt,R,et,ne,j,U,oe,ct,yt,lt,vt,ae,dt,pt,st,N,Jt,Ft,y,nt,Lt,Vt,At,K,ot,Tt,Wt,Pt,F,ft,Rt,ie,ut,re,M,Ot,at,Et,O,mt,ce,z,St,Xt,Nt,de,q,Yt,Q,ht,pe,I,fe,B,ue,P,qt,J,bt,me,gt,he,x,Dt,it,Ht,be,Mt,Zt,V,_t,ge,It,_e,wt,we,W,G,xe,xt,te,X,ee,L,Y,E,Bt,$e,Z,v,Gt;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`,b=s(),p=e("li"),u=e("code"),u.textContent="OPERATOR",C=g(` - is one of:
`),_=e("br"),$=s(),d=e("ul"),tt=e("li"),kt=e("code"),kt.textContent="=",zt=s(),S=e("span"),S.textContent="Equal",Kt=s(),H=e("li"),rt=e("code"),rt.textContent="!=",R=s(),et=e("span"),et.textContent="NOT equal",ne=s(),U=e("li"),j=e("code"),j.textContent=">",oe=s(),ct=e("span"),ct.textContent="Greater than",yt=s(),lt=e("li"),vt=e("code"),vt.textContent=">=",ae=s(),dt=e("span"),dt.textContent="Greater than or equal",pt=s(),st=e("li"),N=e("code"),N.textContent="<",Jt=s(),Ft=e("span"),Ft.textContent="Less than",y=s(),nt=e("li"),Lt=e("code"),Lt.textContent="<=",Vt=s(),At=e("span"),At.textContent="Less than or equal",Q=s(),ot=e("li"),Tt=e("code"),Tt.textContent="~",Wt=s(),Pt=e("span"),Pt.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
`),_=e("br"),$=s(),d=e("ul"),tt=e("li"),kt=e("code"),kt.textContent="=",zt=s(),S=e("span"),S.textContent="Equal",Qt=s(),H=e("li"),rt=e("code"),rt.textContent="!=",R=s(),et=e("span"),et.textContent="NOT equal",ne=s(),j=e("li"),U=e("code"),U.textContent=">",oe=s(),ct=e("span"),ct.textContent="Greater than",yt=s(),lt=e("li"),vt=e("code"),vt.textContent=">=",ae=s(),dt=e("span"),dt.textContent="Greater than or equal",pt=s(),st=e("li"),N=e("code"),N.textContent="<",Jt=s(),Ft=e("span"),Ft.textContent="Less than",y=s(),nt=e("li"),Lt=e("code"),Lt.textContent="<=",Vt=s(),At=e("span"),At.textContent="Less than or equal",K=s(),ot=e("li"),Tt=e("code"),Tt.textContent="~",Wt=s(),Pt=e("span"),Pt.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,F=s(),ft=e("li"),Rt=e("code"),Rt.textContent="!~",ie=s(),ut=e("span"),ut.textContent=`NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,re=s(),M=e("li"),Ot=e("code"),Ot.textContent="?=",at=s(),Et=e("em"),Et.textContent="Any/At least one of",O=s(),mt=e("span"),mt.textContent="Equal",ce=s(),z=e("li"),St=e("code"),St.textContent="?!=",Xt=s(),Nt=e("em"),Nt.textContent="Any/At least one of",de=s(),q=e("span"),q.textContent="NOT equal",Yt=s(),K=e("li"),ht=e("code"),ht.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"),qt=e("code"),qt.textContent="?>=",J=s(),bt=e("em"),bt.textContent="Any/At least one of",me=s(),gt=e("span"),gt.textContent="Greater than or equal",he=s(),x=e("li"),Dt=e("code"),Dt.textContent="?<",it=s(),Ht=e("em"),Ht.textContent="Any/At least one of",be=s(),Mt=e("span"),Mt.textContent="Less than",Zt=s(),V=e("li"),_t=e("code"),_t.textContent="?<=",ge=s(),It=e("em"),It.textContent="Any/At least one of",_e=s(),wt=e("span"),wt.textContent="Less than or equal",we=s(),W=e("li"),G=e("code"),G.textContent="?~",xe=s(),xt=e("em"),xt.textContent="Any/At least one of",te=s(),X=e("span"),X.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,re=s(),M=e("li"),Ot=e("code"),Ot.textContent="?=",at=s(),Et=e("em"),Et.textContent="Any/At least one of",O=s(),mt=e("span"),mt.textContent="Equal",ce=s(),z=e("li"),St=e("code"),St.textContent="?!=",Xt=s(),Nt=e("em"),Nt.textContent="Any/At least one of",de=s(),q=e("span"),q.textContent="NOT equal",Yt=s(),Q=e("li"),ht=e("code"),ht.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"),qt=e("code"),qt.textContent="?>=",J=s(),bt=e("em"),bt.textContent="Any/At least one of",me=s(),gt=e("span"),gt.textContent="Greater than or equal",he=s(),x=e("li"),Dt=e("code"),Dt.textContent="?<",it=s(),Ht=e("em"),Ht.textContent="Any/At least one of",be=s(),Mt=e("span"),Mt.textContent="Less than",Zt=s(),V=e("li"),_t=e("code"),_t.textContent="?<=",ge=s(),It=e("em"),It.textContent="Any/At least one of",_e=s(),wt=e("span"),wt.textContent="Less than or equal",we=s(),W=e("li"),G=e("code"),G.textContent="?~",xe=s(),xt=e("em"),xt.textContent="Any/At least one of",te=s(),X=e("span"),X.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,ee=s(),L=e("li"),Y=e("code"),Y.textContent="?!~",E=s(),Bt=e("em"),Bt.textContent="Any/At least one of",$e=s(),Z=e("span"),Z.textContent=`NOT Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
wildcard match)`,v=s(),Gt=e("p"),Gt.innerHTML=`To group and combine several expressions you could use brackets
<code>(...)</code>, <code>&amp;&amp;</code> (AND) and <code>||</code> (OR) tokens.`,a(u,"class","txt-danger"),a(kt,"class","filter-op svelte-1w7s5nw"),a(S,"class","txt"),a(rt,"class","filter-op svelte-1w7s5nw"),a(et,"class","txt"),a(j,"class","filter-op svelte-1w7s5nw"),a(ct,"class","txt"),a(vt,"class","filter-op svelte-1w7s5nw"),a(dt,"class","txt"),a(N,"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(Pt,"class","txt"),a(Rt,"class","filter-op svelte-1w7s5nw"),a(ut,"class","txt"),a(Ot,"class","filter-op svelte-1w7s5nw"),a(Et,"class","txt-hint"),a(mt,"class","txt"),a(St,"class","filter-op svelte-1w7s5nw"),a(Nt,"class","txt-hint"),a(q,"class","txt"),a(ht,"class","filter-op svelte-1w7s5nw"),a(I,"class","txt-hint"),a(B,"class","txt"),a(qt,"class","filter-op svelte-1w7s5nw"),a(bt,"class","txt-hint"),a(gt,"class","txt"),a(Dt,"class","filter-op svelte-1w7s5nw"),a(Ht,"class","txt-hint"),a(Mt,"class","txt"),a(_t,"class","filter-op svelte-1w7s5nw"),a(It,"class","txt-hint"),a(wt,"class","txt"),a(G,"class","filter-op svelte-1w7s5nw"),a(xt,"class","txt-hint"),a(X,"class","txt"),a(Y,"class","filter-op svelte-1w7s5nw"),a(Bt,"class","txt-hint"),a(Z,"class","txt")},m(A,k){m(A,n,k),m(A,o,k),m(A,i,k),t(i,f),t(i,b),t(i,p),t(p,u),t(p,C),t(p,_),t(p,$),t(p,d),t(d,tt),t(tt,kt),t(tt,zt),t(tt,S),t(d,Kt),t(d,H),t(H,rt),t(H,R),t(H,et),t(d,ne),t(d,U),t(U,j),t(U,oe),t(U,ct),t(d,yt),t(d,lt),t(lt,vt),t(lt,ae),t(lt,dt),t(d,pt),t(d,st),t(st,N),t(st,Jt),t(st,Ft),t(d,y),t(d,nt),t(nt,Lt),t(nt,Vt),t(nt,At),t(d,Q),t(d,ot),t(ot,Tt),t(ot,Wt),t(ot,Pt),t(d,F),t(d,ft),t(ft,Rt),t(ft,ie),t(ft,ut),t(d,re),t(d,M),t(M,Ot),t(M,at),t(M,Et),t(M,O),t(M,mt),t(d,ce),t(d,z),t(z,St),t(z,Xt),t(z,Nt),t(z,de),t(z,q),t(d,Yt),t(d,K),t(K,ht),t(K,pe),t(K,I),t(K,fe),t(K,B),t(d,ue),t(d,P),t(P,qt),t(P,J),t(P,bt),t(P,me),t(P,gt),t(d,he),t(d,x),t(x,Dt),t(x,it),t(x,Ht),t(x,be),t(x,Mt),t(d,Zt),t(d,V),t(V,_t),t(V,ge),t(V,It),t(V,_e),t(V,wt),t(d,we),t(d,W),t(W,G),t(W,xe),t(W,xt),t(W,te),t(W,X),t(d,ee),t(d,L),t(L,Y),t(L,E),t(L,Bt),t(L,$e),t(L,Z),m(A,v,k),m(A,Gt,k)},d(A){A&&(h(n),h(o),h(i),h(v),h(Gt))}}}function ml(r){let n,o,i,f,b;function p($,d){return $[0]?ul:fl}let u=p(r),C=u(r),_=r[0]&&Qe();return{c(){n=e("button"),C.c(),o=s(),_&&_.c(),i=sl(),a(n,"class","btn btn-sm btn-secondary m-t-10")},m($,d){m($,n,d),C.m(n,null),m($,o,d),_&&_.m($,d),m($,i,d),f||(b=ll(n,"click",r[1]),f=!0)},p($,[d]){u!==(u=p($))&&(C.d(1),C=u($),C&&(C.c(),C.m(n,null))),$[0]?_||(_=Qe(),_.c(),_.m(i.parentNode,i)):_&&(_.d(1),_=null)},i:Ue,o:Ue,d($){$&&(h(n),h(o),h(i)),C.d(),_&&_.d($),f=!1,b()}}}function hl(r,n,o){let i=!1;function f(){o(0,i=!i)}return[i,f]}class bl extends Ze{constructor(n){super(),tl(this,n,hl,ml,el,{})}}function ze(r,n,o){const i=r.slice();return i[8]=n[o],i}function Ke(r,n,o){const i=r.slice();return i[8]=n[o],i}function Je(r,n,o){const i=r.slice();return i[13]=n[o],i[15]=o,i}function Ve(r){let n;return{c(){n=e("p"),n.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",a(n,"class","txt-hint txt-sm txt-right")},m(o,i){m(o,n,i)},d(o){o&&h(n)}}}function We(r){let n,o=r[13]+"",i,f=r[15]<r[4].length-1?", ":"",b;return{c(){n=e("code"),i=g(o),b=g(f)},m(p,u){m(p,n,u),t(n,i),m(p,b,u)},p(p,u){u&16&&o!==(o=p[13]+"")&&ke(i,o),u&16&&f!==(f=p[15]<p[4].length-1?", ":"")&&ke(b,f)},d(p){p&&(h(n),h(b))}}}function Xe(r,n){let o,i,f;function b(){return n[7](n[8])}return{key:r,first:null,c(){o=e("button"),o.textContent=`${n[8].code} `,a(o,"type","button"),a(o,"class","tab-item"),Fe(o,"active",n[2]===n[8].code),this.first=o},m(p,u){m(p,o,u),i||(f=ll(o,"click",b),i=!0)},p(p,u){n=p,u&36&&Fe(o,"active",n[2]===n[8].code)},d(p){p&&h(o),i=!1,f()}}}function Ye(r,n){let o,i,f,b;return i=new ve({props:{content:n[8].body}}),{key:r,first:null,c(){o=e("div"),Ut(i.$$.fragment),f=s(),a(o,"class","tab-item"),Fe(o,"active",n[2]===n[8].code),this.first=o},m(p,u){m(p,o,u),jt(i,o,null),t(o,f),b=!0},p(p,u){n=p,(!b||u&36)&&Fe(o,"active",n[2]===n[8].code)},i(p){b||($t(i.$$.fragment,p),b=!0)},o(p){Ct(i.$$.fragment,p),b=!1},d(p){p&&h(o),Qt(i)}}}function gl(r){var Pe,Re,Oe,Ee,Se,Ne;let n,o,i=r[0].name+"",f,b,p,u,C,_,$,d=r[0].name+"",tt,kt,zt,S,Kt,H,rt,R,et,ne,U,j,oe,ct,yt=r[0].name+"",lt,vt,ae,dt,pt,st,N,Jt,Ft,y,nt,Lt,Vt,At,Q,ot,Tt,Wt,Pt,F,ft,Rt,ie,ut,re,M,Ot,at,Et,O,mt,ce,z,St,Xt,Nt,de,q,Yt,K,ht,pe,I,fe,B,ue,P,qt,J,bt,me,gt,he,x,Dt,it,Ht,be,Mt,Zt,V,_t,ge,It,_e,wt,we,W,G,xe,xt,te,X,ee,L,Y,E=[],Bt=new Map,$e,Z,v=[],Gt=new Map,A;S=new nl({props:{js:`
<code>(...)</code>, <code>&amp;&amp;</code> (AND) and <code>||</code> (OR) tokens.`,a(u,"class","txt-danger"),a(kt,"class","filter-op svelte-1w7s5nw"),a(S,"class","txt"),a(rt,"class","filter-op svelte-1w7s5nw"),a(et,"class","txt"),a(U,"class","filter-op svelte-1w7s5nw"),a(ct,"class","txt"),a(vt,"class","filter-op svelte-1w7s5nw"),a(dt,"class","txt"),a(N,"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(Pt,"class","txt"),a(Rt,"class","filter-op svelte-1w7s5nw"),a(ut,"class","txt"),a(Ot,"class","filter-op svelte-1w7s5nw"),a(Et,"class","txt-hint"),a(mt,"class","txt"),a(St,"class","filter-op svelte-1w7s5nw"),a(Nt,"class","txt-hint"),a(q,"class","txt"),a(ht,"class","filter-op svelte-1w7s5nw"),a(I,"class","txt-hint"),a(B,"class","txt"),a(qt,"class","filter-op svelte-1w7s5nw"),a(bt,"class","txt-hint"),a(gt,"class","txt"),a(Dt,"class","filter-op svelte-1w7s5nw"),a(Ht,"class","txt-hint"),a(Mt,"class","txt"),a(_t,"class","filter-op svelte-1w7s5nw"),a(It,"class","txt-hint"),a(wt,"class","txt"),a(G,"class","filter-op svelte-1w7s5nw"),a(xt,"class","txt-hint"),a(X,"class","txt"),a(Y,"class","filter-op svelte-1w7s5nw"),a(Bt,"class","txt-hint"),a(Z,"class","txt")},m(A,k){m(A,n,k),m(A,o,k),m(A,i,k),t(i,f),t(i,b),t(i,p),t(p,u),t(p,C),t(p,_),t(p,$),t(p,d),t(d,tt),t(tt,kt),t(tt,zt),t(tt,S),t(d,Qt),t(d,H),t(H,rt),t(H,R),t(H,et),t(d,ne),t(d,j),t(j,U),t(j,oe),t(j,ct),t(d,yt),t(d,lt),t(lt,vt),t(lt,ae),t(lt,dt),t(d,pt),t(d,st),t(st,N),t(st,Jt),t(st,Ft),t(d,y),t(d,nt),t(nt,Lt),t(nt,Vt),t(nt,At),t(d,K),t(d,ot),t(ot,Tt),t(ot,Wt),t(ot,Pt),t(d,F),t(d,ft),t(ft,Rt),t(ft,ie),t(ft,ut),t(d,re),t(d,M),t(M,Ot),t(M,at),t(M,Et),t(M,O),t(M,mt),t(d,ce),t(d,z),t(z,St),t(z,Xt),t(z,Nt),t(z,de),t(z,q),t(d,Yt),t(d,Q),t(Q,ht),t(Q,pe),t(Q,I),t(Q,fe),t(Q,B),t(d,ue),t(d,P),t(P,qt),t(P,J),t(P,bt),t(P,me),t(P,gt),t(d,he),t(d,x),t(x,Dt),t(x,it),t(x,Ht),t(x,be),t(x,Mt),t(d,Zt),t(d,V),t(V,_t),t(V,ge),t(V,It),t(V,_e),t(V,wt),t(d,we),t(d,W),t(W,G),t(W,xe),t(W,xt),t(W,te),t(W,X),t(d,ee),t(d,L),t(L,Y),t(L,E),t(L,Bt),t(L,$e),t(L,Z),m(A,v,k),m(A,Gt,k)},d(A){A&&(h(n),h(o),h(i),h(v),h(Gt))}}}function ml(r){let n,o,i,f,b;function p($,d){return $[0]?ul:fl}let u=p(r),C=u(r),_=r[0]&&Ke();return{c(){n=e("button"),C.c(),o=s(),_&&_.c(),i=sl(),a(n,"class","btn btn-sm btn-secondary m-t-10")},m($,d){m($,n,d),C.m(n,null),m($,o,d),_&&_.m($,d),m($,i,d),f||(b=ll(n,"click",r[1]),f=!0)},p($,[d]){u!==(u=p($))&&(C.d(1),C=u($),C&&(C.c(),C.m(n,null))),$[0]?_||(_=Ke(),_.c(),_.m(i.parentNode,i)):_&&(_.d(1),_=null)},i:je,o:je,d($){$&&(h(n),h(o),h(i)),C.d(),_&&_.d($),f=!1,b()}}}function hl(r,n,o){let i=!1;function f(){o(0,i=!i)}return[i,f]}class bl extends Ze{constructor(n){super(),tl(this,n,hl,ml,el,{})}}function ze(r,n,o){const i=r.slice();return i[8]=n[o],i}function Qe(r,n,o){const i=r.slice();return i[8]=n[o],i}function Je(r,n,o){const i=r.slice();return i[13]=n[o],i[15]=o,i}function Ve(r){let n;return{c(){n=e("p"),n.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",a(n,"class","txt-hint txt-sm txt-right")},m(o,i){m(o,n,i)},d(o){o&&h(n)}}}function We(r){let n,o=r[13]+"",i,f=r[15]<r[4].length-1?", ":"",b;return{c(){n=e("code"),i=g(o),b=g(f)},m(p,u){m(p,n,u),t(n,i),m(p,b,u)},p(p,u){u&16&&o!==(o=p[13]+"")&&ke(i,o),u&16&&f!==(f=p[15]<p[4].length-1?", ":"")&&ke(b,f)},d(p){p&&(h(n),h(b))}}}function Xe(r,n){let o,i,f;function b(){return n[7](n[8])}return{key:r,first:null,c(){o=e("button"),o.textContent=`${n[8].code} `,a(o,"type","button"),a(o,"class","tab-item"),Fe(o,"active",n[2]===n[8].code),this.first=o},m(p,u){m(p,o,u),i||(f=ll(o,"click",b),i=!0)},p(p,u){n=p,u&36&&Fe(o,"active",n[2]===n[8].code)},d(p){p&&h(o),i=!1,f()}}}function Ye(r,n){let o,i,f,b;return i=new ve({props:{content:n[8].body}}),{key:r,first:null,c(){o=e("div"),jt(i.$$.fragment),f=s(),a(o,"class","tab-item"),Fe(o,"active",n[2]===n[8].code),this.first=o},m(p,u){m(p,o,u),Ut(i,o,null),t(o,f),b=!0},p(p,u){n=p,(!b||u&36)&&Fe(o,"active",n[2]===n[8].code)},i(p){b||($t(i.$$.fragment,p),b=!0)},o(p){Ct(i.$$.fragment,p),b=!1},d(p){p&&h(o),Kt(i)}}}function gl(r){var Pe,Re,Oe,Ee,Se,Ne;let n,o,i=r[0].name+"",f,b,p,u,C,_,$,d=r[0].name+"",tt,kt,zt,S,Qt,H,rt,R,et,ne,j,U,oe,ct,yt=r[0].name+"",lt,vt,ae,dt,pt,st,N,Jt,Ft,y,nt,Lt,Vt,At,K,ot,Tt,Wt,Pt,F,ft,Rt,ie,ut,re,M,Ot,at,Et,O,mt,ce,z,St,Xt,Nt,de,q,Yt,Q,ht,pe,I,fe,B,ue,P,qt,J,bt,me,gt,he,x,Dt,it,Ht,be,Mt,Zt,V,_t,ge,It,_e,wt,we,W,G,xe,xt,te,X,ee,L,Y,E=[],Bt=new Map,$e,Z,v=[],Gt=new Map,A;S=new nl({props:{js:`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${r[3]}');
@@ -56,18 +56,18 @@ import{S as Ze,i as tl,s as el,e,b as s,E as sl,f as a,g as m,u as ll,y as Ue,o
?sort=-created,id
`}});let le=se(r[4]),T=[];for(let l=0;l<le.length;l+=1)T[l]=We(Je(r,le,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"}}),G=new pl({});let ye=se(r[5]);const Ae=l=>l[8].code;for(let l=0;l<ye.length;l+=1){let c=Ke(r,ye,l),w=Ae(c);Bt.set(w,E[l]=Xe(w,c))}let Ce=se(r[5]);const Te=l=>l[8].code;for(let l=0;l<Ce.length;l+=1){let c=ze(r,Ce,l),w=Te(c);Gt.set(w,v[l]=Ye(w,c))}return{c(){n=e("h3"),o=g("List/Search ("),f=g(i),b=g(")"),p=s(),u=e("div"),C=e("p"),_=g("Fetch a paginated "),$=e("strong"),tt=g(d),kt=g(" records list, supporting sorting and filtering."),zt=s(),Ut(S.$$.fragment),Kt=s(),H=e("h6"),H.textContent="API details",rt=s(),R=e("div"),et=e("strong"),et.textContent="GET",ne=s(),U=e("div"),j=e("p"),oe=g("/api/collections/"),ct=e("strong"),lt=g(yt),vt=g("/records"),ae=s(),k&&k.c(),dt=s(),pt=e("div"),pt.textContent="Query parameters",st=s(),N=e("table"),Jt=e("thead"),Jt.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',Ft=s(),y=e("tbody"),nt=e("tr"),nt.innerHTML='<td>page</td> <td><span class="label">Number</span></td> <td>The page (aka. offset) of the paginated list (default to 1).</td>',Lt=s(),Vt=e("tr"),Vt.innerHTML='<td>perPage</td> <td><span class="label">Number</span></td> <td>Specify the max returned records per page (default to 30).</td>',At=s(),Q=e("tr"),ot=e("td"),ot.textContent="sort",Tt=s(),Wt=e("td"),Wt.innerHTML='<span class="label">String</span>',Pt=s(),F=e("td"),ft=g("Specify the records order attribute(s). "),Rt=e("br"),ie=g(`
`}}),P=new bl({}),it=new ve({props:{content:"?expand=relField1,relField2.subRelField"}}),G=new pl({});let ye=se(r[5]);const Ae=l=>l[8].code;for(let l=0;l<ye.length;l+=1){let c=Qe(r,ye,l),w=Ae(c);Bt.set(w,E[l]=Xe(w,c))}let Ce=se(r[5]);const Te=l=>l[8].code;for(let l=0;l<Ce.length;l+=1){let c=ze(r,Ce,l),w=Te(c);Gt.set(w,v[l]=Ye(w,c))}return{c(){n=e("h3"),o=g("List/Search ("),f=g(i),b=g(")"),p=s(),u=e("div"),C=e("p"),_=g("Fetch a paginated "),$=e("strong"),tt=g(d),kt=g(" records list, supporting sorting and filtering."),zt=s(),jt(S.$$.fragment),Qt=s(),H=e("h6"),H.textContent="API details",rt=s(),R=e("div"),et=e("strong"),et.textContent="GET",ne=s(),j=e("div"),U=e("p"),oe=g("/api/collections/"),ct=e("strong"),lt=g(yt),vt=g("/records"),ae=s(),k&&k.c(),dt=s(),pt=e("div"),pt.textContent="Query parameters",st=s(),N=e("table"),Jt=e("thead"),Jt.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',Ft=s(),y=e("tbody"),nt=e("tr"),nt.innerHTML='<td>page</td> <td><span class="label">Number</span></td> <td>The page (aka. offset) of the paginated list (default to 1).</td>',Lt=s(),Vt=e("tr"),Vt.innerHTML='<td>perPage</td> <td><span class="label">Number</span></td> <td>Specify the max returned records per page (default to 30).</td>',At=s(),K=e("tr"),ot=e("td"),ot.textContent="sort",Tt=s(),Wt=e("td"),Wt.innerHTML='<span class="label">String</span>',Pt=s(),F=e("td"),ft=g("Specify the records order attribute(s). "),Rt=e("br"),ie=g(`
Add `),ut=e("code"),ut.textContent="-",re=g(" / "),M=e("code"),M.textContent="+",Ot=g(` (default) in front of the attribute for DESC / ASC order.
Ex.:
`),Ut(at.$$.fragment),Et=s(),O=e("p"),mt=e("strong"),mt.textContent="Supported record sort fields:",ce=s(),z=e("br"),St=s(),Xt=e("code"),Xt.textContent="@random",Nt=g(`,
`);for(let l=0;l<T.length;l+=1)T[l].c();de=s(),q=e("tr"),Yt=e("td"),Yt.textContent="filter",K=s(),ht=e("td"),ht.innerHTML='<span class="label">String</span>',pe=s(),I=e("td"),fe=g(`Filter the returned records. Ex.:
`),Ut(B.$$.fragment),ue=s(),Ut(P.$$.fragment),qt=s(),J=e("tr"),bt=e("td"),bt.textContent="expand",me=s(),gt=e("td"),gt.innerHTML='<span class="label">String</span>',he=s(),x=e("td"),Dt=g(`Auto expand record relations. Ex.:
`),Ut(it.$$.fragment),Ht=g(`
`),jt(at.$$.fragment),Et=s(),O=e("p"),mt=e("strong"),mt.textContent="Supported record sort fields:",ce=s(),z=e("br"),St=s(),Xt=e("code"),Xt.textContent="@random",Nt=g(`,
`);for(let l=0;l<T.length;l+=1)T[l].c();de=s(),q=e("tr"),Yt=e("td"),Yt.textContent="filter",Q=s(),ht=e("td"),ht.innerHTML='<span class="label">String</span>',pe=s(),I=e("td"),fe=g(`Filter the returned records. Ex.:
`),jt(B.$$.fragment),ue=s(),jt(P.$$.fragment),qt=s(),J=e("tr"),bt=e("td"),bt.textContent="expand",me=s(),gt=e("td"),gt.innerHTML='<span class="label">String</span>',he=s(),x=e("td"),Dt=g(`Auto expand record relations. Ex.:
`),jt(it.$$.fragment),Ht=g(`
Supports up to 6-levels depth nested relations expansion. `),be=e("br"),Mt=g(`
The expanded relations will be appended to each individual record under the
`),Zt=e("code"),Zt.textContent="expand",V=g(" property (eg. "),_t=e("code"),_t.textContent='"expand": {"relField1": {...}, ...}',ge=g(`).
`),It=e("br"),_e=g(`
Only the relations to which the request user has permissions to `),wt=e("strong"),wt.textContent="view",we=g(" will be expanded."),W=s(),Ut(G.$$.fragment),xe=s(),xt=e("tr"),xt.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
Only the relations to which the request user has permissions to `),wt=e("strong"),wt.textContent="view",we=g(" will be expanded."),W=s(),jt(G.$$.fragment),xe=s(),xt=e("tr"),xt.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
@@ -76,7 +76,7 @@ import{S as Ze,i as tl,s as el,e,b as s,E as sl,f as a,g as m,u as ll,y as Ue,o
For optimization purposes, it is set by default for the
<code>getFirstListItem()</code>
and
<code>getFullList()</code> SDKs methods.</td>`,te=s(),X=e("div"),X.textContent="Responses",ee=s(),L=e("div"),Y=e("div");for(let l=0;l<E.length;l+=1)E[l].c();$e=s(),Z=e("div");for(let l=0;l<v.length;l+=1)v[l].c();a(n,"class","m-b-sm"),a(u,"class","content txt-lg m-b-sm"),a(H,"class","m-b-xs"),a(et,"class","label label-primary"),a(U,"class","content"),a(R,"class","alert alert-info"),a(pt,"class","section-title"),a(N,"class","table-compact table-border m-b-base"),a(X,"class","section-title"),a(Y,"class","tabs-header compact combined left"),a(Z,"class","tabs-content"),a(L,"class","tabs")},m(l,c){m(l,n,c),t(n,o),t(n,f),t(n,b),m(l,p,c),m(l,u,c),t(u,C),t(C,_),t(C,$),t($,tt),t(C,kt),m(l,zt,c),jt(S,l,c),m(l,Kt,c),m(l,H,c),m(l,rt,c),m(l,R,c),t(R,et),t(R,ne),t(R,U),t(U,j),t(j,oe),t(j,ct),t(ct,lt),t(j,vt),t(R,ae),k&&k.m(R,null),m(l,dt,c),m(l,pt,c),m(l,st,c),m(l,N,c),t(N,Jt),t(N,Ft),t(N,y),t(y,nt),t(y,Lt),t(y,Vt),t(y,At),t(y,Q),t(Q,ot),t(Q,Tt),t(Q,Wt),t(Q,Pt),t(Q,F),t(F,ft),t(F,Rt),t(F,ie),t(F,ut),t(F,re),t(F,M),t(F,Ot),jt(at,F,null),t(F,Et),t(F,O),t(O,mt),t(O,ce),t(O,z),t(O,St),t(O,Xt),t(O,Nt);for(let w=0;w<T.length;w+=1)T[w]&&T[w].m(O,null);t(y,de),t(y,q),t(q,Yt),t(q,K),t(q,ht),t(q,pe),t(q,I),t(I,fe),jt(B,I,null),t(I,ue),jt(P,I,null),t(y,qt),t(y,J),t(J,bt),t(J,me),t(J,gt),t(J,he),t(J,x),t(x,Dt),jt(it,x,null),t(x,Ht),t(x,be),t(x,Mt),t(x,Zt),t(x,V),t(x,_t),t(x,ge),t(x,It),t(x,_e),t(x,wt),t(x,we),t(y,W),jt(G,y,null),t(y,xe),t(y,xt),m(l,te,c),m(l,X,c),m(l,ee,c),m(l,L,c),t(L,Y);for(let w=0;w<E.length;w+=1)E[w]&&E[w].m(Y,null);t(L,$e),t(L,Z);for(let w=0;w<v.length;w+=1)v[w]&&v[w].m(Z,null);A=!0},p(l,[c]){var qe,De,He,Me,Ie,Be;(!A||c&1)&&i!==(i=l[0].name+"")&&ke(f,i),(!A||c&1)&&d!==(d=l[0].name+"")&&ke(tt,d);const w={};if(c&9&&(w.js=`
<code>getFullList()</code> SDKs methods.</td>`,te=s(),X=e("div"),X.textContent="Responses",ee=s(),L=e("div"),Y=e("div");for(let l=0;l<E.length;l+=1)E[l].c();$e=s(),Z=e("div");for(let l=0;l<v.length;l+=1)v[l].c();a(n,"class","m-b-sm"),a(u,"class","content txt-lg m-b-sm"),a(H,"class","m-b-xs"),a(et,"class","label label-primary"),a(j,"class","content"),a(R,"class","alert alert-info"),a(pt,"class","section-title"),a(N,"class","table-compact table-border m-b-base"),a(X,"class","section-title"),a(Y,"class","tabs-header compact combined left"),a(Z,"class","tabs-content"),a(L,"class","tabs")},m(l,c){m(l,n,c),t(n,o),t(n,f),t(n,b),m(l,p,c),m(l,u,c),t(u,C),t(C,_),t(C,$),t($,tt),t(C,kt),m(l,zt,c),Ut(S,l,c),m(l,Qt,c),m(l,H,c),m(l,rt,c),m(l,R,c),t(R,et),t(R,ne),t(R,j),t(j,U),t(U,oe),t(U,ct),t(ct,lt),t(U,vt),t(R,ae),k&&k.m(R,null),m(l,dt,c),m(l,pt,c),m(l,st,c),m(l,N,c),t(N,Jt),t(N,Ft),t(N,y),t(y,nt),t(y,Lt),t(y,Vt),t(y,At),t(y,K),t(K,ot),t(K,Tt),t(K,Wt),t(K,Pt),t(K,F),t(F,ft),t(F,Rt),t(F,ie),t(F,ut),t(F,re),t(F,M),t(F,Ot),Ut(at,F,null),t(F,Et),t(F,O),t(O,mt),t(O,ce),t(O,z),t(O,St),t(O,Xt),t(O,Nt);for(let w=0;w<T.length;w+=1)T[w]&&T[w].m(O,null);t(y,de),t(y,q),t(q,Yt),t(q,Q),t(q,ht),t(q,pe),t(q,I),t(I,fe),Ut(B,I,null),t(I,ue),Ut(P,I,null),t(y,qt),t(y,J),t(J,bt),t(J,me),t(J,gt),t(J,he),t(J,x),t(x,Dt),Ut(it,x,null),t(x,Ht),t(x,be),t(x,Mt),t(x,Zt),t(x,V),t(x,_t),t(x,ge),t(x,It),t(x,_e),t(x,wt),t(x,we),t(y,W),Ut(G,y,null),t(y,xe),t(y,xt),m(l,te,c),m(l,X,c),m(l,ee,c),m(l,L,c),t(L,Y);for(let w=0;w<E.length;w+=1)E[w]&&E[w].m(Y,null);t(L,$e),t(L,Z);for(let w=0;w<v.length;w+=1)v[w]&&v[w].m(Z,null);A=!0},p(l,[c]){var qe,De,He,Me,Ie,Be;(!A||c&1)&&i!==(i=l[0].name+"")&&ke(f,i),(!A||c&1)&&d!==(d=l[0].name+"")&&ke(tt,d);const w={};if(c&9&&(w.js=`
import PocketBase from 'pocketbase';
const pb = new PocketBase('${l[3]}');
@@ -121,7 +121,7 @@ import{S as Ze,i as tl,s as el,e,b as s,E as sl,f as a,g as m,u as ll,y as Ue,o
'someField="test"',
expand: 'relField1,relField2.subRelField',
);
`),S.$set(w),(!A||c&1)&&yt!==(yt=l[0].name+"")&&ke(lt,yt),l[1]?k||(k=Ve(),k.c(),k.m(R,null)):k&&(k.d(1),k=null),c&16){le=se(l[4]);let D;for(D=0;D<le.length;D+=1){const Ge=Je(l,le,D);T[D]?T[D].p(Ge,c):(T[D]=We(Ge),T[D].c(),T[D].m(O,null))}for(;D<T.length;D+=1)T[D].d(1);T.length=le.length}c&36&&(ye=se(l[5]),E=je(E,c,Ae,1,l,ye,Bt,Y,ol,Xe,null,Ke)),c&36&&(Ce=se(l[5]),al(),v=je(v,c,Te,1,l,Ce,Gt,Z,il,Ye,null,ze),rl())},i(l){if(!A){$t(S.$$.fragment,l),$t(at.$$.fragment,l),$t(B.$$.fragment,l),$t(P.$$.fragment,l),$t(it.$$.fragment,l),$t(G.$$.fragment,l);for(let c=0;c<Ce.length;c+=1)$t(v[c]);A=!0}},o(l){Ct(S.$$.fragment,l),Ct(at.$$.fragment,l),Ct(B.$$.fragment,l),Ct(P.$$.fragment,l),Ct(it.$$.fragment,l),Ct(G.$$.fragment,l);for(let c=0;c<v.length;c+=1)Ct(v[c]);A=!1},d(l){l&&(h(n),h(p),h(u),h(zt),h(Kt),h(H),h(rt),h(R),h(dt),h(pt),h(st),h(N),h(te),h(X),h(ee),h(L)),Qt(S,l),k&&k.d(),Qt(at),cl(T,l),Qt(B),Qt(P),Qt(it),Qt(G);for(let c=0;c<E.length;c+=1)E[c].d();for(let c=0;c<v.length;c+=1)v[c].d()}}}function _l(r,n,o){let i,f,b,p,{collection:u}=n,C=200,_=[];const $=d=>o(2,C=d.code);return r.$$set=d=>{"collection"in d&&o(0,u=d.collection)},r.$$.update=()=>{r.$$.dirty&1&&o(4,i=Le.getAllCollectionIdentifiers(u)),r.$$.dirty&1&&o(1,f=(u==null?void 0:u.listRule)===null),r.$$.dirty&1&&o(6,p=Le.dummyCollectionRecord(u)),r.$$.dirty&67&&u!=null&&u.id&&(_.push({code:200,body:JSON.stringify({page:1,perPage:30,totalPages:1,totalItems:2,items:[p,Object.assign({},p,{id:p+"2"})]},null,2)}),_.push({code:400,body:`
`),S.$set(w),(!A||c&1)&&yt!==(yt=l[0].name+"")&&ke(lt,yt),l[1]?k||(k=Ve(),k.c(),k.m(R,null)):k&&(k.d(1),k=null),c&16){le=se(l[4]);let D;for(D=0;D<le.length;D+=1){const Ge=Je(l,le,D);T[D]?T[D].p(Ge,c):(T[D]=We(Ge),T[D].c(),T[D].m(O,null))}for(;D<T.length;D+=1)T[D].d(1);T.length=le.length}c&36&&(ye=se(l[5]),E=Ue(E,c,Ae,1,l,ye,Bt,Y,ol,Xe,null,Qe)),c&36&&(Ce=se(l[5]),al(),v=Ue(v,c,Te,1,l,Ce,Gt,Z,il,Ye,null,ze),rl())},i(l){if(!A){$t(S.$$.fragment,l),$t(at.$$.fragment,l),$t(B.$$.fragment,l),$t(P.$$.fragment,l),$t(it.$$.fragment,l),$t(G.$$.fragment,l);for(let c=0;c<Ce.length;c+=1)$t(v[c]);A=!0}},o(l){Ct(S.$$.fragment,l),Ct(at.$$.fragment,l),Ct(B.$$.fragment,l),Ct(P.$$.fragment,l),Ct(it.$$.fragment,l),Ct(G.$$.fragment,l);for(let c=0;c<v.length;c+=1)Ct(v[c]);A=!1},d(l){l&&(h(n),h(p),h(u),h(zt),h(Qt),h(H),h(rt),h(R),h(dt),h(pt),h(st),h(N),h(te),h(X),h(ee),h(L)),Kt(S,l),k&&k.d(),Kt(at),cl(T,l),Kt(B),Kt(P),Kt(it),Kt(G);for(let c=0;c<E.length;c+=1)E[c].d();for(let c=0;c<v.length;c+=1)v[c].d()}}}function _l(r,n,o){let i,f,b,p,{collection:u}=n,C=200,_=[];const $=d=>o(2,C=d.code);return r.$$set=d=>{"collection"in d&&o(0,u=d.collection)},r.$$.update=()=>{r.$$.dirty&1&&o(4,i=Le.getAllCollectionIdentifiers(u)),r.$$.dirty&1&&o(1,f=(u==null?void 0:u.listRule)===null),r.$$.dirty&1&&o(6,p=Le.dummyCollectionRecord(u)),r.$$.dirty&67&&u!=null&&u.id&&(_.push({code:200,body:JSON.stringify({page:1,perPage:30,totalPages:1,totalItems:2,items:[p,Object.assign({},p,{id:p+"2"})]},null,2)}),_.push({code:400,body:`
{
"code": 400,
"message": "Something went wrong while processing your request. Invalid filter.",
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{S as r,i as c,s as l,e as u,f as p,g as h,y as n,o as d,J as f,K as m,L as g,M as o}from"./index-Co7n6kj7.js";function _(s){let t;return{c(){t=u("div"),t.innerHTML='<h3 class="m-b-sm">Auth failed.</h3> <h5>You can close this window and go back to the app to try again.</h5>',p(t,"class","content txt-hint txt-center p-base")},m(e,a){h(e,t,a)},p:n,i:n,o:n,d(e){e&&d(t)}}}function b(s,t,e){let a;return f(s,o,i=>e(0,a=i)),m(o,a="OAuth2 auth failed",a),g(()=>{window.close()}),[]}class v extends r{constructor(t){super(),c(this,t,b,_,l,{})}}export{v as default};
import{S as r,i as c,s as l,f as u,j as p,l as h,H as n,u as d,N as f,O as m,P as g,Q as o}from"./index-DGnuRrBU.js";function _(s){let t;return{c(){t=u("div"),t.innerHTML='<h3 class="m-b-sm">Auth failed.</h3> <h5>You can close this window and go back to the app to try again.</h5>',p(t,"class","content txt-hint txt-center p-base")},m(e,a){h(e,t,a)},p:n,i:n,o:n,d(e){e&&d(t)}}}function b(s,t,e){let a;return f(s,o,i=>e(0,a=i)),m(o,a="OAuth2 auth failed",a),g(()=>{window.close()}),[]}class v extends r{constructor(t){super(),c(this,t,b,_,l,{})}}export{v as default};
+1
View File
@@ -0,0 +1 @@
import{S as i,i as r,s as u,f as l,j as p,l as h,H as n,u as d,N as m,O as f,P as _,Q as o}from"./index-DGnuRrBU.js";function b(a){let t;return{c(){t=l("div"),t.innerHTML='<h3 class="m-b-sm">Auth completed.</h3> <h5>You can close this window and go back to the app.</h5>',p(t,"class","content txt-hint txt-center p-base")},m(e,s){h(e,t,s)},p:n,i:n,o:n,d(e){e&&d(t)}}}function g(a,t,e){let s;return m(a,o,c=>e(0,s=c)),f(o,s="OAuth2 auth completed",s),_(()=>{window.close()}),[]}class v extends i{constructor(t){super(),r(this,t,g,b,u,{})}}export{v as default};
-1
View File
@@ -1 +0,0 @@
import{S as i,i as r,s as u,e as l,f as p,g as h,y as n,o as d,J as m,K as f,L as g,M as o}from"./index-Co7n6kj7.js";function _(a){let t;return{c(){t=l("div"),t.innerHTML='<h3 class="m-b-sm">Auth completed.</h3> <h5>You can close this window and go back to the app.</h5>',p(t,"class","content txt-hint txt-center p-base")},m(e,s){h(e,t,s)},p:n,i:n,o:n,d(e){e&&d(t)}}}function b(a,t,e){let s;return m(a,o,c=>e(0,s=c)),f(o,s="OAuth2 auth completed",s),g(()=>{window.close()}),[]}class v extends i{constructor(t){super(),r(this,t,b,_,u,{})}}export{v as default};
@@ -1,2 +0,0 @@
import{S as G,i as I,s as J,F as M,c as S,m as L,t as h,a as v,d as z,C as N,E as R,g as _,k as W,n as Y,o as b,G as j,H as A,p as B,q as D,e as m,w as y,b as C,f as p,r as T,h as g,u as P,v as K,y as E,x as O,z as F}from"./index-Co7n6kj7.js";function Q(i){let e,t,n,l,s,o,f,a,r,u,k,$,d=i[3]&&H(i);return o=new D({props:{class:"form-field required",name:"password",$$slots:{default:[V,({uniqueId:c})=>({8:c}),({uniqueId:c})=>c?256:0]},$$scope:{ctx:i}}}),{c(){e=m("form"),t=m("div"),n=m("h5"),l=y(`Type your password to confirm changing your email address
`),d&&d.c(),s=C(),S(o.$$.fragment),f=C(),a=m("button"),r=m("span"),r.textContent="Confirm new email",p(t,"class","content txt-center m-b-base"),p(r,"class","txt"),p(a,"type","submit"),p(a,"class","btn btn-lg btn-block"),a.disabled=i[1],T(a,"btn-loading",i[1])},m(c,w){_(c,e,w),g(e,t),g(t,n),g(n,l),d&&d.m(n,null),g(e,s),L(o,e,null),g(e,f),g(e,a),g(a,r),u=!0,k||($=P(e,"submit",K(i[4])),k=!0)},p(c,w){c[3]?d?d.p(c,w):(d=H(c),d.c(),d.m(n,null)):d&&(d.d(1),d=null);const q={};w&769&&(q.$$scope={dirty:w,ctx:c}),o.$set(q),(!u||w&2)&&(a.disabled=c[1]),(!u||w&2)&&T(a,"btn-loading",c[1])},i(c){u||(h(o.$$.fragment,c),u=!0)},o(c){v(o.$$.fragment,c),u=!1},d(c){c&&b(e),d&&d.d(),z(o),k=!1,$()}}}function U(i){let e,t,n,l,s;return{c(){e=m("div"),e.innerHTML='<div class="icon"><i class="ri-checkbox-circle-line"></i></div> <div class="content txt-bold"><p>Successfully changed the user email address.</p> <p>You can now sign in with your new email address.</p></div>',t=C(),n=m("button"),n.textContent="Close",p(e,"class","alert alert-success"),p(n,"type","button"),p(n,"class","btn btn-transparent btn-block")},m(o,f){_(o,e,f),_(o,t,f),_(o,n,f),l||(s=P(n,"click",i[6]),l=!0)},p:E,i:E,o:E,d(o){o&&(b(e),b(t),b(n)),l=!1,s()}}}function H(i){let e,t,n;return{c(){e=y("to "),t=m("strong"),n=y(i[3]),p(t,"class","txt-nowrap")},m(l,s){_(l,e,s),_(l,t,s),g(t,n)},p(l,s){s&8&&O(n,l[3])},d(l){l&&(b(e),b(t))}}}function V(i){let e,t,n,l,s,o,f,a;return{c(){e=m("label"),t=y("Password"),l=C(),s=m("input"),p(e,"for",n=i[8]),p(s,"type","password"),p(s,"id",o=i[8]),s.required=!0,s.autofocus=!0},m(r,u){_(r,e,u),g(e,t),_(r,l,u),_(r,s,u),F(s,i[0]),s.focus(),f||(a=P(s,"input",i[7]),f=!0)},p(r,u){u&256&&n!==(n=r[8])&&p(e,"for",n),u&256&&o!==(o=r[8])&&p(s,"id",o),u&1&&s.value!==r[0]&&F(s,r[0])},d(r){r&&(b(e),b(l),b(s)),f=!1,a()}}}function X(i){let e,t,n,l;const s=[U,Q],o=[];function f(a,r){return a[2]?0:1}return e=f(i),t=o[e]=s[e](i),{c(){t.c(),n=R()},m(a,r){o[e].m(a,r),_(a,n,r),l=!0},p(a,r){let u=e;e=f(a),e===u?o[e].p(a,r):(W(),v(o[u],1,1,()=>{o[u]=null}),Y(),t=o[e],t?t.p(a,r):(t=o[e]=s[e](a),t.c()),h(t,1),t.m(n.parentNode,n))},i(a){l||(h(t),l=!0)},o(a){v(t),l=!1},d(a){a&&b(n),o[e].d(a)}}}function Z(i){let e,t;return e=new M({props:{nobranding:!0,$$slots:{default:[X]},$$scope:{ctx:i}}}),{c(){S(e.$$.fragment)},m(n,l){L(e,n,l),t=!0},p(n,[l]){const s={};l&527&&(s.$$scope={dirty:l,ctx:n}),e.$set(s)},i(n){t||(h(e.$$.fragment,n),t=!0)},o(n){v(e.$$.fragment,n),t=!1},d(n){z(e,n)}}}function x(i,e,t){let n,{params:l}=e,s="",o=!1,f=!1;async function a(){if(o)return;t(1,o=!0);const k=new j("../");try{const $=A(l==null?void 0:l.token);await k.collection($.collectionId).confirmEmailChange(l==null?void 0:l.token,s),t(2,f=!0)}catch($){B.error($)}t(1,o=!1)}const r=()=>window.close();function u(){s=this.value,t(0,s)}return i.$$set=k=>{"params"in k&&t(5,l=k.params)},i.$$.update=()=>{i.$$.dirty&32&&t(3,n=N.getJWTPayload(l==null?void 0:l.token).newEmail||"")},[s,o,f,n,a,l,r,u]}class te extends G{constructor(e){super(),I(this,e,x,Z,J,{params:5})}}export{te as default};

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