commit 890f3b5571528b490bad3a20825aa43fb531d119 Author: maurice Date: Sat Dec 27 22:43:37 2025 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e8414d5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +pb_data/ +pocketbase +pocketbase.exe \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a9259ed --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# Voorbeeld van een applicatie met PocketBase + +[https://pocketbase.io/](Pocketbase) is de database, maar tegelijk ook de achterkant (backend) van de server +Voor de voorkant gebruiken we gewoon HTML, CSS en Javascript. Als CSS framework is [Pico CSS](https://picocss.com/docs) gekozen. Het is raadzaam de documentatie van beide goed te lezen. + +Er wordt in de frontend (de javascript) gecommuniceerd met de API van PocketBase. +Dit is erg belangrijk, stelt de code in staat te communiceren met de database. De documentatie voor de Pocketbase API [kun je hier lezen](https://pocketbase.io/docs/api-records/). + + +Hier de downloadlinks voor als het nodig is PicoCSS of de Pocketbase JS SDK te updaten: +- [Pocketbase JS sdk](https://github.com/pocketbase/js-sdk/releases). Update de bestanden `www/js/pocketbase.es.js` en `www/js/pocketbase.es.d.ts`. +- [PicoCSS.zip](https://github.com/picocss/pico/archive/refs/heads/main.zip). In de css map, vervang het bestand pico.blue.min.css. Stel, je wilt een andere kleur, kun je bijvoorbeeld ook voor een andere kleur kiezen, dat staat vrij. + +Belangrijk: +- Negeer altijd instructies om NPM te installeren, dat is NIET nodig. + + +# Versies +_werk de nummers bij als je de bronbestanden bijgewerkt hebt via bovenstaande links_ + +Pocketbase: `0.35.0` +Pico CSS: `2.1.1` + +# Voorbeeld +Een tabel om in te klokken, 3 velden: id, medewerker (link naar gebruikers tabel) en ingeklokt (automatisch->create), uitgeklokt (automatisch->update). +Create, List/search en update rule: `medewerker.id = @request.auth.id`, `medewerker.id = @request.auth.id`. + +Voorbeelden van filters in de documentatie: https://pocketbase.io/docs/api-rules-and-filters/ \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..84f77ec --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "CommonJS", + "target": "ES6" + }, + "include": ["www/**/*", "pb_data/*.d.ts"] +} diff --git a/pb_migrations/1766859954_updated_users.js b/pb_migrations/1766859954_updated_users.js new file mode 100644 index 0000000..91eaf8c --- /dev/null +++ b/pb_migrations/1766859954_updated_users.js @@ -0,0 +1,28 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "indexes": [ + "CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `gebruikers` (`tokenKey`)", + "CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `gebruikers` (`email`) WHERE `email` != ''" + ], + "name": "gebruikers" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "indexes": [ + "CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)", + "CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''" + ], + "name": "users" + }, collection) + + return app.save(collection) +}) diff --git a/pb_migrations/1766862082_updated_gebruikers.js b/pb_migrations/1766862082_updated_gebruikers.js new file mode 100644 index 0000000..4a4a0d2 --- /dev/null +++ b/pb_migrations/1766862082_updated_gebruikers.js @@ -0,0 +1,20 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "listRule": "" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "listRule": "id = @request.auth.id" + }, collection) + + return app.save(collection) +}) diff --git a/pb_migrations/1766862129_updated_gebruikers.js b/pb_migrations/1766862129_updated_gebruikers.js new file mode 100644 index 0000000..d5a19f8 --- /dev/null +++ b/pb_migrations/1766862129_updated_gebruikers.js @@ -0,0 +1,22 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "createRule": null, + "listRule": "id = @request.auth.id" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "createRule": "", + "listRule": "" + }, collection) + + return app.save(collection) +}) diff --git a/pb_migrations/1766862167_updated_gebruikers.js b/pb_migrations/1766862167_updated_gebruikers.js new file mode 100644 index 0000000..b11114a --- /dev/null +++ b/pb_migrations/1766862167_updated_gebruikers.js @@ -0,0 +1,87 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "oauth2": { + "mappedFields": { + "avatarURL": "", + "name": "" + } + } + }, collection) + + // remove field + collection.fields.removeById("file376926767") + + // update field + collection.fields.addAt(6, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 255, + "min": 0, + "name": "naam", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("_pb_users_auth_") + + // update collection data + unmarshal({ + "oauth2": { + "mappedFields": { + "avatarURL": "avatar", + "name": "name" + } + } + }, collection) + + // add field + collection.fields.addAt(7, new Field({ + "hidden": false, + "id": "file376926767", + "maxSelect": 1, + "maxSize": 0, + "mimeTypes": [ + "image/jpeg", + "image/png", + "image/svg+xml", + "image/gif", + "image/webp" + ], + "name": "avatar", + "presentable": false, + "protected": false, + "required": false, + "system": false, + "thumbs": null, + "type": "file" + })) + + // update field + collection.fields.addAt(6, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text1579384326", + "max": 255, + "min": 0, + "name": "name", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/pb_migrations/1766865917_created_klokken.js b/pb_migrations/1766865917_created_klokken.js new file mode 100644 index 0000000..08e7f5c --- /dev/null +++ b/pb_migrations/1766865917_created_klokken.js @@ -0,0 +1,60 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "cascadeDelete": false, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation948496446", + "maxSelect": 1, + "minSelect": 0, + "name": "medewerker", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "hidden": false, + "id": "autodate2939903645", + "name": "datumtijd", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_4227797064", + "indexes": [], + "listRule": null, + "name": "klokken", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_4227797064"); + + return app.delete(collection); +}) diff --git a/pb_migrations/1766866192_updated_klokken.js b/pb_migrations/1766866192_updated_klokken.js new file mode 100644 index 0000000..20d4aae --- /dev/null +++ b/pb_migrations/1766866192_updated_klokken.js @@ -0,0 +1,61 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_4227797064") + + // update collection data + unmarshal({ + "createRule": "medewerker.id = @request.auth.id", + "updateRule": "medewerker.id = @request.auth.id" + }, collection) + + // add field + collection.fields.addAt(3, new Field({ + "hidden": false, + "id": "autodate820045582", + "name": "uitgeklokt", + "onCreate": false, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + })) + + // update field + collection.fields.addAt(2, new Field({ + "hidden": false, + "id": "autodate2939903645", + "name": "ingeklokt", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_4227797064") + + // update collection data + unmarshal({ + "createRule": null, + "updateRule": null + }, collection) + + // remove field + collection.fields.removeById("autodate820045582") + + // update field + collection.fields.addAt(2, new Field({ + "hidden": false, + "id": "autodate2939903645", + "name": "datumtijd", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + })) + + return app.save(collection) +}) diff --git a/pb_migrations/1766866668_updated_klokken.js b/pb_migrations/1766866668_updated_klokken.js new file mode 100644 index 0000000..14a199a --- /dev/null +++ b/pb_migrations/1766866668_updated_klokken.js @@ -0,0 +1,20 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_4227797064") + + // update collection data + unmarshal({ + "listRule": "medewerker.id = @request.auth.id" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_4227797064") + + // update collection data + unmarshal({ + "listRule": null + }, collection) + + return app.save(collection) +}) diff --git a/pb_migrations/1766868538_created_berichten.js b/pb_migrations/1766868538_created_berichten.js new file mode 100644 index 0000000..4a969c6 --- /dev/null +++ b/pb_migrations/1766868538_created_berichten.js @@ -0,0 +1,74 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": "afzender = @request.auth.id", + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "cascadeDelete": false, + "collectionId": "_pb_users_auth_", + "hidden": false, + "id": "relation1489550391", + "maxSelect": 1, + "minSelect": 0, + "name": "afzender", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text2895984270", + "max": 0, + "min": 0, + "name": "bericht", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "autodate1587919980", + "name": "verstuurd", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_4257786651", + "indexes": [], + "listRule": "", + "name": "berichten", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_4257786651"); + + return app.delete(collection); +}) diff --git a/pb_migrations/1766869940_updated_berichten.js b/pb_migrations/1766869940_updated_berichten.js new file mode 100644 index 0000000..b11ed56 --- /dev/null +++ b/pb_migrations/1766869940_updated_berichten.js @@ -0,0 +1,20 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_4257786651") + + // update collection data + unmarshal({ + "listRule": "@request.auth.id != ''" + }, collection) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_4257786651") + + // update collection data + unmarshal({ + "listRule": "" + }, collection) + + return app.save(collection) +}) diff --git a/pb_migrations/1766870430_created_berichten_bekijken.js b/pb_migrations/1766870430_created_berichten_bekijken.js new file mode 100644 index 0000000..bae1f8e --- /dev/null +++ b/pb_migrations/1766870430_created_berichten_bekijken.js @@ -0,0 +1,76 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3208210256", + "max": 0, + "min": 0, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "_clone_7KTY", + "max": 0, + "min": 0, + "name": "bericht", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "_clone_HF2I", + "name": "verstuurd", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "_clone_ItTJ", + "max": 255, + "min": 0, + "name": "naam", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + } + ], + "id": "pbc_147944274", + "indexes": [], + "listRule": null, + "name": "berichten_bekijken", + "system": false, + "type": "view", + "updateRule": null, + "viewQuery": "SELECT berichten.id, berichten.bericht, berichten.verstuurd, gebruikers.naam FROM berichten\nINNER JOIN gebruikers ON gebruikers.id = berichten.afzender", + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_147944274"); + + return app.delete(collection); +}) diff --git a/pb_migrations/1766870460_updated_berichten_bekijken.js b/pb_migrations/1766870460_updated_berichten_bekijken.js new file mode 100644 index 0000000..27cc718 --- /dev/null +++ b/pb_migrations/1766870460_updated_berichten_bekijken.js @@ -0,0 +1,126 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_147944274") + + // update collection data + unmarshal({ + "listRule": "" + }, collection) + + // remove field + collection.fields.removeById("_clone_7KTY") + + // remove field + collection.fields.removeById("_clone_HF2I") + + // remove field + collection.fields.removeById("_clone_ItTJ") + + // add field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "_clone_oLDn", + "max": 0, + "min": 0, + "name": "bericht", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // add field + collection.fields.addAt(2, new Field({ + "hidden": false, + "id": "_clone_bb1h", + "name": "verstuurd", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + })) + + // add field + collection.fields.addAt(3, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "_clone_gXjC", + "max": 255, + "min": 0, + "name": "naam", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_147944274") + + // update collection data + unmarshal({ + "listRule": null + }, collection) + + // add field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "_clone_7KTY", + "max": 0, + "min": 0, + "name": "bericht", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // add field + collection.fields.addAt(2, new Field({ + "hidden": false, + "id": "_clone_HF2I", + "name": "verstuurd", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + })) + + // add field + collection.fields.addAt(3, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "_clone_ItTJ", + "max": 255, + "min": 0, + "name": "naam", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + // remove field + collection.fields.removeById("_clone_oLDn") + + // remove field + collection.fields.removeById("_clone_bb1h") + + // remove field + collection.fields.removeById("_clone_gXjC") + + return app.save(collection) +}) diff --git a/www/chat.html b/www/chat.html new file mode 100644 index 0000000..6fa3d9c --- /dev/null +++ b/www/chat.html @@ -0,0 +1,46 @@ + + + + + + + + Chat demo + + + + + + + + + +
+ +
+
+ +
+
+

Bericht versturen

+
+ + +
+
+
+
+ + + \ No newline at end of file diff --git a/www/css/index.css b/www/css/index.css new file mode 100644 index 0000000..fb453d5 --- /dev/null +++ b/www/css/index.css @@ -0,0 +1,3 @@ +.verborgen { + display: none; +} \ No newline at end of file diff --git a/www/css/vendor/pico.blue.min.css b/www/css/vendor/pico.blue.min.css new file mode 100644 index 0000000..cbbe2c3 --- /dev/null +++ b/www/css/vendor/pico.blue.min.css @@ -0,0 +1,4 @@ +@charset "UTF-8";/*! + * Pico CSS ✨ v2.1.1 (https://picocss.com) + * Copyright 2019-2025 - Licensed under MIT + */:host,:root{--pico-font-family-emoji:"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--pico-font-family-sans-serif:system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif,var(--pico-font-family-emoji);--pico-font-family-monospace:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace,var(--pico-font-family-emoji);--pico-font-family:var(--pico-font-family-sans-serif);--pico-line-height:1.5;--pico-font-weight:400;--pico-font-size:100%;--pico-text-underline-offset:0.1rem;--pico-border-radius:0.25rem;--pico-border-width:0.0625rem;--pico-outline-width:0.125rem;--pico-transition:0.2s ease-in-out;--pico-spacing:1rem;--pico-typography-spacing-vertical:1rem;--pico-block-spacing-vertical:var(--pico-spacing);--pico-block-spacing-horizontal:var(--pico-spacing);--pico-grid-column-gap:var(--pico-spacing);--pico-grid-row-gap:var(--pico-spacing);--pico-form-element-spacing-vertical:0.75rem;--pico-form-element-spacing-horizontal:1rem;--pico-group-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-primary-focus);--pico-group-box-shadow-focus-with-input:0 0 0 0.0625rem var(--pico-form-element-border-color);--pico-modal-overlay-backdrop-filter:blur(0.375rem);--pico-nav-element-spacing-vertical:1rem;--pico-nav-element-spacing-horizontal:0.5rem;--pico-nav-link-spacing-vertical:0.5rem;--pico-nav-link-spacing-horizontal:0.5rem;--pico-nav-breadcrumb-divider:">";--pico-icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--pico-icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--pico-icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--pico-icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--pico-icon-loading:url("data:image/svg+xml,%3Csvg fill='none' height='24' width='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cstyle%3E g %7B animation: rotate 2s linear infinite; transform-origin: center center; %7D circle %7B stroke-dasharray: 75,100; stroke-dashoffset: -5; animation: dash 1.5s ease-in-out infinite; stroke-linecap: round; %7D @keyframes rotate %7B 0%25 %7B transform: rotate(0deg); %7D 100%25 %7B transform: rotate(360deg); %7D %7D @keyframes dash %7B 0%25 %7B stroke-dasharray: 1,100; stroke-dashoffset: 0; %7D 50%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -17.5; %7D 100%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -62; %7D %7D %3C/style%3E%3Cg%3E%3Ccircle cx='12' cy='12' r='10' fill='none' stroke='rgb(136, 145, 164)' stroke-width='4' /%3E%3C/g%3E%3C/svg%3E")}@media (min-width:576px){:host,:root{--pico-font-size:106.25%}}@media (min-width:768px){:host,:root{--pico-font-size:112.5%}}@media (min-width:1024px){:host,:root{--pico-font-size:118.75%}}@media (min-width:1280px){:host,:root{--pico-font-size:125%}}@media (min-width:1536px){:host,:root{--pico-font-size:131.25%}}a{--pico-text-decoration:underline}a.contrast,a.secondary{--pico-text-decoration:underline}small{--pico-font-size:0.875em}h1,h2,h3,h4,h5,h6{--pico-font-weight:700}h1{--pico-font-size:2rem;--pico-line-height:1.125;--pico-typography-spacing-top:3rem}h2{--pico-font-size:1.75rem;--pico-line-height:1.15;--pico-typography-spacing-top:2.625rem}h3{--pico-font-size:1.5rem;--pico-line-height:1.175;--pico-typography-spacing-top:2.25rem}h4{--pico-font-size:1.25rem;--pico-line-height:1.2;--pico-typography-spacing-top:1.874rem}h5{--pico-font-size:1.125rem;--pico-line-height:1.225;--pico-typography-spacing-top:1.6875rem}h6{--pico-font-size:1rem;--pico-line-height:1.25;--pico-typography-spacing-top:1.5rem}tfoot td,tfoot th,thead td,thead th{--pico-font-weight:600;--pico-border-width:0.1875rem}code,kbd,pre,samp{--pico-font-family:var(--pico-font-family-monospace)}kbd{--pico-font-weight:bolder}:where(select,textarea),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-outline-width:0.0625rem}[type=search]{--pico-border-radius:5rem}[type=checkbox],[type=radio]{--pico-border-width:0.125rem}[type=checkbox][role=switch]{--pico-border-width:0.1875rem}details.dropdown summary:not([role=button]){--pico-outline-width:0.0625rem}nav details.dropdown summary:focus-visible{--pico-outline-width:0.125rem}[role=search]{--pico-border-radius:5rem}[role=group]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus),[role=search]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus){--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}[role=group]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus),[role=search]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus){--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-contrast-focus)}[role=group] [role=button],[role=group] [type=button],[role=group] [type=submit],[role=group] button,[role=search] [role=button],[role=search] [type=button],[role=search] [type=submit],[role=search] button{--pico-form-element-spacing-horizontal:2rem}details summary[role=button]:not(.outline)::after{filter:brightness(0) invert(1)}[aria-busy=true]:not(input,select,textarea):is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0) invert(1)}:host(:not([data-theme=dark])),:root:not([data-theme=dark]),[data-theme=light]{color-scheme:light;--pico-background-color:#fff;--pico-color:#373c44;--pico-text-selection-color:rgba(116, 139, 248, 0.25);--pico-muted-color:#646b79;--pico-muted-border-color:rgb(231, 234, 239.5);--pico-primary:#2060df;--pico-primary-background:#2060df;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(32, 96, 223, 0.5);--pico-primary-hover:#184eb8;--pico-primary-hover-background:#1d59d0;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(116, 139, 248, 0.5);--pico-primary-inverse:#fff;--pico-secondary:#5d6b89;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(93, 107, 137, 0.5);--pico-secondary-hover:#48536b;--pico-secondary-hover-background:#48536b;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(93, 107, 137, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#181c25;--pico-contrast-background:#181c25;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(24, 28, 37, 0.5);--pico-contrast-hover:#000;--pico-contrast-hover-background:#000;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-secondary-hover);--pico-contrast-focus:rgba(93, 107, 137, 0.25);--pico-contrast-inverse:#fff;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(129, 145, 181, 0.01698),0.0335rem 0.067rem 0.402rem rgba(129, 145, 181, 0.024),0.0625rem 0.125rem 0.75rem rgba(129, 145, 181, 0.03),0.1125rem 0.225rem 1.35rem rgba(129, 145, 181, 0.036),0.2085rem 0.417rem 2.502rem rgba(129, 145, 181, 0.04302),0.5rem 1rem 6rem rgba(129, 145, 181, 0.06),0 0 0 0.0625rem rgba(129, 145, 181, 0.015);--pico-h1-color:#2d3138;--pico-h2-color:#373c44;--pico-h3-color:#424751;--pico-h4-color:#4d535e;--pico-h5-color:#5c6370;--pico-h6-color:#646b79;--pico-mark-background-color:rgb(252.5, 230.5, 191.5);--pico-mark-color:#0f1114;--pico-ins-color:rgb(28.5, 105.5, 84);--pico-del-color:rgb(136, 56.5, 53);--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:rgb(243, 244.5, 246.75);--pico-code-color:#646b79;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:rgb(251, 251.5, 252.25);--pico-form-element-selected-background-color:#dfe3eb;--pico-form-element-border-color:#cfd5e2;--pico-form-element-color:#23262c;--pico-form-element-placeholder-color:var(--pico-muted-color);--pico-form-element-active-background-color:#fff;--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:rgb(183.5, 105.5, 106.5);--pico-form-element-invalid-active-border-color:rgb(200.25, 79.25, 72.25);--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:rgb(76, 154.5, 137.5);--pico-form-element-valid-active-border-color:rgb(39, 152.75, 118.75);--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#bfc7d9;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#dfe3eb;--pico-range-active-border-color:#bfc7d9;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:var(--pico-background-color);--pico-card-border-color:var(--pico-muted-border-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:rgb(251, 251.5, 252.25);--pico-dropdown-background-color:#fff;--pico-dropdown-border-color:#eff1f4;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#eff1f4;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(232, 234, 237, 0.75);--pico-progress-background-color:#dfe3eb;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(76, 154.5, 137.5)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(200.25, 79.25, 72.25)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}:host(:not([data-theme=dark])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:root:not([data-theme=dark]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),[data-theme=light] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}@media only screen and (prefers-color-scheme:dark){:host(:not([data-theme])),:root:not([data-theme]){color-scheme:dark;--pico-background-color:rgb(19, 22.5, 30.5);--pico-color:#c2c7d0;--pico-text-selection-color:rgba(137, 153, 249, 0.1875);--pico-muted-color:#7b8495;--pico-muted-border-color:#202632;--pico-primary:#8999f9;--pico-primary-background:#2060df;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(137, 153, 249, 0.5);--pico-primary-hover:#aeb5fb;--pico-primary-hover-background:#3c71f7;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(137, 153, 249, 0.375);--pico-primary-inverse:#fff;--pico-secondary:#969eaf;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(150, 158, 175, 0.5);--pico-secondary-hover:#b3b9c5;--pico-secondary-hover-background:#5d6b89;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(144, 158, 190, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#dfe3eb;--pico-contrast-background:#eff1f4;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(223, 227, 235, 0.5);--pico-contrast-hover:#fff;--pico-contrast-hover-background:#fff;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-contrast-hover);--pico-contrast-focus:rgba(207, 213, 226, 0.25);--pico-contrast-inverse:#000;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(7, 8.5, 12, 0.01698),0.0335rem 0.067rem 0.402rem rgba(7, 8.5, 12, 0.024),0.0625rem 0.125rem 0.75rem rgba(7, 8.5, 12, 0.03),0.1125rem 0.225rem 1.35rem rgba(7, 8.5, 12, 0.036),0.2085rem 0.417rem 2.502rem rgba(7, 8.5, 12, 0.04302),0.5rem 1rem 6rem rgba(7, 8.5, 12, 0.06),0 0 0 0.0625rem rgba(7, 8.5, 12, 0.015);--pico-h1-color:#f0f1f3;--pico-h2-color:#e0e3e7;--pico-h3-color:#c2c7d0;--pico-h4-color:#b3b9c5;--pico-h5-color:#a4acba;--pico-h6-color:#8891a4;--pico-mark-background-color:#014063;--pico-mark-color:#fff;--pico-ins-color:#62af9a;--pico-del-color:rgb(205.5, 126, 123);--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:rgb(26, 30.5, 40.25);--pico-code-color:#8891a4;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:rgb(28, 33, 43.5);--pico-form-element-selected-background-color:#2a3140;--pico-form-element-border-color:#2a3140;--pico-form-element-color:#e0e3e7;--pico-form-element-placeholder-color:#8891a4;--pico-form-element-active-background-color:rgb(26, 30.5, 40.25);--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:rgb(149.5, 74, 80);--pico-form-element-invalid-active-border-color:rgb(183.25, 63.5, 59);--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:#2a7b6f;--pico-form-element-valid-active-border-color:rgb(22, 137, 105.5);--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#333c4e;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#202632;--pico-range-active-border-color:#2a3140;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:#181c25;--pico-card-border-color:var(--pico-card-background-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:rgb(26, 30.5, 40.25);--pico-dropdown-background-color:#181c25;--pico-dropdown-border-color:#202632;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#202632;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(7.5, 8.5, 10, 0.75);--pico-progress-background-color:#202632;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}:host(:not([data-theme])) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),:root:not([data-theme]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}:host(:not([data-theme])) details summary[role=button].contrast:not(.outline)::after,:root:not([data-theme]) details summary[role=button].contrast:not(.outline)::after{filter:brightness(0)}:host(:not([data-theme])) [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before,:root:not([data-theme]) [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0)}}[data-theme=dark]{color-scheme:dark;--pico-background-color:rgb(19, 22.5, 30.5);--pico-color:#c2c7d0;--pico-text-selection-color:rgba(137, 153, 249, 0.1875);--pico-muted-color:#7b8495;--pico-muted-border-color:#202632;--pico-primary:#8999f9;--pico-primary-background:#2060df;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(137, 153, 249, 0.5);--pico-primary-hover:#aeb5fb;--pico-primary-hover-background:#3c71f7;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(137, 153, 249, 0.375);--pico-primary-inverse:#fff;--pico-secondary:#969eaf;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(150, 158, 175, 0.5);--pico-secondary-hover:#b3b9c5;--pico-secondary-hover-background:#5d6b89;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(144, 158, 190, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#dfe3eb;--pico-contrast-background:#eff1f4;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(223, 227, 235, 0.5);--pico-contrast-hover:#fff;--pico-contrast-hover-background:#fff;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-contrast-hover);--pico-contrast-focus:rgba(207, 213, 226, 0.25);--pico-contrast-inverse:#000;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(7, 8.5, 12, 0.01698),0.0335rem 0.067rem 0.402rem rgba(7, 8.5, 12, 0.024),0.0625rem 0.125rem 0.75rem rgba(7, 8.5, 12, 0.03),0.1125rem 0.225rem 1.35rem rgba(7, 8.5, 12, 0.036),0.2085rem 0.417rem 2.502rem rgba(7, 8.5, 12, 0.04302),0.5rem 1rem 6rem rgba(7, 8.5, 12, 0.06),0 0 0 0.0625rem rgba(7, 8.5, 12, 0.015);--pico-h1-color:#f0f1f3;--pico-h2-color:#e0e3e7;--pico-h3-color:#c2c7d0;--pico-h4-color:#b3b9c5;--pico-h5-color:#a4acba;--pico-h6-color:#8891a4;--pico-mark-background-color:#014063;--pico-mark-color:#fff;--pico-ins-color:#62af9a;--pico-del-color:rgb(205.5, 126, 123);--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:rgb(26, 30.5, 40.25);--pico-code-color:#8891a4;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:rgb(28, 33, 43.5);--pico-form-element-selected-background-color:#2a3140;--pico-form-element-border-color:#2a3140;--pico-form-element-color:#e0e3e7;--pico-form-element-placeholder-color:#8891a4;--pico-form-element-active-background-color:rgb(26, 30.5, 40.25);--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:rgb(149.5, 74, 80);--pico-form-element-invalid-active-border-color:rgb(183.25, 63.5, 59);--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:#2a7b6f;--pico-form-element-valid-active-border-color:rgb(22, 137, 105.5);--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#333c4e;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#202632;--pico-range-active-border-color:#2a3140;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:#181c25;--pico-card-border-color:var(--pico-card-background-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:rgb(26, 30.5, 40.25);--pico-dropdown-background-color:#181c25;--pico-dropdown-border-color:#202632;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#202632;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(7.5, 8.5, 10, 0.75);--pico-progress-background-color:#202632;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(149.5, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E")}[data-theme=dark] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}[data-theme=dark] details summary[role=button].contrast:not(.outline)::after{filter:brightness(0)}[data-theme=dark] [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0)}[type=checkbox],[type=radio],[type=range],progress{accent-color:var(--pico-primary)}*,::after,::before{box-sizing:border-box;background-repeat:no-repeat}::after,::before{text-decoration:inherit;vertical-align:inherit}:where(:host),:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--pico-background-color);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:var(--pico-font-size);line-height:var(--pico-line-height);font-family:var(--pico-font-family);text-underline-offset:var(--pico-text-underline-offset);text-rendering:optimizeLegibility;overflow-wrap:break-word;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{width:100%;margin:0}main{display:block}body>footer,body>header,body>main{padding-block:var(--pico-block-spacing-vertical)}section{margin-bottom:var(--pico-block-spacing-vertical)}.container,.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:var(--pico-spacing);padding-left:var(--pico-spacing)}@media (min-width:576px){.container{max-width:510px;padding-right:0;padding-left:0}}@media (min-width:768px){.container{max-width:700px}}@media (min-width:1024px){.container{max-width:950px}}@media (min-width:1280px){.container{max-width:1200px}}@media (min-width:1536px){.container{max-width:1450px}}.grid{grid-column-gap:var(--pico-grid-column-gap);grid-row-gap:var(--pico-grid-row-gap);display:grid;grid-template-columns:1fr}@media (min-width:768px){.grid{grid-template-columns:repeat(auto-fit,minmax(0%,1fr))}}.grid>*{min-width:0}.overflow-auto{overflow:auto}b,strong{font-weight:bolder}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}address,blockquote,dl,ol,p,pre,table,ul{margin-top:0;margin-bottom:var(--pico-typography-spacing-vertical);color:var(--pico-color);font-style:normal;font-weight:var(--pico-font-weight)}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:var(--pico-typography-spacing-vertical);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:var(--pico-font-size);line-height:var(--pico-line-height);font-family:var(--pico-font-family)}h1{--pico-color:var(--pico-h1-color)}h2{--pico-color:var(--pico-h2-color)}h3{--pico-color:var(--pico-h3-color)}h4{--pico-color:var(--pico-h4-color)}h5{--pico-color:var(--pico-h5-color)}h6{--pico-color:var(--pico-h6-color)}:where(article,address,blockquote,dl,figure,form,ol,p,pre,table,ul)~:is(h1,h2,h3,h4,h5,h6){margin-top:var(--pico-typography-spacing-top)}p{margin-bottom:var(--pico-typography-spacing-vertical)}hgroup{margin-bottom:var(--pico-typography-spacing-vertical)}hgroup>*{margin-top:0;margin-bottom:0}hgroup>:not(:first-child):last-child{--pico-color:var(--pico-muted-color);--pico-font-weight:unset;font-size:1rem}:where(ol,ul) li{margin-bottom:calc(var(--pico-typography-spacing-vertical) * .25)}:where(dl,ol,ul) :where(dl,ol,ul){margin:0;margin-top:calc(var(--pico-typography-spacing-vertical) * .25)}ul li{list-style:square}mark{padding:.125rem .25rem;background-color:var(--pico-mark-background-color);color:var(--pico-mark-color);vertical-align:baseline}blockquote{display:block;margin:var(--pico-typography-spacing-vertical) 0;padding:var(--pico-spacing);border-right:none;border-left:.25rem solid var(--pico-blockquote-border-color);border-inline-start:0.25rem solid var(--pico-blockquote-border-color);border-inline-end:none}blockquote footer{margin-top:calc(var(--pico-typography-spacing-vertical) * .5);color:var(--pico-blockquote-footer-color)}abbr[title]{border-bottom:1px dotted;text-decoration:none;cursor:help}ins{color:var(--pico-ins-color);text-decoration:none}del{color:var(--pico-del-color)}::-moz-selection{background-color:var(--pico-text-selection-color)}::selection{background-color:var(--pico-text-selection-color)}:where(a:not([role=button])),[role=link]{--pico-color:var(--pico-primary);--pico-background-color:transparent;--pico-underline:var(--pico-primary-underline);outline:0;background-color:var(--pico-background-color);color:var(--pico-color);-webkit-text-decoration:var(--pico-text-decoration);text-decoration:var(--pico-text-decoration);text-decoration-color:var(--pico-underline);text-underline-offset:0.125em;transition:background-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition),-webkit-text-decoration var(--pico-transition);transition:background-color var(--pico-transition),color var(--pico-transition),text-decoration var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),color var(--pico-transition),text-decoration var(--pico-transition),box-shadow var(--pico-transition),-webkit-text-decoration var(--pico-transition)}:where(a:not([role=button])):is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-primary-hover);--pico-underline:var(--pico-primary-hover-underline);--pico-text-decoration:underline}:where(a:not([role=button])):focus-visible,[role=link]:focus-visible{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}:where(a:not([role=button])).secondary,[role=link].secondary{--pico-color:var(--pico-secondary);--pico-underline:var(--pico-secondary-underline)}:where(a:not([role=button])).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link].secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-secondary-hover);--pico-underline:var(--pico-secondary-hover-underline)}:where(a:not([role=button])).contrast,[role=link].contrast{--pico-color:var(--pico-contrast);--pico-underline:var(--pico-contrast-underline)}:where(a:not([role=button])).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link].contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-contrast-hover);--pico-underline:var(--pico-contrast-hover-underline)}a[role=button]{display:inline-block}button{margin:0;overflow:visible;font-family:inherit;text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[role=button],[type=button],[type=file]::file-selector-button,[type=reset],[type=submit],button{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);--pico-color:var(--pico-primary-inverse);--pico-box-shadow:var(--pico-button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);border:var(--pico-border-width) solid var(--pico-border-color);border-radius:var(--pico-border-radius);outline:0;background-color:var(--pico-background-color);box-shadow:var(--pico-box-shadow);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:1rem;line-height:var(--pico-line-height);text-align:center;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}[role=button]:is(:hover,:active,:focus),[role=button]:is([aria-current]:not([aria-current=false])),[type=button]:is(:hover,:active,:focus),[type=button]:is([aria-current]:not([aria-current=false])),[type=file]::file-selector-button:is(:hover,:active,:focus),[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])),[type=reset]:is(:hover,:active,:focus),[type=reset]:is([aria-current]:not([aria-current=false])),[type=submit]:is(:hover,:active,:focus),[type=submit]:is([aria-current]:not([aria-current=false])),button:is(:hover,:active,:focus),button:is([aria-current]:not([aria-current=false])){--pico-background-color:var(--pico-primary-hover-background);--pico-border-color:var(--pico-primary-hover-border);--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));--pico-color:var(--pico-primary-inverse)}[role=button]:focus,[role=button]:is([aria-current]:not([aria-current=false])):focus,[type=button]:focus,[type=button]:is([aria-current]:not([aria-current=false])):focus,[type=file]::file-selector-button:focus,[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])):focus,[type=reset]:focus,[type=reset]:is([aria-current]:not([aria-current=false])):focus,[type=submit]:focus,[type=submit]:is([aria-current]:not([aria-current=false])):focus,button:focus,button:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}[type=button],[type=reset],[type=submit]{margin-bottom:var(--pico-spacing)}:is(button,[type=submit],[type=button],[role=button]).secondary,[type=file]::file-selector-button,[type=reset]{--pico-background-color:var(--pico-secondary-background);--pico-border-color:var(--pico-secondary-border);--pico-color:var(--pico-secondary-inverse);cursor:pointer}:is(button,[type=submit],[type=button],[role=button]).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=file]::file-selector-button:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:var(--pico-secondary-hover-background);--pico-border-color:var(--pico-secondary-hover-border);--pico-color:var(--pico-secondary-inverse)}:is(button,[type=submit],[type=button],[role=button]).secondary:focus,:is(button,[type=submit],[type=button],[role=button]).secondary:is([aria-current]:not([aria-current=false])):focus,[type=file]::file-selector-button:focus,[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])):focus,[type=reset]:focus,[type=reset]:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}:is(button,[type=submit],[type=button],[role=button]).contrast{--pico-background-color:var(--pico-contrast-background);--pico-border-color:var(--pico-contrast-border);--pico-color:var(--pico-contrast-inverse)}:is(button,[type=submit],[type=button],[role=button]).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:var(--pico-contrast-hover-background);--pico-border-color:var(--pico-contrast-hover-border);--pico-color:var(--pico-contrast-inverse)}:is(button,[type=submit],[type=button],[role=button]).contrast:focus,:is(button,[type=submit],[type=button],[role=button]).contrast:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-contrast-focus)}:is(button,[type=submit],[type=button],[role=button]).outline,[type=reset].outline{--pico-background-color:transparent;--pico-color:var(--pico-primary);--pico-border-color:var(--pico-primary)}:is(button,[type=submit],[type=button],[role=button]).outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset].outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:transparent;--pico-color:var(--pico-primary-hover);--pico-border-color:var(--pico-primary-hover)}:is(button,[type=submit],[type=button],[role=button]).outline.secondary,[type=reset].outline{--pico-color:var(--pico-secondary);--pico-border-color:var(--pico-secondary)}:is(button,[type=submit],[type=button],[role=button]).outline.secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset].outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-secondary-hover);--pico-border-color:var(--pico-secondary-hover)}:is(button,[type=submit],[type=button],[role=button]).outline.contrast{--pico-color:var(--pico-contrast);--pico-border-color:var(--pico-contrast)}:is(button,[type=submit],[type=button],[role=button]).outline.contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-contrast-hover);--pico-border-color:var(--pico-contrast-hover)}:where(button,[type=submit],[type=reset],[type=button],[role=button])[disabled],:where(fieldset[disabled]) :is(button,[type=submit],[type=button],[type=reset],[role=button]){opacity:.5;pointer-events:none}:where(table){width:100%;border-collapse:collapse;border-spacing:0;text-indent:0}td,th{padding:calc(var(--pico-spacing)/ 2) var(--pico-spacing);border-bottom:var(--pico-border-width) solid var(--pico-table-border-color);background-color:var(--pico-background-color);color:var(--pico-color);font-weight:var(--pico-font-weight);text-align:left;text-align:start}tfoot td,tfoot th{border-top:var(--pico-border-width) solid var(--pico-table-border-color);border-bottom:0}table.striped tbody tr:nth-child(odd) td,table.striped tbody tr:nth-child(odd) th{background-color:var(--pico-table-row-stripped-background-color)}:where(audio,canvas,iframe,img,svg,video){vertical-align:middle}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}:where(iframe){border-style:none}img{max-width:100%;height:auto;border-style:none}:where(svg:not([fill])){fill:currentColor}svg:not(:host),svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-size:.875em;font-family:var(--pico-font-family)}pre code,pre samp{font-size:inherit;font-family:inherit}pre{-ms-overflow-style:scrollbar;overflow:auto}code,kbd,pre,samp{border-radius:var(--pico-border-radius);background:var(--pico-code-background-color);color:var(--pico-code-color);font-weight:var(--pico-font-weight);line-height:initial}code,kbd,samp{display:inline-block;padding:.375rem}pre{display:block;margin-bottom:var(--pico-spacing);overflow-x:auto}pre>code,pre>samp{display:block;padding:var(--pico-spacing);background:0 0;line-height:var(--pico-line-height)}kbd{background-color:var(--pico-code-kbd-background-color);color:var(--pico-code-kbd-color);vertical-align:baseline}figure{display:block;margin:0;padding:0}figure figcaption{padding:calc(var(--pico-spacing) * .5) 0;color:var(--pico-muted-color)}hr{height:0;margin:var(--pico-typography-spacing-vertical) 0;border:0;border-top:1px solid var(--pico-muted-border-color);color:inherit}[hidden],template{display:none!important}canvas{display:inline-block}input,optgroup,select,textarea{margin:0;font-size:1rem;line-height:var(--pico-line-height);font-family:inherit;letter-spacing:inherit}input{overflow:visible}select{text-transform:none}legend{max-width:100%;padding:0;color:inherit;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{padding:0}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}::-moz-focus-inner{padding:0;border-style:none}:-moz-focusring{outline:0}:-moz-ui-invalid{box-shadow:none}::-ms-expand{display:none}[type=file],[type=range]{padding:0;border-width:0}input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2)}fieldset{width:100%;margin:0;margin-bottom:var(--pico-spacing);padding:0;border:0}fieldset legend,label{display:block;margin-bottom:calc(var(--pico-spacing) * .375);color:var(--pico-color);font-weight:var(--pico-form-label-font-weight,var(--pico-font-weight))}fieldset legend{margin-bottom:calc(var(--pico-spacing) * .5)}button[type=submit],input:not([type=checkbox],[type=radio]),select,textarea{width:100%}input:not([type=checkbox],[type=radio],[type=range],[type=file]),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal)}input,select,textarea{--pico-background-color:var(--pico-form-element-background-color);--pico-border-color:var(--pico-form-element-border-color);--pico-color:var(--pico-form-element-color);--pico-box-shadow:none;border:var(--pico-border-width) solid var(--pico-border-color);border-radius:var(--pico-border-radius);outline:0;background-color:var(--pico-background-color);box-shadow:var(--pico-box-shadow);color:var(--pico-color);font-weight:var(--pico-font-weight);transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}:where(select,textarea):not([readonly]):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus){--pico-background-color:var(--pico-form-element-active-background-color)}:where(select,textarea):not([readonly]):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus){--pico-border-color:var(--pico-form-element-active-border-color)}:where(select,textarea):not([readonly]):focus,input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus{--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-focus-color)}:where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea),input:not([type=submit],[type=button],[type=reset])[disabled],label[aria-disabled=true],select[disabled],textarea[disabled]{opacity:var(--pico-form-element-disabled-opacity);pointer-events:none}label[aria-disabled=true] input[disabled]{opacity:1}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid]{padding-right:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--pico-form-element-spacing-horizontal);padding-inline-start:var(--pico-form-element-spacing-horizontal)!important;padding-inline-end:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=false]:not(select){background-image:var(--pico-icon-valid)}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=true]:not(select){background-image:var(--pico-icon-invalid)}:where(input,select,textarea)[aria-invalid=false]{--pico-border-color:var(--pico-form-element-valid-border-color)}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--pico-border-color:var(--pico-form-element-valid-active-border-color)!important}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus):not([type=checkbox],[type=radio]){--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-valid-focus-color)!important}:where(input,select,textarea)[aria-invalid=true]{--pico-border-color:var(--pico-form-element-invalid-border-color)}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--pico-border-color:var(--pico-form-element-invalid-active-border-color)!important}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus):not([type=checkbox],[type=radio]){--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-invalid-focus-color)!important}[dir=rtl] :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}input::-webkit-input-placeholder,input::placeholder,select:invalid,textarea::-webkit-input-placeholder,textarea::placeholder{color:var(--pico-form-element-placeholder-color);opacity:1}input:not([type=checkbox],[type=radio]),select,textarea{margin-bottom:var(--pico-spacing)}select::-ms-expand{border:0;background-color:transparent}select:not([multiple],[size]){padding-right:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem);padding-left:var(--pico-form-element-spacing-horizontal);padding-inline-start:var(--pico-form-element-spacing-horizontal);padding-inline-end:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem);background-image:var(--pico-icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}select[multiple] option:checked{background:var(--pico-form-element-selected-background-color);color:var(--pico-form-element-color)}[dir=rtl] select:not([multiple],[size]){background-position:center left .75rem}textarea{display:block;resize:vertical}textarea[aria-invalid]{--pico-icon-height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);background-position:top right .75rem!important;background-size:1rem var(--pico-icon-height)!important}:where(input,select,textarea,fieldset,.grid)+small{display:block;width:100%;margin-top:calc(var(--pico-spacing) * -.75);margin-bottom:var(--pico-spacing);color:var(--pico-muted-color)}:where(input,select,textarea,fieldset,.grid)[aria-invalid=false]+small{color:var(--pico-ins-color)}:where(input,select,textarea,fieldset,.grid)[aria-invalid=true]+small{color:var(--pico-del-color)}label>:where(input,select,textarea){margin-top:calc(var(--pico-spacing) * .25)}label:has([type=checkbox],[type=radio]){width:-moz-fit-content;width:fit-content;cursor:pointer}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-inline-end:.5em;border-width:var(--pico-border-width);vertical-align:middle;cursor:pointer}[type=checkbox]::-ms-check,[type=radio]::-ms-check{display:none}[type=checkbox]:checked,[type=checkbox]:checked:active,[type=checkbox]:checked:focus,[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);background-image:var(--pico-icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=checkbox]~label,[type=radio]~label{display:inline-block;margin-bottom:0;cursor:pointer}[type=checkbox]~label:not(:last-of-type),[type=radio]~label:not(:last-of-type){margin-inline-end:1em}[type=checkbox]:indeterminate{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);background-image:var(--pico-icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=radio]{border-radius:50%}[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--pico-background-color:var(--pico-primary-inverse);border-width:.35em;background-image:none}[type=checkbox][role=switch]{--pico-background-color:var(--pico-switch-background-color);--pico-color:var(--pico-switch-color);width:2.25em;height:1.25em;border:var(--pico-border-width) solid var(--pico-border-color);border-radius:1.25em;background-color:var(--pico-background-color);line-height:1.25em}[type=checkbox][role=switch]:not([aria-invalid]){--pico-border-color:var(--pico-switch-background-color)}[type=checkbox][role=switch]:before{display:block;aspect-ratio:1;height:100%;border-radius:50%;background-color:var(--pico-color);box-shadow:var(--pico-switch-thumb-box-shadow);content:"";transition:margin .1s ease-in-out}[type=checkbox][role=switch]:focus{--pico-background-color:var(--pico-switch-background-color);--pico-border-color:var(--pico-switch-background-color)}[type=checkbox][role=switch]:checked{--pico-background-color:var(--pico-switch-checked-background-color);--pico-border-color:var(--pico-switch-checked-background-color);background-image:none}[type=checkbox][role=switch]:checked::before{margin-inline-start:calc(2.25em - 1.25em)}[type=checkbox][role=switch][disabled]{--pico-background-color:var(--pico-border-color)}[type=checkbox][aria-invalid=false]:checked,[type=checkbox][aria-invalid=false]:checked:active,[type=checkbox][aria-invalid=false]:checked:focus,[type=checkbox][role=switch][aria-invalid=false]:checked,[type=checkbox][role=switch][aria-invalid=false]:checked:active,[type=checkbox][role=switch][aria-invalid=false]:checked:focus{--pico-background-color:var(--pico-form-element-valid-border-color)}[type=checkbox]:checked:active[aria-invalid=true],[type=checkbox]:checked:focus[aria-invalid=true],[type=checkbox]:checked[aria-invalid=true],[type=checkbox][role=switch]:checked:active[aria-invalid=true],[type=checkbox][role=switch]:checked:focus[aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true]{--pico-background-color:var(--pico-form-element-invalid-border-color)}[type=checkbox][aria-invalid=false]:checked,[type=checkbox][aria-invalid=false]:checked:active,[type=checkbox][aria-invalid=false]:checked:focus,[type=checkbox][role=switch][aria-invalid=false]:checked,[type=checkbox][role=switch][aria-invalid=false]:checked:active,[type=checkbox][role=switch][aria-invalid=false]:checked:focus,[type=radio][aria-invalid=false]:checked,[type=radio][aria-invalid=false]:checked:active,[type=radio][aria-invalid=false]:checked:focus{--pico-border-color:var(--pico-form-element-valid-border-color)}[type=checkbox]:checked:active[aria-invalid=true],[type=checkbox]:checked:focus[aria-invalid=true],[type=checkbox]:checked[aria-invalid=true],[type=checkbox][role=switch]:checked:active[aria-invalid=true],[type=checkbox][role=switch]:checked:focus[aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true],[type=radio]:checked:active[aria-invalid=true],[type=radio]:checked:focus[aria-invalid=true],[type=radio]:checked[aria-invalid=true]{--pico-border-color:var(--pico-form-element-invalid-border-color)}[type=color]::-webkit-color-swatch-wrapper{padding:0}[type=color]::-moz-focus-inner{padding:0}[type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--pico-border-radius) * .5)}[type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--pico-border-radius) * .5)}input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--pico-icon-position:0.75rem;--pico-icon-width:1rem;padding-right:calc(var(--pico-icon-width) + var(--pico-icon-position));background-image:var(--pico-icon-date);background-position:center right var(--pico-icon-position);background-size:var(--pico-icon-width) auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--pico-icon-time)}[type=date]::-webkit-calendar-picker-indicator,[type=datetime-local]::-webkit-calendar-picker-indicator,[type=month]::-webkit-calendar-picker-indicator,[type=time]::-webkit-calendar-picker-indicator,[type=week]::-webkit-calendar-picker-indicator{width:var(--pico-icon-width);margin-right:calc(var(--pico-icon-width) * -1);margin-left:var(--pico-icon-position);opacity:0}@-moz-document url-prefix(){[type=date],[type=datetime-local],[type=month],[type=time],[type=week]{padding-right:var(--pico-form-element-spacing-horizontal)!important;background-image:none!important}}[dir=rtl] :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}[type=file]{--pico-color:var(--pico-muted-color);margin-left:calc(var(--pico-outline-width) * -1);padding:calc(var(--pico-form-element-spacing-vertical) * .5) 0;padding-left:var(--pico-outline-width);border:0;border-radius:0;background:0 0}[type=file]::file-selector-button{margin-right:calc(var(--pico-spacing)/ 2);padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal)}[type=file]:is(:hover,:active,:focus)::file-selector-button{--pico-background-color:var(--pico-secondary-hover-background);--pico-border-color:var(--pico-secondary-hover-border)}[type=file]:focus::file-selector-button{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:0 0}[type=range]::-webkit-slider-runnable-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-webkit-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-moz-range-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-moz-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-ms-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-ms-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-webkit-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-moz-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-ms-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]:active,[type=range]:focus-within{--pico-range-border-color:var(--pico-range-active-border-color);--pico-range-thumb-color:var(--pico-range-thumb-active-color)}[type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}[type=range]:active::-moz-range-thumb{transform:scale(1.25)}[type=range]:active::-ms-thumb{transform:scale(1.25)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{padding-inline-start:calc(var(--pico-form-element-spacing-horizontal) + 1.75rem);background-image:var(--pico-icon-search);background-position:center left calc(var(--pico-form-element-spacing-horizontal) + .125rem);background-size:1rem auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{padding-inline-start:calc(var(--pico-form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--pico-icon-search),var(--pico-icon-valid)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--pico-icon-search),var(--pico-icon-invalid)}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}details{display:block;margin-bottom:var(--pico-spacing)}details summary{line-height:1rem;list-style-type:none;cursor:pointer;transition:color var(--pico-transition)}details summary:not([role]){color:var(--pico-accordion-close-summary-color)}details summary::-webkit-details-marker{display:none}details summary::marker{display:none}details summary::-moz-list-bullet{list-style-type:none}details summary::after{display:block;width:1rem;height:1rem;margin-inline-start:calc(var(--pico-spacing,1rem) * .5);float:right;transform:rotate(-90deg);background-image:var(--pico-icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:"";transition:transform var(--pico-transition)}details summary:focus{outline:0}details summary:focus:not([role]){color:var(--pico-accordion-active-summary-color)}details summary:focus-visible:not([role]){outline:var(--pico-outline-width) solid var(--pico-primary-focus);outline-offset:calc(var(--pico-spacing,1rem) * 0.5);color:var(--pico-primary)}details summary[role=button]{width:100%;text-align:left}details summary[role=button]::after{height:calc(1rem * var(--pico-line-height,1.5))}details[open]>summary{margin-bottom:var(--pico-spacing)}details[open]>summary:not([role]):not(:focus){color:var(--pico-accordion-open-summary-color)}details[open]>summary::after{transform:rotate(0)}[dir=rtl] details summary{text-align:right}[dir=rtl] details summary::after{float:left;background-position:left center}article{margin-bottom:var(--pico-block-spacing-vertical);padding:var(--pico-block-spacing-vertical) var(--pico-block-spacing-horizontal);border-radius:var(--pico-border-radius);background:var(--pico-card-background-color);box-shadow:var(--pico-card-box-shadow)}article>footer,article>header{margin-right:calc(var(--pico-block-spacing-horizontal) * -1);margin-left:calc(var(--pico-block-spacing-horizontal) * -1);padding:calc(var(--pico-block-spacing-vertical) * .66) var(--pico-block-spacing-horizontal);background-color:var(--pico-card-sectioning-background-color)}article>header{margin-top:calc(var(--pico-block-spacing-vertical) * -1);margin-bottom:var(--pico-block-spacing-vertical);border-bottom:var(--pico-border-width) solid var(--pico-card-border-color);border-top-right-radius:var(--pico-border-radius);border-top-left-radius:var(--pico-border-radius)}article>footer{margin-top:var(--pico-block-spacing-vertical);margin-bottom:calc(var(--pico-block-spacing-vertical) * -1);border-top:var(--pico-border-width) solid var(--pico-card-border-color);border-bottom-right-radius:var(--pico-border-radius);border-bottom-left-radius:var(--pico-border-radius)}details.dropdown{position:relative;border-bottom:none}details.dropdown>a::after,details.dropdown>button::after,details.dropdown>summary::after{display:block;width:1rem;height:calc(1rem * var(--pico-line-height,1.5));margin-inline-start:.25rem;float:right;transform:rotate(0) translateX(.2rem);background-image:var(--pico-icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:""}nav details.dropdown{margin-bottom:0}details.dropdown>summary:not([role]){height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);border:var(--pico-border-width) solid var(--pico-form-element-border-color);border-radius:var(--pico-border-radius);background-color:var(--pico-form-element-background-color);color:var(--pico-form-element-placeholder-color);line-height:inherit;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}details.dropdown>summary:not([role]):active,details.dropdown>summary:not([role]):focus{border-color:var(--pico-form-element-active-border-color);background-color:var(--pico-form-element-active-background-color)}details.dropdown>summary:not([role]):focus{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-focus-color)}details.dropdown>summary:not([role]):focus-visible{outline:0}details.dropdown>summary:not([role])[aria-invalid=false]{--pico-form-element-border-color:var(--pico-form-element-valid-border-color);--pico-form-element-active-border-color:var(--pico-form-element-valid-focus-color);--pico-form-element-focus-color:var(--pico-form-element-valid-focus-color)}details.dropdown>summary:not([role])[aria-invalid=true]{--pico-form-element-border-color:var(--pico-form-element-invalid-border-color);--pico-form-element-active-border-color:var(--pico-form-element-invalid-focus-color);--pico-form-element-focus-color:var(--pico-form-element-invalid-focus-color)}nav details.dropdown{display:inline;margin:calc(var(--pico-nav-element-spacing-vertical) * -1) 0}nav details.dropdown>summary::after{transform:rotate(0) translateX(0)}nav details.dropdown>summary:not([role]){height:calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 2);padding:calc(var(--pico-nav-link-spacing-vertical) - var(--pico-border-width) * 2) var(--pico-nav-link-spacing-horizontal)}nav details.dropdown>summary:not([role]):focus-visible{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}details.dropdown>summary+ul{display:flex;z-index:99;position:absolute;left:0;flex-direction:column;width:100%;min-width:-moz-fit-content;min-width:fit-content;margin:0;margin-top:var(--pico-outline-width);padding:0;border:var(--pico-border-width) solid var(--pico-dropdown-border-color);border-radius:var(--pico-border-radius);background-color:var(--pico-dropdown-background-color);box-shadow:var(--pico-dropdown-box-shadow);color:var(--pico-dropdown-color);white-space:nowrap;opacity:0;transition:opacity var(--pico-transition),transform 0s ease-in-out 1s}details.dropdown>summary+ul[dir=rtl]{right:0;left:auto}details.dropdown>summary+ul li{width:100%;margin-bottom:0;padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal);list-style:none}details.dropdown>summary+ul li:first-of-type{margin-top:calc(var(--pico-form-element-spacing-vertical) * .5)}details.dropdown>summary+ul li:last-of-type{margin-bottom:calc(var(--pico-form-element-spacing-vertical) * .5)}details.dropdown>summary+ul li a{display:block;margin:calc(var(--pico-form-element-spacing-vertical) * -.5) calc(var(--pico-form-element-spacing-horizontal) * -1);padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal);overflow:hidden;border-radius:0;color:var(--pico-dropdown-color);text-decoration:none;text-overflow:ellipsis}details.dropdown>summary+ul li a:active,details.dropdown>summary+ul li a:focus,details.dropdown>summary+ul li a:focus-visible,details.dropdown>summary+ul li a:hover,details.dropdown>summary+ul li a[aria-current]:not([aria-current=false]){background-color:var(--pico-dropdown-hover-background-color)}details.dropdown>summary+ul li label{width:100%}details.dropdown>summary+ul li:has(label):hover{background-color:var(--pico-dropdown-hover-background-color)}details.dropdown[open]>summary{margin-bottom:0}details.dropdown[open]>summary+ul{transform:scaleY(1);opacity:1;transition:opacity var(--pico-transition),transform 0s ease-in-out 0s}details.dropdown[open]>summary::before{display:block;z-index:1;position:fixed;width:100vw;height:100vh;inset:0;background:0 0;content:"";cursor:default}label>details.dropdown{margin-top:calc(var(--pico-spacing) * .25)}[role=group],[role=search]{display:inline-flex;position:relative;width:100%;margin-bottom:var(--pico-spacing);border-radius:var(--pico-border-radius);box-shadow:var(--pico-group-box-shadow,0 0 0 transparent);vertical-align:middle;transition:box-shadow var(--pico-transition)}[role=group] input:not([type=checkbox],[type=radio]),[role=group] select,[role=group]>*,[role=search] input:not([type=checkbox],[type=radio]),[role=search] select,[role=search]>*{position:relative;flex:1 1 auto;margin-bottom:0}[role=group] input:not([type=checkbox],[type=radio]):not(:first-child),[role=group] select:not(:first-child),[role=group]>:not(:first-child),[role=search] input:not([type=checkbox],[type=radio]):not(:first-child),[role=search] select:not(:first-child),[role=search]>:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}[role=group] input:not([type=checkbox],[type=radio]):not(:last-child),[role=group] select:not(:last-child),[role=group]>:not(:last-child),[role=search] input:not([type=checkbox],[type=radio]):not(:last-child),[role=search] select:not(:last-child),[role=search]>:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}[role=group] input:not([type=checkbox],[type=radio]):focus,[role=group] select:focus,[role=group]>:focus,[role=search] input:not([type=checkbox],[type=radio]):focus,[role=search] select:focus,[role=search]>:focus{z-index:2}[role=group] [role=button]:not(:first-child),[role=group] [type=button]:not(:first-child),[role=group] [type=reset]:not(:first-child),[role=group] [type=submit]:not(:first-child),[role=group] button:not(:first-child),[role=group] input:not([type=checkbox],[type=radio]):not(:first-child),[role=group] select:not(:first-child),[role=search] [role=button]:not(:first-child),[role=search] [type=button]:not(:first-child),[role=search] [type=reset]:not(:first-child),[role=search] [type=submit]:not(:first-child),[role=search] button:not(:first-child),[role=search] input:not([type=checkbox],[type=radio]):not(:first-child),[role=search] select:not(:first-child){margin-left:calc(var(--pico-border-width) * -1)}[role=group] [role=button],[role=group] [type=button],[role=group] [type=reset],[role=group] [type=submit],[role=group] button,[role=search] [role=button],[role=search] [type=button],[role=search] [type=reset],[role=search] [type=submit],[role=search] button{width:auto}@supports selector(:has(*)){[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus),[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus){--pico-group-box-shadow:var(--pico-group-box-shadow-focus-with-button)}[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select,[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select{border-color:transparent}[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus),[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus){--pico-group-box-shadow:var(--pico-group-box-shadow-focus-with-input)}[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) button,[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) button{--pico-button-box-shadow:0 0 0 var(--pico-border-width) var(--pico-primary-border);--pico-button-hover-box-shadow:0 0 0 var(--pico-border-width) var(--pico-primary-hover-border)}[role=group] [role=button]:focus,[role=group] [type=button]:focus,[role=group] [type=reset]:focus,[role=group] [type=submit]:focus,[role=group] button:focus,[role=search] [role=button]:focus,[role=search] [type=button]:focus,[role=search] [type=reset]:focus,[role=search] [type=submit]:focus,[role=search] button:focus{box-shadow:none}}[role=search]>:first-child{border-top-left-radius:5rem;border-bottom-left-radius:5rem}[role=search]>:last-child{border-top-right-radius:5rem;border-bottom-right-radius:5rem}[aria-busy=true]:not(input,select,textarea,html,form){white-space:nowrap}[aria-busy=true]:not(input,select,textarea,html,form)::before{display:inline-block;width:1em;height:1em;background-image:var(--pico-icon-loading);background-size:1em auto;background-repeat:no-repeat;content:"";vertical-align:-.125em}[aria-busy=true]:not(input,select,textarea,html,form):not(:empty)::before{margin-inline-end:calc(var(--pico-spacing) * .5)}[aria-busy=true]:not(input,select,textarea,html,form):empty{text-align:center}[role=button][aria-busy=true],[type=button][aria-busy=true],[type=reset][aria-busy=true],[type=submit][aria-busy=true],a[aria-busy=true],button[aria-busy=true]{pointer-events:none}:host,:root{--pico-scrollbar-width:0px}dialog{display:flex;z-index:999;position:fixed;top:0;right:0;bottom:0;left:0;align-items:center;justify-content:center;width:inherit;min-width:100%;height:inherit;min-height:100%;padding:0;border:0;-webkit-backdrop-filter:var(--pico-modal-overlay-backdrop-filter);backdrop-filter:var(--pico-modal-overlay-backdrop-filter);background-color:var(--pico-modal-overlay-background-color);color:var(--pico-color)}dialog>article{width:100%;max-height:calc(100vh - var(--pico-spacing) * 2);margin:var(--pico-spacing);overflow:auto}@media (min-width:576px){dialog>article{max-width:510px}}@media (min-width:768px){dialog>article{max-width:700px}}dialog>article>header>*{margin-bottom:0}dialog>article>header .close,dialog>article>header :is(a,button)[rel=prev]{margin:0;margin-left:var(--pico-spacing);padding:0;float:right}dialog>article>footer{text-align:right}dialog>article>footer [role=button],dialog>article>footer button{margin-bottom:0}dialog>article>footer [role=button]:not(:first-of-type),dialog>article>footer button:not(:first-of-type){margin-left:calc(var(--pico-spacing) * .5)}dialog>article .close,dialog>article :is(a,button)[rel=prev]{display:block;width:1rem;height:1rem;margin-top:calc(var(--pico-spacing) * -1);margin-bottom:var(--pico-spacing);margin-left:auto;border:none;background-image:var(--pico-icon-close);background-position:center;background-size:auto 1rem;background-repeat:no-repeat;background-color:transparent;opacity:.5;transition:opacity var(--pico-transition)}dialog>article .close:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),dialog>article :is(a,button)[rel=prev]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){opacity:1}dialog:not([open]),dialog[open=false]{display:none}.modal-is-open{padding-right:var(--pico-scrollbar-width,0);overflow:hidden;pointer-events:none;touch-action:none}.modal-is-open dialog{pointer-events:auto;touch-action:auto}:where(.modal-is-opening,.modal-is-closing) dialog,:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-duration:.2s;animation-timing-function:ease-in-out;animation-fill-mode:both}:where(.modal-is-opening,.modal-is-closing) dialog{animation-duration:.8s;animation-name:modal-overlay}:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-delay:.2s;animation-name:modal}.modal-is-closing dialog,.modal-is-closing dialog>article{animation-delay:0s;animation-direction:reverse}@keyframes modal-overlay{from{-webkit-backdrop-filter:none;backdrop-filter:none;background-color:transparent}}@keyframes modal{from{transform:translateY(-100%);opacity:0}}:where(nav li)::before{float:left;content:"​"}nav,nav ul{display:flex}nav{justify-content:space-between;overflow:visible}nav ol,nav ul{align-items:center;margin-bottom:0;padding:0;list-style:none}nav ol:first-of-type,nav ul:first-of-type{margin-left:calc(var(--pico-nav-element-spacing-horizontal) * -1)}nav ol:last-of-type,nav ul:last-of-type{margin-right:calc(var(--pico-nav-element-spacing-horizontal) * -1)}nav li{display:inline-block;margin:0;padding:var(--pico-nav-element-spacing-vertical) var(--pico-nav-element-spacing-horizontal)}nav li :where(a,[role=link]){display:inline-block;margin:calc(var(--pico-nav-link-spacing-vertical) * -1) calc(var(--pico-nav-link-spacing-horizontal) * -1);padding:var(--pico-nav-link-spacing-vertical) var(--pico-nav-link-spacing-horizontal);border-radius:var(--pico-border-radius)}nav li :where(a,[role=link]):not(:hover){text-decoration:none}nav li [role=button],nav li [type=button],nav li button,nav li input:not([type=checkbox],[type=radio],[type=range],[type=file]),nav li select{height:auto;margin-right:inherit;margin-bottom:0;margin-left:inherit;padding:calc(var(--pico-nav-link-spacing-vertical) - var(--pico-border-width) * 2) var(--pico-nav-link-spacing-horizontal)}nav[aria-label=breadcrumb]{align-items:center;justify-content:start}nav[aria-label=breadcrumb] ul li:not(:first-child){margin-inline-start:var(--pico-nav-link-spacing-horizontal)}nav[aria-label=breadcrumb] ul li a{margin:calc(var(--pico-nav-link-spacing-vertical) * -1) 0;margin-inline-start:calc(var(--pico-nav-link-spacing-horizontal) * -1)}nav[aria-label=breadcrumb] ul li:not(:last-child)::after{display:inline-block;position:absolute;width:calc(var(--pico-nav-link-spacing-horizontal) * 4);margin:0 calc(var(--pico-nav-link-spacing-horizontal) * -1);content:var(--pico-nav-breadcrumb-divider);color:var(--pico-muted-color);text-align:center;text-decoration:none;white-space:nowrap}nav[aria-label=breadcrumb] a[aria-current]:not([aria-current=false]){background-color:transparent;color:inherit;text-decoration:none;pointer-events:none}aside li,aside nav,aside ol,aside ul{display:block}aside li{padding:calc(var(--pico-nav-element-spacing-vertical) * .5) var(--pico-nav-element-spacing-horizontal)}aside li a{display:block}aside li [role=button]{margin:inherit}[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{content:"\\"}progress{display:inline-block;vertical-align:baseline}progress{-webkit-appearance:none;-moz-appearance:none;display:inline-block;appearance:none;width:100%;height:.5rem;margin-bottom:calc(var(--pico-spacing) * .5);overflow:hidden;border:0;border-radius:var(--pico-border-radius);background-color:var(--pico-progress-background-color);color:var(--pico-progress-color)}progress::-webkit-progress-bar{border-radius:var(--pico-border-radius);background:0 0}progress[value]::-webkit-progress-value{background-color:var(--pico-progress-color);-webkit-transition:inline-size var(--pico-transition);transition:inline-size var(--pico-transition)}progress::-moz-progress-bar{background-color:var(--pico-progress-color)}@media (prefers-reduced-motion:no-preference){progress:indeterminate{background:var(--pico-progress-background-color) linear-gradient(to right,var(--pico-progress-color) 30%,var(--pico-progress-background-color) 30%) top left/150% 150% no-repeat;animation:progress-indeterminate 1s linear infinite}progress:indeterminate[value]::-webkit-progress-value{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}}@media (prefers-reduced-motion:no-preference){[dir=rtl] progress:indeterminate{animation-direction:reverse}}@keyframes progress-indeterminate{0%{background-position:200% 0}100%{background-position:-200% 0}}[data-tooltip]{position:relative}[data-tooltip]:not(a,button,input,[role=button]){border-bottom:1px dotted;text-decoration:none;cursor:help}[data-tooltip]::after,[data-tooltip]::before,[data-tooltip][data-placement=top]::after,[data-tooltip][data-placement=top]::before{display:block;z-index:99;position:absolute;bottom:100%;left:50%;padding:.25rem .5rem;overflow:hidden;transform:translate(-50%,-.25rem);border-radius:var(--pico-border-radius);background:var(--pico-tooltip-background-color);content:attr(data-tooltip);color:var(--pico-tooltip-color);font-style:normal;font-weight:var(--pico-font-weight);font-size:.875rem;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;opacity:0;pointer-events:none}[data-tooltip]::after,[data-tooltip][data-placement=top]::after{padding:0;transform:translate(-50%,0);border-top:.3rem solid;border-right:.3rem solid transparent;border-left:.3rem solid transparent;border-radius:0;background-color:transparent;content:"";color:var(--pico-tooltip-background-color)}[data-tooltip][data-placement=bottom]::after,[data-tooltip][data-placement=bottom]::before{top:100%;bottom:auto;transform:translate(-50%,.25rem)}[data-tooltip][data-placement=bottom]:after{transform:translate(-50%,-.3rem);border:.3rem solid transparent;border-bottom:.3rem solid}[data-tooltip][data-placement=left]::after,[data-tooltip][data-placement=left]::before{top:50%;right:100%;bottom:auto;left:auto;transform:translate(-.25rem,-50%)}[data-tooltip][data-placement=left]:after{transform:translate(.3rem,-50%);border:.3rem solid transparent;border-left:.3rem solid}[data-tooltip][data-placement=right]::after,[data-tooltip][data-placement=right]::before{top:50%;right:auto;bottom:auto;left:100%;transform:translate(.25rem,-50%)}[data-tooltip][data-placement=right]:after{transform:translate(-.3rem,-50%);border:.3rem solid transparent;border-right:.3rem solid}[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{opacity:1}@media (hover:hover) and (pointer:fine){[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{--pico-tooltip-slide-to:translate(-50%, -0.25rem);transform:translate(-50%,.75rem);animation-duration:.2s;animation-fill-mode:forwards;animation-name:tooltip-slide;opacity:0}[data-tooltip]:focus::after,[data-tooltip]:hover::after{--pico-tooltip-caret-slide-to:translate(-50%, 0rem);transform:translate(-50%,-.25rem);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover::after,[data-tooltip][data-placement=bottom]:hover::before{--pico-tooltip-slide-to:translate(-50%, 0.25rem);transform:translate(-50%,-.75rem);animation-name:tooltip-slide}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover::after{--pico-tooltip-caret-slide-to:translate(-50%, -0.3rem);transform:translate(-50%,-.5rem);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:focus::before,[data-tooltip][data-placement=left]:hover::after,[data-tooltip][data-placement=left]:hover::before{--pico-tooltip-slide-to:translate(-0.25rem, -50%);transform:translate(.75rem,-50%);animation-name:tooltip-slide}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:hover::after{--pico-tooltip-caret-slide-to:translate(0.3rem, -50%);transform:translate(.05rem,-50%);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:focus::before,[data-tooltip][data-placement=right]:hover::after,[data-tooltip][data-placement=right]:hover::before{--pico-tooltip-slide-to:translate(0.25rem, -50%);transform:translate(-.75rem,-50%);animation-name:tooltip-slide}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:hover::after{--pico-tooltip-caret-slide-to:translate(-0.3rem, -50%);transform:translate(-.05rem,-50%);animation-name:tooltip-caret-slide}}@keyframes tooltip-slide{to{transform:var(--pico-tooltip-slide-to);opacity:1}}@keyframes tooltip-caret-slide{50%{opacity:0}to{transform:var(--pico-tooltip-caret-slide-to);opacity:1}}[aria-controls]{cursor:pointer}[aria-disabled=true],[disabled]{cursor:not-allowed}[aria-hidden=false][hidden]{display:initial}[aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}[tabindex],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation}[dir=rtl]{direction:rtl}@media (prefers-reduced-motion:reduce){:not([aria-busy=true]),:not([aria-busy=true])::after,:not([aria-busy=true])::before{background-attachment:initial!important;animation-duration:1ms!important;animation-delay:-1ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-delay:0s!important;transition-duration:0s!important}} \ No newline at end of file diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..73bdebe --- /dev/null +++ b/www/index.html @@ -0,0 +1,41 @@ + + + + + + + + PocketDB Demo + + + + + + + + +
+ +
+

Welkom,

+ + + + + +
+
+ + + \ No newline at end of file diff --git a/www/inloggen.html b/www/inloggen.html new file mode 100644 index 0000000..9b037da --- /dev/null +++ b/www/inloggen.html @@ -0,0 +1,41 @@ + + + + + + + + Demo - Inloggen + + + + + + + + + + +
+
+

Inloggen

+
+
+ + +
+ + +
+
+
+ + + \ No newline at end of file diff --git a/www/js/chat-onveilig.js b/www/js/chat-onveilig.js new file mode 100644 index 0000000..919569f --- /dev/null +++ b/www/js/chat-onveilig.js @@ -0,0 +1,58 @@ +import { database, alleenIngelogd } from "./index.js"; + +alleenIngelogd(); + +// Berichten versturen +/** @type {HTMLFormElement} */ +const formulier = document.getElementById('verstuurform'); + +formulier.addEventListener('submit', async (event) => { + event.preventDefault(); + const gegevens = new FormData(formulier); + await verstuurBericht(gegevens.get('bericht')) + formulier.reset(); +}); + +async function verstuurBericht(bericht) { + await database.collection('berichten').create({ + afzender: database.authStore.record.id, + bericht + }); +} + +// Laad 20 nieuwste berichten in, soorteer bij verstuurd (hoog naar laag) +const berichten = await database.collection('berichten').getList(1, 20, { + sort: '-verstuurd', + expand: 'afzender' +}); + +const berichtenlijst = document.getElementById('berichten'); + +let berichtenHtml = []; + +berichten.items.forEach(bericht => { + berichtenHtml.push(`
+

${bericht.expand.afzender.naam}

+

${bericht.verstuurd}

+
${bericht.bericht}
+
`); +}); + +berichtenlijst.innerHTML = berichtenHtml.join('\n'); + +// Schrijf in op nieuwe berichten (Create) en werk dan de berichtenlijst bij +database.collection('berichten').subscribe('*', function(event) { + if(event.action !== 'create') { + return; + } + + const bericht = event.record; + berichtenlijst.innerHTML = `
+

${bericht.expand.afzender.naam}

+

${bericht.verstuurd}

+
${bericht.bericht}
+
` + '\n' + berichtenlijst.innerHTML; +}, { + expand: 'afzender' +}); + diff --git a/www/js/chat-veilig.js b/www/js/chat-veilig.js new file mode 100644 index 0000000..f14acec --- /dev/null +++ b/www/js/chat-veilig.js @@ -0,0 +1,54 @@ +import { database, alleenIngelogd } from "./index.js"; + +alleenIngelogd(); + +// Berichten versturen +/** @type {HTMLFormElement} */ +const formulier = document.getElementById('verstuurform'); + +formulier.addEventListener('submit', async (event) => { + event.preventDefault(); + const gegevens = new FormData(formulier); + await verstuurBericht(gegevens.get('bericht')) + formulier.reset(); +}); + +async function verstuurBericht(bericht) { + await database.collection('berichten').create({ + afzender: database.authStore.record.id, + bericht + }); +} + +// Laad 20 nieuwste berichten in, soorteer bij verstuurd (hoog naar laag) +const berichten = await database.collection('berichten_bekijken').getList(1, 20, { + sort: '-verstuurd' +}); + +const berichtenlijst = document.getElementById('berichten'); + +let berichtenHtml = []; + +berichten.items.forEach(bericht => { + berichtenHtml.push(`
+

${bericht.naam}

+

${bericht.verstuurd}

+
${bericht.bericht}
+
`); +}); + +berichtenlijst.innerHTML = berichtenHtml.join('\n'); + +// Schrijf in op nieuwe berichten (Create) en werk dan de berichtenlijst bij +// Helaas kan dit niet, subscriben op een view... +database.collection('berichten_bekijken').subscribe('*', function(event) { + const bericht = event.record; + berichtenlijst.innerHTML = `
+

${bericht.naam}

+

${bericht.verstuurd}

+
${bericht.bericht}
+
` + '\n' + berichtenlijst.innerHTML; +}, { + expand: 'afzender' +}); + diff --git a/www/js/home.js b/www/js/home.js new file mode 100644 index 0000000..934ce87 --- /dev/null +++ b/www/js/home.js @@ -0,0 +1,52 @@ +import { alleenIngelogd, database } from "./index.js"; + +// Controleer of iemand ingelogd is +alleenIngelogd(); + +// Toon naam van ingelogde gebruiker +document.getElementById('naam').textContent = + database.authStore.record.naam; + +// Haal eerste record is waarop gebruiker NIET uitgeklokt is (dan is iemand namelijk ingeklokt) +let ingeklokt = undefined; + +try { + const item = await database.collection('klokken').getFirstListItem('uitgeklokt = NULL'); + ingeklokt = item.id; + document.getElementById('klokknop').textContent = 'Uitklokken'; +} catch { + // Niet ingeklokt, want niet gevonden +} + +document.getElementById('klokknop').addEventListener('click', async () => { + try { + if (!ingeklokt) { + await inklokken(); + } else { + await uitklokken(); + } + } catch { + alert('In- of uitklokken mislukt'); + } +}); + +document.getElementById('uitlogknop').addEventListener('click', () => { + database.authStore.clear(); + window.location.href = 'inloggen.html'; +}); + +async function inklokken() { + const item = await database.collection('klokken') + .create({ medewerker: database.authStore.record.id }); + + document.getElementById('klokknop').textContent = 'Uitklokken'; + ingeklokt = item.id; +} + +async function uitklokken() { + await database.collection('klokken') + .update(ingeklokt); + + document.getElementById('klokknop').textContent = 'Inklokken'; + ingeklokt = undefined; +} \ No newline at end of file diff --git a/www/js/index.js b/www/js/index.js new file mode 100644 index 0000000..e86f4c0 --- /dev/null +++ b/www/js/index.js @@ -0,0 +1,18 @@ +import PocketBase from './vendor/pocketbase.es.js'; + +/** + * Database + */ +export const database = new PocketBase('http://localhost:8090'); + +window.db = database; + +/** + * Controleer of iemand ingelogd is. Zo niet, stuur iemand naar inloggen.html + */ +export function alleenIngelogd() { + // Als iemand niet ingelogd is, stuur iemand naar inloggen.js + if (!database.authStore.isValid) { + window.location.href = 'inloggen.html'; + } +} \ No newline at end of file diff --git a/www/js/inloggen.js b/www/js/inloggen.js new file mode 100644 index 0000000..5fd4197 --- /dev/null +++ b/www/js/inloggen.js @@ -0,0 +1,45 @@ +import { ClientResponseError } from './vendor/pocketbase.es.js'; +import { database } from './index.js'; + +/** @type {HTMLFormElement} */ +const inlogformulier = document.getElementById('loginform'); + +inlogformulier.addEventListener('submit', async (event) => { + event.preventDefault(); // Voorkomt dat de pagina gaat herladen + + const formdata = new FormData(inlogformulier); + + try { + const email = formdata.get('email'); + const wachtwoord = formdata.get('wachtwoord'); + + await database.collection('gebruikers').authWithPassword(email, wachtwoord); + + verbergFoutmeldingen(); + + // Inloggen gelukt, ga naar andere pagina + window.location.href = 'index.html'; + } catch (e) { + /** @type {ClientResponseError} */ + const error = e; + + if (error.status === 400) { + toonFoutmeldingen(); + } + } +}); + +function toonFoutmeldingen() { + // Toon foutmelding + document.getElementById('foutmelding').classList.remove('verborgen'); + + // Maak wachtwoord, email rood + Array.from(document.getElementsByTagName('input')) + .forEach(veld => veld.ariaInvalid = true); +} + +function verbergFoutmeldingen() { + document.getElementById('foutmelding').classList.add('verborgen'); + Array.from(document.getElementsByTagName('input')) + .forEach(veld => veld.ariaInvalid = undefined); +} \ No newline at end of file diff --git a/www/js/vendor/pocketbase.es.d.ts b/www/js/vendor/pocketbase.es.d.ts new file mode 100644 index 0000000..df8e682 --- /dev/null +++ b/www/js/vendor/pocketbase.es.d.ts @@ -0,0 +1,1583 @@ +interface ParseOptions { + decode?: (val: string) => string; +} +/** + * Parses the given cookie header string into an object + * The object has the various cookies as keys(names) => values + */ +declare function cookieParse(str: string, options?: ParseOptions): { + [key: string]: any; +}; +interface SerializeOptions { + encode?: (val: string | number | boolean) => string; + maxAge?: number; + domain?: string; + path?: string; + expires?: Date; + httpOnly?: boolean; + secure?: boolean; + priority?: string; + sameSite?: boolean | string; +} +/** + * Serialize data into a cookie header. + * + * Serialize the a name value pair into a cookie string suitable for + * http headers. An optional options object specified cookie parameters. + * + * ```js + * cookieSerialize('foo', 'bar', { httpOnly: true }) // "foo=bar; httpOnly" + * ``` + */ +declare function cookieSerialize(name: string, val: string, options?: SerializeOptions): string; +interface ListResult { + page: number; + perPage: number; + totalItems: number; + totalPages: number; + items: Array; +} +interface BaseModel { + [key: string]: any; + id: string; +} +interface LogModel extends BaseModel { + level: string; + message: string; + created: string; + updated: string; + data: { + [key: string]: any; + }; +} +interface RecordModel extends BaseModel { + collectionId: string; + collectionName: string; + expand?: { + [key: string]: any; + }; +} +// ------------------------------------------------------------------- +// Collection types +// ------------------------------------------------------------------- +interface CollectionField { + [key: string]: any; + id: string; + name: string; + type: string; + system: boolean; + hidden: boolean; + presentable: boolean; +} +interface TokenConfig { + duration: number; + secret?: string; +} +interface AuthAlertConfig { + enabled: boolean; + emailTemplate: EmailTemplate; +} +interface OTPConfig { + enabled: boolean; + duration: number; + length: number; + emailTemplate: EmailTemplate; +} +interface MFAConfig { + enabled: boolean; + duration: number; + rule: string; +} +interface PasswordAuthConfig { + enabled: boolean; + identityFields: Array; +} +interface OAuth2Provider { + pkce?: boolean; + clientId: string; + name: string; + clientSecret: string; + authURL: string; + tokenURL: string; + userInfoURL: string; + displayName: string; + extra?: { + [key: string]: any; + }; +} +interface OAuth2Config { + enabled: boolean; + mappedFields: { + [key: string]: string; + }; + providers: Array; +} +interface EmailTemplate { + subject: string; + body: string; +} +interface collection extends BaseModel { + name: string; + fields: Array; + indexes: Array; + system: boolean; + listRule?: string; + viewRule?: string; + createRule?: string; + updateRule?: string; + deleteRule?: string; +} +interface BaseCollectionModel extends collection { + type: "base"; +} +interface ViewCollectionModel extends collection { + type: "view"; + viewQuery: string; +} +interface AuthCollectionModel extends collection { + type: "auth"; + authRule?: string; + manageRule?: string; + authAlert: AuthAlertConfig; + oauth2: OAuth2Config; + passwordAuth: PasswordAuthConfig; + mfa: MFAConfig; + otp: OTPConfig; + authToken: TokenConfig; + passwordResetToken: TokenConfig; + emailChangeToken: TokenConfig; + verificationToken: TokenConfig; + fileToken: TokenConfig; + verificationTemplate: EmailTemplate; + resetPasswordTemplate: EmailTemplate; + confirmEmailChangeTemplate: EmailTemplate; +} +type CollectionModel = BaseCollectionModel | ViewCollectionModel | AuthCollectionModel; +type AuthRecord = RecordModel | null; +type AuthModel = AuthRecord; // for backward compatibility +// for backward compatibility +type OnStoreChangeFunc = (token: string, record: AuthRecord) => void; +/** + * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane). + * + * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore + * or extend it with your own custom implementation. + */ +declare class BaseAuthStore { + protected baseToken: string; + protected baseModel: AuthRecord; + private _onChangeCallbacks; + /** + * Retrieves the stored token (if any). + */ + get token(): string; + /** + * Retrieves the stored model data (if any). + */ + get record(): AuthRecord; + /** + * @deprecated use `record` instead. + */ + get model(): AuthRecord; + /** + * Loosely checks if the store has valid token (aka. existing and unexpired exp claim). + */ + get isValid(): boolean; + /** + * Loosely checks whether the currently loaded store state is for superuser. + * + * Alternatively you can also compare directly `pb.authStore.record?.collectionName`. + */ + get isSuperuser(): boolean; + /** + * @deprecated use `isSuperuser` instead or simply check the record.collectionName property. + */ + get isAdmin(): boolean; + /** + * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property. + */ + get isAuthRecord(): boolean; + /** + * Saves the provided new token and model data in the auth store. + */ + save(token: string, record?: AuthRecord): void; + /** + * Removes the stored token and model data form the auth store. + */ + clear(): void; + /** + * Parses the provided cookie string and updates the store state + * with the cookie's token and model data. + * + * NB! This function doesn't validate the token or its data. + * Usually this isn't a concern if you are interacting only with the + * PocketBase API because it has the proper server-side security checks in place, + * but if you are using the store `isValid` state for permission controls + * in a node server (eg. SSR), then it is recommended to call `authRefresh()` + * after loading the cookie to ensure an up-to-date token and model state. + * For example: + * + * ```js + * pb.authStore.loadFromCookie("cookie string..."); + * + * try { + * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any) + * pb.authStore.isValid && await pb.collection('users').authRefresh(); + * } catch (_) { + * // clear the auth store on failed refresh + * pb.authStore.clear(); + * } + * ``` + */ + loadFromCookie(cookie: string, key?: string): void; + /** + * Exports the current store state as cookie string. + * + * By default the following optional attributes are added: + * - Secure + * - HttpOnly + * - SameSite=Strict + * - Path=/ + * - Expires={the token expiration date} + * + * NB! If the generated cookie exceeds 4096 bytes, this method will + * strip the model data to the bare minimum to try to fit within the + * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1. + */ + exportToCookie(options?: SerializeOptions, key?: string): string; + /** + * Register a callback function that will be called on store change. + * + * You can set the `fireImmediately` argument to true in order to invoke + * the provided callback right after registration. + * + * Returns a removal function that you could call to "unsubscribe" from the changes. + */ + onChange(callback: OnStoreChangeFunc, fireImmediately?: boolean): () => void; + protected triggerChange(): void; +} +/** + * BaseService class that should be inherited from all API services. + */ +declare abstract class BaseService { + readonly client: Client; + constructor(client: Client); +} +interface SendOptions extends RequestInit { + // for backward compatibility and to minimize the verbosity, + // any top-level field that doesn't exist in RequestInit or the + // fields below will be treated as query parameter. + [key: string]: any; + /** + * Optional custom fetch function to use for sending the request. + */ + fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise; + /** + * Custom headers to send with the requests. + */ + headers?: { + [key: string]: string; + }; + /** + * The body of the request (serialized automatically for json requests). + */ + body?: any; + /** + * Query parameters that will be appended to the request url. + */ + query?: { + [key: string]: any; + }; + /** + * @deprecated use `query` instead + * + * for backward-compatibility `params` values are merged with `query`, + * but this option may get removed in the final v1 release + */ + params?: { + [key: string]: any; + }; + /** + * The request identifier that can be used to cancel pending requests. + */ + requestKey?: string | null; + /** + * @deprecated use `requestKey:string` instead + */ + $cancelKey?: string; + /** + * @deprecated use `requestKey:null` instead + */ + $autoCancel?: boolean; +} +interface CommonOptions extends SendOptions { + fields?: string; +} +interface ListOptions extends CommonOptions { + page?: number; + perPage?: number; + sort?: string; + filter?: string; + skipTotal?: boolean; +} +interface FullListOptions extends ListOptions { + batch?: number; +} +interface RecordOptions extends CommonOptions { + expand?: string; +} +interface RecordListOptions extends ListOptions, RecordOptions { +} +interface RecordFullListOptions extends FullListOptions, RecordOptions { +} +interface RecordSubscribeOptions extends SendOptions { + fields?: string; + filter?: string; + expand?: string; +} +interface LogStatsOptions extends CommonOptions { + filter?: string; +} +interface FileOptions extends CommonOptions { + thumb?: string; + download?: boolean; +} +interface AuthOptions extends CommonOptions { + /** + * If autoRefreshThreshold is set it will take care to auto refresh + * when necessary the auth data before each request to ensure that + * the auth state is always valid. + * + * The value must be in seconds, aka. the amount of seconds + * that will be subtracted from the current token `exp` claim in order + * to determine whether it is going to expire within the specified time threshold. + * + * For example, if you want to auto refresh the token if it is + * going to expire in the next 30mins (or already has expired), + * it can be set to `1800` + */ + autoRefreshThreshold?: number; +} +// modifies in place the provided options by moving unknown send options as query parameters. +declare function normalizeUnknownQueryParams(options?: SendOptions): void; +declare function serializeQueryParams(params: { + [key: string]: any; +}): string; +interface appleClientSecret { + secret: string; +} +declare class SettingsService extends BaseService { + /** + * Fetch all available app settings. + * + * @throws {ClientResponseError} + */ + getAll(options?: CommonOptions): Promise<{ + [key: string]: any; + }>; + /** + * Bulk updates app settings. + * + * @throws {ClientResponseError} + */ + update(bodyParams?: { + [key: string]: any; + } | FormData, options?: CommonOptions): Promise<{ + [key: string]: any; + }>; + /** + * Performs a S3 filesystem connection test. + * + * The currently supported `filesystem` are "storage" and "backups". + * + * @throws {ClientResponseError} + */ + testS3(filesystem?: string, options?: CommonOptions): Promise; + /** + * Sends a test email. + * + * The possible `emailTemplate` values are: + * - verification + * - password-reset + * - email-change + * + * @throws {ClientResponseError} + */ + testEmail(collectionIdOrName: string, toEmail: string, emailTemplate: string, options?: CommonOptions): Promise; + /** + * Generates a new Apple OAuth2 client secret. + * + * @throws {ClientResponseError} + */ + generateAppleClientSecret(clientId: string, teamId: string, keyId: string, privateKey: string, duration: number, options?: CommonOptions): Promise; +} +type UnsubscribeFunc = () => Promise; +declare class RealtimeService extends BaseService { + clientId: string; + private eventSource; + private subscriptions; + private lastSentSubscriptions; + private connectTimeoutId; + private maxConnectTimeout; + private reconnectTimeoutId; + private reconnectAttempts; + private maxReconnectAttempts; + private predefinedReconnectIntervals; + private pendingConnects; + /** + * Returns whether the realtime connection has been established. + */ + get isConnected(): boolean; + /** + * An optional hook that is invoked when the realtime client disconnects + * either when unsubscribing from all subscriptions or when the + * connection was interrupted or closed by the server. + * + * The received argument could be used to determine whether the disconnect + * is a result from unsubscribing (`activeSubscriptions.length == 0`) + * or because of network/server error (`activeSubscriptions.length > 0`). + * + * If you want to listen for the opposite, aka. when the client connection is established, + * subscribe to the `PB_CONNECT` event. + */ + onDisconnect?: (activeSubscriptions: Array) => void; + /** + * Register the subscription listener. + * + * You can subscribe multiple times to the same topic. + * + * If the SSE connection is not started yet, + * this method will also initialize it. + */ + subscribe(topic: string, callback: (data: any) => void, options?: SendOptions): Promise; + /** + * Unsubscribe from all subscription listeners with the specified topic. + * + * If `topic` is not provided, then this method will unsubscribe + * from all active subscriptions. + * + * This method is no-op if there are no active subscriptions. + * + * The related sse connection will be autoclosed if after the + * unsubscribe operation there are no active subscriptions left. + */ + unsubscribe(topic?: string): Promise; + /** + * Unsubscribe from all subscription listeners starting with the specified topic prefix. + * + * This method is no-op if there are no active subscriptions with the specified topic prefix. + * + * The related sse connection will be autoclosed if after the + * unsubscribe operation there are no active subscriptions left. + */ + unsubscribeByPrefix(keyPrefix: string): Promise; + /** + * Unsubscribe from all subscriptions matching the specified topic and listener function. + * + * This method is no-op if there are no active subscription with + * the specified topic and listener. + * + * The related sse connection will be autoclosed if after the + * unsubscribe operation there are no active subscriptions left. + */ + unsubscribeByTopicAndListener(topic: string, listener: EventListener): Promise; + private hasSubscriptionListeners; + private submitSubscriptions; + private getSubscriptionsCancelKey; + private getSubscriptionsByTopic; + private getNonEmptySubscriptionKeys; + private addAllSubscriptionListeners; + private removeAllSubscriptionListeners; + private connect; + private initConnect; + private hasUnsentSubscriptions; + private connectErrorHandler; + private disconnect; +} +declare abstract class CrudService extends BaseService { + /** + * Base path for the crud actions (without trailing slash, eg. '/admins'). + */ + abstract get baseCrudPath(): string; + /** + * Response data decoder. + */ + decode(data: { + [key: string]: any; + }): T; + /** + * Returns a promise with all list items batch fetched at once + * (by default 500 items per request; to change it set the `batch` query param). + * + * You can use the generic T to supply a wrapper type of the crud model. + * + * @throws {ClientResponseError} + */ + getFullList(options?: FullListOptions): Promise>; + /** + * Legacy version of getFullList with explicitly specified batch size. + */ + getFullList(batch?: number, options?: ListOptions): Promise>; + /** + * Returns paginated items list. + * + * You can use the generic T to supply a wrapper type of the crud model. + * + * @throws {ClientResponseError} + */ + getList(page?: number, perPage?: number, options?: ListOptions): Promise>; + /** + * Returns the first found item by the specified filter. + * + * Internally it calls `getList(1, 1, { filter, skipTotal })` and + * returns the first found item. + * + * You can use the generic T to supply a wrapper type of the crud model. + * + * For consistency with `getOne`, this method will throw a 404 + * ClientResponseError if no item was found. + * + * @throws {ClientResponseError} + */ + getFirstListItem(filter: string, options?: CommonOptions): Promise; + /** + * Returns single item by its id. + * + * You can use the generic T to supply a wrapper type of the crud model. + * + * If `id` is empty it will throw a 404 error. + * + * @throws {ClientResponseError} + */ + getOne(id: string, options?: CommonOptions): Promise; + /** + * Creates a new item. + * + * You can use the generic T to supply a wrapper type of the crud model. + * + * @throws {ClientResponseError} + */ + create(bodyParams?: { + [key: string]: any; + } | FormData, options?: CommonOptions): Promise; + /** + * Updates an existing item by its id. + * + * You can use the generic T to supply a wrapper type of the crud model. + * + * @throws {ClientResponseError} + */ + update(id: string, bodyParams?: { + [key: string]: any; + } | FormData, options?: CommonOptions): Promise; + /** + * Deletes an existing item by its id. + * + * @throws {ClientResponseError} + */ + delete(id: string, options?: CommonOptions): Promise; + /** + * Returns a promise with all list items batch fetched at once. + */ + protected _getFullList(batchSize?: number, options?: ListOptions): Promise>; +} +interface RecordAuthResponse { + /** + * The signed PocketBase auth record. + */ + record: T; + /** + * The PocketBase record auth token. + * + * If you are looking for the OAuth2 access and refresh tokens + * they are available under the `meta.accessToken` and `meta.refreshToken` props. + */ + token: string; + /** + * Auth meta data usually filled when OAuth2 is used. + */ + meta?: { + [key: string]: any; + }; +} +interface AuthProviderInfo { + name: string; + displayName: string; + state: string; + authURL: string; + codeVerifier: string; + codeChallenge: string; + codeChallengeMethod: string; +} +interface AuthMethodsList { + mfa: { + enabled: boolean; + duration: number; + }; + otp: { + enabled: boolean; + duration: number; + }; + password: { + enabled: boolean; + identityFields: Array; + }; + oauth2: { + enabled: boolean; + providers: Array; + }; +} +interface RecordSubscription { + action: string; // eg. create, update, delete + record: T; +} +type OAuth2UrlCallback = (url: string) => void | Promise; +interface OAuth2AuthConfig extends SendOptions { + // the name of the OAuth2 provider (eg. "google") + provider: string; + // custom scopes to overwrite the default ones + scopes?: Array; + // optional record create data + createData?: { + [key: string]: any; + }; + // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation + urlCallback?: OAuth2UrlCallback; + // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.) + query?: RecordOptions; +} +interface OTPResponse { + otpId: string; +} +declare class RecordService extends CrudService { + readonly collectionIdOrName: string; + constructor(client: Client, collectionIdOrName: string); + /** + * @inheritdoc + */ + get baseCrudPath(): string; + /** + * Returns the current collection service base path. + */ + get baseCollectionPath(): string; + /** + * Returns whether the current service collection is superusers. + */ + get isSuperusers(): boolean; + // --------------------------------------------------------------- + // Realtime handlers + // --------------------------------------------------------------- + /** + * Subscribe to realtime changes to the specified topic ("*" or record id). + * + * If `topic` is the wildcard "*", then this method will subscribe to + * any record changes in the collection. + * + * If `topic` is a record id, then this method will subscribe only + * to changes of the specified record id. + * + * It's OK to subscribe multiple times to the same topic. + * You can use the returned `UnsubscribeFunc` to remove only a single subscription. + * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic. + */ + subscribe(topic: string, callback: (data: RecordSubscription) => void, options?: RecordSubscribeOptions): Promise; + /** + * Unsubscribe from all subscriptions of the specified topic + * ("*" or record id). + * + * If `topic` is not set, then this method will unsubscribe from + * all subscriptions associated to the current collection. + */ + unsubscribe(topic?: string): Promise; + // --------------------------------------------------------------- + // Crud handers + // --------------------------------------------------------------- + /** + * @inheritdoc + */ + getFullList(options?: RecordFullListOptions): Promise>; + /** + * @inheritdoc + */ + getFullList(batch?: number, options?: RecordListOptions): Promise>; + /** + * @inheritdoc + */ + getList(page?: number, perPage?: number, options?: RecordListOptions): Promise>; + /** + * @inheritdoc + */ + getFirstListItem(filter: string, options?: RecordListOptions): Promise; + /** + * @inheritdoc + */ + getOne(id: string, options?: RecordOptions): Promise; + /** + * @inheritdoc + */ + create(bodyParams?: { + [key: string]: any; + } | FormData, options?: RecordOptions): Promise; + /** + * @inheritdoc + * + * If the current `client.authStore.record` matches with the updated id, then + * on success the `client.authStore.record` will be updated with the new response record fields. + */ + update(id: string, bodyParams?: { + [key: string]: any; + } | FormData, options?: RecordOptions): Promise; + /** + * @inheritdoc + * + * If the current `client.authStore.record` matches with the deleted id, + * then on success the `client.authStore` will be cleared. + */ + delete(id: string, options?: CommonOptions): Promise; + // --------------------------------------------------------------- + // Auth handlers + // --------------------------------------------------------------- + /** + * Prepare successful collection authorization response. + */ + protected authResponse(responseData: any): RecordAuthResponse; + /** + * Returns all available collection auth methods. + * + * @throws {ClientResponseError} + */ + listAuthMethods(options?: CommonOptions): Promise; + /** + * Authenticate a single auth collection record via its username/email and password. + * + * On success, this method also automatically updates + * the client's AuthStore data and returns: + * - the authentication token + * - the authenticated record model + * + * @throws {ClientResponseError} + */ + authWithPassword(usernameOrEmail: string, password: string, options?: RecordOptions): Promise>; + /** + * Authenticate a single auth collection record with OAuth2 code. + * + * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method. + * + * On success, this method also automatically updates + * the client's AuthStore data and returns: + * - the authentication token + * - the authenticated record model + * - the OAuth2 account data (eg. name, email, avatar, etc.) + * + * @throws {ClientResponseError} + */ + authWithOAuth2Code(provider: string, code: string, codeVerifier: string, redirectURL: string, createData?: { + [key: string]: any; + }, options?: RecordOptions): Promise>; + /** + * @deprecated + * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?). + */ + authWithOAuth2Code(provider: string, code: string, codeVerifier: string, redirectURL: string, createData?: { + [key: string]: any; + }, body?: any, query?: any): Promise>; + /** + * @deprecated This form of authWithOAuth2 is deprecated. + * + * Please use `authWithOAuth2Code()` OR its simplified realtime version + * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration. + */ + authWithOAuth2(provider: string, code: string, codeVerifier: string, redirectURL: string, createData?: { + [key: string]: any; + }, bodyParams?: { + [key: string]: any; + }, queryParams?: RecordOptions): Promise>; + /** + * Authenticate a single auth collection record with OAuth2 + * **without custom redirects, deeplinks or even page reload**. + * + * This method initializes a one-off realtime subscription and will + * open a popup window with the OAuth2 vendor page to authenticate. + * Once the external OAuth2 sign-in/sign-up flow is completed, the popup + * window will be automatically closed and the OAuth2 data sent back + * to the user through the previously established realtime connection. + * + * You can specify an optional `urlCallback` prop to customize + * the default url `window.open` behavior. + * + * On success, this method also automatically updates + * the client's AuthStore data and returns: + * - the authentication token + * - the authenticated record model + * - the OAuth2 account data (eg. name, email, avatar, etc.) + * + * Example: + * + * ```js + * const authData = await pb.collection("users").authWithOAuth2({ + * provider: "google", + * }) + * ``` + * + * Note1: When creating the OAuth2 app in the provider dashboard + * you have to configure `https://yourdomain.com/api/oauth2-redirect` + * as redirect URL. + * + * Note2: Safari may block the default `urlCallback` popup because + * it doesn't allow `window.open` calls as part of an `async` click functions. + * To workaround this you can either change your click handler to not be marked as `async` + * OR manually call `window.open` before your `async` function and use the + * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061). + * For example: + * ```js + * + * ... + * document.getElementById("btn").addEventListener("click", () => { + * pb.collection("users").authWithOAuth2({ + * provider: "gitlab", + * }).then((authData) => { + * console.log(authData) + * }).catch((err) => { + * console.log(err, err.originalError); + * }); + * }) + * ``` + * + * @throws {ClientResponseError} + */ + authWithOAuth2(options: OAuth2AuthConfig): Promise>; + /** + * Refreshes the current authenticated record instance and + * returns a new token and record data. + * + * On success this method also automatically updates the client's AuthStore. + * + * @throws {ClientResponseError} + */ + authRefresh(options?: RecordOptions): Promise>; + /** + * @deprecated + * Consider using authRefresh(options?). + */ + authRefresh(body?: any, query?: any): Promise>; + /** + * Sends auth record password reset request. + * + * @throws {ClientResponseError} + */ + requestPasswordReset(email: string, options?: CommonOptions): Promise; + /** + * @deprecated + * Consider using requestPasswordReset(email, options?). + */ + requestPasswordReset(email: string, body?: any, query?: any): Promise; + /** + * Confirms auth record password reset request. + * + * @throws {ClientResponseError} + */ + confirmPasswordReset(passwordResetToken: string, password: string, passwordConfirm: string, options?: CommonOptions): Promise; + /** + * @deprecated + * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?). + */ + confirmPasswordReset(passwordResetToken: string, password: string, passwordConfirm: string, body?: any, query?: any): Promise; + /** + * Sends auth record verification email request. + * + * @throws {ClientResponseError} + */ + requestVerification(email: string, options?: CommonOptions): Promise; + /** + * @deprecated + * Consider using requestVerification(email, options?). + */ + requestVerification(email: string, body?: any, query?: any): Promise; + /** + * Confirms auth record email verification request. + * + * If the current `client.authStore.record` matches with the auth record from the token, + * then on success the `client.authStore.record.verified` will be updated to `true`. + * + * @throws {ClientResponseError} + */ + confirmVerification(verificationToken: string, options?: CommonOptions): Promise; + /** + * @deprecated + * Consider using confirmVerification(verificationToken, options?). + */ + confirmVerification(verificationToken: string, body?: any, query?: any): Promise; + /** + * Sends an email change request to the authenticated record model. + * + * @throws {ClientResponseError} + */ + requestEmailChange(newEmail: string, options?: CommonOptions): Promise; + /** + * @deprecated + * Consider using requestEmailChange(newEmail, options?). + */ + requestEmailChange(newEmail: string, body?: any, query?: any): Promise; + /** + * Confirms auth record's new email address. + * + * If the current `client.authStore.record` matches with the auth record from the token, + * then on success the `client.authStore` will be cleared. + * + * @throws {ClientResponseError} + */ + confirmEmailChange(emailChangeToken: string, password: string, options?: CommonOptions): Promise; + /** + * @deprecated + * Consider using confirmEmailChange(emailChangeToken, password, options?). + */ + confirmEmailChange(emailChangeToken: string, password: string, body?: any, query?: any): Promise; + /** + * @deprecated use collection("_externalAuths").* + * + * Lists all linked external auth providers for the specified auth record. + * + * @throws {ClientResponseError} + */ + listExternalAuths(recordId: string, options?: CommonOptions): Promise>; + /** + * @deprecated use collection("_externalAuths").* + * + * Unlink a single external auth provider from the specified auth record. + * + * @throws {ClientResponseError} + */ + unlinkExternalAuth(recordId: string, provider: string, options?: CommonOptions): Promise; + /** + * Sends auth record OTP to the provided email. + * + * @throws {ClientResponseError} + */ + requestOTP(email: string, options?: CommonOptions): Promise; + /** + * Authenticate a single auth collection record via OTP. + * + * On success, this method also automatically updates + * the client's AuthStore data and returns: + * - the authentication token + * - the authenticated record model + * + * @throws {ClientResponseError} + */ + authWithOTP(otpId: string, password: string, options?: CommonOptions): Promise>; + /** + * Impersonate authenticates with the specified recordId and + * returns a new client with the received auth token in a memory store. + * + * If `duration` is 0 the generated auth token will fallback + * to the default collection auth token duration. + * + * This action currently requires superusers privileges. + * + * @throws {ClientResponseError} + */ + impersonate(recordId: string, duration: number, options?: CommonOptions): Promise; + // --------------------------------------------------------------- + // very rudimentary url query params replacement because at the moment + // URL (and URLSearchParams) doesn't seem to be fully supported in React Native + // + // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html + private _replaceQueryParams; +} +declare class CollectionService extends CrudService { + /** + * @inheritdoc + */ + get baseCrudPath(): string; + /** + * Imports the provided collections. + * + * If `deleteMissing` is `true`, all local collections and their fields, + * that are not present in the imported configuration, WILL BE DELETED + * (including their related records data)! + * + * @throws {ClientResponseError} + */ + import(collections: Array, deleteMissing?: boolean, options?: CommonOptions): Promise; + /** + * Returns type indexed map with scaffolded collection models + * populated with their default field values. + * + * @throws {ClientResponseError} + */ + getScaffolds(options?: CommonOptions): Promise<{ + [key: string]: CollectionModel; + }>; + /** + * Deletes all records associated with the specified collection. + * + * @throws {ClientResponseError} + */ + truncate(collectionIdOrName: string, options?: CommonOptions): Promise; +} +interface HourlyStats { + total: number; + date: string; +} +declare class LogService extends BaseService { + /** + * Returns paginated logs list. + * + * @throws {ClientResponseError} + */ + getList(page?: number, perPage?: number, options?: ListOptions): Promise>; + /** + * Returns a single log by its id. + * + * If `id` is empty it will throw a 404 error. + * + * @throws {ClientResponseError} + */ + getOne(id: string, options?: CommonOptions): Promise; + /** + * Returns logs statistics. + * + * @throws {ClientResponseError} + */ + getStats(options?: LogStatsOptions): Promise>; +} +interface HealthCheckResponse { + code: number; + message: string; + data: { + [key: string]: any; + }; +} +declare class HealthService extends BaseService { + /** + * Checks the health status of the api. + * + * @throws {ClientResponseError} + */ + check(options?: CommonOptions): Promise; +} +declare class FileService extends BaseService { + /** + * @deprecated Please replace with `pb.files.getURL()`. + */ + getUrl(record: { + [key: string]: any; + }, filename: string, queryParams?: FileOptions): string; + /** + * Builds and returns an absolute record file url for the provided filename. + */ + getURL(record: { + [key: string]: any; + }, filename: string, queryParams?: FileOptions): string; + /** + * Requests a new private file access token for the current auth model. + * + * @throws {ClientResponseError} + */ + getToken(options?: CommonOptions): Promise; +} +interface BackupFileInfo { + key: string; + size: number; + modified: string; +} +declare class BackupService extends BaseService { + /** + * Returns list with all available backup files. + * + * @throws {ClientResponseError} + */ + getFullList(options?: CommonOptions): Promise>; + /** + * Initializes a new backup. + * + * @throws {ClientResponseError} + */ + create(basename: string, options?: CommonOptions): Promise; + /** + * Uploads an existing backup file. + * + * Example: + * + * ```js + * await pb.backups.upload({ + * file: new Blob([...]), + * }); + * ``` + * + * @throws {ClientResponseError} + */ + upload(bodyParams: { + [key: string]: any; + } | FormData, options?: CommonOptions): Promise; + /** + * Deletes a single backup file. + * + * @throws {ClientResponseError} + */ + delete(key: string, options?: CommonOptions): Promise; + /** + * Initializes an app data restore from an existing backup. + * + * @throws {ClientResponseError} + */ + restore(key: string, options?: CommonOptions): Promise; + /** + * @deprecated Please use `getDownloadURL()`. + */ + getDownloadUrl(token: string, key: string): string; + /** + * Builds a download url for a single existing backup using a + * superuser file token and the backup file key. + * + * The file token can be generated via `pb.files.getToken()`. + */ + getDownloadURL(token: string, key: string): string; +} +interface CronJob { + id: string; + expression: string; +} +declare class CronService extends BaseService { + /** + * Returns list with all registered cron jobs. + * + * @throws {ClientResponseError} + */ + getFullList(options?: CommonOptions): Promise>; + /** + * Runs the specified cron job. + * + * @throws {ClientResponseError} + */ + run(jobId: string, options?: CommonOptions): Promise; +} +interface BatchRequest { + method: string; + url: string; + json?: { + [key: string]: any; + }; + files?: { + [key: string]: Array; + }; + headers?: { + [key: string]: string; + }; +} +interface BatchRequestResult { + status: number; + body: any; +} +declare class BatchService extends BaseService { + private requests; + private subs; + /** + * Starts constructing a batch request entry for the specified collection. + */ + collection(collectionIdOrName: string): SubBatchService; + /** + * Sends the batch requests. + * + * @throws {ClientResponseError} + */ + send(options?: SendOptions): Promise>; +} +declare class SubBatchService { + private requests; + private readonly collectionIdOrName; + constructor(requests: Array, collectionIdOrName: string); + /** + * Registers a record upsert request into the current batch queue. + * + * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create. + */ + upsert(bodyParams?: { + [key: string]: any; + } | FormData, options?: RecordOptions): void; + /** + * Registers a record create request into the current batch queue. + */ + create(bodyParams?: { + [key: string]: any; + } | FormData, options?: RecordOptions): void; + /** + * Registers a record update request into the current batch queue. + */ + update(id: string, bodyParams?: { + [key: string]: any; + } | FormData, options?: RecordOptions): void; + /** + * Registers a record delete request into the current batch queue. + */ + delete(id: string, options?: SendOptions): void; + private prepareRequest; +} +interface BeforeSendResult { + [key: string]: any; // for backward compatibility + url?: string; + options?: { + [key: string]: any; + }; +} +/** + * PocketBase JS Client. + */ +declare class Client { + /** + * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090'). + */ + baseURL: string; + /** + * Legacy getter alias for baseURL. + * @deprecated Please replace with baseURL. + */ + get baseUrl(): string; + /** + * Legacy setter alias for baseURL. + * @deprecated Please replace with baseURL. + */ + set baseUrl(v: string); + /** + * Hook that get triggered right before sending the fetch request, + * allowing you to inspect and modify the url and request options. + * + * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options + * + * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely. + * + * Example: + * ```js + * const pb = new PocketBase("https://example.com") + * + * pb.beforeSend = function (url, options) { + * options.headers = Object.assign({}, options.headers, { + * 'X-Custom-Header': 'example', + * }) + * + * return { url, options } + * } + * + * // use the created client as usual... + * ``` + */ + beforeSend?: (url: string, options: SendOptions) => BeforeSendResult | Promise; + /** + * Hook that get triggered after successfully sending the fetch request, + * allowing you to inspect/modify the response object and its parsed data. + * + * Returns the new Promise resolved `data` that will be returned to the client. + * + * Example: + * ```js + * const pb = new PocketBase("https://example.com") + * + * pb.afterSend = function (response, data, options) { + * if (response.status != 200) { + * throw new ClientResponseError({ + * url: response.url, + * status: response.status, + * response: { ... }, + * }) + * } + * + * return data; + * } + * + * // use the created client as usual... + * ``` + */ + afterSend?: ((response: Response, data: any) => any) & ((response: Response, data: any, options: SendOptions) => any); + /** + * Optional language code (default to `en-US`) that will be sent + * with the requests to the server as `Accept-Language` header. + */ + lang: string; + /** + * A replaceable instance of the local auth store service. + */ + authStore: BaseAuthStore; + /** + * An instance of the service that handles the **Settings APIs**. + */ + readonly settings: SettingsService; + /** + * An instance of the service that handles the **Collection APIs**. + */ + readonly collections: CollectionService; + /** + * An instance of the service that handles the **File APIs**. + */ + readonly files: FileService; + /** + * An instance of the service that handles the **Log APIs**. + */ + readonly logs: LogService; + /** + * An instance of the service that handles the **Realtime APIs**. + */ + readonly realtime: RealtimeService; + /** + * An instance of the service that handles the **Health APIs**. + */ + readonly health: HealthService; + /** + * An instance of the service that handles the **Backup APIs**. + */ + readonly backups: BackupService; + /** + * An instance of the service that handles the **Cron APIs**. + */ + readonly crons: CronService; + private cancelControllers; + private recordServices; + private enableAutoCancellation; + constructor(baseURL?: string, authStore?: BaseAuthStore | null, lang?: string); + /** + * @deprecated + * With PocketBase v0.23.0 admins are converted to a regular auth + * collection named "_superusers", aka. you can use directly collection("_superusers"). + */ + get admins(): RecordService; + /** + * Creates a new batch handler for sending multiple transactional + * create/update/upsert/delete collection requests in one network call. + * + * Example: + * ```js + * const batch = pb.createBatch(); + * + * batch.collection("example1").create({ ... }) + * batch.collection("example2").update("RECORD_ID", { ... }) + * batch.collection("example3").delete("RECORD_ID") + * batch.collection("example4").upsert({ ... }) + * + * await batch.send() + * ``` + */ + createBatch(): BatchService; + /** + * Returns the RecordService associated to the specified collection. + */ + collection(idOrName: string): RecordService; + /** + * Globally enable or disable auto cancellation for pending duplicated requests. + */ + autoCancellation(enable: boolean): Client; + /** + * Cancels single request by its cancellation key. + */ + cancelRequest(requestKey: string): Client; + /** + * Cancels all pending requests. + */ + cancelAllRequests(): Client; + /** + * Constructs a filter expression with placeholders populated from a parameters object. + * + * Placeholder parameters are defined with the `{:paramName}` notation. + * + * The following parameter values are supported: + * + * - `string` (_single quotes are autoescaped_) + * - `number` + * - `boolean` + * - `Date` object (_stringified into the PocketBase datetime format_) + * - `null` + * - everything else is converted to a string using `JSON.stringify()` + * + * Example: + * + * ```js + * pb.collection("example").getFirstListItem(pb.filter( + * 'title ~ {:title} && created >= {:created}', + * { title: "example", created: new Date()} + * )) + * ``` + */ + filter(raw: string, params?: { + [key: string]: any; + }): string; + /** + * @deprecated Please use `pb.files.getURL()`. + */ + getFileUrl(record: { + [key: string]: any; + }, filename: string, queryParams?: FileOptions): string; + /** + * @deprecated Please use `pb.buildURL()`. + */ + buildUrl(path: string): string; + /** + * Builds a full client url by safely concatenating the provided path. + */ + buildURL(path: string): string; + /** + * Sends an api http request. + * + * @throws {ClientResponseError} + */ + send(path: string, options: SendOptions): Promise; + /** + * Shallow copy the provided object and takes care to initialize + * any options required to preserve the backward compatability. + * + * @param {SendOptions} options + * @return {SendOptions} + */ + private initSendOptions; + /** + * Extracts the header with the provided name in case-insensitive manner. + * Returns `null` if no header matching the name is found. + */ + private getHeader; +} +/** + * ClientResponseError is a custom Error class that is intended to wrap + * and normalize any error thrown by `Client.send()`. + */ +declare class ClientResponseError extends Error { + url: string; + status: number; + response: { + [key: string]: any; + }; + isAbort: boolean; + originalError: any; + constructor(errData?: any); + /** + * Alias for `this.response` for backward compatibility. + */ + get data(): { + [key: string]: any; + }; + /** + * Make a POJO's copy of the current error class instance. + * @see https://github.com/vuex-orm/vuex-orm/issues/255 + */ + toJSON(): this; +} +type AsyncSaveFunc = (serializedPayload: string) => Promise; +type AsyncClearFunc = () => Promise; +/** + * AsyncAuthStore is a helper auth store implementation + * that could be used with any external async persistent layer + * (key-value db, local file, etc.). + * + * Here is an example with the React Native AsyncStorage package: + * + * ``` + * import AsyncStorage from "@react-native-async-storage/async-storage"; + * import PocketBase, { AsyncAuthStore } from "pocketbase"; + * + * const store = new AsyncAuthStore({ + * save: async (serialized) => AsyncStorage.setItem("pb_auth", serialized), + * initial: AsyncStorage.getItem("pb_auth"), + * }); + * + * const pb = new PocketBase("https://example.com", store) + * ``` + */ +declare class AsyncAuthStore extends BaseAuthStore { + private saveFunc; + private clearFunc?; + private queue; + constructor(config: { + // The async function that is called every time + // when the auth store state needs to be persisted. + save: AsyncSaveFunc; + /// An *optional* async function that is called every time + /// when the auth store needs to be cleared. + /// + /// If not explicitly set, `saveFunc` with empty data will be used. + clear?: AsyncClearFunc; + // An *optional* initial data to load into the store. + initial?: string | Promise; + }); + /** + * @inheritdoc + */ + save(token: string, record?: AuthRecord): void; + /** + * @inheritdoc + */ + clear(): void; + /** + * Initializes the auth store state. + */ + private _loadInitial; + /** + * Appends an async function to the queue. + */ + private _enqueue; + /** + * Starts the queue processing. + */ + private _dequeue; +} +/** + * The default token store for browsers with auto fallback + * to runtime/memory if local storage is undefined (e.g. in node env). + */ +declare class LocalAuthStore extends BaseAuthStore { + private storageFallback; + private storageKey; + constructor(storageKey?: string); + /** + * @inheritdoc + */ + get token(): string; + /** + * @inheritdoc + */ + get record(): AuthRecord; + /** + * @deprecated use `record` instead. + */ + get model(): AuthRecord; + /** + * @inheritdoc + */ + save(token: string, record?: AuthRecord): void; + /** + * @inheritdoc + */ + clear(): void; + // --------------------------------------------------------------- + // Internal helpers: + // --------------------------------------------------------------- + /** + * Retrieves `key` from the browser's local storage + * (or runtime/memory if local storage is undefined). + */ + private _storageGet; + /** + * Stores a new data in the browser's local storage + * (or runtime/memory if local storage is undefined). + */ + private _storageSet; + /** + * Removes `key` from the browser's local storage and the runtime/memory. + */ + private _storageRemove; + /** + * Updates the current store state on localStorage change. + */ + private _bindStorageEvent; +} +/** + * Returns JWT token's payload data. + */ +declare function getTokenPayload(token: string): { + [key: string]: any; +}; +/** + * Checks whether a JWT token is expired or not. + * Tokens without `exp` payload key are considered valid. + * Tokens with empty payload (eg. invalid token strings) are considered expired. + * + * @param token The token to check. + * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property. + */ +declare function isTokenExpired(token: string, expirationThreshold?: number): boolean; +export { Client as default, BeforeSendResult, ClientResponseError, CollectionService, HealthCheckResponse, HealthService, HourlyStats, LogService, UnsubscribeFunc, RealtimeService, RecordAuthResponse, AuthProviderInfo, AuthMethodsList, RecordSubscription, OAuth2UrlCallback, OAuth2AuthConfig, OTPResponse, RecordService, CrudService, BatchRequest, BatchRequestResult, BatchService, SubBatchService, AsyncSaveFunc, AsyncClearFunc, AsyncAuthStore, AuthRecord, AuthModel, OnStoreChangeFunc, BaseAuthStore, LocalAuthStore, ListResult, BaseModel, LogModel, RecordModel, CollectionField, TokenConfig, AuthAlertConfig, OTPConfig, MFAConfig, PasswordAuthConfig, OAuth2Provider, OAuth2Config, EmailTemplate, BaseCollectionModel, ViewCollectionModel, AuthCollectionModel, CollectionModel, SendOptions, CommonOptions, ListOptions, FullListOptions, RecordOptions, RecordListOptions, RecordFullListOptions, RecordSubscribeOptions, LogStatsOptions, FileOptions, AuthOptions, normalizeUnknownQueryParams, serializeQueryParams, ParseOptions, cookieParse, SerializeOptions, cookieSerialize, getTokenPayload, isTokenExpired }; diff --git a/www/js/vendor/pocketbase.es.js b/www/js/vendor/pocketbase.es.js new file mode 100644 index 0000000..b56e631 --- /dev/null +++ b/www/js/vendor/pocketbase.es.js @@ -0,0 +1,2 @@ +class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&("AbortError"==e.name||20==e.code)&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong."),this.cause=this.originalError}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},t||{}).decode||defaultDecode;let n=0;for(;n0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=cookieParse(e||"")[t]||"";let n={};try{n=JSON.parse(s),(null===typeof n||"object"!=typeof n||Array.isArray(n))&&(n={})}catch(e){}this.save(n.token||"",n.record||n.model||null)}exportToCookie(e,t=i){const s={secure:!0,sameSite:!0,httpOnly:!0,path:"/"},n=getTokenPayload(this.token);s.expires=n?.exp?new Date(1e3*n.exp):new Date("1970-01-01"),e=Object.assign({},s,e);const r={token:this.token,record:this.record?JSON.parse(JSON.stringify(this.record)):null};let o=cookieSerialize(t,JSON.stringify(r),e);const a="undefined"!=typeof Blob?new Blob([o]).size:o.length;if(r.record&&a>4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){const i=encodeURIComponent(s),n=Array.isArray(e[s])?e[s]:[e[s]];for(let e of n)e=prepareQueryParamValue(e),null!==e&&t.push(i+"="+e)}return t.join("&")}function prepareQueryParamValue(e){return null==e?null:e instanceof Date?encodeURIComponent(e.toISOString().replace("T"," ")):"object"==typeof e?encodeURIComponent(JSON.stringify(e)):encodeURIComponent(e)}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(this.clientId&&this.onDisconnect&&this.onDisconnect(Object.keys(this.subscriptions)),clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}class CronService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/crons",e)}async run(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/crons/${encodeURIComponent(e)}`,t).then((()=>!0))}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor?.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}const r=/^[\-\.\d]+$/;function inferFormDataValue(e){if("string"!=typeof e)return e;if("true"==e)return!0;if("false"==e)return!1;if(("-"===e[0]||e[0]>="0"&&e[0]<="9")&&r.test(e)){let t=+e;if(""+t===e)return t}return e}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e{if("@jsonPayload"===s&&"string"==typeof e)try{let s=JSON.parse(e);Object.assign(t,s)}catch(e){console.warn("@jsonPayload error:",e)}else void 0!==t[s]?(Array.isArray(t[s])||(t[s]=[t[s]]),t[s].push(inferFormDataValue(e))):t[s]=inferFormDataValue(e)})),t}(s));for(const t in s){const i=s[t];if(isFile(i))e.files[t]=e.files[t]||[],e.files[t].push(i);else if(Array.isArray(i)){const s=[],n=[];for(const e of i)isFile(e)?s.push(e):n.push(e);if(s.length>0&&s.length==i.length){e.files[t]=e.files[t]||[];for(let i of s)e.files[t].push(i)}else if(e.json[t]=n,s.length>0){let i=t;t.startsWith("+")||t.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let t of s)e.files[i].push(t)}}else e.json[t]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this),this.crons=new CronService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){if(t.signal?.aborted||"undefined"!=typeof DOMException&&e instanceof DOMException&&("AbortError"==e.name||20==e.code))throw e}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if(void 0!==i)if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}class AsyncAuthStore extends BaseAuthStore{constructor(e){super(),this.queue=[],this.saveFunc=e.save,this.clearFunc=e.clear,this._enqueue((()=>this._loadInitial(e.initial)))}save(e,t){super.save(e,t);let s="";try{s=JSON.stringify({token:e,record:t})}catch(e){console.warn("AsyncAuthStore: failed to stringify the new state")}this._enqueue((()=>this.saveFunc(s)))}clear(){super.clear(),this.clearFunc?this._enqueue((()=>this.clearFunc())):this._enqueue((()=>this.saveFunc("")))}async _loadInitial(e){try{if(e=await e){let t;"string"==typeof e?t=JSON.parse(e)||{}:"object"==typeof e&&(t=e),this.save(t.token||"",t.record||t.model||null)}}catch(e){}}_enqueue(e){this.queue.push(e),1==this.queue.length&&this._dequeue()}_dequeue(){this.queue.length&&this.queue[0]().finally((()=>{this.queue.shift(),this.queue.length&&this._dequeue()}))}}export{AsyncAuthStore,BaseAuthStore,BatchService,ClientResponseError,CollectionService,CrudService,HealthService,LocalAuthStore,LogService,RealtimeService,RecordService,SubBatchService,cookieParse,cookieSerialize,Client as default,getTokenPayload,isTokenExpired,normalizeUnknownQueryParams,serializeQueryParams}; +//# sourceMappingURL=pocketbase.es.js.map