Compare commits
50 Commits
4de852cb68
...
4dc8be7bd3
| Author | SHA1 | Date |
|---|---|---|
|
|
4dc8be7bd3 | |
|
|
90d896e1cc | |
|
|
c13d83adb1 | |
|
|
9b73295a7c | |
|
|
3c6ce2de74 | |
|
|
63b89533a9 | |
|
|
779059eca3 | |
|
|
9abdadf0dc | |
|
|
6500b8c518 | |
|
|
91f1ca273d | |
|
|
6e739fd33d | |
|
|
2525f29c1c | |
|
|
1dc5e061b8 | |
|
|
09d7f6a7c3 | |
|
|
1775585b68 | |
|
|
f4e6c5edee | |
|
|
94b11bf2c3 | |
|
|
ddb8c88a37 | |
|
|
0f5411d81c | |
|
|
423d234da1 | |
|
|
6184b31d82 | |
|
|
63a9d045a1 | |
|
|
501ab0e6be | |
|
|
7ad08ef6bf | |
|
|
6210f361b0 | |
|
|
fcb5b5dd67 | |
|
|
41607679a0 | |
|
|
ca7e5b7f7b | |
|
|
593721dcea | |
|
|
153ad12e64 | |
|
|
482fe2bce0 | |
|
|
48489b6a07 | |
|
|
67ee431585 | |
|
|
d5dcd01551 | |
|
|
749bf7815c | |
|
|
ceae5e005f | |
|
|
7b6b71e18d | |
|
|
885d907beb | |
|
|
afb942bc41 | |
|
|
83a26d436e | |
|
|
7b52d0b56a | |
|
|
5a8eae7089 | |
|
|
0bd712752f | |
|
|
0b6157e1cc | |
|
|
c8980edf85 | |
|
|
a7ebb98e20 | |
|
|
69be986132 | |
|
|
58da159641 | |
|
|
8acb48b884 | |
|
|
91b521595a |
|
|
@ -2,4 +2,6 @@
|
||||||
|
|
||||||
If you discover a security vulnerability within PocketBase, please send an e-mail to **support at pocketbase.io**.
|
If you discover a security vulnerability within PocketBase, please send an e-mail to **support at pocketbase.io**.
|
||||||
|
|
||||||
|
**This is non-commercial personal open source project, so there are no bounties!**
|
||||||
|
|
||||||
All reports will be promptly addressed and you'll be credited in the fix release notes.
|
All reports will be promptly addressed and you'll be credited in the fix release notes.
|
||||||
|
|
|
||||||
78
CHANGELOG.md
78
CHANGELOG.md
|
|
@ -1,3 +1,79 @@
|
||||||
|
## v0.34.0
|
||||||
|
|
||||||
|
- Added `@request.body.someField:changed` modifier.
|
||||||
|
It could be used when you want to ensure that a body field either wasn't submitted or was submitted with the same value.
|
||||||
|
Or in other words, if you want to disallow a field change the below 2 expressions would be equivalent:
|
||||||
|
```js
|
||||||
|
// (old)
|
||||||
|
(@request.body.someField:isset = false || @request.body.someField = someField)
|
||||||
|
|
||||||
|
// (new)
|
||||||
|
@request.body.someField:changed = false
|
||||||
|
```
|
||||||
|
|
||||||
|
- Added `MailerRecordEvent.Meta["info"]` property for the `OnMailerRecordAuthAlertSend` hook.
|
||||||
|
|
||||||
|
- Updated the backup restore popup with a short info about the performed restore steps.
|
||||||
|
|
||||||
|
- Updated Go deps.
|
||||||
|
|
||||||
|
|
||||||
|
## v0.33.0
|
||||||
|
|
||||||
|
- Added extra `id` characters validation in addition to the user specified regex pattern ([#7312](https://github.com/pocketbase/pocketbase/issues/7312)).
|
||||||
|
_The following special characters are always forbidden: `./\|"'``<>:?*%$\n\r\t\0 `. Common reserved Windows file names such as `aux`, `prn`, `con`, `nul`, `com1-9`, `lpt1-9` are also not allowed._
|
||||||
|
_The list is not exhaustive but it should help minimizing eventual filesystem compatibility issues in case of wildcards or other loose regex patterns._
|
||||||
|
|
||||||
|
- Added `{ALERT_INFO}` placeholder to the auth alert mail template ([#7314](https://github.com/pocketbase/pocketbase/issues/7314)).
|
||||||
|
_⚠️ `mails.SendRecordAuthAlert(app, authRecord, info)` also now accepts a 3rd `info` string argument._
|
||||||
|
|
||||||
|
- Updated Go deps.
|
||||||
|
|
||||||
|
|
||||||
|
## v0.32.0
|
||||||
|
|
||||||
|
- ⚠️ Added extra List/Search API rules checks for the client-side `filter`/`sort` relations.
|
||||||
|
|
||||||
|
This is continuation of the effort to eliminate the risk of information disclosure _(and eventually the side-channel attacks that may originate from that)_.
|
||||||
|
|
||||||
|
So far this was accepted tradeoff between performance, usability and correctness since the solutions at the time weren't really practical _(especially with the back-relations as mentioned in ["Security and performance" section in #4417](https://github.com/pocketbase/pocketbase/discussions/4417))_, but with v0.23+ changes we can implement the extra checks without littering the code too much, with very little impact on the performance and at the same time ensuring better out of the box security _(especially for the cases where users operate with sensitive fields like "code", "token", "secret", etc.)_.
|
||||||
|
|
||||||
|
Similar to the previous release, probably for most users with already configured API rules this change won't be breaking, but if you have an _intermediate/junction collection_ that is "locked" (superusers-only) we no longer will allow the client-side relation filter to pass through it and you'll have to set its List/Search API rule to enable the current user to search in it.
|
||||||
|
|
||||||
|
For example, if you have a client-side filter that targets `rel1.rel2.token`, the client must have not only List/Search API rule access to the main collection BUT also to the collections referenced by "rel1" and "rel2" relation fields.
|
||||||
|
|
||||||
|
Note that this change is only for the **client-side** `filter`/`sort` and doesn't affect the execution of superuser requests, API rules and `expand` - they continue to work the same as it is.
|
||||||
|
|
||||||
|
An optional environment variable to toggle this behavior was considered but for now I think having 2 ways of resolving client-side filters would introduce maintenance burden and can even cause confusion (this change should actually make things more intuitive and clear because we can simply say something like _"you can search by a collection X field only if you have List/Search API rule access to it"_ no matter whether the targeted collection is the request's main collection, the first or last relation from the filter chain, etc.).
|
||||||
|
|
||||||
|
If you stumble on an error or extreme query performance degradation as a result of the extra checks, please open a Q&A discussion with the failing request and export of your collections configuration as JSON (_Settings > Export collections_) and I'll try to investigate it.
|
||||||
|
|
||||||
|
- Increased the default SQLite `PRAGMA cache_size` to ~32MB.
|
||||||
|
|
||||||
|
- Fixed deadlock when manually triggering the `OnTerminate` hook ([#7305](https://github.com/pocketbase/pocketbase/pull/7305); thanks @yerTools).
|
||||||
|
|
||||||
|
- Fixed some code comment typos, regenerated the JSVM types and updated npm dependencies.
|
||||||
|
|
||||||
|
- Updated `modernc.org/sqlite` to 1.40.0.
|
||||||
|
|
||||||
|
|
||||||
|
## v0.31.0
|
||||||
|
|
||||||
|
- Visualize presentable multiple `relation` fields ([#7260](https://github.com/pocketbase/pocketbase/issues/7260)).
|
||||||
|
|
||||||
|
- Support Ed25519 in the optional OIDC `id_token` signature validation ([#7252](https://github.com/pocketbase/pocketbase/issues/7252); thanks @shynome).
|
||||||
|
|
||||||
|
- Added `ApiScenario.DisableTestAppCleanup` optional field to skip the auto test app cleanup and leave it up to the developers to do the cleanup manually ([#7267](https://github.com/pocketbase/pocketbase/discussions/7267)).
|
||||||
|
|
||||||
|
- Added `FileDownloadRequestEvent.ThumbError` field that is populated in case of a thumb generation failure (e.g. unsupported format, timing out, etc.), allowing developers to reject the thumb fallback and/or supply their own custom thumb generation ([#7268](https://github.com/pocketbase/pocketbase/discussions/7268)).
|
||||||
|
|
||||||
|
- ⚠️ Disallow client-side filtering and sorting of relations where the collection of the last targeted relation field has superusers-only List/Search API rule to further minimize the risk of eventual side-channel attack.
|
||||||
|
_This should be a non-breaking change for most users, but if you want the old behavior, please open a new Q&A discussion with details about your use case to evaluate making it configurable._
|
||||||
|
_Note also that as mentioned in the "Security and performance" section of [#4417](https://github.com/pocketbase/pocketbase/discussions/4417) and [#5863](https://github.com/pocketbase/pocketbase/discussions/5863), the easiest and recommended solution to protect security sensitive fields (tokens, codes, passwords, etc.) is to mark them as "Hidden" (aka. make them non-API filterable)._
|
||||||
|
|
||||||
|
- Regenerated JSVM types and updated npm and Go deps.
|
||||||
|
|
||||||
|
|
||||||
## v0.30.4
|
## v0.30.4
|
||||||
|
|
||||||
- Fixed `json` field CSS regression introduced with the overflow workaround in v0.30.3 ([#7259](https://github.com/pocketbase/pocketbase/issues/7259)).
|
- Fixed `json` field CSS regression introduced with the overflow workaround in v0.30.3 ([#7259](https://github.com/pocketbase/pocketbase/issues/7259)).
|
||||||
|
|
@ -186,7 +262,7 @@
|
||||||
If you are having difficulties adjusting your code, feel free to open a [Q&A discussion](https://github.com/pocketbase/pocketbase/discussions) with the failing/problematic code sample.
|
If you are having difficulties adjusting your code, feel free to open a [Q&A discussion](https://github.com/pocketbase/pocketbase/discussions) with the failing/problematic code sample.
|
||||||
|
|
||||||
- Added [new `geoPoint` field](https://pocketbase.io/docs/collections/#geopoint) for storing `{"lon":x,"lat":y}` geographic coordinates.
|
- Added [new `geoPoint` field](https://pocketbase.io/docs/collections/#geopoint) for storing `{"lon":x,"lat":y}` geographic coordinates.
|
||||||
In addition, a new [`geoDistance(lonA, lotA, lonB, lotB)` function](htts://pocketbase.io/docs/api-rules-and-filters/#geodistancelona-lata-lonb-latb) was also implemented that could be used to apply an API rule or filter constraint based on the distance (in km) between 2 geo points.
|
In addition, a new [`geoDistance(lonA, lotA, lonB, lotB)` function](https://pocketbase.io/docs/api-rules-and-filters/#geodistancelona-lata-lonb-latb) was also implemented that could be used to apply an API rule or filter constraint based on the distance (in km) between 2 geo points.
|
||||||
|
|
||||||
- Updated the `select` field UI to accommodate better larger lists and RTL languages ([#4674](https://github.com/pocketbase/pocketbase/issues/4674)).
|
- Updated the `select` field UI to accommodate better larger lists and RTL languages ([#4674](https://github.com/pocketbase/pocketbase/issues/4674)).
|
||||||
|
|
||||||
|
|
|
||||||
37
apis/file.go
37
apis/file.go
|
|
@ -142,8 +142,14 @@ func (api *fileApi) download(e *core.RequestEvent) error {
|
||||||
defer fsys.Close()
|
defer fsys.Close()
|
||||||
|
|
||||||
originalPath := baseFilesPath + "/" + filename
|
originalPath := baseFilesPath + "/" + filename
|
||||||
servedPath := originalPath
|
|
||||||
servedName := filename
|
event := new(core.FileDownloadRequestEvent)
|
||||||
|
event.RequestEvent = e
|
||||||
|
event.Collection = collection
|
||||||
|
event.Record = record
|
||||||
|
event.FileField = fileField
|
||||||
|
event.ServedPath = originalPath
|
||||||
|
event.ServedName = filename
|
||||||
|
|
||||||
// check for valid thumb size param
|
// check for valid thumb size param
|
||||||
thumbSize := e.Request.URL.Query().Get("thumb")
|
thumbSize := e.Request.URL.Query().Get("thumb")
|
||||||
|
|
@ -157,34 +163,31 @@ func (api *fileApi) download(e *core.RequestEvent) error {
|
||||||
// check if it is an image
|
// check if it is an image
|
||||||
if list.ExistInSlice(oAttrs.ContentType, imageContentTypes) {
|
if list.ExistInSlice(oAttrs.ContentType, imageContentTypes) {
|
||||||
// add thumb size as file suffix
|
// add thumb size as file suffix
|
||||||
servedName = thumbSize + "_" + filename
|
event.ServedName = thumbSize + "_" + filename
|
||||||
servedPath = baseFilesPath + "/thumbs_" + filename + "/" + servedName
|
event.ServedPath = baseFilesPath + "/thumbs_" + filename + "/" + event.ServedName
|
||||||
|
|
||||||
// create a new thumb if it doesn't exist
|
// create a new thumb if it doesn't exist
|
||||||
if exists, _ := fsys.Exists(servedPath); !exists {
|
if exists, _ := fsys.Exists(event.ServedPath); !exists {
|
||||||
if err := api.createThumb(e, fsys, originalPath, servedPath, thumbSize); err != nil {
|
if err := api.createThumb(e, fsys, originalPath, event.ServedPath, thumbSize); err != nil {
|
||||||
e.App.Logger().Warn(
|
e.App.Logger().Warn(
|
||||||
"Fallback to original - failed to create thumb "+servedName,
|
"Fallback to original - failed to create thumb "+event.ServedName,
|
||||||
slog.Any("error", err),
|
slog.Any("error", err),
|
||||||
slog.String("original", originalPath),
|
slog.String("original", originalPath),
|
||||||
slog.String("thumb", servedPath),
|
slog.String("thumb", event.ServedPath),
|
||||||
)
|
)
|
||||||
|
|
||||||
// fallback to the original
|
// fallback to the original
|
||||||
servedName = filename
|
event.ThumbError = err
|
||||||
servedPath = originalPath
|
event.ServedName = filename
|
||||||
|
event.ServedPath = originalPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event := new(core.FileDownloadRequestEvent)
|
if thumbSize != "" && event.ThumbError == nil && event.ServedPath == originalPath {
|
||||||
event.RequestEvent = e
|
event.ThumbError = fmt.Errorf("the thumb size %q or the original file format are not supported", thumbSize)
|
||||||
event.Collection = collection
|
}
|
||||||
event.Record = record
|
|
||||||
event.FileField = fileField
|
|
||||||
event.ServedPath = servedPath
|
|
||||||
event.ServedName = servedName
|
|
||||||
|
|
||||||
// clickjacking shouldn't be a concern when serving uploaded files,
|
// clickjacking shouldn't be a concern when serving uploaded files,
|
||||||
// so it safe to unset the global X-Frame-Options to allow files embedding
|
// so it safe to unset the global X-Frame-Options to allow files embedding
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing image - missing thumb (should fallback to the original)",
|
Name: "existing image - missing thumb (should fallback to the original)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=999x999",
|
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=999x999",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError == nil {
|
||||||
|
t.Fatal("Expected thumb error, got nil")
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testImg)},
|
ExpectedContent: []string{string(testImg)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
@ -195,6 +203,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing image - existing thumb (crop center)",
|
Name: "existing image - existing thumb (crop center)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50",
|
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError != nil {
|
||||||
|
t.Fatalf("Expected no thumb error, got %v", e.ThumbError)
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testThumbCropCenter)},
|
ExpectedContent: []string{string(testThumbCropCenter)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
@ -206,6 +222,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing image - existing thumb (crop top)",
|
Name: "existing image - existing thumb (crop top)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50t",
|
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50t",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError != nil {
|
||||||
|
t.Fatalf("Expected no thumb error, got %v", e.ThumbError)
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testThumbCropTop)},
|
ExpectedContent: []string{string(testThumbCropTop)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
@ -217,6 +241,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing image - existing thumb (crop bottom)",
|
Name: "existing image - existing thumb (crop bottom)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50b",
|
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50b",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError != nil {
|
||||||
|
t.Fatalf("Expected no thumb error, got %v", e.ThumbError)
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testThumbCropBottom)},
|
ExpectedContent: []string{string(testThumbCropBottom)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
@ -228,6 +260,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing image - existing thumb (fit)",
|
Name: "existing image - existing thumb (fit)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50f",
|
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x50f",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError != nil {
|
||||||
|
t.Fatalf("Expected no thumb error, got %v", e.ThumbError)
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testThumbFit)},
|
ExpectedContent: []string{string(testThumbFit)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
@ -239,6 +279,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing image - existing thumb (zero width)",
|
Name: "existing image - existing thumb (zero width)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=0x50",
|
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=0x50",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError != nil {
|
||||||
|
t.Fatalf("Expected no thumb error, got %v", e.ThumbError)
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testThumbZeroWidth)},
|
ExpectedContent: []string{string(testThumbZeroWidth)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
@ -250,6 +298,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing image - existing thumb (zero height)",
|
Name: "existing image - existing thumb (zero height)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x0",
|
URL: "/api/files/_pb_users_auth_/4q1xlclmfloku33/300_1SEi6Q6U72.png?thumb=70x0",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError != nil {
|
||||||
|
t.Fatalf("Expected no thumb error, got %v", e.ThumbError)
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testThumbZeroHeight)},
|
ExpectedContent: []string{string(testThumbZeroHeight)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
@ -261,6 +317,14 @@ func TestFileDownload(t *testing.T) {
|
||||||
Name: "existing non image file - thumb parameter should be ignored",
|
Name: "existing non image file - thumb parameter should be ignored",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/files/_pb_users_auth_/oap640cot4yru2s/test_kfd2wYLxkz.txt?thumb=100x100",
|
URL: "/api/files/_pb_users_auth_/oap640cot4yru2s/test_kfd2wYLxkz.txt?thumb=100x100",
|
||||||
|
BeforeTestFunc: func(t testing.TB, app *tests.TestApp, e *core.ServeEvent) {
|
||||||
|
app.OnFileDownloadRequest().BindFunc(func(e *core.FileDownloadRequestEvent) error {
|
||||||
|
if e.ThumbError == nil {
|
||||||
|
t.Fatal("Expected thumb error, got nil")
|
||||||
|
}
|
||||||
|
return e.Next()
|
||||||
|
})
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{string(testFile)},
|
ExpectedContent: []string{string(testFile)},
|
||||||
ExpectedEvents: map[string]int{
|
ExpectedEvents: map[string]int{
|
||||||
|
|
|
||||||
|
|
@ -234,12 +234,12 @@ func newRateLimiter(maxAllowed int, intervalInSec int64, minDeleteIntervalInSec
|
||||||
maxAllowed: maxAllowed,
|
maxAllowed: maxAllowed,
|
||||||
interval: intervalInSec,
|
interval: intervalInSec,
|
||||||
minDeleteInterval: minDeleteIntervalInSec,
|
minDeleteInterval: minDeleteIntervalInSec,
|
||||||
clients: map[string]*fixedWindow{},
|
clients: map[string]*rateClient{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type rateLimiter struct {
|
type rateLimiter struct {
|
||||||
clients map[string]*fixedWindow
|
clients map[string]*rateClient
|
||||||
|
|
||||||
maxAllowed int
|
maxAllowed int
|
||||||
interval int64
|
interval int64
|
||||||
|
|
@ -250,7 +250,7 @@ type rateLimiter struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused
|
//nolint:unused
|
||||||
func (rt *rateLimiter) getClient(key string) (*fixedWindow, bool) {
|
func (rt *rateLimiter) getClient(key string) (*rateClient, bool) {
|
||||||
rt.RLock()
|
rt.RLock()
|
||||||
client, ok := rt.clients[key]
|
client, ok := rt.clients[key]
|
||||||
rt.RUnlock()
|
rt.RUnlock()
|
||||||
|
|
@ -269,7 +269,7 @@ func (rt *rateLimiter) isAllowed(key string) bool {
|
||||||
// check again in case the client was added by another request
|
// check again in case the client was added by another request
|
||||||
client, ok = rt.clients[key]
|
client, ok = rt.clients[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
client = newFixedWindow(rt.maxAllowed, rt.interval)
|
client = newRateClient(rt.maxAllowed, rt.interval)
|
||||||
rt.clients[key] = client
|
rt.clients[key] = client
|
||||||
}
|
}
|
||||||
rt.Unlock()
|
rt.Unlock()
|
||||||
|
|
@ -295,7 +295,7 @@ func (rt *rateLimiter) clean() {
|
||||||
//
|
//
|
||||||
// @todo remove after https://github.com/golang/go/issues/20135
|
// @todo remove after https://github.com/golang/go/issues/20135
|
||||||
if rt.totalDeleted >= 300 {
|
if rt.totalDeleted >= 300 {
|
||||||
shrunk := make(map[string]*fixedWindow, len(rt.clients))
|
shrunk := make(map[string]*rateClient, len(rt.clients))
|
||||||
for k, v := range rt.clients {
|
for k, v := range rt.clients {
|
||||||
shrunk[k] = v
|
shrunk[k] = v
|
||||||
}
|
}
|
||||||
|
|
@ -304,14 +304,20 @@ func (rt *rateLimiter) clean() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFixedWindow(maxAllowed int, intervalInSec int64) *fixedWindow {
|
func newRateClient(maxAllowed int, intervalInSec int64) *rateClient {
|
||||||
return &fixedWindow{
|
return &rateClient{
|
||||||
maxAllowed: maxAllowed,
|
maxAllowed: maxAllowed,
|
||||||
interval: intervalInSec,
|
interval: intervalInSec,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type fixedWindow struct {
|
// @todo evaluate swiching to a more traditional fixed window or sliding window counter
|
||||||
|
// implementations since some users complained that it is not intuitive (see #7329).
|
||||||
|
//
|
||||||
|
// rateClient is a mixture of token bucket and fixed window rate limit strategies
|
||||||
|
// that refills the allowance only after at least "interval" seconds
|
||||||
|
// has elapsed since the last request.
|
||||||
|
type rateClient struct {
|
||||||
// use plain Mutex instead of RWMutex since the operations are expected
|
// use plain Mutex instead of RWMutex since the operations are expected
|
||||||
// to be mostly writes (e.g. consume()) and it should perform better
|
// to be mostly writes (e.g. consume()) and it should perform better
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
|
|
@ -324,18 +330,18 @@ type fixedWindow struct {
|
||||||
|
|
||||||
// hasExpired checks whether it has been at least minElapsed seconds since the lastConsume time.
|
// hasExpired checks whether it has been at least minElapsed seconds since the lastConsume time.
|
||||||
// (usually used to perform periodic cleanup of staled instances).
|
// (usually used to perform periodic cleanup of staled instances).
|
||||||
func (l *fixedWindow) hasExpired(relativeNow int64, minElapsed int64) bool {
|
func (l *rateClient) hasExpired(relativeNow int64, minElapsed int64) bool {
|
||||||
l.Lock()
|
l.Lock()
|
||||||
defer l.Unlock()
|
defer l.Unlock()
|
||||||
|
|
||||||
return relativeNow-l.lastConsume > minElapsed
|
return relativeNow-l.lastConsume > minElapsed
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume decrease the current window allowance with 1 (if not exhausted already).
|
// consume decreases the current allowance with 1 (if not exhausted already).
|
||||||
//
|
//
|
||||||
// It returns false if the allowance has been already exhausted and the user
|
// It returns false if the allowance has been already exhausted and the user
|
||||||
// has to wait until it resets back to its maxAllowed value.
|
// has to wait until it resets back to its maxAllowed value.
|
||||||
func (l *fixedWindow) consume() bool {
|
func (l *rateClient) consume() bool {
|
||||||
l.Lock()
|
l.Lock()
|
||||||
defer l.Unlock()
|
defer l.Unlock()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -769,7 +769,11 @@ func realtimeCanAccessRecord(
|
||||||
}
|
}
|
||||||
|
|
||||||
q.AndWhere(expr)
|
q.AndWhere(expr)
|
||||||
resolver.UpdateQuery(q)
|
|
||||||
|
err = resolver.UpdateQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
err = q.Limit(1).Row(&exists)
|
err = q.Limit(1).Row(&exists)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ func recordsList(e *core.RequestEvent) error {
|
||||||
len(e.Records) == 0 &&
|
len(e.Records) == 0 &&
|
||||||
checkRateLimit(e.RequestEvent, "@pb_list_timing_check_"+collection.Id, listTimingRateLimitRule) != nil {
|
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)
|
e.App.Logger().Debug("Randomized throttle because of too many failed searches", "collectionId", collection.Id)
|
||||||
randomizedThrottle(150)
|
randomizedThrottle(500)
|
||||||
}
|
}
|
||||||
|
|
||||||
return execAfterSuccessTx(true, e.App, func() error {
|
return execAfterSuccessTx(true, e.App, func() error {
|
||||||
|
|
@ -169,12 +169,18 @@ func recordView(e *core.RequestEvent) error {
|
||||||
ruleFunc := func(q *dbx.SelectQuery) error {
|
ruleFunc := func(q *dbx.SelectQuery) error {
|
||||||
if !requestInfo.HasSuperuserAuth() && collection.ViewRule != nil && *collection.ViewRule != "" {
|
if !requestInfo.HasSuperuserAuth() && collection.ViewRule != nil && *collection.ViewRule != "" {
|
||||||
resolver := core.NewRecordFieldResolver(e.App, collection, requestInfo, true)
|
resolver := core.NewRecordFieldResolver(e.App, collection, requestInfo, true)
|
||||||
|
|
||||||
expr, err := search.FilterData(*collection.ViewRule).BuildExpr(resolver)
|
expr, err := search.FilterData(*collection.ViewRule).BuildExpr(resolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resolver.UpdateQuery(q)
|
|
||||||
q.AndWhere(expr)
|
q.AndWhere(expr)
|
||||||
|
|
||||||
|
err = resolver.UpdateQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -310,7 +316,10 @@ func recordCreate(responseWriteAfterTx bool, optFinalizer func(data any) error)
|
||||||
}
|
}
|
||||||
ruleQuery.AndWhere(expr)
|
ruleQuery.AndWhere(expr)
|
||||||
|
|
||||||
resolver.UpdateQuery(ruleQuery)
|
err = resolver.UpdateQuery(ruleQuery)
|
||||||
|
if err != nil {
|
||||||
|
return e.BadRequestError("Failed to create record", fmt.Errorf("create rule update query failure: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
var exists int
|
var exists int
|
||||||
err = ruleQuery.Limit(1).Row(&exists)
|
err = ruleQuery.Limit(1).Row(&exists)
|
||||||
|
|
@ -430,12 +439,18 @@ func recordUpdate(responseWriteAfterTx bool, optFinalizer func(data any) error)
|
||||||
ruleFunc := func(q *dbx.SelectQuery) error {
|
ruleFunc := func(q *dbx.SelectQuery) error {
|
||||||
if !hasSuperuserAuth && collection.UpdateRule != nil && *collection.UpdateRule != "" {
|
if !hasSuperuserAuth && collection.UpdateRule != nil && *collection.UpdateRule != "" {
|
||||||
resolver := core.NewRecordFieldResolver(e.App, collection, requestInfo, true)
|
resolver := core.NewRecordFieldResolver(e.App, collection, requestInfo, true)
|
||||||
|
|
||||||
expr, err := search.FilterData(*collection.UpdateRule).BuildExpr(resolver)
|
expr, err := search.FilterData(*collection.UpdateRule).BuildExpr(resolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resolver.UpdateQuery(q)
|
|
||||||
q.AndWhere(expr)
|
q.AndWhere(expr)
|
||||||
|
|
||||||
|
err = resolver.UpdateQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -546,12 +561,18 @@ func recordDelete(responseWriteAfterTx bool, optFinalizer func(data any) error)
|
||||||
ruleFunc := func(q *dbx.SelectQuery) error {
|
ruleFunc := func(q *dbx.SelectQuery) error {
|
||||||
if !requestInfo.HasSuperuserAuth() && collection.DeleteRule != nil && *collection.DeleteRule != "" {
|
if !requestInfo.HasSuperuserAuth() && collection.DeleteRule != nil && *collection.DeleteRule != "" {
|
||||||
resolver := core.NewRecordFieldResolver(e.App, collection, requestInfo, true)
|
resolver := core.NewRecordFieldResolver(e.App, collection, requestInfo, true)
|
||||||
|
|
||||||
expr, err := search.FilterData(*collection.DeleteRule).BuildExpr(resolver)
|
expr, err := search.FilterData(*collection.DeleteRule).BuildExpr(resolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resolver.UpdateQuery(q)
|
|
||||||
q.AndWhere(expr)
|
q.AndWhere(expr)
|
||||||
|
|
||||||
|
err = resolver.UpdateQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -732,7 +753,10 @@ func hasAuthManageAccess(app core.App, requestInfo *core.RequestInfo, collection
|
||||||
}
|
}
|
||||||
query.AndWhere(expr)
|
query.AndWhere(expr)
|
||||||
|
|
||||||
resolver.UpdateQuery(query)
|
err = resolver.UpdateQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var exists int
|
var exists int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -382,10 +382,32 @@ func TestRecordCrudList(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "multi-match - at least one of",
|
Name: "multi-match - at least one of (guest - non-satisfied relation filter API rule)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/collections/demo4/records?filter=" + url.QueryEscape("rel_many_no_cascade_required.files:length?=2"),
|
URL: "/api/collections/demo4/records?filter=" + url.QueryEscape("rel_many_no_cascade_required.files:length?=2"),
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
|
ExpectedContent: []string{
|
||||||
|
`"page":1`,
|
||||||
|
`"perPage":30`,
|
||||||
|
`"totalPages":0`,
|
||||||
|
`"totalItems":0`,
|
||||||
|
`"items":[]`,
|
||||||
|
},
|
||||||
|
ExpectedEvents: map[string]int{
|
||||||
|
"*": 0,
|
||||||
|
"OnRecordsListRequest": 1,
|
||||||
|
"OnRecordEnrich": 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "multi-match - at least one of (clients)",
|
||||||
|
Method: http.MethodGet,
|
||||||
|
URL: "/api/collections/demo4/records?filter=" + url.QueryEscape("rel_many_no_cascade_required.files:length?=2"),
|
||||||
|
Headers: map[string]string{
|
||||||
|
// clients, test@example.com
|
||||||
|
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImdrMzkwcWVnczR5NDd3biIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoidjg1MXE0cjc5MHJoa25sIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.0ONnm_BsvPRZyDNT31GN1CKUB6uQRxvVvQ-Wc9AZfG0",
|
||||||
|
},
|
||||||
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{
|
ExpectedContent: []string{
|
||||||
`"page":1`,
|
`"page":1`,
|
||||||
`"perPage":30`,
|
`"perPage":30`,
|
||||||
|
|
@ -401,9 +423,13 @@ func TestRecordCrudList(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "multi-match - all",
|
Name: "multi-match - all (clients)",
|
||||||
Method: http.MethodGet,
|
Method: http.MethodGet,
|
||||||
URL: "/api/collections/demo4/records?filter=" + url.QueryEscape("rel_many_no_cascade_required.files:length=2"),
|
URL: "/api/collections/demo4/records?filter=" + url.QueryEscape("rel_many_no_cascade_required.files:length=2"),
|
||||||
|
Headers: map[string]string{
|
||||||
|
// clients, test@example.com
|
||||||
|
"Authorization": "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImdrMzkwcWVnczR5NDd3biIsInR5cGUiOiJhdXRoIiwiY29sbGVjdGlvbklkIjoidjg1MXE0cjc5MHJoa25sIiwiZXhwIjoyNTI0NjA0NDYxLCJyZWZyZXNoYWJsZSI6dHJ1ZX0.0ONnm_BsvPRZyDNT31GN1CKUB6uQRxvVvQ-Wc9AZfG0",
|
||||||
|
},
|
||||||
ExpectedStatus: 200,
|
ExpectedStatus: 200,
|
||||||
ExpectedContent: []string{
|
ExpectedContent: []string{
|
||||||
`"page":1`,
|
`"page":1`,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/pocketbase/pocketbase/tools/routine"
|
"github.com/pocketbase/pocketbase/tools/routine"
|
||||||
"github.com/pocketbase/pocketbase/tools/search"
|
"github.com/pocketbase/pocketbase/tools/search"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -160,7 +161,11 @@ func wantsMFA(e *core.RequestEvent, record *core.Record) (bool, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
resolver.UpdateQuery(query)
|
|
||||||
|
err = resolver.UpdateQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
err = query.AndWhere(expr).Limit(1).Row(&exists)
|
err = query.AndWhere(expr).Limit(1).Row(&exists)
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
|
@ -379,12 +384,18 @@ func expandFetch(app core.App, originalRequestInfo *core.RequestInfo) core.Expan
|
||||||
|
|
||||||
if *relCollection.ViewRule != "" {
|
if *relCollection.ViewRule != "" {
|
||||||
resolver := core.NewRecordFieldResolver(app, relCollection, requestInfoPtr, true)
|
resolver := core.NewRecordFieldResolver(app, relCollection, requestInfoPtr, true)
|
||||||
|
|
||||||
expr, err := search.FilterData(*(relCollection.ViewRule)).BuildExpr(resolver)
|
expr, err := search.FilterData(*(relCollection.ViewRule)).BuildExpr(resolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resolver.UpdateQuery(q)
|
|
||||||
q.AndWhere(expr)
|
q.AndWhere(expr)
|
||||||
|
|
||||||
|
err = resolver.UpdateQuery(q)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -465,10 +476,16 @@ func autoResolveRecordsFlags(app core.App, records []*core.Record, requestInfo *
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resolver.UpdateQuery(query)
|
|
||||||
query.AndWhere(expr)
|
query.AndWhere(expr)
|
||||||
|
|
||||||
if err := query.Column(&managedIds); err != nil {
|
err = resolver.UpdateQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = query.Column(&managedIds)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// ---
|
// ---
|
||||||
|
|
@ -563,13 +580,17 @@ func execAfterSuccessTx(checkTx bool, app core.App, fn func() error) error {
|
||||||
const maxAuthOrigins = 5
|
const maxAuthOrigins = 5
|
||||||
|
|
||||||
func authAlert(e *core.RequestEvent, authRecord *core.Record) error {
|
func authAlert(e *core.RequestEvent, authRecord *core.Record) error {
|
||||||
// generating fingerprint
|
// generate fingerprint
|
||||||
// ---
|
// ---
|
||||||
|
ip := e.RealIP()
|
||||||
|
|
||||||
userAgent := e.Request.UserAgent()
|
userAgent := e.Request.UserAgent()
|
||||||
if len(userAgent) > 300 {
|
if len(userAgent) > 200 {
|
||||||
userAgent = userAgent[:300]
|
userAgent = userAgent[:200] + "..."
|
||||||
}
|
}
|
||||||
fingerprint := security.MD5(e.RealIP() + userAgent)
|
|
||||||
|
fingerprint := security.MD5(ip + userAgent)
|
||||||
|
alertInfo := fmt.Sprintf("%s - %s %s", types.NowDateTime().String(), ip, userAgent)
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
origins, err := e.App.FindAllAuthOriginsByRecord(authRecord)
|
origins, err := e.App.FindAllAuthOriginsByRecord(authRecord)
|
||||||
|
|
@ -609,7 +630,7 @@ func authAlert(e *core.RequestEvent, authRecord *core.Record) error {
|
||||||
})
|
})
|
||||||
|
|
||||||
routine.FireAndForget(func() {
|
routine.FireAndForget(func() {
|
||||||
err := mails.SendRecordAuthAlert(e.App, authRecord)
|
err := mails.SendRecordAuthAlert(e.App, authRecord, alertInfo)
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
mailSent <- err
|
mailSent <- err
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1195,7 +1195,7 @@ type App interface {
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
// OnMailerSend hook is triggered every time when a new email is
|
// OnMailerSend hook is triggered every time when a new email is
|
||||||
// being send using the [App.NewMailClient()] instance.
|
// being sent using the [App.NewMailClient()] instance.
|
||||||
//
|
//
|
||||||
// It allows intercepting the email message or to use a custom mailer client.
|
// It allows intercepting the email message or to use a custom mailer client.
|
||||||
OnMailerSend() *hook.Hook[*MailerEvent]
|
OnMailerSend() *hook.Hook[*MailerEvent]
|
||||||
|
|
|
||||||
|
|
@ -1408,7 +1408,7 @@ func getLoggerMinLevel(app App) slog.Level {
|
||||||
func (app *BaseApp) initLogger() error {
|
func (app *BaseApp) initLogger() error {
|
||||||
duration := 3 * time.Second
|
duration := 3 * time.Second
|
||||||
ticker := time.NewTicker(duration)
|
ticker := time.NewTicker(duration)
|
||||||
done := make(chan bool)
|
done := make(chan bool, 1)
|
||||||
|
|
||||||
handler := logger.NewBatchHandler(logger.BatchOptions{
|
handler := logger.NewBatchHandler(logger.BatchOptions{
|
||||||
Level: getLoggerMinLevel(app),
|
Level: getLoggerMinLevel(app),
|
||||||
|
|
@ -1479,7 +1479,11 @@ func (app *BaseApp) initLogger() error {
|
||||||
|
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
|
|
||||||
done <- true
|
// don't block in case OnTerminate is triggered more than once
|
||||||
|
select {
|
||||||
|
case done <- true:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
return e.Next()
|
return e.Next()
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -552,3 +552,19 @@ func TestBaseAppAuxDBDualBuilder(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBaseAppTriggerOnTerminate(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
app, _ := tests.NewTestApp()
|
||||||
|
defer app.Cleanup()
|
||||||
|
|
||||||
|
event := new(core.TerminateEvent)
|
||||||
|
event.App = app
|
||||||
|
|
||||||
|
// trigger OnTerminate multiple times to ensure that it doesn't deadlock
|
||||||
|
// https://github.com/pocketbase/pocketbase/pull/7305
|
||||||
|
app.OnTerminate().Trigger(event)
|
||||||
|
app.OnTerminate().Trigger(event)
|
||||||
|
app.OnTerminate().Trigger(event)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ const (
|
||||||
EmailPlaceholderToken string = "{TOKEN}"
|
EmailPlaceholderToken string = "{TOKEN}"
|
||||||
EmailPlaceholderOTP string = "{OTP}"
|
EmailPlaceholderOTP string = "{OTP}"
|
||||||
EmailPlaceholderOTPId string = "{OTP_ID}"
|
EmailPlaceholderOTPId string = "{OTP_ID}"
|
||||||
|
EmailPlaceholderAlertInfo string = "{ALERT_INFO}"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultVerificationTemplate = EmailTemplate{
|
var defaultVerificationTemplate = EmailTemplate{
|
||||||
|
|
@ -65,9 +66,10 @@ var defaultOTPTemplate = EmailTemplate{
|
||||||
var defaultAuthAlertTemplate = EmailTemplate{
|
var defaultAuthAlertTemplate = EmailTemplate{
|
||||||
Subject: "Login from a new location",
|
Subject: "Login from a new location",
|
||||||
Body: `<p>Hello,</p>
|
Body: `<p>Hello,</p>
|
||||||
<p>We noticed a login to your ` + EmailPlaceholderAppName + ` account from a new location.</p>
|
<p>We noticed a login to your ` + EmailPlaceholderAppName + ` account from a new location:</p>
|
||||||
<p>If this was you, you may disregard this email.</p>
|
<p><em>` + EmailPlaceholderAlertInfo + `</em></p>
|
||||||
<p><strong>If this wasn't you, you should immediately change your ` + EmailPlaceholderAppName + ` account password to revoke access from all other locations.</strong></p>
|
<p><strong>If this wasn't you, you should immediately change your ` + EmailPlaceholderAppName + ` account password to revoke access from all other locations.</strong></p>
|
||||||
|
<p>If this was you, you may disregard this email.</p>
|
||||||
<p>
|
<p>
|
||||||
Thanks,<br/>
|
Thanks,<br/>
|
||||||
` + EmailPlaceholderAppName + ` team
|
` + EmailPlaceholderAppName + ` team
|
||||||
|
|
|
||||||
|
|
@ -489,7 +489,7 @@ func (validator *collectionValidator) checkRule(value any) error {
|
||||||
return nil // nothing to check
|
return nil // nothing to check
|
||||||
}
|
}
|
||||||
|
|
||||||
r := NewRecordFieldResolver(validator.app, validator.new, nil, true)
|
r := NewRecordFieldResolver(validator.app, validator.new, &RequestInfo{}, true)
|
||||||
_, err := search.FilterData(vStr).BuildExpr(r)
|
_, err := search.FilterData(vStr).BuildExpr(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return validation.NewError("validation_invalid_rule", "Invalid rule. Raw error: "+err.Error())
|
return validation.NewError("validation_invalid_rule", "Invalid rule. Raw error: "+err.Error())
|
||||||
|
|
|
||||||
|
|
@ -319,8 +319,8 @@ func TestCollectionValidate(t *testing.T) {
|
||||||
c.ListRule = types.Pointer("!invalid")
|
c.ListRule = types.Pointer("!invalid")
|
||||||
c.ViewRule = types.Pointer("missing = 123")
|
c.ViewRule = types.Pointer("missing = 123")
|
||||||
c.CreateRule = types.Pointer("id = 123 && missing = 456")
|
c.CreateRule = types.Pointer("id = 123 && missing = 456")
|
||||||
c.UpdateRule = types.Pointer("(id = 123")
|
c.UpdateRule = types.Pointer("@request.body.missing:changed = false")
|
||||||
c.DeleteRule = types.Pointer("missing = 123")
|
c.DeleteRule = types.Pointer("(id=123")
|
||||||
return c, nil
|
return c, nil
|
||||||
},
|
},
|
||||||
expectedErrors: []string{"listRule", "viewRule", "createRule", "updateRule", "deleteRule"},
|
expectedErrors: []string{"listRule", "viewRule", "createRule", "updateRule", "deleteRule"},
|
||||||
|
|
@ -333,7 +333,7 @@ func TestCollectionValidate(t *testing.T) {
|
||||||
c.ListRule = types.Pointer("")
|
c.ListRule = types.Pointer("")
|
||||||
c.ViewRule = types.Pointer("f1 = 123")
|
c.ViewRule = types.Pointer("f1 = 123")
|
||||||
c.CreateRule = types.Pointer("id = 123 && f1 = 456")
|
c.CreateRule = types.Pointer("id = 123 && f1 = 456")
|
||||||
c.UpdateRule = types.Pointer("(id = 123)")
|
c.UpdateRule = types.Pointer("(id = 123 && @request.body.f1:changed = false)")
|
||||||
c.DeleteRule = types.Pointer("f1 = 123")
|
c.DeleteRule = types.Pointer("f1 = 123")
|
||||||
return c, nil
|
return c, nil
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ func DefaultDBConnect(dbPath string) (*dbx.DB, error) {
|
||||||
// Note: the busy_timeout pragma must be first because
|
// Note: the busy_timeout pragma must be first because
|
||||||
// the connection needs to be set to block on busy before WAL mode
|
// the connection needs to be set to block on busy before WAL mode
|
||||||
// is set in case it hasn't been already set by another connection.
|
// is set in case it hasn't been already set by another connection.
|
||||||
pragmas := "?_pragma=busy_timeout(10000)&_pragma=journal_mode(WAL)&_pragma=journal_size_limit(200000000)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(ON)&_pragma=temp_store(MEMORY)&_pragma=cache_size(-16000)"
|
pragmas := "?_pragma=busy_timeout(10000)&_pragma=journal_mode(WAL)&_pragma=journal_size_limit(200000000)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(ON)&_pragma=temp_store(MEMORY)&_pragma=cache_size(-32000)"
|
||||||
|
|
||||||
db, err := dbx.Open("sqlite", dbPath+pragmas)
|
db, err := dbx.Open("sqlite", dbPath+pragmas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -384,6 +384,13 @@ type FileDownloadRequestEvent struct {
|
||||||
FileField *FileField
|
FileField *FileField
|
||||||
ServedPath string
|
ServedPath string
|
||||||
ServedName string
|
ServedName string
|
||||||
|
|
||||||
|
// ThumbError indicates the a thumb wasn't able to be generated
|
||||||
|
// (e.g. because it didn't satisfy the support image formats or it timed out).
|
||||||
|
//
|
||||||
|
// Note that PocketBase fallbacks to the original file in case of a thumb error,
|
||||||
|
// but developers can check the field and provide their own custom thumb generation if necessary.
|
||||||
|
ThumbError error
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,22 @@ var (
|
||||||
_ RecordInterceptor = (*TextField)(nil)
|
_ RecordInterceptor = (*TextField)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var forbiddenPKCharacters = []string{
|
||||||
|
".", "/", `\`, "|", `"`, "'", "`",
|
||||||
|
"<", ">", ":", "?", "*", "%", "$",
|
||||||
|
"\000", "\t", "\n", "\r", " ",
|
||||||
|
}
|
||||||
|
|
||||||
|
// (see largestReservedPKLength)
|
||||||
|
var caseInsensitiveReservedPKs = []string{
|
||||||
|
// reserved Windows files names
|
||||||
|
"CON", "PRN", "AUX", "NUL",
|
||||||
|
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||||
|
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||||
|
}
|
||||||
|
|
||||||
|
const largestReservedPKLength = 4
|
||||||
|
|
||||||
// TextField defines "text" type field for storing any string value.
|
// TextField defines "text" type field for storing any string value.
|
||||||
//
|
//
|
||||||
// The respective zero record field value is empty string.
|
// The respective zero record field value is empty string.
|
||||||
|
|
@ -155,8 +171,6 @@ func (f *TextField) PrepareValue(record *Record, raw any) (any, error) {
|
||||||
return cast.ToString(raw), nil
|
return cast.ToString(raw), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var forbiddenPKChars = []string{"/", "\\"}
|
|
||||||
|
|
||||||
// ValidateValue implements [Field.ValidateValue] interface method.
|
// ValidateValue implements [Field.ValidateValue] interface method.
|
||||||
func (f *TextField) ValidateValue(ctx context.Context, app App, record *Record) error {
|
func (f *TextField) ValidateValue(ctx context.Context, app App, record *Record) error {
|
||||||
newVal, ok := record.GetRaw(f.Name).(string)
|
newVal, ok := record.GetRaw(f.Name).(string)
|
||||||
|
|
@ -178,15 +192,6 @@ func (f *TextField) ValidateValue(ctx context.Context, app App, record *Record)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// disallow PK special characters no matter of the Pattern validator to minimize
|
|
||||||
// side-effects when the primary key is used for example in a directory path
|
|
||||||
for _, c := range forbiddenPKChars {
|
|
||||||
if strings.Contains(newVal, c) {
|
|
||||||
return validation.NewError("validation_pk_forbidden", "The record primary key contains forbidden characters.").
|
|
||||||
SetParams(map[string]any{"forbidden": c})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this technically shouldn't be necessarily but again to
|
// this technically shouldn't be necessarily but again to
|
||||||
// minimize misuse of the Pattern validator that could cause
|
// minimize misuse of the Pattern validator that could cause
|
||||||
// side-effects on some platforms check for duplicates in a case-insensitive manner
|
// side-effects on some platforms check for duplicates in a case-insensitive manner
|
||||||
|
|
@ -226,7 +231,7 @@ func (f *TextField) ValidatePlainValue(value string) error {
|
||||||
length := len([]rune(value))
|
length := len([]rune(value))
|
||||||
|
|
||||||
if f.Min > 0 && length < f.Min {
|
if f.Min > 0 && length < f.Min {
|
||||||
return validation.NewError("validation_min_text_constraint", "Must be at least {{.min}} character(s)").
|
return validation.NewError("validation_min_text_constraint", "Must be at least {{.min}} character(s).").
|
||||||
SetParams(map[string]any{"min": f.Min})
|
SetParams(map[string]any{"min": f.Min})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,14 +241,34 @@ func (f *TextField) ValidatePlainValue(value string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if max > 0 && length > max {
|
if max > 0 && length > max {
|
||||||
return validation.NewError("validation_max_text_constraint", "Must be no more than {{.max}} character(s)").
|
return validation.NewError("validation_max_text_constraint", "Must be no more than {{.max}} character(s).").
|
||||||
SetParams(map[string]any{"max": max})
|
SetParams(map[string]any{"max": max})
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Pattern != "" {
|
if f.Pattern != "" {
|
||||||
match, _ := regexp.MatchString(f.Pattern, value)
|
match, _ := regexp.MatchString(f.Pattern, value)
|
||||||
if !match {
|
if !match {
|
||||||
return validation.NewError("validation_invalid_format", "Invalid value format")
|
return validation.NewError("validation_invalid_format", "Invalid value format.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// additional primary key checks to minimize eventual filesystem compatibility issues
|
||||||
|
// because the primary key is often used as a file/directory name
|
||||||
|
if f.PrimaryKey && f.Pattern != defaultLowercaseRecordIdPattern {
|
||||||
|
for _, ch := range forbiddenPKCharacters {
|
||||||
|
if strings.Contains(value, ch) {
|
||||||
|
return validation.NewError("validation_forbidden_pk_character", "'{{.ch}}' is not a valid primary key character.").
|
||||||
|
SetParams(map[string]any{"ch": ch})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if largestReservedPKLength >= length {
|
||||||
|
for _, reserved := range caseInsensitiveReservedPKs {
|
||||||
|
if strings.EqualFold(value, reserved) {
|
||||||
|
return validation.NewError("validation_reserved_pk", "The primary key '{{.reserved}}' is reserved and cannot be used.").
|
||||||
|
SetParams(map[string]any{"reserved": reserved})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ func TestTextFieldValidateValue(t *testing.T) {
|
||||||
&core.TextField{Name: "test", PrimaryKey: false},
|
&core.TextField{Name: "test", PrimaryKey: false},
|
||||||
func() *core.Record {
|
func() *core.Record {
|
||||||
record := core.NewRecord(collection)
|
record := core.NewRecord(collection)
|
||||||
record.SetRaw("test", "/")
|
record.SetRaw("test", "abc/")
|
||||||
return record
|
return record
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
|
|
@ -139,7 +139,37 @@ func TestTextFieldValidateValue(t *testing.T) {
|
||||||
&core.TextField{Name: "test", PrimaryKey: false},
|
&core.TextField{Name: "test", PrimaryKey: false},
|
||||||
func() *core.Record {
|
func() *core.Record {
|
||||||
record := core.NewRecord(collection)
|
record := core.NewRecord(collection)
|
||||||
record.SetRaw("test", "\\")
|
record.SetRaw("test", "abc\\")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"special forbidden character . (non-primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: false},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "abc.")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"special forbidden character ' ' (non-primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: false},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "ab c")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"special forbidden character * (non-primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: false},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "abc*")
|
||||||
return record
|
return record
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
|
|
@ -149,7 +179,7 @@ func TestTextFieldValidateValue(t *testing.T) {
|
||||||
&core.TextField{Name: "test", PrimaryKey: true},
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
func() *core.Record {
|
func() *core.Record {
|
||||||
record := core.NewRecord(collection)
|
record := core.NewRecord(collection)
|
||||||
record.SetRaw("test", "/")
|
record.SetRaw("test", "abc/")
|
||||||
return record
|
return record
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
|
|
@ -159,11 +189,71 @@ func TestTextFieldValidateValue(t *testing.T) {
|
||||||
&core.TextField{Name: "test", PrimaryKey: true},
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
func() *core.Record {
|
func() *core.Record {
|
||||||
record := core.NewRecord(collection)
|
record := core.NewRecord(collection)
|
||||||
record.SetRaw("test", "\\")
|
record.SetRaw("test", "abc\\")
|
||||||
return record
|
return record
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"special forbidden character . (primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "abc.")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"special forbidden character ' ' (primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "ab c")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"special forbidden character * (primaryKey; used in the realtime events too)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "abc*")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reserved pk literal (non-primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: false},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "aUx")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reserved pk literal (primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "aUx")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reserved pk literal (non-exact match, primaryKey)",
|
||||||
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
|
func() *core.Record {
|
||||||
|
record := core.NewRecord(collection)
|
||||||
|
record.SetRaw("test", "aUx-")
|
||||||
|
return record
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"zero field value (primaryKey)",
|
"zero field value (primaryKey)",
|
||||||
&core.TextField{Name: "test", PrimaryKey: true},
|
&core.TextField{Name: "test", PrimaryKey: true},
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ const (
|
||||||
issetModifier string = "isset"
|
issetModifier string = "isset"
|
||||||
lengthModifier string = "length"
|
lengthModifier string = "length"
|
||||||
lowerModifier string = "lower"
|
lowerModifier string = "lower"
|
||||||
|
changedModifier string = "changed"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ensure that `search.FieldResolver` interface is implemented
|
// ensure that `search.FieldResolver` interface is implemented
|
||||||
|
|
@ -48,6 +49,10 @@ type RecordFieldResolver struct {
|
||||||
allowedFields []string
|
allowedFields []string
|
||||||
joins []*join
|
joins []*join
|
||||||
allowHiddenFields bool
|
allowHiddenFields bool
|
||||||
|
// ---
|
||||||
|
listRuleJoins map[string]*Collection // tableAlias->collection
|
||||||
|
joinAliasSuffix string // used for uniqueness in the flatten collection list rule join
|
||||||
|
baseCollectionAlias string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllowedFields returns a copy of the resolver's allowed fields.
|
// AllowedFields returns a copy of the resolver's allowed fields.
|
||||||
|
|
@ -115,6 +120,8 @@ func NewRecordFieldResolver(
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo think of a better a way how to call it automatically after BuildExpr
|
||||||
|
//
|
||||||
// UpdateQuery implements `search.FieldResolver` interface.
|
// UpdateQuery implements `search.FieldResolver` interface.
|
||||||
//
|
//
|
||||||
// Conditionally updates the provided search query based on the
|
// Conditionally updates the provided search query based on the
|
||||||
|
|
@ -131,6 +138,49 @@ func (r *RecordFieldResolver) UpdateQuery(query *dbx.SelectQuery) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// note: for now the joins are not applied for multi-match conditions to avoid excessive checks
|
||||||
|
if len(r.listRuleJoins) > 0 {
|
||||||
|
for alias, c := range r.listRuleJoins {
|
||||||
|
err := r.updateQueryWithCollectionListRule(c, alias, query)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RecordFieldResolver) updateQueryWithCollectionListRule(c *Collection, tableAlias string, query *dbx.SelectQuery) error {
|
||||||
|
if r.allowHiddenFields || c == nil || c.ListRule == nil || *c.ListRule == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cloneR := *r
|
||||||
|
cloneR.joins = []*join{}
|
||||||
|
cloneR.baseCollection = c
|
||||||
|
cloneR.baseCollectionAlias = tableAlias
|
||||||
|
cloneR.allowHiddenFields = true
|
||||||
|
cloneR.joinAliasSuffix = security.PseudorandomString(6)
|
||||||
|
|
||||||
|
expr, err := search.FilterData(*c.ListRule).BuildExpr(&cloneR)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("to buld %q list rule join subquery filter expression: %w", c.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
query.AndWhere(expr)
|
||||||
|
|
||||||
|
if len(cloneR.joins) > 0 {
|
||||||
|
query.Distinct(true)
|
||||||
|
|
||||||
|
for _, j := range cloneR.joins {
|
||||||
|
query.LeftJoin(
|
||||||
|
(j.tableName + " " + j.tableAlias),
|
||||||
|
j.on,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -186,7 +236,7 @@ func (r *RecordFieldResolver) resolveStaticRequestField(path ...string) (*search
|
||||||
|
|
||||||
switch v := resultVal.(type) {
|
switch v := resultVal.(type) {
|
||||||
case nil:
|
case nil:
|
||||||
return &search.ResolverResult{Identifier: "NULL"}, nil
|
// no further processing is needed...
|
||||||
case string:
|
case string:
|
||||||
// check if it is a number field and explicitly try to cast to
|
// check if it is a number field and explicitly try to cast to
|
||||||
// float in case of a numeric string value was used
|
// float in case of a numeric string value was used
|
||||||
|
|
@ -216,8 +266,20 @@ func (r *RecordFieldResolver) resolveStaticRequestField(path ...string) (*search
|
||||||
resultVal = val
|
resultVal = val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unsupported modifier
|
||||||
|
// @todo consider deprecating with the introduction of filter functions
|
||||||
|
if modifier != "" && modifier != lowerModifier {
|
||||||
|
return nil, fmt.Errorf("invalid modifier sequence %s:%s", lastProp, modifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to wrap as placeholder if we already know that it is null
|
||||||
|
if resultVal == nil {
|
||||||
|
return &search.ResolverResult{Identifier: "NULL"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
placeholder := "f" + security.PseudorandomString(8)
|
placeholder := "f" + security.PseudorandomString(8)
|
||||||
|
|
||||||
|
// @todo consider deprecating with the introduction of filter functions
|
||||||
if modifier == lowerModifier {
|
if modifier == lowerModifier {
|
||||||
return &search.ResolverResult{
|
return &search.ResolverResult{
|
||||||
Identifier: "LOWER({:" + placeholder + "})",
|
Identifier: "LOWER({:" + placeholder + "})",
|
||||||
|
|
@ -239,23 +301,42 @@ func (r *RecordFieldResolver) loadCollection(collectionNameOrId string) (*Collec
|
||||||
return getCollectionByModelOrIdentifier(r.app, collectionNameOrId)
|
return getCollectionByModelOrIdentifier(r.app, collectionNameOrId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RecordFieldResolver) registerJoin(tableName string, tableAlias string, on dbx.Expression) {
|
func (r *RecordFieldResolver) registerJoin(tableName string, tableAlias string, on dbx.Expression) error {
|
||||||
join := &join{
|
newJoin := &join{
|
||||||
tableName: tableName,
|
tableName: tableName,
|
||||||
tableAlias: tableAlias,
|
tableAlias: tableAlias,
|
||||||
on: on,
|
on: on,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// (see updateQueryWithCollectionListRule)
|
||||||
|
if !r.allowHiddenFields {
|
||||||
|
c, _ := r.loadCollection(tableName)
|
||||||
|
|
||||||
|
// ignore non-collections since the table name could be an expression (e.g. json) or some other subquery
|
||||||
|
if c != nil {
|
||||||
|
// treat all fields as if they are hidden
|
||||||
|
if c.ListRule == nil {
|
||||||
|
return fmt.Errorf("%q fields can be accessed only when allowHiddenFields is enabled or by superusers", c.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.listRuleJoins == nil {
|
||||||
|
r.listRuleJoins = map[string]*Collection{}
|
||||||
|
}
|
||||||
|
r.listRuleJoins[newJoin.tableAlias] = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// replace existing join
|
// replace existing join
|
||||||
for i, j := range r.joins {
|
for i, j := range r.joins {
|
||||||
if j.tableAlias == join.tableAlias {
|
if j.tableAlias == newJoin.tableAlias {
|
||||||
r.joins[i] = join
|
r.joins[i] = newJoin
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// register new join
|
// register new join
|
||||||
r.joins = append(r.joins, join)
|
r.joins = append(r.joins, newJoin)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type mapExtractor interface {
|
type mapExtractor interface {
|
||||||
|
|
@ -395,7 +476,8 @@ func splitModifier(combined string) (string, string, error) {
|
||||||
case issetModifier,
|
case issetModifier,
|
||||||
eachModifier,
|
eachModifier,
|
||||||
lengthModifier,
|
lengthModifier,
|
||||||
lowerModifier:
|
lowerModifier,
|
||||||
|
changedModifier:
|
||||||
return parts[0], parts[1], nil
|
return parts[0], parts[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pocketbase/dbx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ dbx.Expression = (*replaceWithExpression)(nil)
|
||||||
|
|
||||||
|
// replaceWithExpression defines a custom expression that will replace
|
||||||
|
// a placeholder identifier found in "old" with the result of "new".
|
||||||
|
type replaceWithExpression struct {
|
||||||
|
placeholder string
|
||||||
|
old dbx.Expression
|
||||||
|
new dbx.Expression
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build converts the expression into a SQL fragment.
|
||||||
|
//
|
||||||
|
// Implements [dbx.Expression] interface.
|
||||||
|
func (e *replaceWithExpression) Build(db *dbx.DB, params dbx.Params) string {
|
||||||
|
if e.placeholder == "" || e.old == nil || e.new == nil {
|
||||||
|
return "0=1"
|
||||||
|
}
|
||||||
|
|
||||||
|
oldResult := e.old.Build(db, params)
|
||||||
|
newResult := e.new.Build(db, params)
|
||||||
|
|
||||||
|
return strings.ReplaceAll(oldResult, e.placeholder, newResult)
|
||||||
|
}
|
||||||
|
|
@ -52,7 +52,6 @@ type runner struct {
|
||||||
activeProps []string // holds the active props that remains to be processed
|
activeProps []string // holds the active props that remains to be processed
|
||||||
activeCollectionName string // the last used collection name
|
activeCollectionName string // the last used collection name
|
||||||
activeTableAlias string // the last used table alias
|
activeTableAlias string // the last used table alias
|
||||||
allowHiddenFields bool // indicates whether hidden fields (eg. email) should be allowed without extra conditions
|
|
||||||
nullifyMisingField bool // indicating whether to return null on missing field or return an error
|
nullifyMisingField bool // indicating whether to return null on missing field or return an error
|
||||||
withMultiMatch bool // indicates whether to attach a multiMatchSubquery condition to the ResolverResult
|
withMultiMatch bool // indicates whether to attach a multiMatchSubquery condition to the ResolverResult
|
||||||
multiMatchActiveTableAlias string // the last used multi-match table alias
|
multiMatchActiveTableAlias string // the last used multi-match table alias
|
||||||
|
|
@ -81,6 +80,7 @@ func (r *runner) run() (*search.ResolverResult, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.activeProps[0] == "@request" {
|
if r.activeProps[0] == "@request" {
|
||||||
|
// @todo consider returning an error instead?
|
||||||
if r.resolver.requestInfo == nil {
|
if r.resolver.requestInfo == nil {
|
||||||
return &search.ResolverResult{Identifier: "NULL"}, nil
|
return &search.ResolverResult{Identifier: "NULL"}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +89,9 @@ func (r *runner) run() (*search.ResolverResult, error) {
|
||||||
return r.processRequestAuthField()
|
return r.processRequestAuthField()
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(r.fieldName, "@request.body.") && len(r.activeProps) > 2 {
|
totalProps := len(r.activeProps)
|
||||||
|
|
||||||
|
if strings.HasPrefix(r.fieldName, "@request.body.") && totalProps > 2 {
|
||||||
name, modifier, err := splitModifier(r.activeProps[2])
|
name, modifier, err := splitModifier(r.activeProps[2])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -101,23 +103,21 @@ func (r *runner) run() (*search.ResolverResult, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for body relation field
|
// check for body relation field
|
||||||
if bodyField.Type() == FieldTypeRelation && len(r.activeProps) > 3 {
|
if bodyField.Type() == FieldTypeRelation && totalProps > 3 {
|
||||||
return r.processRequestInfoRelationField(bodyField)
|
return r.processRequestBodyRelationField(bodyField)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for body arrayble fields ":each" modifier
|
if totalProps == 3 { // aka. last prop
|
||||||
if modifier == eachModifier && len(r.activeProps) == 3 {
|
switch modifier {
|
||||||
return r.processRequestInfoEachModifier(bodyField)
|
case eachModifier:
|
||||||
|
return r.processRequestBodyEachModifier(bodyField)
|
||||||
|
case lengthModifier:
|
||||||
|
return r.processRequestBodyLengthModifier(bodyField)
|
||||||
|
case lowerModifier:
|
||||||
|
return r.processRequestBodyLowerModifier(bodyField)
|
||||||
|
case changedModifier:
|
||||||
|
return r.processRequestBodyChangedModifier(bodyField)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for body arrayble fields ":length" modifier
|
|
||||||
if modifier == lengthModifier && len(r.activeProps) == 3 {
|
|
||||||
return r.processRequestInfoLengthModifier(bodyField)
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for body arrayble fields ":lower" modifier
|
|
||||||
if modifier == lowerModifier && len(r.activeProps) == 3 {
|
|
||||||
return r.processRequestInfoLowerModifier(bodyField)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,12 +133,10 @@ func (r *runner) prepare() {
|
||||||
r.activeProps = strings.Split(r.fieldName, ".")
|
r.activeProps = strings.Split(r.fieldName, ".")
|
||||||
|
|
||||||
r.activeCollectionName = r.resolver.baseCollection.Name
|
r.activeCollectionName = r.resolver.baseCollection.Name
|
||||||
|
if r.resolver.baseCollectionAlias == "" {
|
||||||
r.activeTableAlias = inflector.Columnify(r.activeCollectionName)
|
r.activeTableAlias = inflector.Columnify(r.activeCollectionName)
|
||||||
|
} else {
|
||||||
r.allowHiddenFields = r.resolver.allowHiddenFields
|
r.activeTableAlias = r.resolver.baseCollectionAlias
|
||||||
// always allow hidden fields since the @.* filter is a system one
|
|
||||||
if r.activeProps[0] == "@collection" || r.activeProps[0] == "@request" {
|
|
||||||
r.allowHiddenFields = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable the ignore flag for missing @request.* fields for backward
|
// enable the ignore flag for missing @request.* fields for backward
|
||||||
|
|
@ -172,18 +170,21 @@ func (r *runner) processCollectionField() (*search.ResolverResult, error) {
|
||||||
r.activeCollectionName = collection.Name
|
r.activeCollectionName = collection.Name
|
||||||
|
|
||||||
if len(collectionParts) == 2 && collectionParts[1] != "" {
|
if len(collectionParts) == 2 && collectionParts[1] != "" {
|
||||||
r.activeTableAlias = inflector.Columnify("__collection_alias_" + collectionParts[1])
|
r.activeTableAlias = inflector.Columnify("__collection_alias_"+collectionParts[1]) + r.resolver.joinAliasSuffix
|
||||||
} else {
|
} else {
|
||||||
r.activeTableAlias = inflector.Columnify("__collection_" + r.activeCollectionName)
|
r.activeTableAlias = inflector.Columnify("__collection_"+r.activeCollectionName) + r.resolver.joinAliasSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
r.withMultiMatch = true
|
r.withMultiMatch = true
|
||||||
|
|
||||||
// join the collection to the main query
|
// join the collection to the main query
|
||||||
r.resolver.registerJoin(inflector.Columnify(collection.Name), r.activeTableAlias, nil)
|
err = r.resolver.registerJoin(inflector.Columnify(collection.Name), r.activeTableAlias, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// join the collection to the multi-match subquery
|
// join the collection to the multi-match subquery
|
||||||
r.multiMatchActiveTableAlias = "__mm" + r.activeTableAlias
|
r.multiMatchActiveTableAlias = "__mm_" + r.activeTableAlias
|
||||||
r.multiMatch.joins = append(r.multiMatch.joins, &join{
|
r.multiMatch.joins = append(r.multiMatch.joins, &join{
|
||||||
tableName: inflector.Columnify(collection.Name),
|
tableName: inflector.Columnify(collection.Name),
|
||||||
tableAlias: r.multiMatchActiveTableAlias,
|
tableAlias: r.multiMatchActiveTableAlias,
|
||||||
|
|
@ -212,10 +213,10 @@ func (r *runner) processRequestAuthField() (*search.ResolverResult, error) {
|
||||||
collection := r.resolver.requestInfo.Auth.Collection()
|
collection := r.resolver.requestInfo.Auth.Collection()
|
||||||
|
|
||||||
r.activeCollectionName = collection.Name
|
r.activeCollectionName = collection.Name
|
||||||
r.activeTableAlias = "__auth_" + inflector.Columnify(r.activeCollectionName)
|
r.activeTableAlias = "__auth_" + inflector.Columnify(r.activeCollectionName) + r.resolver.joinAliasSuffix
|
||||||
|
|
||||||
// join the auth collection to the main query
|
// join the auth collection to the main query
|
||||||
r.resolver.registerJoin(
|
err := r.resolver.registerJoin(
|
||||||
inflector.Columnify(r.activeCollectionName),
|
inflector.Columnify(r.activeCollectionName),
|
||||||
r.activeTableAlias,
|
r.activeTableAlias,
|
||||||
dbx.HashExp{
|
dbx.HashExp{
|
||||||
|
|
@ -223,6 +224,9 @@ func (r *runner) processRequestAuthField() (*search.ResolverResult, error) {
|
||||||
(r.activeTableAlias + ".id"): r.resolver.requestInfo.Auth.Id,
|
(r.activeTableAlias + ".id"): r.resolver.requestInfo.Auth.Id,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// join the auth collection to the multi-match subquery
|
// join the auth collection to the multi-match subquery
|
||||||
r.multiMatchActiveTableAlias = "__mm_" + r.activeTableAlias
|
r.multiMatchActiveTableAlias = "__mm_" + r.activeTableAlias
|
||||||
|
|
@ -268,7 +272,34 @@ func toSlice(value any) []any {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) processRequestInfoLowerModifier(bodyField Field) (*search.ResolverResult, error) {
|
func (r *runner) processRequestBodyChangedModifier(bodyField Field) (*search.ResolverResult, error) {
|
||||||
|
name := bodyField.GetName()
|
||||||
|
|
||||||
|
alias := search.FilterData(fmt.Sprintf("@request.body.%s:isset = true && @request.body.%s != %s", name, name, name))
|
||||||
|
|
||||||
|
aliasExpr, err := alias.BuildExpr(r.resolver)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
placeholder := "@changed@" + name + security.PseudorandomString(6)
|
||||||
|
|
||||||
|
result := &search.ResolverResult{
|
||||||
|
Identifier: placeholder,
|
||||||
|
NoCoalesce: true,
|
||||||
|
AfterBuild: func(expr dbx.Expression) dbx.Expression {
|
||||||
|
return &replaceWithExpression{
|
||||||
|
placeholder: placeholder,
|
||||||
|
old: expr,
|
||||||
|
new: aliasExpr,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *runner) processRequestBodyLowerModifier(bodyField Field) (*search.ResolverResult, error) {
|
||||||
rawValue := cast.ToString(r.resolver.requestInfo.Body[bodyField.GetName()])
|
rawValue := cast.ToString(r.resolver.requestInfo.Body[bodyField.GetName()])
|
||||||
|
|
||||||
placeholder := "infoLower" + bodyField.GetName() + security.PseudorandomString(6)
|
placeholder := "infoLower" + bodyField.GetName() + security.PseudorandomString(6)
|
||||||
|
|
@ -281,7 +312,7 @@ func (r *runner) processRequestInfoLowerModifier(bodyField Field) (*search.Resol
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) processRequestInfoLengthModifier(bodyField Field) (*search.ResolverResult, error) {
|
func (r *runner) processRequestBodyLengthModifier(bodyField Field) (*search.ResolverResult, error) {
|
||||||
if _, ok := bodyField.(MultiValuer); !ok {
|
if _, ok := bodyField.(MultiValuer); !ok {
|
||||||
return nil, fmt.Errorf("field %q doesn't support multivalue operations", bodyField.GetName())
|
return nil, fmt.Errorf("field %q doesn't support multivalue operations", bodyField.GetName())
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +326,7 @@ func (r *runner) processRequestInfoLengthModifier(bodyField Field) (*search.Reso
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) processRequestInfoEachModifier(bodyField Field) (*search.ResolverResult, error) {
|
func (r *runner) processRequestBodyEachModifier(bodyField Field) (*search.ResolverResult, error) {
|
||||||
multiValuer, ok := bodyField.(MultiValuer)
|
multiValuer, ok := bodyField.(MultiValuer)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("field %q doesn't support multivalue operations", bodyField.GetName())
|
return nil, fmt.Errorf("field %q doesn't support multivalue operations", bodyField.GetName())
|
||||||
|
|
@ -310,8 +341,12 @@ func (r *runner) processRequestInfoEachModifier(bodyField Field) (*search.Resolv
|
||||||
placeholder := "dataEach" + security.PseudorandomString(6)
|
placeholder := "dataEach" + security.PseudorandomString(6)
|
||||||
cleanFieldName := inflector.Columnify(bodyField.GetName())
|
cleanFieldName := inflector.Columnify(bodyField.GetName())
|
||||||
jeTable := fmt.Sprintf("json_each({:%s})", placeholder)
|
jeTable := fmt.Sprintf("json_each({:%s})", placeholder)
|
||||||
jeAlias := "__dataEach_" + cleanFieldName + "_je"
|
jeAlias := "__dataEach_je_" + cleanFieldName + r.resolver.joinAliasSuffix
|
||||||
r.resolver.registerJoin(jeTable, jeAlias, nil)
|
|
||||||
|
err = r.resolver.registerJoin(jeTable, jeAlias, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
result := &search.ResolverResult{
|
result := &search.ResolverResult{
|
||||||
Identifier: fmt.Sprintf("[[%s.value]]", jeAlias),
|
Identifier: fmt.Sprintf("[[%s.value]]", jeAlias),
|
||||||
|
|
@ -325,7 +360,7 @@ func (r *runner) processRequestInfoEachModifier(bodyField Field) (*search.Resolv
|
||||||
if r.withMultiMatch {
|
if r.withMultiMatch {
|
||||||
placeholder2 := "mm" + placeholder
|
placeholder2 := "mm" + placeholder
|
||||||
jeTable2 := fmt.Sprintf("json_each({:%s})", placeholder2)
|
jeTable2 := fmt.Sprintf("json_each({:%s})", placeholder2)
|
||||||
jeAlias2 := "__mm" + jeAlias
|
jeAlias2 := "__mm_" + jeAlias
|
||||||
|
|
||||||
r.multiMatch.joins = append(r.multiMatch.joins, &join{
|
r.multiMatch.joins = append(r.multiMatch.joins, &join{
|
||||||
tableName: jeTable2,
|
tableName: jeTable2,
|
||||||
|
|
@ -340,7 +375,7 @@ func (r *runner) processRequestInfoEachModifier(bodyField Field) (*search.Resolv
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) processRequestInfoRelationField(bodyField Field) (*search.ResolverResult, error) {
|
func (r *runner) processRequestBodyRelationField(bodyField Field) (*search.ResolverResult, error) {
|
||||||
relField, ok := bodyField.(*RelationField)
|
relField, ok := bodyField.(*RelationField)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to initialize data relation field %q", bodyField.GetName())
|
return nil, fmt.Errorf("failed to initialize data relation field %q", bodyField.GetName())
|
||||||
|
|
@ -360,10 +395,10 @@ func (r *runner) processRequestInfoRelationField(bodyField Field) (*search.Resol
|
||||||
}
|
}
|
||||||
|
|
||||||
r.activeCollectionName = dataRelCollection.Name
|
r.activeCollectionName = dataRelCollection.Name
|
||||||
r.activeTableAlias = inflector.Columnify("__data_" + dataRelCollection.Name + "_" + relField.Name)
|
r.activeTableAlias = inflector.Columnify("__data_"+dataRelCollection.Name+"_"+relField.Name) + r.resolver.joinAliasSuffix
|
||||||
|
|
||||||
// join the data rel collection to the main collection
|
// join the data rel collection to the main collection
|
||||||
r.resolver.registerJoin(
|
err = r.resolver.registerJoin(
|
||||||
r.activeCollectionName,
|
r.activeCollectionName,
|
||||||
r.activeTableAlias,
|
r.activeTableAlias,
|
||||||
dbx.In(
|
dbx.In(
|
||||||
|
|
@ -371,13 +406,16 @@ func (r *runner) processRequestInfoRelationField(bodyField Field) (*search.Resol
|
||||||
list.ToInterfaceSlice(dataRelIds)...,
|
list.ToInterfaceSlice(dataRelIds)...,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if relField.IsMultiple() {
|
if relField.IsMultiple() {
|
||||||
r.withMultiMatch = true
|
r.withMultiMatch = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// join the data rel collection to the multi-match subquery
|
// join the data rel collection to the multi-match subquery
|
||||||
r.multiMatchActiveTableAlias = inflector.Columnify("__data_mm_" + dataRelCollection.Name + "_" + relField.Name)
|
r.multiMatchActiveTableAlias = "__mm_" + r.activeTableAlias
|
||||||
r.multiMatch.joins = append(
|
r.multiMatch.joins = append(
|
||||||
r.multiMatch.joins,
|
r.multiMatch.joins,
|
||||||
&join{
|
&join{
|
||||||
|
|
@ -399,6 +437,7 @@ func (r *runner) processRequestInfoRelationField(bodyField Field) (*search.Resol
|
||||||
|
|
||||||
var viaRegex = regexp.MustCompile(`^(\w+)_via_(\w+)$`)
|
var viaRegex = regexp.MustCompile(`^(\w+)_via_(\w+)$`)
|
||||||
|
|
||||||
|
// @todo refactor and abstract lastProp processing with the support of field plugins
|
||||||
func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
totalProps := len(r.activeProps)
|
totalProps := len(r.activeProps)
|
||||||
|
|
||||||
|
|
@ -410,17 +449,17 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
|
|
||||||
// last prop
|
// last prop
|
||||||
if i == totalProps-1 {
|
if i == totalProps-1 {
|
||||||
return r.processLastProp(collection, prop)
|
return r.finalizeActivePropsProcessing(collection, prop, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
field := collection.Fields.GetByName(prop)
|
field := collection.Fields.GetByName(prop)
|
||||||
|
|
||||||
if field != nil && field.GetHidden() && !r.allowHiddenFields {
|
if field != nil && field.GetHidden() && !r.resolver.allowHiddenFields {
|
||||||
return nil, fmt.Errorf("non-filterable field %q", prop)
|
return nil, fmt.Errorf("non-filterable field %q", prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo consider moving to the finalizer and converting to "JSONExtractable" interface with optional extra validation for the remaining props?
|
||||||
// json or geoPoint field -> treat the rest of the props as json path
|
// json or geoPoint field -> treat the rest of the props as json path
|
||||||
// @todo consider converting to "JSONExtractable" interface with optional extra validation for the remaining props?
|
|
||||||
if field != nil && (field.Type() == FieldTypeJSON || field.Type() == FieldTypeGeoPoint) {
|
if field != nil && (field.Type() == FieldTypeJSON || field.Type() == FieldTypeGeoPoint) {
|
||||||
var jsonPath strings.Builder
|
var jsonPath strings.Builder
|
||||||
for j, p := range r.activeProps[i+1:] {
|
for j, p := range r.activeProps[i+1:] {
|
||||||
|
|
@ -488,7 +527,7 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
return nil, fmt.Errorf("invalid back relation field %q", parts[2])
|
return nil, fmt.Errorf("invalid back relation field %q", parts[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
if backField.GetHidden() && !r.allowHiddenFields {
|
if backField.GetHidden() && !r.resolver.allowHiddenFields {
|
||||||
return nil, fmt.Errorf("non-filterable back relation field %q", backField.GetName())
|
return nil, fmt.Errorf("non-filterable back relation field %q", backField.GetName())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -508,7 +547,7 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
// ---
|
// ---
|
||||||
cleanProp := inflector.Columnify(prop)
|
cleanProp := inflector.Columnify(prop)
|
||||||
cleanBackFieldName := inflector.Columnify(backRelField.Name)
|
cleanBackFieldName := inflector.Columnify(backRelField.Name)
|
||||||
newTableAlias := r.activeTableAlias + "_" + cleanProp
|
newTableAlias := r.activeTableAlias + "_" + cleanProp + r.resolver.joinAliasSuffix
|
||||||
newCollectionName := inflector.Columnify(backCollection.Name)
|
newCollectionName := inflector.Columnify(backCollection.Name)
|
||||||
|
|
||||||
isBackRelMultiple := backRelField.IsMultiple()
|
isBackRelMultiple := backRelField.IsMultiple()
|
||||||
|
|
@ -519,14 +558,17 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isBackRelMultiple {
|
if !isBackRelMultiple {
|
||||||
r.resolver.registerJoin(
|
err := r.resolver.registerJoin(
|
||||||
newCollectionName,
|
newCollectionName,
|
||||||
newTableAlias,
|
newTableAlias,
|
||||||
dbx.NewExp(fmt.Sprintf("[[%s.%s]] = [[%s.id]]", newTableAlias, cleanBackFieldName, r.activeTableAlias)),
|
dbx.NewExp(fmt.Sprintf("[[%s.%s]] = [[%s.id]]", newTableAlias, cleanBackFieldName, r.activeTableAlias)),
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
jeAlias := r.activeTableAlias + "_" + cleanProp + "_je"
|
jeAlias := "__je_" + newTableAlias
|
||||||
r.resolver.registerJoin(
|
err := r.resolver.registerJoin(
|
||||||
newCollectionName,
|
newCollectionName,
|
||||||
newTableAlias,
|
newTableAlias,
|
||||||
dbx.NewExp(fmt.Sprintf(
|
dbx.NewExp(fmt.Sprintf(
|
||||||
|
|
@ -537,6 +579,9 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
jeAlias,
|
jeAlias,
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.activeCollectionName = newCollectionName
|
r.activeCollectionName = newCollectionName
|
||||||
|
|
@ -549,7 +594,7 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
r.withMultiMatch = true // enable multimatch if not already
|
r.withMultiMatch = true // enable multimatch if not already
|
||||||
}
|
}
|
||||||
|
|
||||||
newTableAlias2 := r.multiMatchActiveTableAlias + "_" + cleanProp
|
newTableAlias2 := r.multiMatchActiveTableAlias + "_" + cleanProp + r.resolver.joinAliasSuffix
|
||||||
|
|
||||||
if !isBackRelMultiple {
|
if !isBackRelMultiple {
|
||||||
r.multiMatch.joins = append(
|
r.multiMatch.joins = append(
|
||||||
|
|
@ -561,7 +606,7 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
jeAlias2 := r.multiMatchActiveTableAlias + "_" + cleanProp + "_je"
|
jeAlias2 := "__je_" + newTableAlias2
|
||||||
r.multiMatch.joins = append(
|
r.multiMatch.joins = append(
|
||||||
r.multiMatch.joins,
|
r.multiMatch.joins,
|
||||||
&join{
|
&join{
|
||||||
|
|
@ -607,28 +652,39 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
if !relField.IsMultiple() &&
|
if !relField.IsMultiple() &&
|
||||||
// the penultimate prop is "id"
|
// the penultimate prop is "id"
|
||||||
i == totalProps-2 && r.activeProps[i+1] == FieldNameId {
|
i == totalProps-2 && r.activeProps[i+1] == FieldNameId {
|
||||||
return r.processLastProp(collection, relField.Name)
|
return r.finalizeActivePropsProcessing(collection, relField.Name, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanFieldName := inflector.Columnify(relField.Name)
|
cleanFieldName := inflector.Columnify(relField.Name)
|
||||||
prefixedFieldName := r.activeTableAlias + "." + cleanFieldName
|
prefixedFieldName := r.activeTableAlias + "." + cleanFieldName
|
||||||
newTableAlias := r.activeTableAlias + "_" + cleanFieldName
|
newTableAlias := r.activeTableAlias + "_" + cleanFieldName + r.resolver.joinAliasSuffix
|
||||||
newCollectionName := relCollection.Name
|
newCollectionName := relCollection.Name
|
||||||
|
|
||||||
if !relField.IsMultiple() {
|
if !relField.IsMultiple() {
|
||||||
r.resolver.registerJoin(
|
err := r.resolver.registerJoin(
|
||||||
inflector.Columnify(newCollectionName),
|
inflector.Columnify(newCollectionName),
|
||||||
newTableAlias,
|
newTableAlias,
|
||||||
dbx.NewExp(fmt.Sprintf("[[%s.id]] = [[%s]]", newTableAlias, prefixedFieldName)),
|
dbx.NewExp(fmt.Sprintf("[[%s.id]] = [[%s]]", newTableAlias, prefixedFieldName)),
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
jeAlias := r.activeTableAlias + "_" + cleanFieldName + "_je"
|
jeAlias := "__je_" + newTableAlias
|
||||||
r.resolver.registerJoin(dbutils.JSONEach(prefixedFieldName), jeAlias, nil)
|
|
||||||
r.resolver.registerJoin(
|
err := r.resolver.registerJoin(dbutils.JSONEach(prefixedFieldName), jeAlias, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = r.resolver.registerJoin(
|
||||||
inflector.Columnify(newCollectionName),
|
inflector.Columnify(newCollectionName),
|
||||||
newTableAlias,
|
newTableAlias,
|
||||||
dbx.NewExp(fmt.Sprintf("[[%s.id]] = [[%s.value]]", newTableAlias, jeAlias)),
|
dbx.NewExp(fmt.Sprintf("[[%s.id]] = [[%s.value]]", newTableAlias, jeAlias)),
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.activeCollectionName = newCollectionName
|
r.activeCollectionName = newCollectionName
|
||||||
|
|
@ -676,7 +732,7 @@ func (r *runner) processActiveProps() (*search.ResolverResult, error) {
|
||||||
return nil, fmt.Errorf("failed to resolve field %q", r.fieldName)
|
return nil, fmt.Errorf("failed to resolve field %q", r.fieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *runner) processLastProp(collection *Collection, prop string) (*search.ResolverResult, error) {
|
func (r *runner) finalizeActivePropsProcessing(collection *Collection, prop string, propDepth int) (*search.ResolverResult, error) {
|
||||||
name, modifier, err := splitModifier(prop)
|
name, modifier, err := splitModifier(prop)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -690,7 +746,7 @@ func (r *runner) processLastProp(collection *Collection, prop string) (*search.R
|
||||||
return nil, fmt.Errorf("unknown field %q", name)
|
return nil, fmt.Errorf("unknown field %q", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if field.GetHidden() && !r.allowHiddenFields {
|
if field.GetHidden() && !r.resolver.allowHiddenFields {
|
||||||
return nil, fmt.Errorf("non-filterable field %q", name)
|
return nil, fmt.Errorf("non-filterable field %q", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -720,8 +776,12 @@ func (r *runner) processLastProp(collection *Collection, prop string) (*search.R
|
||||||
// -------------------------------------------------------
|
// -------------------------------------------------------
|
||||||
if modifier == eachModifier && isMultivaluer {
|
if modifier == eachModifier && isMultivaluer {
|
||||||
jePair := r.activeTableAlias + "." + cleanFieldName
|
jePair := r.activeTableAlias + "." + cleanFieldName
|
||||||
jeAlias := r.activeTableAlias + "_" + cleanFieldName + "_je"
|
jeAlias := "__je_" + r.activeTableAlias + "_" + cleanFieldName + r.resolver.joinAliasSuffix
|
||||||
r.resolver.registerJoin(dbutils.JSONEach(jePair), jeAlias, nil)
|
|
||||||
|
err := r.resolver.registerJoin(dbutils.JSONEach(jePair), jeAlias, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
result := &search.ResolverResult{
|
result := &search.ResolverResult{
|
||||||
Identifier: fmt.Sprintf("[[%s.value]]", jeAlias),
|
Identifier: fmt.Sprintf("[[%s.value]]", jeAlias),
|
||||||
|
|
@ -733,7 +793,7 @@ func (r *runner) processLastProp(collection *Collection, prop string) (*search.R
|
||||||
|
|
||||||
if r.withMultiMatch {
|
if r.withMultiMatch {
|
||||||
jePair2 := r.multiMatchActiveTableAlias + "." + cleanFieldName
|
jePair2 := r.multiMatchActiveTableAlias + "." + cleanFieldName
|
||||||
jeAlias2 := r.multiMatchActiveTableAlias + "_" + cleanFieldName + "_je"
|
jeAlias2 := "__je_" + r.multiMatchActiveTableAlias + "_" + cleanFieldName + r.resolver.joinAliasSuffix
|
||||||
|
|
||||||
r.multiMatch.joins = append(r.multiMatch.joins, &join{
|
r.multiMatch.joins = append(r.multiMatch.joins, &join{
|
||||||
tableName: dbutils.JSONEach(jePair2),
|
tableName: dbutils.JSONEach(jePair2),
|
||||||
|
|
@ -759,7 +819,7 @@ func (r *runner) processLastProp(collection *Collection, prop string) (*search.R
|
||||||
}
|
}
|
||||||
|
|
||||||
// allow querying only auth records with emails marked as public
|
// allow querying only auth records with emails marked as public
|
||||||
if field.GetName() == FieldNameEmail && !r.allowHiddenFields && collection.IsAuth() {
|
if field.GetName() == FieldNameEmail && !r.resolver.allowHiddenFields && collection.IsAuth() {
|
||||||
result.AfterBuild = func(expr dbx.Expression) dbx.Expression {
|
result.AfterBuild = func(expr dbx.Expression) dbx.Expression {
|
||||||
return dbx.Enclose(dbx.And(expr, dbx.NewExp(fmt.Sprintf(
|
return dbx.Enclose(dbx.And(expr, dbx.NewExp(fmt.Sprintf(
|
||||||
"[[%s.%s]] = TRUE",
|
"[[%s.%s]] = TRUE",
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -397,7 +397,10 @@ func (app *BaseApp) FindRecordsByFilter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolver.UpdateQuery(q) // attaches any adhoc joins and aliases
|
err = resolver.UpdateQuery(q) // attaches any adhoc joins and aliases
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
if offset > 0 {
|
if offset > 0 {
|
||||||
|
|
@ -611,7 +614,11 @@ func (app *BaseApp) CanAccessRecord(record *Record, requestInfo *RequestInfo, ac
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
resolver.UpdateQuery(query)
|
|
||||||
|
err = resolver.UpdateQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
err = query.AndWhere(expr).Limit(1).Row(&exists)
|
err = query.AndWhere(expr).Limit(1).Row(&exists)
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/go-ozzo/ozzo-validation/v4/is"
|
"github.com/go-ozzo/ozzo-validation/v4/is"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/mails"
|
"github.com/pocketbase/pocketbase/mails"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -109,7 +110,8 @@ func (form *TestEmailSend) Submit() error {
|
||||||
case TestTemplateOTP:
|
case TestTemplateOTP:
|
||||||
return mails.SendRecordOTP(form.app, record, "_PB_TEST_OTP_ID_", "123456")
|
return mails.SendRecordOTP(form.app, record, "_PB_TEST_OTP_ID_", "123456")
|
||||||
case TestTemplateAuthAlert:
|
case TestTemplateAuthAlert:
|
||||||
return mails.SendRecordAuthAlert(form.app, record)
|
testEvent := types.NowDateTime().String() + " - TEST_IP TEST_USER_AGENT"
|
||||||
|
return mails.SendRecordAuthAlert(form.app, record, testEvent)
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown template " + form.Template)
|
return errors.New("unknown template " + form.Template)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
28
go.mod
28
go.mod
|
|
@ -5,11 +5,11 @@ go 1.24.0
|
||||||
require (
|
require (
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/domodwyer/mailyak/v3 v3.6.2
|
github.com/domodwyer/mailyak/v3 v3.6.2
|
||||||
github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994
|
github.com/dop251/goja v0.0.0-20251103141225-af2ceb9156d7
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20250409162600-f7acab6894b0
|
github.com/dop251/goja_nodejs v0.0.0-20250409162600-f7acab6894b0
|
||||||
github.com/fatih/color v1.18.0
|
github.com/fatih/color v1.18.0
|
||||||
github.com/fsnotify/fsnotify v1.7.0
|
github.com/fsnotify/fsnotify v1.7.0
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10
|
github.com/gabriel-vasile/mimetype v1.4.11
|
||||||
github.com/ganigeorgiev/fexpr v0.5.0
|
github.com/ganigeorgiev/fexpr v0.5.0
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0
|
github.com/golang-jwt/jwt/v5 v5.3.0
|
||||||
|
|
@ -17,12 +17,12 @@ require (
|
||||||
github.com/pocketbase/tygoja v0.0.0-20250812183945-97ffe055281f
|
github.com/pocketbase/tygoja v0.0.0-20250812183945-97ffe055281f
|
||||||
github.com/spf13/cast v1.10.0
|
github.com/spf13/cast v1.10.0
|
||||||
github.com/spf13/cobra v1.10.1
|
github.com/spf13/cobra v1.10.1
|
||||||
golang.org/x/crypto v0.43.0
|
golang.org/x/crypto v0.45.0
|
||||||
golang.org/x/image v0.32.0
|
golang.org/x/image v0.33.0
|
||||||
golang.org/x/net v0.46.0
|
golang.org/x/net v0.47.0
|
||||||
golang.org/x/oauth2 v0.32.0
|
golang.org/x/oauth2 v0.33.0
|
||||||
golang.org/x/sync v0.17.0
|
golang.org/x/sync v0.18.0
|
||||||
modernc.org/sqlite v1.39.1
|
modernc.org/sqlite v1.40.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|
@ -31,7 +31,7 @@ require (
|
||||||
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217 // indirect
|
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.4+incompatible // indirect
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect
|
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
|
|
@ -39,11 +39,11 @@ require (
|
||||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b // indirect
|
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
|
||||||
golang.org/x/mod v0.29.0 // indirect
|
golang.org/x/mod v0.30.0 // indirect
|
||||||
golang.org/x/sys v0.37.0 // indirect
|
golang.org/x/sys v0.38.0 // indirect
|
||||||
golang.org/x/text v0.30.0 // indirect
|
golang.org/x/text v0.31.0 // indirect
|
||||||
golang.org/x/tools v0.38.0 // indirect
|
golang.org/x/tools v0.39.0 // indirect
|
||||||
modernc.org/libc v1.66.10 // indirect
|
modernc.org/libc v1.66.10 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.11.0 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
|
|
|
||||||
56
go.sum
56
go.sum
|
|
@ -14,8 +14,8 @@ github.com/domodwyer/mailyak/v3 v3.6.2 h1:x3tGMsyFhTCaxp6ycgR0FE/bu5QiNp+hetUuCO
|
||||||
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
github.com/domodwyer/mailyak/v3 v3.6.2/go.mod h1:lOm/u9CyCVWHeaAmHIdF4RiKVxKUT/H5XX10lIKAL6c=
|
||||||
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217 h1:16iT9CBDOniJwFGPI41MbUDfEk74hFaKTqudrX8kenY=
|
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217 h1:16iT9CBDOniJwFGPI41MbUDfEk74hFaKTqudrX8kenY=
|
||||||
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217/go.mod h1:eIb+f24U+eWQCIsj9D/ah+MD9UP+wdxuqzsdLD+mhGM=
|
github.com/dop251/base64dec v0.0.0-20231022112746-c6c9f9a96217/go.mod h1:eIb+f24U+eWQCIsj9D/ah+MD9UP+wdxuqzsdLD+mhGM=
|
||||||
github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994 h1:aQYWswi+hRL2zJqGacdCZx32XjKYV8ApXFGntw79XAM=
|
github.com/dop251/goja v0.0.0-20251103141225-af2ceb9156d7 h1:jxmXU5V9tXxJnydU5v/m9SG8TRUa/Z7IXODBpMs/P+U=
|
||||||
github.com/dop251/goja v0.0.0-20250630131328-58d95d85e994/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
|
github.com/dop251/goja v0.0.0-20251103141225-af2ceb9156d7/go.mod h1:MxLav0peU43GgvwVgNbLAj1s/bSGboKkhuULvq/7hx4=
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20250409162600-f7acab6894b0 h1:fuHXpEVTTk7TilRdfGRLHpiTD6tnT0ihEowCfWjlFvw=
|
github.com/dop251/goja_nodejs v0.0.0-20250409162600-f7acab6894b0 h1:fuHXpEVTTk7TilRdfGRLHpiTD6tnT0ihEowCfWjlFvw=
|
||||||
github.com/dop251/goja_nodejs v0.0.0-20250409162600-f7acab6894b0/go.mod h1:Tb7Xxye4LX7cT3i8YLvmPMGCV92IOi4CDZvm/V8ylc0=
|
github.com/dop251/goja_nodejs v0.0.0-20250409162600-f7acab6894b0/go.mod h1:Tb7Xxye4LX7cT3i8YLvmPMGCV92IOi4CDZvm/V8ylc0=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
|
|
@ -26,8 +26,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||||
github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
|
github.com/ganigeorgiev/fexpr v0.5.0 h1:XA9JxtTE/Xm+g/JFI6RfZEHSiQlk+1glLvRK1Lpv/Tk=
|
||||||
github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
github.com/ganigeorgiev/fexpr v0.5.0/go.mod h1:RyGiGqmeXhEQ6+mlGdnUleLHgtzzu/VGO2WtJkF5drE=
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
|
||||||
|
|
@ -41,8 +41,8 @@ github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArs
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d h1:KJIErDwbSHjnp/SGzE5ed8Aol7JsKiI5X7yWKAtzhM0=
|
||||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
github.com/google/pprof v0.0.0-20251007162407-5df77e3f7d1d/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
|
@ -79,33 +79,33 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
|
||||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||||
golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA=
|
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
|
||||||
golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
|
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.32.0 h1:6lZQWq75h7L5IWNk0r+SCpUJ6tUVd3v4ZHnbRKLkUDQ=
|
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
|
||||||
golang.org/x/image v0.32.0/go.mod h1:/R37rrQmKXtO6tYXAjtDLwQgFLHmhW+V6ayXlxzP2Pc=
|
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
|
||||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
|
||||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
|
||||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
|
||||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|
@ -133,8 +133,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||||
modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4=
|
modernc.org/sqlite v1.40.1 h1:VfuXcxcUWWKRBuP8+BR9L7VnmusMgBNNnBYGEe9w/iY=
|
||||||
modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=
|
modernc.org/sqlite v1.40.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=
|
||||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// SendRecordAuthAlert sends a new device login alert to the specified auth record.
|
// SendRecordAuthAlert sends a new device login alert to the specified auth record.
|
||||||
func SendRecordAuthAlert(app core.App, authRecord *core.Record) error {
|
func SendRecordAuthAlert(app core.App, authRecord *core.Record, info string) error {
|
||||||
mailClient := app.NewMailClient()
|
mailClient := app.NewMailClient()
|
||||||
|
|
||||||
subject, body, err := resolveEmailTemplate(app, authRecord, authRecord.Collection().AuthAlert.EmailTemplate, nil)
|
info = html.EscapeString(info)
|
||||||
|
|
||||||
|
subject, body, err := resolveEmailTemplate(app, authRecord, authRecord.Collection().AuthAlert.EmailTemplate, map[string]any{
|
||||||
|
core.EmailPlaceholderAlertInfo: info,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -35,6 +39,9 @@ func SendRecordAuthAlert(app core.App, authRecord *core.Record) error {
|
||||||
event.Mailer = mailClient
|
event.Mailer = mailClient
|
||||||
event.Message = message
|
event.Message = message
|
||||||
event.Record = authRecord
|
event.Record = authRecord
|
||||||
|
event.Meta = map[string]any{
|
||||||
|
"info": info,
|
||||||
|
}
|
||||||
|
|
||||||
return app.OnMailerRecordAuthAlertSend().Trigger(event, func(e *core.MailerRecordEvent) error {
|
return app.OnMailerRecordAuthAlertSend().Trigger(event, func(e *core.MailerRecordEvent) error {
|
||||||
return e.Mailer.Send(e.Message)
|
return e.Mailer.Send(e.Message)
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,14 @@ func TestSendRecordAuthAlert(t *testing.T) {
|
||||||
testApp, _ := tests.NewTestApp()
|
testApp, _ := tests.NewTestApp()
|
||||||
defer testApp.Cleanup()
|
defer testApp.Cleanup()
|
||||||
|
|
||||||
|
info := "<p>test_info</p>"
|
||||||
|
|
||||||
user, _ := testApp.FindFirstRecordByData("users", "email", "test@example.com")
|
user, _ := testApp.FindFirstRecordByData("users", "email", "test@example.com")
|
||||||
|
|
||||||
// to test that it is escaped
|
// to test that it is escaped
|
||||||
user.Set("name", "<p>"+user.GetString("name")+"</p>")
|
user.Set("name", "<p>"+user.GetString("name")+"</p>")
|
||||||
|
|
||||||
err := mails.SendRecordAuthAlert(testApp, user)
|
err := mails.SendRecordAuthAlert(testApp, user, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -34,6 +36,7 @@ func TestSendRecordAuthAlert(t *testing.T) {
|
||||||
"login to your " + testApp.Settings().Meta.AppName + " account from a new location",
|
"login to your " + testApp.Settings().Meta.AppName + " account from a new location",
|
||||||
"If this was you",
|
"If this was you",
|
||||||
"If this wasn't you",
|
"If this wasn't you",
|
||||||
|
html.EscapeString(info),
|
||||||
}
|
}
|
||||||
for _, part := range expectedParts {
|
for _, part := range expectedParts {
|
||||||
if !strings.Contains(testApp.TestMailer.LastMessage().HTML, part) {
|
if !strings.Contains(testApp.TestMailer.LastMessage().HTML, part) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
const oldAuthAlertTemplate = `<p>Hello,</p>
|
||||||
|
<p>We noticed a login to your {APP_NAME} account from a new location.</p>
|
||||||
|
<p>If this was you, you may disregard this email.</p>
|
||||||
|
<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>
|
||||||
|
<p>
|
||||||
|
Thanks,<br/>
|
||||||
|
{APP_NAME} team
|
||||||
|
</p>`
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
core.SystemMigrations.Register(func(txApp core.App) error {
|
||||||
|
collections, err := txApp.FindAllCollections(core.CollectionTypeAuth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newTemplate := core.NewAuthCollection("up").AuthAlert.EmailTemplate.Body
|
||||||
|
|
||||||
|
for _, c := range collections {
|
||||||
|
if c.AuthAlert.EmailTemplate.Body != oldAuthAlertTemplate {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AuthAlert.EmailTemplate.Body = newTemplate
|
||||||
|
|
||||||
|
err = txApp.Save(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func(txApp core.App) error {
|
||||||
|
collections, err := txApp.FindAllCollections(core.CollectionTypeAuth)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newTemplate := core.NewAuthCollection("down").AuthAlert.EmailTemplate.Body
|
||||||
|
|
||||||
|
for _, c := range collections {
|
||||||
|
if c.AuthAlert.EmailTemplate.Body != newTemplate {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AuthAlert.EmailTemplate.Body = oldAuthAlertTemplate
|
||||||
|
|
||||||
|
err = txApp.Save(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
expectedDriverVersion = "v1.39.1"
|
expectedDriverVersion = "v1.40.1"
|
||||||
expectedLibcVersion = "v1.66.10"
|
expectedLibcVersion = "v1.66.10"
|
||||||
|
|
||||||
// ModerncDepsCheckHookId is the id of the hook that performs the modernc.org/* deps checks.
|
// ModerncDepsCheckHookId is the id of the hook that performs the modernc.org/* deps checks.
|
||||||
|
|
|
||||||
|
|
@ -663,6 +663,7 @@ func mailsBinds(vm *goja.Runtime) {
|
||||||
obj.Set("sendRecordVerification", mails.SendRecordVerification)
|
obj.Set("sendRecordVerification", mails.SendRecordVerification)
|
||||||
obj.Set("sendRecordChangeEmail", mails.SendRecordChangeEmail)
|
obj.Set("sendRecordChangeEmail", mails.SendRecordChangeEmail)
|
||||||
obj.Set("sendRecordOTP", mails.SendRecordOTP)
|
obj.Set("sendRecordOTP", mails.SendRecordOTP)
|
||||||
|
obj.Set("sendRecordAuthAlert", mails.SendRecordAuthAlert)
|
||||||
}
|
}
|
||||||
|
|
||||||
func securityBinds(vm *goja.Runtime) {
|
func securityBinds(vm *goja.Runtime) {
|
||||||
|
|
|
||||||
|
|
@ -795,7 +795,7 @@ func TestMailsBindsCount(t *testing.T) {
|
||||||
vm := goja.New()
|
vm := goja.New()
|
||||||
mailsBinds(vm)
|
mailsBinds(vm)
|
||||||
|
|
||||||
testBindsCount(vm, "$mails", 4, t)
|
testBindsCount(vm, "$mails", 5, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMailsBinds(t *testing.T) {
|
func TestMailsBinds(t *testing.T) {
|
||||||
|
|
@ -833,6 +833,11 @@ func TestMailsBinds(t *testing.T) {
|
||||||
if (!$app.testMailer.lastMessage().html.includes("test_otp_pass")) {
|
if (!$app.testMailer.lastMessage().html.includes("test_otp_pass")) {
|
||||||
throw new Error("Expected record OTP email, got:" + JSON.stringify($app.testMailer.lastMessage()))
|
throw new Error("Expected record OTP email, got:" + JSON.stringify($app.testMailer.lastMessage()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$mails.sendRecordAuthAlert($app, record, "test_alert_info");
|
||||||
|
if (!$app.testMailer.lastMessage().html.includes("test_alert_info")) {
|
||||||
|
throw new Error("Expected record OTP email, got:" + JSON.stringify($app.testMailer.lastMessage()))
|
||||||
|
}
|
||||||
`)
|
`)
|
||||||
if vmErr != nil {
|
if vmErr != nil {
|
||||||
t.Fatal(vmErr)
|
t.Fatal(vmErr)
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -788,6 +788,7 @@ declare namespace $mails {
|
||||||
let sendRecordVerification: mails.sendRecordVerification
|
let sendRecordVerification: mails.sendRecordVerification
|
||||||
let sendRecordChangeEmail: mails.sendRecordChangeEmail
|
let sendRecordChangeEmail: mails.sendRecordChangeEmail
|
||||||
let sendRecordOTP: mails.sendRecordOTP
|
let sendRecordOTP: mails.sendRecordOTP
|
||||||
|
let sendRecordAuthAlert: mails.sendRecordAuthAlert
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ migrate((app) => {
|
||||||
const collection = new Collection({
|
const collection = new Collection({
|
||||||
"authAlert": {
|
"authAlert": {
|
||||||
"emailTemplate": {
|
"emailTemplate": {
|
||||||
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location.</p>\n<p>If this was you, you may disregard this email.</p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location:</p>\n<p><em>{ALERT_INFO}</em></p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>If this was you, you may disregard this email.</p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
||||||
"subject": "Login from a new location"
|
"subject": "Login from a new location"
|
||||||
},
|
},
|
||||||
"enabled": true
|
"enabled": true
|
||||||
|
|
@ -205,7 +205,7 @@ func init() {
|
||||||
jsonData := ` + "`" + `{
|
jsonData := ` + "`" + `{
|
||||||
"authAlert": {
|
"authAlert": {
|
||||||
"emailTemplate": {
|
"emailTemplate": {
|
||||||
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location.</p>\n<p>If this was you, you may disregard this email.</p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location:</p>\n<p><em>{ALERT_INFO}</em></p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>If this was you, you may disregard this email.</p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
||||||
"subject": "Login from a new location"
|
"subject": "Login from a new location"
|
||||||
},
|
},
|
||||||
"enabled": true
|
"enabled": true
|
||||||
|
|
@ -470,7 +470,7 @@ migrate((app) => {
|
||||||
const collection = new Collection({
|
const collection = new Collection({
|
||||||
"authAlert": {
|
"authAlert": {
|
||||||
"emailTemplate": {
|
"emailTemplate": {
|
||||||
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location.</p>\n<p>If this was you, you may disregard this email.</p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location:</p>\n<p><em>{ALERT_INFO}</em></p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>If this was you, you may disregard this email.</p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
||||||
"subject": "Login from a new location"
|
"subject": "Login from a new location"
|
||||||
},
|
},
|
||||||
"enabled": true
|
"enabled": true
|
||||||
|
|
@ -649,7 +649,7 @@ func init() {
|
||||||
jsonData := ` + "`" + `{
|
jsonData := ` + "`" + `{
|
||||||
"authAlert": {
|
"authAlert": {
|
||||||
"emailTemplate": {
|
"emailTemplate": {
|
||||||
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location.</p>\n<p>If this was you, you may disregard this email.</p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
"body": "<p>Hello,</p>\n<p>We noticed a login to your {APP_NAME} account from a new location:</p>\n<p><em>{ALERT_INFO}</em></p>\n<p><strong>If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.</strong></p>\n<p>If this was you, you may disregard this email.</p>\n<p>\n Thanks,<br/>\n {APP_NAME} team\n</p>",
|
||||||
"subject": "Login from a new location"
|
"subject": "Login from a new location"
|
||||||
},
|
},
|
||||||
"enabled": true
|
"enabled": true
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,8 @@ func (pb *PocketBase) Execute() error {
|
||||||
<-done
|
<-done
|
||||||
|
|
||||||
// trigger cleanups
|
// trigger cleanups
|
||||||
|
//
|
||||||
|
// @todo consider skipping and just call the finalizer in case OnTerminate was already invoked manually?
|
||||||
event := new(core.TerminateEvent)
|
event := new(core.TerminateEvent)
|
||||||
event.App = pb
|
event.App = pb
|
||||||
return pb.OnTerminate().Trigger(event, func(e *core.TerminateEvent) error {
|
return pb.OnTerminate().Trigger(event, func(e *core.TerminateEvent) error {
|
||||||
|
|
|
||||||
12
tests/api.go
12
tests/api.go
|
|
@ -48,6 +48,14 @@ type ApiScenario struct {
|
||||||
// A zero or negative value means that there will be no timeout.
|
// A zero or negative value means that there will be no timeout.
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
|
|
||||||
|
// DisableTestAppCleanup disables the builtin TestApp cleanup at
|
||||||
|
// the end of the ApiScenario execution.
|
||||||
|
//
|
||||||
|
// This option works only when explicit TestAppFactory is specified
|
||||||
|
// and means that the developer is responsible to do the necessary
|
||||||
|
// after test cleanup on their own (e.g. by manually calling testApp.Cleanup()).
|
||||||
|
DisableTestAppCleanup bool
|
||||||
|
|
||||||
// expectations
|
// expectations
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
|
|
@ -172,7 +180,11 @@ func (scenario *ApiScenario) test(t testing.TB) {
|
||||||
t.Fatalf("Failed to initialize the test app instance: %v", testAppErr)
|
t.Fatalf("Failed to initialize the test app instance: %v", testAppErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/pocketbase/pocketbase/discussions/7267
|
||||||
|
if scenario.TestAppFactory == nil || !scenario.DisableTestAppCleanup {
|
||||||
defer testApp.Cleanup()
|
defer testApp.Cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
baseRouter, err := apis.NewRouter(testApp)
|
baseRouter, err := apis.NewRouter(testApp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/auth/internal/jwk"
|
||||||
"github.com/pocketbase/pocketbase/tools/types"
|
"github.com/pocketbase/pocketbase/tools/types"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
@ -108,10 +110,10 @@ func (p *Apple) parseAndVerifyIdToken(idToken string) (jwt.MapClaims, error) {
|
||||||
return nil, errors.New("empty id_token")
|
return nil, errors.New("empty id_token")
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the token header params and claims
|
// extract the token claims
|
||||||
// ---
|
// ---
|
||||||
claims := jwt.MapClaims{}
|
claims := jwt.MapClaims{}
|
||||||
t, _, err := jwt.NewParser().ParseUnverified(idToken, claims)
|
_, _, err := jwt.NewParser().ParseUnverified(idToken, claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -136,10 +138,9 @@ func (p *Apple) parseAndVerifyIdToken(idToken string) (jwt.MapClaims, error) {
|
||||||
// the token which is a result of direct TLS communication with the provider
|
// the token which is a result of direct TLS communication with the provider
|
||||||
// (see also https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation)
|
// (see also https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation)
|
||||||
// ---
|
// ---
|
||||||
kid, _ := t.Header["kid"].(string)
|
err = jwk.ValidateTokenSignature(p.ctx, idToken, p.jwksURL)
|
||||||
err = validateIdTokenSignature(p.ctx, idToken, p.jwksURL, kid)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("id_token validation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims, nil
|
return claims, nil
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,163 @@
|
||||||
|
// Package jwk implements some common utilities for interacting with JWKs
|
||||||
|
// (mostly used with OIDC providers).
|
||||||
|
package jwk
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/ed25519"
|
||||||
|
"crypto/rsa"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type JWK struct {
|
||||||
|
Kty string `json:"kty"`
|
||||||
|
Kid string `json:"kid"`
|
||||||
|
Use string `json:"use"`
|
||||||
|
Alg string `json:"alg"`
|
||||||
|
// RS256 (RSA)
|
||||||
|
E string `json:"e"`
|
||||||
|
N string `json:"n"`
|
||||||
|
// Ed25519 (OKP)
|
||||||
|
Crv string `json:"crv"`
|
||||||
|
X string `json:"x"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKey reconstructs and returns the public key from the current JWK.
|
||||||
|
func (key *JWK) PublicKey() (any, error) {
|
||||||
|
switch key.Kty {
|
||||||
|
case "RSA":
|
||||||
|
// RFC 7518
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc7518#section-6.3
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc7517#appendix-A.1
|
||||||
|
exponent, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(key.E, "="))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
modulus, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(key.N, "="))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &rsa.PublicKey{
|
||||||
|
E: int(big.NewInt(0).SetBytes(exponent).Uint64()),
|
||||||
|
N: big.NewInt(0).SetBytes(modulus),
|
||||||
|
}, nil
|
||||||
|
case "OKP":
|
||||||
|
// RFC 8037
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc8037#section-2
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc8037#appendix-A
|
||||||
|
if key.Crv != "Ed25519" {
|
||||||
|
return nil, fmt.Errorf("unsupported OKP curve (must be Ed25519): %q", key.Crv)
|
||||||
|
}
|
||||||
|
|
||||||
|
x, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(key.X, "="))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if l := len(x); l != ed25519.PublicKeySize {
|
||||||
|
return nil, fmt.Errorf("invalid Ed25519 key length: %d", l)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ed25519.PublicKey(x), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported kty (must be RSA or OKP): %q", key.Kty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch retrieves the JSON Web Key Set located at jwksURL and returns
|
||||||
|
// the first key that matches the specified kid.
|
||||||
|
func Fetch(ctx context.Context, jwksURL string, kid string) (*JWK, error) {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, "GET", jwksURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
rawBody, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// http.Client.Get doesn't treat non 2xx responses as error
|
||||||
|
if res.StatusCode >= 400 {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"failed to fetch JSON Web Key Set from %s (%d):\n%s",
|
||||||
|
jwksURL,
|
||||||
|
res.StatusCode,
|
||||||
|
string(rawBody),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
jwks := struct {
|
||||||
|
Keys []*JWK
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err = json.Unmarshal(rawBody, &jwks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range jwks.Keys {
|
||||||
|
if key.Kid == kid {
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("JWK with kid %q was not found", kid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateTokenSignature validates the signature of a token with the
|
||||||
|
// public key retrievied from a remote JWKS.
|
||||||
|
func ValidateTokenSignature(ctx context.Context, token string, jwksURL string) error {
|
||||||
|
// extract the kid token header
|
||||||
|
// ---
|
||||||
|
t, _, err := jwt.NewParser().ParseUnverified(token, jwt.MapClaims{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kid, _ := t.Header["kid"].(string)
|
||||||
|
if kid == "" {
|
||||||
|
return errors.New("missing kid header value")
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch the public key set
|
||||||
|
// ---
|
||||||
|
key, err := Fetch(ctx, jwksURL, kid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify the signature
|
||||||
|
// ---
|
||||||
|
parser := jwt.NewParser(jwt.WithValidMethods([]string{key.Alg}))
|
||||||
|
|
||||||
|
parsedToken, err := parser.Parse(token, func(t *jwt.Token) (any, error) {
|
||||||
|
return key.PublicKey()
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !parsedToken.Valid {
|
||||||
|
return errors.New("the parsed token is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,314 @@
|
||||||
|
package jwk_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"crypto/ed25519"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/auth/internal/jwk"
|
||||||
|
)
|
||||||
|
|
||||||
|
type publicKey interface {
|
||||||
|
Equal(x crypto.PublicKey) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJWK_PublicKey(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rsaPrivate, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
name string
|
||||||
|
key *jwk.JWK
|
||||||
|
expectError bool
|
||||||
|
expectKey crypto.PublicKey
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"empty",
|
||||||
|
&jwk.JWK{},
|
||||||
|
true,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid kty",
|
||||||
|
&jwk.JWK{
|
||||||
|
Kty: "invalid",
|
||||||
|
Alg: "RS256",
|
||||||
|
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(rsaPrivate.E)).Bytes()),
|
||||||
|
N: base64.RawURLEncoding.EncodeToString(rsaPrivate.N.Bytes()),
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"RSA",
|
||||||
|
&jwk.JWK{
|
||||||
|
Kty: "RSA",
|
||||||
|
Alg: "RS256",
|
||||||
|
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(rsaPrivate.E)).Bytes()),
|
||||||
|
N: base64.RawURLEncoding.EncodeToString(rsaPrivate.N.Bytes()),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
&rsaPrivate.PublicKey,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"OKP with unsupported curve",
|
||||||
|
&jwk.JWK{
|
||||||
|
Kty: "OKP",
|
||||||
|
Crv: "invalid",
|
||||||
|
X: base64.RawURLEncoding.EncodeToString([]byte(strings.Repeat("a", ed25519.PublicKeySize))),
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"OKP with invalid public key length",
|
||||||
|
&jwk.JWK{
|
||||||
|
Kty: "OKP",
|
||||||
|
Crv: "Ed25519",
|
||||||
|
X: base64.RawURLEncoding.EncodeToString([]byte(strings.Repeat("a", ed25519.PublicKeySize-1))),
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"valid OKP",
|
||||||
|
&jwk.JWK{
|
||||||
|
Kty: "OKP",
|
||||||
|
Crv: "Ed25519",
|
||||||
|
X: base64.RawURLEncoding.EncodeToString([]byte(strings.Repeat("a", ed25519.PublicKeySize))),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
ed25519.PublicKey([]byte(strings.Repeat("a", ed25519.PublicKeySize))),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.name, func(t *testing.T) {
|
||||||
|
result, err := s.key.PublicKey()
|
||||||
|
|
||||||
|
hasErr := err != nil
|
||||||
|
if hasErr != s.expectError {
|
||||||
|
t.Fatalf("Expected hasErr %v, got %v (%v)", s.expectError, hasErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasErr && result == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
k, ok := result.(publicKey)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("The returned public key %T doesn't satisfy the expected common interface", k)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !k.Equal(s.expectKey) {
|
||||||
|
t.Fatalf("The returned public key doesn't match with the expected one:\n%v\n%v", k, s.expectKey)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetch(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||||
|
if req.URL.Query().Has("error") {
|
||||||
|
res.WriteHeader(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(res, `{
|
||||||
|
"keys": [
|
||||||
|
{
|
||||||
|
"kid": "abc",
|
||||||
|
"kty": "OKP",
|
||||||
|
"crv": "Ed25519",
|
||||||
|
"x": "test_x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kid": "def",
|
||||||
|
"kty": "RSA",
|
||||||
|
"alg": "RS256",
|
||||||
|
"n": "test_n",
|
||||||
|
"e": "test_e"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`)
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
name string
|
||||||
|
kid string
|
||||||
|
expectError bool
|
||||||
|
contains []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"error response",
|
||||||
|
"def",
|
||||||
|
true,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"non-matching kid",
|
||||||
|
"missing",
|
||||||
|
true,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matching kid",
|
||||||
|
"def",
|
||||||
|
false,
|
||||||
|
[]string{
|
||||||
|
`"kid":"def"`,
|
||||||
|
`"kty":"RSA"`,
|
||||||
|
`"alg":"RS256"`,
|
||||||
|
`"n":"test_n"`,
|
||||||
|
`"e":"test_e"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.name, func(t *testing.T) {
|
||||||
|
url := server.URL
|
||||||
|
if s.expectError {
|
||||||
|
url += "?error"
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := jwk.Fetch(context.Background(), url, s.kid)
|
||||||
|
|
||||||
|
hasErr := err != nil
|
||||||
|
if hasErr != s.expectError {
|
||||||
|
t.Fatalf("Expected hasErr %v, got %v (%v)", s.expectError, hasErr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := json.Marshal(key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
rawStr := string(raw)
|
||||||
|
|
||||||
|
for _, substr := range s.contains {
|
||||||
|
if !strings.Contains(rawStr, substr) {
|
||||||
|
t.Fatalf("Missing expected substring\n%s\nin\n%s", substr, rawStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateTokenSignature(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rsaPrivate, err := rsa.GenerateKey(rand.Reader, 1024)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ed25519Public, ed25519Private, err := ed25519.GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nonmatchingKidToken := jwt.New(&jwt.SigningMethodEd25519{})
|
||||||
|
nonmatchingKidToken.Header["kid"] = "missing"
|
||||||
|
nonmatchingKidTokenStr, err := nonmatchingKidToken.SignedString(ed25519Private)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key1Token := jwt.New(&jwt.SigningMethodEd25519{})
|
||||||
|
key1Token.Header["kid"] = "key1"
|
||||||
|
key1TokenStr, err := key1Token.SignedString(ed25519Private)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key2Token := jwt.New(jwt.SigningMethodRS256)
|
||||||
|
key2Token.Header["kid"] = "key2"
|
||||||
|
key2TokenStr, err := key2Token.SignedString(rsaPrivate)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
|
||||||
|
_ = json.NewEncoder(res).Encode(map[string]any{"keys": []*jwk.JWK{
|
||||||
|
{
|
||||||
|
Kid: "key1",
|
||||||
|
Kty: "OKP",
|
||||||
|
Alg: "EdDSA",
|
||||||
|
Crv: "Ed25519",
|
||||||
|
X: base64.RawURLEncoding.EncodeToString(ed25519Public),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Kid: "key2",
|
||||||
|
Kty: "RSA",
|
||||||
|
Alg: "RS256",
|
||||||
|
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(rsaPrivate.E)).Bytes()),
|
||||||
|
N: base64.RawURLEncoding.EncodeToString(rsaPrivate.N.Bytes()),
|
||||||
|
},
|
||||||
|
}})
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
name string
|
||||||
|
token string
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"empty token",
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invlaid token",
|
||||||
|
"abc",
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"no matching kid",
|
||||||
|
nonmatchingKidTokenStr,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"valid Ed25519 token",
|
||||||
|
key1TokenStr,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"valid RSA token",
|
||||||
|
key2TokenStr,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(s.name, func(t *testing.T) {
|
||||||
|
err := jwk.ValidateTokenSignature(
|
||||||
|
context.Background(),
|
||||||
|
s.token,
|
||||||
|
server.URL,
|
||||||
|
)
|
||||||
|
|
||||||
|
hasErr := err != nil
|
||||||
|
if hasErr != s.expectError {
|
||||||
|
t.Fatalf("Expected hasErr %v, got %v (%v)", s.expectError, hasErr, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,20 +2,15 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rsa"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"math/big"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/auth/internal/jwk"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
"github.com/pocketbase/pocketbase/tools/types"
|
"github.com/pocketbase/pocketbase/tools/types"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
|
@ -140,7 +135,7 @@ func (p *OIDC) parseIdToken(token *oauth2.Token) (jwt.MapClaims, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
claims := jwt.MapClaims{}
|
claims := jwt.MapClaims{}
|
||||||
t, _, err := jwt.NewParser().ParseUnverified(idToken, claims)
|
_, _, err := jwt.NewParser().ParseUnverified(idToken, claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -181,112 +176,11 @@ func (p *OIDC) parseIdToken(token *oauth2.Token) (jwt.MapClaims, error) {
|
||||||
// (see also https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation)
|
// (see also https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation)
|
||||||
jwksURL := cast.ToString(p.Extra()["jwksURL"])
|
jwksURL := cast.ToString(p.Extra()["jwksURL"])
|
||||||
if jwksURL != "" {
|
if jwksURL != "" {
|
||||||
kid, _ := t.Header["kid"].(string)
|
err = jwk.ValidateTokenSignature(p.ctx, idToken, jwksURL)
|
||||||
err = validateIdTokenSignature(p.ctx, idToken, jwksURL, kid)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("id_token validation failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateIdTokenSignature(ctx context.Context, idToken string, jwksURL string, kid string) error {
|
|
||||||
// fetch the public key set
|
|
||||||
// ---
|
|
||||||
if kid == "" {
|
|
||||||
return errors.New("missing kid header value")
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := fetchJWK(ctx, jwksURL, kid)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode the key params per RFC 7518 (https://tools.ietf.org/html/rfc7518#section-6.3)
|
|
||||||
// and construct a valid publicKey from them
|
|
||||||
// ---
|
|
||||||
exponent, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(key.E, "="))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
modulus, err := base64.RawURLEncoding.DecodeString(strings.TrimRight(key.N, "="))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
publicKey := &rsa.PublicKey{
|
|
||||||
// https://tools.ietf.org/html/rfc7517#appendix-A.1
|
|
||||||
E: int(big.NewInt(0).SetBytes(exponent).Uint64()),
|
|
||||||
N: big.NewInt(0).SetBytes(modulus),
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify the signiture
|
|
||||||
// ---
|
|
||||||
parser := jwt.NewParser(jwt.WithValidMethods([]string{key.Alg}))
|
|
||||||
|
|
||||||
parsedToken, err := parser.Parse(idToken, func(t *jwt.Token) (any, error) {
|
|
||||||
return publicKey, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !parsedToken.Valid {
|
|
||||||
return errors.New("the parsed id_token is invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type jwk struct {
|
|
||||||
Kty string
|
|
||||||
Kid string
|
|
||||||
Use string
|
|
||||||
Alg string
|
|
||||||
N string
|
|
||||||
E string
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetchJWK(ctx context.Context, jwksURL string, kid string) (*jwk, error) {
|
|
||||||
req, err := http.NewRequestWithContext(ctx, "GET", jwksURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
|
|
||||||
rawBody, err := io.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// http.Client.Get doesn't treat non 2xx responses as error
|
|
||||||
if res.StatusCode >= 400 {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"failed to verify the provided id_token (%d):\n%s",
|
|
||||||
res.StatusCode,
|
|
||||||
string(rawBody),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
jwks := struct {
|
|
||||||
Keys []*jwk
|
|
||||||
}{}
|
|
||||||
if err := json.Unmarshal(rawBody, &jwks); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, key := range jwks.Keys {
|
|
||||||
if key.Kid == kid {
|
|
||||||
return key, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("jwk with kid %q was not found", kid)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -327,7 +327,6 @@ func (s *Provider) Exec(items any) (*Result, error) {
|
||||||
if !s.skipTotal {
|
if !s.skipTotal {
|
||||||
// execute the 2 queries concurrently
|
// execute the 2 queries concurrently
|
||||||
errg := new(errgroup.Group)
|
errg := new(errgroup.Group)
|
||||||
errg.SetLimit(2)
|
|
||||||
errg.Go(countExec)
|
errg.Go(countExec)
|
||||||
errg.Go(modelsExec)
|
errg.Go(modelsExec)
|
||||||
if err := errg.Wait(); err != nil {
|
if err := errg.Wait(); err != nil {
|
||||||
|
|
|
||||||
2
ui/.env
2
ui/.env
|
|
@ -9,4 +9,4 @@ PB_DOCS_URL = "https://pocketbase.io/docs"
|
||||||
PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk"
|
PB_JS_SDK_URL = "https://github.com/pocketbase/js-sdk"
|
||||||
PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk"
|
PB_DART_SDK_URL = "https://github.com/pocketbase/dart-sdk"
|
||||||
PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases"
|
PB_RELEASES = "https://github.com/pocketbase/pocketbase/releases"
|
||||||
PB_VERSION = "v0.30.4"
|
PB_VERSION = "v0.34.0"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as Ce,i as Be,s as Te,V as Le,X as J,h as u,d as ae,t as Q,a as G,I as N,Z as we,_ as Se,C as De,$ as Re,D as Ue,l as d,n as a,m as ne,u as c,A as y,v as k,c as ie,w as h,p as oe,J as je,k as O,o as qe,W as Ee}from"./index-CaLRFnGa.js";import{F as Fe}from"./FieldsQueryParam-CjR_BU8D.js";function ye(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=y(o),b=k(),h(l,"class","tab-item"),O(l,"active",s[1]===s[8].code),this.first=l},m(v,$){d(v,l,$),a(l,p),a(l,b),i||(f=qe(l,"click",m),i=!0)},p(v,$){s=v,$&4&&o!==(o=s[8].code+"")&&N(p,o),$&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 Ee({props:{content:s[8].body}}),{key:n,first:null,c(){l=c("div"),ie(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||(G(o.$$.fragment,i),b=!0)},o(i){Q(o.$$.fragment,i),b=!1},d(i){i&&u(l),ae(o)}}}function He(n){var ke,ge;let s,l,o=n[0].name+"",p,b,i,f,m,v,$,g=n[0].name+"",V,ce,W,M,X,L,Z,A,E,re,F,S,ue,z,H=n[0].name+"",K,de,Y,D,x,P,ee,fe,te,T,le,R,se,C,U,w=[],me=new Map,pe,j,_=[],be=new Map,B;M=new Le({props:{js:`
|
import{S as Ce,i as Be,s as Te,V as Le,X as J,h as u,d as ae,t as Q,a as G,I as N,Z as we,_ as Se,C as De,$ as Re,D as Ue,l as d,n as a,m as ne,u as c,A as y,v as k,c as ie,w as h,p as oe,J as je,k as O,o as qe,W as Ee}from"./index-D5lV2xwk.js";import{F as Fe}from"./FieldsQueryParam-CbVvvpRu.js";function ye(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=y(o),b=k(),h(l,"class","tab-item"),O(l,"active",s[1]===s[8].code),this.first=l},m(v,$){d(v,l,$),a(l,p),a(l,b),i||(f=qe(l,"click",m),i=!0)},p(v,$){s=v,$&4&&o!==(o=s[8].code+"")&&N(p,o),$&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 Ee({props:{content:s[8].body}}),{key:n,first:null,c(){l=c("div"),ie(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||(G(o.$$.fragment,i),b=!0)},o(i){Q(o.$$.fragment,i),b=!1},d(i){i&&u(l),ae(o)}}}function He(n){var ke,ge;let s,l,o=n[0].name+"",p,b,i,f,m,v,$,g=n[0].name+"",V,ce,W,M,X,L,Z,A,E,re,F,S,ue,z,H=n[0].name+"",K,de,Y,D,x,P,ee,fe,te,T,le,R,se,C,U,w=[],me=new Map,pe,j,_=[],be=new Map,B;M=new Le({props:{js:`
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${n[3]}');
|
const pb = new PocketBase('${n[3]}');
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as je,i as xe,s as Ie,V as Ke,W as Ue,X as I,h as d,d as K,t as E,a as z,I as de,Z as Oe,_ as Qe,C as We,$ as Xe,D as Ze,l as u,n as o,m as Q,u as s,A as k,v as p,c as W,w as b,J as Ve,p as Ge,k as X,o as Ye}from"./index-CaLRFnGa.js";import{F as et}from"./FieldsQueryParam-CjR_BU8D.js";function Ee(r,a,l){const n=r.slice();return n[5]=a[l],n}function ze(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"),X(l,"active",a[1]===a[5].code),this.first=l},m(v,w){u(v,l,w),o(l,m),o(l,_),i||(h=Ye(l,"click",g),i=!0)},p(v,w){a=v,w&4&&n!==(n=a[5].code+"")&&de(m,n),w&6&&X(l,"active",a[1]===a[5].code)},d(v){v&&d(l),i=!1,h()}}}function Ne(r,a){let l,n,m,_;return n=new Ue({props:{content:a[5].body}}),{key:r,first:null,c(){l=s("div"),W(n.$$.fragment),m=p(),b(l,"class","tab-item"),X(l,"active",a[1]===a[5].code),this.first=l},m(i,h){u(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)&&X(l,"active",a[1]===a[5].code)},i(i){_||(z(n.$$.fragment,i),_=!0)},o(i){E(n.$$.fragment,i),_=!1},d(i){i&&d(l),K(n)}}}function tt(r){var qe,Fe;let a,l,n=r[0].name+"",m,_,i,h,g,v,w,D,Z,S,J,ue,N,M,pe,G,U=r[0].name+"",Y,he,fe,j,ee,q,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{S as je,i as xe,s as Ie,V as Ke,W as Ue,X as I,h as d,d as K,t as E,a as z,I as de,Z as Oe,_ as Qe,C as We,$ as Xe,D as Ze,l as u,n as o,m as Q,u as s,A as k,v as p,c as W,w as b,J as Ve,p as Ge,k as X,o as Ye}from"./index-D5lV2xwk.js";import{F as et}from"./FieldsQueryParam-CbVvvpRu.js";function Ee(r,a,l){const n=r.slice();return n[5]=a[l],n}function ze(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"),X(l,"active",a[1]===a[5].code),this.first=l},m(v,w){u(v,l,w),o(l,m),o(l,_),i||(h=Ye(l,"click",g),i=!0)},p(v,w){a=v,w&4&&n!==(n=a[5].code+"")&&de(m,n),w&6&&X(l,"active",a[1]===a[5].code)},d(v){v&&d(l),i=!1,h()}}}function Ne(r,a){let l,n,m,_;return n=new Ue({props:{content:a[5].body}}),{key:r,first:null,c(){l=s("div"),W(n.$$.fragment),m=p(),b(l,"class","tab-item"),X(l,"active",a[1]===a[5].code),this.first=l},m(i,h){u(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)&&X(l,"active",a[1]===a[5].code)},i(i){_||(z(n.$$.fragment,i),_=!0)},o(i){E(n.$$.fragment,i),_=!1},d(i){i&&d(l),K(n)}}}function tt(r){var qe,Fe;let a,l,n=r[0].name+"",m,_,i,h,g,v,w,D,Z,S,J,ue,N,M,pe,G,U=r[0].name+"",Y,he,fe,j,ee,q,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';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${r[3]}');
|
const pb = new PocketBase('${r[3]}');
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as Je,i as xe,s as Ee,V as Ne,W as je,X as Q,h as r,d as Z,t as j,a as J,I as pe,Z as Ue,_ as Ie,C as Qe,$ as Ze,D as ze,l as c,n as a,m as z,u as o,A as _,v as h,c as K,w as p,J as Be,p as Ke,k as X,o as Xe}from"./index-CaLRFnGa.js";import{F as Ge}from"./FieldsQueryParam-CjR_BU8D.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 k(){return l[4](l[5])}return{key:s,first:null,c(){n=o("button"),f=_(i),g=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(v,O){c(v,n,O),a(n,f),a(n,g),d||(b=Xe(n,"click",k),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&&r(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"),K(i.$$.fragment),f=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(d,b){c(d,n,b),z(i,n,null),a(n,f),g=!0},p(d,b){l=d;const k={};b&4&&(k.content=l[5].body),i.$set(k),(!g||b&6)&&X(n,"active",l[1]===l[5].code)},i(d){g||(J(i.$$.fragment,d),g=!0)},o(d){j(i.$$.fragment,d),g=!1},d(d){d&&r(n),Z(i)}}}function Ye(s){let l,n,i=s[0].name+"",f,g,d,b,k,v,O,R,G,A,x,be,E,P,me,Y,N=s[0].name+"",ee,fe,te,M,ae,W,le,U,ne,y,oe,ge,B,S,se,_e,ie,ke,m,ve,C,we,$e,Oe,re,Ae,ce,ye,Se,Te,de,Ce,qe,q,ue,F,he,T,L,$=[],De=new Map,Re,H,w=[],Pe=new Map,D;v=new Ne({props:{js:`
|
import{S as Je,i as xe,s as Ee,V as Ne,W as je,X as Q,h as r,d as Z,t as j,a as J,I as pe,Z as Ue,_ as Ie,C as Qe,$ as Ze,D as ze,l as c,n as a,m as z,u as o,A as _,v as h,c as K,w as p,J as Be,p as Ke,k as X,o as Xe}from"./index-D5lV2xwk.js";import{F as Ge}from"./FieldsQueryParam-CbVvvpRu.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 k(){return l[4](l[5])}return{key:s,first:null,c(){n=o("button"),f=_(i),g=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(v,O){c(v,n,O),a(n,f),a(n,g),d||(b=Xe(n,"click",k),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&&r(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"),K(i.$$.fragment),f=h(),p(n,"class","tab-item"),X(n,"active",l[1]===l[5].code),this.first=n},m(d,b){c(d,n,b),z(i,n,null),a(n,f),g=!0},p(d,b){l=d;const k={};b&4&&(k.content=l[5].body),i.$set(k),(!g||b&6)&&X(n,"active",l[1]===l[5].code)},i(d){g||(J(i.$$.fragment,d),g=!0)},o(d){j(i.$$.fragment,d),g=!1},d(d){d&&r(n),Z(i)}}}function Ye(s){let l,n,i=s[0].name+"",f,g,d,b,k,v,O,R,G,A,x,be,E,P,me,Y,N=s[0].name+"",ee,fe,te,M,ae,W,le,U,ne,y,oe,ge,B,S,se,_e,ie,ke,m,ve,C,we,$e,Oe,re,Ae,ce,ye,Se,Te,de,Ce,qe,q,ue,F,he,T,L,$=[],De=new Map,Re,H,w=[],Pe=new Map,D;v=new Ne({props:{js:`
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${s[3]}');
|
const pb = new PocketBase('${s[3]}');
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as be,i as _e,s as ve,W as ge,X as V,h as b,d as x,t as j,a as J,I as ce,Z as de,_ as je,C as ue,$ as Qe,D as he,l as _,n as s,m as ee,u as d,v as T,A as R,c as te,w as g,J as ke,k as N,o as $e,V as Ke,Y as De,p as Xe,a0 as Me}from"./index-CaLRFnGa.js";import{F as Ze}from"./FieldsQueryParam-CjR_BU8D.js";function Be(a,t,e){const l=a.slice();return l[4]=t[e],l}function Ie(a,t,e){const l=a.slice();return l[4]=t[e],l}function We(a,t){let e,l=t[4].code+"",h,i,c,n;function m(){return t[3](t[4])}return{key:a,first:null,c(){e=d("button"),h=R(l),i=T(),g(e,"class","tab-item"),N(e,"active",t[1]===t[4].code),this.first=e},m(v,C){_(v,e,C),s(e,h),s(e,i),c||(n=$e(e,"click",m),c=!0)},p(v,C){t=v,C&4&&l!==(l=t[4].code+"")&&ce(h,l),C&6&&N(e,"active",t[1]===t[4].code)},d(v){v&&b(e),c=!1,n()}}}function Fe(a,t){let e,l,h,i;return l=new ge({props:{content:t[4].body}}),{key:a,first:null,c(){e=d("div"),te(l.$$.fragment),h=T(),g(e,"class","tab-item"),N(e,"active",t[1]===t[4].code),this.first=e},m(c,n){_(c,e,n),ee(l,e,null),s(e,h),i=!0},p(c,n){t=c;const m={};n&4&&(m.content=t[4].body),l.$set(m),(!i||n&6)&&N(e,"active",t[1]===t[4].code)},i(c){i||(J(l.$$.fragment,c),i=!0)},o(c){j(l.$$.fragment,c),i=!1},d(c){c&&b(e),x(l)}}}function ze(a){let t,e,l,h,i,c,n,m=a[0].name+"",v,C,F,B,I,D,Q,M,U,y,O,q,k,L,Y,A,X,E,o,$,P,z,u,p,S,w,Z,we,Te,Pe,pe,Oe,ye,le,fe,oe,me,G,ae,K=[],Se=new Map,qe,ne,H=[],Ce=new Map,se;P=new ge({props:{content:"?expand=relField1,relField2.subRelField"}}),le=new Ze({props:{prefix:"record."}});let re=V(a[2]);const Ae=r=>r[4].code;for(let r=0;r<re.length;r+=1){let f=Ie(a,re,r),W=Ae(f);Se.set(W,K[r]=We(W,f))}let ie=V(a[2]);const Re=r=>r[4].code;for(let r=0;r<ie.length;r+=1){let f=Be(a,ie,r),W=Re(f);Ce.set(W,H[r]=Fe(W,f))}return{c(){t=d("div"),e=d("strong"),e.textContent="POST",l=T(),h=d("div"),i=d("p"),c=R("/api/collections/"),n=d("strong"),v=R(m),C=R("/auth-with-otp"),F=T(),B=d("div"),B.textContent="Body Parameters",I=T(),D=d("table"),D.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>',Q=T(),M=d("div"),M.textContent="Query parameters",U=T(),y=d("table"),O=d("thead"),O.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',q=T(),k=d("tbody"),L=d("tr"),Y=d("td"),Y.textContent="expand",A=T(),X=d("td"),X.innerHTML='<span class="label">String</span>',E=T(),o=d("td"),$=R(`Auto expand record relations. Ex.:
|
import{S as be,i as _e,s as ve,W as ge,X as V,h as b,d as x,t as j,a as J,I as ce,Z as de,_ as je,C as ue,$ as Qe,D as he,l as _,n as s,m as ee,u as d,v as T,A as R,c as te,w as g,J as ke,k as N,o as $e,V as Ke,Y as De,p as Xe,a0 as Me}from"./index-D5lV2xwk.js";import{F as Ze}from"./FieldsQueryParam-CbVvvpRu.js";function Be(a,t,e){const l=a.slice();return l[4]=t[e],l}function Ie(a,t,e){const l=a.slice();return l[4]=t[e],l}function We(a,t){let e,l=t[4].code+"",h,i,c,n;function m(){return t[3](t[4])}return{key:a,first:null,c(){e=d("button"),h=R(l),i=T(),g(e,"class","tab-item"),N(e,"active",t[1]===t[4].code),this.first=e},m(v,C){_(v,e,C),s(e,h),s(e,i),c||(n=$e(e,"click",m),c=!0)},p(v,C){t=v,C&4&&l!==(l=t[4].code+"")&&ce(h,l),C&6&&N(e,"active",t[1]===t[4].code)},d(v){v&&b(e),c=!1,n()}}}function Fe(a,t){let e,l,h,i;return l=new ge({props:{content:t[4].body}}),{key:a,first:null,c(){e=d("div"),te(l.$$.fragment),h=T(),g(e,"class","tab-item"),N(e,"active",t[1]===t[4].code),this.first=e},m(c,n){_(c,e,n),ee(l,e,null),s(e,h),i=!0},p(c,n){t=c;const m={};n&4&&(m.content=t[4].body),l.$set(m),(!i||n&6)&&N(e,"active",t[1]===t[4].code)},i(c){i||(J(l.$$.fragment,c),i=!0)},o(c){j(l.$$.fragment,c),i=!1},d(c){c&&b(e),x(l)}}}function ze(a){let t,e,l,h,i,c,n,m=a[0].name+"",v,C,F,B,I,D,Q,M,U,y,O,q,k,L,Y,A,X,E,o,$,P,z,u,p,S,w,Z,we,Te,Pe,pe,Oe,ye,le,fe,oe,me,G,ae,K=[],Se=new Map,qe,ne,H=[],Ce=new Map,se;P=new ge({props:{content:"?expand=relField1,relField2.subRelField"}}),le=new Ze({props:{prefix:"record."}});let re=V(a[2]);const Ae=r=>r[4].code;for(let r=0;r<re.length;r+=1){let f=Ie(a,re,r),W=Ae(f);Se.set(W,K[r]=We(W,f))}let ie=V(a[2]);const Re=r=>r[4].code;for(let r=0;r<ie.length;r+=1){let f=Be(a,ie,r),W=Re(f);Ce.set(W,H[r]=Fe(W,f))}return{c(){t=d("div"),e=d("strong"),e.textContent="POST",l=T(),h=d("div"),i=d("p"),c=R("/api/collections/"),n=d("strong"),v=R(m),C=R("/auth-with-otp"),F=T(),B=d("div"),B.textContent="Body Parameters",I=T(),D=d("table"),D.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>',Q=T(),M=d("div"),M.textContent="Query parameters",U=T(),y=d("table"),O=d("thead"),O.innerHTML='<tr><th>Param</th> <th>Type</th> <th width="60%">Description</th></tr>',q=T(),k=d("tbody"),L=d("tr"),Y=d("td"),Y.textContent="expand",A=T(),X=d("td"),X.innerHTML='<span class="label">String</span>',E=T(),o=d("td"),$=R(`Auto expand record relations. Ex.:
|
||||||
`),te(P.$$.fragment),z=R(`
|
`),te(P.$$.fragment),z=R(`
|
||||||
Supports up to 6-levels depth nested relations expansion. `),u=d("br"),p=R(`
|
Supports up to 6-levels depth nested relations expansion. `),u=d("br"),p=R(`
|
||||||
The expanded relations will be appended to the record under the
|
The expanded relations will be appended to the record under the
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as kt,i as gt,s as vt,V as St,X as L,W as _t,h as c,d as ae,Y as wt,t as X,a as Z,I as z,Z as ct,_ as yt,C as $t,$ as Pt,D as Ct,l as d,n as t,m as oe,u as s,A as f,v as u,c as se,w as k,J as dt,p as Rt,k as ne,o as Ot}from"./index-CaLRFnGa.js";import{F as Tt}from"./FieldsQueryParam-CjR_BU8D.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){d(a,o,n)},d(a){a&&c(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),d(r,o,h),d(r,a,h),t(a,m)},p(r,h){h&2&&n!==(n=r[12]+"")&&z(m,n)},d(r){r&&(c(o),c(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($,_){d($,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($){$&&c(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"),se(n.$$.fragment),m=u(),k(a,"class","tab-item"),ne(a,"active",o[2]===o[7].code),this.first=a},m(r,h){d(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||(Z(n.$$.fragment,r),b=!0)},o(r){X(n.$$.fragment,r),b=!1},d(r){r&&c(a),ae(n)}}}function Dt(i){var ot,st;let o,a,n=i[0].name+"",m,b,r,h,g,$,_,G=i[1].join("/")+"",ie,De,re,We,ce,C,de,q,pe,R,x,Fe,ee,H,Me,ue,te=i[0].name+"",he,Ue,be,Y,fe,O,me,Be,j,T,_e,Le,ke,qe,V,ge,He,ve,Se,E,we,A,ye,Ye,N,D,$e,je,Pe,Ve,v,Ee,M,Ne,Ie,Je,Ce,Qe,Re,Ke,Xe,Ze,Oe,ze,Ge,U,Te,I,Ae,W,J,P=[],xe=new Map,et,Q,w=[],tt=new Map,F;C=new St({props:{js:`
|
import{S as kt,i as gt,s as vt,V as St,X as L,W as _t,h as c,d as ae,Y as wt,t as X,a as Z,I as z,Z as ct,_ as yt,C as $t,$ as Pt,D as Ct,l as d,n as t,m as oe,u as s,A as f,v as u,c as se,w as k,J as dt,p as Rt,k as ne,o as Ot}from"./index-D5lV2xwk.js";import{F as Tt}from"./FieldsQueryParam-CbVvvpRu.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){d(a,o,n)},d(a){a&&c(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),d(r,o,h),d(r,a,h),t(a,m)},p(r,h){h&2&&n!==(n=r[12]+"")&&z(m,n)},d(r){r&&(c(o),c(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($,_){d($,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($){$&&c(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"),se(n.$$.fragment),m=u(),k(a,"class","tab-item"),ne(a,"active",o[2]===o[7].code),this.first=a},m(r,h){d(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||(Z(n.$$.fragment,r),b=!0)},o(r){X(n.$$.fragment,r),b=!1},d(r){r&&c(a),ae(n)}}}function Dt(i){var ot,st;let o,a,n=i[0].name+"",m,b,r,h,g,$,_,G=i[1].join("/")+"",ie,De,re,We,ce,C,de,q,pe,R,x,Fe,ee,H,Me,ue,te=i[0].name+"",he,Ue,be,Y,fe,O,me,Be,j,T,_e,Le,ke,qe,V,ge,He,ve,Se,E,we,A,ye,Ye,N,D,$e,je,Pe,Ve,v,Ee,M,Ne,Ie,Je,Ce,Qe,Re,Ke,Xe,Ze,Oe,ze,Ge,U,Te,I,Ae,W,J,P=[],xe=new Map,et,Q,w=[],tt=new Map,F;C=new St({props:{js:`
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${i[5]}');
|
const pb = new PocketBase('${i[5]}');
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as St,i as At,s as Lt,V as Mt,W as Ht,X as Q,h as d,d as Re,t as Y,a as x,I as jt,Z as Pt,_ as Nt,C as Ut,$ as Jt,D as zt,l as u,n as t,m as Te,E as Wt,G as Gt,u as o,A as _,v as i,c as Pe,w as b,J as Ft,p as Kt,k as ee,o as Vt}from"./index-CaLRFnGa.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 f(){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,h){u(r,n,h),c||(y=Vt(n,"click",f),c=!0)},p(r,h){s=r,h&10&&ee(n,"active",s[1]===s[6].code)},d(r){r&&d(n),c=!1,y()}}}function It(a,s){let n,c,y,f;return c=new Ht({props:{content:s[6].body}}),{key:a,first:null,c(){n=o("div"),Pe(c.$$.fragment),y=i(),b(n,"class","tab-item"),ee(n,"active",s[1]===s[6].code),this.first=n},m(r,h){u(r,n,h),Te(c,n,null),t(n,y),f=!0},p(r,h){s=r,(!f||h&10)&&ee(n,"active",s[1]===s[6].code)},i(r){f||(x(c.$$.fragment,r),f=!0)},o(r){Y(c.$$.fragment,r),f=!1},d(r){r&&d(n),Re(c)}}}function Xt(a){var pt,mt,bt,ht,ft,_t,yt,kt;let s,n,c=a[0].name+"",y,f,r,h,F,g,U,Fe,P,B,Be,E,Ee,Oe,te,le,w,oe,O,ae,I,se,H,ne,J,ie,q,ce,Ie,re,S,z,He,k,W,Se,de,Ae,D,G,Le,ue,Me,K,je,pe,Ne,C,Ue,me,Je,ze,We,V,Ge,X,Ke,be,Ve,he,Xe,fe,Ze,p,_e,Qe,ye,Ye,ke,xe,$e,et,ge,tt,ve,lt,ot,at,De,st,R,Ce,A,we,T,L,v=[],nt=new Map,it,M,$=[],ct=new Map,j,qe,rt;w=new Mt({props:{js:`
|
import{S as St,i as At,s as Lt,V as Mt,W as Ht,X as Q,h as d,d as Re,t as Y,a as x,I as jt,Z as Pt,_ as Nt,C as Ut,$ as Jt,D as zt,l as u,n as t,m as Te,E as Wt,G as Gt,u as o,A as _,v as i,c as Pe,w as b,J as Ft,p as Kt,k as ee,o as Vt}from"./index-D5lV2xwk.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 f(){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,h){u(r,n,h),c||(y=Vt(n,"click",f),c=!0)},p(r,h){s=r,h&10&&ee(n,"active",s[1]===s[6].code)},d(r){r&&d(n),c=!1,y()}}}function It(a,s){let n,c,y,f;return c=new Ht({props:{content:s[6].body}}),{key:a,first:null,c(){n=o("div"),Pe(c.$$.fragment),y=i(),b(n,"class","tab-item"),ee(n,"active",s[1]===s[6].code),this.first=n},m(r,h){u(r,n,h),Te(c,n,null),t(n,y),f=!0},p(r,h){s=r,(!f||h&10)&&ee(n,"active",s[1]===s[6].code)},i(r){f||(x(c.$$.fragment,r),f=!0)},o(r){Y(c.$$.fragment,r),f=!1},d(r){r&&d(n),Re(c)}}}function Xt(a){var pt,mt,bt,ht,ft,_t,yt,kt;let s,n,c=a[0].name+"",y,f,r,h,F,g,U,Fe,P,B,Be,E,Ee,Oe,te,le,w,oe,O,ae,I,se,H,ne,J,ie,q,ce,Ie,re,S,z,He,k,W,Se,de,Ae,D,G,Le,ue,Me,K,je,pe,Ne,C,Ue,me,Je,ze,We,V,Ge,X,Ke,be,Ve,he,Xe,fe,Ze,p,_e,Qe,ye,Ye,ke,xe,$e,et,ge,tt,ve,lt,ot,at,De,st,R,Ce,A,we,T,L,v=[],nt=new Map,it,M,$=[],ct=new Map,j,qe,rt;w=new Mt({props:{js:`
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${a[2]}');
|
const pb = new PocketBase('${a[2]}');
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as $t,i as qt,s as Tt,V as St,X as ce,W as Ct,h as o,d as $e,t as he,a as ve,I as ae,Z as Ne,_ as pt,C as Mt,$ as Pt,D as Lt,l as r,n as i,m as qe,u as a,A as b,v as p,c as Te,w,J as we,p as Ft,k as Se,o as Ht,L as Ot,H as fe}from"./index-CaLRFnGa.js";import{F as Rt}from"./FieldsQueryParam-CjR_BU8D.js";function mt(s,e,t){const l=s.slice();return l[10]=e[t],l}function bt(s,e,t){const l=s.slice();return l[10]=e[t],l}function _t(s,e,t){const l=s.slice();return l[15]=e[t],l}function kt(s){let e;return{c(){e=a("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&&o(e)}}}function yt(s){let e,t,l,c,f,u,_,m,q,y,g,B,S,$,R,P,I,D,M,W,L,T,k,F,ee,z,U,oe,K,X,Y;function ue(h,C){var N,x,O;return C&1&&(u=null),u==null&&(u=!!((O=(x=(N=h[0])==null?void 0:N.fields)==null?void 0:x.find(Yt))!=null&&O.required)),u?Bt:At}let te=ue(s,-1),E=te(s);function Z(h,C){var N,x,O;return C&1&&(I=null),I==null&&(I=!!((O=(x=(N=h[0])==null?void 0:N.fields)==null?void 0:x.find(Xt))!=null&&O.required)),I?Nt:Vt}let G=Z(s,-1),H=G(s);return{c(){e=a("tr"),e.innerHTML='<td colspan="3" class="txt-hint txt-bold">Auth specific fields</td>',t=p(),l=a("tr"),c=a("td"),f=a("div"),E.c(),_=p(),m=a("span"),m.textContent="email",q=p(),y=a("td"),y.innerHTML='<span class="label">String</span>',g=p(),B=a("td"),B.textContent="Auth record email address.",S=p(),$=a("tr"),R=a("td"),P=a("div"),H.c(),D=p(),M=a("span"),M.textContent="emailVisibility",W=p(),L=a("td"),L.innerHTML='<span class="label">Boolean</span>',T=p(),k=a("td"),k.textContent="Whether to show/hide the auth record email when fetching the record data.",F=p(),ee=a("tr"),ee.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>',z=p(),U=a("tr"),U.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>',oe=p(),K=a("tr"),K.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 Tt,V as St,X as ce,W as Ct,h as o,d as $e,t as he,a as ve,I as ae,Z as Ne,_ as pt,C as Mt,$ as Pt,D as Lt,l as r,n as i,m as qe,u as a,A as b,v as p,c as Te,w,J as we,p as Ft,k as Se,o as Ht,L as Ot,H as fe}from"./index-D5lV2xwk.js";import{F as Rt}from"./FieldsQueryParam-CbVvvpRu.js";function mt(s,e,t){const l=s.slice();return l[10]=e[t],l}function bt(s,e,t){const l=s.slice();return l[10]=e[t],l}function _t(s,e,t){const l=s.slice();return l[15]=e[t],l}function kt(s){let e;return{c(){e=a("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&&o(e)}}}function yt(s){let e,t,l,c,f,u,_,m,q,y,g,B,S,$,R,P,I,D,M,W,L,T,k,F,ee,z,U,oe,K,X,Y;function ue(h,C){var N,x,O;return C&1&&(u=null),u==null&&(u=!!((O=(x=(N=h[0])==null?void 0:N.fields)==null?void 0:x.find(Yt))!=null&&O.required)),u?Bt:At}let te=ue(s,-1),E=te(s);function Z(h,C){var N,x,O;return C&1&&(I=null),I==null&&(I=!!((O=(x=(N=h[0])==null?void 0:N.fields)==null?void 0:x.find(Xt))!=null&&O.required)),I?Nt:Vt}let G=Z(s,-1),H=G(s);return{c(){e=a("tr"),e.innerHTML='<td colspan="3" class="txt-hint txt-bold">Auth specific fields</td>',t=p(),l=a("tr"),c=a("td"),f=a("div"),E.c(),_=p(),m=a("span"),m.textContent="email",q=p(),y=a("td"),y.innerHTML='<span class="label">String</span>',g=p(),B=a("td"),B.textContent="Auth record email address.",S=p(),$=a("tr"),R=a("td"),P=a("div"),H.c(),D=p(),M=a("span"),M.textContent="emailVisibility",W=p(),L=a("td"),L.innerHTML='<span class="label">Boolean</span>',T=p(),k=a("td"),k.textContent="Whether to show/hide the auth record email when fetching the record data.",F=p(),ee=a("tr"),ee.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>',z=p(),U=a("tr"),U.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>',oe=p(),K=a("tr"),K.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/>
|
<br/>
|
||||||
This field can be set only by superusers or auth records with "Manage" access.</td>`,X=p(),Y=a("tr"),Y.innerHTML='<td colspan="3" class="txt-hint txt-bold">Other fields</td>',w(f,"class","inline-flex"),w(P,"class","inline-flex")},m(h,C){r(h,e,C),r(h,t,C),r(h,l,C),i(l,c),i(c,f),E.m(f,null),i(f,_),i(f,m),i(l,q),i(l,y),i(l,g),i(l,B),r(h,S,C),r(h,$,C),i($,R),i(R,P),H.m(P,null),i(P,D),i(P,M),i($,W),i($,L),i($,T),i($,k),r(h,F,C),r(h,ee,C),r(h,z,C),r(h,U,C),r(h,oe,C),r(h,K,C),r(h,X,C),r(h,Y,C)},p(h,C){te!==(te=ue(h,C))&&(E.d(1),E=te(h),E&&(E.c(),E.m(f,_))),G!==(G=Z(h,C))&&(H.d(1),H=G(h),H&&(H.c(),H.m(P,D)))},d(h){h&&(o(e),o(t),o(l),o(S),o($),o(F),o(ee),o(z),o(U),o(oe),o(K),o(X),o(Y)),E.d(),H.d()}}}function At(s){let e;return{c(){e=a("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Bt(s){let e;return{c(){e=a("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Vt(s){let e;return{c(){e=a("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Nt(s){let e;return{c(){e=a("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function jt(s){let e;return{c(){e=a("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Jt(s){let e;return{c(){e=a("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Dt(s){let e,t=s[15].maxSelect===1?"id":"ids",l,c;return{c(){e=b("Relation record "),l=b(t),c=b(".")},m(f,u){r(f,e,u),r(f,l,u),r(f,c,u)},p(f,u){u&32&&t!==(t=f[15].maxSelect===1?"id":"ids")&&ae(l,t)},d(f){f&&(o(e),o(l),o(c))}}}function Et(s){let e,t,l,c,f,u,_,m,q;return{c(){e=b("File object."),t=a("br"),l=b(`
|
This field can be set only by superusers or auth records with "Manage" access.</td>`,X=p(),Y=a("tr"),Y.innerHTML='<td colspan="3" class="txt-hint txt-bold">Other fields</td>',w(f,"class","inline-flex"),w(P,"class","inline-flex")},m(h,C){r(h,e,C),r(h,t,C),r(h,l,C),i(l,c),i(c,f),E.m(f,null),i(f,_),i(f,m),i(l,q),i(l,y),i(l,g),i(l,B),r(h,S,C),r(h,$,C),i($,R),i(R,P),H.m(P,null),i(P,D),i(P,M),i($,W),i($,L),i($,T),i($,k),r(h,F,C),r(h,ee,C),r(h,z,C),r(h,U,C),r(h,oe,C),r(h,K,C),r(h,X,C),r(h,Y,C)},p(h,C){te!==(te=ue(h,C))&&(E.d(1),E=te(h),E&&(E.c(),E.m(f,_))),G!==(G=Z(h,C))&&(H.d(1),H=G(h),H&&(H.c(),H.m(P,D)))},d(h){h&&(o(e),o(t),o(l),o(S),o($),o(F),o(ee),o(z),o(U),o(oe),o(K),o(X),o(Y)),E.d(),H.d()}}}function At(s){let e;return{c(){e=a("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Bt(s){let e;return{c(){e=a("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Vt(s){let e;return{c(){e=a("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Nt(s){let e;return{c(){e=a("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function jt(s){let e;return{c(){e=a("span"),e.textContent="Required",w(e,"class","label label-success")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Jt(s){let e;return{c(){e=a("span"),e.textContent="Optional",w(e,"class","label label-warning")},m(t,l){r(t,e,l)},d(t){t&&o(e)}}}function Dt(s){let e,t=s[15].maxSelect===1?"id":"ids",l,c;return{c(){e=b("Relation record "),l=b(t),c=b(".")},m(f,u){r(f,e,u),r(f,l,u),r(f,c,u)},p(f,u){u&32&&t!==(t=f[15].maxSelect===1?"id":"ids")&&ae(l,t)},d(f){f&&(o(e),o(l),o(c))}}}function Et(s){let e,t,l,c,f,u,_,m,q;return{c(){e=b("File object."),t=a("br"),l=b(`
|
||||||
Set to empty value (`),c=a("code"),c.textContent="null",f=b(", "),u=a("code"),u.textContent='""',_=b(" or "),m=a("code"),m.textContent="[]",q=b(`) to delete
|
Set to empty value (`),c=a("code"),c.textContent="null",f=b(", "),u=a("code"),u.textContent='""',_=b(" or "),m=a("code"),m.textContent="[]",q=b(`) to delete
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as Re,i as Ee,s as Pe,V as Te,X as j,h as p,d as De,t as te,a as le,I as ee,Z as he,_ as Be,C as Ie,$ as Oe,D as Ae,l as f,n as i,m as Ce,u as c,A as $,v as k,c as we,w as m,J as Me,p as qe,k as z,o as Le,W as Se}from"./index-CaLRFnGa.js";function ke(a,l,s){const n=a.slice();return n[6]=l[s],n}function ge(a,l,s){const n=a.slice();return n[6]=l[s],n}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,n){f(s,l,n)},d(s){s&&p(l)}}}function $e(a,l){let s,n,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(o,d){f(o,s,d),n||(h=Le(s,"click",r),n=!0)},p(o,d){l=o,d&20&&z(s,"active",l[2]===l[6].code)},d(o){o&&p(s),n=!1,h()}}}function ye(a,l){let s,n,h,r;return n=new Se({props:{content:l[6].body}}),{key:a,first:null,c(){s=c("div"),we(n.$$.fragment),h=k(),m(s,"class","tab-item"),z(s,"active",l[2]===l[6].code),this.first=s},m(o,d){f(o,s,d),Ce(n,s,null),i(s,h),r=!0},p(o,d){l=o,(!r||d&20)&&z(s,"active",l[2]===l[6].code)},i(o){r||(le(n.$$.fragment,o),r=!0)},o(o){te(n.$$.fragment,o),r=!1},d(o){o&&p(s),De(n)}}}function He(a){var fe,me;let l,s,n=a[0].name+"",h,r,o,d,y,D,F,q=a[0].name+"",J,se,K,C,N,P,V,g,L,ae,S,E,ne,W,H=a[0].name+"",X,oe,Z,ie,G,T,Q,B,Y,I,x,w,O,v=[],ce=new Map,re,A,b=[],de=new Map,R;C=new Te({props:{js:`
|
import{S as Re,i as Ee,s as Pe,V as Te,X as j,h as p,d as De,t as te,a as le,I as ee,Z as he,_ as Be,C as Ie,$ as Oe,D as Ae,l as f,n as i,m as Ce,u as c,A as $,v as k,c as we,w as m,J as Me,p as qe,k as z,o as Le,W as Se}from"./index-D5lV2xwk.js";function ke(a,l,s){const n=a.slice();return n[6]=l[s],n}function ge(a,l,s){const n=a.slice();return n[6]=l[s],n}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,n){f(s,l,n)},d(s){s&&p(l)}}}function $e(a,l){let s,n,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(o,d){f(o,s,d),n||(h=Le(s,"click",r),n=!0)},p(o,d){l=o,d&20&&z(s,"active",l[2]===l[6].code)},d(o){o&&p(s),n=!1,h()}}}function ye(a,l){let s,n,h,r;return n=new Se({props:{content:l[6].body}}),{key:a,first:null,c(){s=c("div"),we(n.$$.fragment),h=k(),m(s,"class","tab-item"),z(s,"active",l[2]===l[6].code),this.first=s},m(o,d){f(o,s,d),Ce(n,s,null),i(s,h),r=!0},p(o,d){l=o,(!r||d&20)&&z(s,"active",l[2]===l[6].code)},i(o){r||(le(n.$$.fragment,o),r=!0)},o(o){te(n.$$.fragment,o),r=!1},d(o){o&&p(s),De(n)}}}function He(a){var fe,me;let l,s,n=a[0].name+"",h,r,o,d,y,D,F,q=a[0].name+"",J,se,K,C,N,P,V,g,L,ae,S,E,ne,W,H=a[0].name+"",X,oe,Z,ie,G,T,Q,B,Y,I,x,w,O,v=[],ce=new Map,re,A,b=[],de=new Map,R;C=new Te({props:{js:`
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${a[3]}');
|
const pb = new PocketBase('${a[3]}');
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as se,i as oe,s as ie,X as K,h as g,t as X,a as V,I as F,Z as le,_ as Re,C as ne,$ as Se,D as ae,l as v,n as u,u as p,v as y,A as U,w as b,k as Y,o as ce,W as Oe,d as x,m as ee,c as te,V as Me,Y as _e,J as Be,p as De,a0 as be}from"./index-CaLRFnGa.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,q){v(k,t,q),u(t,d),u(t,i),r||(a=ce(t,"click",m),r=!0)},p(k,q){e=k,q&4&&l!==(l=e[4].code+"")&&F(d,l),q&6&&Y(t,"active",e[1]===e[4].code)},d(k){k&&g(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"),te(l.$$.fragment),d=y(),b(t,"class","tab-item"),Y(t,"active",e[1]===e[4].code),this.first=t},m(r,a){v(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&&g(t),x(l)}}}function Ne(n){let e,t,l,d,i,r,a,m=n[0].name+"",k,q,G,H,J,L,z,B,D,S,N,A=[],O=new Map,P,j,T=[],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,A[c]=ke(s,f))}let _=K(n[2]);const Z=c=>c[4].code;for(let c=0;c<_.length;c+=1){let f=ge(n,_,c),s=Z(f);W.set(s,T[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),q=U("/confirm-email-change"),G=y(),H=p("div"),H.textContent="Body Parameters",J=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<A.length;c+=1)A[c].c();P=y(),j=p("div");for(let c=0;c<T.length;c+=1)T[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){v(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,q),v(c,G,f),v(c,H,f),v(c,J,f),v(c,L,f),v(c,z,f),v(c,B,f),v(c,D,f),v(c,S,f),u(S,N);for(let s=0;s<A.length;s+=1)A[s]&&A[s].m(N,null);u(S,P),u(S,j);for(let s=0;s<T.length;s+=1)T[s]&&T[s].m(j,null);w=!0},p(c,[f]){(!w||f&1)&&m!==(m=c[0].name+"")&&F(k,m),f&6&&(E=K(c[2]),A=le(A,f,M,1,c,E,O,N,Re,ke,null,ve)),f&6&&(_=K(c[2]),ne(),T=le(T,f,Z,1,c,_,W,j,Se,$e,null,ge),ae())},i(c){if(!w){for(let f=0;f<_.length;f+=1)V(T[f]);w=!0}},o(c){for(let f=0;f<T.length;f+=1)X(T[f]);w=!1},d(c){c&&(g(e),g(G),g(H),g(J),g(L),g(z),g(B),g(D),g(S));for(let f=0;f<A.length;f+=1)A[f].d();for(let f=0;f<T.length;f+=1)T[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:`
|
import{S as se,i as oe,s as ie,X as K,h as g,t as X,a as V,I as F,Z as le,_ as Re,C as ne,$ as Se,D as ae,l as v,n as u,u as p,v as y,A as U,w as b,k as Y,o as ce,W as Oe,d as x,m as ee,c as te,V as Me,Y as _e,J as Be,p as De,a0 as be}from"./index-D5lV2xwk.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,q){v(k,t,q),u(t,d),u(t,i),r||(a=ce(t,"click",m),r=!0)},p(k,q){e=k,q&4&&l!==(l=e[4].code+"")&&F(d,l),q&6&&Y(t,"active",e[1]===e[4].code)},d(k){k&&g(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"),te(l.$$.fragment),d=y(),b(t,"class","tab-item"),Y(t,"active",e[1]===e[4].code),this.first=t},m(r,a){v(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&&g(t),x(l)}}}function Ne(n){let e,t,l,d,i,r,a,m=n[0].name+"",k,q,G,H,J,L,z,B,D,S,N,A=[],O=new Map,P,j,T=[],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,A[c]=ke(s,f))}let _=K(n[2]);const Z=c=>c[4].code;for(let c=0;c<_.length;c+=1){let f=ge(n,_,c),s=Z(f);W.set(s,T[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),q=U("/confirm-email-change"),G=y(),H=p("div"),H.textContent="Body Parameters",J=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<A.length;c+=1)A[c].c();P=y(),j=p("div");for(let c=0;c<T.length;c+=1)T[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){v(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,q),v(c,G,f),v(c,H,f),v(c,J,f),v(c,L,f),v(c,z,f),v(c,B,f),v(c,D,f),v(c,S,f),u(S,N);for(let s=0;s<A.length;s+=1)A[s]&&A[s].m(N,null);u(S,P),u(S,j);for(let s=0;s<T.length;s+=1)T[s]&&T[s].m(j,null);w=!0},p(c,[f]){(!w||f&1)&&m!==(m=c[0].name+"")&&F(k,m),f&6&&(E=K(c[2]),A=le(A,f,M,1,c,E,O,N,Re,ke,null,ve)),f&6&&(_=K(c[2]),ne(),T=le(T,f,Z,1,c,_,W,j,Se,$e,null,ge),ae())},i(c){if(!w){for(let f=0;f<_.length;f+=1)V(T[f]);w=!0}},o(c){for(let f=0;f<T.length;f+=1)X(T[f]);w=!1},d(c){c&&(g(e),g(G),g(H),g(J),g(L),g(z),g(B),g(D),g(S));for(let f=0;f<A.length;f+=1)A[f].d();for(let f=0;f<T.length;f+=1)T[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:`
|
||||||
{
|
{
|
||||||
"status": 400,
|
"status": 400,
|
||||||
"message": "An error occurred while validating the submitted data.",
|
"message": "An error occurred while validating the submitted data.",
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as J,i as N,s as O,W as P,h as Q,d as R,t as W,a as j,I as z,l as D,n as e,m as G,u as t,v as c,A as i,c as K,w as U}from"./index-CaLRFnGa.js";function V(f){let n,o,u,d,k,s,p,w,g,y,r,F,_,S,b,E,C,a,$,L,q,H,I,M,m,T,v,A,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>',k=c(),s=t("td"),p=t("p"),w=i(`Comma separated string of the fields to return in the JSON response
|
import{S as J,i as N,s as O,W as P,h as Q,d as R,t as W,a as j,I as z,l as D,n as e,m as G,u as t,v as c,A as i,c as K,w as U}from"./index-D5lV2xwk.js";function V(f){let n,o,u,d,k,s,p,w,g,y,r,F,_,S,b,E,C,a,$,L,q,H,I,M,m,T,v,A,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>',k=c(),s=t("td"),p=t("p"),w=i(`Comma separated string of the fields to return in the JSON response
|
||||||
`),g=t("em"),g.textContent="(by default returns all fields)",y=i(`. Ex.:
|
`),g=t("em"),g.textContent="(by default returns all fields)",y=i(`. Ex.:
|
||||||
`),K(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(`
|
`),K(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.
|
Returns a short plain text version of the field string value.
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as el,i as ll,s as sl,H as ze,h as m,l as h,o as nl,u as e,v as s,L as ol,w as a,n as t,A as g,V as al,W as Le,X as ae,d as Kt,Y as il,t as Ct,a as kt,I as ve,Z as Je,_ as rl,C as cl,$ as dl,D as pl,m as Qt,c as Vt,J as Te,p as fl,k as Ae}from"./index-CaLRFnGa.js";import{F as ul}from"./FieldsQueryParam-CjR_BU8D.js";function ml(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){h(f,n,b),h(f,o,b),h(f,i,b)},d(f){f&&(m(n),m(o),m(i))}}}function hl(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){h(f,n,b),h(f,o,b),h(f,i,b)},d(f){f&&(m(n),m(o),m(i))}}}function Ke(r){let n,o,i,f,b,p,u,C,_,x,d,Y,yt,Wt,E,Xt,D,it,P,Z,ie,j,U,re,rt,vt,tt,Ft,ce,ct,dt,et,N,Yt,Lt,k,lt,At,Zt,Tt,z,st,Pt,te,Rt,v,pt,Ot,de,ft,pe,H,St,nt,Et,F,ut,fe,J,Nt,ee,qt,le,Dt,ue,L,mt,me,ht,he,M,be,T,Ht,ot,Mt,K,bt,ge,I,It,y,Bt,at,Gt,_e,Q,gt,we,_t,xe,jt,$e,B,Ut,Ce,G,ke,wt,se,R,xt,V,W,O,zt,ne,X;return{c(){n=e("p"),n.innerHTML=`The syntax basically follows the format
|
import{S as el,i as ll,s as sl,H as ze,h as m,l as h,o as nl,u as e,v as s,L as ol,w as a,n as t,A as g,V as al,W as Le,X as ae,d as Kt,Y as il,t as Ct,a as kt,I as ve,Z as Je,_ as rl,C as cl,$ as dl,D as pl,m as Qt,c as Vt,J as Te,p as fl,k as Ae}from"./index-D5lV2xwk.js";import{F as ul}from"./FieldsQueryParam-CbVvvpRu.js";function ml(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){h(f,n,b),h(f,o,b),h(f,i,b)},d(f){f&&(m(n),m(o),m(i))}}}function hl(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){h(f,n,b),h(f,o,b),h(f,i,b)},d(f){f&&(m(n),m(o),m(i))}}}function Ke(r){let n,o,i,f,b,p,u,C,_,x,d,Y,yt,Wt,E,Xt,D,it,P,Z,ie,j,U,re,rt,vt,tt,Ft,ce,ct,dt,et,N,Yt,Lt,k,lt,At,Zt,Tt,z,st,Pt,te,Rt,v,pt,Ot,de,ft,pe,H,St,nt,Et,F,ut,fe,J,Nt,ee,qt,le,Dt,ue,L,mt,me,ht,he,M,be,T,Ht,ot,Mt,K,bt,ge,I,It,y,Bt,at,Gt,_e,Q,gt,we,_t,xe,jt,$e,B,Ut,Ce,G,ke,wt,se,R,xt,V,W,O,zt,ne,X;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
|
<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:
|
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"),x=s(),d=e("ul"),Y=e("li"),yt=e("code"),yt.textContent="=",Wt=s(),E=e("span"),E.textContent="Equal",Xt=s(),D=e("li"),it=e("code"),it.textContent="!=",P=s(),Z=e("span"),Z.textContent="NOT equal",ie=s(),j=e("li"),U=e("code"),U.textContent=">",re=s(),rt=e("span"),rt.textContent="Greater than",vt=s(),tt=e("li"),Ft=e("code"),Ft.textContent=">=",ce=s(),ct=e("span"),ct.textContent="Greater than or equal",dt=s(),et=e("li"),N=e("code"),N.textContent="<",Yt=s(),Lt=e("span"),Lt.textContent="Less than",k=s(),lt=e("li"),At=e("code"),At.textContent="<=",Zt=s(),Tt=e("span"),Tt.textContent="Less than or equal",z=s(),st=e("li"),Pt=e("code"),Pt.textContent="~",te=s(),Rt=e("span"),Rt.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
|
`),_=e("br"),x=s(),d=e("ul"),Y=e("li"),yt=e("code"),yt.textContent="=",Wt=s(),E=e("span"),E.textContent="Equal",Xt=s(),D=e("li"),it=e("code"),it.textContent="!=",P=s(),Z=e("span"),Z.textContent="NOT equal",ie=s(),j=e("li"),U=e("code"),U.textContent=">",re=s(),rt=e("span"),rt.textContent="Greater than",vt=s(),tt=e("li"),Ft=e("code"),Ft.textContent=">=",ce=s(),ct=e("span"),ct.textContent="Greater than or equal",dt=s(),et=e("li"),N=e("code"),N.textContent="<",Yt=s(),Lt=e("span"),Lt.textContent="Less than",k=s(),lt=e("li"),At=e("code"),At.textContent="<=",Zt=s(),Tt=e("span"),Tt.textContent="Less than or equal",z=s(),st=e("li"),Pt=e("code"),Pt.textContent="~",te=s(),Rt=e("span"),Rt.textContent=`Like/Contains (if not specified auto wraps the right string OPERAND in a "%" for
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1 +1 @@
|
||||||
import{S as r,i as c,s as l,H as n,h as u,l as h,u as p,w as d,O as f,P as m,Q as g,R as o}from"./index-CaLRFnGa.js";function _(s){let t;return{c(){t=p("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>',d(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&&u(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 x extends r{constructor(t){super(),c(this,t,b,_,l,{})}}export{x as default};
|
import{S as r,i as c,s as l,H as n,h as u,l as h,u as p,w as d,O as f,P as m,Q as g,R as o}from"./index-D5lV2xwk.js";function _(s){let t;return{c(){t=p("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>',d(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&&u(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 x extends r{constructor(t){super(),c(this,t,b,_,l,{})}}export{x as default};
|
||||||
|
|
@ -1 +1 @@
|
||||||
import{S as i,i as r,s as u,H as n,h as l,l as p,u as h,w as d,O as m,P as f,Q as _,R as o}from"./index-CaLRFnGa.js";function b(a){let t;return{c(){t=h("div"),t.innerHTML='<h3 class="m-b-sm">Auth completed.</h3> <h5>You can close this window and go back to the app.</h5>',d(t,"class","content txt-hint txt-center p-base")},m(e,s){p(e,t,s)},p:n,i:n,o:n,d(e){e&&l(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 x extends i{constructor(t){super(),r(this,t,g,b,u,{})}}export{x as default};
|
import{S as i,i as r,s as u,H as n,h as l,l as p,u as h,w as d,O as m,P as f,Q as _,R as o}from"./index-D5lV2xwk.js";function b(a){let t;return{c(){t=h("div"),t.innerHTML='<h3 class="m-b-sm">Auth completed.</h3> <h5>You can close this window and go back to the app.</h5>',d(t,"class","content txt-hint txt-center p-base")},m(e,s){p(e,t,s)},p:n,i:n,o:n,d(e){e&&l(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 x extends i{constructor(t){super(),r(this,t,g,b,u,{})}}export{x as default};
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import{S as J,i as M,s as z,F as A,d as L,t as h,a as v,m as S,c as I,J as D,h as _,D as N,l as b,L as R,M as W,g as Y,p as j,H as P,o as q,u as m,v as y,w as p,f as B,k as T,n as g,q as G,A as C,I as K,z as F,C as O}from"./index-CaLRFnGa.js";function Q(i){let e,t,n,l,s,o,f,a,r,u,k,$,d=i[3]&&H(i);return o=new B({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=C(`Type your password to confirm changing your email address
|
import{S as J,i as M,s as z,F as A,d as L,t as h,a as v,m as S,c as I,J as D,h as _,D as N,l as b,L as R,M as W,g as Y,p as j,H as P,o as q,u as m,v as y,w as p,f as B,k as T,n as g,q as G,A as C,I as K,z as F,C as O}from"./index-D5lV2xwk.js";function Q(i){let e,t,n,l,s,o,f,a,r,u,k,$,d=i[3]&&H(i);return o=new B({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=C(`Type your password to confirm changing your email address
|
||||||
`),d&&d.c(),s=y(),I(o.$$.fragment),f=y(),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){b(c,e,w),g(e,t),g(t,n),g(n,l),d&&d.m(n,null),g(e,s),S(o,e,null),g(e,f),g(e,a),g(a,r),u=!0,k||($=q(e,"submit",G(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 E={};w&769&&(E.$$scope={dirty:w,ctx:c}),o.$set(E),(!u||w&2)&&(a.disabled=c[1]),(!u||w&2)&&T(a,"btn-loading",c[1])},i(c){u||(v(o.$$.fragment,c),u=!0)},o(c){h(o.$$.fragment,c),u=!1},d(c){c&&_(e),d&&d.d(),L(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=y(),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){b(o,e,f),b(o,t,f),b(o,n,f),l||(s=q(n,"click",i[6]),l=!0)},p:P,i:P,o:P,d(o){o&&(_(e),_(t),_(n)),l=!1,s()}}}function H(i){let e,t,n;return{c(){e=C("to "),t=m("strong"),n=C(i[3]),p(t,"class","txt-nowrap")},m(l,s){b(l,e,s),b(l,t,s),g(t,n)},p(l,s){s&8&&K(n,l[3])},d(l){l&&(_(e),_(t))}}}function V(i){let e,t,n,l,s,o,f,a;return{c(){e=m("label"),t=C("Password"),l=y(),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){b(r,e,u),g(e,t),b(r,l,u),b(r,s,u),F(s,i[0]),s.focus(),f||(a=q(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&&(_(e),_(l),_(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),b(a,n,r),l=!0},p(a,r){let u=e;e=f(a),e===u?o[e].p(a,r):(O(),h(o[u],1,1,()=>{o[u]=null}),N(),t=o[e],t?t.p(a,r):(t=o[e]=s[e](a),t.c()),v(t,1),t.m(n.parentNode,n))},i(a){l||(v(t),l=!0)},o(a){h(t),l=!1},d(a){a&&_(n),o[e].d(a)}}}function Z(i){let e,t;return e=new A({props:{nobranding:!0,$$slots:{default:[X]},$$scope:{ctx:i}}}),{c(){I(e.$$.fragment)},m(n,l){S(e,n,l),t=!0},p(n,[l]){const s={};l&527&&(s.$$scope={dirty:l,ctx:n}),e.$set(s)},i(n){t||(v(e.$$.fragment,n),t=!0)},o(n){h(e.$$.fragment,n),t=!1},d(n){L(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 W("../");try{const $=Y(l==null?void 0:l.token);await k.collection($.collectionId).confirmEmailChange(l==null?void 0:l.token,s),t(2,f=!0)}catch($){j.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=D.getJWTPayload(l==null?void 0:l.token).newEmail||"")},[s,o,f,n,a,l,r,u]}class te extends J{constructor(e){super(),M(this,e,x,Z,z,{params:5})}}export{te as default};
|
`),d&&d.c(),s=y(),I(o.$$.fragment),f=y(),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){b(c,e,w),g(e,t),g(t,n),g(n,l),d&&d.m(n,null),g(e,s),S(o,e,null),g(e,f),g(e,a),g(a,r),u=!0,k||($=q(e,"submit",G(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 E={};w&769&&(E.$$scope={dirty:w,ctx:c}),o.$set(E),(!u||w&2)&&(a.disabled=c[1]),(!u||w&2)&&T(a,"btn-loading",c[1])},i(c){u||(v(o.$$.fragment,c),u=!0)},o(c){h(o.$$.fragment,c),u=!1},d(c){c&&_(e),d&&d.d(),L(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=y(),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){b(o,e,f),b(o,t,f),b(o,n,f),l||(s=q(n,"click",i[6]),l=!0)},p:P,i:P,o:P,d(o){o&&(_(e),_(t),_(n)),l=!1,s()}}}function H(i){let e,t,n;return{c(){e=C("to "),t=m("strong"),n=C(i[3]),p(t,"class","txt-nowrap")},m(l,s){b(l,e,s),b(l,t,s),g(t,n)},p(l,s){s&8&&K(n,l[3])},d(l){l&&(_(e),_(t))}}}function V(i){let e,t,n,l,s,o,f,a;return{c(){e=m("label"),t=C("Password"),l=y(),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){b(r,e,u),g(e,t),b(r,l,u),b(r,s,u),F(s,i[0]),s.focus(),f||(a=q(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&&(_(e),_(l),_(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),b(a,n,r),l=!0},p(a,r){let u=e;e=f(a),e===u?o[e].p(a,r):(O(),h(o[u],1,1,()=>{o[u]=null}),N(),t=o[e],t?t.p(a,r):(t=o[e]=s[e](a),t.c()),v(t,1),t.m(n.parentNode,n))},i(a){l||(v(t),l=!0)},o(a){h(t),l=!1},d(a){a&&_(n),o[e].d(a)}}}function Z(i){let e,t;return e=new A({props:{nobranding:!0,$$slots:{default:[X]},$$scope:{ctx:i}}}),{c(){I(e.$$.fragment)},m(n,l){S(e,n,l),t=!0},p(n,[l]){const s={};l&527&&(s.$$scope={dirty:l,ctx:n}),e.$set(s)},i(n){t||(v(e.$$.fragment,n),t=!0)},o(n){h(e.$$.fragment,n),t=!1},d(n){L(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 W("../");try{const $=Y(l==null?void 0:l.token);await k.collection($.collectionId).confirmEmailChange(l==null?void 0:l.token,s),t(2,f=!0)}catch($){j.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=D.getJWTPayload(l==null?void 0:l.token).newEmail||"")},[s,o,f,n,a,l,r,u]}class te extends J{constructor(e){super(),M(this,e,x,Z,z,{params:5})}}export{te as default};
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import{S as A,i as D,s as W,F as Y,d as H,t as P,a as q,m as L,c as N,J as j,h as _,C as B,D as E,l as m,L as G,M as K,g as O,p as Q,H as F,o as S,u as b,v as C,w as p,f as J,k as M,n as w,q as U,A as y,I as V,z as R}from"./index-CaLRFnGa.js";function X(a){let e,l,s,n,t,o,c,r,i,u,v,g,k,h,d=a[4]&&z(a);return o=new J({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:a}}}),r=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:a}}}),{c(){e=b("form"),l=b("div"),s=b("h5"),n=y(`Reset your user password
|
import{S as A,i as D,s as W,F as Y,d as H,t as P,a as q,m as L,c as N,J as j,h as _,C as B,D as E,l as m,L as G,M as K,g as O,p as Q,H as F,o as S,u as b,v as C,w as p,f as J,k as M,n as w,q as U,A as y,I as V,z as R}from"./index-D5lV2xwk.js";function X(a){let e,l,s,n,t,o,c,r,i,u,v,g,k,h,d=a[4]&&z(a);return o=new J({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:a}}}),r=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:a}}}),{c(){e=b("form"),l=b("div"),s=b("h5"),n=y(`Reset your user password
|
||||||
`),d&&d.c(),t=C(),N(o.$$.fragment),c=C(),N(r.$$.fragment),i=C(),u=b("button"),v=b("span"),v.textContent="Set new password",p(l,"class","content txt-center m-b-base"),p(v,"class","txt"),p(u,"type","submit"),p(u,"class","btn btn-lg btn-block"),u.disabled=a[2],M(u,"btn-loading",a[2])},m(f,$){m(f,e,$),w(e,l),w(l,s),w(s,n),d&&d.m(s,null),w(e,t),L(o,e,null),w(e,c),L(r,e,null),w(e,i),w(e,u),w(u,v),g=!0,k||(h=S(e,"submit",U(a[5])),k=!0)},p(f,$){f[4]?d?d.p(f,$):(d=z(f),d.c(),d.m(s,null)):d&&(d.d(1),d=null);const T={};$&3073&&(T.$$scope={dirty:$,ctx:f}),o.$set(T);const I={};$&3074&&(I.$$scope={dirty:$,ctx:f}),r.$set(I),(!g||$&4)&&(u.disabled=f[2]),(!g||$&4)&&M(u,"btn-loading",f[2])},i(f){g||(q(o.$$.fragment,f),q(r.$$.fragment,f),g=!0)},o(f){P(o.$$.fragment,f),P(r.$$.fragment,f),g=!1},d(f){f&&_(e),d&&d.d(),H(o),H(r),k=!1,h()}}}function Z(a){let e,l,s,n,t;return{c(){e=b("div"),e.innerHTML='<div class="icon"><i class="ri-checkbox-circle-line"></i></div> <div class="content txt-bold"><p>Successfully changed the user password.</p> <p>You can now sign in with your new password.</p></div>',l=C(),s=b("button"),s.textContent="Close",p(e,"class","alert alert-success"),p(s,"type","button"),p(s,"class","btn btn-transparent btn-block")},m(o,c){m(o,e,c),m(o,l,c),m(o,s,c),n||(t=S(s,"click",a[7]),n=!0)},p:F,i:F,o:F,d(o){o&&(_(e),_(l),_(s)),n=!1,t()}}}function z(a){let e,l,s;return{c(){e=y("for "),l=b("strong"),s=y(a[4])},m(n,t){m(n,e,t),m(n,l,t),w(l,s)},p(n,t){t&16&&V(s,n[4])},d(n){n&&(_(e),_(l))}}}function x(a){let e,l,s,n,t,o,c,r;return{c(){e=b("label"),l=y("New password"),n=C(),t=b("input"),p(e,"for",s=a[10]),p(t,"type","password"),p(t,"id",o=a[10]),t.required=!0,t.autofocus=!0},m(i,u){m(i,e,u),w(e,l),m(i,n,u),m(i,t,u),R(t,a[0]),t.focus(),c||(r=S(t,"input",a[8]),c=!0)},p(i,u){u&1024&&s!==(s=i[10])&&p(e,"for",s),u&1024&&o!==(o=i[10])&&p(t,"id",o),u&1&&t.value!==i[0]&&R(t,i[0])},d(i){i&&(_(e),_(n),_(t)),c=!1,r()}}}function ee(a){let e,l,s,n,t,o,c,r;return{c(){e=b("label"),l=y("New password confirm"),n=C(),t=b("input"),p(e,"for",s=a[10]),p(t,"type","password"),p(t,"id",o=a[10]),t.required=!0},m(i,u){m(i,e,u),w(e,l),m(i,n,u),m(i,t,u),R(t,a[1]),c||(r=S(t,"input",a[9]),c=!0)},p(i,u){u&1024&&s!==(s=i[10])&&p(e,"for",s),u&1024&&o!==(o=i[10])&&p(t,"id",o),u&2&&t.value!==i[1]&&R(t,i[1])},d(i){i&&(_(e),_(n),_(t)),c=!1,r()}}}function te(a){let e,l,s,n;const t=[Z,X],o=[];function c(r,i){return r[3]?0:1}return e=c(a),l=o[e]=t[e](a),{c(){l.c(),s=G()},m(r,i){o[e].m(r,i),m(r,s,i),n=!0},p(r,i){let u=e;e=c(r),e===u?o[e].p(r,i):(B(),P(o[u],1,1,()=>{o[u]=null}),E(),l=o[e],l?l.p(r,i):(l=o[e]=t[e](r),l.c()),q(l,1),l.m(s.parentNode,s))},i(r){n||(q(l),n=!0)},o(r){P(l),n=!1},d(r){r&&_(s),o[e].d(r)}}}function se(a){let e,l;return e=new Y({props:{nobranding:!0,$$slots:{default:[te]},$$scope:{ctx:a}}}),{c(){N(e.$$.fragment)},m(s,n){L(e,s,n),l=!0},p(s,[n]){const t={};n&2079&&(t.$$scope={dirty:n,ctx:s}),e.$set(t)},i(s){l||(q(e.$$.fragment,s),l=!0)},o(s){P(e.$$.fragment,s),l=!1},d(s){H(e,s)}}}function le(a,e,l){let s,{params:n}=e,t="",o="",c=!1,r=!1;async function i(){if(c)return;l(2,c=!0);const k=new K("../");try{const h=O(n==null?void 0:n.token);await k.collection(h.collectionId).confirmPasswordReset(n==null?void 0:n.token,t,o),l(3,r=!0)}catch(h){Q.error(h)}l(2,c=!1)}const u=()=>window.close();function v(){t=this.value,l(0,t)}function g(){o=this.value,l(1,o)}return a.$$set=k=>{"params"in k&&l(6,n=k.params)},a.$$.update=()=>{a.$$.dirty&64&&l(4,s=j.getJWTPayload(n==null?void 0:n.token).email||"")},[t,o,c,r,s,i,n,u,v,g]}class oe extends A{constructor(e){super(),D(this,e,le,se,W,{params:6})}}export{oe as default};
|
`),d&&d.c(),t=C(),N(o.$$.fragment),c=C(),N(r.$$.fragment),i=C(),u=b("button"),v=b("span"),v.textContent="Set new password",p(l,"class","content txt-center m-b-base"),p(v,"class","txt"),p(u,"type","submit"),p(u,"class","btn btn-lg btn-block"),u.disabled=a[2],M(u,"btn-loading",a[2])},m(f,$){m(f,e,$),w(e,l),w(l,s),w(s,n),d&&d.m(s,null),w(e,t),L(o,e,null),w(e,c),L(r,e,null),w(e,i),w(e,u),w(u,v),g=!0,k||(h=S(e,"submit",U(a[5])),k=!0)},p(f,$){f[4]?d?d.p(f,$):(d=z(f),d.c(),d.m(s,null)):d&&(d.d(1),d=null);const T={};$&3073&&(T.$$scope={dirty:$,ctx:f}),o.$set(T);const I={};$&3074&&(I.$$scope={dirty:$,ctx:f}),r.$set(I),(!g||$&4)&&(u.disabled=f[2]),(!g||$&4)&&M(u,"btn-loading",f[2])},i(f){g||(q(o.$$.fragment,f),q(r.$$.fragment,f),g=!0)},o(f){P(o.$$.fragment,f),P(r.$$.fragment,f),g=!1},d(f){f&&_(e),d&&d.d(),H(o),H(r),k=!1,h()}}}function Z(a){let e,l,s,n,t;return{c(){e=b("div"),e.innerHTML='<div class="icon"><i class="ri-checkbox-circle-line"></i></div> <div class="content txt-bold"><p>Successfully changed the user password.</p> <p>You can now sign in with your new password.</p></div>',l=C(),s=b("button"),s.textContent="Close",p(e,"class","alert alert-success"),p(s,"type","button"),p(s,"class","btn btn-transparent btn-block")},m(o,c){m(o,e,c),m(o,l,c),m(o,s,c),n||(t=S(s,"click",a[7]),n=!0)},p:F,i:F,o:F,d(o){o&&(_(e),_(l),_(s)),n=!1,t()}}}function z(a){let e,l,s;return{c(){e=y("for "),l=b("strong"),s=y(a[4])},m(n,t){m(n,e,t),m(n,l,t),w(l,s)},p(n,t){t&16&&V(s,n[4])},d(n){n&&(_(e),_(l))}}}function x(a){let e,l,s,n,t,o,c,r;return{c(){e=b("label"),l=y("New password"),n=C(),t=b("input"),p(e,"for",s=a[10]),p(t,"type","password"),p(t,"id",o=a[10]),t.required=!0,t.autofocus=!0},m(i,u){m(i,e,u),w(e,l),m(i,n,u),m(i,t,u),R(t,a[0]),t.focus(),c||(r=S(t,"input",a[8]),c=!0)},p(i,u){u&1024&&s!==(s=i[10])&&p(e,"for",s),u&1024&&o!==(o=i[10])&&p(t,"id",o),u&1&&t.value!==i[0]&&R(t,i[0])},d(i){i&&(_(e),_(n),_(t)),c=!1,r()}}}function ee(a){let e,l,s,n,t,o,c,r;return{c(){e=b("label"),l=y("New password confirm"),n=C(),t=b("input"),p(e,"for",s=a[10]),p(t,"type","password"),p(t,"id",o=a[10]),t.required=!0},m(i,u){m(i,e,u),w(e,l),m(i,n,u),m(i,t,u),R(t,a[1]),c||(r=S(t,"input",a[9]),c=!0)},p(i,u){u&1024&&s!==(s=i[10])&&p(e,"for",s),u&1024&&o!==(o=i[10])&&p(t,"id",o),u&2&&t.value!==i[1]&&R(t,i[1])},d(i){i&&(_(e),_(n),_(t)),c=!1,r()}}}function te(a){let e,l,s,n;const t=[Z,X],o=[];function c(r,i){return r[3]?0:1}return e=c(a),l=o[e]=t[e](a),{c(){l.c(),s=G()},m(r,i){o[e].m(r,i),m(r,s,i),n=!0},p(r,i){let u=e;e=c(r),e===u?o[e].p(r,i):(B(),P(o[u],1,1,()=>{o[u]=null}),E(),l=o[e],l?l.p(r,i):(l=o[e]=t[e](r),l.c()),q(l,1),l.m(s.parentNode,s))},i(r){n||(q(l),n=!0)},o(r){P(l),n=!1},d(r){r&&_(s),o[e].d(r)}}}function se(a){let e,l;return e=new Y({props:{nobranding:!0,$$slots:{default:[te]},$$scope:{ctx:a}}}),{c(){N(e.$$.fragment)},m(s,n){L(e,s,n),l=!0},p(s,[n]){const t={};n&2079&&(t.$$scope={dirty:n,ctx:s}),e.$set(t)},i(s){l||(q(e.$$.fragment,s),l=!0)},o(s){P(e.$$.fragment,s),l=!1},d(s){H(e,s)}}}function le(a,e,l){let s,{params:n}=e,t="",o="",c=!1,r=!1;async function i(){if(c)return;l(2,c=!0);const k=new K("../");try{const h=O(n==null?void 0:n.token);await k.collection(h.collectionId).confirmPasswordReset(n==null?void 0:n.token,t,o),l(3,r=!0)}catch(h){Q.error(h)}l(2,c=!1)}const u=()=>window.close();function v(){t=this.value,l(0,t)}function g(){o=this.value,l(1,o)}return a.$$set=k=>{"params"in k&&l(6,n=k.params)},a.$$.update=()=>{a.$$.dirty&64&&l(4,s=j.getJWTPayload(n==null?void 0:n.token).email||"")},[t,o,c,r,s,i,n,u,v,g]}class oe extends A{constructor(e){super(),D(this,e,le,se,W,{params:6})}}export{oe as default};
|
||||||
|
|
@ -1 +1 @@
|
||||||
import{S as M,i as P,s as R,F as I,d as N,t as S,a as V,m as q,c as F,M as w,g as y,N as E,h as r,l as a,L as g,p as j,H as k,u,w as d,o as m,v,k as C,n as z}from"./index-CaLRFnGa.js";function A(o){let e,l,n;function t(i,f){return i[4]?K:J}let s=t(o),c=s(o);return{c(){e=u("div"),e.innerHTML='<div class="icon"><i class="ri-error-warning-line"></i></div> <div class="content txt-bold"><p>Invalid or expired verification token.</p></div>',l=v(),c.c(),n=g(),d(e,"class","alert alert-danger")},m(i,f){a(i,e,f),a(i,l,f),c.m(i,f),a(i,n,f)},p(i,f){s===(s=t(i))&&c?c.p(i,f):(c.d(1),c=s(i),c&&(c.c(),c.m(n.parentNode,n)))},d(i){i&&(r(e),r(l),r(n)),c.d(i)}}}function B(o){let e,l,n,t,s;return{c(){e=u("div"),e.innerHTML='<div class="icon"><i class="ri-checkbox-circle-line"></i></div> <div class="content txt-bold"><p>Please check your email for the new verification link.</p></div>',l=v(),n=u("button"),n.textContent="Close",d(e,"class","alert alert-success"),d(n,"type","button"),d(n,"class","btn btn-transparent btn-block")},m(c,i){a(c,e,i),a(c,l,i),a(c,n,i),t||(s=m(n,"click",o[8]),t=!0)},p:k,d(c){c&&(r(e),r(l),r(n)),t=!1,s()}}}function D(o){let e,l,n,t,s;return{c(){e=u("div"),e.innerHTML='<div class="icon"><i class="ri-checkbox-circle-line"></i></div> <div class="content txt-bold"><p>Successfully verified email address.</p></div>',l=v(),n=u("button"),n.textContent="Close",d(e,"class","alert alert-success"),d(n,"type","button"),d(n,"class","btn btn-transparent btn-block")},m(c,i){a(c,e,i),a(c,l,i),a(c,n,i),t||(s=m(n,"click",o[7]),t=!0)},p:k,d(c){c&&(r(e),r(l),r(n)),t=!1,s()}}}function G(o){let e;return{c(){e=u("div"),e.innerHTML='<div class="loader loader-lg"><em>Please wait...</em></div>',d(e,"class","txt-center")},m(l,n){a(l,e,n)},p:k,d(l){l&&r(e)}}}function J(o){let e,l,n;return{c(){e=u("button"),e.textContent="Close",d(e,"type","button"),d(e,"class","btn btn-transparent btn-block")},m(t,s){a(t,e,s),l||(n=m(e,"click",o[9]),l=!0)},p:k,d(t){t&&r(e),l=!1,n()}}}function K(o){let e,l,n,t;return{c(){e=u("button"),l=u("span"),l.textContent="Resend",d(l,"class","txt"),d(e,"type","button"),d(e,"class","btn btn-transparent btn-block"),e.disabled=o[3],C(e,"btn-loading",o[3])},m(s,c){a(s,e,c),z(e,l),n||(t=m(e,"click",o[5]),n=!0)},p(s,c){c&8&&(e.disabled=s[3]),c&8&&C(e,"btn-loading",s[3])},d(s){s&&r(e),n=!1,t()}}}function O(o){let e;function l(s,c){return s[1]?G:s[0]?D:s[2]?B:A}let n=l(o),t=n(o);return{c(){t.c(),e=g()},m(s,c){t.m(s,c),a(s,e,c)},p(s,c){n===(n=l(s))&&t?t.p(s,c):(t.d(1),t=n(s),t&&(t.c(),t.m(e.parentNode,e)))},d(s){s&&r(e),t.d(s)}}}function Q(o){let e,l;return e=new I({props:{nobranding:!0,$$slots:{default:[O]},$$scope:{ctx:o}}}),{c(){F(e.$$.fragment)},m(n,t){q(e,n,t),l=!0},p(n,[t]){const s={};t&2079&&(s.$$scope={dirty:t,ctx:n}),e.$set(s)},i(n){l||(V(e.$$.fragment,n),l=!0)},o(n){S(e.$$.fragment,n),l=!1},d(n){N(e,n)}}}function U(o,e,l){let n,{params:t}=e,s=!1,c=!1,i=!1,f=!1;x();async function x(){if(c)return;l(1,c=!0);const p=new w("../");try{const b=y(t==null?void 0:t.token);await p.collection(b.collectionId).confirmVerification(t==null?void 0:t.token),l(0,s=!0)}catch{l(0,s=!1)}l(1,c=!1)}async function T(){const p=y(t==null?void 0:t.token);if(f||!p.collectionId||!p.email)return;l(3,f=!0);const b=new w("../");try{const _=y(t==null?void 0:t.token);await b.collection(_.collectionId).requestVerification(_.email),l(2,i=!0)}catch(_){j.error(_),l(2,i=!1)}l(3,f=!1)}const h=()=>window.close(),H=()=>window.close(),L=()=>window.close();return o.$$set=p=>{"params"in p&&l(6,t=p.params)},o.$$.update=()=>{o.$$.dirty&64&&l(4,n=(t==null?void 0:t.token)&&E(t.token))},[s,c,i,f,n,T,t,h,H,L]}class X extends M{constructor(e){super(),P(this,e,U,Q,R,{params:6})}}export{X as default};
|
import{S as M,i as P,s as R,F as I,d as N,t as S,a as V,m as q,c as F,M as w,g as y,N as E,h as r,l as a,L as g,p as j,H as k,u,w as d,o as m,v,k as C,n as z}from"./index-D5lV2xwk.js";function A(o){let e,l,n;function t(i,f){return i[4]?K:J}let s=t(o),c=s(o);return{c(){e=u("div"),e.innerHTML='<div class="icon"><i class="ri-error-warning-line"></i></div> <div class="content txt-bold"><p>Invalid or expired verification token.</p></div>',l=v(),c.c(),n=g(),d(e,"class","alert alert-danger")},m(i,f){a(i,e,f),a(i,l,f),c.m(i,f),a(i,n,f)},p(i,f){s===(s=t(i))&&c?c.p(i,f):(c.d(1),c=s(i),c&&(c.c(),c.m(n.parentNode,n)))},d(i){i&&(r(e),r(l),r(n)),c.d(i)}}}function B(o){let e,l,n,t,s;return{c(){e=u("div"),e.innerHTML='<div class="icon"><i class="ri-checkbox-circle-line"></i></div> <div class="content txt-bold"><p>Please check your email for the new verification link.</p></div>',l=v(),n=u("button"),n.textContent="Close",d(e,"class","alert alert-success"),d(n,"type","button"),d(n,"class","btn btn-transparent btn-block")},m(c,i){a(c,e,i),a(c,l,i),a(c,n,i),t||(s=m(n,"click",o[8]),t=!0)},p:k,d(c){c&&(r(e),r(l),r(n)),t=!1,s()}}}function D(o){let e,l,n,t,s;return{c(){e=u("div"),e.innerHTML='<div class="icon"><i class="ri-checkbox-circle-line"></i></div> <div class="content txt-bold"><p>Successfully verified email address.</p></div>',l=v(),n=u("button"),n.textContent="Close",d(e,"class","alert alert-success"),d(n,"type","button"),d(n,"class","btn btn-transparent btn-block")},m(c,i){a(c,e,i),a(c,l,i),a(c,n,i),t||(s=m(n,"click",o[7]),t=!0)},p:k,d(c){c&&(r(e),r(l),r(n)),t=!1,s()}}}function G(o){let e;return{c(){e=u("div"),e.innerHTML='<div class="loader loader-lg"><em>Please wait...</em></div>',d(e,"class","txt-center")},m(l,n){a(l,e,n)},p:k,d(l){l&&r(e)}}}function J(o){let e,l,n;return{c(){e=u("button"),e.textContent="Close",d(e,"type","button"),d(e,"class","btn btn-transparent btn-block")},m(t,s){a(t,e,s),l||(n=m(e,"click",o[9]),l=!0)},p:k,d(t){t&&r(e),l=!1,n()}}}function K(o){let e,l,n,t;return{c(){e=u("button"),l=u("span"),l.textContent="Resend",d(l,"class","txt"),d(e,"type","button"),d(e,"class","btn btn-transparent btn-block"),e.disabled=o[3],C(e,"btn-loading",o[3])},m(s,c){a(s,e,c),z(e,l),n||(t=m(e,"click",o[5]),n=!0)},p(s,c){c&8&&(e.disabled=s[3]),c&8&&C(e,"btn-loading",s[3])},d(s){s&&r(e),n=!1,t()}}}function O(o){let e;function l(s,c){return s[1]?G:s[0]?D:s[2]?B:A}let n=l(o),t=n(o);return{c(){t.c(),e=g()},m(s,c){t.m(s,c),a(s,e,c)},p(s,c){n===(n=l(s))&&t?t.p(s,c):(t.d(1),t=n(s),t&&(t.c(),t.m(e.parentNode,e)))},d(s){s&&r(e),t.d(s)}}}function Q(o){let e,l;return e=new I({props:{nobranding:!0,$$slots:{default:[O]},$$scope:{ctx:o}}}),{c(){F(e.$$.fragment)},m(n,t){q(e,n,t),l=!0},p(n,[t]){const s={};t&2079&&(s.$$scope={dirty:t,ctx:n}),e.$set(s)},i(n){l||(V(e.$$.fragment,n),l=!0)},o(n){S(e.$$.fragment,n),l=!1},d(n){N(e,n)}}}function U(o,e,l){let n,{params:t}=e,s=!1,c=!1,i=!1,f=!1;x();async function x(){if(c)return;l(1,c=!0);const p=new w("../");try{const b=y(t==null?void 0:t.token);await p.collection(b.collectionId).confirmVerification(t==null?void 0:t.token),l(0,s=!0)}catch{l(0,s=!1)}l(1,c=!1)}async function T(){const p=y(t==null?void 0:t.token);if(f||!p.collectionId||!p.email)return;l(3,f=!0);const b=new w("../");try{const _=y(t==null?void 0:t.token);await b.collection(_.collectionId).requestVerification(_.email),l(2,i=!0)}catch(_){j.error(_),l(2,i=!1)}l(3,f=!1)}const h=()=>window.close(),H=()=>window.close(),L=()=>window.close();return o.$$set=p=>{"params"in p&&l(6,t=p.params)},o.$$.update=()=>{o.$$.dirty&64&&l(4,n=(t==null?void 0:t.token)&&E(t.token))},[s,c,i,f,n,T,t,h,H,L]}class X extends M{constructor(e){super(),P(this,e,U,Q,R,{params:6})}}export{X as default};
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
import{S as L,i as W,s as y,F as D,d as R,t as J,a as N,m as T,c as j,J as M,f as G,h as b,j as O,k as H,l as w,n as c,o as z,E as Q,q as U,G as V,u as _,A as P,v as h,w as f,p as I,K as X,r as Y,I as Z,z as q}from"./index-CaLRFnGa.js";function K(r){let e,n,s;return{c(){e=P("for "),n=_("strong"),s=P(r[3]),f(n,"class","txt-nowrap")},m(l,t){w(l,e,t),w(l,n,t),c(n,s)},p(l,t){t&8&&Z(s,l[3])},d(l){l&&(b(e),b(n))}}}function x(r){let e,n,s,l,t,i,p,d;return{c(){e=_("label"),n=P("New password"),l=h(),t=_("input"),f(e,"for",s=r[8]),f(t,"type","password"),f(t,"id",i=r[8]),t.required=!0,t.autofocus=!0},m(u,a){w(u,e,a),c(e,n),w(u,l,a),w(u,t,a),q(t,r[0]),t.focus(),p||(d=z(t,"input",r[6]),p=!0)},p(u,a){a&256&&s!==(s=u[8])&&f(e,"for",s),a&256&&i!==(i=u[8])&&f(t,"id",i),a&1&&t.value!==u[0]&&q(t,u[0])},d(u){u&&(b(e),b(l),b(t)),p=!1,d()}}}function ee(r){let e,n,s,l,t,i,p,d;return{c(){e=_("label"),n=P("New password confirm"),l=h(),t=_("input"),f(e,"for",s=r[8]),f(t,"type","password"),f(t,"id",i=r[8]),t.required=!0},m(u,a){w(u,e,a),c(e,n),w(u,l,a),w(u,t,a),q(t,r[1]),p||(d=z(t,"input",r[7]),p=!0)},p(u,a){a&256&&s!==(s=u[8])&&f(e,"for",s),a&256&&i!==(i=u[8])&&f(t,"id",i),a&2&&t.value!==u[1]&&q(t,u[1])},d(u){u&&(b(e),b(l),b(t)),p=!1,d()}}}function te(r){let e,n,s,l,t,i,p,d,u,a,g,S,C,v,k,F,A,m=r[3]&&K(r);return i=new G({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:o})=>({8:o}),({uniqueId:o})=>o?256:0]},$$scope:{ctx:r}}}),d=new G({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:o})=>({8:o}),({uniqueId:o})=>o?256:0]},$$scope:{ctx:r}}}),{c(){e=_("form"),n=_("div"),s=_("h4"),l=P(`Reset your superuser password
|
import{S as L,i as W,s as y,F as D,d as R,t as J,a as N,m as T,c as j,J as M,f as G,h as b,j as O,k as H,l as w,n as c,o as z,E as Q,q as U,G as V,u as _,A as P,v as h,w as f,p as I,K as X,r as Y,I as Z,z as q}from"./index-D5lV2xwk.js";function K(r){let e,n,s;return{c(){e=P("for "),n=_("strong"),s=P(r[3]),f(n,"class","txt-nowrap")},m(l,t){w(l,e,t),w(l,n,t),c(n,s)},p(l,t){t&8&&Z(s,l[3])},d(l){l&&(b(e),b(n))}}}function x(r){let e,n,s,l,t,i,p,d;return{c(){e=_("label"),n=P("New password"),l=h(),t=_("input"),f(e,"for",s=r[8]),f(t,"type","password"),f(t,"id",i=r[8]),t.required=!0,t.autofocus=!0},m(u,a){w(u,e,a),c(e,n),w(u,l,a),w(u,t,a),q(t,r[0]),t.focus(),p||(d=z(t,"input",r[6]),p=!0)},p(u,a){a&256&&s!==(s=u[8])&&f(e,"for",s),a&256&&i!==(i=u[8])&&f(t,"id",i),a&1&&t.value!==u[0]&&q(t,u[0])},d(u){u&&(b(e),b(l),b(t)),p=!1,d()}}}function ee(r){let e,n,s,l,t,i,p,d;return{c(){e=_("label"),n=P("New password confirm"),l=h(),t=_("input"),f(e,"for",s=r[8]),f(t,"type","password"),f(t,"id",i=r[8]),t.required=!0},m(u,a){w(u,e,a),c(e,n),w(u,l,a),w(u,t,a),q(t,r[1]),p||(d=z(t,"input",r[7]),p=!0)},p(u,a){a&256&&s!==(s=u[8])&&f(e,"for",s),a&256&&i!==(i=u[8])&&f(t,"id",i),a&2&&t.value!==u[1]&&q(t,u[1])},d(u){u&&(b(e),b(l),b(t)),p=!1,d()}}}function te(r){let e,n,s,l,t,i,p,d,u,a,g,S,C,v,k,F,A,m=r[3]&&K(r);return i=new G({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:o})=>({8:o}),({uniqueId:o})=>o?256:0]},$$scope:{ctx:r}}}),d=new G({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:o})=>({8:o}),({uniqueId:o})=>o?256:0]},$$scope:{ctx:r}}}),{c(){e=_("form"),n=_("div"),s=_("h4"),l=P(`Reset your superuser password
|
||||||
`),m&&m.c(),t=h(),j(i.$$.fragment),p=h(),j(d.$$.fragment),u=h(),a=_("button"),g=_("span"),g.textContent="Set new password",S=h(),C=_("div"),v=_("a"),v.textContent="Back to login",f(s,"class","m-b-xs"),f(n,"class","content txt-center m-b-sm"),f(g,"class","txt"),f(a,"type","submit"),f(a,"class","btn btn-lg btn-block"),a.disabled=r[2],H(a,"btn-loading",r[2]),f(e,"class","m-b-base"),f(v,"href","/login"),f(v,"class","link-hint"),f(C,"class","content txt-center")},m(o,$){w(o,e,$),c(e,n),c(n,s),c(s,l),m&&m.m(s,null),c(e,t),T(i,e,null),c(e,p),T(d,e,null),c(e,u),c(e,a),c(a,g),w(o,S,$),w(o,C,$),c(C,v),k=!0,F||(A=[z(e,"submit",U(r[4])),Q(V.call(null,v))],F=!0)},p(o,$){o[3]?m?m.p(o,$):(m=K(o),m.c(),m.m(s,null)):m&&(m.d(1),m=null);const B={};$&769&&(B.$$scope={dirty:$,ctx:o}),i.$set(B);const E={};$&770&&(E.$$scope={dirty:$,ctx:o}),d.$set(E),(!k||$&4)&&(a.disabled=o[2]),(!k||$&4)&&H(a,"btn-loading",o[2])},i(o){k||(N(i.$$.fragment,o),N(d.$$.fragment,o),k=!0)},o(o){J(i.$$.fragment,o),J(d.$$.fragment,o),k=!1},d(o){o&&(b(e),b(S),b(C)),m&&m.d(),R(i),R(d),F=!1,O(A)}}}function se(r){let e,n;return e=new D({props:{$$slots:{default:[te]},$$scope:{ctx:r}}}),{c(){j(e.$$.fragment)},m(s,l){T(e,s,l),n=!0},p(s,[l]){const t={};l&527&&(t.$$scope={dirty:l,ctx:s}),e.$set(t)},i(s){n||(N(e.$$.fragment,s),n=!0)},o(s){J(e.$$.fragment,s),n=!1},d(s){R(e,s)}}}function le(r,e,n){let s,{params:l}=e,t="",i="",p=!1;async function d(){if(!p){n(2,p=!0);try{await I.collection("_superusers").confirmPasswordReset(l==null?void 0:l.token,t,i),X("Successfully set a new superuser password."),Y("/")}catch(g){I.error(g)}n(2,p=!1)}}function u(){t=this.value,n(0,t)}function a(){i=this.value,n(1,i)}return r.$$set=g=>{"params"in g&&n(5,l=g.params)},r.$$.update=()=>{r.$$.dirty&32&&n(3,s=M.getJWTPayload(l==null?void 0:l.token).email||"")},[t,i,p,s,d,l,u,a]}class ae extends L{constructor(e){super(),W(this,e,le,se,y,{params:5})}}export{ae as default};
|
`),m&&m.c(),t=h(),j(i.$$.fragment),p=h(),j(d.$$.fragment),u=h(),a=_("button"),g=_("span"),g.textContent="Set new password",S=h(),C=_("div"),v=_("a"),v.textContent="Back to login",f(s,"class","m-b-xs"),f(n,"class","content txt-center m-b-sm"),f(g,"class","txt"),f(a,"type","submit"),f(a,"class","btn btn-lg btn-block"),a.disabled=r[2],H(a,"btn-loading",r[2]),f(e,"class","m-b-base"),f(v,"href","/login"),f(v,"class","link-hint"),f(C,"class","content txt-center")},m(o,$){w(o,e,$),c(e,n),c(n,s),c(s,l),m&&m.m(s,null),c(e,t),T(i,e,null),c(e,p),T(d,e,null),c(e,u),c(e,a),c(a,g),w(o,S,$),w(o,C,$),c(C,v),k=!0,F||(A=[z(e,"submit",U(r[4])),Q(V.call(null,v))],F=!0)},p(o,$){o[3]?m?m.p(o,$):(m=K(o),m.c(),m.m(s,null)):m&&(m.d(1),m=null);const B={};$&769&&(B.$$scope={dirty:$,ctx:o}),i.$set(B);const E={};$&770&&(E.$$scope={dirty:$,ctx:o}),d.$set(E),(!k||$&4)&&(a.disabled=o[2]),(!k||$&4)&&H(a,"btn-loading",o[2])},i(o){k||(N(i.$$.fragment,o),N(d.$$.fragment,o),k=!0)},o(o){J(i.$$.fragment,o),J(d.$$.fragment,o),k=!1},d(o){o&&(b(e),b(S),b(C)),m&&m.d(),R(i),R(d),F=!1,O(A)}}}function se(r){let e,n;return e=new D({props:{$$slots:{default:[te]},$$scope:{ctx:r}}}),{c(){j(e.$$.fragment)},m(s,l){T(e,s,l),n=!0},p(s,[l]){const t={};l&527&&(t.$$scope={dirty:l,ctx:s}),e.$set(t)},i(s){n||(N(e.$$.fragment,s),n=!0)},o(s){J(e.$$.fragment,s),n=!1},d(s){R(e,s)}}}function le(r,e,n){let s,{params:l}=e,t="",i="",p=!1;async function d(){if(!p){n(2,p=!0);try{await I.collection("_superusers").confirmPasswordReset(l==null?void 0:l.token,t,i),X("Successfully set a new superuser password."),Y("/")}catch(g){I.error(g)}n(2,p=!1)}}function u(){t=this.value,n(0,t)}function a(){i=this.value,n(1,i)}return r.$$set=g=>{"params"in g&&n(5,l=g.params)},r.$$.update=()=>{r.$$.dirty&32&&n(3,s=M.getJWTPayload(l==null?void 0:l.token).email||"")},[t,i,p,s,d,l,u,a]}class ae extends L{constructor(e){super(),W(this,e,le,se,y,{params:5})}}export{ae as default};
|
||||||
|
|
@ -1 +1 @@
|
||||||
import{S as M,i as T,s as z,F as A,d as E,t as w,a as y,m as H,c as L,h as g,C as B,D,l as k,n as d,E as G,G as I,v,u as m,w as p,p as C,H as F,I as N,A as h,f as j,k as P,o as R,q as J,z as S}from"./index-CaLRFnGa.js";function K(u){let e,s,n,l,t,r,c,_,i,a,b,f;return l=new j({props:{class:"form-field required",name:"email",$$slots:{default:[Q,({uniqueId:o})=>({5:o}),({uniqueId:o})=>o?32:0]},$$scope:{ctx:u}}}),{c(){e=m("form"),s=m("div"),s.innerHTML='<h4 class="m-b-xs">Forgotten superuser password</h4> <p>Enter the email associated with your account and we’ll send you a recovery link:</p>',n=v(),L(l.$$.fragment),t=v(),r=m("button"),c=m("i"),_=v(),i=m("span"),i.textContent="Send recovery link",p(s,"class","content txt-center m-b-sm"),p(c,"class","ri-mail-send-line"),p(i,"class","txt"),p(r,"type","submit"),p(r,"class","btn btn-lg btn-block"),r.disabled=u[1],P(r,"btn-loading",u[1]),p(e,"class","m-b-base")},m(o,$){k(o,e,$),d(e,s),d(e,n),H(l,e,null),d(e,t),d(e,r),d(r,c),d(r,_),d(r,i),a=!0,b||(f=R(e,"submit",J(u[3])),b=!0)},p(o,$){const q={};$&97&&(q.$$scope={dirty:$,ctx:o}),l.$set(q),(!a||$&2)&&(r.disabled=o[1]),(!a||$&2)&&P(r,"btn-loading",o[1])},i(o){a||(y(l.$$.fragment,o),a=!0)},o(o){w(l.$$.fragment,o),a=!1},d(o){o&&g(e),E(l),b=!1,f()}}}function O(u){let e,s,n,l,t,r,c,_,i;return{c(){e=m("div"),s=m("div"),s.innerHTML='<i class="ri-checkbox-circle-line"></i>',n=v(),l=m("div"),t=m("p"),r=h("Check "),c=m("strong"),_=h(u[0]),i=h(" for the recovery link."),p(s,"class","icon"),p(c,"class","txt-nowrap"),p(l,"class","content"),p(e,"class","alert alert-success")},m(a,b){k(a,e,b),d(e,s),d(e,n),d(e,l),d(l,t),d(t,r),d(t,c),d(c,_),d(t,i)},p(a,b){b&1&&N(_,a[0])},i:F,o:F,d(a){a&&g(e)}}}function Q(u){let e,s,n,l,t,r,c,_;return{c(){e=m("label"),s=h("Email"),l=v(),t=m("input"),p(e,"for",n=u[5]),p(t,"type","email"),p(t,"id",r=u[5]),t.required=!0,t.autofocus=!0},m(i,a){k(i,e,a),d(e,s),k(i,l,a),k(i,t,a),S(t,u[0]),t.focus(),c||(_=R(t,"input",u[4]),c=!0)},p(i,a){a&32&&n!==(n=i[5])&&p(e,"for",n),a&32&&r!==(r=i[5])&&p(t,"id",r),a&1&&t.value!==i[0]&&S(t,i[0])},d(i){i&&(g(e),g(l),g(t)),c=!1,_()}}}function U(u){let e,s,n,l,t,r,c,_;const i=[O,K],a=[];function b(f,o){return f[2]?0:1}return e=b(u),s=a[e]=i[e](u),{c(){s.c(),n=v(),l=m("div"),t=m("a"),t.textContent="Back to login",p(t,"href","/login"),p(t,"class","link-hint"),p(l,"class","content txt-center")},m(f,o){a[e].m(f,o),k(f,n,o),k(f,l,o),d(l,t),r=!0,c||(_=G(I.call(null,t)),c=!0)},p(f,o){let $=e;e=b(f),e===$?a[e].p(f,o):(B(),w(a[$],1,1,()=>{a[$]=null}),D(),s=a[e],s?s.p(f,o):(s=a[e]=i[e](f),s.c()),y(s,1),s.m(n.parentNode,n))},i(f){r||(y(s),r=!0)},o(f){w(s),r=!1},d(f){f&&(g(n),g(l)),a[e].d(f),c=!1,_()}}}function V(u){let e,s;return e=new A({props:{$$slots:{default:[U]},$$scope:{ctx:u}}}),{c(){L(e.$$.fragment)},m(n,l){H(e,n,l),s=!0},p(n,[l]){const t={};l&71&&(t.$$scope={dirty:l,ctx:n}),e.$set(t)},i(n){s||(y(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){E(e,n)}}}function W(u,e,s){let n="",l=!1,t=!1;async function r(){if(!l){s(1,l=!0);try{await C.collection("_superusers").requestPasswordReset(n),s(2,t=!0)}catch(_){C.error(_)}s(1,l=!1)}}function c(){n=this.value,s(0,n)}return[n,l,t,r,c]}class Y extends M{constructor(e){super(),T(this,e,W,V,z,{})}}export{Y as default};
|
import{S as M,i as T,s as z,F as A,d as E,t as w,a as y,m as H,c as L,h as g,C as B,D,l as k,n as d,E as G,G as I,v,u as m,w as p,p as C,H as F,I as N,A as h,f as j,k as P,o as R,q as J,z as S}from"./index-D5lV2xwk.js";function K(u){let e,s,n,l,t,r,c,_,i,a,b,f;return l=new j({props:{class:"form-field required",name:"email",$$slots:{default:[Q,({uniqueId:o})=>({5:o}),({uniqueId:o})=>o?32:0]},$$scope:{ctx:u}}}),{c(){e=m("form"),s=m("div"),s.innerHTML='<h4 class="m-b-xs">Forgotten superuser password</h4> <p>Enter the email associated with your account and we’ll send you a recovery link:</p>',n=v(),L(l.$$.fragment),t=v(),r=m("button"),c=m("i"),_=v(),i=m("span"),i.textContent="Send recovery link",p(s,"class","content txt-center m-b-sm"),p(c,"class","ri-mail-send-line"),p(i,"class","txt"),p(r,"type","submit"),p(r,"class","btn btn-lg btn-block"),r.disabled=u[1],P(r,"btn-loading",u[1]),p(e,"class","m-b-base")},m(o,$){k(o,e,$),d(e,s),d(e,n),H(l,e,null),d(e,t),d(e,r),d(r,c),d(r,_),d(r,i),a=!0,b||(f=R(e,"submit",J(u[3])),b=!0)},p(o,$){const q={};$&97&&(q.$$scope={dirty:$,ctx:o}),l.$set(q),(!a||$&2)&&(r.disabled=o[1]),(!a||$&2)&&P(r,"btn-loading",o[1])},i(o){a||(y(l.$$.fragment,o),a=!0)},o(o){w(l.$$.fragment,o),a=!1},d(o){o&&g(e),E(l),b=!1,f()}}}function O(u){let e,s,n,l,t,r,c,_,i;return{c(){e=m("div"),s=m("div"),s.innerHTML='<i class="ri-checkbox-circle-line"></i>',n=v(),l=m("div"),t=m("p"),r=h("Check "),c=m("strong"),_=h(u[0]),i=h(" for the recovery link."),p(s,"class","icon"),p(c,"class","txt-nowrap"),p(l,"class","content"),p(e,"class","alert alert-success")},m(a,b){k(a,e,b),d(e,s),d(e,n),d(e,l),d(l,t),d(t,r),d(t,c),d(c,_),d(t,i)},p(a,b){b&1&&N(_,a[0])},i:F,o:F,d(a){a&&g(e)}}}function Q(u){let e,s,n,l,t,r,c,_;return{c(){e=m("label"),s=h("Email"),l=v(),t=m("input"),p(e,"for",n=u[5]),p(t,"type","email"),p(t,"id",r=u[5]),t.required=!0,t.autofocus=!0},m(i,a){k(i,e,a),d(e,s),k(i,l,a),k(i,t,a),S(t,u[0]),t.focus(),c||(_=R(t,"input",u[4]),c=!0)},p(i,a){a&32&&n!==(n=i[5])&&p(e,"for",n),a&32&&r!==(r=i[5])&&p(t,"id",r),a&1&&t.value!==i[0]&&S(t,i[0])},d(i){i&&(g(e),g(l),g(t)),c=!1,_()}}}function U(u){let e,s,n,l,t,r,c,_;const i=[O,K],a=[];function b(f,o){return f[2]?0:1}return e=b(u),s=a[e]=i[e](u),{c(){s.c(),n=v(),l=m("div"),t=m("a"),t.textContent="Back to login",p(t,"href","/login"),p(t,"class","link-hint"),p(l,"class","content txt-center")},m(f,o){a[e].m(f,o),k(f,n,o),k(f,l,o),d(l,t),r=!0,c||(_=G(I.call(null,t)),c=!0)},p(f,o){let $=e;e=b(f),e===$?a[e].p(f,o):(B(),w(a[$],1,1,()=>{a[$]=null}),D(),s=a[e],s?s.p(f,o):(s=a[e]=i[e](f),s.c()),y(s,1),s.m(n.parentNode,n))},i(f){r||(y(s),r=!0)},o(f){w(s),r=!1},d(f){f&&(g(n),g(l)),a[e].d(f),c=!1,_()}}}function V(u){let e,s;return e=new A({props:{$$slots:{default:[U]},$$scope:{ctx:u}}}),{c(){L(e.$$.fragment)},m(n,l){H(e,n,l),s=!0},p(n,[l]){const t={};l&71&&(t.$$scope={dirty:l,ctx:n}),e.$set(t)},i(n){s||(y(e.$$.fragment,n),s=!0)},o(n){w(e.$$.fragment,n),s=!1},d(n){E(e,n)}}}function W(u,e,s){let n="",l=!1,t=!1;async function r(){if(!l){s(1,l=!0);try{await C.collection("_superusers").requestPasswordReset(n),s(2,t=!0)}catch(_){C.error(_)}s(1,l=!1)}}function c(){n=this.value,s(0,n)}return[n,l,t,r,c]}class Y extends M{constructor(e){super(),T(this,e,W,V,z,{})}}export{Y as default};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as se,i as ne,s as oe,X as H,h as b,t as X,a as V,I as Z,Z as ee,_ as ye,C as te,$ as Te,D as le,l as v,n as u,u as p,v as S,A as D,w as k,k as L,o as ae,W as Ee,d as G,m as Q,c as x,V as Ce,Y as fe,J as qe,p as Oe,a0 as pe}from"./index-CaLRFnGa.js";function me(o,t,e){const n=o.slice();return n[4]=t[e],n}function _e(o,t,e){const n=o.slice();return n[4]=t[e],n}function he(o,t){let e,n=t[4].code+"",d,c,r,a;function f(){return t[3](t[4])}return{key:o,first:null,c(){e=p("button"),d=D(n),c=S(),k(e,"class","tab-item"),L(e,"active",t[1]===t[4].code),this.first=e},m(g,y){v(g,e,y),u(e,d),u(e,c),r||(a=ae(e,"click",f),r=!0)},p(g,y){t=g,y&4&&n!==(n=t[4].code+"")&&Z(d,n),y&6&&L(e,"active",t[1]===t[4].code)},d(g){g&&b(e),r=!1,a()}}}function be(o,t){let e,n,d,c;return n=new Ee({props:{content:t[4].body}}),{key:o,first:null,c(){e=p("div"),x(n.$$.fragment),d=S(),k(e,"class","tab-item"),L(e,"active",t[1]===t[4].code),this.first=e},m(r,a){v(r,e,a),Q(n,e,null),u(e,d),c=!0},p(r,a){t=r;const f={};a&4&&(f.content=t[4].body),n.$set(f),(!c||a&6)&&L(e,"active",t[1]===t[4].code)},i(r){c||(V(n.$$.fragment,r),c=!0)},o(r){X(n.$$.fragment,r),c=!1},d(r){r&&b(e),G(n)}}}function Ae(o){let t,e,n,d,c,r,a,f=o[0].name+"",g,y,F,q,J,W,U,O,A,T,C,R=[],M=new Map,j,N,h=[],K=new Map,E,P=H(o[2]);const B=l=>l[4].code;for(let l=0;l<P.length;l+=1){let s=_e(o,P,l),_=B(s);M.set(_,R[l]=he(_,s))}let m=H(o[2]);const Y=l=>l[4].code;for(let l=0;l<m.length;l+=1){let s=me(o,m,l),_=Y(s);K.set(_,h[l]=be(_,s))}return{c(){t=p("div"),e=p("strong"),e.textContent="POST",n=S(),d=p("div"),c=p("p"),r=D("/api/collections/"),a=p("strong"),g=D(f),y=D("/confirm-password-reset"),F=S(),q=p("div"),q.textContent="Body Parameters",J=S(),W=p("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>token</span></div></td> <td><span class="label">String</span></td> <td>The token from the password reset request email.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>password</span></div></td> <td><span class="label">String</span></td> <td>The new password to set.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>passwordConfirm</span></div></td> <td><span class="label">String</span></td> <td>The new password confirmation.</td></tr></tbody>',U=S(),O=p("div"),O.textContent="Responses",A=S(),T=p("div"),C=p("div");for(let l=0;l<R.length;l+=1)R[l].c();j=S(),N=p("div");for(let l=0;l<h.length;l+=1)h[l].c();k(e,"class","label label-primary"),k(d,"class","content"),k(t,"class","alert alert-success"),k(q,"class","section-title"),k(W,"class","table-compact table-border m-b-base"),k(O,"class","section-title"),k(C,"class","tabs-header compact combined left"),k(N,"class","tabs-content"),k(T,"class","tabs")},m(l,s){v(l,t,s),u(t,e),u(t,n),u(t,d),u(d,c),u(c,r),u(c,a),u(a,g),u(c,y),v(l,F,s),v(l,q,s),v(l,J,s),v(l,W,s),v(l,U,s),v(l,O,s),v(l,A,s),v(l,T,s),u(T,C);for(let _=0;_<R.length;_+=1)R[_]&&R[_].m(C,null);u(T,j),u(T,N);for(let _=0;_<h.length;_+=1)h[_]&&h[_].m(N,null);E=!0},p(l,[s]){(!E||s&1)&&f!==(f=l[0].name+"")&&Z(g,f),s&6&&(P=H(l[2]),R=ee(R,s,B,1,l,P,M,C,ye,he,null,_e)),s&6&&(m=H(l[2]),te(),h=ee(h,s,Y,1,l,m,K,N,Te,be,null,me),le())},i(l){if(!E){for(let s=0;s<m.length;s+=1)V(h[s]);E=!0}},o(l){for(let s=0;s<h.length;s+=1)X(h[s]);E=!1},d(l){l&&(b(t),b(F),b(q),b(J),b(W),b(U),b(O),b(A),b(T));for(let s=0;s<R.length;s+=1)R[s].d();for(let s=0;s<h.length;s+=1)h[s].d()}}}function We(o,t,e){let{collection:n}=t,d=204,c=[];const r=a=>e(1,d=a.code);return o.$$set=a=>{"collection"in a&&e(0,n=a.collection)},e(2,c=[{code:204,body:"null"},{code:400,body:`
|
import{S as se,i as ne,s as oe,X as H,h as b,t as X,a as V,I as Z,Z as ee,_ as ye,C as te,$ as Te,D as le,l as v,n as u,u as p,v as S,A as D,w as k,k as L,o as ae,W as Ee,d as G,m as Q,c as x,V as Ce,Y as fe,J as qe,p as Oe,a0 as pe}from"./index-D5lV2xwk.js";function me(o,t,e){const n=o.slice();return n[4]=t[e],n}function _e(o,t,e){const n=o.slice();return n[4]=t[e],n}function he(o,t){let e,n=t[4].code+"",d,c,r,a;function f(){return t[3](t[4])}return{key:o,first:null,c(){e=p("button"),d=D(n),c=S(),k(e,"class","tab-item"),L(e,"active",t[1]===t[4].code),this.first=e},m(g,y){v(g,e,y),u(e,d),u(e,c),r||(a=ae(e,"click",f),r=!0)},p(g,y){t=g,y&4&&n!==(n=t[4].code+"")&&Z(d,n),y&6&&L(e,"active",t[1]===t[4].code)},d(g){g&&b(e),r=!1,a()}}}function be(o,t){let e,n,d,c;return n=new Ee({props:{content:t[4].body}}),{key:o,first:null,c(){e=p("div"),x(n.$$.fragment),d=S(),k(e,"class","tab-item"),L(e,"active",t[1]===t[4].code),this.first=e},m(r,a){v(r,e,a),Q(n,e,null),u(e,d),c=!0},p(r,a){t=r;const f={};a&4&&(f.content=t[4].body),n.$set(f),(!c||a&6)&&L(e,"active",t[1]===t[4].code)},i(r){c||(V(n.$$.fragment,r),c=!0)},o(r){X(n.$$.fragment,r),c=!1},d(r){r&&b(e),G(n)}}}function Ae(o){let t,e,n,d,c,r,a,f=o[0].name+"",g,y,F,q,J,W,U,O,A,T,C,R=[],M=new Map,j,N,h=[],K=new Map,E,P=H(o[2]);const B=l=>l[4].code;for(let l=0;l<P.length;l+=1){let s=_e(o,P,l),_=B(s);M.set(_,R[l]=he(_,s))}let m=H(o[2]);const Y=l=>l[4].code;for(let l=0;l<m.length;l+=1){let s=me(o,m,l),_=Y(s);K.set(_,h[l]=be(_,s))}return{c(){t=p("div"),e=p("strong"),e.textContent="POST",n=S(),d=p("div"),c=p("p"),r=D("/api/collections/"),a=p("strong"),g=D(f),y=D("/confirm-password-reset"),F=S(),q=p("div"),q.textContent="Body Parameters",J=S(),W=p("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>token</span></div></td> <td><span class="label">String</span></td> <td>The token from the password reset request email.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>password</span></div></td> <td><span class="label">String</span></td> <td>The new password to set.</td></tr> <tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>passwordConfirm</span></div></td> <td><span class="label">String</span></td> <td>The new password confirmation.</td></tr></tbody>',U=S(),O=p("div"),O.textContent="Responses",A=S(),T=p("div"),C=p("div");for(let l=0;l<R.length;l+=1)R[l].c();j=S(),N=p("div");for(let l=0;l<h.length;l+=1)h[l].c();k(e,"class","label label-primary"),k(d,"class","content"),k(t,"class","alert alert-success"),k(q,"class","section-title"),k(W,"class","table-compact table-border m-b-base"),k(O,"class","section-title"),k(C,"class","tabs-header compact combined left"),k(N,"class","tabs-content"),k(T,"class","tabs")},m(l,s){v(l,t,s),u(t,e),u(t,n),u(t,d),u(d,c),u(c,r),u(c,a),u(a,g),u(c,y),v(l,F,s),v(l,q,s),v(l,J,s),v(l,W,s),v(l,U,s),v(l,O,s),v(l,A,s),v(l,T,s),u(T,C);for(let _=0;_<R.length;_+=1)R[_]&&R[_].m(C,null);u(T,j),u(T,N);for(let _=0;_<h.length;_+=1)h[_]&&h[_].m(N,null);E=!0},p(l,[s]){(!E||s&1)&&f!==(f=l[0].name+"")&&Z(g,f),s&6&&(P=H(l[2]),R=ee(R,s,B,1,l,P,M,C,ye,he,null,_e)),s&6&&(m=H(l[2]),te(),h=ee(h,s,Y,1,l,m,K,N,Te,be,null,me),le())},i(l){if(!E){for(let s=0;s<m.length;s+=1)V(h[s]);E=!0}},o(l){for(let s=0;s<h.length;s+=1)X(h[s]);E=!1},d(l){l&&(b(t),b(F),b(q),b(J),b(W),b(U),b(O),b(A),b(T));for(let s=0;s<R.length;s+=1)R[s].d();for(let s=0;s<h.length;s+=1)h[s].d()}}}function We(o,t,e){let{collection:n}=t,d=204,c=[];const r=a=>e(1,d=a.code);return o.$$set=a=>{"collection"in a&&e(0,n=a.collection)},e(2,c=[{code:204,body:"null"},{code:400,body:`
|
||||||
{
|
{
|
||||||
"status": 400,
|
"status": 400,
|
||||||
"message": "An error occurred while validating the submitted data.",
|
"message": "An error occurred while validating the submitted data.",
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as re,i as ae,s as be,V as pe,W as ue,J as P,h as s,d as se,t as ne,a as ie,I as me,l as n,n as y,m as ce,u as p,A as I,v as a,c as le,w as u,p as de}from"./index-CaLRFnGa.js";function he(o){var B,U,W,A,L,H,T,q,J,M,j,N;let i,m,c=o[0].name+"",b,d,k,h,D,f,_,l,S,$,w,g,C,v,E,r,R;return l=new pe({props:{js:`
|
import{S as re,i as ae,s as be,V as pe,W as ue,J as P,h as s,d as se,t as ne,a as ie,I as me,l as n,n as y,m as ce,u as p,A as I,v as a,c as le,w as u,p as de}from"./index-D5lV2xwk.js";function he(o){var B,U,W,A,L,H,T,q,J,M,j,N;let i,m,c=o[0].name+"",b,d,k,h,D,f,_,l,S,$,w,g,C,v,E,r,R;return l=new pe({props:{js:`
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${o[1]}');
|
const pb = new PocketBase('${o[1]}');
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as $t,i as Mt,s as St,V as Ot,X as se,W as Tt,h as d,d as ge,t as _e,a as he,I as ee,Z as Je,_ as bt,C as qt,$ as Rt,D as Ht,l as o,n as a,m as we,u as s,A as _,v as f,c as Ce,w as k,J as ye,p as Pt,k as Te,o as Lt,H as te}from"./index-CaLRFnGa.js";import{F as Dt}from"./FieldsQueryParam-CjR_BU8D.js";function mt(r,e,t){const n=r.slice();return n[10]=e[t],n}function _t(r,e,t){const n=r.slice();return n[10]=e[t],n}function ht(r,e,t){const n=r.slice();return n[15]=e[t],n}function yt(r){let e;return{c(){e=s("p"),e.innerHTML=`<em>Note that in case of a password change all previously issued tokens for the current record
|
import{S as $t,i as Mt,s as St,V as Ot,X as se,W as Tt,h as d,d as ge,t as _e,a as he,I as ee,Z as Je,_ as bt,C as qt,$ as Rt,D as Ht,l as o,n as a,m as we,u as s,A as _,v as f,c as Ce,w as k,J as ye,p as Pt,k as Te,o as Lt,H as te}from"./index-D5lV2xwk.js";import{F as Dt}from"./FieldsQueryParam-CbVvvpRu.js";function mt(r,e,t){const n=r.slice();return n[10]=e[t],n}function _t(r,e,t){const n=r.slice();return n[10]=e[t],n}function ht(r,e,t){const n=r.slice();return n[15]=e[t],n}function yt(r){let e;return{c(){e=s("p"),e.innerHTML=`<em>Note that in case of a password change all previously issued tokens for the current record
|
||||||
will be automatically invalidated and if you want your user to remain signed in you need to
|
will be automatically invalidated and if you want your user to remain signed in you need to
|
||||||
reauthenticate manually after the update call.</em>`},m(t,n){o(t,e,n)},d(t){t&&d(e)}}}function kt(r){let e;return{c(){e=s("p"),e.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",k(e,"class","txt-hint txt-sm txt-right")},m(t,n){o(t,e,n)},d(t){t&&d(e)}}}function vt(r){let e,t,n,b,p,c,u,m,S,T,H,P,$,M,q,L,J,j,O,R,D,v,g,w;function x(h,C){var le,W,ne;return C&1&&(m=null),m==null&&(m=!!((ne=(W=(le=h[0])==null?void 0:le.fields)==null?void 0:W.find(zt))!=null&&ne.required)),m?Bt:Ft}let Q=x(r,-1),B=Q(r);return{c(){e=s("tr"),e.innerHTML='<td colspan="3" class="txt-hint txt-bold">Auth specific fields</td>',t=f(),n=s("tr"),n.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span> <span>email</span></div></td> <td><span class="label">String</span></td> <td>The auth record email address.
|
reauthenticate manually after the update call.</em>`},m(t,n){o(t,e,n)},d(t){t&&d(e)}}}function kt(r){let e;return{c(){e=s("p"),e.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",k(e,"class","txt-hint txt-sm txt-right")},m(t,n){o(t,e,n)},d(t){t&&d(e)}}}function vt(r){let e,t,n,b,p,c,u,m,S,T,H,P,$,M,q,L,J,j,O,R,D,v,g,w;function x(h,C){var le,W,ne;return C&1&&(m=null),m==null&&(m=!!((ne=(W=(le=h[0])==null?void 0:le.fields)==null?void 0:W.find(zt))!=null&&ne.required)),m?Bt:Ft}let Q=x(r,-1),B=Q(r);return{c(){e=s("tr"),e.innerHTML='<td colspan="3" class="txt-hint txt-bold">Auth specific fields</td>',t=f(),n=s("tr"),n.innerHTML=`<td><div class="inline-flex"><span class="label label-warning">Optional</span> <span>email</span></div></td> <td><span class="label">String</span></td> <td>The auth record email address.
|
||||||
<br/>
|
<br/>
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as le,i as ne,s as ie,X as F,h as b,t as j,a as U,I as Y,Z as x,_ as Te,C as ee,$ as Ce,D as te,l as h,n as u,u as m,v as y,A as M,w as v,k as K,o as oe,W as qe,d as z,m as G,c as Q,V as Ve,Y as fe,J as Ae,p as Ie,a0 as ue}from"./index-CaLRFnGa.js";function de(s,t,e){const o=s.slice();return o[4]=t[e],o}function me(s,t,e){const o=s.slice();return o[4]=t[e],o}function pe(s,t){let e,o=t[4].code+"",f,c,r,a;function d(){return t[3](t[4])}return{key:s,first:null,c(){e=m("button"),f=M(o),c=y(),v(e,"class","tab-item"),K(e,"active",t[1]===t[4].code),this.first=e},m(g,C){h(g,e,C),u(e,f),u(e,c),r||(a=oe(e,"click",d),r=!0)},p(g,C){t=g,C&4&&o!==(o=t[4].code+"")&&Y(f,o),C&6&&K(e,"active",t[1]===t[4].code)},d(g){g&&b(e),r=!1,a()}}}function _e(s,t){let e,o,f,c;return o=new qe({props:{content:t[4].body}}),{key:s,first:null,c(){e=m("div"),Q(o.$$.fragment),f=y(),v(e,"class","tab-item"),K(e,"active",t[1]===t[4].code),this.first=e},m(r,a){h(r,e,a),G(o,e,null),u(e,f),c=!0},p(r,a){t=r;const d={};a&4&&(d.content=t[4].body),o.$set(d),(!c||a&6)&&K(e,"active",t[1]===t[4].code)},i(r){c||(U(o.$$.fragment,r),c=!0)},o(r){j(o.$$.fragment,r),c=!1},d(r){r&&b(e),z(o)}}}function Pe(s){let t,e,o,f,c,r,a,d=s[0].name+"",g,C,D,P,L,R,B,O,N,q,V,$=[],J=new Map,H,I,p=[],T=new Map,A,_=F(s[2]);const X=l=>l[4].code;for(let l=0;l<_.length;l+=1){let i=me(s,_,l),n=X(i);J.set(n,$[l]=pe(n,i))}let E=F(s[2]);const W=l=>l[4].code;for(let l=0;l<E.length;l+=1){let i=de(s,E,l),n=W(i);T.set(n,p[l]=_e(n,i))}return{c(){t=m("div"),e=m("strong"),e.textContent="POST",o=y(),f=m("div"),c=m("p"),r=M("/api/collections/"),a=m("strong"),g=M(d),C=M("/confirm-verification"),D=y(),P=m("div"),P.textContent="Body Parameters",L=y(),R=m("table"),R.innerHTML='<thead><tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr></thead> <tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>token</span></div></td> <td><span class="label">String</span></td> <td>The token from the verification request email.</td></tr></tbody>',B=y(),O=m("div"),O.textContent="Responses",N=y(),q=m("div"),V=m("div");for(let l=0;l<$.length;l+=1)$[l].c();H=y(),I=m("div");for(let l=0;l<p.length;l+=1)p[l].c();v(e,"class","label label-primary"),v(f,"class","content"),v(t,"class","alert alert-success"),v(P,"class","section-title"),v(R,"class","table-compact table-border m-b-base"),v(O,"class","section-title"),v(V,"class","tabs-header compact combined left"),v(I,"class","tabs-content"),v(q,"class","tabs")},m(l,i){h(l,t,i),u(t,e),u(t,o),u(t,f),u(f,c),u(c,r),u(c,a),u(a,g),u(c,C),h(l,D,i),h(l,P,i),h(l,L,i),h(l,R,i),h(l,B,i),h(l,O,i),h(l,N,i),h(l,q,i),u(q,V);for(let n=0;n<$.length;n+=1)$[n]&&$[n].m(V,null);u(q,H),u(q,I);for(let n=0;n<p.length;n+=1)p[n]&&p[n].m(I,null);A=!0},p(l,[i]){(!A||i&1)&&d!==(d=l[0].name+"")&&Y(g,d),i&6&&(_=F(l[2]),$=x($,i,X,1,l,_,J,V,Te,pe,null,me)),i&6&&(E=F(l[2]),ee(),p=x(p,i,W,1,l,E,T,I,Ce,_e,null,de),te())},i(l){if(!A){for(let i=0;i<E.length;i+=1)U(p[i]);A=!0}},o(l){for(let i=0;i<p.length;i+=1)j(p[i]);A=!1},d(l){l&&(b(t),b(D),b(P),b(L),b(R),b(B),b(O),b(N),b(q));for(let i=0;i<$.length;i+=1)$[i].d();for(let i=0;i<p.length;i+=1)p[i].d()}}}function Re(s,t,e){let{collection:o}=t,f=204,c=[];const r=a=>e(1,f=a.code);return s.$$set=a=>{"collection"in a&&e(0,o=a.collection)},e(2,c=[{code:204,body:"null"},{code:400,body:`
|
import{S as le,i as ne,s as ie,X as F,h as b,t as j,a as U,I as Y,Z as x,_ as Te,C as ee,$ as Ce,D as te,l as h,n as u,u as m,v as y,A as M,w as v,k as K,o as oe,W as qe,d as z,m as G,c as Q,V as Ve,Y as fe,J as Ae,p as Ie,a0 as ue}from"./index-D5lV2xwk.js";function de(s,t,e){const o=s.slice();return o[4]=t[e],o}function me(s,t,e){const o=s.slice();return o[4]=t[e],o}function pe(s,t){let e,o=t[4].code+"",f,c,r,a;function d(){return t[3](t[4])}return{key:s,first:null,c(){e=m("button"),f=M(o),c=y(),v(e,"class","tab-item"),K(e,"active",t[1]===t[4].code),this.first=e},m(g,C){h(g,e,C),u(e,f),u(e,c),r||(a=oe(e,"click",d),r=!0)},p(g,C){t=g,C&4&&o!==(o=t[4].code+"")&&Y(f,o),C&6&&K(e,"active",t[1]===t[4].code)},d(g){g&&b(e),r=!1,a()}}}function _e(s,t){let e,o,f,c;return o=new qe({props:{content:t[4].body}}),{key:s,first:null,c(){e=m("div"),Q(o.$$.fragment),f=y(),v(e,"class","tab-item"),K(e,"active",t[1]===t[4].code),this.first=e},m(r,a){h(r,e,a),G(o,e,null),u(e,f),c=!0},p(r,a){t=r;const d={};a&4&&(d.content=t[4].body),o.$set(d),(!c||a&6)&&K(e,"active",t[1]===t[4].code)},i(r){c||(U(o.$$.fragment,r),c=!0)},o(r){j(o.$$.fragment,r),c=!1},d(r){r&&b(e),z(o)}}}function Pe(s){let t,e,o,f,c,r,a,d=s[0].name+"",g,C,D,P,L,R,B,O,N,q,V,$=[],J=new Map,H,I,p=[],T=new Map,A,_=F(s[2]);const X=l=>l[4].code;for(let l=0;l<_.length;l+=1){let i=me(s,_,l),n=X(i);J.set(n,$[l]=pe(n,i))}let E=F(s[2]);const W=l=>l[4].code;for(let l=0;l<E.length;l+=1){let i=de(s,E,l),n=W(i);T.set(n,p[l]=_e(n,i))}return{c(){t=m("div"),e=m("strong"),e.textContent="POST",o=y(),f=m("div"),c=m("p"),r=M("/api/collections/"),a=m("strong"),g=M(d),C=M("/confirm-verification"),D=y(),P=m("div"),P.textContent="Body Parameters",L=y(),R=m("table"),R.innerHTML='<thead><tr><th>Param</th> <th>Type</th> <th width="50%">Description</th></tr></thead> <tbody><tr><td><div class="inline-flex"><span class="label label-success">Required</span> <span>token</span></div></td> <td><span class="label">String</span></td> <td>The token from the verification request email.</td></tr></tbody>',B=y(),O=m("div"),O.textContent="Responses",N=y(),q=m("div"),V=m("div");for(let l=0;l<$.length;l+=1)$[l].c();H=y(),I=m("div");for(let l=0;l<p.length;l+=1)p[l].c();v(e,"class","label label-primary"),v(f,"class","content"),v(t,"class","alert alert-success"),v(P,"class","section-title"),v(R,"class","table-compact table-border m-b-base"),v(O,"class","section-title"),v(V,"class","tabs-header compact combined left"),v(I,"class","tabs-content"),v(q,"class","tabs")},m(l,i){h(l,t,i),u(t,e),u(t,o),u(t,f),u(f,c),u(c,r),u(c,a),u(a,g),u(c,C),h(l,D,i),h(l,P,i),h(l,L,i),h(l,R,i),h(l,B,i),h(l,O,i),h(l,N,i),h(l,q,i),u(q,V);for(let n=0;n<$.length;n+=1)$[n]&&$[n].m(V,null);u(q,H),u(q,I);for(let n=0;n<p.length;n+=1)p[n]&&p[n].m(I,null);A=!0},p(l,[i]){(!A||i&1)&&d!==(d=l[0].name+"")&&Y(g,d),i&6&&(_=F(l[2]),$=x($,i,X,1,l,_,J,V,Te,pe,null,me)),i&6&&(E=F(l[2]),ee(),p=x(p,i,W,1,l,E,T,I,Ce,_e,null,de),te())},i(l){if(!A){for(let i=0;i<E.length;i+=1)U(p[i]);A=!0}},o(l){for(let i=0;i<p.length;i+=1)j(p[i]);A=!1},d(l){l&&(b(t),b(D),b(P),b(L),b(R),b(B),b(O),b(N),b(q));for(let i=0;i<$.length;i+=1)$[i].d();for(let i=0;i<p.length;i+=1)p[i].d()}}}function Re(s,t,e){let{collection:o}=t,f=204,c=[];const r=a=>e(1,f=a.code);return s.$$set=a=>{"collection"in a&&e(0,o=a.collection)},e(2,c=[{code:204,body:"null"},{code:400,body:`
|
||||||
{
|
{
|
||||||
"status": 400,
|
"status": 400,
|
||||||
"message": "An error occurred while validating the submitted data.",
|
"message": "An error occurred while validating the submitted data.",
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as lt,i as st,s as nt,V as at,W as tt,X as K,h as r,d as W,t as V,a as j,I as ve,Z as Ge,_ as ot,C as it,$ as rt,D as dt,l as d,n as l,m as X,u as a,A as _,v as b,c as Z,w as m,J as Ke,p as ct,k as Y,o as pt}from"./index-CaLRFnGa.js";import{F as ut}from"./FieldsQueryParam-CjR_BU8D.js";function We(o,s,n){const i=o.slice();return i[6]=s[n],i}function Xe(o,s,n){const i=o.slice();return i[6]=s[n],i}function Ze(o){let s;return{c(){s=a("p"),s.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",m(s,"class","txt-hint txt-sm txt-right")},m(n,i){d(n,s,i)},d(n){n&&r(s)}}}function Ye(o,s){let n,i,v;function p(){return s[5](s[6])}return{key:o,first:null,c(){n=a("button"),n.textContent=`${s[6].code} `,m(n,"class","tab-item"),Y(n,"active",s[2]===s[6].code),this.first=n},m(c,f){d(c,n,f),i||(v=pt(n,"click",p),i=!0)},p(c,f){s=c,f&20&&Y(n,"active",s[2]===s[6].code)},d(c){c&&r(n),i=!1,v()}}}function et(o,s){let n,i,v,p;return i=new tt({props:{content:s[6].body}}),{key:o,first:null,c(){n=a("div"),Z(i.$$.fragment),v=b(),m(n,"class","tab-item"),Y(n,"active",s[2]===s[6].code),this.first=n},m(c,f){d(c,n,f),X(i,n,null),l(n,v),p=!0},p(c,f){s=c,(!p||f&20)&&Y(n,"active",s[2]===s[6].code)},i(c){p||(j(i.$$.fragment,c),p=!0)},o(c){V(i.$$.fragment,c),p=!1},d(c){c&&r(n),W(i)}}}function ft(o){var Je,Ne;let s,n,i=o[0].name+"",v,p,c,f,w,C,ee,J=o[0].name+"",te,$e,le,F,se,B,ne,$,N,ye,Q,T,we,ae,z=o[0].name+"",oe,Ce,ie,Fe,re,I,de,S,ce,x,pe,R,ue,Re,M,D,fe,De,be,Oe,h,Pe,E,Te,Ee,Ae,me,Be,_e,Ie,Se,xe,he,Me,qe,A,ke,q,ge,O,H,y=[],He=new Map,Le,L,k=[],Ue=new Map,P;F=new at({props:{js:`
|
import{S as lt,i as st,s as nt,V as at,W as tt,X as K,h as r,d as W,t as V,a as j,I as ve,Z as Ge,_ as ot,C as it,$ as rt,D as dt,l as d,n as l,m as X,u as a,A as _,v as b,c as Z,w as m,J as Ke,p as ct,k as Y,o as pt}from"./index-D5lV2xwk.js";import{F as ut}from"./FieldsQueryParam-CbVvvpRu.js";function We(o,s,n){const i=o.slice();return i[6]=s[n],i}function Xe(o,s,n){const i=o.slice();return i[6]=s[n],i}function Ze(o){let s;return{c(){s=a("p"),s.innerHTML="Requires superuser <code>Authorization:TOKEN</code> header",m(s,"class","txt-hint txt-sm txt-right")},m(n,i){d(n,s,i)},d(n){n&&r(s)}}}function Ye(o,s){let n,i,v;function p(){return s[5](s[6])}return{key:o,first:null,c(){n=a("button"),n.textContent=`${s[6].code} `,m(n,"class","tab-item"),Y(n,"active",s[2]===s[6].code),this.first=n},m(c,f){d(c,n,f),i||(v=pt(n,"click",p),i=!0)},p(c,f){s=c,f&20&&Y(n,"active",s[2]===s[6].code)},d(c){c&&r(n),i=!1,v()}}}function et(o,s){let n,i,v,p;return i=new tt({props:{content:s[6].body}}),{key:o,first:null,c(){n=a("div"),Z(i.$$.fragment),v=b(),m(n,"class","tab-item"),Y(n,"active",s[2]===s[6].code),this.first=n},m(c,f){d(c,n,f),X(i,n,null),l(n,v),p=!0},p(c,f){s=c,(!p||f&20)&&Y(n,"active",s[2]===s[6].code)},i(c){p||(j(i.$$.fragment,c),p=!0)},o(c){V(i.$$.fragment,c),p=!1},d(c){c&&r(n),W(i)}}}function ft(o){var Je,Ne;let s,n,i=o[0].name+"",v,p,c,f,w,C,ee,J=o[0].name+"",te,$e,le,F,se,B,ne,$,N,ye,Q,T,we,ae,z=o[0].name+"",oe,Ce,ie,Fe,re,I,de,S,ce,x,pe,R,ue,Re,M,D,fe,De,be,Oe,h,Pe,E,Te,Ee,Ae,me,Be,_e,Ie,Se,xe,he,Me,qe,A,ke,q,ge,O,H,y=[],He=new Map,Le,L,k=[],Ue=new Map,P;F=new at({props:{js:`
|
||||||
import PocketBase from 'pocketbase';
|
import PocketBase from 'pocketbase';
|
||||||
|
|
||||||
const pb = new PocketBase('${o[3]}');
|
const pb = new PocketBase('${o[3]}');
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -37,8 +37,8 @@
|
||||||
window.Prism = window.Prism || {};
|
window.Prism = window.Prism || {};
|
||||||
window.Prism.manual = true;
|
window.Prism.manual = true;
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="./assets/index-CaLRFnGa.js"></script>
|
<script type="module" crossorigin src="./assets/index-D5lV2xwk.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="./assets/index-DPZYPEXL.css">
|
<link rel="stylesheet" crossorigin href="./assets/index-wnKjfGML.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
|
||||||
|
|
@ -46,9 +46,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/autocomplete": {
|
"node_modules/@codemirror/autocomplete": {
|
||||||
"version": "6.19.0",
|
"version": "6.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.19.1.tgz",
|
||||||
"integrity": "sha512-61Hfv3cF07XvUxNeC3E7jhG8XNi1Yom1G0lRC936oLnlF+jrbrv8rc/J98XlYzcsAoTVupfsf5fLej1aI8kyIg==",
|
"integrity": "sha512-q6NenYkEy2fn9+JyjIxMWcNjzTL/IhwqfzOut1/G3PrIFkrbl4AL7Wkse5tLrQUUyqGoAKU5+Pi5jnnXxH5HGw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -59,9 +59,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.9.0",
|
"version": "6.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.0.tgz",
|
||||||
"integrity": "sha512-454TVgjhO6cMufsyyGN70rGIfJxJEjcqjBG2x2Y03Y/+Fm99d3O/Kv1QDYWuG6hvxsgmjXmBuATikIIYvERX+w==",
|
"integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -171,9 +171,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/lint": {
|
"node_modules/@codemirror/lint": {
|
||||||
"version": "6.9.0",
|
"version": "6.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz",
|
||||||
"integrity": "sha512-wZxW+9XDytH3SKvS8cQzMyQCaaazH8XL1EMHleHe00wVzsv7NBQKVW2yzEHrRhmM7ZOhVdItPbvlRBvMp9ej7A==",
|
"integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -655,9 +655,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/common": {
|
"node_modules/@lezer/common": {
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.3.0.tgz",
|
||||||
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
|
"integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
|
@ -674,13 +674,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/highlight": {
|
"node_modules/@lezer/highlight": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
|
||||||
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/html": {
|
"node_modules/@lezer/html": {
|
||||||
|
|
@ -720,9 +720,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/lr": {
|
"node_modules/@lezer/lr": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.3.tgz",
|
||||||
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
"integrity": "sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -1047,9 +1047,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.1.tgz",
|
||||||
"integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==",
|
"integrity": "sha512-bxZtughE4VNVJlL1RdoSE545kc4JxL7op57KKoi59/gwuU5rV6jLWFXXc8jwgFoT6vtj+ZjO+Z2C5nrY0Cl6wA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -1061,9 +1061,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-android-arm64": {
|
"node_modules/@rollup/rollup-android-arm64": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.1.tgz",
|
||||||
"integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==",
|
"integrity": "sha512-44a1hreb02cAAfAKmZfXVercPFaDjqXCK+iKeVOlJ9ltvnO6QqsBHgKVPTu+MJHSLLeMEUbeG2qiDYgbFPU48g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -1075,9 +1075,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.1.tgz",
|
||||||
"integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==",
|
"integrity": "sha512-usmzIgD0rf1syoOZ2WZvy8YpXK5G1V3btm3QZddoGSa6mOgfXWkkv+642bfUUldomgrbiLQGrPryb7DXLovPWQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -1089,9 +1089,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-darwin-x64": {
|
"node_modules/@rollup/rollup-darwin-x64": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.1.tgz",
|
||||||
"integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==",
|
"integrity": "sha512-is3r/k4vig2Gt8mKtTlzzyaSQ+hd87kDxiN3uDSDwggJLUV56Umli6OoL+/YZa/KvtdrdyNfMKHzL/P4siOOmg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -1103,9 +1103,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.1.tgz",
|
||||||
"integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==",
|
"integrity": "sha512-QJ1ksgp/bDJkZB4daldVmHaEQkG4r8PUXitCOC2WRmRaSaHx5RwPoI3DHVfXKwDkB+Sk6auFI/+JHacTekPRSw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -1117,9 +1117,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.1.tgz",
|
||||||
"integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==",
|
"integrity": "sha512-J6ma5xgAzvqsnU6a0+jgGX/gvoGokqpkx6zY4cWizRrm0ffhHDpJKQgC8dtDb3+MqfZDIqs64REbfHDMzxLMqQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -1131,9 +1131,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.1.tgz",
|
||||||
"integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==",
|
"integrity": "sha512-JzWRR41o2U3/KMNKRuZNsDUAcAVUYhsPuMlx5RUldw0E4lvSIXFUwejtYz1HJXohUmqs/M6BBJAUBzKXZVddbg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -1145,9 +1145,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.1.tgz",
|
||||||
"integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==",
|
"integrity": "sha512-L8kRIrnfMrEoHLHtHn+4uYA52fiLDEDyezgxZtGUTiII/yb04Krq+vk3P2Try+Vya9LeCE9ZHU8CXD6J9EhzHQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm"
|
"arm"
|
||||||
],
|
],
|
||||||
|
|
@ -1159,9 +1159,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.1.tgz",
|
||||||
"integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==",
|
"integrity": "sha512-ysAc0MFRV+WtQ8li8hi3EoFi7us6d1UzaS/+Dp7FYZfg3NdDljGMoVyiIp6Ucz7uhlYDBZ/zt6XI0YEZbUO11Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -1173,9 +1173,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.1.tgz",
|
||||||
"integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==",
|
"integrity": "sha512-UV6l9MJpDbDZZ/fJvqNcvO1PcivGEf1AvKuTcHoLjVZVFeAMygnamCTDikCVMRnA+qJe+B3pSbgX2+lBMqgBhA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -1187,9 +1187,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.1.tgz",
|
||||||
"integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==",
|
"integrity": "sha512-UDUtelEprkA85g95Q+nj3Xf0M4hHa4DiJ+3P3h4BuGliY4NReYYqwlc0Y8ICLjN4+uIgCEvaygYlpf0hUj90Yg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"loong64"
|
"loong64"
|
||||||
],
|
],
|
||||||
|
|
@ -1201,9 +1201,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.1.tgz",
|
||||||
"integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==",
|
"integrity": "sha512-vrRn+BYhEtNOte/zbc2wAUQReJXxEx2URfTol6OEfY2zFEUK92pkFBSXRylDM7aHi+YqEPJt9/ABYzmcrS4SgQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ppc64"
|
"ppc64"
|
||||||
],
|
],
|
||||||
|
|
@ -1215,9 +1215,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.1.tgz",
|
||||||
"integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==",
|
"integrity": "sha512-gto/1CxHyi4A7YqZZNznQYrVlPSaodOBPKM+6xcDSCMVZN/Fzb4K+AIkNz/1yAYz9h3Ng+e2fY9H6bgawVq17w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
|
@ -1229,9 +1229,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.1.tgz",
|
||||||
"integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==",
|
"integrity": "sha512-KZ6Vx7jAw3aLNjFR8eYVcQVdFa/cvBzDNRFM3z7XhNNunWjA03eUrEwJYPk0G8V7Gs08IThFKcAPS4WY/ybIrQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"riscv64"
|
"riscv64"
|
||||||
],
|
],
|
||||||
|
|
@ -1243,9 +1243,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.1.tgz",
|
||||||
"integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==",
|
"integrity": "sha512-HvEixy2s/rWNgpwyKpXJcHmE7om1M89hxBTBi9Fs6zVuLU4gOrEMQNbNsN/tBVIMbLyysz/iwNiGtMOpLAOlvA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"s390x"
|
"s390x"
|
||||||
],
|
],
|
||||||
|
|
@ -1257,9 +1257,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.1.tgz",
|
||||||
"integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==",
|
"integrity": "sha512-E/n8x2MSjAQgjj9IixO4UeEUeqXLtiA7pyoXCFYLuXpBA/t2hnbIdxHfA7kK9BFsYAoNU4st1rHYdldl8dTqGA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -1271,9 +1271,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.1.tgz",
|
||||||
"integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==",
|
"integrity": "sha512-IhJ087PbLOQXCN6Ui/3FUkI9pWNZe/Z7rEIVOzMsOs1/HSAECCvSZ7PkIbkNqL/AZn6WbZvnoVZw/qwqYMo4/w==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -1285,9 +1285,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.1.tgz",
|
||||||
"integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==",
|
"integrity": "sha512-0++oPNgLJHBblreu0SFM7b3mAsBJBTY0Ksrmu9N6ZVrPiTkRgda52mWR7TKhHAsUb9noCjFvAw9l6ZO1yzaVbA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -1299,9 +1299,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.1.tgz",
|
||||||
"integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==",
|
"integrity": "sha512-VJXivz61c5uVdbmitLkDlbcTk9Or43YC2QVLRkqp86QoeFSqI81bNgjhttqhKNMKnQMWnecOCm7lZz4s+WLGpQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
|
|
@ -1313,9 +1313,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.1.tgz",
|
||||||
"integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==",
|
"integrity": "sha512-NmZPVTUOitCXUH6erJDzTQ/jotYw4CnkMDjCYRxNHVD9bNyfrGoIse684F9okwzKCV4AIHRbUkeTBc9F2OOH5Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"ia32"
|
"ia32"
|
||||||
],
|
],
|
||||||
|
|
@ -1327,9 +1327,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.1.tgz",
|
||||||
"integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==",
|
"integrity": "sha512-2SNj7COIdAf6yliSpLdLG8BEsp5lgzRehgfkP0Av8zKfQFKku6JcvbobvHASPJu4f3BFxej5g+HuQPvqPhHvpQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -1341,9 +1341,9 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.1.tgz",
|
||||||
"integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==",
|
"integrity": "sha512-rLarc1Ofcs3DHtgSzFO31pZsCh8g05R2azN1q3fF+H423Co87My0R+tazOEvYVKXSLh8C4LerMK41/K7wlklcg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|
@ -1770,9 +1770,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.19",
|
"version": "0.30.21",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||||
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
|
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -1929,9 +1929,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "4.52.4",
|
"version": "4.53.1",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.1.tgz",
|
||||||
"integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==",
|
"integrity": "sha512-n2I0V0lN3E9cxxMqBCT3opWOiQBzRN7UG60z/WDKqdX2zHUS/39lezBcsckZFsV6fUTSnfqI7kHf60jDAPGKug==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -1945,35 +1945,35 @@
|
||||||
"npm": ">=8.0.0"
|
"npm": ">=8.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@rollup/rollup-android-arm-eabi": "4.52.4",
|
"@rollup/rollup-android-arm-eabi": "4.53.1",
|
||||||
"@rollup/rollup-android-arm64": "4.52.4",
|
"@rollup/rollup-android-arm64": "4.53.1",
|
||||||
"@rollup/rollup-darwin-arm64": "4.52.4",
|
"@rollup/rollup-darwin-arm64": "4.53.1",
|
||||||
"@rollup/rollup-darwin-x64": "4.52.4",
|
"@rollup/rollup-darwin-x64": "4.53.1",
|
||||||
"@rollup/rollup-freebsd-arm64": "4.52.4",
|
"@rollup/rollup-freebsd-arm64": "4.53.1",
|
||||||
"@rollup/rollup-freebsd-x64": "4.52.4",
|
"@rollup/rollup-freebsd-x64": "4.53.1",
|
||||||
"@rollup/rollup-linux-arm-gnueabihf": "4.52.4",
|
"@rollup/rollup-linux-arm-gnueabihf": "4.53.1",
|
||||||
"@rollup/rollup-linux-arm-musleabihf": "4.52.4",
|
"@rollup/rollup-linux-arm-musleabihf": "4.53.1",
|
||||||
"@rollup/rollup-linux-arm64-gnu": "4.52.4",
|
"@rollup/rollup-linux-arm64-gnu": "4.53.1",
|
||||||
"@rollup/rollup-linux-arm64-musl": "4.52.4",
|
"@rollup/rollup-linux-arm64-musl": "4.53.1",
|
||||||
"@rollup/rollup-linux-loong64-gnu": "4.52.4",
|
"@rollup/rollup-linux-loong64-gnu": "4.53.1",
|
||||||
"@rollup/rollup-linux-ppc64-gnu": "4.52.4",
|
"@rollup/rollup-linux-ppc64-gnu": "4.53.1",
|
||||||
"@rollup/rollup-linux-riscv64-gnu": "4.52.4",
|
"@rollup/rollup-linux-riscv64-gnu": "4.53.1",
|
||||||
"@rollup/rollup-linux-riscv64-musl": "4.52.4",
|
"@rollup/rollup-linux-riscv64-musl": "4.53.1",
|
||||||
"@rollup/rollup-linux-s390x-gnu": "4.52.4",
|
"@rollup/rollup-linux-s390x-gnu": "4.53.1",
|
||||||
"@rollup/rollup-linux-x64-gnu": "4.52.4",
|
"@rollup/rollup-linux-x64-gnu": "4.53.1",
|
||||||
"@rollup/rollup-linux-x64-musl": "4.52.4",
|
"@rollup/rollup-linux-x64-musl": "4.53.1",
|
||||||
"@rollup/rollup-openharmony-arm64": "4.52.4",
|
"@rollup/rollup-openharmony-arm64": "4.53.1",
|
||||||
"@rollup/rollup-win32-arm64-msvc": "4.52.4",
|
"@rollup/rollup-win32-arm64-msvc": "4.53.1",
|
||||||
"@rollup/rollup-win32-ia32-msvc": "4.52.4",
|
"@rollup/rollup-win32-ia32-msvc": "4.53.1",
|
||||||
"@rollup/rollup-win32-x64-gnu": "4.52.4",
|
"@rollup/rollup-win32-x64-gnu": "4.53.1",
|
||||||
"@rollup/rollup-win32-x64-msvc": "4.52.4",
|
"@rollup/rollup-win32-x64-msvc": "4.53.1",
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.93.2",
|
"version": "1.93.3",
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.93.2.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.93.3.tgz",
|
||||||
"integrity": "sha512-t+YPtOQHpGW1QWsh1CHQ5cPIr9lbbGZLZnbihP/D/qZj/yuV68m8qarcV17nvkOX81BCrvzAlq2klCQFZghyTg==",
|
"integrity": "sha512-elOcIZRTM76dvxNAjqYrucTSI0teAF/L2Lv0s6f6b7FOwcwIuA357bIE871580AjHJuSvLIRUosgV+lIWx6Rgg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -2002,9 +2002,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/style-mod": {
|
"node_modules/style-mod": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
|
||||||
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
|
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
|
@ -2088,9 +2088,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.4.20",
|
"version": "5.4.21",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.20.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
|
||||||
"integrity": "sha512-j3lYzGC3P+B5Yfy/pfKNgVEg4+UtcIJcVRt2cDjIOmhLourAqPqf8P7acgxeiSgUB7E3p2P8/3gNIgDLpwzs4g==",
|
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@
|
||||||
$: authAlertTemplate = {
|
$: authAlertTemplate = {
|
||||||
key: "authAlert.emailTemplate",
|
key: "authAlert.emailTemplate",
|
||||||
label: "Default Login alert email template",
|
label: "Default Login alert email template",
|
||||||
placeholders: ["APP_NAME", "APP_URL", "RECORD:*"],
|
placeholders: ["APP_NAME", "APP_URL", "RECORD:*", "ALERT_INFO"],
|
||||||
config: collection.authAlert.emailTemplate,
|
config: collection.authAlert.emailTemplate,
|
||||||
};
|
};
|
||||||
$: emailTemplatesList = isSuperusers
|
$: emailTemplatesList = isSuperusers
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@
|
||||||
{#if field.primaryKey}
|
{#if field.primaryKey}
|
||||||
<i
|
<i
|
||||||
class="ri-information-line link-hint"
|
class="ri-information-line link-hint"
|
||||||
use:tooltip={"All record ids have unique case-insensitive (ASCII) validation applied in addition to the user defined validation pattern."}
|
use:tooltip={"All record ids have forbidden characters and unique case-insensitive (ASCII) validations in addition to the user defined regex pattern."}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</label>
|
</label>
|
||||||
|
|
|
||||||
|
|
@ -136,4 +136,7 @@
|
||||||
max-height: 100px;
|
max-height: 100px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
.inline-flex {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
const result = await ApiClient.collection(selectedCollection.id).getList(page, batchSize, {
|
const result = await ApiClient.collection(selectedCollection.id).getList(page, batchSize, {
|
||||||
filter: normalizedFilter,
|
filter: normalizedFilter,
|
||||||
sort: sort,
|
sort: sort,
|
||||||
fields: "*:excerpt(100)",
|
fields: CommonHelper.getExcerptCollectionFieldsList(selectedCollection),
|
||||||
skipTotal: 1,
|
skipTotal: 1,
|
||||||
requestKey: uniqueId + "loadImagePicker",
|
requestKey: uniqueId + "loadImagePicker",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,15 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="record-info">
|
<div class="record-info-excerpt">
|
||||||
|
<div class="info-content">
|
||||||
<RecordInfoContent {record} />
|
<RecordInfoContent {record} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="#/collections?collection={record.collectionId}&recordId={record.id}"
|
href="#/collections?collection={record.collectionId}&recordId={record.id}"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
class="inline-flex link-hint"
|
class="record-link link-hint"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
use:tooltip={{
|
use:tooltip={{
|
||||||
text:
|
text:
|
||||||
|
|
@ -39,16 +41,3 @@
|
||||||
<i class="ri-external-link-line txt-sm"></i>
|
<i class="ri-external-link-line txt-sm"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.record-info {
|
|
||||||
display: inline-flex;
|
|
||||||
vertical-align: top;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
max-width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
gap: 5px;
|
|
||||||
padding-left: 1px; // for visual alignment with the new tab icon
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
||||||
|
|
@ -50,15 +50,27 @@
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
{#each nonFileDisplayFields as field, i}
|
{#each nonFileDisplayFields as field, i}
|
||||||
{#if i > 0},{/if}
|
{#if i > 0}
|
||||||
|
<span class="delimiter">•</span>
|
||||||
|
{/if}
|
||||||
{#if field.type == "relation" && record.expand?.[field.name]}
|
{#if field.type == "relation" && record.expand?.[field.name]}
|
||||||
<RecordInfoContent bind:record={record.expand[field.name]} />
|
{@const isMultiple = Array.isArray(record.expand?.[field.name])}
|
||||||
|
{@const expanded = CommonHelper.toArray(record.expand?.[field.name])}
|
||||||
|
{#if isMultiple}<span class="expand-start">{"["}</span>{/if}
|
||||||
|
{#each expanded.slice(0, 2) as expandRecord, j}
|
||||||
|
{#if j > 0}<span class="delimiter">|</span>{/if}
|
||||||
|
<RecordInfoContent record={expandRecord} />
|
||||||
|
{/each}
|
||||||
|
{#if expanded.length > 2}
|
||||||
|
<span class="delimiter">|</span>
|
||||||
|
<small class="delimiter txt-hint">({expanded.length - 2} more)</small>
|
||||||
|
{/if}
|
||||||
|
{#if isMultiple}<span class="expand-end">{"]"}</span>{/if}
|
||||||
{:else if field.type == "geoPoint"}
|
{:else if field.type == "geoPoint"}
|
||||||
<GeoPointValue value={record[field.name]} />
|
<GeoPointValue value={record[field.name]} />
|
||||||
{:else}
|
{:else}
|
||||||
{CommonHelper.truncate(CommonHelper.displayValue(record, [field.name]), 70)}
|
<span class="txt">{CommonHelper.truncate(CommonHelper.displayValue(record, [field.name]), 70)}</span>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
{CommonHelper.truncate(CommonHelper.displayValue(record, []), 70)}
|
<span class="txt">{CommonHelper.truncate(CommonHelper.displayValue(record, []), 70)}</span>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
import { addErrorToast } from "@/stores/toasts";
|
import { addErrorToast } from "@/stores/toasts";
|
||||||
import ApiClient from "@/utils/ApiClient";
|
import ApiClient from "@/utils/ApiClient";
|
||||||
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
|
import OverlayPanel from "@/components/base/OverlayPanel.svelte";
|
||||||
import CopyIcon from "@/components/base/CopyIcon.svelte";
|
|
||||||
import FormattedDate from "@/components/base/FormattedDate.svelte";
|
|
||||||
import RecordFieldValue from "@/components/records/RecordFieldValue.svelte";
|
import RecordFieldValue from "@/components/records/RecordFieldValue.svelte";
|
||||||
|
|
||||||
export let collection;
|
export let collection;
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@
|
||||||
|
|
||||||
const listFields = editorFields
|
const listFields = editorFields
|
||||||
.map((f) => f.name + ":excerpt(200)")
|
.map((f) => f.name + ":excerpt(200)")
|
||||||
|
// @todo exclude id and single rel fields from the excerpt list
|
||||||
.concat(relFields.map((field) => "expand." + field.name + ".*:excerpt(200)"));
|
.concat(relFields.map((field) => "expand." + field.name + ".*:excerpt(200)"));
|
||||||
if (listFields.length) {
|
if (listFields.length) {
|
||||||
listFields.unshift("*");
|
listFields.unshift("*");
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
ApiClient.collection(collectionId).getFullList({
|
ApiClient.collection(collectionId).getFullList({
|
||||||
batch: batchSize,
|
batch: batchSize,
|
||||||
filter: filters.join("||"),
|
filter: filters.join("||"),
|
||||||
fields: "*:excerpt(200)",
|
fields: CommonHelper.getExcerptCollectionFieldsList(collection),
|
||||||
expand: getExpand(),
|
expand: getExpand(),
|
||||||
requestKey: null,
|
requestKey: null,
|
||||||
}),
|
}),
|
||||||
|
|
@ -162,7 +162,7 @@
|
||||||
const result = await ApiClient.collection(collectionId).getList(page, batchSize, {
|
const result = await ApiClient.collection(collectionId).getList(page, batchSize, {
|
||||||
filter: CommonHelper.normalizeSearchFilter(filter, fallbackSearchFields),
|
filter: CommonHelper.normalizeSearchFilter(filter, fallbackSearchFields),
|
||||||
sort: sort,
|
sort: sort,
|
||||||
fields: "*:excerpt(200)",
|
fields: CommonHelper.getExcerptCollectionFieldsList(collection),
|
||||||
skipTotal: 1,
|
skipTotal: 1,
|
||||||
expand: getExpand(),
|
expand: getExpand(),
|
||||||
requestKey: uniqueId + "loadList",
|
requestKey: uniqueId + "loadList",
|
||||||
|
|
@ -190,7 +190,7 @@
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const reloaded = await ApiClient.collection(collectionId).getOne(record.id, {
|
const reloaded = await ApiClient.collection(collectionId).getOne(record.id, {
|
||||||
fields: "*:excerpt(200)",
|
fields: CommonHelper.getExcerptCollectionFieldsList(collection),
|
||||||
expand: getExpand(),
|
expand: getExpand(),
|
||||||
requestKey: uniqueId + "reload" + record.id,
|
requestKey: uniqueId + "reload" + record.id,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,4 @@
|
||||||
export let value = {};
|
export let value = {};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="txt">
|
<div class="txt">{value?.lon}, {value?.lat}</div>
|
||||||
{value?.lon}
|
|
||||||
<span class="txt-disabled txt-xs">|</span>
|
|
||||||
{value.lat}
|
|
||||||
</div>
|
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,12 @@
|
||||||
|
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
|
|
||||||
|
const fieldCollection = $collections.find((c) => c.id == field.collectionId);
|
||||||
|
|
||||||
let expands = [];
|
let expands = [];
|
||||||
const presentableRelFields = $collections
|
const presentableRelFields = fieldCollection?.fields?.filter(
|
||||||
.find((c) => c.id == field.collectionId)
|
(f) => !f.hidden && f.presentable && f.type == "relation",
|
||||||
?.fields?.filter((f) => !f.hidden && f.presentable && f.type == "relation");
|
);
|
||||||
for (const field of presentableRelFields) {
|
for (const field of presentableRelFields) {
|
||||||
expands = expands.concat(CommonHelper.getExpandPresentableRelFields(field, $collections, 2));
|
expands = expands.concat(CommonHelper.getExpandPresentableRelFields(field, $collections, 2));
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +86,7 @@
|
||||||
loadPromises.push(
|
loadPromises.push(
|
||||||
ApiClient.collection(field.collectionId).getFullList(batchSize, {
|
ApiClient.collection(field.collectionId).getFullList(batchSize, {
|
||||||
filter: filters.join("||"),
|
filter: filters.join("||"),
|
||||||
fields: "*:excerpt(200)",
|
fields: CommonHelper.getExcerptCollectionFieldsList(fieldCollection),
|
||||||
expand: expands.join(","),
|
expand: expands.join(","),
|
||||||
requestKey: null,
|
requestKey: null,
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -88,13 +88,20 @@
|
||||||
the backup and will restart the application process.
|
the backup and will restart the application process.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
This means that on success all of your data (including app settings, users, superusers, etc.) will
|
This means that on success all of your data (including app settings, users, superusers, etc.)
|
||||||
be replaced with the ones from the backup.
|
will be replaced with the ones from the backup.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Nothing will happen if the backup is invalid or incompatible (ex. missing
|
Nothing will happen if the backup is invalid (ex. missing
|
||||||
<code>data.db</code> file).
|
<code>data.db</code> file).
|
||||||
</p>
|
</p>
|
||||||
|
<p>Below is an oversimplified version of the restore flow:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Replaces the current <code>pb_data</code> with the content from the backup</li>
|
||||||
|
<li>Triggers app restart</li>
|
||||||
|
<li>Applies all migrations that are missing in the restored <code>pb_data</code></li>
|
||||||
|
<li>Initializes the app server as usual</li>
|
||||||
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -959,6 +959,62 @@ a.thumb:not(.thumb-active) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.record-info-excerpt {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
gap: 5px;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 40px;
|
||||||
|
line-height: 18px;;
|
||||||
|
padding-left: 1px; // for visual alignment with the new tab icon
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
.info-content {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
row-gap: 2px;
|
||||||
|
column-gap: 5px;
|
||||||
|
width: auto;
|
||||||
|
min-width: 0;
|
||||||
|
text-align: left;
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-all;
|
||||||
|
.txt {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
.col-type-relation & {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.delimiter {
|
||||||
|
min-width: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 0.8em;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: var(--txtDisabledColor);
|
||||||
|
}
|
||||||
|
.expand-start,
|
||||||
|
.expand-end {
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--txtDisabledColor);
|
||||||
|
}
|
||||||
|
.expand-start {
|
||||||
|
margin-right: -2px;
|
||||||
|
}
|
||||||
|
.expand-end {
|
||||||
|
margin-left: -2px;
|
||||||
|
}
|
||||||
|
.record-link {
|
||||||
|
margin-left: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sidebar menu
|
// sidebar menu
|
||||||
.sidebar-menu {
|
.sidebar-menu {
|
||||||
--sidebarListItemMargin: 10px;
|
--sidebarListItemMargin: 10px;
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,9 @@ table {
|
||||||
line-height: var(--smLineHeight);
|
line-height: var(--smLineHeight);
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
.col-type-relation {
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
.col-type-text {
|
.col-type-text {
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ class AppAuthStore extends LocalAuthStore {
|
||||||
const pb = new PocketBase(import.meta.env.PB_BACKEND_URL, new AppAuthStore());
|
const pb = new PocketBase(import.meta.env.PB_BACKEND_URL, new AppAuthStore());
|
||||||
|
|
||||||
if (pb.authStore.isValid) {
|
if (pb.authStore.isValid) {
|
||||||
pb.collection(pb.authStore.record.collectionName)
|
pb.collection(pb.authStore.record.collectionName || "_superusers")
|
||||||
.authRefresh()
|
.authRefresh()
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn("Failed to refresh the existing auth token:", err);
|
console.warn("Failed to refresh the existing auth token:", err);
|
||||||
|
|
|
||||||
|
|
@ -1774,7 +1774,7 @@ export default class CommonHelper {
|
||||||
/**
|
/**
|
||||||
* Returns an array with all public collection identifiers (collection fields + type specific fields).
|
* Returns an array with all public collection identifiers (collection fields + type specific fields).
|
||||||
*
|
*
|
||||||
* @param {[type]} collection The collection to extract identifiers from.
|
* @param {Object} collection The collection to extract identifiers from.
|
||||||
* @param {String} prefix Optional prefix for each found identified.
|
* @param {String} prefix Optional prefix for each found identified.
|
||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
|
|
@ -1804,6 +1804,30 @@ export default class CommonHelper {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a wildcard "fields" string with the excerpt modifier applied to all collection fields
|
||||||
|
* (except the primary key and relation fields).
|
||||||
|
*
|
||||||
|
* @param {Object} collection
|
||||||
|
* @param {Number} [maxExcerpt]
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
static getExcerptCollectionFieldsList(collection, maxExcerpt = 200) {
|
||||||
|
let result = ["*"];
|
||||||
|
|
||||||
|
const fields = collection?.fields || [];
|
||||||
|
for (const field of fields) {
|
||||||
|
if (field.primaryKey || field.type == "relation") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(`${field.name}:excerpt(${maxExcerpt})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.join(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates recursively a list with all the autocomplete field keys
|
* Generates recursively a list with all the autocomplete field keys
|
||||||
* for the collectionNameOrId collection.
|
* for the collectionNameOrId collection.
|
||||||
|
|
@ -1923,13 +1947,14 @@ export default class CommonHelper {
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
result.push(key);
|
result.push(key);
|
||||||
|
|
||||||
// add ":isset" modifier to non-base keys
|
// add ":isset"/":changed" modifier to non-base keys
|
||||||
const parts = key.split(".");
|
const parts = key.split(".");
|
||||||
if (
|
if (
|
||||||
parts.length === 3 &&
|
parts.length === 3 &&
|
||||||
// doesn't contain another modifier
|
// doesn't contain another modifier
|
||||||
parts[2].indexOf(":") === -1
|
parts[2].indexOf(":") === -1
|
||||||
) {
|
) {
|
||||||
|
result.push(key + ":changed");
|
||||||
result.push(key + ":isset");
|
result.push(key + ":isset");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue