From 200c19b26fe20d1278ddaafc3e69ba94083cd21f Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sat, 1 Aug 2026 15:05:40 +0300 Subject: [PATCH 01/37] added non-zero exit status support for returned command errors --- CHANGELOG.md | 5 ++++- pocketbase.go | 56 +++++++++++++++++++-------------------------------- 2 files changed, 25 insertions(+), 36 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19ca9e00c2..b928bcf485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ -## v0.39.11 (WIP) +## v0.40.0 (WIP) + +- Propagate console command errors and recovered panics to `app.Start()` so that the program can exit with non-zero code while still ensuring that `app.OnTerminate` hook (responsible for the app graceful shutdown handling) was triggered. + _⚠️ Note that this could be a slight breaking change in case you are chaining PocketBase commands and relied on the previous `0` exit status for `Command.RunE` returned errors._ - Fixed "API preview" examples ([#7782](https://github.com/pocketbase/pocketbase/issues/7782)). diff --git a/pocketbase.go b/pocketbase.go index 91b92c8105..509364c390 100644 --- a/pocketbase.go +++ b/pocketbase.go @@ -1,6 +1,7 @@ package pocketbase import ( + "errors" "io" "os" "os/signal" @@ -9,7 +10,6 @@ import ( "syscall" "time" - "github.com/fatih/color" "github.com/pocketbase/pocketbase/cmd" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/tools/hook" @@ -117,8 +117,9 @@ func NewWithConfig(config Config) *PocketBase { hideStartBanner: config.HideStartBanner, } - // replace with a colored stderr writer - pb.RootCmd.SetErr(newErrWriter()) + // don't write command errors to the stderr because the error is + // propagated back to the app.Start() and could result in duplication + pb.RootCmd.SetErr(&nopWrite{}) // parse base flags // (errors are ignored, since the full flags parsing happens on Execute()) @@ -183,26 +184,25 @@ func (pb *PocketBase) Execute() error { } } - done := make(chan bool, 1) + execCh := make(chan error, 1) + sigCh := make(chan os.Signal, 1) // listen for interrupt signal to gracefully shutdown the application - go func() { - sigch := make(chan os.Signal, 1) - signal.Notify(sigch, os.Interrupt, syscall.SIGTERM) - <-sigch - - done <- true - }() + signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) // execute the root command go func() { - // note: leave to the commands to decide whether to print their error - pb.RootCmd.Execute() - - done <- true + execCh <- routine.SafeWrap(pb.RootCmd.Execute)() }() - <-done + // wait for either an OS signal or the command to complete + var execErr error + select { + case <-sigCh: + case execErr = <-execCh: + } + + signal.Stop(sigCh) // trigger cleanups // @@ -210,7 +210,7 @@ func (pb *PocketBase) Execute() error { event := new(core.TerminateEvent) event.App = pb return pb.OnTerminate().Trigger(event, func(e *core.TerminateEvent) error { - return e.App.ResetBootstrapState() + return errors.Join(e.App.ResetBootstrapState(), execErr) }) } @@ -308,24 +308,10 @@ func inspectRuntime() (baseDir string, withGoRun bool) { return } -// newErrWriter returns a red colored stderr writter. -func newErrWriter() *coloredWriter { - return &coloredWriter{ - w: os.Stderr, - c: color.New(color.FgRed), - } -} +var _ io.Writer = (*nopWrite)(nil) -// coloredWriter is a small wrapper struct to construct a [color.Color] writter. -type coloredWriter struct { - w io.Writer - c *color.Color -} +type nopWrite struct{} -// Write writes the p bytes using the colored writer. -func (colored *coloredWriter) Write(p []byte) (n int, err error) { - colored.c.SetWriter(colored.w) - defer colored.c.UnsetWriter(colored.w) - - return colored.c.Print(string(p)) +func (w *nopWrite) Write(p []byte) (n int, err error) { + return } From f9795da8c7c6170c863c39c375dba7bc298f9092 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sun, 2 Aug 2026 14:20:31 +0300 Subject: [PATCH 02/37] added hasArchiveExtension util --- .../{index-CQVsfOm8.js => index-BQ-53gTd.js} | 4 +- ....js => pageConfirmEmailChange-l_DOk6UT.js} | 2 +- ...s => pageConfirmPasswordReset-UQX1jz2S.js} | 2 +- ...js => pageConfirmVerification-Bc6dMZfz.js} | 2 +- ...-BDYLSgKa.js => pageInstaller-2TD7r9Pz.js} | 2 +- ui/dist/index.html | 2 +- ui/src/utils.js | 41 +++++++++++++++---- 7 files changed, 40 insertions(+), 15 deletions(-) rename ui/dist/assets/{index-CQVsfOm8.js => index-BQ-53gTd.js} (99%) rename ui/dist/assets/{pageConfirmEmailChange-BvW30fMG.js => pageConfirmEmailChange-l_DOk6UT.js} (97%) rename ui/dist/assets/{pageConfirmPasswordReset-CG0h2Q6K.js => pageConfirmPasswordReset-UQX1jz2S.js} (97%) rename ui/dist/assets/{pageConfirmVerification-C5mNs2GJ.js => pageConfirmVerification-Bc6dMZfz.js} (96%) rename ui/dist/assets/{pageInstaller-BDYLSgKa.js => pageInstaller-2TD7r9Pz.js} (98%) diff --git a/ui/dist/assets/index-CQVsfOm8.js b/ui/dist/assets/index-BQ-53gTd.js similarity index 99% rename from ui/dist/assets/index-CQVsfOm8.js rename to ui/dist/assets/index-BQ-53gTd.js index e92a6f7bf9..991daadfed 100644 --- a/ui/dist/assets/index-CQVsfOm8.js +++ b/ui/dist/assets/index-BQ-53gTd.js @@ -1,6 +1,6 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./docsList-DsIHfo2q.js","./expandInfo-CJ9aeAaN.js","./fieldsInfo-CiLcXgNq.js","./docsView-oyuvqZP8.js","./docsCreate-Ap21j9FE.js","./docsUpdate-DAnNYWFv.js","./docsListAuthMethods-CYETXzX7.js","./docsAuthWithPassword-NXiq7pZI.js","./docsAuthWithOAuth2-qI6si9uJ.js","./docsAuthWithOTP-75iz1Xmg.js","./docsAuthRefresh-Cq3xTY6M.js"])))=>i.map(i=>d[i]); var e=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,n)=>()=>(n||(e((n={exports:{}}).exports,n),e=null),n.exports),c=(e,a,s,c)=>{if(a&&typeof a==`object`||typeof a==`function`)for(var l=i(a),u=0,d=l.length,f;ua[e]).bind(null,f),enumerable:!(c=r(a,f))||c.enumerable});return e},l=(r,i,o)=>(o=r==null?{}:e(a(r)),c(i||!r||!r.__esModule?n(o,`default`,{value:r,enumerable:!0}):o,r));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))r(e);new MutationObserver(e=>{for(let n of e)if(n.type===`childList`)for(let e of n.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&r(e)}).observe(document,{childList:!0,subtree:!0});function n(e){let n={};return e.integrity&&(n.integrity=e.integrity),e.referrerPolicy&&(n.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?n.credentials=`include`:e.crossOrigin===`anonymous`?n.credentials=`omit`:n.credentials=`same-origin`,n}function r(e){if(e.ep)return;e.ep=!0;let r=n(e);fetch(e.href,r)}})();var u=`abcdefghijklmnopqrstuvwxyz0123456789`,d=store({hash:window.location.hash});window.addEventListener(`hashchange`,()=>{d.hash=window.location.hash}),Prism.languages.pbrule={string:Prism.languages.js.string,number:Prism.languages.js.number,function:Prism.languages.js.function,boolean:/\b(?:true|false)\b/i,constant:/\b(?:null)\b/i,comment:{pattern:/\/\/.*/,greedy:!0},italic:/_via_|\:\w+/,keyword:/&&|\|\||\??(?:!~|!=|>=|<=|=|~|>|>|<)(?=[@\w\s]|$)/};var f={isObject(e){return typeof e==`object`&&!!e&&e.constructor===Object},isEmpty(e){return e==null||e===``||Array.isArray(e)&&e.length===0||typeof e==`object`&&app.utils.isEmptyObject(e)},isEmptyObject(e){for(let n in e)return!1;return!0},toArray(e,n=!1){return Array.isArray(e)?e.slice():(n||!f.isEmpty(e))&&e!==void 0?[e]:[]},removeByValue(e,n){if(!Array.isArray(e)){console.warn(`[removeByValue] not an array:`,e);return}for(let r=e.length-1;r>=0;r--)if(e[r]==n){e.splice(r,1);break}},removeByKey(e,n,r){if(!Array.isArray(e)){console.warn(`[removeByKey] not an array:`,e);return}for(let i in e)if(e[i][n]==r){e.splice(i,1);break}},pushUnique(e,n){if(!Array.isArray(e)){console.warn(`[pushUnique] not an array:`,e);return}e.includes(n)||e.push(n)},mergeUnique(e,n){for(let r of n)app.utils.pushUnique(e,r);return e},pushOrReplaceObject(e,n,r=`id`){for(let i=e.length-1;i>=0;i--)if(e[i][r]==n[r]){e[i]=n;return}e.push(n)},filterDuplicatesByKey(e,n=`id`){e=Array.isArray(e)?e:[];let r={};for(let i of e)r[i[n]]=i;return Object.values(r)},filterRedactedProps(e,n=`******`){let r=JSON.parse(JSON.stringify(e||{}));for(let e in r)typeof r[e]==`object`&&r[e]!==null?r[e]=f.filterRedactedProps(r[e],n):r[e]===n&&delete r[e];return r},getByPath(e,n,r=null,i=`.`){let a=e||{},o=(n||``).split(i);for(let e of o){if(!f.isObject(a)&&!Array.isArray(a)||a[e]===void 0)return r;a=a[e]}return a},setByPath(e,n,r,i=`.`){if(typeof e!=`object`||!e){console.warn(`setByPath: data not an object or array.`);return}let a=e,o=n.split(i),s=o.pop();for(let e of o)(!f.isObject(a)&&!Array.isArray(a)||!f.isObject(a[e])&&!Array.isArray(a[e]))&&(a[e]={}),a=a[e];a[s]=r},deleteByPath(e,n,r=`.`){let i=e||{},a=(n||``).split(r),o=a.pop();for(let e of a)(!f.isObject(i)&&!Array.isArray(i)||!f.isObject(i[e])&&!Array.isArray(i[e]))&&(i[e]={}),i=i[e];Array.isArray(i)?i.splice(o,1):f.isObject(i)&&delete i[o],a.length>0&&(Array.isArray(i)&&!i.length||f.isObject(i)&&!Object.keys(i).length)&&(Array.isArray(e)&&e.length>0||f.isObject(e)&&Object.keys(e).length>0)&&f.deleteByPath(e,a.join(r),r)},emptyClone(e,n=[]){let r=JSON.parse(JSON.stringify(e));for(let e in r)n.includes(e)||(typeof r[e]==`string`?r[e]=``:typeof r[e]==`number`?r[e]=0:typeof r[e]==`boolean`?r[e]=!1:Array.isArray(r[e])?r[e]=[]:app.utils.isObject(r[e])&&(r[e]={}));return r},randomString(e=8,n=u){let r=``;for(let i=0;i`u`)return app.utils.randomString(e);let n=new Uint8Array(e);crypto.getRandomValues(n);let r=``;for(let i=0;i`,`>`).replaceAll(`"`,`"`).replaceAll(`'`,`'`):``},plainText(e){return e?(new DOMParser().parseFromString(e,`text/html`).body.textContent||``).trim():``},truncate(e,n=150,r=!0){if(e=``+e,e.length<=n)return e;if(e=e.slice(0,n),r){for(;e.endsWith(`.`);)e=e.slice(0,-1);e+=`...`}return e},truncateObject(e,n=150,r=!0){let i=Array.isArray(e)?[]:{};for(let a in e){let o=e[a];typeof o==`string`?o=app.utils.truncate(o,n,r):(Array.isArray(o)||app.utils.isObject(o))&&(o=app.utils.truncateObject(o,n,r)),i[a]=o}return i},displayValue(e,n=150,r=`N/A`){if(f.isEmpty(e))return r;if(typeof e!=`string`)if(typeof e==`boolean`)e=e?`True`:`False`;else if(Array.isArray(e)&&typeof e[0]!=`object`)e=e.map(e=>f.displayValue(e,n,r)).join(`, `);else try{e=JSON.stringify(e)||``}catch{e=``+e}return e?f.truncate(e,n):r},splitNonEmpty(e,n=`,`){let r=(e||``).split(n),i=[];for(let e of r)e=e.trim(),f.isEmpty(e)||i.push(e);return i},joinNonEmpty(e,n=`, `){e||=[];let r=[];for(let n of e)n=typeof n==`string`?n.trim():n,f.isEmpty(n)||r.push(``+n);return r.join(n)},formattedFileSize(e){let n=e?Math.floor(Math.log(e)/Math.log(1024)):0;return(e/1024**n).toFixed(2)*1+` `+[`B`,`KB`,`MB`,`GB`,`TB`][n]},toRFC3339Datetime(e){if(!e)return``;let n;return n=e instanceof Date?e:typeof e==`string`?new Date(e.replace(` `,`T`)):new Date(e),n.toISOString().replace(`T`,` `)},toLocalDatetime(e){if(!e)return``;let n;n=e instanceof Date?e:typeof e==`string`?new Date(e.replace(` `,`T`)):new Date(e);let r=n.getFullYear();return isNaN(r)?``:`${r}-${(n.getMonth()+1).toString().padStart(2,`0`)}-${n.getDate().toString().padStart(2,`0`)} ${n.getHours().toString().padStart(2,`0`)}:${n.getMinutes().toString().padStart(2,`0`)}:${n.getSeconds().toString().padStart(2,`0`)}.${n.getMilliseconds().toString().padStart(3,`0`)}`},toDatetimeLocalInputValue(e){if(!e)return``;let n;n=e instanceof Date?e:typeof e==`string`?new Date(e.replaceAll(` `,`T`)):new Date(e);let r=n.getFullYear();return isNaN(r)?``:`${r}-${(n.getMonth()+1).toString().padStart(2,`0`)}-${n.getDate().toString().padStart(2,`0`)}T${n.getHours().toString().padStart(2,`0`)}:${n.getMinutes().toString().padStart(2,`0`)}:${n.getSeconds().toString().padStart(2,`0`)}`},async copyToClipboard(e){if(e=e==null?``:e instanceof Date?e.toISOString():typeof e==`object`?JSON.stringify(e):``+e,!(!e.length||!window.navigator?.clipboard))return window.navigator.clipboard.writeText(e).catch(e=>{console.warn(`Failed to copy.`,e)})},download(e,n){let r=document.createElement(`a`);r.setAttribute(`href`,e),r.setAttribute(`download`,n),r.setAttribute(`target`,`_blank`),r.setAttribute(`rel`,`noopener noreferrer`),r.click(),r=null},downloadJSON(e,n){n=n.endsWith(`.json`)?n:n+`.json`;let r=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),i=window.URL.createObjectURL(r);f.download(i,n)},downloadCSV(e,n){n=n.endsWith(`.csv`)?n:n+`.csv`;let r=e.map(e=>e.map(e=>`"`+(``+e).replaceAll(`"`,`""`)+`"`).join(`,`)).join(` -`),i=new Blob([r],{type:`text/csv;charset=utf-8;`}),a=window.URL.createObjectURL(i);f.download(a,n)},getApiExampleURL(){let e;if(app.pb.baseURL.startsWith(`http://`)||app.pb.baseURL.startsWith(`https://`))e=app.pb.baseURL;else{e=window.location.href;let n=e.indexOf(`/_/`);e=n>=0?e.substring(0,n):window.location.origin}return e.replace(`//localhost`,`//127.0.0.1`)},isActivePath(e,n=!0,r=``){r||=d.hash;let i;return i=RegExp(n?`^`+RegExp.escape(e)+`\\/?.*$`:`^`+RegExp.escape(e)+`\\/?(?:\\?.+)?$`),i.test(r)},getHashQueryParams(e=``){e||=d.hash;let n=``,r=e.indexOf(`?`);return r>-1&&(n=window.location.hash.substring(r+1)),Object.fromEntries(new URLSearchParams(n))},replaceHashQueryParams(e,n=null){e||={};let r=``,i=window.location.hash,a=i.indexOf(`?`);a>-1&&(r=i.substring(a+1),i=i.substring(0,a));let o=new URLSearchParams(r);for(let n in e){let r=e[n];f.isEmpty(r)?o.delete(n):o.set(n,r)}r=o.toString(),r!=``&&(i+=`?`+r);let s=window.location.href,c=s.indexOf(`#`);c>-1&&(s=s.substring(0,c));let l=s+i;return n===!1||(n===!0?window.history.pushState(null,``,l):window.history.replaceState(null,``,l)),l},getLocalHistory(e,n=null){try{let r=window.localStorage.getItem(e);if(r)return JSON.parse(r)||n}catch(n){console.log(`failed to load local history:`,e,n)}return n},saveLocalHistory(e,n){try{app.utils.isEmpty(n)?window.localStorage.removeItem(e):typeof n==`string`?window.localStorage.setItem(e,n):window.localStorage.setItem(e,JSON.stringify(n))}catch(n){console.log(`failed to save local history:`,e,n)}},generateThumb(e,n=100,r=100){return new Promise(i=>{let a=new FileReader;a.onload=function(a){let o=new Image;o.onload=function(){let a=document.createElement(`canvas`),s=a.getContext(`2d`),c=o.width,l=o.height;return a.width=n,a.height=r,s.drawImage(o,c>l?(c-l)/2:0,0,c>l?l:c,c>l?l:c,0,0,n,r),i(a.toDataURL(e.type))},o.src=a.target.result},a.readAsDataURL(e)})},normalizeSearchFilter(e,n=[]){if(e=(e||``).trim(),!e||!n.length)return e;for(let n of[`=`,`!=`,`~`,`!~`,`>`,`>=`,`<`,`<=`])if(e.includes(n))return e;return e=isNaN(e)&&e!=`true`&&e!=`false`?`"${e.replace(/^[\"\'\`]|[\"\'\`]$/gm,``)}"`:e,n.map(n=>`${n}~${e}`).join(`||`)},logLevels:{[-4]:{label:`DEBUG`,class:``},0:{label:`INFO`,class:`success`},4:{label:`WARN`,class:`warning`},8:{label:`ERROR`,class:`danger`}},logDataFormatters:{execTime:function(e){return e?.data?.execTime===void 0?`N/A`:e.data.execTime+`ms`}},extendStore(e,n={},...r){let i=[];for(let a in n){let o=n[a];typeof e.__raw?.[a]==`function`||typeof o!=`function`||a.length>2&&a.startsWith(`on`)||r.includes(a)?e[a]=o:i.push(watch(o,n=>{e[a]=n}))}return i},cssTimeToMs(e){return e?(e=e.toLowerCase(),e.endsWith(`ms`)?Number(e.substring(0,e.length-2)):e.endsWith(`s`)?Number(e.substring(0,e.length-1)):Number(e)||0):0},isDarkEnoughForWhiteText(e){if(e=e?.startsWith(`#`)?e.substring(1):e,e?.length!=6)return!1;let n=parseInt(e.substring(0,2),16),r=parseInt(e.substring(2,4),16),i=parseInt(e.substring(4,6),16);return(n*299+r*587+i*114)/1e3<128},bulkSelectRange(e,n,r,i){let a=e.findIndex(e=>e.id==r.id);if(a==-1)return;let o=Object.keys(n),s=o[o.length-1],c=e.findIndex(e=>e.id==s);if(c==-1)return;let l=c,u=a;l>u&&([l,u]=[u,l]);for(let r=l;r<=u;r++)i?n[e[r].id]=e[r]:delete n[e[r].id]},imageExtensions:[`.jpg`,`.jpeg`,`.png`,`.svg`,`.gif`,`.jfif`,`.webp`,`.avif`],videoExtensions:[`.mp4`,`.avi`,`.mov`,`.3gp`,`.wmv`],audioExtensions:[`.aa`,`.aac`,`.m4v`,`.mp3`,`.ogg`,`.oga`,`.mogg`,`.amr`],documentExtensions:[`.pdf`,`.doc`,`.docx`,`.xls`,`.xlsx`,`.ppt`,`.pptx`,`.odp`,`.odt`,`.ods`,`.txt`],hasImageExtension(e){return e=(e||``).toLowerCase(),!!app.utils.imageExtensions.find(n=>e.endsWith(n))},hasVideoExtension(e){return e=(e||``).toLowerCase(),!!app.utils.videoExtensions.find(n=>e.endsWith(n))},hasAudioExtension(e){return e=(e||``).toLowerCase(),!!app.utils.audioExtensions.find(n=>e.endsWith(n))},hasDocumentExtension(e){return e=(e||``).toLowerCase(),!!app.utils.documentExtensions.find(n=>e.endsWith(n))},getFileType(e){return app.utils.hasImageExtension(e)?`image`:app.utils.hasVideoExtension(e)?`video`:app.utils.hasAudioExtension(e)?`audio`:app.utils.hasDocumentExtension(e)?`document`:`file`},fileTypeIcons:{image:`ri-image-line`,video:`ri-movie-line`,audio:`ri-music-2-line`,document:`ri-file-line`,file:`ri-file-line`},fallbackFieldIcon:`ri-puzzle-line`,fallbackCollectionIcon:`ri-puzzle-line`,fallbackProviderIcon:`ri-puzzle-line`,fallbackPresentableProps:[`title`,`name`,`slug`,`email`,`username`,`nickname`,`displayName`,`label`,`subject`,`topic`,`message`,`heading`,`headline`,`header`,`caption`,`key`,`identifier`,`id`],sortedCollections(e=[]){let n,r;function i(e,i){return n=e.name.startsWith(`_`),r=i.name.startsWith(`_`),n&&!r?1:!n&&r?-1:e.name>i.name?1:e.namee?.id&&!a.find(n=>n.id==e.id)),s=a.filter(e=>e?.id&&!i.find(n=>n.id==e.id)),c=a.filter(e=>{let n=app.utils.isObject(e)&&i.find(n=>n.id==e.id);if(!n)return!1;for(let r in n)if(JSON.stringify(e[r])!=JSON.stringify(n[r]))return!0;return!1});return!!(s.length||c.length||r&&o.length)},extractColumnsFromQuery(e){let n=`__PBGROUP__`;e=(e||``).replace(/\([\s\S]+?\)/gm,n).replace(/[\t\r\n]|(?:\s\s)+/g,` `);let r=e.match(/select\s+([\s\S]+)\s+from/)?.[1]?.split(`,`)||[],i=[];for(let e of r){let r=e.trim().split(` `).pop();r!=``&&r!=n&&i.push(r.replace(/[\'\"\`\[\]\s]/g,``))}return i},getAllCollectionIdentifiers(e,n=``){if(!e)return[];let r=[n+`id`],i=e.type==`auth`;if(e.type===`view`)for(let i of app.utils.extractColumnsFromQuery(e.viewQuery))app.utils.pushUnique(r,n+i);let a=e.fields||[];for(let e of a)if(!(e.type==`password`||i&&e.name==`tokenKey`))if(app.fieldTypes[e.type]?.identifierExtractor){let i=app.utils.toArray(app.fieldTypes[e.type]?.identifierExtractor(e,n));for(let e of i)app.utils.pushUnique(r,e)}else app.utils.pushUnique(r,n+e.name);return r},getDummyFieldsData(e,n=!1){let r=e?.fields||[],i={};for(let e of r)if(!e.hidden)if(app.fieldTypes[e.type]?.dummyData){let r=app.fieldTypes[e.type].dummyData(e,n);r!==void 0&&(i[e.name]=r)}else i[e.name]=`[[DATA]]`;return i},parseIndex(e){let n={unique:!1,optional:!1,schemaName:``,indexName:``,tableName:``,columns:[],where:``},r=/create\s+(unique\s+)?\s*index\s*(if\s+not\s+exists\s+)?(\S*)\s+on\s+(\S*)\s*\(([\s\S]*)\)(?:\s*where\s+([\s\S]*))?/gim.exec((e||``).trim());if(r?.length!=7)return n;let i=/^[\"\'\`\[\{}]|[\"\'\`\]\}]$/gm;n.unique=r[1]?.trim().toLowerCase()===`unique`,n.optional=!app.utils.isEmpty(r[2]?.trim());let a=(r[3]||``).split(`.`);a.length==2?(n.schemaName=a[0].replace(i,``),n.indexName=a[1].replace(i,``)):(n.schemaName=``,n.indexName=a[0].replace(i,``)),n.tableName=(r[4]||``).replace(i,``);let o=(r[5]||``).replace(/,(?=[^\(]*\))/gim,`{PB_TEMP}`).split(`,`);for(let e of o){e=e.trim().replaceAll(`{PB_TEMP}`,`,`);let r=/^([\s\S]+?)(?:\s+collate\s+([\w]+))?(?:\s+(asc|desc))?$/gim.exec(e);if(r?.length!=4)continue;let a=r[1]?.trim()?.replace(i,``);a&&n.columns.push({name:a,collate:r[2]||``,sort:r[3]?.toUpperCase()||``})}return n.where=r[6]||``,n},buildIndex(e){let n=`CREATE `;e.unique&&(n+=`UNIQUE `),n+=`INDEX `,e.optional&&(n+=`IF NOT EXISTS `),e.schemaName&&(n+=`\`${e.schemaName}\`.`),n+=`\`${e.indexName||`idx_`+app.utils.randomString(10)}\` `,n+=`ON \`${e.tableName}\` (`;let r=e.columns.filter(e=>!!e?.name);return r.length>1&&(n+=` +`),i=new Blob([r],{type:`text/csv;charset=utf-8;`}),a=window.URL.createObjectURL(i);f.download(a,n)},getApiExampleURL(){let e;if(app.pb.baseURL.startsWith(`http://`)||app.pb.baseURL.startsWith(`https://`))e=app.pb.baseURL;else{e=window.location.href;let n=e.indexOf(`/_/`);e=n>=0?e.substring(0,n):window.location.origin}return e.replace(`//localhost`,`//127.0.0.1`)},isActivePath(e,n=!0,r=``){r||=d.hash;let i;return i=RegExp(n?`^`+RegExp.escape(e)+`\\/?.*$`:`^`+RegExp.escape(e)+`\\/?(?:\\?.+)?$`),i.test(r)},getHashQueryParams(e=``){e||=d.hash;let n=``,r=e.indexOf(`?`);return r>-1&&(n=window.location.hash.substring(r+1)),Object.fromEntries(new URLSearchParams(n))},replaceHashQueryParams(e,n=null){e||={};let r=``,i=window.location.hash,a=i.indexOf(`?`);a>-1&&(r=i.substring(a+1),i=i.substring(0,a));let o=new URLSearchParams(r);for(let n in e){let r=e[n];f.isEmpty(r)?o.delete(n):o.set(n,r)}r=o.toString(),r!=``&&(i+=`?`+r);let s=window.location.href,c=s.indexOf(`#`);c>-1&&(s=s.substring(0,c));let l=s+i;return n===!1||(n===!0?window.history.pushState(null,``,l):window.history.replaceState(null,``,l)),l},getLocalHistory(e,n=null){try{let r=window.localStorage.getItem(e);if(r)return JSON.parse(r)||n}catch(n){console.log(`failed to load local history:`,e,n)}return n},saveLocalHistory(e,n){try{app.utils.isEmpty(n)?window.localStorage.removeItem(e):typeof n==`string`?window.localStorage.setItem(e,n):window.localStorage.setItem(e,JSON.stringify(n))}catch(n){console.log(`failed to save local history:`,e,n)}},generateThumb(e,n=100,r=100){return new Promise(i=>{let a=new FileReader;a.onload=function(a){let o=new Image;o.onload=function(){let a=document.createElement(`canvas`),s=a.getContext(`2d`),c=o.width,l=o.height;return a.width=n,a.height=r,s.drawImage(o,c>l?(c-l)/2:0,0,c>l?l:c,c>l?l:c,0,0,n,r),i(a.toDataURL(e.type))},o.src=a.target.result},a.readAsDataURL(e)})},normalizeSearchFilter(e,n=[]){if(e=(e||``).trim(),!e||!n.length)return e;for(let n of[`=`,`!=`,`~`,`!~`,`>`,`>=`,`<`,`<=`])if(e.includes(n))return e;return e=isNaN(e)&&e!=`true`&&e!=`false`?`"${e.replace(/^[\"\'\`]|[\"\'\`]$/gm,``)}"`:e,n.map(n=>`${n}~${e}`).join(`||`)},logLevels:{[-4]:{label:`DEBUG`,class:``},0:{label:`INFO`,class:`success`},4:{label:`WARN`,class:`warning`},8:{label:`ERROR`,class:`danger`}},logDataFormatters:{execTime:function(e){return e?.data?.execTime===void 0?`N/A`:e.data.execTime+`ms`}},extendStore(e,n={},...r){let i=[];for(let a in n){let o=n[a];typeof e.__raw?.[a]==`function`||typeof o!=`function`||a.length>2&&a.startsWith(`on`)||r.includes(a)?e[a]=o:i.push(watch(o,n=>{e[a]=n}))}return i},cssTimeToMs(e){return e?(e=e.toLowerCase(),e.endsWith(`ms`)?Number(e.substring(0,e.length-2)):e.endsWith(`s`)?Number(e.substring(0,e.length-1)):Number(e)||0):0},isDarkEnoughForWhiteText(e){if(e=e?.startsWith(`#`)?e.substring(1):e,e?.length!=6)return!1;let n=parseInt(e.substring(0,2),16),r=parseInt(e.substring(2,4),16),i=parseInt(e.substring(4,6),16);return(n*299+r*587+i*114)/1e3<128},bulkSelectRange(e,n,r,i){let a=e.findIndex(e=>e.id==r.id);if(a==-1)return;let o=Object.keys(n),s=o[o.length-1],c=e.findIndex(e=>e.id==s);if(c==-1)return;let l=c,u=a;l>u&&([l,u]=[u,l]);for(let r=l;r<=u;r++)i?n[e[r].id]=e[r]:delete n[e[r].id]},imageExtensions:[`.jpg`,`.jpeg`,`.png`,`.svg`,`.gif`,`.jfif`,`.webp`,`.avif`],videoExtensions:[`.mp4`,`.avi`,`.mov`,`.3gp`,`.wmv`],audioExtensions:[`.aa`,`.aac`,`.m4v`,`.mp3`,`.ogg`,`.oga`,`.mogg`,`.amr`],documentExtensions:[`.pdf`,`.doc`,`.docx`,`.xls`,`.xlsx`,`.ppt`,`.pptx`,`.odp`,`.odt`,`.ods`,`.txt`],archiveExtensions:[`.zip`,`.gz`,`.tar`,`.rar`,`.7z`],hasExtension(e,n){return typeof n==`string`?(n=n.toLowerCase(),!!e?.find(e=>n.endsWith(e))):!1},hasImageExtension(e){return app.utils.hasExtension(app.utils.imageExtensions,e)},hasVideoExtension(e){return app.utils.hasExtension(app.utils.videoExtensions,e)},hasAudioExtension(e){return app.utils.hasExtension(app.utils.audioExtensions,e)},hasDocumentExtension(e){return app.utils.hasExtension(app.utils.documentExtensions,e)},hasArchiveExtension(e){return app.utils.hasExtension(app.utils.archiveExtensions,e)},getFileType(e){return app.utils.hasImageExtension(e)?`image`:app.utils.hasVideoExtension(e)?`video`:app.utils.hasAudioExtension(e)?`audio`:app.utils.hasDocumentExtension(e)?`document`:app.utils.hasArchiveExtension(e)?`archive`:`file`},fileTypeIcons:{image:`ri-image-line`,video:`ri-movie-line`,audio:`ri-music-2-line`,document:`ri-file-line`,archive:`ri-file-zip-line`,file:`ri-file-line`},fallbackFieldIcon:`ri-puzzle-line`,fallbackCollectionIcon:`ri-puzzle-line`,fallbackProviderIcon:`ri-puzzle-line`,fallbackPresentableProps:[`title`,`name`,`slug`,`email`,`username`,`nickname`,`displayName`,`label`,`subject`,`topic`,`message`,`heading`,`headline`,`header`,`caption`,`key`,`identifier`,`id`],sortedCollections(e=[]){let n,r;function i(e,i){return n=e.name.startsWith(`_`),r=i.name.startsWith(`_`),n&&!r?1:!n&&r?-1:e.name>i.name?1:e.namee?.id&&!a.find(n=>n.id==e.id)),s=a.filter(e=>e?.id&&!i.find(n=>n.id==e.id)),c=a.filter(e=>{let n=app.utils.isObject(e)&&i.find(n=>n.id==e.id);if(!n)return!1;for(let r in n)if(JSON.stringify(e[r])!=JSON.stringify(n[r]))return!0;return!1});return!!(s.length||c.length||r&&o.length)},extractColumnsFromQuery(e){let n=`__PBGROUP__`;e=(e||``).replace(/\([\s\S]+?\)/gm,n).replace(/[\t\r\n]|(?:\s\s)+/g,` `);let r=e.match(/select\s+([\s\S]+)\s+from/)?.[1]?.split(`,`)||[],i=[];for(let e of r){let r=e.trim().split(` `).pop();r!=``&&r!=n&&i.push(r.replace(/[\'\"\`\[\]\s]/g,``))}return i},getAllCollectionIdentifiers(e,n=``){if(!e)return[];let r=[n+`id`],i=e.type==`auth`;if(e.type===`view`)for(let i of app.utils.extractColumnsFromQuery(e.viewQuery))app.utils.pushUnique(r,n+i);let a=e.fields||[];for(let e of a)if(!(e.type==`password`||i&&e.name==`tokenKey`))if(app.fieldTypes[e.type]?.identifierExtractor){let i=app.utils.toArray(app.fieldTypes[e.type]?.identifierExtractor(e,n));for(let e of i)app.utils.pushUnique(r,e)}else app.utils.pushUnique(r,n+e.name);return r},getDummyFieldsData(e,n=!1){let r=e?.fields||[],i={};for(let e of r)if(!e.hidden)if(app.fieldTypes[e.type]?.dummyData){let r=app.fieldTypes[e.type].dummyData(e,n);r!==void 0&&(i[e.name]=r)}else i[e.name]=`[[DATA]]`;return i},parseIndex(e){let n={unique:!1,optional:!1,schemaName:``,indexName:``,tableName:``,columns:[],where:``},r=/create\s+(unique\s+)?\s*index\s*(if\s+not\s+exists\s+)?(\S*)\s+on\s+(\S*)\s*\(([\s\S]*)\)(?:\s*where\s+([\s\S]*))?/gim.exec((e||``).trim());if(r?.length!=7)return n;let i=/^[\"\'\`\[\{}]|[\"\'\`\]\}]$/gm;n.unique=r[1]?.trim().toLowerCase()===`unique`,n.optional=!app.utils.isEmpty(r[2]?.trim());let a=(r[3]||``).split(`.`);a.length==2?(n.schemaName=a[0].replace(i,``),n.indexName=a[1].replace(i,``)):(n.schemaName=``,n.indexName=a[0].replace(i,``)),n.tableName=(r[4]||``).replace(i,``);let o=(r[5]||``).replace(/,(?=[^\(]*\))/gim,`{PB_TEMP}`).split(`,`);for(let e of o){e=e.trim().replaceAll(`{PB_TEMP}`,`,`);let r=/^([\s\S]+?)(?:\s+collate\s+([\w]+))?(?:\s+(asc|desc))?$/gim.exec(e);if(r?.length!=4)continue;let a=r[1]?.trim()?.replace(i,``);a&&n.columns.push({name:a,collate:r[2]||``,sort:r[3]?.toUpperCase()||``})}return n.where=r[6]||``,n},buildIndex(e){let n=`CREATE `;e.unique&&(n+=`UNIQUE `),n+=`INDEX `,e.optional&&(n+=`IF NOT EXISTS `),e.schemaName&&(n+=`\`${e.schemaName}\`.`),n+=`\`${e.indexName||`idx_`+app.utils.randomString(10)}\` `,n+=`ON \`${e.tableName}\` (`;let r=e.columns.filter(e=>!!e?.name);return r.length>1&&(n+=` `),n+=r.map(e=>{let n=``;return e.name.includes(`(`)||e.name.includes(` `)?n+=e.name:n+="`"+e.name+"`",e.collate&&(n+=` COLLATE `+e.collate),e.sort&&(n+=` `+e.sort.toUpperCase()),n}).join(`, `),r.length>1&&(n+=` `),n+=`)`,e.where&&(n+=` WHERE ${e.where}`),n},replaceIndexFields(e,n){let r=app.utils.parseIndex(e);return typeof n==`function`?Object.assign(r,n(r)||{}):Object.assign(r,n||{}),app.utils.buildIndex(r)},replaceIndexColumn(e,n,r){if(n===r)return e;let i=app.utils.parseIndex(e),a=!1;for(let e of i.columns)e.name===n&&(e.name=r,a=!0);return a?app.utils.buildIndex(i):e}};window.app=window.app||{},window.app.utils=f,window.app=window.app||{},window.app.utils=window.app.utils||{},window.app.utils.mimeTypes=[{ext:``,mimeType:`application/octet-stream`},{ext:`.xpm`,mimeType:`image/x-xpixmap`},{ext:`.7z`,mimeType:`application/x-7z-compressed`},{ext:`.zip`,mimeType:`application/zip`},{ext:`.xlsx`,mimeType:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`},{ext:`.docx`,mimeType:`application/vnd.openxmlformats-officedocument.wordprocessingml.document`},{ext:`.pptx`,mimeType:`application/vnd.openxmlformats-officedocument.presentationml.presentation`},{ext:`.epub`,mimeType:`application/epub+zip`},{ext:`.apk`,mimeType:`application/vnd.android.package-archive`},{ext:`.jar`,mimeType:`application/jar`},{ext:`.odt`,mimeType:`application/vnd.oasis.opendocument.text`},{ext:`.ott`,mimeType:`application/vnd.oasis.opendocument.text-template`},{ext:`.ods`,mimeType:`application/vnd.oasis.opendocument.spreadsheet`},{ext:`.ots`,mimeType:`application/vnd.oasis.opendocument.spreadsheet-template`},{ext:`.odp`,mimeType:`application/vnd.oasis.opendocument.presentation`},{ext:`.otp`,mimeType:`application/vnd.oasis.opendocument.presentation-template`},{ext:`.odg`,mimeType:`application/vnd.oasis.opendocument.graphics`},{ext:`.otg`,mimeType:`application/vnd.oasis.opendocument.graphics-template`},{ext:`.odf`,mimeType:`application/vnd.oasis.opendocument.formula`},{ext:`.odc`,mimeType:`application/vnd.oasis.opendocument.chart`},{ext:`.sxc`,mimeType:`application/vnd.sun.xml.calc`},{ext:`.pdf`,mimeType:`application/pdf`},{ext:`.fdf`,mimeType:`application/vnd.fdf`},{ext:``,mimeType:`application/x-ole-storage`},{ext:`.msi`,mimeType:`application/x-ms-installer`},{ext:`.aaf`,mimeType:`application/octet-stream`},{ext:`.msg`,mimeType:`application/vnd.ms-outlook`},{ext:`.xls`,mimeType:`application/vnd.ms-excel`},{ext:`.pub`,mimeType:`application/vnd.ms-publisher`},{ext:`.ppt`,mimeType:`application/vnd.ms-powerpoint`},{ext:`.doc`,mimeType:`application/msword`},{ext:`.ps`,mimeType:`application/postscript`},{ext:`.psd`,mimeType:`image/vnd.adobe.photoshop`},{ext:`.p7s`,mimeType:`application/pkcs7-signature`},{ext:`.ogg`,mimeType:`application/ogg`},{ext:`.oga`,mimeType:`audio/ogg`},{ext:`.ogv`,mimeType:`video/ogg`},{ext:`.png`,mimeType:`image/png`},{ext:`.png`,mimeType:`image/vnd.mozilla.apng`},{ext:`.jpg`,mimeType:`image/jpeg`},{ext:`.jxl`,mimeType:`image/jxl`},{ext:`.jp2`,mimeType:`image/jp2`},{ext:`.jpf`,mimeType:`image/jpx`},{ext:`.jpm`,mimeType:`image/jpm`},{ext:`.jxs`,mimeType:`image/jxs`},{ext:`.gif`,mimeType:`image/gif`},{ext:`.webp`,mimeType:`image/webp`},{ext:`.exe`,mimeType:`application/vnd.microsoft.portable-executable`},{ext:``,mimeType:`application/x-elf`},{ext:``,mimeType:`application/x-object`},{ext:``,mimeType:`application/x-executable`},{ext:`.so`,mimeType:`application/x-sharedlib`},{ext:``,mimeType:`application/x-coredump`},{ext:`.a`,mimeType:`application/x-archive`},{ext:`.deb`,mimeType:`application/vnd.debian.binary-package`},{ext:`.tar`,mimeType:`application/x-tar`},{ext:`.xar`,mimeType:`application/x-xar`},{ext:`.bz2`,mimeType:`application/x-bzip2`},{ext:`.fits`,mimeType:`application/fits`},{ext:`.tiff`,mimeType:`image/tiff`},{ext:`.bmp`,mimeType:`image/bmp`},{ext:`.ico`,mimeType:`image/x-icon`},{ext:`.mp3`,mimeType:`audio/mpeg`},{ext:`.flac`,mimeType:`audio/flac`},{ext:`.midi`,mimeType:`audio/midi`},{ext:`.ape`,mimeType:`audio/ape`},{ext:`.mpc`,mimeType:`audio/musepack`},{ext:`.amr`,mimeType:`audio/amr`},{ext:`.wav`,mimeType:`audio/wav`},{ext:`.aiff`,mimeType:`audio/aiff`},{ext:`.au`,mimeType:`audio/basic`},{ext:`.mpeg`,mimeType:`video/mpeg`},{ext:`.mov`,mimeType:`video/quicktime`},{ext:`.mp4`,mimeType:`video/mp4`},{ext:`.avif`,mimeType:`image/avif`},{ext:`.3gp`,mimeType:`video/3gpp`},{ext:`.3g2`,mimeType:`video/3gpp2`},{ext:`.mp4`,mimeType:`audio/mp4`},{ext:`.mqv`,mimeType:`video/quicktime`},{ext:`.m4a`,mimeType:`audio/x-m4a`},{ext:`.m4v`,mimeType:`video/x-m4v`},{ext:`.heic`,mimeType:`image/heic`},{ext:`.heic`,mimeType:`image/heic-sequence`},{ext:`.heif`,mimeType:`image/heif`},{ext:`.heif`,mimeType:`image/heif-sequence`},{ext:`.mj2`,mimeType:`video/mj2`},{ext:`.dvb`,mimeType:`video/vnd.dvb.file`},{ext:`.webm`,mimeType:`video/webm`},{ext:`.avi`,mimeType:`video/x-msvideo`},{ext:`.flv`,mimeType:`video/x-flv`},{ext:`.mkv`,mimeType:`video/x-matroska`},{ext:`.asf`,mimeType:`video/x-ms-asf`},{ext:`.asf`,mimeType:`video/x-ms-wmv`},{ext:`.asf`,mimeType:`video/asf`},{ext:`.aac`,mimeType:`audio/aac`},{ext:`.voc`,mimeType:`audio/x-unknown`},{ext:`.m3u`,mimeType:`application/vnd.apple.mpegurl`},{ext:`.rmvb`,mimeType:`application/vnd.rn-realmedia-vbr`},{ext:`.gz`,mimeType:`application/gzip`},{ext:`.class`,mimeType:`application/x-java-applet`},{ext:`.swf`,mimeType:`application/x-shockwave-flash`},{ext:`.crx`,mimeType:`application/x-chrome-extension`},{ext:`.ttf`,mimeType:`font/ttf`},{ext:`.woff`,mimeType:`font/woff`},{ext:`.woff2`,mimeType:`font/woff2`},{ext:`.otf`,mimeType:`font/otf`},{ext:`.ttc`,mimeType:`font/collection`},{ext:`.eot`,mimeType:`application/vnd.ms-fontobject`},{ext:`.wasm`,mimeType:`application/wasm`},{ext:`.shx`,mimeType:`application/vnd.shx`},{ext:`.shp`,mimeType:`application/vnd.shp`},{ext:`.dbf`,mimeType:`application/x-dbf`},{ext:`.dcm`,mimeType:`application/dicom`},{ext:`.rar`,mimeType:`application/x-rar-compressed`},{ext:`.djvu`,mimeType:`image/vnd.djvu`},{ext:`.mobi`,mimeType:`application/x-mobipocket-ebook`},{ext:`.lit`,mimeType:`application/x-ms-reader`},{ext:`.bpg`,mimeType:`image/bpg`},{ext:`.cbor`,mimeType:`application/cbor`},{ext:`.sqlite`,mimeType:`application/vnd.sqlite3`},{ext:`.dwg`,mimeType:`image/vnd.dwg`},{ext:`.nes`,mimeType:`application/vnd.nintendo.snes.rom`},{ext:`.lnk`,mimeType:`application/x-ms-shortcut`},{ext:`.macho`,mimeType:`application/x-mach-binary`},{ext:`.qcp`,mimeType:`audio/qcelp`},{ext:`.icns`,mimeType:`image/x-icns`},{ext:`.hdr`,mimeType:`image/vnd.radiance`},{ext:`.mrc`,mimeType:`application/marc`},{ext:`.mdb`,mimeType:`application/x-msaccess`},{ext:`.accdb`,mimeType:`application/x-msaccess`},{ext:`.zst`,mimeType:`application/zstd`},{ext:`.cab`,mimeType:`application/vnd.ms-cab-compressed`},{ext:`.rpm`,mimeType:`application/x-rpm`},{ext:`.xz`,mimeType:`application/x-xz`},{ext:`.lz`,mimeType:`application/lzip`},{ext:`.torrent`,mimeType:`application/x-bittorrent`},{ext:`.cpio`,mimeType:`application/x-cpio`},{ext:``,mimeType:`application/tzif`},{ext:`.xcf`,mimeType:`image/x-xcf`},{ext:`.pat`,mimeType:`image/x-gimp-pat`},{ext:`.gbr`,mimeType:`image/x-gimp-gbr`},{ext:`.glb`,mimeType:`model/gltf-binary`},{ext:`.cab`,mimeType:`application/x-installshield`},{ext:`.jxr`,mimeType:`image/jxr`},{ext:`.parquet`,mimeType:`application/vnd.apache.parquet`},{ext:`.txt`,mimeType:`text/plain`},{ext:`.html`,mimeType:`text/html`},{ext:`.svg`,mimeType:`image/svg+xml`},{ext:`.xml`,mimeType:`text/xml`},{ext:`.rss`,mimeType:`application/rss+xml`},{ext:`.atom`,mimeType:`application/atom+xml`},{ext:`.x3d`,mimeType:`model/x3d+xml`},{ext:`.kml`,mimeType:`application/vnd.google-earth.kml+xml`},{ext:`.xlf`,mimeType:`application/x-xliff+xml`},{ext:`.dae`,mimeType:`model/vnd.collada+xml`},{ext:`.gml`,mimeType:`application/gml+xml`},{ext:`.gpx`,mimeType:`application/gpx+xml`},{ext:`.tcx`,mimeType:`application/vnd.garmin.tcx+xml`},{ext:`.amf`,mimeType:`application/x-amf`},{ext:`.3mf`,mimeType:`application/vnd.ms-package.3dmanufacturing-3dmodel+xml`},{ext:`.xfdf`,mimeType:`application/vnd.adobe.xfdf`},{ext:`.owl`,mimeType:`application/owl+xml`},{ext:`.php`,mimeType:`text/x-php`},{ext:`.js`,mimeType:`text/javascript`},{ext:`.lua`,mimeType:`text/x-lua`},{ext:`.pl`,mimeType:`text/x-perl`},{ext:`.py`,mimeType:`text/x-python`},{ext:`.json`,mimeType:`application/json`},{ext:`.geojson`,mimeType:`application/geo+json`},{ext:`.har`,mimeType:`application/json`},{ext:`.ndjson`,mimeType:`application/x-ndjson`},{ext:`.rtf`,mimeType:`text/rtf`},{ext:`.srt`,mimeType:`application/x-subrip`},{ext:`.tcl`,mimeType:`text/x-tcl`},{ext:`.csv`,mimeType:`text/csv`},{ext:`.tsv`,mimeType:`text/tab-separated-values`},{ext:`.vcf`,mimeType:`text/vcard`},{ext:`.ics`,mimeType:`text/calendar`},{ext:`.warc`,mimeType:`application/warc`},{ext:`.vtt`,mimeType:`text/vtt`},{ext:`.pbm`,mimeType:`image/x-portable-bitmap`},{ext:`.pgm`,mimeType:`image/x-portable-graymap`},{ext:`.ppm`,mimeType:`image/x-portable-pixmap`},{ext:`.eml`,mimeType:`message/rfc822`}];var p=new BroadcastChannel(`tabsSync`),m=`pbSettings`,h=`pbColorScheme`;window.app=window.app||{},window.app.store=store({_ready:!1,superuser:null,showHeader:!0,page:t.div({className:`page`},()=>{if(!app.store._ready)return t.span({className:`loader lg m-auto`,title:`Loading plugins...`})}),mainLogo:`./images/logo.svg`,headerLogo:`./images/logo_white.svg`,favicon:``,title:``,_mediaColorScheme:``,userColorScheme:window.localStorage.getItem(h)||``,get activeColorScheme(){return app.store.userColorScheme?app.store.userColorScheme:app.store._mediaColorScheme||`light`},errors:null,creditLinks:[{href:`https://pocketbase.io/docs`,icon:`ri-book-open-line`,label:`Docs`},{href:`https://github.com/pocketbase/pocketbase/releases`,icon:`ri-github-line`,label:`PocketBase v0.39.11-dev`}],headerLinks:[{href:`#/collections`,icon:`ri-database-2-line`,label:`Collections`},{href:`#/logs`,icon:`ri-bar-chart-box-line`,label:`Logs`},{href:`#/settings`,icon:`ri-settings-3-line`,label:`Settings`}],settingsNavGroups:{System:[{href:`#/settings`,icon:`ri-home-gear-line`,label:`Application`},{href:`#/settings/mail`,icon:`ri-send-plane-2-line`,label:`Mail settings`},{href:`#/settings/storage`,icon:`ri-archive-drawer-line`,label:`Files storage`},{href:`#/settings/backups`,icon:`ri-archive-line`,label:`Backups`},{href:`#/settings/crons`,icon:`ri-time-line`,label:`Crons`}],Sync:[{href:`#/settings/export-collections`,icon:`ri-uninstall-line`,label:`Export collections`},{href:`#/settings/import-collections`,icon:`ri-install-line`,label:`Import collections`}],Debug:[{href:`#/settings/sql`,icon:`ri-terminal-box-line`,label:`SQL console`}]},predefinedAccentColors:[`#1055c9`,`#a3142a`,`#096d5c`,`#e6620a`,`#007d9c`,`#3f3da9`],settings:app.utils.getLocalHistory(m,{}),isLoadingSettings:!1,async loadSettings(){app.store.isLoadingSettings=!0;try{let e=await app.pb.settings.getAll({requestKey:`appStore.loadSettings`});app.store.settings=e,app.store.isLoadingSettings=!1}catch(e){e.isAbort||(app.store.isLoadingSettings=!1,app.checkApiError(e))}},collections:[],collectionScaffolds:{},isLoadingCollections:!1,_activeCollectionIdOrName:``,get activeCollection(){let e=app.store._activeCollectionIdOrName;return app.store.collections.find(n=>n.id==e||n.name==e)||app.store.collections[0]},set activeCollection(e){typeof e==`string`?app.store._activeCollectionIdOrName=e:app.store._activeCollectionIdOrName=e?.id},async silentlyReloadCollections(){try{let e=await app.pb.collections.getFullList({requestKey:`appStore.silentlyReloadCollections`});e=app.utils.sortedCollectionsByType(e),JSON.stringify(e)!=JSON.stringify(app.store.collections)&&(app.store.collections=e)}catch(e){e.isAbort||console.warn(`failed to reload app store collections:`,e)}},async loadCollections(e=null){app.store.isLoadingCollections=!0;try{let[n,r]=await Promise.all([app.pb.collections.getScaffolds({requestKey:`appStore.loadCollections.getScaffolds`}),app.pb.collections.getFullList({requestKey:`appStore.loadCollections.getFullList`})]);r=app.utils.sortedCollectionsByType(r),JSON.stringify(app.store.collections)!=JSON.stringify(r)&&(app.store.collections=r),app.store.collectionScaffolds=n,app.store._activeCollectionIdOrName=e||app.store._activeCollectionIdOrName||app.store.collections[0]?.id||``,app.store.isLoadingCollections=!1}catch(e){e.isAbort||(app.store.isLoadingCollections=!1,app.checkApiError(e))}},addOrUpdateCollection(e){let n=app.store.collections.findIndex(n=>n.id==e.id);n>=0?(app.store.activeCollection?.id==e.id&&(app.store._activeCollectionIdOrName=e.id),app.store.collections[n]=e):app.store.collections.push(e),app.store.collections=app.utils.sortedCollectionsByType(app.store.collections)},oauth2Providers:[],isLoadingOAuth2Providers:!1,async loadOAuth2Providers(){app.store.isLoadingOAuth2Providers=!0;try{app.store.oauth2Providers=await app.pb.collections.getAllOAuth2Providers(),app.store.isLoadingOAuth2Providers=!1}catch(e){e.isAbort||(app.checkApiError(e),app.store.isLoadingOAuth2Providers=!1)}}}),window.addEventListener(`hashchange`,()=>{app.store.title=``,app.store.errors=null}),watch(()=>{let e=app.utils.toArray(app.store.title),n=app.store.settings?.meta?.appName||``;n&&e.push(n),document.title=e.join(` - `)});var g;watch(()=>app.store.settings?.meta?.accentColor,e=>{g||(g=t.meta({name:`theme-color`}),document.head.appendChild(g)),e?(g?.setAttribute(`content`,e),document.documentElement.style.setProperty(`--accentColor`,e)):(g?.removeAttribute(`content`),document.documentElement.style.removeProperty(`--accentColor`))});var _;watch(()=>app.store.favicon,e=>{_||(_=t.link({rel:`icon`}),document.head.appendChild(_)),e?_.href=e:_.href=window.location.href.startsWith(`https://`)?`./images/favicon_prod.png`:`./images/favicon.png`});var v=window.matchMedia(`(prefers-color-scheme: dark)`);app.store._mediaColorScheme=v.matches?`dark`:`light`,v.addEventListener(`change`,({matches:e})=>{app.store._mediaColorScheme=e?`dark`:`light`}),watch(()=>app.store.userColorScheme,e=>{e?window.localStorage.setItem(h,e):window.localStorage.removeItem(h),p?.postMessage({colorScheme:e})});var ee;watch(()=>app.store.activeColorScheme,e=>{clearTimeout(ee),document.documentElement.style.setProperty(`--animationSpeed`,`0`),document.documentElement.setAttribute(`data-color-scheme`,e),ee=setTimeout(()=>{document.documentElement.style.removeProperty(`--animationSpeed`)},100)});function te(e,n){e.__errListener&&=(e.removeEventListener(`input`,e.__errListener),e.removeEventListener(`change`,e.__errListener),null),e.setCustomValidity&&(e.setCustomValidity(``),e._oldTitle?e.setAttribute(`title`,e._oldTitle):e.removeAttribute(`title`)),e.removeAttribute(`data-error`);let r=n.nextSibling;r&&r.classList?.contains(`generated-error`)&&r.getAttribute(`data-input-name`)==e.getAttribute(`name`)&&r.remove(),n.querySelector(`[data-error]`)||n.classList.remove(`error`)}watch(()=>JSON.stringify(app.store.errors)&&app.store.errors,e=>{let n=document.querySelectorAll(`[name]`);for(let r of n){if(r.classList.contains(`no-error`))continue;let n=r.closest(`.field-list`)||r.closest(`.fields`)||r.closest(`.field`);if(!n)continue;let i=r.getAttribute(`name`);te(r,n);let a=app.utils.getByPath(e,i),o=a?.message||``;if(!o&&!app.utils.isEmpty(a)){let e=[];for(let n in a)a[n]?.message&&e.push(`${n}: ${a[n]?.message}`);o=e.join(` @@ -83,4 +83,4 @@ Records update will also require an extra unlock step before save.`)})))),t.div( @weekly @daily @midnight -@hourly`)},`macros`),`.`,t.br(),`By default the timezone is in UTC.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`backups.cronMaxKeep`},`Max @auto backups to keep`),t.input({id:`backups.cronMaxKeep`,name:`backups.cronMaxKeep`,type:`number`,required:()=>a.enableAutoBackups,min:1,value:()=>a.formSettings.backups.cronMaxKeep,oninput:e=>{a.formSettings.backups.cronMaxKeep=parseInt(e.target.value,10)}})))))),t.div({className:`col-lg-12`},app.components.s3ConfigFields({toggleLabel:`Store backups in S3 storage`,testFilesystem:`backups`,config:()=>a.formSettings.backups.s3})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!a.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:l},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${a.isSaving?`loading`:``}`,disabled:()=>!a.hasChanges||a.isSaving},t.span({className:`txt`},`Save changes`))))])))}function zi(e={oncreated:null}){let n=Bi(e);n&&(document.body.appendChild(n),app.modals.open(n))}function Bi(e){let n,r=`backup_create_`+app.utils.randomString(),i=store({name:``,isSubmitting:!1}),a;async function o(){if(!i.isSubmitting){i.isSubmitting=!0,clearTimeout(a),a=setTimeout(()=>{app.modals.close(n)},1500);try{await app.pb.backups.create(i.name,{requestKey:r}),i.isSubmitting=!1,e.oncreated&&e.oncreated(i.name),app.toasts.success(`Successfully generated new backup.`),app.modals.close(n)}catch(e){e.isAbort||(clearTimeout(a),i.isSubmitting=!1,app.checkApiError(e))}}}return n=t.div({pbEvent:`backupCreateModal`,className:`modal popup backup-create-modal`,onbeforeclose:()=>{i.isSubmitting&&app.toasts.info(`The backup was started but may take a while to complete. You can come back later.`)},onafterclose:e=>{clearTimeout(a),e?.remove()}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Initialize new backup`)),t.form({id:r,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Please note that during the backup other concurrent write requests may fail since the database will be temporary "locked" (this usually happens only during the ZIP generation).`),t.p({className:`txt-bold`},`If you are using S3 storage for the collections file upload, you'll have to backup them separately since they are not locally stored and they will not be included in the generated backup!`)))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`_name`},`Backup name`),t.input({id:r+`_name`,name:`name`,type:`text`,pattern:`^[a-z0-9_-]+.zip$`,placeholder:`Leave empty to autogenerate`,value:()=>i.name,oninput:e=>i.name=e.target.value})),t.div({className:`field-help`},`Must be in the format [a-z0-9_-].zip`)))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>i.isSubmitting,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Cancel`)),t.button({"html-form":r,type:`submit`,className:()=>`btn ${i.isSubmitting?`loading`:``}`,disabled:()=>i.isSubmitting},t.span({className:`txt`},`Start backup`)))),n}function Vi(e){let n=Hi(e);document.body.appendChild(n),app.modals.open(n)}function Hi(e){let n=`backup_restore_`+app.utils.randomString(),r=store({key:e,keyConfirm:``,isSubmitting:!1,get canSubmit(){return r.key&&r.key==r.keyConfirm}}),i;async function a(){if(!(r.isSubmitting||!r.canSubmit)){clearTimeout(i),r.isSubmitting=!0;try{await app.pb.backups.restore(r.keyConfirm),i=setTimeout(()=>{window.location.reload(),r.isSubmitting=!1},2e3)}catch(e){clearTimeout(i),e?.isAbort||(r.isSubmitting=!1,app.checkApiError(e))}}}return t.div({pbEvent:`backupRestoreModal`,className:`modal popup backup-restore-modal`,onbeforeclose:()=>!r.isSubmitting,onafterclose:e=>{e?.remove()},onunmount:()=>{clearTimeout(i)}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Restore `,t.strong(null,()=>r.key))),t.form({id:n,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert danger`},t.div({className:`content`},t.p({className:`txt-bold`},`Please proceed with extreme caution and use it only with trusted backups!`),t.p(null,`Backup restore currently works only on UNIX based systems.`),t.p(null,`The restore operation will attempt to replace your existing `,t.code(null,`pb_data`),` with the one from the backup and will restart the application process.`),t.p(null,`This means that on success all of your data (including app settings, users, superusers, etc.) will be replaced with the ones from the backup.`),t.p(null,`The operation will be reverted if the backup is invalid (ex. missing `,t.code(null,`data.db`),` file).`),t.p(null,`Below is an oversimplified version of the restore flow:`),t.ol(null,t.li(null,`Replaces the current `,t.code(null,`pb_data`),` with the content from the backup.`),t.li(null,`Triggers app restart.`),t.li(null,`Applies all migrations that are missing in the restored `,t.code(null,`pb_data`),`.`),t.li(null,`Initializes the app server as usual.`))))),t.div({className:`col-lg-12`},t.div({className:`confirm-key-label m-b-sm`},`Type the backup name `,t.div({className:`label`},()=>r.key,app.components.copyButton(()=>r.key)),` to confirm:`),t.div({className:`field`},t.label({htmlFor:n+`_key`},`Backup name`),t.input({id:n+`_key`,name:`key`,type:`text`,required:!0,value:()=>r.keyConfirm,oninput:e=>r.keyConfirm=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>r.isSubmitting},t.span({className:`txt`},`Cancel`)),t.button({"html-form":n,type:`submit`,className:()=>`btn ${r.isSubmitting?`loading`:``}`,disabled:()=>r.isSubmitting||!r.canSubmit},t.span({className:`txt`},`Restore backup`))))}function Ui(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({canBackup:!0,isLoading:!1,isDownloading:{},isDeleting:{},backups:[]});async function a(){i.isLoading=!0;try{i.backups=await app.pb.backups.getFullList(),i.backups.sort((e,n)=>e.modifiedn.modified?-1:0),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){app.modals.confirm(`Do you really want to delete ${e}?`,()=>s(e))}async function s(e){if(!i.isDeleting[e]){i.isDeleting[e]=!0;try{await app.pb.backups.delete(e),a(),app.toasts.success(`Successfully deleted ${e}.`)}catch(e){app.checkApiError(e)}delete i.isDeleting[e]}}async function c(){try{let e=await app.pb.health.check({requestKey:null}),n=i.canBackup;i.canBackup=e?.data?.canBackup||!1,i.canBackup&&n!=i.canBackup&&a()}catch(e){console.warn(`failed to load canBackup checks`,e)}}async function l(e){if(!i.isDownloading[e]){i.isDownloading[e]=!0;try{let n=await app.pb.files.getToken({requestKey:null});app.utils.download(app.pb.backups.getDownloadURL(n,e))}catch(e){app.checkApiError(e)}delete i.isDownloading[e]}}return t.div({pbEvent:`backupsList`,className:`list backups-list`,onmount:e=>{r.push(watch(()=>n.reset,()=>{a()})),e._canBackupIntervalId=setInterval(()=>{c()},3500)},onunmount:e=>{clearInterval(e._canBackupIntervalId),r.forEach(e=>e?.unwatch())}},t.div({className:`list-content`},t.div({hidden:()=>!i.isLoading||i.backups.length,className:`list-item`},t.div({className:`skeleton-loader`})),t.div({hidden:()=>i.isLoading||i.backups.length,className:()=>`list-item`},t.div({className:`content block txt-hint`},`No backups found.`)),()=>i.backups.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.i({className:`ri-folder-zip-line`,ariaHidden:!0}),t.div({className:`content`},t.span({className:`backup-name txt-ellipsis`,title:()=>e.key,textContent:()=>e.key}),t.small({className:`backup-size txt-hint txt-nowrap`},`(`,()=>app.utils.formattedFileSize(e.size),`)`)),t.nav({hidden:()=>i.isLoading,className:`actions autohide`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Download`),className:()=>`btn sm circle secondary transparent ${i.isDownloading[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>l(e.key)},t.i({className:`ri-download-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Restore`),className:()=>`btn sm circle secondary transparent`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>Vi(e.key)},t.i({className:`ri-restart-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Delete`),className:()=>`btn sm circle secondary transparent ${i.isDeleting[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>o(e.key)},t.i({className:`ri-delete-bin-7-line`,ariaHidden:!0})))))),t.div({className:`list-item`},t.button({type:`button`,className:()=>`btn secondary block ${i.isLoading?`loading`:``}`,disabled:()=>!i.canBackup||i.isLoading,onclick:()=>{zi({oncreated:()=>a()})}},()=>i.canBackup?[t.i({className:`ri-play-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Initialize new backup`)]:[t.span({className:`loader sm`}),t.span({className:`txt`},`Backup/restore operation is in process`)])))}function Wi(e=null){let n=`backup_upload_`+app.utils.randomString(),r=store({isUploading:!1});function i(e){e&&app.modals.confirm(`Note that we don't perform validations for the uploaded backup files. Proceed with extreme caution and only if you trust the source.\n\nDo you really want to upload "${e.name}"?`,()=>{a(e)},()=>{o()})}async function a(i){if(!(!i||r.isUploading)){r.isUploading=!0;try{let a=new FormData;a.set(`file`,i),await app.pb.backups.upload(a,{requestKey:n}),r.isUploading=!1,e(i),app.toasts.success(`Successfully uploaded a new backup.`)}catch(e){e.isAbort||(r.isUploading=!1,e.response?.formData?.file?.message?app.toasts.error(e.response.formData.file.message):app.checkApiError(e))}o()}}function o(){s&&(s.value=``)}let s=t.input({type:`file`,accept:`application/zip`,className:`hidden`,onchange:e=>{i(e.target?.files?.[0])}});return t.div(null,t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Upload backup`),className:()=>`btn sm transparent secondary circle ${r.isUploading?`loading`:``}`,disabled:()=>r.isUploading,onclick:()=>s?.click(),onunmount:()=>{app.pb.cancelRequest(n)}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0})),s)}function Gi(e){app.store.title=`Backups`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageBackupsSettings`,className:`page page-backups-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Backup and restore your PocketBase data`),app.components.refreshButton({className:`btn sm transparent secondary circle tooltip-bottom`,onclick:r}),Wi(r)),Ui({reset:()=>n.resetList})),t.div({className:`col-lg-12`},Ri({onsave:()=>r()})))),t.footer({className:`page-footer`},app.components.credits())))}function Ki(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({isLoading:!1,isRunning:{},crons:[]});async function a(){i.isLoading=!0;try{i.crons=await app.pb.crons.getFullList(),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){if(!(!e||i.isRunning[e])){i.isRunning[e]=!0;try{await app.pb.crons.run(e),app.toasts.success(`Successfully triggered "${e}".`),i.isRunning[e]=!1}catch(n){n.isAbort||(ApiClient.error(n),i.isRunning[e]=!1)}}}return t.div({pbEvent:`cronsList`,className:`list`,onmount:()=>{r.push(watch(()=>n.reset,()=>{a()}))},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!i.isLoading||i.crons.length)return;let e=[];for(let n=0;n<4;n++)e.push(t.div({rid:`skeleton_`+n,className:`list-item`},t.div({className:`skeleton-loader`})));return e},t.div({hidden:()=>i.isLoading||i.crons.length,className:`list-item`},t.div({className:`content block txt-hint`},`No registered crons found.`)),()=>i.crons.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.div({className:`content`},t.span({className:`cron-id txt-code txt-ellipsis`,title:()=>e.id,textContent:()=>e.id})),t.small({className:`cron-expression txt-hint txt-nowrap txt-code`},()=>e.expression),t.nav({hidden:()=>i.isLoading,className:`actions`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Run`),className:()=>`btn sm circle secondary transparent ${i.isRunning[e.id]?`loading`:``}`,disabled:()=>i.isRunning[e.id],onclick:()=>o(e.id)},t.i({className:`ri-play-large-line`,ariaHidden:!0}))))))}function qi(e){app.store.title=`Crons`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageCronsSettings`,className:`page`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Registered app cron jobs`),app.components.refreshButton({className:`btn sm transparent secondary circle`,onclick:r})),Ki({reset:()=>n.resetList}),t.div({className:`txt-sm txt-hint m-t-sm`},`App cron jobs can be registered only programmatically with `,t.a({href:`https://pocketbase.io/docs/go-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JavaScript`}),`.`)),t.footer({className:`page-footer`},app.components.credits())))}function Ji(e){app.store.title=`Mail settings`;let n=[{label:`Auto (StartTLS)`,value:!1},{label:`Always`,value:!0}],r=[{label:`PLAIN (default)`,value:`PLAIN`},{label:`LOGIN`,value:`LOGIN`}],i=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,showMoreOptions:!1,get hasChanges(){return i.initSerialized!=JSON.stringify(i.formSettings)}});a();async function a(){i.isLoading=!0;try{s(await app.pb.settings.getAll()),i.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function o(){if(!(i.isSaving||!i.hasChanges)){i.isSaving=!0;try{let e=app.utils.filterRedactedProps(i.formSettings);s(await app.pb.settings.update(e)),app.toasts.success(`Successfully saved mail settings.`)}catch(e){app.checkApiError(e)}i.isSaving=!1}}function s(e={}){app.store.settings=JSON.parse(JSON.stringify(e)),i.formSettings={meta:e?.meta||{},smtp:e?.smtp||{}},i.formSettings.smtp.authMethod||(i.formSettings.smtp.authMethod=r[0].value),i.initSerialized=JSON.stringify(i.formSettings)}function c(){i.formSettings=JSON.parse(i.initSerialized)}return t.div({pbEvent:`pageMailSettings`,className:`page page-mail-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`mailSettingsForm`,className:`grid mail-settings-form`,inert:()=>i.isSaving,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`Configure common settings for sending emails.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderName`},`Sender name`),t.input({id:`meta.senderName`,name:`meta.senderName`,type:`text`,required:!0,value:()=>i.formSettings.meta.senderName||``,oninput:e=>i.formSettings.meta.senderName=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderAddress`},`Sender address`),t.input({id:`meta.senderAddress`,name:`meta.senderAddress`,type:`email`,required:!0,value:()=>i.formSettings.meta.senderAddress||``,oninput:e=>i.formSettings.meta.senderAddress=e.target.value}))),t.div({className:`col-lg-12`},t.div({className:`field`},t.input({id:`smtp.enabled`,name:`smtp.enabled`,type:`checkbox`,className:`switch`,checked:()=>!!i.formSettings.smtp.enabled,onchange:e=>i.formSettings.smtp.enabled=e.target.checked}),t.label({htmlFor:`smtp.enabled`},t.span({className:`txt`},`Use SMTP mail server `,t.strong(null,`(recommended)`)),t.i({className:`ri-information-line link-faded`,ariaDescription:app.attrs.tooltip(`By default PocketBase uses the unix "sendmail" command for sending emails. For better emails deliverability it is recommended to use a SMTP mail server.`)}))),app.components.slide(()=>i.formSettings.smtp.enabled,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-4`},t.div({className:`field`},t.label({htmlFor:`smtp.host`},`SMTP server host`),t.input({id:`smtp.host`,name:`smtp.host`,type:`text`,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.host||``,oninput:e=>i.formSettings.smtp.host=e.target.value}))),t.div({className:`col-lg-2`},t.div({className:`field`},t.label({htmlFor:`smtp.port`},`Port`),t.input({id:`smtp.port`,name:`smtp.port`,type:`number`,min:0,step:1,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.port||``,oninput:e=>i.formSettings.smtp.port=parseInt(e.target.value,10)}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.username`},`Username`),t.input({id:`smtp.username`,name:`smtp.username`,type:`text`,autocomplete:`off`,value:()=>i.formSettings.smtp.username||``,oninput:e=>i.formSettings.smtp.username=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.password`},`Password`),t.input({id:`smtp.password`,name:`smtp.password`,type:`password`,autocomplete:`new-password`,value:()=>i.formSettings.smtp.password||``,oninput:e=>i.formSettings.smtp.password=e.target.value,onkeyup:e=>{e.key==`Backspace`&&i.formSettings.smtp.password===void 0&&(i.formSettings.smtp.password=``)},placeholder:()=>i.formSettings.smtp.password===void 0?`* * * * * *`:``})))),t.button({type:`button`,className:`btn secondary sm m-t-sm`,onclick:()=>i.showMoreOptions=!i.showMoreOptions},t.span({className:`txt`},()=>i.showMoreOptions?`Hide more options`:`Show more options`),t.i({className:()=>i.showMoreOptions?`ri-arrow-drop-up-line`:`ri-arrow-drop-down-line`})),app.components.slide(()=>i.showMoreOptions,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.tls`},`TLS encryption`),app.components.select({id:`smtp.tls`,name:`smtp.tls`,required:!0,options:n,value:()=>i.formSettings.smtp.tls||!1,onchange:e=>{i.formSettings.smtp.tls=e?.[0]?.value}}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.authMethod`},`AUTH method`),app.components.select({id:`smtp.authMethod`,name:`smtp.authMethod`,required:!0,options:r,value:()=>i.formSettings.smtp.authMethod||r[0].value,onchange:e=>{i.formSettings.smtp.authMethod=e?.[0]?.value}}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`smtp.localName`},t.span({className:`txt`},`EHLO/HELO domain`),t.i({className:`ri-information-line link-hint tooltip-top`,ariaDescription:app.attrs.tooltip(`Some SMTP servers, such as the Gmail SMTP-relay, requires a proper domain name in the inital EHLO/HELO exchange and will reject attempts to use localhost.`)})),t.input({id:`smtp.localName`,name:`smtp.localName`,type:`text`,placeholder:`Default to localhost`,value:()=>i.formSettings.smtp.localName||``,oninput:e=>i.formSettings.smtp.localName=e.target.value}))))))),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),()=>i.hasChanges?[t.button({type:`button`,className:`btn transparent secondary`,onclick:c},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${i.isSaving?`loading`:``}`,disabled:()=>!i.hasChanges||i.isSaving},t.span({className:`txt`},`Save changes`))]:t.button({type:`button`,className:()=>`btn expanded-lg outline`,onclick:()=>app.modals.openMailTest()},t.i({className:`ri-mail-check-line`,ariaHidden:!0}),t.span({className:`txt`},`Send test email`)))))),t.footer({className:`page-footer`},app.components.credits())))}var Yi=`pbSQLConsoleHistory`;function Xi(e){app.store.title=`SQL console`;let n=`sql_console_`+app.utils.randomString(),r=n+`editor`,i=n+`executeSQL`,a=store({askedForConfirmationAtLeastOnce:!1,isExecuting:!1,maxRows:250,query:``,result:{},sort:{},errorMsg:``,executedHistory:app.utils.getLocalHistory(Yi,[]),get sortedResultRows(){if(a.sort?.index===void 0){let e=a.result?.rows||[];return a.maxRows>=e.length?e:e.slice(0,a.maxRows)}let e=!!a.sort?.asc,n=a.result?.rows?.toSorted((n,r)=>{let i=n[a.sort.index],o=r[a.sort.index];return e||(i=r[a.sort.index],o=n[a.sort.index]),i==o?0:i==null?-1:o==null?1:i.localeCompare(o)})||[];return a.maxRows>=n.length?n:n.slice(0,a.maxRows)},get totalRemainingRows(){return(a.result?.rows?.length<<0)-a.sortedResultRows.length}});function o(e){return e?.trim()?!a.askedForConfirmationAtLeastOnce&&app.store.settings?.meta?.hideControls?!0:(e=e?.replace(/[\s\;]/gm,` `).toUpperCase()+` `,!![`ALTER `,`REPLACE `,`INSERT `,`CREATE `,`UPDATE `,`DELETE `,`DROP `,`DETACH `,`PRAGMA `].find(n=>e.includes(n))):!1}async function s(){return o(a.query)?(a.askedForConfirmationAtLeastOnce=!0,app.modals.confirm(t.div({className:`txt-center`},t.h6(null,`Be careful and continue only if you really know what you are doing because, depending on the query, the operation could break your application and may not be reversible.`)),()=>c(),null,{yesButton:`Execute`,noButton:`Cancel`})):c()}async function c(){a.isExecuting=!0,a.maxRows=250,a.result={},a.sort={},a.errorMsg=``;let e=a.query.trim();if(!e){app.pb.cancelRequest(i),a.isExecuting=!1;return}try{a.result=await app.pb.sql.run(e,{requestKey:i}),u(e),a.isExecuting=!1}catch(e){e?.isAbort||(a.isExecuting=!1,a.errorMsg=e?.response?.message||e?.message||`Failed to execute query.`)}}function l(e){function n(e){return e.replace(/[\s\;]/gm,``).toUpperCase()}let r=n(e);for(let i=a.executedHistory.length-1;i>=0;i--)(a.executedHistory[i]==e||n(a.executedHistory[i])==r)&&a.executedHistory.splice(i,1)}function u(e){l(e),a.executedHistory.unshift(a.query),a.executedHistory.length>10&&a.executedHistory.splice(10)}function d(){if(!a.sortedResultRows.length)return;let e=[a.result.columns.map(e=>e.name)].concat(a.sortedResultRows),n=`export_`+new Date().toISOString().replace(/[\-\:\.]/g,``)+`.csv`;app.utils.downloadCSV(e,n)}function f(e){a.sort?.index==e?a.sort={index:e,asc:!a.sort.asc}:a.sort={index:e,asc:!0}}let p=[watch(()=>JSON.stringify(a.executedHistory),(e,n)=>{n!==void 0&&window.localStorage.setItem(Yi,e)})];return t.div({pbEvent:`pageSQLConsole`,className:`page`,onunmount:()=>{app.pb.cancelRequest(i),p.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title)),t.div({className:`page-header-secondary-btns`},t.button({type:`button`,className:`btn circle transparent secondary`,ariaDescription:app.attrs.tooltip(`Recently executed queries`,`right`),"html-popovertarget":`sql-console-history-dropdown`},t.i({className:`ri-history-line`,ariaHidden:!0})),t.div({id:`sql-console-history-dropdown`,className:()=>`dropdown left sql-console-history-dropdown ${a.executedHistory.length?``:`no-items`}`,popover:`auto`},()=>a.executedHistory.length?a.executedHistory.map(e=>t.button({role:`button`,className:`dropdown-item`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),a.query=e,document.getElementById(r)?.click()}},t.span({className:`query`},()=>app.utils.truncate(e,500)),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),l(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.span({className:`txt txt-hint p-5`},`No recently executed queries.`))),t.div({className:`page-header-primary-btns`},t.button({type:`button`,className:()=>`btn expanded-lg ${a.isExecuting?`loading`:``}`,disabled:()=>a.isExecuting,onclick:()=>s()},t.i({className:`ri-play-large-line`,ariaHidden:!0}),t.span({className:`txt`},`Execute`)))),t.div({className:`field sql-console-field`},app.components.codeEditor({id:r,language:`sql`,required:!0,name:`query`,placeholder:`e.g. EXPLAIN QUERY PLAN SELECT * from users WHERE verified=true`,value:()=>a.query,oninput:e=>a.query=e,onblur:e=>a.query=e.trim()})),t.div({className:`flex field-help m-b-sm`},t.button({type:`button`,className:`link-hint m-l-auto`,"html-popovertarget":n+`caveats_dropdown`},()=>`SQL console caveats`),t.div({id:n+`caveats_dropdown`,className:`dropdown sm query-caveats-dropdown`,popover:`auto`},t.ul(null,t.li(null,`The returned rows are limited up to 1000.`),t.li(null,`The executed queries have a max timeout of 3 minutes.`),t.li(null,`The data is returned as byte strings without any additional formatting.`),t.li(null,`Multiple queries are supported but only the result of the last one is returned.`)))),t.div({hidden:()=>a.isExecuting||!a.errorMsg,className:`alert danger m-b-sm`},t.pre(null,()=>a.errorMsg)),t.div({hidden:()=>a.isExecuting||a.errorMsg||a.result?.columns?.length||app.utils.isEmpty(a.result),className:`alert success m-b-sm`},t.p({className:`txt-bold`},`Query executed successfully!`),()=>{if(a.result?.affectedRows)return t.p(null,`Affected rows: `,a.result?.affectedRows)}),t.div({hidden:()=>a.isExecuting||!a.result?.columns?.length,className:`page-table-wrapper`},t.table({className:`sql-console-table responsive-table optimize`},t.thead({className:`sticky`},t.tr(null,()=>a.result?.columns?.map((e,n)=>t.th({textContent:e.name,className:()=>{let e=`sort-handle`;return a.sort?.index==n&&(e+=a.sort.asc?` asc`:` desc`),e},onclick:()=>f(n)})))),t.tbody(null,()=>a.sortedResultRows.length?a.sortedResultRows.map(e=>t.tr(null,()=>a.result?.columns?.map((n,r)=>{let i=e[r];return t.td({"html-data-name":n.name},i==null?`NULL`:app.utils.truncate(i,2e3))}))):t.tr(null,t.td({colSpan:a.result?.columns?.length||1,className:`txt-center`},t.span({className:`txt-hint`},`No rows found.`))),t.tr({hidden:()=>a.isExecuting||!a.result?.rows?.length||a.result.rows.length<=a.sortedResultRows.length},t.td({colSpan:99},t.button({type:`button`,className:`btn lg secondary load-more-btn`,onclick:()=>{a.maxRows=a.result?.rows?.length||250}},t.span({className:`txt`,textContent:()=>`Load remaining (${a.totalRemainingRows})`}))))))),t.footer({className:`page-footer`},t.span({className:()=>`exec-time ${a.isExecuting?`faded`:``}`},`Time: `,()=>(a.result?.execTime||0)+`ms`),t.span({hidden:()=>!a.result?.columns?.length,className:()=>`total-count ${a.isExecuting?`faded`:``}`},`Rows: `,()=>a.result?.rows?.length||0,()=>{if(a.result?.rows?.length)return[` (`,t.span({role:`button`,className:`link-hint`,textContent:`Export as CSV`,onclick:d}),`)`]}),app.components.credits())))}function Zi(){app.store.title=`File storage`;let e=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,originalFormSettings:null,get hasChanges(){return e.initSerialized!=JSON.stringify(e.formSettings)}});n();async function n(){e.isLoading=!0;try{i(await app.pb.settings.getAll()),e.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function r(){if(!(e.isSaving||!e.hasChanges)){e.isSaving=!0;try{let n=app.utils.filterRedactedProps(e.formSettings);i(await app.pb.settings.update(n)),app.toasts.success(`Successfully saved storage settings.`)}catch(e){app.checkApiError(e)}e.isSaving=!1}}function i(n={}){app.store.settings=JSON.parse(JSON.stringify(n)),e.formSettings={s3:n?.s3||{}},e.initSerialized=JSON.stringify(e.formSettings),e.originalFormSettings=JSON.parse(e.initSerialized)}function a(){e.formSettings=JSON.parse(e.initSerialized)}return t.div({pbEvent:`pageStorageSettings`,className:`page page-storage-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>e.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`storageSettingsForm`,className:`grid storage-settings-form`,inert:()=>e.isSaving,onsubmit:e=>{e.preventDefault(),r()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`By default PocketBase uses and recommends the local file system to store uploaded files because it is more performant, easier to manage and backup.`),t.p(null,`Alternatively, if you have limited disk space available, you could opt to an S3 compatible external storage.`)),t.div({className:`col-lg-12`},app.components.s3ConfigFields({config:()=>e.formSettings.s3,before:()=>{let n=e.originalFormSettings.s3?.enabled;if(n!=e.formSettings.s3?.enabled)return t.div({className:`alert info m-t-sm`},`If you have existing uploaded files, you'll have to migrate them manually from the `,t.strong(null,n?`S3 storage`:`local file system`),` to the `,t.strong(null,e.formSettings.s3?.enabled?`S3 storage`:`local file system`),`.`,t.br(),`There are several command line tools that can help you, such as: `,t.a({href:`https://github.com/rclone/rclone`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`rclone`}),`, `,t.a({href:`https://github.com/peak/s5cmd`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`s5cmd`}),`, etc.`)}})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!e.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:a},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${e.isSaving?`loading`:``}`,disabled:()=>!e.hasChanges||e.isSaving},t.span({className:`txt`},`Save changes`)))))),t.footer({className:`page-footer`},app.components.credits())))}function Qi(e){app.store.title=`Export collections`;let n=`export_`+app.utils.randomString(),r=store({isLoading:!1,collections:[],bulkSelected:{},get bulkSelectStr(){return JSON.stringify(app.utils.sortedCollectionsByType(Object.values(r.bulkSelected)),null,2)},get totalSelected(){return Object.keys(r.bulkSelected).length},get areAllSelected(){return r.collections.length&&r.collections.length==r.totalSelected}});i();async function i(){r.isLoading=!0;try{let e=await app.pb.collections.getFullList({requestKey:n});for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;r.collections=app.utils.sortedCollectionsByType(e),c(),r.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoading=!1)}}function a(){let e=app.utils.sortedCollectionsByType(Object.values(r.bulkSelected));app.utils.downloadJSON(e,`pb_schema`)}function o(){r.areAllSelected?s():c()}function s(){r.bulkSelected={}}function c(){r.bulkSelected={};for(let e of r.collections)r.bulkSelected[e.id]=e}return t.div({pbEvent:`pageExportCollections`,className:`page page-export-collections`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>r.isLoading?t.div({className:`txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`txt-lg`},`Below you'll find your current collections configuration that you could import in another PocketBase environment.`)),t.div({className:`col-lg-12`},t.div({className:`export-panel`},t.aside({className:`export-list`},t.div({className:`list-item`},t.div({className:`field`},t.input({id:n+`.select_all`,type:`checkbox`,checked:()=>r.areAllSelected,onchange:()=>o()}),t.label({htmlFor:n+`.select_all`},`Select all`))),()=>r.collections.map(e=>{let i=n+`_c_`+e.id;return t.div({className:`list-item`},t.div({className:`field`},t.input({id:i,type:`checkbox`,checked:()=>!!r.bulkSelected[e.id],onchange:n=>{let i=Object.assign({},r.bulkSelected);n.target.__shiftKey&&(n.target.__shiftKey=!1,app.utils.bulkSelectRange(r.collections,i,e,n.target.checked)),n.target.checked?i[e.id]=e:delete i[e.id],r.bulkSelected=i}}),t.label({htmlFor:i,textContent:()=>e.name,onclick:e=>{e.preventDefault();let n=document.getElementById(e.target.htmlFor);n&&(n.__shiftKey=e.shiftKey,n.click())}})))})),t.output({className:`export-preview`},app.components.codeBlock({value:()=>r.bulkSelectStr,language:`plain`}),t.nav({className:`ctrls`},app.components.copyButton(()=>r.bulkSelectStr))))),t.div({className:`col-lg-12 txt-right`},t.button({className:`btn`,onclick:a},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download as JSON`))))),t.footer({className:`page-footer`},app.components.credits())))}function $i(e){app.store.title=`Import collections`;let n=`import_`+app.utils.randomString(),r=[],i=store({rawNewCollections:``,oldCollections:[],newCollections:[],collectionsToUpdate:[],deleteMissing:!0,isLoadingFile:!1,isLoadingOldCollections:!1,mergeWithOldCollections:!1,get isRawValid(){return!!i.rawNewCollections&&i.newCollections?.length>0&&i.newCollections.length==i.newCollections.filter(e=>!!e.id&&!!e.name).length},get collectionsToDelete(){return i.oldCollections.filter(e=>i.isRawValid&&!i.mergeWithOldCollections&&i.deleteMissing&&!i.newCollections.find(n=>n.id==e.id))},get collectionsToAdd(){return i.newCollections.filter(e=>i.isRawValid&&!i.oldCollections.find(n=>n.id==e.id))},get idReplacableCollections(){return i.newCollections.filter(e=>{let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)return!1;if(n.id!=e.id)return!0;let r=Array.isArray(n.fields)?n.fields:[],a=Array.isArray(e.fields)?e.fields:[];for(let e of a){if(r.find(n=>n.id==e.id))continue;let n=r.find(n=>n.name==e.name);if(n&&e.id!=n.id)return!0}return!1})},get hasChanges(){return!!i.rawNewCollections&&!!(i.collectionsToDelete.length||i.collectionsToAdd.length||i.collectionsToUpdate.length)},get canReview(){return!i.isLoadingOldCollections&&i.isRawValid&&i.hasChanges}}),a=t.input({id:n+`_load_json`,type:`file`,className:`hidden`,accept:`.json`,onchange:()=>{d(a.files?.[0])}});o();async function o(){i.isLoadingOldCollections=!0;try{let e=await app.pb.collections.getFullList();for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;i.oldCollections=e,i.isLoadingOldCollections=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoadingOldCollections=!1)}}r.push(watch(()=>i.rawNewCollections,()=>{s()}));function s(){let e=[];try{e=JSON.parse(i.rawNewCollections),e=Array.isArray(e)?app.utils.filterDuplicatesByKey(e):[];for(let n of e)delete n.created,delete n.updated,n.fields&&=app.utils.filterDuplicatesByKey(n.fields)}catch{}i.newCollections=e}r.push(watch(()=>[i.newCollections,i.deleteMissing],()=>{c()}));function c(){if(i.collectionsToUpdate=[],i.isRawValid)for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.id==e.id);!n?.id||!app.utils.hasCollectionChanges(n,e,i.deleteMissing)||i.collectionsToUpdate.push({new:e,old:n})}}function l(){for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)continue;let r=e.id,a=n.id;e.id=a;let o=Array.isArray(n.fields)?n.fields:[],s=Array.isArray(e.fields)?e.fields:[];for(let e of s){let n=o.find(n=>n.name==e.name);n&&n.id&&(e.id=n.id)}for(let e of i.newCollections)if(Array.isArray(e.fields))for(let n of e.fields)n.collectionId&&n.collectionId===r&&(n.collectionId=a);for(let n=0;ne.replace(r,a))}i.rawNewCollections=JSON.stringify(i.newCollections,null,2)}function u(){i.rawNewCollections=``,a.value=``,app.store.errors=null}function d(e){i.isLoadingFile=!0;let n=new FileReader;n.onload=async e=>{i.isLoadingFile=!1,a.value=``,i.rawNewCollections=e.target.result,await new Promise(e=>setTimeout(e,0)),i.newCollections.length||(app.toasts.error(`Invalid collections configuration.`),u())},n.onerror=e=>{app.toasts.error(`Failed to load the imported JSON.`),console.warn(e),i.isLoadingFile=!1,a.value=``},n.readAsText(e)}function f(){let e=i.mergeWithOldCollections?app.utils.filterDuplicatesByKey(i.oldCollections.concat(i.newCollections)):i.newCollections;app.modals.openImportCollectionsReview(i.oldCollections,e,{deleteMissing:i.deleteMissing,onsubmit:()=>{u(),o()}})}return t.div({pbEvent:`pageImportCollections`,className:`page page-import-collections`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoadingOldCollections?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.span({className:`txt-lg m-r-5`},`Paste below the collections configuration you want to import or`),t.label({htmlFor:a.id,className:()=>`btn sm outline ${i.isLoadingFile?`loading`:``}`},t.span({className:`txt`},`Load from JSON file`)),a,t.p({className:`txt-hint`},t.em(null,`You can use the `,t.a({href:`https://pocketbase.io/docs/go-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JS`}),` migrations to manage your collections programmatically in more granular and version controlled manner.`))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:n+`_collections_field`},`Collections`),t.textarea({id:n+`_collections_field`,name:`collections`,rows:12,className:`txt-code`,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,value:()=>i.rawNewCollections,oninput:e=>i.rawNewCollections=e.target.value})),t.div({className:()=>`field-help error ${i.rawNewCollections&&!i.isRawValid?``:`hidden`}`},`Invalid collections configuration.`)),t.div({className:()=>`col-lg-12 ${i.isRawValid?``:`hidden`}`},t.div({className:`field`},t.input({id:n+`_merge_checkbox`,type:`checkbox`,className:`switch`,checked:()=>i.mergeWithOldCollections,onchange:e=>i.mergeWithOldCollections=e.target.checked}),t.label({htmlFor:n+`_merge_checkbox`},`Merge with the existing collections`))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&!i.hasChanges?``:`hidden`}`},t.div({className:`alert info`},t.div({className:`content`},t.p(null,`Your collections configuration is already up-to-date!`)))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&i.hasChanges?``:`hidden`}`},t.p({className:`txt-hint txt-bold`},`Detected changes`),t.div({className:`list`},()=>i.collectionsToDelete.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))),()=>i.collectionsToUpdate.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(e.old.name!=e.new.name)return[t.span({className:`txt-strikethrough txt-hint`,textContent:e.old.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>e.new.name}),t.small({className:()=>`txt-hint ${e.new.id?``:`hidden`}`,textContent:()=>e.new.id})))),()=>i.collectionsToAdd.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label success`,textContent:`Added`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))))),t.div({className:()=>`col-lg-12 ${i.idReplacableCollections?.length?``:`hidden`}`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Some of the imported collections share the same name and/or fields but are imported with different IDs.`),t.p(null,`You can replace them in the import if you want to:`,t.button({type:`button`,className:`btn warning sm m-l-10`,textContent:`Replace with original IDs`,onclick:l}))))),t.div({className:`col-lg-12`},t.div({className:`flex`},t.button({type:`button`,className:()=>`btn secondary ${i.rawNewCollections?``:`hidden`}`,onclick:u},t.span({className:`txt`},`Clear`)),t.button({type:`button`,className:`btn expanded-lg m-l-auto`,disabled:()=>!i.canReview,onclick:f},t.span({className:`txt`},`Review`)))))),t.footer({className:`page-footer`},app.components.credits())))}window.app=window.app||{},window.app.routes=window.app.routes||{},window.app.routes.fallbackPath=`#/collections`,app.routes.guestOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(app.pb.authStore.isValid&&app.pb.authStore.record?.id){window.location.hash=`#/`;return}app.store.showHeader=!1,app.store.page=await n(e)}},app.routes.superuserOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(!app.pb.authStore.isValid||!app.pb.authStore.record?.id){window.location.hash=`#/login`;return}app.store.showHeader=!0,app.store.page=await n(e)}},app.routes.blank=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{app.store.showHeader=!1,app.store.page=await n(e)}};var ea={},ta;function na(){ta&&ta(),ta=router(ea,{fallbackPath:app.routes.fallbackPath})}app.routes.guestOnly(`#/pbinstall/{token}`,async e=>{let{pageInstaller:n}=await G(async()=>{let{pageInstaller:e}=await import(`./pageInstaller-BDYLSgKa.js`);return{pageInstaller:e}},[],import.meta.url);return n(e)}),app.routes.guestOnly(`#/login`,e=>$r(e)),app.routes.guestOnly(`#/request-password-reset`,async e=>{let{pageRequestSuperuserPasswordReset:n}=await G(async()=>{let{pageRequestSuperuserPasswordReset:e}=await import(`./pageRequestSuperuserPasswordReset-C39AMhGf.js`);return{pageRequestSuperuserPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-password-reset/{token}`,async e=>{let{pageConfirmPasswordReset:n}=await G(async()=>{let{pageConfirmPasswordReset:e}=await import(`./pageConfirmPasswordReset-CG0h2Q6K.js`);return{pageConfirmPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-verification/{token}`,async e=>{let{pageConfirmVerification:n}=await G(async()=>{let{pageConfirmVerification:e}=await import(`./pageConfirmVerification-C5mNs2GJ.js`);return{pageConfirmVerification:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-email-change/{token}`,async e=>{let{pageConfirmEmailChange:n}=await G(async()=>{let{pageConfirmEmailChange:e}=await import(`./pageConfirmEmailChange-BvW30fMG.js`);return{pageConfirmEmailChange:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-success`,async e=>{let{pageOAuth2RedirectSuccess:n}=await G(async()=>{let{pageOAuth2RedirectSuccess:e}=await import(`./pageOAuth2RedirectSuccess-DmZV1eyz.js`);return{pageOAuth2RedirectSuccess:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-failure`,async e=>{let{pageOAuth2RedirectFailure:n}=await G(async()=>{let{pageOAuth2RedirectFailure:e}=await import(`./pageOAuth2RedirectFailure-CRvz4PXa.js`);return{pageOAuth2RedirectFailure:e}},[],import.meta.url);return n(e)}),app.routes.superuserOnly(`#/collections`,hi),app.routes.superuserOnly(`#/logs`,Ei),app.routes.superuserOnly(`#/settings`,Ii),app.routes.superuserOnly(`#/settings/mail`,Ji),app.routes.superuserOnly(`#/settings/storage`,Zi),app.routes.superuserOnly(`#/settings/backups`,Gi),app.routes.superuserOnly(`#/settings/crons`,qi),app.routes.superuserOnly(`#/settings/export-collections`,Qi),app.routes.superuserOnly(`#/settings/import-collections`,$i),app.routes.superuserOnly(`#/settings/sql`,Xi);var ra=t;t=new Proxy({},{get(e,n){return function(){let e=arguments?.[0];if(e&&e.pbEvent){let n=e.onmount;e.onmount=r=>{n?.(r),r.dataset.pb=e.pbEvent,document.dispatchEvent(new CustomEvent(`mount:`+e.pbEvent,{detail:r}))};let r=e.onunmount;e.onunmount=n=>{document.dispatchEvent(new CustomEvent(`unmount:`+e.pbEvent,{detail:n})),r?.(n)}}return ra[n](...arguments)}}}),document.body.prepend(t.main({"html-class":`app`,className:()=>`app ${app.store.settings?.meta?.hideControls?`hide-controls`:``}`},Fe(),e=>(typeof app.store.page==`function`&&app.store.page(e),app.store.page))),watch(()=>app.store._ready,e=>{e&&na()}),document.body.appendChild(t.script({type:`module`,src:app.pb.buildURL(`/_/extensions.js`),onload:()=>{app.store._ready=!0},onerror:e=>{console.warn(`Failed to load extensions:`,e),app.store._ready=!0}}));export{S as n,se as r,Ee as t}; \ No newline at end of file +@hourly`)},`macros`),`.`,t.br(),`By default the timezone is in UTC.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`backups.cronMaxKeep`},`Max @auto backups to keep`),t.input({id:`backups.cronMaxKeep`,name:`backups.cronMaxKeep`,type:`number`,required:()=>a.enableAutoBackups,min:1,value:()=>a.formSettings.backups.cronMaxKeep,oninput:e=>{a.formSettings.backups.cronMaxKeep=parseInt(e.target.value,10)}})))))),t.div({className:`col-lg-12`},app.components.s3ConfigFields({toggleLabel:`Store backups in S3 storage`,testFilesystem:`backups`,config:()=>a.formSettings.backups.s3})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!a.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:l},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${a.isSaving?`loading`:``}`,disabled:()=>!a.hasChanges||a.isSaving},t.span({className:`txt`},`Save changes`))))])))}function zi(e={oncreated:null}){let n=Bi(e);n&&(document.body.appendChild(n),app.modals.open(n))}function Bi(e){let n,r=`backup_create_`+app.utils.randomString(),i=store({name:``,isSubmitting:!1}),a;async function o(){if(!i.isSubmitting){i.isSubmitting=!0,clearTimeout(a),a=setTimeout(()=>{app.modals.close(n)},1500);try{await app.pb.backups.create(i.name,{requestKey:r}),i.isSubmitting=!1,e.oncreated&&e.oncreated(i.name),app.toasts.success(`Successfully generated new backup.`),app.modals.close(n)}catch(e){e.isAbort||(clearTimeout(a),i.isSubmitting=!1,app.checkApiError(e))}}}return n=t.div({pbEvent:`backupCreateModal`,className:`modal popup backup-create-modal`,onbeforeclose:()=>{i.isSubmitting&&app.toasts.info(`The backup was started but may take a while to complete. You can come back later.`)},onafterclose:e=>{clearTimeout(a),e?.remove()}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Initialize new backup`)),t.form({id:r,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Please note that during the backup other concurrent write requests may fail since the database will be temporary "locked" (this usually happens only during the ZIP generation).`),t.p({className:`txt-bold`},`If you are using S3 storage for the collections file upload, you'll have to backup them separately since they are not locally stored and they will not be included in the generated backup!`)))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`_name`},`Backup name`),t.input({id:r+`_name`,name:`name`,type:`text`,pattern:`^[a-z0-9_-]+.zip$`,placeholder:`Leave empty to autogenerate`,value:()=>i.name,oninput:e=>i.name=e.target.value})),t.div({className:`field-help`},`Must be in the format [a-z0-9_-].zip`)))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>i.isSubmitting,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Cancel`)),t.button({"html-form":r,type:`submit`,className:()=>`btn ${i.isSubmitting?`loading`:``}`,disabled:()=>i.isSubmitting},t.span({className:`txt`},`Start backup`)))),n}function Vi(e){let n=Hi(e);document.body.appendChild(n),app.modals.open(n)}function Hi(e){let n=`backup_restore_`+app.utils.randomString(),r=store({key:e,keyConfirm:``,isSubmitting:!1,get canSubmit(){return r.key&&r.key==r.keyConfirm}}),i;async function a(){if(!(r.isSubmitting||!r.canSubmit)){clearTimeout(i),r.isSubmitting=!0;try{await app.pb.backups.restore(r.keyConfirm),i=setTimeout(()=>{window.location.reload(),r.isSubmitting=!1},2e3)}catch(e){clearTimeout(i),e?.isAbort||(r.isSubmitting=!1,app.checkApiError(e))}}}return t.div({pbEvent:`backupRestoreModal`,className:`modal popup backup-restore-modal`,onbeforeclose:()=>!r.isSubmitting,onafterclose:e=>{e?.remove()},onunmount:()=>{clearTimeout(i)}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Restore `,t.strong(null,()=>r.key))),t.form({id:n,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert danger`},t.div({className:`content`},t.p({className:`txt-bold`},`Please proceed with extreme caution and use it only with trusted backups!`),t.p(null,`Backup restore currently works only on UNIX based systems.`),t.p(null,`The restore operation will attempt to replace your existing `,t.code(null,`pb_data`),` with the one from the backup and will restart the application process.`),t.p(null,`This means that on success all of your data (including app settings, users, superusers, etc.) will be replaced with the ones from the backup.`),t.p(null,`The operation will be reverted if the backup is invalid (ex. missing `,t.code(null,`data.db`),` file).`),t.p(null,`Below is an oversimplified version of the restore flow:`),t.ol(null,t.li(null,`Replaces the current `,t.code(null,`pb_data`),` with the content from the backup.`),t.li(null,`Triggers app restart.`),t.li(null,`Applies all migrations that are missing in the restored `,t.code(null,`pb_data`),`.`),t.li(null,`Initializes the app server as usual.`))))),t.div({className:`col-lg-12`},t.div({className:`confirm-key-label m-b-sm`},`Type the backup name `,t.div({className:`label`},()=>r.key,app.components.copyButton(()=>r.key)),` to confirm:`),t.div({className:`field`},t.label({htmlFor:n+`_key`},`Backup name`),t.input({id:n+`_key`,name:`key`,type:`text`,required:!0,value:()=>r.keyConfirm,oninput:e=>r.keyConfirm=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>r.isSubmitting},t.span({className:`txt`},`Cancel`)),t.button({"html-form":n,type:`submit`,className:()=>`btn ${r.isSubmitting?`loading`:``}`,disabled:()=>r.isSubmitting||!r.canSubmit},t.span({className:`txt`},`Restore backup`))))}function Ui(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({canBackup:!0,isLoading:!1,isDownloading:{},isDeleting:{},backups:[]});async function a(){i.isLoading=!0;try{i.backups=await app.pb.backups.getFullList(),i.backups.sort((e,n)=>e.modifiedn.modified?-1:0),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){app.modals.confirm(`Do you really want to delete ${e}?`,()=>s(e))}async function s(e){if(!i.isDeleting[e]){i.isDeleting[e]=!0;try{await app.pb.backups.delete(e),a(),app.toasts.success(`Successfully deleted ${e}.`)}catch(e){app.checkApiError(e)}delete i.isDeleting[e]}}async function c(){try{let e=await app.pb.health.check({requestKey:null}),n=i.canBackup;i.canBackup=e?.data?.canBackup||!1,i.canBackup&&n!=i.canBackup&&a()}catch(e){console.warn(`failed to load canBackup checks`,e)}}async function l(e){if(!i.isDownloading[e]){i.isDownloading[e]=!0;try{let n=await app.pb.files.getToken({requestKey:null});app.utils.download(app.pb.backups.getDownloadURL(n,e))}catch(e){app.checkApiError(e)}delete i.isDownloading[e]}}return t.div({pbEvent:`backupsList`,className:`list backups-list`,onmount:e=>{r.push(watch(()=>n.reset,()=>{a()})),e._canBackupIntervalId=setInterval(()=>{c()},3500)},onunmount:e=>{clearInterval(e._canBackupIntervalId),r.forEach(e=>e?.unwatch())}},t.div({className:`list-content`},t.div({hidden:()=>!i.isLoading||i.backups.length,className:`list-item`},t.div({className:`skeleton-loader`})),t.div({hidden:()=>i.isLoading||i.backups.length,className:()=>`list-item`},t.div({className:`content block txt-hint`},`No backups found.`)),()=>i.backups.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.i({className:`ri-folder-zip-line`,ariaHidden:!0}),t.div({className:`content`},t.span({className:`backup-name txt-ellipsis`,title:()=>e.key,textContent:()=>e.key}),t.small({className:`backup-size txt-hint txt-nowrap`},`(`,()=>app.utils.formattedFileSize(e.size),`)`)),t.nav({hidden:()=>i.isLoading,className:`actions autohide`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Download`),className:()=>`btn sm circle secondary transparent ${i.isDownloading[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>l(e.key)},t.i({className:`ri-download-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Restore`),className:()=>`btn sm circle secondary transparent`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>Vi(e.key)},t.i({className:`ri-restart-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Delete`),className:()=>`btn sm circle secondary transparent ${i.isDeleting[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>o(e.key)},t.i({className:`ri-delete-bin-7-line`,ariaHidden:!0})))))),t.div({className:`list-item`},t.button({type:`button`,className:()=>`btn secondary block ${i.isLoading?`loading`:``}`,disabled:()=>!i.canBackup||i.isLoading,onclick:()=>{zi({oncreated:()=>a()})}},()=>i.canBackup?[t.i({className:`ri-play-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Initialize new backup`)]:[t.span({className:`loader sm`}),t.span({className:`txt`},`Backup/restore operation is in process`)])))}function Wi(e=null){let n=`backup_upload_`+app.utils.randomString(),r=store({isUploading:!1});function i(e){e&&app.modals.confirm(`Note that we don't perform validations for the uploaded backup files. Proceed with extreme caution and only if you trust the source.\n\nDo you really want to upload "${e.name}"?`,()=>{a(e)},()=>{o()})}async function a(i){if(!(!i||r.isUploading)){r.isUploading=!0;try{let a=new FormData;a.set(`file`,i),await app.pb.backups.upload(a,{requestKey:n}),r.isUploading=!1,e(i),app.toasts.success(`Successfully uploaded a new backup.`)}catch(e){e.isAbort||(r.isUploading=!1,e.response?.formData?.file?.message?app.toasts.error(e.response.formData.file.message):app.checkApiError(e))}o()}}function o(){s&&(s.value=``)}let s=t.input({type:`file`,accept:`application/zip`,className:`hidden`,onchange:e=>{i(e.target?.files?.[0])}});return t.div(null,t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Upload backup`),className:()=>`btn sm transparent secondary circle ${r.isUploading?`loading`:``}`,disabled:()=>r.isUploading,onclick:()=>s?.click(),onunmount:()=>{app.pb.cancelRequest(n)}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0})),s)}function Gi(e){app.store.title=`Backups`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageBackupsSettings`,className:`page page-backups-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Backup and restore your PocketBase data`),app.components.refreshButton({className:`btn sm transparent secondary circle tooltip-bottom`,onclick:r}),Wi(r)),Ui({reset:()=>n.resetList})),t.div({className:`col-lg-12`},Ri({onsave:()=>r()})))),t.footer({className:`page-footer`},app.components.credits())))}function Ki(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({isLoading:!1,isRunning:{},crons:[]});async function a(){i.isLoading=!0;try{i.crons=await app.pb.crons.getFullList(),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){if(!(!e||i.isRunning[e])){i.isRunning[e]=!0;try{await app.pb.crons.run(e),app.toasts.success(`Successfully triggered "${e}".`),i.isRunning[e]=!1}catch(n){n.isAbort||(ApiClient.error(n),i.isRunning[e]=!1)}}}return t.div({pbEvent:`cronsList`,className:`list`,onmount:()=>{r.push(watch(()=>n.reset,()=>{a()}))},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!i.isLoading||i.crons.length)return;let e=[];for(let n=0;n<4;n++)e.push(t.div({rid:`skeleton_`+n,className:`list-item`},t.div({className:`skeleton-loader`})));return e},t.div({hidden:()=>i.isLoading||i.crons.length,className:`list-item`},t.div({className:`content block txt-hint`},`No registered crons found.`)),()=>i.crons.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.div({className:`content`},t.span({className:`cron-id txt-code txt-ellipsis`,title:()=>e.id,textContent:()=>e.id})),t.small({className:`cron-expression txt-hint txt-nowrap txt-code`},()=>e.expression),t.nav({hidden:()=>i.isLoading,className:`actions`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Run`),className:()=>`btn sm circle secondary transparent ${i.isRunning[e.id]?`loading`:``}`,disabled:()=>i.isRunning[e.id],onclick:()=>o(e.id)},t.i({className:`ri-play-large-line`,ariaHidden:!0}))))))}function qi(e){app.store.title=`Crons`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageCronsSettings`,className:`page`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Registered app cron jobs`),app.components.refreshButton({className:`btn sm transparent secondary circle`,onclick:r})),Ki({reset:()=>n.resetList}),t.div({className:`txt-sm txt-hint m-t-sm`},`App cron jobs can be registered only programmatically with `,t.a({href:`https://pocketbase.io/docs/go-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JavaScript`}),`.`)),t.footer({className:`page-footer`},app.components.credits())))}function Ji(e){app.store.title=`Mail settings`;let n=[{label:`Auto (StartTLS)`,value:!1},{label:`Always`,value:!0}],r=[{label:`PLAIN (default)`,value:`PLAIN`},{label:`LOGIN`,value:`LOGIN`}],i=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,showMoreOptions:!1,get hasChanges(){return i.initSerialized!=JSON.stringify(i.formSettings)}});a();async function a(){i.isLoading=!0;try{s(await app.pb.settings.getAll()),i.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function o(){if(!(i.isSaving||!i.hasChanges)){i.isSaving=!0;try{let e=app.utils.filterRedactedProps(i.formSettings);s(await app.pb.settings.update(e)),app.toasts.success(`Successfully saved mail settings.`)}catch(e){app.checkApiError(e)}i.isSaving=!1}}function s(e={}){app.store.settings=JSON.parse(JSON.stringify(e)),i.formSettings={meta:e?.meta||{},smtp:e?.smtp||{}},i.formSettings.smtp.authMethod||(i.formSettings.smtp.authMethod=r[0].value),i.initSerialized=JSON.stringify(i.formSettings)}function c(){i.formSettings=JSON.parse(i.initSerialized)}return t.div({pbEvent:`pageMailSettings`,className:`page page-mail-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`mailSettingsForm`,className:`grid mail-settings-form`,inert:()=>i.isSaving,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`Configure common settings for sending emails.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderName`},`Sender name`),t.input({id:`meta.senderName`,name:`meta.senderName`,type:`text`,required:!0,value:()=>i.formSettings.meta.senderName||``,oninput:e=>i.formSettings.meta.senderName=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderAddress`},`Sender address`),t.input({id:`meta.senderAddress`,name:`meta.senderAddress`,type:`email`,required:!0,value:()=>i.formSettings.meta.senderAddress||``,oninput:e=>i.formSettings.meta.senderAddress=e.target.value}))),t.div({className:`col-lg-12`},t.div({className:`field`},t.input({id:`smtp.enabled`,name:`smtp.enabled`,type:`checkbox`,className:`switch`,checked:()=>!!i.formSettings.smtp.enabled,onchange:e=>i.formSettings.smtp.enabled=e.target.checked}),t.label({htmlFor:`smtp.enabled`},t.span({className:`txt`},`Use SMTP mail server `,t.strong(null,`(recommended)`)),t.i({className:`ri-information-line link-faded`,ariaDescription:app.attrs.tooltip(`By default PocketBase uses the unix "sendmail" command for sending emails. For better emails deliverability it is recommended to use a SMTP mail server.`)}))),app.components.slide(()=>i.formSettings.smtp.enabled,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-4`},t.div({className:`field`},t.label({htmlFor:`smtp.host`},`SMTP server host`),t.input({id:`smtp.host`,name:`smtp.host`,type:`text`,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.host||``,oninput:e=>i.formSettings.smtp.host=e.target.value}))),t.div({className:`col-lg-2`},t.div({className:`field`},t.label({htmlFor:`smtp.port`},`Port`),t.input({id:`smtp.port`,name:`smtp.port`,type:`number`,min:0,step:1,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.port||``,oninput:e=>i.formSettings.smtp.port=parseInt(e.target.value,10)}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.username`},`Username`),t.input({id:`smtp.username`,name:`smtp.username`,type:`text`,autocomplete:`off`,value:()=>i.formSettings.smtp.username||``,oninput:e=>i.formSettings.smtp.username=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.password`},`Password`),t.input({id:`smtp.password`,name:`smtp.password`,type:`password`,autocomplete:`new-password`,value:()=>i.formSettings.smtp.password||``,oninput:e=>i.formSettings.smtp.password=e.target.value,onkeyup:e=>{e.key==`Backspace`&&i.formSettings.smtp.password===void 0&&(i.formSettings.smtp.password=``)},placeholder:()=>i.formSettings.smtp.password===void 0?`* * * * * *`:``})))),t.button({type:`button`,className:`btn secondary sm m-t-sm`,onclick:()=>i.showMoreOptions=!i.showMoreOptions},t.span({className:`txt`},()=>i.showMoreOptions?`Hide more options`:`Show more options`),t.i({className:()=>i.showMoreOptions?`ri-arrow-drop-up-line`:`ri-arrow-drop-down-line`})),app.components.slide(()=>i.showMoreOptions,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.tls`},`TLS encryption`),app.components.select({id:`smtp.tls`,name:`smtp.tls`,required:!0,options:n,value:()=>i.formSettings.smtp.tls||!1,onchange:e=>{i.formSettings.smtp.tls=e?.[0]?.value}}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.authMethod`},`AUTH method`),app.components.select({id:`smtp.authMethod`,name:`smtp.authMethod`,required:!0,options:r,value:()=>i.formSettings.smtp.authMethod||r[0].value,onchange:e=>{i.formSettings.smtp.authMethod=e?.[0]?.value}}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`smtp.localName`},t.span({className:`txt`},`EHLO/HELO domain`),t.i({className:`ri-information-line link-hint tooltip-top`,ariaDescription:app.attrs.tooltip(`Some SMTP servers, such as the Gmail SMTP-relay, requires a proper domain name in the inital EHLO/HELO exchange and will reject attempts to use localhost.`)})),t.input({id:`smtp.localName`,name:`smtp.localName`,type:`text`,placeholder:`Default to localhost`,value:()=>i.formSettings.smtp.localName||``,oninput:e=>i.formSettings.smtp.localName=e.target.value}))))))),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),()=>i.hasChanges?[t.button({type:`button`,className:`btn transparent secondary`,onclick:c},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${i.isSaving?`loading`:``}`,disabled:()=>!i.hasChanges||i.isSaving},t.span({className:`txt`},`Save changes`))]:t.button({type:`button`,className:()=>`btn expanded-lg outline`,onclick:()=>app.modals.openMailTest()},t.i({className:`ri-mail-check-line`,ariaHidden:!0}),t.span({className:`txt`},`Send test email`)))))),t.footer({className:`page-footer`},app.components.credits())))}var Yi=`pbSQLConsoleHistory`;function Xi(e){app.store.title=`SQL console`;let n=`sql_console_`+app.utils.randomString(),r=n+`editor`,i=n+`executeSQL`,a=store({askedForConfirmationAtLeastOnce:!1,isExecuting:!1,maxRows:250,query:``,result:{},sort:{},errorMsg:``,executedHistory:app.utils.getLocalHistory(Yi,[]),get sortedResultRows(){if(a.sort?.index===void 0){let e=a.result?.rows||[];return a.maxRows>=e.length?e:e.slice(0,a.maxRows)}let e=!!a.sort?.asc,n=a.result?.rows?.toSorted((n,r)=>{let i=n[a.sort.index],o=r[a.sort.index];return e||(i=r[a.sort.index],o=n[a.sort.index]),i==o?0:i==null?-1:o==null?1:i.localeCompare(o)})||[];return a.maxRows>=n.length?n:n.slice(0,a.maxRows)},get totalRemainingRows(){return(a.result?.rows?.length<<0)-a.sortedResultRows.length}});function o(e){return e?.trim()?!a.askedForConfirmationAtLeastOnce&&app.store.settings?.meta?.hideControls?!0:(e=e?.replace(/[\s\;]/gm,` `).toUpperCase()+` `,!![`ALTER `,`REPLACE `,`INSERT `,`CREATE `,`UPDATE `,`DELETE `,`DROP `,`DETACH `,`PRAGMA `].find(n=>e.includes(n))):!1}async function s(){return o(a.query)?(a.askedForConfirmationAtLeastOnce=!0,app.modals.confirm(t.div({className:`txt-center`},t.h6(null,`Be careful and continue only if you really know what you are doing because, depending on the query, the operation could break your application and may not be reversible.`)),()=>c(),null,{yesButton:`Execute`,noButton:`Cancel`})):c()}async function c(){a.isExecuting=!0,a.maxRows=250,a.result={},a.sort={},a.errorMsg=``;let e=a.query.trim();if(!e){app.pb.cancelRequest(i),a.isExecuting=!1;return}try{a.result=await app.pb.sql.run(e,{requestKey:i}),u(e),a.isExecuting=!1}catch(e){e?.isAbort||(a.isExecuting=!1,a.errorMsg=e?.response?.message||e?.message||`Failed to execute query.`)}}function l(e){function n(e){return e.replace(/[\s\;]/gm,``).toUpperCase()}let r=n(e);for(let i=a.executedHistory.length-1;i>=0;i--)(a.executedHistory[i]==e||n(a.executedHistory[i])==r)&&a.executedHistory.splice(i,1)}function u(e){l(e),a.executedHistory.unshift(a.query),a.executedHistory.length>10&&a.executedHistory.splice(10)}function d(){if(!a.sortedResultRows.length)return;let e=[a.result.columns.map(e=>e.name)].concat(a.sortedResultRows),n=`export_`+new Date().toISOString().replace(/[\-\:\.]/g,``)+`.csv`;app.utils.downloadCSV(e,n)}function f(e){a.sort?.index==e?a.sort={index:e,asc:!a.sort.asc}:a.sort={index:e,asc:!0}}let p=[watch(()=>JSON.stringify(a.executedHistory),(e,n)=>{n!==void 0&&window.localStorage.setItem(Yi,e)})];return t.div({pbEvent:`pageSQLConsole`,className:`page`,onunmount:()=>{app.pb.cancelRequest(i),p.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title)),t.div({className:`page-header-secondary-btns`},t.button({type:`button`,className:`btn circle transparent secondary`,ariaDescription:app.attrs.tooltip(`Recently executed queries`,`right`),"html-popovertarget":`sql-console-history-dropdown`},t.i({className:`ri-history-line`,ariaHidden:!0})),t.div({id:`sql-console-history-dropdown`,className:()=>`dropdown left sql-console-history-dropdown ${a.executedHistory.length?``:`no-items`}`,popover:`auto`},()=>a.executedHistory.length?a.executedHistory.map(e=>t.button({role:`button`,className:`dropdown-item`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),a.query=e,document.getElementById(r)?.click()}},t.span({className:`query`},()=>app.utils.truncate(e,500)),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),l(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.span({className:`txt txt-hint p-5`},`No recently executed queries.`))),t.div({className:`page-header-primary-btns`},t.button({type:`button`,className:()=>`btn expanded-lg ${a.isExecuting?`loading`:``}`,disabled:()=>a.isExecuting,onclick:()=>s()},t.i({className:`ri-play-large-line`,ariaHidden:!0}),t.span({className:`txt`},`Execute`)))),t.div({className:`field sql-console-field`},app.components.codeEditor({id:r,language:`sql`,required:!0,name:`query`,placeholder:`e.g. EXPLAIN QUERY PLAN SELECT * from users WHERE verified=true`,value:()=>a.query,oninput:e=>a.query=e,onblur:e=>a.query=e.trim()})),t.div({className:`flex field-help m-b-sm`},t.button({type:`button`,className:`link-hint m-l-auto`,"html-popovertarget":n+`caveats_dropdown`},()=>`SQL console caveats`),t.div({id:n+`caveats_dropdown`,className:`dropdown sm query-caveats-dropdown`,popover:`auto`},t.ul(null,t.li(null,`The returned rows are limited up to 1000.`),t.li(null,`The executed queries have a max timeout of 3 minutes.`),t.li(null,`The data is returned as byte strings without any additional formatting.`),t.li(null,`Multiple queries are supported but only the result of the last one is returned.`)))),t.div({hidden:()=>a.isExecuting||!a.errorMsg,className:`alert danger m-b-sm`},t.pre(null,()=>a.errorMsg)),t.div({hidden:()=>a.isExecuting||a.errorMsg||a.result?.columns?.length||app.utils.isEmpty(a.result),className:`alert success m-b-sm`},t.p({className:`txt-bold`},`Query executed successfully!`),()=>{if(a.result?.affectedRows)return t.p(null,`Affected rows: `,a.result?.affectedRows)}),t.div({hidden:()=>a.isExecuting||!a.result?.columns?.length,className:`page-table-wrapper`},t.table({className:`sql-console-table responsive-table optimize`},t.thead({className:`sticky`},t.tr(null,()=>a.result?.columns?.map((e,n)=>t.th({textContent:e.name,className:()=>{let e=`sort-handle`;return a.sort?.index==n&&(e+=a.sort.asc?` asc`:` desc`),e},onclick:()=>f(n)})))),t.tbody(null,()=>a.sortedResultRows.length?a.sortedResultRows.map(e=>t.tr(null,()=>a.result?.columns?.map((n,r)=>{let i=e[r];return t.td({"html-data-name":n.name},i==null?`NULL`:app.utils.truncate(i,2e3))}))):t.tr(null,t.td({colSpan:a.result?.columns?.length||1,className:`txt-center`},t.span({className:`txt-hint`},`No rows found.`))),t.tr({hidden:()=>a.isExecuting||!a.result?.rows?.length||a.result.rows.length<=a.sortedResultRows.length},t.td({colSpan:99},t.button({type:`button`,className:`btn lg secondary load-more-btn`,onclick:()=>{a.maxRows=a.result?.rows?.length||250}},t.span({className:`txt`,textContent:()=>`Load remaining (${a.totalRemainingRows})`}))))))),t.footer({className:`page-footer`},t.span({className:()=>`exec-time ${a.isExecuting?`faded`:``}`},`Time: `,()=>(a.result?.execTime||0)+`ms`),t.span({hidden:()=>!a.result?.columns?.length,className:()=>`total-count ${a.isExecuting?`faded`:``}`},`Rows: `,()=>a.result?.rows?.length||0,()=>{if(a.result?.rows?.length)return[` (`,t.span({role:`button`,className:`link-hint`,textContent:`Export as CSV`,onclick:d}),`)`]}),app.components.credits())))}function Zi(){app.store.title=`File storage`;let e=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,originalFormSettings:null,get hasChanges(){return e.initSerialized!=JSON.stringify(e.formSettings)}});n();async function n(){e.isLoading=!0;try{i(await app.pb.settings.getAll()),e.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function r(){if(!(e.isSaving||!e.hasChanges)){e.isSaving=!0;try{let n=app.utils.filterRedactedProps(e.formSettings);i(await app.pb.settings.update(n)),app.toasts.success(`Successfully saved storage settings.`)}catch(e){app.checkApiError(e)}e.isSaving=!1}}function i(n={}){app.store.settings=JSON.parse(JSON.stringify(n)),e.formSettings={s3:n?.s3||{}},e.initSerialized=JSON.stringify(e.formSettings),e.originalFormSettings=JSON.parse(e.initSerialized)}function a(){e.formSettings=JSON.parse(e.initSerialized)}return t.div({pbEvent:`pageStorageSettings`,className:`page page-storage-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>e.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`storageSettingsForm`,className:`grid storage-settings-form`,inert:()=>e.isSaving,onsubmit:e=>{e.preventDefault(),r()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`By default PocketBase uses and recommends the local file system to store uploaded files because it is more performant, easier to manage and backup.`),t.p(null,`Alternatively, if you have limited disk space available, you could opt to an S3 compatible external storage.`)),t.div({className:`col-lg-12`},app.components.s3ConfigFields({config:()=>e.formSettings.s3,before:()=>{let n=e.originalFormSettings.s3?.enabled;if(n!=e.formSettings.s3?.enabled)return t.div({className:`alert info m-t-sm`},`If you have existing uploaded files, you'll have to migrate them manually from the `,t.strong(null,n?`S3 storage`:`local file system`),` to the `,t.strong(null,e.formSettings.s3?.enabled?`S3 storage`:`local file system`),`.`,t.br(),`There are several command line tools that can help you, such as: `,t.a({href:`https://github.com/rclone/rclone`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`rclone`}),`, `,t.a({href:`https://github.com/peak/s5cmd`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`s5cmd`}),`, etc.`)}})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!e.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:a},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${e.isSaving?`loading`:``}`,disabled:()=>!e.hasChanges||e.isSaving},t.span({className:`txt`},`Save changes`)))))),t.footer({className:`page-footer`},app.components.credits())))}function Qi(e){app.store.title=`Export collections`;let n=`export_`+app.utils.randomString(),r=store({isLoading:!1,collections:[],bulkSelected:{},get bulkSelectStr(){return JSON.stringify(app.utils.sortedCollectionsByType(Object.values(r.bulkSelected)),null,2)},get totalSelected(){return Object.keys(r.bulkSelected).length},get areAllSelected(){return r.collections.length&&r.collections.length==r.totalSelected}});i();async function i(){r.isLoading=!0;try{let e=await app.pb.collections.getFullList({requestKey:n});for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;r.collections=app.utils.sortedCollectionsByType(e),c(),r.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoading=!1)}}function a(){let e=app.utils.sortedCollectionsByType(Object.values(r.bulkSelected));app.utils.downloadJSON(e,`pb_schema`)}function o(){r.areAllSelected?s():c()}function s(){r.bulkSelected={}}function c(){r.bulkSelected={};for(let e of r.collections)r.bulkSelected[e.id]=e}return t.div({pbEvent:`pageExportCollections`,className:`page page-export-collections`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>r.isLoading?t.div({className:`txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`txt-lg`},`Below you'll find your current collections configuration that you could import in another PocketBase environment.`)),t.div({className:`col-lg-12`},t.div({className:`export-panel`},t.aside({className:`export-list`},t.div({className:`list-item`},t.div({className:`field`},t.input({id:n+`.select_all`,type:`checkbox`,checked:()=>r.areAllSelected,onchange:()=>o()}),t.label({htmlFor:n+`.select_all`},`Select all`))),()=>r.collections.map(e=>{let i=n+`_c_`+e.id;return t.div({className:`list-item`},t.div({className:`field`},t.input({id:i,type:`checkbox`,checked:()=>!!r.bulkSelected[e.id],onchange:n=>{let i=Object.assign({},r.bulkSelected);n.target.__shiftKey&&(n.target.__shiftKey=!1,app.utils.bulkSelectRange(r.collections,i,e,n.target.checked)),n.target.checked?i[e.id]=e:delete i[e.id],r.bulkSelected=i}}),t.label({htmlFor:i,textContent:()=>e.name,onclick:e=>{e.preventDefault();let n=document.getElementById(e.target.htmlFor);n&&(n.__shiftKey=e.shiftKey,n.click())}})))})),t.output({className:`export-preview`},app.components.codeBlock({value:()=>r.bulkSelectStr,language:`plain`}),t.nav({className:`ctrls`},app.components.copyButton(()=>r.bulkSelectStr))))),t.div({className:`col-lg-12 txt-right`},t.button({className:`btn`,onclick:a},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download as JSON`))))),t.footer({className:`page-footer`},app.components.credits())))}function $i(e){app.store.title=`Import collections`;let n=`import_`+app.utils.randomString(),r=[],i=store({rawNewCollections:``,oldCollections:[],newCollections:[],collectionsToUpdate:[],deleteMissing:!0,isLoadingFile:!1,isLoadingOldCollections:!1,mergeWithOldCollections:!1,get isRawValid(){return!!i.rawNewCollections&&i.newCollections?.length>0&&i.newCollections.length==i.newCollections.filter(e=>!!e.id&&!!e.name).length},get collectionsToDelete(){return i.oldCollections.filter(e=>i.isRawValid&&!i.mergeWithOldCollections&&i.deleteMissing&&!i.newCollections.find(n=>n.id==e.id))},get collectionsToAdd(){return i.newCollections.filter(e=>i.isRawValid&&!i.oldCollections.find(n=>n.id==e.id))},get idReplacableCollections(){return i.newCollections.filter(e=>{let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)return!1;if(n.id!=e.id)return!0;let r=Array.isArray(n.fields)?n.fields:[],a=Array.isArray(e.fields)?e.fields:[];for(let e of a){if(r.find(n=>n.id==e.id))continue;let n=r.find(n=>n.name==e.name);if(n&&e.id!=n.id)return!0}return!1})},get hasChanges(){return!!i.rawNewCollections&&!!(i.collectionsToDelete.length||i.collectionsToAdd.length||i.collectionsToUpdate.length)},get canReview(){return!i.isLoadingOldCollections&&i.isRawValid&&i.hasChanges}}),a=t.input({id:n+`_load_json`,type:`file`,className:`hidden`,accept:`.json`,onchange:()=>{d(a.files?.[0])}});o();async function o(){i.isLoadingOldCollections=!0;try{let e=await app.pb.collections.getFullList();for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;i.oldCollections=e,i.isLoadingOldCollections=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoadingOldCollections=!1)}}r.push(watch(()=>i.rawNewCollections,()=>{s()}));function s(){let e=[];try{e=JSON.parse(i.rawNewCollections),e=Array.isArray(e)?app.utils.filterDuplicatesByKey(e):[];for(let n of e)delete n.created,delete n.updated,n.fields&&=app.utils.filterDuplicatesByKey(n.fields)}catch{}i.newCollections=e}r.push(watch(()=>[i.newCollections,i.deleteMissing],()=>{c()}));function c(){if(i.collectionsToUpdate=[],i.isRawValid)for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.id==e.id);!n?.id||!app.utils.hasCollectionChanges(n,e,i.deleteMissing)||i.collectionsToUpdate.push({new:e,old:n})}}function l(){for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)continue;let r=e.id,a=n.id;e.id=a;let o=Array.isArray(n.fields)?n.fields:[],s=Array.isArray(e.fields)?e.fields:[];for(let e of s){let n=o.find(n=>n.name==e.name);n&&n.id&&(e.id=n.id)}for(let e of i.newCollections)if(Array.isArray(e.fields))for(let n of e.fields)n.collectionId&&n.collectionId===r&&(n.collectionId=a);for(let n=0;ne.replace(r,a))}i.rawNewCollections=JSON.stringify(i.newCollections,null,2)}function u(){i.rawNewCollections=``,a.value=``,app.store.errors=null}function d(e){i.isLoadingFile=!0;let n=new FileReader;n.onload=async e=>{i.isLoadingFile=!1,a.value=``,i.rawNewCollections=e.target.result,await new Promise(e=>setTimeout(e,0)),i.newCollections.length||(app.toasts.error(`Invalid collections configuration.`),u())},n.onerror=e=>{app.toasts.error(`Failed to load the imported JSON.`),console.warn(e),i.isLoadingFile=!1,a.value=``},n.readAsText(e)}function f(){let e=i.mergeWithOldCollections?app.utils.filterDuplicatesByKey(i.oldCollections.concat(i.newCollections)):i.newCollections;app.modals.openImportCollectionsReview(i.oldCollections,e,{deleteMissing:i.deleteMissing,onsubmit:()=>{u(),o()}})}return t.div({pbEvent:`pageImportCollections`,className:`page page-import-collections`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoadingOldCollections?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.span({className:`txt-lg m-r-5`},`Paste below the collections configuration you want to import or`),t.label({htmlFor:a.id,className:()=>`btn sm outline ${i.isLoadingFile?`loading`:``}`},t.span({className:`txt`},`Load from JSON file`)),a,t.p({className:`txt-hint`},t.em(null,`You can use the `,t.a({href:`https://pocketbase.io/docs/go-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JS`}),` migrations to manage your collections programmatically in more granular and version controlled manner.`))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:n+`_collections_field`},`Collections`),t.textarea({id:n+`_collections_field`,name:`collections`,rows:12,className:`txt-code`,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,value:()=>i.rawNewCollections,oninput:e=>i.rawNewCollections=e.target.value})),t.div({className:()=>`field-help error ${i.rawNewCollections&&!i.isRawValid?``:`hidden`}`},`Invalid collections configuration.`)),t.div({className:()=>`col-lg-12 ${i.isRawValid?``:`hidden`}`},t.div({className:`field`},t.input({id:n+`_merge_checkbox`,type:`checkbox`,className:`switch`,checked:()=>i.mergeWithOldCollections,onchange:e=>i.mergeWithOldCollections=e.target.checked}),t.label({htmlFor:n+`_merge_checkbox`},`Merge with the existing collections`))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&!i.hasChanges?``:`hidden`}`},t.div({className:`alert info`},t.div({className:`content`},t.p(null,`Your collections configuration is already up-to-date!`)))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&i.hasChanges?``:`hidden`}`},t.p({className:`txt-hint txt-bold`},`Detected changes`),t.div({className:`list`},()=>i.collectionsToDelete.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))),()=>i.collectionsToUpdate.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(e.old.name!=e.new.name)return[t.span({className:`txt-strikethrough txt-hint`,textContent:e.old.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>e.new.name}),t.small({className:()=>`txt-hint ${e.new.id?``:`hidden`}`,textContent:()=>e.new.id})))),()=>i.collectionsToAdd.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label success`,textContent:`Added`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))))),t.div({className:()=>`col-lg-12 ${i.idReplacableCollections?.length?``:`hidden`}`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Some of the imported collections share the same name and/or fields but are imported with different IDs.`),t.p(null,`You can replace them in the import if you want to:`,t.button({type:`button`,className:`btn warning sm m-l-10`,textContent:`Replace with original IDs`,onclick:l}))))),t.div({className:`col-lg-12`},t.div({className:`flex`},t.button({type:`button`,className:()=>`btn secondary ${i.rawNewCollections?``:`hidden`}`,onclick:u},t.span({className:`txt`},`Clear`)),t.button({type:`button`,className:`btn expanded-lg m-l-auto`,disabled:()=>!i.canReview,onclick:f},t.span({className:`txt`},`Review`)))))),t.footer({className:`page-footer`},app.components.credits())))}window.app=window.app||{},window.app.routes=window.app.routes||{},window.app.routes.fallbackPath=`#/collections`,app.routes.guestOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(app.pb.authStore.isValid&&app.pb.authStore.record?.id){window.location.hash=`#/`;return}app.store.showHeader=!1,app.store.page=await n(e)}},app.routes.superuserOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(!app.pb.authStore.isValid||!app.pb.authStore.record?.id){window.location.hash=`#/login`;return}app.store.showHeader=!0,app.store.page=await n(e)}},app.routes.blank=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{app.store.showHeader=!1,app.store.page=await n(e)}};var ea={},ta;function na(){ta&&ta(),ta=router(ea,{fallbackPath:app.routes.fallbackPath})}app.routes.guestOnly(`#/pbinstall/{token}`,async e=>{let{pageInstaller:n}=await G(async()=>{let{pageInstaller:e}=await import(`./pageInstaller-2TD7r9Pz.js`);return{pageInstaller:e}},[],import.meta.url);return n(e)}),app.routes.guestOnly(`#/login`,e=>$r(e)),app.routes.guestOnly(`#/request-password-reset`,async e=>{let{pageRequestSuperuserPasswordReset:n}=await G(async()=>{let{pageRequestSuperuserPasswordReset:e}=await import(`./pageRequestSuperuserPasswordReset-C39AMhGf.js`);return{pageRequestSuperuserPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-password-reset/{token}`,async e=>{let{pageConfirmPasswordReset:n}=await G(async()=>{let{pageConfirmPasswordReset:e}=await import(`./pageConfirmPasswordReset-UQX1jz2S.js`);return{pageConfirmPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-verification/{token}`,async e=>{let{pageConfirmVerification:n}=await G(async()=>{let{pageConfirmVerification:e}=await import(`./pageConfirmVerification-Bc6dMZfz.js`);return{pageConfirmVerification:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-email-change/{token}`,async e=>{let{pageConfirmEmailChange:n}=await G(async()=>{let{pageConfirmEmailChange:e}=await import(`./pageConfirmEmailChange-l_DOk6UT.js`);return{pageConfirmEmailChange:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-success`,async e=>{let{pageOAuth2RedirectSuccess:n}=await G(async()=>{let{pageOAuth2RedirectSuccess:e}=await import(`./pageOAuth2RedirectSuccess-DmZV1eyz.js`);return{pageOAuth2RedirectSuccess:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-failure`,async e=>{let{pageOAuth2RedirectFailure:n}=await G(async()=>{let{pageOAuth2RedirectFailure:e}=await import(`./pageOAuth2RedirectFailure-CRvz4PXa.js`);return{pageOAuth2RedirectFailure:e}},[],import.meta.url);return n(e)}),app.routes.superuserOnly(`#/collections`,hi),app.routes.superuserOnly(`#/logs`,Ei),app.routes.superuserOnly(`#/settings`,Ii),app.routes.superuserOnly(`#/settings/mail`,Ji),app.routes.superuserOnly(`#/settings/storage`,Zi),app.routes.superuserOnly(`#/settings/backups`,Gi),app.routes.superuserOnly(`#/settings/crons`,qi),app.routes.superuserOnly(`#/settings/export-collections`,Qi),app.routes.superuserOnly(`#/settings/import-collections`,$i),app.routes.superuserOnly(`#/settings/sql`,Xi);var ra=t;t=new Proxy({},{get(e,n){return function(){let e=arguments?.[0];if(e&&e.pbEvent){let n=e.onmount;e.onmount=r=>{n?.(r),r.dataset.pb=e.pbEvent,document.dispatchEvent(new CustomEvent(`mount:`+e.pbEvent,{detail:r}))};let r=e.onunmount;e.onunmount=n=>{document.dispatchEvent(new CustomEvent(`unmount:`+e.pbEvent,{detail:n})),r?.(n)}}return ra[n](...arguments)}}}),document.body.prepend(t.main({"html-class":`app`,className:()=>`app ${app.store.settings?.meta?.hideControls?`hide-controls`:``}`},Fe(),e=>(typeof app.store.page==`function`&&app.store.page(e),app.store.page))),watch(()=>app.store._ready,e=>{e&&na()}),document.body.appendChild(t.script({type:`module`,src:app.pb.buildURL(`/_/extensions.js`),onload:()=>{app.store._ready=!0},onerror:e=>{console.warn(`Failed to load extensions:`,e),app.store._ready=!0}}));export{S as n,se as r,Ee as t}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmEmailChange-BvW30fMG.js b/ui/dist/assets/pageConfirmEmailChange-l_DOk6UT.js similarity index 97% rename from ui/dist/assets/pageConfirmEmailChange-BvW30fMG.js rename to ui/dist/assets/pageConfirmEmailChange-l_DOk6UT.js index 811598ed76..21b9218523 100644 --- a/ui/dist/assets/pageConfirmEmailChange-BvW30fMG.js +++ b/ui/dist/assets/pageConfirmEmailChange-l_DOk6UT.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-CQVsfOm8.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.newEmail||!a.collectionId){app.toasts.error(`Invalid or expired email change token.`),window.location.hash=`#/`;return}app.store.title=`Confirm email change`;let o=store({password:``,isSubmitting:!1,isSuccess:!1,showPassword:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmEmailChange(i,o.password),o.isSuccess=!0}catch(e){app.checkApiError(e),o.isSuccess=!1}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmEmailChange`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmEmailChangeAlert`,className:`alert success txt-center`},t.p(null,`The email was successfully changed.`),t.p(null,`You can go back and sign in with your new email address.`)):t.form({pbEvent:`confirmEmailChangeForm`,className:`grid confirm-email-change-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your password to confirm changing your email address to `,t.strong(null,a.newEmail),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`password_confirm`},`Password`),t.input({id:`password_confirm`,name:`password`,required:!0,autofocus:!0,type:()=>o.showPassword?`text`:`password`,value:()=>o.password,oninput:e=>o.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showPassword?`Hide password`:`Show password`),onclick:()=>o.showPassword=!o.showPassword},t.i({className:()=>o.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Confirm new email`)))))}export{r as pageConfirmEmailChange}; \ No newline at end of file +import{n as e,t as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.newEmail||!a.collectionId){app.toasts.error(`Invalid or expired email change token.`),window.location.hash=`#/`;return}app.store.title=`Confirm email change`;let o=store({password:``,isSubmitting:!1,isSuccess:!1,showPassword:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmEmailChange(i,o.password),o.isSuccess=!0}catch(e){app.checkApiError(e),o.isSuccess=!1}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmEmailChange`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmEmailChangeAlert`,className:`alert success txt-center`},t.p(null,`The email was successfully changed.`),t.p(null,`You can go back and sign in with your new email address.`)):t.form({pbEvent:`confirmEmailChangeForm`,className:`grid confirm-email-change-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your password to confirm changing your email address to `,t.strong(null,a.newEmail),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`password_confirm`},`Password`),t.input({id:`password_confirm`,name:`password`,required:!0,autofocus:!0,type:()=>o.showPassword?`text`:`password`,value:()=>o.password,oninput:e=>o.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showPassword?`Hide password`:`Show password`),onclick:()=>o.showPassword=!o.showPassword},t.i({className:()=>o.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Confirm new email`)))))}export{r as pageConfirmEmailChange}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmPasswordReset-CG0h2Q6K.js b/ui/dist/assets/pageConfirmPasswordReset-UQX1jz2S.js similarity index 97% rename from ui/dist/assets/pageConfirmPasswordReset-CG0h2Q6K.js rename to ui/dist/assets/pageConfirmPasswordReset-UQX1jz2S.js index 34ba5190d2..61719216b6 100644 --- a/ui/dist/assets/pageConfirmPasswordReset-CG0h2Q6K.js +++ b/ui/dist/assets/pageConfirmPasswordReset-UQX1jz2S.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-CQVsfOm8.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired password reset token.`),window.location.hash=`#/`;return}app.store.title=`Confirm password reset`;let o=store({newPassword:``,newPasswordConfirm:``,showNewPassword:!1,showNewPasswordConfirm:!1,isSubmitting:!1,isSuccess:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmPasswordReset(i,o.newPassword,o.newPasswordConfirm),o.isSuccess=!0}catch(e){app.checkApiError(e)}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmPasswordReset`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmPasswordResetAlert`,className:`alert success txt-center`},t.p(null,`The password was successfully changed.`),t.p(null,`You can go back to sign in with your new password.`)):t.form({pbEvent:`confirmPasswordResetForm`,className:`grid confirm-password-reset-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your new password for `,t.strong(null,a.email),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPassword`},`New password`),t.input({id:`newPassword`,name:`password`,required:!0,autofocus:!0,autocomplete:`new-password`,type:()=>o.showNewPassword?`text`:`password`,value:()=>o.newPassword,oninput:e=>o.newPassword=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPassword?`Hide password`:`Show password`),onclick:()=>o.showNewPassword=!o.showNewPassword},t.i({className:()=>o.showNewPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPasswordConfirm`},`New password confirm`),t.input({id:`newPasswordConfirm`,name:`passwordConfirm`,required:!0,autocomplete:`new-password`,type:()=>o.showNewPasswordConfirm?`text`:`password`,value:()=>o.newPasswordConfirm,oninput:e=>o.newPasswordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPasswordConfirm?`Hide password`:`Show password`),onclick:()=>o.showNewPasswordConfirm=!o.showNewPasswordConfirm},t.i({className:()=>o.showNewPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Set new password`)))))}export{r as pageConfirmPasswordReset}; \ No newline at end of file +import{n as e,t as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired password reset token.`),window.location.hash=`#/`;return}app.store.title=`Confirm password reset`;let o=store({newPassword:``,newPasswordConfirm:``,showNewPassword:!1,showNewPasswordConfirm:!1,isSubmitting:!1,isSuccess:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmPasswordReset(i,o.newPassword,o.newPasswordConfirm),o.isSuccess=!0}catch(e){app.checkApiError(e)}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmPasswordReset`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmPasswordResetAlert`,className:`alert success txt-center`},t.p(null,`The password was successfully changed.`),t.p(null,`You can go back to sign in with your new password.`)):t.form({pbEvent:`confirmPasswordResetForm`,className:`grid confirm-password-reset-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your new password for `,t.strong(null,a.email),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPassword`},`New password`),t.input({id:`newPassword`,name:`password`,required:!0,autofocus:!0,autocomplete:`new-password`,type:()=>o.showNewPassword?`text`:`password`,value:()=>o.newPassword,oninput:e=>o.newPassword=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPassword?`Hide password`:`Show password`),onclick:()=>o.showNewPassword=!o.showNewPassword},t.i({className:()=>o.showNewPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPasswordConfirm`},`New password confirm`),t.input({id:`newPasswordConfirm`,name:`passwordConfirm`,required:!0,autocomplete:`new-password`,type:()=>o.showNewPasswordConfirm?`text`:`password`,value:()=>o.newPasswordConfirm,oninput:e=>o.newPasswordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPasswordConfirm?`Hide password`:`Show password`),onclick:()=>o.showNewPasswordConfirm=!o.showNewPasswordConfirm},t.i({className:()=>o.showNewPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Set new password`)))))}export{r as pageConfirmPasswordReset}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmVerification-C5mNs2GJ.js b/ui/dist/assets/pageConfirmVerification-Bc6dMZfz.js similarity index 96% rename from ui/dist/assets/pageConfirmVerification-C5mNs2GJ.js rename to ui/dist/assets/pageConfirmVerification-Bc6dMZfz.js index 5a7d3ceda1..b92b506473 100644 --- a/ui/dist/assets/pageConfirmVerification-C5mNs2GJ.js +++ b/ui/dist/assets/pageConfirmVerification-Bc6dMZfz.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-CQVsfOm8.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired verification token.`),window.location.hash=`#/`;return}app.store.title=`Confirm verification`;let o=store({isConfirming:!1,isConfirmSuccess:!1,isResending:!1,isResendSuccess:!1});s();async function s(){if(o.isConfirming)return;o.isConfirming=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmVerification(i),o.isConfirmSuccess=!0}catch{o.isConfirmSuccess=!1}o.isConfirming=!1}async function c(){if(o.isResending)return;o.isResending=!0;let e=new n(`../`);try{await e.collection(a.collectionId).requestVerification(a.email),o.isResendSuccess=!0}catch(e){app.checkApiError(e),o.isResendSuccess=!1}o.isResending=!1}return t.div({pbEvent:`pageConfirmVerification`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isConfirming?t.div({className:`block txt-center`},t.span({className:`loader`},`Please wait...`)):o.isConfirmSuccess?t.div({pbEvent:`confirmVerificationSuccessAlert`,className:`alert success txt-center`},t.p(null,`Successfully verified `,t.strong(null,a.email),`.`)):o.isResendSuccess?t.div({pbEvent:`confirmVerificationResendAlert`,className:`alert success txt-center`},t.p(null,`Please check your email for the new verification link.`)):[t.div({pbEvent:`confirmVerificationErrorAlert`,className:`alert danger txt-center m-b-base`},t.p(null,`Invalid or expired verification token.`)),t.button({type:`button`,className:()=>`btn transparent lg block ${o.isResending?`loading`:``}`,disabled:()=>o.isResending,onclick:()=>c()},t.span({className:`txt`},`Resend`))])}export{r as pageConfirmVerification}; \ No newline at end of file +import{n as e,t as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired verification token.`),window.location.hash=`#/`;return}app.store.title=`Confirm verification`;let o=store({isConfirming:!1,isConfirmSuccess:!1,isResending:!1,isResendSuccess:!1});s();async function s(){if(o.isConfirming)return;o.isConfirming=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmVerification(i),o.isConfirmSuccess=!0}catch{o.isConfirmSuccess=!1}o.isConfirming=!1}async function c(){if(o.isResending)return;o.isResending=!0;let e=new n(`../`);try{await e.collection(a.collectionId).requestVerification(a.email),o.isResendSuccess=!0}catch(e){app.checkApiError(e),o.isResendSuccess=!1}o.isResending=!1}return t.div({pbEvent:`pageConfirmVerification`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isConfirming?t.div({className:`block txt-center`},t.span({className:`loader`},`Please wait...`)):o.isConfirmSuccess?t.div({pbEvent:`confirmVerificationSuccessAlert`,className:`alert success txt-center`},t.p(null,`Successfully verified `,t.strong(null,a.email),`.`)):o.isResendSuccess?t.div({pbEvent:`confirmVerificationResendAlert`,className:`alert success txt-center`},t.p(null,`Please check your email for the new verification link.`)):[t.div({pbEvent:`confirmVerificationErrorAlert`,className:`alert danger txt-center m-b-base`},t.p(null,`Invalid or expired verification token.`)),t.button({type:`button`,className:()=>`btn transparent lg block ${o.isResending?`loading`:``}`,disabled:()=>o.isResending,onclick:()=>c()},t.span({className:`txt`},`Resend`))])}export{r as pageConfirmVerification}; \ No newline at end of file diff --git a/ui/dist/assets/pageInstaller-BDYLSgKa.js b/ui/dist/assets/pageInstaller-2TD7r9Pz.js similarity index 98% rename from ui/dist/assets/pageInstaller-BDYLSgKa.js rename to ui/dist/assets/pageInstaller-2TD7r9Pz.js index cdd070c1f9..73da7f72d4 100644 --- a/ui/dist/assets/pageInstaller-BDYLSgKa.js +++ b/ui/dist/assets/pageInstaller-2TD7r9Pz.js @@ -1 +1 @@ -import{n as e,r as n}from"./index-CQVsfOm8.js";function r(r){let i=r.params?.token||``;if(e(i).type!=`auth`||n(i)){app.toasts.error(`The installer token is invalid or has expired.`),window.location.hash=`#/`;return}app.store.title=`Setup your PocketBase instance`;let a=store({email:``,password:``,passwordConfirm:``,showPassword:!1,showPasswordConfirm:!1,isSubmitting:!1,isUploading:!1,get isBusy(){return a.isSubmitting||a.isUploading}});async function o(){if(!a.isBusy){a.isSubmitting=!0;try{await app.pb.collection(`_superusers`).create({email:a.email,password:a.password,passwordConfirm:a.passwordConfirm},{headers:{Authorization:i}}),await app.pb.collection(`_superusers`).authWithPassword(a.email,a.password),window.location.hash=`#/`}catch(e){app.checkApiError(e)}a.isSubmitting=!1}}let s=`backupFileInput`;function c(){let e=document.getElementById(s);e&&(e.value=``)}function l(e){e&&app.modals.confirm(t.h6(null,`Note that we don't perform validations for the uploaded backup files. Proceed with caution and only if you trust the file source.\n\nDo you really want to upload and initialize "${e.name}"?`),()=>{u(e)},()=>{c()})}async function u(e){if(!(!e||a.isBusy)){a.isUploading=!0;try{await app.pb.backups.upload({file:e},{headers:{Authorization:i}}),await app.pb.backups.restore(e.name,{headers:{Authorization:i}}),app.toasts.info(`Please wait while extracting the uploaded archive!`),await new Promise(e=>setTimeout(e,3e3)),window.location.href=`#/`}catch(e){app.checkApiError(e)}c(),a.isUploading=!1}}return t.div({pbEvent:`pageInstaller`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),t.form({pbEvent:`installerForm`,className:`grid installer-form`,onsubmit:e=>{e.preventDefault(),o(a)}},t.div({className:`col-12 txt-center`},`Create your first superuser account in order to continue:`),t.div({className:`col-12`},t.div({className:`field`},t.label({htmlFor:`superuser_email`},`Email`),t.input({id:`superuser_email`,name:`email`,type:`email`,required:!0,autofocus:!0,autocomplete:`off`,disabled:()=>a.isBusy,value:()=>a.email,oninput:e=>a.email=e.target.value}))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password`},`Password`),t.input({id:`superuser_password`,name:`password`,min:10,required:!0,disabled:()=>a.isBusy,type:()=>a.showPassword?`text`:`password`,value:()=>a.password,oninput:e=>a.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPassword?`Hide password`:`Show password`),onclick:()=>a.showPassword=!a.showPassword},t.i({className:()=>a.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0})))),t.div({className:`field-help`},`Recommended at least 10 characters.`)),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password_confirm`},`Password confirm`),t.input({id:`superuser_password_confirm`,name:`passwordConfirm`,required:!0,disabled:()=>a.isBusy,type:()=>a.showPasswordConfirm?`text`:`password`,value:()=>a.passwordConfirm,oninput:e=>a.passwordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPasswordConfirm?`Hide password`:`Show password`),onclick:()=>a.showPasswordConfirm=!a.showPasswordConfirm},t.i({className:()=>a.showPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg next block ${a.isSubmitting?`loading`:``}`,disabled:()=>a.isBusy},t.span({className:`txt`},`Create superuser and login`),t.i({className:`ri-arrow-right-line`,ariaHidden:!0})))),t.hr(),t.label({htmlFor:s,className:()=>`btn secondary transparent lg block ${a.isBusy?`disabled`:``} ${a.isUploading?`loading`:``}`},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Or initialize from backup`)),t.input({id:s,type:`file`,className:`hidden`,accept:`.zip`,onchange:e=>{l(e.target?.files?.[0])}}))}export{r as pageInstaller}; \ No newline at end of file +import{n as e,r as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``;if(e(i).type!=`auth`||n(i)){app.toasts.error(`The installer token is invalid or has expired.`),window.location.hash=`#/`;return}app.store.title=`Setup your PocketBase instance`;let a=store({email:``,password:``,passwordConfirm:``,showPassword:!1,showPasswordConfirm:!1,isSubmitting:!1,isUploading:!1,get isBusy(){return a.isSubmitting||a.isUploading}});async function o(){if(!a.isBusy){a.isSubmitting=!0;try{await app.pb.collection(`_superusers`).create({email:a.email,password:a.password,passwordConfirm:a.passwordConfirm},{headers:{Authorization:i}}),await app.pb.collection(`_superusers`).authWithPassword(a.email,a.password),window.location.hash=`#/`}catch(e){app.checkApiError(e)}a.isSubmitting=!1}}let s=`backupFileInput`;function c(){let e=document.getElementById(s);e&&(e.value=``)}function l(e){e&&app.modals.confirm(t.h6(null,`Note that we don't perform validations for the uploaded backup files. Proceed with caution and only if you trust the file source.\n\nDo you really want to upload and initialize "${e.name}"?`),()=>{u(e)},()=>{c()})}async function u(e){if(!(!e||a.isBusy)){a.isUploading=!0;try{await app.pb.backups.upload({file:e},{headers:{Authorization:i}}),await app.pb.backups.restore(e.name,{headers:{Authorization:i}}),app.toasts.info(`Please wait while extracting the uploaded archive!`),await new Promise(e=>setTimeout(e,3e3)),window.location.href=`#/`}catch(e){app.checkApiError(e)}c(),a.isUploading=!1}}return t.div({pbEvent:`pageInstaller`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),t.form({pbEvent:`installerForm`,className:`grid installer-form`,onsubmit:e=>{e.preventDefault(),o(a)}},t.div({className:`col-12 txt-center`},`Create your first superuser account in order to continue:`),t.div({className:`col-12`},t.div({className:`field`},t.label({htmlFor:`superuser_email`},`Email`),t.input({id:`superuser_email`,name:`email`,type:`email`,required:!0,autofocus:!0,autocomplete:`off`,disabled:()=>a.isBusy,value:()=>a.email,oninput:e=>a.email=e.target.value}))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password`},`Password`),t.input({id:`superuser_password`,name:`password`,min:10,required:!0,disabled:()=>a.isBusy,type:()=>a.showPassword?`text`:`password`,value:()=>a.password,oninput:e=>a.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPassword?`Hide password`:`Show password`),onclick:()=>a.showPassword=!a.showPassword},t.i({className:()=>a.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0})))),t.div({className:`field-help`},`Recommended at least 10 characters.`)),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password_confirm`},`Password confirm`),t.input({id:`superuser_password_confirm`,name:`passwordConfirm`,required:!0,disabled:()=>a.isBusy,type:()=>a.showPasswordConfirm?`text`:`password`,value:()=>a.passwordConfirm,oninput:e=>a.passwordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPasswordConfirm?`Hide password`:`Show password`),onclick:()=>a.showPasswordConfirm=!a.showPasswordConfirm},t.i({className:()=>a.showPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg next block ${a.isSubmitting?`loading`:``}`,disabled:()=>a.isBusy},t.span({className:`txt`},`Create superuser and login`),t.i({className:`ri-arrow-right-line`,ariaHidden:!0})))),t.hr(),t.label({htmlFor:s,className:()=>`btn secondary transparent lg block ${a.isBusy?`disabled`:``} ${a.isUploading?`loading`:``}`},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Or initialize from backup`)),t.input({id:s,type:`file`,className:`hidden`,accept:`.zip`,onchange:e=>{l(e.target?.files?.[0])}}))}export{r as pageInstaller}; \ No newline at end of file diff --git a/ui/dist/index.html b/ui/dist/index.html index c56af50420..c85e1343ec 100644 --- a/ui/dist/index.html +++ b/ui/dist/index.html @@ -13,7 +13,7 @@ - + diff --git a/ui/src/utils.js b/ui/src/utils.js index 78a885b801..02829e418e 100644 --- a/ui/src/utils.js +++ b/ui/src/utils.js @@ -1295,6 +1295,23 @@ const utils = { videoExtensions: [".mp4", ".avi", ".mov", ".3gp", ".wmv"], audioExtensions: [".aa", ".aac", ".m4v", ".mp3", ".ogg", ".oga", ".mogg", ".amr"], documentExtensions: [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".odp", ".odt", ".ods", ".txt"], + archiveExtensions: [".zip", ".gz", ".tar", ".rar", ".7z"], + + /** + * Loosely check if a file has an extension from the specified list. + * + * @param {Array} extensionsList + * @param {string} filename + * @return {boolean} + */ + hasExtension(extensionsList, filename) { + if (typeof filename != "string") { + return false; + } + + filename = filename.toLowerCase(); + return !!extensionsList?.find((ext) => filename.endsWith(ext)); + }, /** * Loosely check if a file has image extension. @@ -1303,8 +1320,7 @@ const utils = { * @return {boolean} */ hasImageExtension(filename) { - filename = (filename || "").toLowerCase(); - return !!app.utils.imageExtensions.find((ext) => filename.endsWith(ext)); + return app.utils.hasExtension(app.utils.imageExtensions, filename); }, /** @@ -1314,8 +1330,7 @@ const utils = { * @return {boolean} */ hasVideoExtension(filename) { - filename = (filename || "").toLowerCase(); - return !!app.utils.videoExtensions.find((ext) => filename.endsWith(ext)); + return app.utils.hasExtension(app.utils.videoExtensions, filename); }, /** @@ -1325,8 +1340,7 @@ const utils = { * @return {boolean} */ hasAudioExtension(filename) { - filename = (filename || "").toLowerCase(); - return !!app.utils.audioExtensions.find((ext) => filename.endsWith(ext)); + return app.utils.hasExtension(app.utils.audioExtensions, filename); }, /** @@ -1336,8 +1350,17 @@ const utils = { * @return {boolean} */ hasDocumentExtension(filename) { - filename = (filename || "").toLowerCase(); - return !!app.utils.documentExtensions.find((ext) => filename.endsWith(ext)); + return app.utils.hasExtension(app.utils.documentExtensions, filename); + }, + + /** + * Loosely check if a file has an archive extension. + * + * @param {string} filename + * @return {boolean} + */ + hasArchiveExtension(filename) { + return app.utils.hasExtension(app.utils.archiveExtensions, filename); }, /** @@ -1351,6 +1374,7 @@ const utils = { if (app.utils.hasVideoExtension(filename)) return "video"; if (app.utils.hasAudioExtension(filename)) return "audio"; if (app.utils.hasDocumentExtension(filename)) return "document"; + if (app.utils.hasArchiveExtension(filename)) return "archive"; return "file"; }, fileTypeIcons: { @@ -1358,6 +1382,7 @@ const utils = { video: "ri-movie-line", audio: "ri-music-2-line", document: "ri-file-line", + archive: "ri-file-zip-line", file: "ri-file-line", }, From 4c6c1666035da7ca748b1081b00f68005c89122a Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sun, 2 Aug 2026 15:45:31 +0300 Subject: [PATCH 03/37] order new files at the end --- .../{index-BQ-53gTd.js => index-C9WMzSfg.js} | 4 ++-- ...T.js => pageConfirmEmailChange-BY7xJuWX.js} | 2 +- ...js => pageConfirmPasswordReset-DDVg4sJm.js} | 2 +- ....js => pageConfirmVerification-DePQEvON.js} | 2 +- ...r-2TD7r9Pz.js => pageInstaller-Btd_kQ3V.js} | 2 +- ui/dist/index.html | 2 +- ui/src/fields/file/input.js | 18 +++++++++++++++++- ui/src/records/recordFilePickerModal.js | 2 +- 8 files changed, 25 insertions(+), 9 deletions(-) rename ui/dist/assets/{index-BQ-53gTd.js => index-C9WMzSfg.js} (99%) rename ui/dist/assets/{pageConfirmEmailChange-l_DOk6UT.js => pageConfirmEmailChange-BY7xJuWX.js} (97%) rename ui/dist/assets/{pageConfirmPasswordReset-UQX1jz2S.js => pageConfirmPasswordReset-DDVg4sJm.js} (97%) rename ui/dist/assets/{pageConfirmVerification-Bc6dMZfz.js => pageConfirmVerification-DePQEvON.js} (96%) rename ui/dist/assets/{pageInstaller-2TD7r9Pz.js => pageInstaller-Btd_kQ3V.js} (98%) diff --git a/ui/dist/assets/index-BQ-53gTd.js b/ui/dist/assets/index-C9WMzSfg.js similarity index 99% rename from ui/dist/assets/index-BQ-53gTd.js rename to ui/dist/assets/index-C9WMzSfg.js index 991daadfed..9d20ef053e 100644 --- a/ui/dist/assets/index-BQ-53gTd.js +++ b/ui/dist/assets/index-C9WMzSfg.js @@ -49,7 +49,7 @@ The field cannot be presentable if hidden.`),n})})))},()=>{if(i.showHidden)retur This field is disabled if "Only domains" is set.`)})),t.input({type:`text`,id:n+`.exceptDomains`,disabled:()=>!app.utils.isEmpty(e.field.onlyDomains),name:()=>`fields.${e.fieldIndex}.exceptDomains`,value:()=>app.utils.joinNonEmpty(e.field.exceptDomains),onchange:n=>e.field.exceptDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.onlyDomains`},t.span({className:`txt`},`Only domains`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of domains that are ONLY allowed. This field is disabled if "Except domains" is set.`)})),t.input({type:`text`,id:n+`.onlyDomains`,disabled:()=>!app.utils.isEmpty(e.field.exceptDomains),name:()=>`fields.${e.fieldIndex}.onlyDomains`,value:()=>app.utils.joinNonEmpty(e.field.onlyDomains),onchange:n=>e.field.onlyDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string.`)})))]})}function zn(e){return t.div({className:`record-field-view field-type-email`},()=>{let n=e.record[e.field.name]||``;return n?e.short?t.span({className:`txt txt-ellipsis`,textContent:app.utils.truncate(n)}):n:t.span({className:`missing-value`})})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.email={icon:`ri-mail-line`,label:`Email`,settings:Rn,input:Ln,view:zn,filterModifiers:e=>[`lower`],dummyData:(e,n=!1)=>`test_${app.utils.randomString(3,`123567890`)}@example.com`};function Bn(e){let n=`url_`+app.utils.randomString();return t.div({className:`record-field-input field-type-url`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.url.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),t.input({type:`url`,id:n,spellcheck:!1,name:()=>e.field.name,required:()=>e.field.required,value:()=>e.record[e.field.name]||``,oninput:n=>e.record[e.field.name]=n.target.value})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function Vn(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.exceptDomains`},t.span({className:`txt`},`Except domains`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of domains that are NOT allowed. This field is disabled if "Only domains" is set.`)})),t.input({type:`text`,id:n+`.exceptDomains`,disabled:()=>!app.utils.isEmpty(e.field.onlyDomains),name:()=>`fields.${e.fieldIndex}.exceptDomains`,value:()=>app.utils.joinNonEmpty(e.field.exceptDomains),onchange:n=>e.field.exceptDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.onlyDomains`},t.span({className:`txt`},`Only domains`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of domains that are ONLY allowed. -This field is disabled if "Except domains" is set.`)})),t.input({type:`text`,id:n+`.onlyDomains`,disabled:()=>!app.utils.isEmpty(e.field.exceptDomains),name:()=>`fields.${e.fieldIndex}.onlyDomains`,value:()=>app.utils.joinNonEmpty(e.field.onlyDomains),onchange:n=>e.field.onlyDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string.`)})))]})}function Hn(e){return t.div({className:`record-field-view field-type-url`},()=>{let n=e.record[e.field.name]||``;return n?t.a({href:()=>n,className:()=>`txt ${e.short?`txt-ellipsis`:``}`,rel:`noopener noreferrer`,target:`_blank`,textContent:app.utils.truncate(n),ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:e=>{e.stopPropagation()}}):t.span({className:`missing-value`})})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.url={icon:`ri-link`,label:`URL`,settings:Vn,input:Bn,view:Hn,dummyData:(e,n=!1)=>`https://example.com`};var Un=Intl.DateTimeFormat().resolvedOptions().timeZone;function Wn(e){let n=`date_`+app.utils.randomString();return t.div({className:`record-field-input field-type-date`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.date.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name,` (`,Un,`)`)),t.input({id:n,step:1,type:`datetime-local`,name:()=>e.field.name,required:()=>e.field.required,value:()=>app.utils.toDatetimeLocalInputValue(e.record[e.field.name]),onchange:n=>{n.target.value&&(e.record[e.field.name]=app.utils.toRFC3339Datetime(n.target.value))},onblur:n=>{e.record[e.field.name]=null,e.record[e.field.name]=app.utils.toRFC3339Datetime(n.target.value)}})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function Gn(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.min`},t.span({className:`txt`},`Min date (Local)`)),t.input({type:`datetime-local`,id:n+`.min`,step:1,name:()=>`fields.${e.fieldIndex}.min`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.min),onchange:n=>{e.field.min=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.max`},t.span({className:`txt`},`Max date (Local)`)),t.input({type:`datetime-local`,id:n+`.max`,step:1,name:()=>`fields.${e.fieldIndex}.max`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.max),onchange:n=>{e.field.max=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string.`)})))]})}function Kn(e){return t.div({className:`record-field-view field-type-date`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.date={icon:`ri-calendar-line`,label:`Datetime`,settings:Gn,input:Wn,view:Kn,dummyData:(e,n=!1)=>new Date().toISOString().replaceAll(`T`,` `)};function qn(e){delete e.clone[e.field.name]}function Jn(e){let n=[{label:`Create`,value:1},{label:`Update`,value:2},{label:`Create/Update`,value:3}];function r(e){return e.onCreate&&e.onUpdate?3:e.onUpdate?2:1}function i(n){switch(n){case 1:e.field.onCreate=!0,e.field.onUpdate=!1;break;case 2:e.field.onCreate=!1,e.field.onUpdate=!0;break;case 3:e.field.onCreate=!0,e.field.onUpdate=!0;break}}let a=store({isDropdownOpen:!1});return app.components.fieldSettings(e,{header:t.div({className:`field header-select autodate-select`,ariaDescription:app.attrs.tooltip(`Auto set on`,`left`),onmount:()=>{i(r(e.field))}},app.components.select({required:!0,options:n,disabled:()=>e.originalCollection?.system,value:()=>r(e.field),onchange:e=>i(e?.[0]?.value),ondropdowntoggle:e=>{a.isDropdownOpen=e.newState==`open`}}))})}function Yn(e){return t.div({className:`record-field-view field-type-autodate`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.autodate={icon:`ri-calendar-check-line`,label:`Autodate`,settings:Jn,view:Yn,onrecordduplicate:qn,dummyData:(e,n=!1)=>{if(!n)return new Date().toISOString().replaceAll(`T`,` `)}};var Xn=`@@filesToDelete`;function Zn(e){let n=app.utils.toArray(e.payload[e.field.name]),r=app.utils.toArray(e.record[Xn]?.[e.field.name]);for(let e of r){let r=n.indexOf(e);r>=0&&n.splice(r,1)}e.payload[e.field.name]=n}function Qn(e){let n=`file_`+app.utils.randomString();function r(n){return typeof n==`string`&&!!e.record[Xn]?.[e.field.name]?.includes(n)}function i(n){if(typeof n==`string`){e.record[Xn]=e.record[`@@filesToDelete`]||{},e.record[Xn][e.field.name]=e.record[`@@filesToDelete`][e.field.name]||[],app.utils.pushUnique(e.record[Xn][e.field.name],n),c();return}let r=app.utils.toArray(e.record[e.field.name]),i=r.indexOf(n);i>=0&&(r.splice(i,1),e.record[e.field.name]=r,c())}function a(n){typeof n==`string`&&(app.utils.removeByValue(e.record[Xn]?.[e.field.name],n),c())}function o(){return e.record[`@@filesToDelete`]?.[e.field.name]?.length||0}function s(){return app.utils.toArray(e.record[e.field.name]).length-o()}function c(){f?.dispatchEvent(new CustomEvent(`change`,{detail:{data:e},bubbles:!0}))}let l=store({get maxReached(){let n=e.field.maxSelect||1;return s()>=n}});function u(n){let r=app.utils.toArray(e.record[e.field.name]);for(let e of n){if(l.maxReached){console.warn(`can't add more files - max allowed files reached`);break}r.push(e)}e.record[e.field.name]=r,c()}let d=t.input({type:`file`,hidden:!0,multiple:()=>e.field.maxSelect>1,accept:()=>e.field.mimeTypes?.join(`,`)||void 0,onchange:e=>{u(e.target.files),e.target.value=null}}),f=t.output({className:`field-content`,name:()=>e.field.name},app.components.sortable({className:`list`,data:()=>{let n=app.utils.toArray(e.record[e.field.name]),r=!1;for(let e=n.length-1;e>=0;e--)typeof n[e]==`string`||n[e]instanceof Blob||(r=!0,n.splice(e,1));return r&&(e.record[e.field.name]=n),n},onchange:n=>{e.record[e.field.name]=n,c()},dataItem:(n,o)=>t.div({rid:n,className:()=>`list-item highlight ${r(n)?`deleted`:``}`},t.div({className:`content gap-10`},()=>typeof n==`string`?[app.components.recordFileThumb({record:e.record,filename:n}),t.button({type:`button`,ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:async()=>{let r=await app.getFileToken(e.record.collectionId),i=app.pb.files.getURL(e.record,n,{token:r});window.open(i,`_blank`,`noreferrer,noopener`)}},t.span({className:`txt link-primary`},n))]:[app.components.uploadedFileThumb({file:n}),t.span({className:`label success`},`New`),t.span({className:`txt`},n.name)]),t.div({className:`actions`},t.button({type:`button`,className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Remove file`),hidden:()=>r(n),onclick:()=>i(n)},t.i({className:`ri-close-line`,ariaHidden:!0})),t.button({type:`button`,className:`btn sm warning transparent`,hidden:()=>!r(n),onclick:()=>a(n)},t.span({className:`txt`},`Restore`))))}),t.hr({className:`m-t-5 m-b-0`,hidden:()=>app.utils.toArray(e.record[e.field.name]).length>0}),t.button({type:`button`,className:`btn sm secondary block`,title:()=>l.maxReached?`Max allowed files reached`:void 0,disabled:()=>l.maxReached,onclick:e=>{l.maxReached||d?.click(),document.activeElement?.blur()}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Upload or drop new file`)));return t.div({className:`record-field-input field-type-file`,ondragover:e=>{e.preventDefault()},ondrop:e=>{let n=e.dataTransfer?.files||[];n.length&&(e.preventDefault(),!l.maxReached&&u(n))}},t.div({className:()=>`field-list ${e.field.required?`required`:``}`},t.label({htmlFor:n},t.i({className:app.fieldTypes.file.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),d,f),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function $n(e){delete e.clone[e.field.name]}function er(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{header:[t.div({className:`field header-select single-multiple-select`},app.components.select({required:!0,options:[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],value:()=>e.field.maxSelect>1,onchange:n=>{n?.[0]?.value?(!e.field.maxSelect||e.field.maxSelect<2)&&(e.field.maxSelect=10):e.field.maxSelect=1}}))],content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.mimeTypes`},t.span({className:`txt`},`Allowed mime types`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Allow files ONLY with the listed mime types. +This field is disabled if "Except domains" is set.`)})),t.input({type:`text`,id:n+`.onlyDomains`,disabled:()=>!app.utils.isEmpty(e.field.exceptDomains),name:()=>`fields.${e.fieldIndex}.onlyDomains`,value:()=>app.utils.joinNonEmpty(e.field.onlyDomains),onchange:n=>e.field.onlyDomains=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},`Use comma as separator.`)),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string.`)})))]})}function Hn(e){return t.div({className:`record-field-view field-type-url`},()=>{let n=e.record[e.field.name]||``;return n?t.a({href:()=>n,className:()=>`txt ${e.short?`txt-ellipsis`:``}`,rel:`noopener noreferrer`,target:`_blank`,textContent:app.utils.truncate(n),ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:e=>{e.stopPropagation()}}):t.span({className:`missing-value`})})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.url={icon:`ri-link`,label:`URL`,settings:Vn,input:Bn,view:Hn,dummyData:(e,n=!1)=>`https://example.com`};var Un=Intl.DateTimeFormat().resolvedOptions().timeZone;function Wn(e){let n=`date_`+app.utils.randomString();return t.div({className:`record-field-input field-type-date`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.date.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name,` (`,Un,`)`)),t.input({id:n,step:1,type:`datetime-local`,name:()=>e.field.name,required:()=>e.field.required,value:()=>app.utils.toDatetimeLocalInputValue(e.record[e.field.name]),onchange:n=>{n.target.value&&(e.record[e.field.name]=app.utils.toRFC3339Datetime(n.target.value))},onblur:n=>{e.record[e.field.name]=null,e.record[e.field.name]=app.utils.toRFC3339Datetime(n.target.value)}})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function Gn(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.min`},t.span({className:`txt`},`Min date (Local)`)),t.input({type:`datetime-local`,id:n+`.min`,step:1,name:()=>`fields.${e.fieldIndex}.min`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.min),onchange:n=>{e.field.min=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-6`},t.div({className:`field`},t.label({htmlFor:n+`.max`},t.span({className:`txt`},`Max date (Local)`)),t.input({type:`datetime-local`,id:n+`.max`,step:1,name:()=>`fields.${e.fieldIndex}.max`,value:()=>app.utils.toDatetimeLocalInputValue(e.field.max),onchange:n=>{e.field.max=app.utils.toRFC3339Datetime(n.target.value)}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Requires the field value to be nonempty string.`)})))]})}function Kn(e){return t.div({className:`record-field-view field-type-date`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.date={icon:`ri-calendar-line`,label:`Datetime`,settings:Gn,input:Wn,view:Kn,dummyData:(e,n=!1)=>new Date().toISOString().replaceAll(`T`,` `)};function qn(e){delete e.clone[e.field.name]}function Jn(e){let n=[{label:`Create`,value:1},{label:`Update`,value:2},{label:`Create/Update`,value:3}];function r(e){return e.onCreate&&e.onUpdate?3:e.onUpdate?2:1}function i(n){switch(n){case 1:e.field.onCreate=!0,e.field.onUpdate=!1;break;case 2:e.field.onCreate=!1,e.field.onUpdate=!0;break;case 3:e.field.onCreate=!0,e.field.onUpdate=!0;break}}let a=store({isDropdownOpen:!1});return app.components.fieldSettings(e,{header:t.div({className:`field header-select autodate-select`,ariaDescription:app.attrs.tooltip(`Auto set on`,`left`),onmount:()=>{i(r(e.field))}},app.components.select({required:!0,options:n,disabled:()=>e.originalCollection?.system,value:()=>r(e.field),onchange:e=>i(e?.[0]?.value),ondropdowntoggle:e=>{a.isDropdownOpen=e.newState==`open`}}))})}function Yn(e){return t.div({className:`record-field-view field-type-autodate`},app.components.formattedDate({value:()=>e.record[e.field.name],short:()=>e.short}))}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.autodate={icon:`ri-calendar-check-line`,label:`Autodate`,settings:Jn,view:Yn,onrecordduplicate:qn,dummyData:(e,n=!1)=>{if(!n)return new Date().toISOString().replaceAll(`T`,` `)}};var Xn=`@@filesToDelete`;function Zn(e){let n=app.utils.toArray(e.payload[e.field.name]),r=app.utils.toArray(e.record[Xn]?.[e.field.name]);for(let e of r){let r=n.indexOf(e);r>=0&&n.splice(r,1)}e.payload[e.field.name]=n}function Qn(e){let n=`file_`+app.utils.randomString();function r(n){return typeof n==`string`&&!!e.record[Xn]?.[e.field.name]?.includes(n)}function i(n){if(typeof n==`string`){e.record[Xn]=e.record[`@@filesToDelete`]||{},e.record[Xn][e.field.name]=e.record[`@@filesToDelete`][e.field.name]||[],app.utils.pushUnique(e.record[Xn][e.field.name],n),c();return}let r=app.utils.toArray(e.record[e.field.name]),i=r.indexOf(n);i>=0&&(r.splice(i,1),e.record[e.field.name]=r,c())}function a(n){typeof n==`string`&&(app.utils.removeByValue(e.record[Xn]?.[e.field.name],n),c())}function o(){return e.record[`@@filesToDelete`]?.[e.field.name]?.length||0}function s(){return app.utils.toArray(e.record[e.field.name]).length-o()}function c(){f?.dispatchEvent(new CustomEvent(`change`,{detail:{data:e},bubbles:!0}))}let l=store({get maxReached(){let n=e.field.maxSelect||1;return s()>=n}});function u(n){let r=app.utils.toArray(e.record[e.field.name]);for(let e of n){if(l.maxReached){console.warn(`can't add more files - max allowed files reached`);break}r.push(e)}e.record[e.field.name]=r,c()}let d=t.input({type:`file`,hidden:!0,multiple:()=>e.field.maxSelect>1,accept:()=>e.field.mimeTypes?.join(`,`)||void 0,onchange:e=>{u(e.target.files),e.target.value=null}}),f=t.output({className:`field-content`,name:()=>e.field.name},app.components.sortable({className:`list`,data:()=>{let n=app.utils.toArray(e.record[e.field.name]),r=!1;for(let e=n.length-1;e>=0;e--)typeof n[e]==`string`||n[e]instanceof Blob||(r=!0,n.splice(e,1));return r&&(e.record[e.field.name]=n),n},onchange:n=>{n.sort((e,n)=>{let r=typeof e==`string`,i=typeof n==`string`;return r&&!i?-1:!r&&i?1:0}),e.record[e.field.name]=n,c()},dataItem:(n,o)=>t.div({rid:n,className:()=>`list-item highlight ${r(n)?`deleted`:``}`},t.div({className:`content gap-10`},()=>typeof n==`string`?[app.components.recordFileThumb({record:e.record,filename:n}),t.button({type:`button`,ariaDescription:app.attrs.tooltip(`Open in new tab`),onclick:async()=>{let r=await app.getFileToken(e.record.collectionId),i=app.pb.files.getURL(e.record,n,{token:r});window.open(i,`_blank`,`noreferrer,noopener`)}},t.span({className:`txt link-primary`},n))]:[app.components.uploadedFileThumb({file:n}),t.span({className:`label success`},`New`),t.span({className:`txt`},n.name)]),t.div({className:`actions`},t.button({type:`button`,className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Remove file`),hidden:()=>r(n),onclick:()=>i(n)},t.i({className:`ri-close-line`,ariaHidden:!0})),t.button({type:`button`,className:`btn sm warning transparent`,hidden:()=>!r(n),onclick:()=>a(n)},t.span({className:`txt`},`Restore`))))}),t.hr({className:`m-t-5 m-b-0`,hidden:()=>app.utils.toArray(e.record[e.field.name]).length>0}),t.button({type:`button`,className:`btn sm secondary block`,title:()=>l.maxReached?`Max allowed files reached`:void 0,disabled:()=>l.maxReached,onclick:e=>{l.maxReached||d?.click(),document.activeElement?.blur()}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Upload or drop new file`)));return t.div({className:`record-field-input field-type-file`,ondragover:e=>{e.preventDefault()},ondrop:e=>{let n=e.dataTransfer?.files||[];n.length&&(e.preventDefault(),!l.maxReached&&u(n))}},t.div({className:()=>`field-list ${e.field.required?`required`:``}`},t.label({htmlFor:n},t.i({className:app.fieldTypes.file.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),d,f),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function $n(e){delete e.clone[e.field.name]}function er(e){let n=`f_`+app.utils.randomString();return app.components.fieldSettings(e,{header:[t.div({className:`field header-select single-multiple-select`},app.components.select({required:!0,options:[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],value:()=>e.field.maxSelect>1,onchange:n=>{n?.[0]?.value?(!e.field.maxSelect||e.field.maxSelect<2)&&(e.field.maxSelect=10):e.field.maxSelect=1}}))],content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.mimeTypes`},t.span({className:`txt`},`Allowed mime types`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Allow files ONLY with the listed mime types. Leave empty for no restriction.`)})),app.components.select({max:99,placeholder:`No restriction`,options:app.utils.mimeTypes.map(e=>({value:e.mimeType,label:()=>t.div({className:`inline-flex gap-10`},t.span({className:`txt`},e.ext||`-`),t.small({className:`txt-hint`},e.mimeType))})),name:()=>`fields.${e.fieldIndex}.mimeTypes`,value:()=>app.utils.toArray(e.field.mimeTypes),onchange:n=>e.field.mimeTypes=n.map(e=>e.value)})),t.div({className:`field-help`},t.button({type:`button`,className:`link-hint gap-0`,"html-popovertarget":n+`mimeTypesDropdown`},t.span({className:`txt`},`Choose presets`),t.i({className:`ri-arrow-drop-down-fill`,ariaHidden:!0})),t.div({id:n+`mimeTypesDropdown`,className:`dropdown sm nowrap left p-10`,popover:`auto`},t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`image/jpeg`,`image/png`,`image/svg+xml`,`image/gif`,`image/webp`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Images (jpg, png, svg, gif, webp)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`application/pdf`,`application/msword`,`application/vnd.openxmlformats-officedocument.wordprocessingml.document`,`application/vnd.ms-excel`,`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Documents (pdf, doc/docx, xls/xlsx)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`video/mp4`,`video/mpeg`,`video/x-msvideo`,`video/quicktime`,`video/3gpp`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Videos (mp4, mpeg, avi, mov, 3gp)`}),t.button({type:`button`,className:`dropdown-item`,role:`menuitem`,onclick:n=>{e.field.mimeTypes=[`application/zip`,`application/x-7z-compressed`,`application/x-rar-compressed`],n.target.closest(`.dropdown`).hidePopover()},textContent:`Archives (zip, 7zip, rar)`})))),t.div({className:()=>e.field.maxSelect>1?`col-sm-6`:`col-sm-9`},t.div({className:`field`},t.label({htmlFor:n+`.thumbs`},t.span({className:`txt`},`Thumb sizes`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`List of additional thumb sizes for image files, along with the default thumb size of 100x100. The thumbs are generated lazily on first access.`)})),t.input({type:`text`,id:n+`.thumbs`,placeholder:`e.g. 50x50, 480x720`,name:()=>`fields.${e.fieldIndex}.thumbs`,value:()=>app.utils.joinNonEmpty(e.field.thumbs),onchange:n=>e.field.thumbs=app.utils.splitNonEmpty(n.target.value,`,`)})),t.div({className:`field-help`},t.span({className:`txt m-r-5`},`Use comma as separator.`),t.button({type:`button`,className:`link-hint gap-0`,"html-popovertarget":n+`thumbFormatsDropdown`},t.span({className:`txt`},`Supported formats`),t.i({className:`ri-arrow-drop-down-fill`,ariaHidden:!0})),t.div({id:n+`thumbFormatsDropdown`,className:`dropdown sm nowrap left p-10`,popover:`auto`},t.ul({className:`m-0 p-l-sm`},t.li(null,t.strong(null,`WxH`),t.span(null,` (e.g. 100x50) - crop to WxH viewbox (from center)`)),t.li(null,t.strong(null,`WxHt`),t.span(null,` (e.g. 100x50t) - crop to WxH viewbox (from top)`)),t.li(null,t.strong(null,`WxHb`),t.span(null,` (e.g. 100x50b) - crop to WxH viewbox (from bottom)`)),t.li(null,t.strong(null,`WxHf`),t.span(null,` (e.g. 100x50f) - fit inside a WxH viewbox (without cropping)`)),t.li(null,t.strong(null,`0xH`),t.span(null,` (e.g. 0x50) - resize to H height preserving the aspect ratio`)),t.li(null,t.strong(null,`Wx0`),t.span(null,` (e.g. 100x0) - resize to W width preserving the aspect ratio`)))))),t.div({className:`col-sm-3`},t.div({className:`field`},t.label({htmlFor:n+`.maxSize`},`Max size`),t.input({type:`number`,id:n+`.maxSize`,step:1,min:0,max:2**53-1,placeholder:`~5MB default`,name:()=>`fields.${e.fieldIndex}.maxSize`,value:()=>e.field.maxSize||``,oninput:n=>{n.target.value?.length>1&&n.target.value[0]==`0`||(e.field.maxSize=parseInt(n.target.value,10))},onchange:n=>{e.field.maxSize=null,e.field.maxSize=parseInt(n.target.value,10)}})),t.div({className:`field-help`},`In bytes.`)),t.div({className:`col-sm-3`,hidden:()=>e.field.maxSelect<<0<2},t.div({className:`field`},t.label({htmlFor:n+`.maxSelect`},`Max select`),t.input({type:`number`,id:n+`.maxSelect`,placeholder:`Default to single`,step:1,min:2,required:!0,max:2**53-1,name:()=>`fields.${e.fieldIndex}.maxSelect`,value:()=>e.field.maxSelect||``,onchange:n=>{let r=parseInt(n.target.value,10);r>1?e.field.maxSelect=r:e.field.maxSelect=1}}))),t.div({className:`col-sm-12`},t.div({className:`field m-t-5 m-b-5`},t.input({className:`switch`,type:`checkbox`,id:n+`.protected`,name:()=>`fields.${e.fieldIndex}.protected`,checked:()=>!!e.field.protected,onchange:n=>e.field.protected=n.target.checked}),t.label({htmlFor:n+`.protected`},t.span({className:`txt`},`Protected`),t.small({className:`txt-hint`},`File download requests will need to satisfy the View API rule (`,t.a({href:`https://pocketbase.io/docs/files-handling#protected-files`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Learn more`}),`).`)))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},()=>e.field.maxSelect>1?`(!=[])`:`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(()=>`Requires the field value to be nonempty ${e.field.maxSelect>1?`array`:`string`}.`)})))]})}function tr(e){return t.div({className:`record-field-view field-type-file`},()=>{let n=app.utils.toArray(e.record[e.field.name]);if(!n.length)return t.span({className:`missing-value`});let r=[],i=e.short?5:100;for(let a=0;a=i){r.push(t.span({className:`thumb sm`},`+`,n.length-i));break}r.push(app.components.recordFileThumb({record:e.record,filename:n[a]}))}return r})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.file={icon:`ri-image-line`,label:`File`,settings:er,input:Qn,view:tr,summaryPriority:-1,onrecordsave:Zn,onrecordduplicate:$n,filterModifiers:e=>e.maxSelect>1?[`each`,`length`]:[],dummyData:(e,n=!1)=>n?e.maxSelect>1?[nr(`test1.txt`),nr(`test2.txt`)]:nr(`test1.txt`):e.maxSelect>1?[`test1_`+app.utils.randomString(10)+`.txt`,`test2_`+app.utils.randomString(10)+`.txt`]:`test_`+app.utils.randomString(10)+`.txt`};function nr(e){return{toString(){return`new File([...], '${e}')`},toJSON(){return`[[new File([...], '${e}')]]`}}}function rr(e){let n=`rel_`+app.utils.randomString();function r(){l?.dispatchEvent(new CustomEvent(`change`,{detail:{data:e},bubbles:!0}))}let i=store({selected:[],isLoading:!0,get maxReached(){let n=e.field.maxSelect||1;return app.utils.toArray(e.record[e.field.name]).length>=n}});async function a(){i.isLoading=!0;let n=app.utils.toArray(e.record[e.field.name]);if(!n.length){i.selected=[],i.isLoading=!1;return}let r=[],a=[],o=app.utils.toArray(e.record.expand?.[e.field.name]);for(let e of n){let n=o.find(n=>n.id==e);n?r.push(n):a.push(e)}try{if(a.length){let n=app.store.collections.find(n=>n.id==e.field.collectionId),i=[],o=n?.fields?.filter(e=>!e.hidden&&e.presentable&&e.type==`relation`)||[];for(let e of o)i.push(e.name);let s=await app.pb.collection(e.field.collectionId).getFullList({requestKey:null,filter:a.map(e=>app.pb.filter(`id={:id}`,{id:e})).join(`||`),expand:i.join(`,`)||void 0});for(let e of a){let n=s.find(n=>n.id==e);n?r.push(n):console.warn(`missing relation id:`,e)}}i.selected=r,i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}function o(n){let r=app.utils.toArray(e.record[e.field.name]),a=r.indexOf(n);a>=0&&(r.splice(a,1),s(r));let o=i.selected.findIndex(e=>e.id==n);i.selected.splice(o,1)}function s(n=[]){e.record[e.field.name]=e.field.maxSelect>1?n:n?.[0]||``,r()}let c=[watch(()=>e.record[e.field.name],()=>a())],l=t.output({className:`field-content`,name:()=>e.field.name},t.div({hidden:()=>!i.isLoading,className:`list`},()=>app.utils.toArray(e.record[e.field.name]).map(()=>t.div({className:`list-item`},t.span({className:`skeleton-loader`})))),app.components.sortable({className:`list`,hidden:()=>i.isLoading,data:()=>i.selected,onchange:e=>{s(e.map(e=>e.id)),i.selected=e},dataItem:(e,n)=>t.div({rid:e,className:`list-item highlight`},t.div({className:`content`},()=>app.components.recordSummary(e)),t.div({className:`actions`},t.button({type:`button`,className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Remove`),onclick:()=>o(e.id)},t.i({className:`ri-close-line`,ariaHidden:!0}))))}),t.hr({hidden:()=>!app.utils.isEmpty(e.record[e.field.name]),className:`m-t-5 m-b-0`}),t.button({type:`button`,className:`btn sm secondary block`,disabled:()=>i.isLoading,onclick:n=>{app.modals.openRecordsPicker({collection:e.field.collectionId,selectedIds:app.utils.toArray(e.record[e.field.name]),maxSelect:e.field.maxSelect,onselect:e=>{s(e.map(e=>e.id)),i.selected=e}})}},t.i({className:`ri-magic-line`,ariaHidden:!0}),t.span({className:`txt`},`Open records picker`)));return t.div({className:`record-field-input field-type-relation`,onunmount:()=>{c.forEach(e=>e?.unwatch())}},t.div({className:()=>`field-list ${e.field.required?`required`:``}`},t.label({htmlFor:n},t.i({className:app.fieldTypes.relation.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),l),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function ir(e){let n=`f_`+app.utils.randomString(),r=[{label:`False`,value:!1},{label:`True`,value:!0}],i=[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],a=[watch(()=>e.field.maxSelect,n=>{n||=1,n<=1&&(e.field.minSelect=0)})];return app.components.fieldSettings(e,{header:[t.div({className:`field header-select collections-select`,onunmount:()=>{a.forEach(e=>e?.unwatch())}},app.components.select({required:!0,className:`inline-error`,placeholder:`Select collection*`,name:()=>`fields.${e.fieldIndex}.collectionId`,disabled:()=>!!e.originalField?.id,options:()=>app.utils.sortedCollections(app.store.collections.filter(e=>e.type!=`view`)).map(e=>({value:e.id,label:e.name})),value:()=>e.field.collectionId,onchange:n=>{e.field.collectionId=n?.[0]?.value||``},after:()=>[t.hr({className:`m-t-5 m-b-5`}),t.button({type:`button`,className:`btn sm outline`,onclick:()=>{app.modals.openCollectionUpsert({},{onsave:n=>{e.field.collectionId=n.id}})}},t.i({className:`ri-add-line`,ariaHidden:!0}),t.span({className:`txt`},`New collection`))]})),t.div({className:`field header-select single-multiple-select`},app.components.select({required:!0,options:i,value:()=>e.field.maxSelect>1,onchange:n=>{n?.[0]?.value?e.field.maxSelect<<0<2&&(e.field.maxSelect=10):e.field.maxSelect=1}}))],content:()=>t.div({className:`grid sm`},t.div({className:`col-sm-6`,hidden:()=>e.field.maxSelect<<0<2},t.div({className:`field`},t.label({htmlFor:n+`.minSelect`},`Min select`),t.input({type:`number`,id:n+`.minSelect`,step:1,min:0,max:2**53-1,placeholder:`No min limit`,name:()=>`fields.${e.fieldIndex}.minSelect`,value:()=>e.field.minSelect||``,onchange:n=>e.field.minSelect=parseInt(n.target.value,10)}))),t.div({className:`col-sm-6`,hidden:()=>e.field.maxSelect<<0<2},t.div({className:`field`},t.label({htmlFor:n+`.maxSelect`},`Max select`),t.input({type:`number`,id:n+`.maxSelect`,step:1,min:()=>e.field.minSelect||2,max:2**53-1,placeholder:`Default to single`,name:()=>`fields.${e.fieldIndex}.maxSelect`,value:()=>e.field.maxSelect||``,onchange:n=>{let r=parseInt(n.target.value,10);r>1?e.field.maxSelect=r:e.field.maxSelect=1}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.cascadeDelete`},`Cascade delete`),app.components.select({required:!0,id:n+`.cascadeDelete`,name:()=>`fields.${e.fieldIndex}.cascadeDelete`,options:r,value:()=>e.field.cascadeDelete||!1,onchange:n=>{e.field.cascadeDelete=!!n?.[0].value}}))),t.div({className:`col-sm-12`},t.div({className:`field`},t.label({htmlFor:n+`.help`},`Help text`),t.input({type:`text`,id:n+`.help`,name:()=>`fields.${e.fieldIndex}.help`,value:()=>e.field.help||``,oninput:n=>e.field.help=n.target.value})))),footer:()=>[t.div({className:`field`},t.input({className:`sm`,type:`checkbox`,id:n+`.required`,name:()=>`fields.${e.fieldIndex}.required`,checked:()=>!!e.field.required,onchange:n=>e.field.required=n.target.checked}),t.label({htmlFor:n+`.required`},t.span({className:`txt`},`Required`),t.small({className:`txt-hint`},()=>e.field.maxSelect>1?`(!=[])`:`(!='')`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(()=>`Requires the field value to be nonempty ${e.field.maxSelect>1?`array`:`string`}.`)})))]})}window.app=window.app||{},window.app.fieldTypes=window.app.fieldTypes||{},window.app.fieldTypes.relation={icon:`ri-mind-map`,label:`Relation`,settings:ir,input:rr,view:hn,filterModifiers:e=>e.maxSelect>1?[`each`,`length`]:[],dummyData:(e,n=!1)=>e.maxSelect>1?[`RECORD_ID1`,`RECORD_ID2`]:`RECORD_ID`};function ar(e){let n=`select_`+app.utils.randomString();return t.div({className:`record-field-input field-type-select`},t.div({className:`field`},t.label({htmlFor:n},t.i({className:app.fieldTypes.select.icon,ariaHidden:!0}),t.span({className:`txt`},()=>e.field.name)),app.components.select({id:n,name:()=>e.field.name,max:()=>e.field.maxSelect||1,required:()=>e.field.required,options:()=>e.field.values.map(e=>({value:e})),value:()=>app.utils.toArray(e.record[e.field.name]),onchange:n=>{if(e.field.maxSelect<=1){e.record[e.field.name]=n?.[0]?.value||``;return}e.record[e.field.name]=n.map(e=>e.value)}})),()=>{if(e.field.help)return t.div({className:`field-help`},e.field.help)})}function or(e){let n=`f_`+app.utils.randomString(),r=[{label:`Single`,value:!1},{label:`Multiple`,value:!0}],i=t.div({popover:`manual`,className:`dropdown field-select-choices-dropdown`},t.div({className:`field-help m-t-0`,style:`font-size: 0.9em`},`New-line separated choices:`),t.div({className:`field`},t.textarea({className:`autoexpand`,required:!0,value:()=>app.utils.toArray(e.field.values,!1).join(` `),oninput:n=>{let r=n.target.value.trimStart().replaceAll(` @@ -83,4 +83,4 @@ Records update will also require an extra unlock step before save.`)})))),t.div( @weekly @daily @midnight -@hourly`)},`macros`),`.`,t.br(),`By default the timezone is in UTC.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`backups.cronMaxKeep`},`Max @auto backups to keep`),t.input({id:`backups.cronMaxKeep`,name:`backups.cronMaxKeep`,type:`number`,required:()=>a.enableAutoBackups,min:1,value:()=>a.formSettings.backups.cronMaxKeep,oninput:e=>{a.formSettings.backups.cronMaxKeep=parseInt(e.target.value,10)}})))))),t.div({className:`col-lg-12`},app.components.s3ConfigFields({toggleLabel:`Store backups in S3 storage`,testFilesystem:`backups`,config:()=>a.formSettings.backups.s3})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!a.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:l},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${a.isSaving?`loading`:``}`,disabled:()=>!a.hasChanges||a.isSaving},t.span({className:`txt`},`Save changes`))))])))}function zi(e={oncreated:null}){let n=Bi(e);n&&(document.body.appendChild(n),app.modals.open(n))}function Bi(e){let n,r=`backup_create_`+app.utils.randomString(),i=store({name:``,isSubmitting:!1}),a;async function o(){if(!i.isSubmitting){i.isSubmitting=!0,clearTimeout(a),a=setTimeout(()=>{app.modals.close(n)},1500);try{await app.pb.backups.create(i.name,{requestKey:r}),i.isSubmitting=!1,e.oncreated&&e.oncreated(i.name),app.toasts.success(`Successfully generated new backup.`),app.modals.close(n)}catch(e){e.isAbort||(clearTimeout(a),i.isSubmitting=!1,app.checkApiError(e))}}}return n=t.div({pbEvent:`backupCreateModal`,className:`modal popup backup-create-modal`,onbeforeclose:()=>{i.isSubmitting&&app.toasts.info(`The backup was started but may take a while to complete. You can come back later.`)},onafterclose:e=>{clearTimeout(a),e?.remove()}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Initialize new backup`)),t.form({id:r,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Please note that during the backup other concurrent write requests may fail since the database will be temporary "locked" (this usually happens only during the ZIP generation).`),t.p({className:`txt-bold`},`If you are using S3 storage for the collections file upload, you'll have to backup them separately since they are not locally stored and they will not be included in the generated backup!`)))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`_name`},`Backup name`),t.input({id:r+`_name`,name:`name`,type:`text`,pattern:`^[a-z0-9_-]+.zip$`,placeholder:`Leave empty to autogenerate`,value:()=>i.name,oninput:e=>i.name=e.target.value})),t.div({className:`field-help`},`Must be in the format [a-z0-9_-].zip`)))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>i.isSubmitting,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Cancel`)),t.button({"html-form":r,type:`submit`,className:()=>`btn ${i.isSubmitting?`loading`:``}`,disabled:()=>i.isSubmitting},t.span({className:`txt`},`Start backup`)))),n}function Vi(e){let n=Hi(e);document.body.appendChild(n),app.modals.open(n)}function Hi(e){let n=`backup_restore_`+app.utils.randomString(),r=store({key:e,keyConfirm:``,isSubmitting:!1,get canSubmit(){return r.key&&r.key==r.keyConfirm}}),i;async function a(){if(!(r.isSubmitting||!r.canSubmit)){clearTimeout(i),r.isSubmitting=!0;try{await app.pb.backups.restore(r.keyConfirm),i=setTimeout(()=>{window.location.reload(),r.isSubmitting=!1},2e3)}catch(e){clearTimeout(i),e?.isAbort||(r.isSubmitting=!1,app.checkApiError(e))}}}return t.div({pbEvent:`backupRestoreModal`,className:`modal popup backup-restore-modal`,onbeforeclose:()=>!r.isSubmitting,onafterclose:e=>{e?.remove()},onunmount:()=>{clearTimeout(i)}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Restore `,t.strong(null,()=>r.key))),t.form({id:n,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert danger`},t.div({className:`content`},t.p({className:`txt-bold`},`Please proceed with extreme caution and use it only with trusted backups!`),t.p(null,`Backup restore currently works only on UNIX based systems.`),t.p(null,`The restore operation will attempt to replace your existing `,t.code(null,`pb_data`),` with the one from the backup and will restart the application process.`),t.p(null,`This means that on success all of your data (including app settings, users, superusers, etc.) will be replaced with the ones from the backup.`),t.p(null,`The operation will be reverted if the backup is invalid (ex. missing `,t.code(null,`data.db`),` file).`),t.p(null,`Below is an oversimplified version of the restore flow:`),t.ol(null,t.li(null,`Replaces the current `,t.code(null,`pb_data`),` with the content from the backup.`),t.li(null,`Triggers app restart.`),t.li(null,`Applies all migrations that are missing in the restored `,t.code(null,`pb_data`),`.`),t.li(null,`Initializes the app server as usual.`))))),t.div({className:`col-lg-12`},t.div({className:`confirm-key-label m-b-sm`},`Type the backup name `,t.div({className:`label`},()=>r.key,app.components.copyButton(()=>r.key)),` to confirm:`),t.div({className:`field`},t.label({htmlFor:n+`_key`},`Backup name`),t.input({id:n+`_key`,name:`key`,type:`text`,required:!0,value:()=>r.keyConfirm,oninput:e=>r.keyConfirm=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>r.isSubmitting},t.span({className:`txt`},`Cancel`)),t.button({"html-form":n,type:`submit`,className:()=>`btn ${r.isSubmitting?`loading`:``}`,disabled:()=>r.isSubmitting||!r.canSubmit},t.span({className:`txt`},`Restore backup`))))}function Ui(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({canBackup:!0,isLoading:!1,isDownloading:{},isDeleting:{},backups:[]});async function a(){i.isLoading=!0;try{i.backups=await app.pb.backups.getFullList(),i.backups.sort((e,n)=>e.modifiedn.modified?-1:0),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){app.modals.confirm(`Do you really want to delete ${e}?`,()=>s(e))}async function s(e){if(!i.isDeleting[e]){i.isDeleting[e]=!0;try{await app.pb.backups.delete(e),a(),app.toasts.success(`Successfully deleted ${e}.`)}catch(e){app.checkApiError(e)}delete i.isDeleting[e]}}async function c(){try{let e=await app.pb.health.check({requestKey:null}),n=i.canBackup;i.canBackup=e?.data?.canBackup||!1,i.canBackup&&n!=i.canBackup&&a()}catch(e){console.warn(`failed to load canBackup checks`,e)}}async function l(e){if(!i.isDownloading[e]){i.isDownloading[e]=!0;try{let n=await app.pb.files.getToken({requestKey:null});app.utils.download(app.pb.backups.getDownloadURL(n,e))}catch(e){app.checkApiError(e)}delete i.isDownloading[e]}}return t.div({pbEvent:`backupsList`,className:`list backups-list`,onmount:e=>{r.push(watch(()=>n.reset,()=>{a()})),e._canBackupIntervalId=setInterval(()=>{c()},3500)},onunmount:e=>{clearInterval(e._canBackupIntervalId),r.forEach(e=>e?.unwatch())}},t.div({className:`list-content`},t.div({hidden:()=>!i.isLoading||i.backups.length,className:`list-item`},t.div({className:`skeleton-loader`})),t.div({hidden:()=>i.isLoading||i.backups.length,className:()=>`list-item`},t.div({className:`content block txt-hint`},`No backups found.`)),()=>i.backups.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.i({className:`ri-folder-zip-line`,ariaHidden:!0}),t.div({className:`content`},t.span({className:`backup-name txt-ellipsis`,title:()=>e.key,textContent:()=>e.key}),t.small({className:`backup-size txt-hint txt-nowrap`},`(`,()=>app.utils.formattedFileSize(e.size),`)`)),t.nav({hidden:()=>i.isLoading,className:`actions autohide`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Download`),className:()=>`btn sm circle secondary transparent ${i.isDownloading[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>l(e.key)},t.i({className:`ri-download-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Restore`),className:()=>`btn sm circle secondary transparent`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>Vi(e.key)},t.i({className:`ri-restart-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Delete`),className:()=>`btn sm circle secondary transparent ${i.isDeleting[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>o(e.key)},t.i({className:`ri-delete-bin-7-line`,ariaHidden:!0})))))),t.div({className:`list-item`},t.button({type:`button`,className:()=>`btn secondary block ${i.isLoading?`loading`:``}`,disabled:()=>!i.canBackup||i.isLoading,onclick:()=>{zi({oncreated:()=>a()})}},()=>i.canBackup?[t.i({className:`ri-play-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Initialize new backup`)]:[t.span({className:`loader sm`}),t.span({className:`txt`},`Backup/restore operation is in process`)])))}function Wi(e=null){let n=`backup_upload_`+app.utils.randomString(),r=store({isUploading:!1});function i(e){e&&app.modals.confirm(`Note that we don't perform validations for the uploaded backup files. Proceed with extreme caution and only if you trust the source.\n\nDo you really want to upload "${e.name}"?`,()=>{a(e)},()=>{o()})}async function a(i){if(!(!i||r.isUploading)){r.isUploading=!0;try{let a=new FormData;a.set(`file`,i),await app.pb.backups.upload(a,{requestKey:n}),r.isUploading=!1,e(i),app.toasts.success(`Successfully uploaded a new backup.`)}catch(e){e.isAbort||(r.isUploading=!1,e.response?.formData?.file?.message?app.toasts.error(e.response.formData.file.message):app.checkApiError(e))}o()}}function o(){s&&(s.value=``)}let s=t.input({type:`file`,accept:`application/zip`,className:`hidden`,onchange:e=>{i(e.target?.files?.[0])}});return t.div(null,t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Upload backup`),className:()=>`btn sm transparent secondary circle ${r.isUploading?`loading`:``}`,disabled:()=>r.isUploading,onclick:()=>s?.click(),onunmount:()=>{app.pb.cancelRequest(n)}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0})),s)}function Gi(e){app.store.title=`Backups`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageBackupsSettings`,className:`page page-backups-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Backup and restore your PocketBase data`),app.components.refreshButton({className:`btn sm transparent secondary circle tooltip-bottom`,onclick:r}),Wi(r)),Ui({reset:()=>n.resetList})),t.div({className:`col-lg-12`},Ri({onsave:()=>r()})))),t.footer({className:`page-footer`},app.components.credits())))}function Ki(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({isLoading:!1,isRunning:{},crons:[]});async function a(){i.isLoading=!0;try{i.crons=await app.pb.crons.getFullList(),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){if(!(!e||i.isRunning[e])){i.isRunning[e]=!0;try{await app.pb.crons.run(e),app.toasts.success(`Successfully triggered "${e}".`),i.isRunning[e]=!1}catch(n){n.isAbort||(ApiClient.error(n),i.isRunning[e]=!1)}}}return t.div({pbEvent:`cronsList`,className:`list`,onmount:()=>{r.push(watch(()=>n.reset,()=>{a()}))},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!i.isLoading||i.crons.length)return;let e=[];for(let n=0;n<4;n++)e.push(t.div({rid:`skeleton_`+n,className:`list-item`},t.div({className:`skeleton-loader`})));return e},t.div({hidden:()=>i.isLoading||i.crons.length,className:`list-item`},t.div({className:`content block txt-hint`},`No registered crons found.`)),()=>i.crons.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.div({className:`content`},t.span({className:`cron-id txt-code txt-ellipsis`,title:()=>e.id,textContent:()=>e.id})),t.small({className:`cron-expression txt-hint txt-nowrap txt-code`},()=>e.expression),t.nav({hidden:()=>i.isLoading,className:`actions`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Run`),className:()=>`btn sm circle secondary transparent ${i.isRunning[e.id]?`loading`:``}`,disabled:()=>i.isRunning[e.id],onclick:()=>o(e.id)},t.i({className:`ri-play-large-line`,ariaHidden:!0}))))))}function qi(e){app.store.title=`Crons`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageCronsSettings`,className:`page`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Registered app cron jobs`),app.components.refreshButton({className:`btn sm transparent secondary circle`,onclick:r})),Ki({reset:()=>n.resetList}),t.div({className:`txt-sm txt-hint m-t-sm`},`App cron jobs can be registered only programmatically with `,t.a({href:`https://pocketbase.io/docs/go-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JavaScript`}),`.`)),t.footer({className:`page-footer`},app.components.credits())))}function Ji(e){app.store.title=`Mail settings`;let n=[{label:`Auto (StartTLS)`,value:!1},{label:`Always`,value:!0}],r=[{label:`PLAIN (default)`,value:`PLAIN`},{label:`LOGIN`,value:`LOGIN`}],i=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,showMoreOptions:!1,get hasChanges(){return i.initSerialized!=JSON.stringify(i.formSettings)}});a();async function a(){i.isLoading=!0;try{s(await app.pb.settings.getAll()),i.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function o(){if(!(i.isSaving||!i.hasChanges)){i.isSaving=!0;try{let e=app.utils.filterRedactedProps(i.formSettings);s(await app.pb.settings.update(e)),app.toasts.success(`Successfully saved mail settings.`)}catch(e){app.checkApiError(e)}i.isSaving=!1}}function s(e={}){app.store.settings=JSON.parse(JSON.stringify(e)),i.formSettings={meta:e?.meta||{},smtp:e?.smtp||{}},i.formSettings.smtp.authMethod||(i.formSettings.smtp.authMethod=r[0].value),i.initSerialized=JSON.stringify(i.formSettings)}function c(){i.formSettings=JSON.parse(i.initSerialized)}return t.div({pbEvent:`pageMailSettings`,className:`page page-mail-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`mailSettingsForm`,className:`grid mail-settings-form`,inert:()=>i.isSaving,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`Configure common settings for sending emails.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderName`},`Sender name`),t.input({id:`meta.senderName`,name:`meta.senderName`,type:`text`,required:!0,value:()=>i.formSettings.meta.senderName||``,oninput:e=>i.formSettings.meta.senderName=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderAddress`},`Sender address`),t.input({id:`meta.senderAddress`,name:`meta.senderAddress`,type:`email`,required:!0,value:()=>i.formSettings.meta.senderAddress||``,oninput:e=>i.formSettings.meta.senderAddress=e.target.value}))),t.div({className:`col-lg-12`},t.div({className:`field`},t.input({id:`smtp.enabled`,name:`smtp.enabled`,type:`checkbox`,className:`switch`,checked:()=>!!i.formSettings.smtp.enabled,onchange:e=>i.formSettings.smtp.enabled=e.target.checked}),t.label({htmlFor:`smtp.enabled`},t.span({className:`txt`},`Use SMTP mail server `,t.strong(null,`(recommended)`)),t.i({className:`ri-information-line link-faded`,ariaDescription:app.attrs.tooltip(`By default PocketBase uses the unix "sendmail" command for sending emails. For better emails deliverability it is recommended to use a SMTP mail server.`)}))),app.components.slide(()=>i.formSettings.smtp.enabled,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-4`},t.div({className:`field`},t.label({htmlFor:`smtp.host`},`SMTP server host`),t.input({id:`smtp.host`,name:`smtp.host`,type:`text`,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.host||``,oninput:e=>i.formSettings.smtp.host=e.target.value}))),t.div({className:`col-lg-2`},t.div({className:`field`},t.label({htmlFor:`smtp.port`},`Port`),t.input({id:`smtp.port`,name:`smtp.port`,type:`number`,min:0,step:1,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.port||``,oninput:e=>i.formSettings.smtp.port=parseInt(e.target.value,10)}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.username`},`Username`),t.input({id:`smtp.username`,name:`smtp.username`,type:`text`,autocomplete:`off`,value:()=>i.formSettings.smtp.username||``,oninput:e=>i.formSettings.smtp.username=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.password`},`Password`),t.input({id:`smtp.password`,name:`smtp.password`,type:`password`,autocomplete:`new-password`,value:()=>i.formSettings.smtp.password||``,oninput:e=>i.formSettings.smtp.password=e.target.value,onkeyup:e=>{e.key==`Backspace`&&i.formSettings.smtp.password===void 0&&(i.formSettings.smtp.password=``)},placeholder:()=>i.formSettings.smtp.password===void 0?`* * * * * *`:``})))),t.button({type:`button`,className:`btn secondary sm m-t-sm`,onclick:()=>i.showMoreOptions=!i.showMoreOptions},t.span({className:`txt`},()=>i.showMoreOptions?`Hide more options`:`Show more options`),t.i({className:()=>i.showMoreOptions?`ri-arrow-drop-up-line`:`ri-arrow-drop-down-line`})),app.components.slide(()=>i.showMoreOptions,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.tls`},`TLS encryption`),app.components.select({id:`smtp.tls`,name:`smtp.tls`,required:!0,options:n,value:()=>i.formSettings.smtp.tls||!1,onchange:e=>{i.formSettings.smtp.tls=e?.[0]?.value}}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.authMethod`},`AUTH method`),app.components.select({id:`smtp.authMethod`,name:`smtp.authMethod`,required:!0,options:r,value:()=>i.formSettings.smtp.authMethod||r[0].value,onchange:e=>{i.formSettings.smtp.authMethod=e?.[0]?.value}}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`smtp.localName`},t.span({className:`txt`},`EHLO/HELO domain`),t.i({className:`ri-information-line link-hint tooltip-top`,ariaDescription:app.attrs.tooltip(`Some SMTP servers, such as the Gmail SMTP-relay, requires a proper domain name in the inital EHLO/HELO exchange and will reject attempts to use localhost.`)})),t.input({id:`smtp.localName`,name:`smtp.localName`,type:`text`,placeholder:`Default to localhost`,value:()=>i.formSettings.smtp.localName||``,oninput:e=>i.formSettings.smtp.localName=e.target.value}))))))),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),()=>i.hasChanges?[t.button({type:`button`,className:`btn transparent secondary`,onclick:c},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${i.isSaving?`loading`:``}`,disabled:()=>!i.hasChanges||i.isSaving},t.span({className:`txt`},`Save changes`))]:t.button({type:`button`,className:()=>`btn expanded-lg outline`,onclick:()=>app.modals.openMailTest()},t.i({className:`ri-mail-check-line`,ariaHidden:!0}),t.span({className:`txt`},`Send test email`)))))),t.footer({className:`page-footer`},app.components.credits())))}var Yi=`pbSQLConsoleHistory`;function Xi(e){app.store.title=`SQL console`;let n=`sql_console_`+app.utils.randomString(),r=n+`editor`,i=n+`executeSQL`,a=store({askedForConfirmationAtLeastOnce:!1,isExecuting:!1,maxRows:250,query:``,result:{},sort:{},errorMsg:``,executedHistory:app.utils.getLocalHistory(Yi,[]),get sortedResultRows(){if(a.sort?.index===void 0){let e=a.result?.rows||[];return a.maxRows>=e.length?e:e.slice(0,a.maxRows)}let e=!!a.sort?.asc,n=a.result?.rows?.toSorted((n,r)=>{let i=n[a.sort.index],o=r[a.sort.index];return e||(i=r[a.sort.index],o=n[a.sort.index]),i==o?0:i==null?-1:o==null?1:i.localeCompare(o)})||[];return a.maxRows>=n.length?n:n.slice(0,a.maxRows)},get totalRemainingRows(){return(a.result?.rows?.length<<0)-a.sortedResultRows.length}});function o(e){return e?.trim()?!a.askedForConfirmationAtLeastOnce&&app.store.settings?.meta?.hideControls?!0:(e=e?.replace(/[\s\;]/gm,` `).toUpperCase()+` `,!![`ALTER `,`REPLACE `,`INSERT `,`CREATE `,`UPDATE `,`DELETE `,`DROP `,`DETACH `,`PRAGMA `].find(n=>e.includes(n))):!1}async function s(){return o(a.query)?(a.askedForConfirmationAtLeastOnce=!0,app.modals.confirm(t.div({className:`txt-center`},t.h6(null,`Be careful and continue only if you really know what you are doing because, depending on the query, the operation could break your application and may not be reversible.`)),()=>c(),null,{yesButton:`Execute`,noButton:`Cancel`})):c()}async function c(){a.isExecuting=!0,a.maxRows=250,a.result={},a.sort={},a.errorMsg=``;let e=a.query.trim();if(!e){app.pb.cancelRequest(i),a.isExecuting=!1;return}try{a.result=await app.pb.sql.run(e,{requestKey:i}),u(e),a.isExecuting=!1}catch(e){e?.isAbort||(a.isExecuting=!1,a.errorMsg=e?.response?.message||e?.message||`Failed to execute query.`)}}function l(e){function n(e){return e.replace(/[\s\;]/gm,``).toUpperCase()}let r=n(e);for(let i=a.executedHistory.length-1;i>=0;i--)(a.executedHistory[i]==e||n(a.executedHistory[i])==r)&&a.executedHistory.splice(i,1)}function u(e){l(e),a.executedHistory.unshift(a.query),a.executedHistory.length>10&&a.executedHistory.splice(10)}function d(){if(!a.sortedResultRows.length)return;let e=[a.result.columns.map(e=>e.name)].concat(a.sortedResultRows),n=`export_`+new Date().toISOString().replace(/[\-\:\.]/g,``)+`.csv`;app.utils.downloadCSV(e,n)}function f(e){a.sort?.index==e?a.sort={index:e,asc:!a.sort.asc}:a.sort={index:e,asc:!0}}let p=[watch(()=>JSON.stringify(a.executedHistory),(e,n)=>{n!==void 0&&window.localStorage.setItem(Yi,e)})];return t.div({pbEvent:`pageSQLConsole`,className:`page`,onunmount:()=>{app.pb.cancelRequest(i),p.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title)),t.div({className:`page-header-secondary-btns`},t.button({type:`button`,className:`btn circle transparent secondary`,ariaDescription:app.attrs.tooltip(`Recently executed queries`,`right`),"html-popovertarget":`sql-console-history-dropdown`},t.i({className:`ri-history-line`,ariaHidden:!0})),t.div({id:`sql-console-history-dropdown`,className:()=>`dropdown left sql-console-history-dropdown ${a.executedHistory.length?``:`no-items`}`,popover:`auto`},()=>a.executedHistory.length?a.executedHistory.map(e=>t.button({role:`button`,className:`dropdown-item`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),a.query=e,document.getElementById(r)?.click()}},t.span({className:`query`},()=>app.utils.truncate(e,500)),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),l(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.span({className:`txt txt-hint p-5`},`No recently executed queries.`))),t.div({className:`page-header-primary-btns`},t.button({type:`button`,className:()=>`btn expanded-lg ${a.isExecuting?`loading`:``}`,disabled:()=>a.isExecuting,onclick:()=>s()},t.i({className:`ri-play-large-line`,ariaHidden:!0}),t.span({className:`txt`},`Execute`)))),t.div({className:`field sql-console-field`},app.components.codeEditor({id:r,language:`sql`,required:!0,name:`query`,placeholder:`e.g. EXPLAIN QUERY PLAN SELECT * from users WHERE verified=true`,value:()=>a.query,oninput:e=>a.query=e,onblur:e=>a.query=e.trim()})),t.div({className:`flex field-help m-b-sm`},t.button({type:`button`,className:`link-hint m-l-auto`,"html-popovertarget":n+`caveats_dropdown`},()=>`SQL console caveats`),t.div({id:n+`caveats_dropdown`,className:`dropdown sm query-caveats-dropdown`,popover:`auto`},t.ul(null,t.li(null,`The returned rows are limited up to 1000.`),t.li(null,`The executed queries have a max timeout of 3 minutes.`),t.li(null,`The data is returned as byte strings without any additional formatting.`),t.li(null,`Multiple queries are supported but only the result of the last one is returned.`)))),t.div({hidden:()=>a.isExecuting||!a.errorMsg,className:`alert danger m-b-sm`},t.pre(null,()=>a.errorMsg)),t.div({hidden:()=>a.isExecuting||a.errorMsg||a.result?.columns?.length||app.utils.isEmpty(a.result),className:`alert success m-b-sm`},t.p({className:`txt-bold`},`Query executed successfully!`),()=>{if(a.result?.affectedRows)return t.p(null,`Affected rows: `,a.result?.affectedRows)}),t.div({hidden:()=>a.isExecuting||!a.result?.columns?.length,className:`page-table-wrapper`},t.table({className:`sql-console-table responsive-table optimize`},t.thead({className:`sticky`},t.tr(null,()=>a.result?.columns?.map((e,n)=>t.th({textContent:e.name,className:()=>{let e=`sort-handle`;return a.sort?.index==n&&(e+=a.sort.asc?` asc`:` desc`),e},onclick:()=>f(n)})))),t.tbody(null,()=>a.sortedResultRows.length?a.sortedResultRows.map(e=>t.tr(null,()=>a.result?.columns?.map((n,r)=>{let i=e[r];return t.td({"html-data-name":n.name},i==null?`NULL`:app.utils.truncate(i,2e3))}))):t.tr(null,t.td({colSpan:a.result?.columns?.length||1,className:`txt-center`},t.span({className:`txt-hint`},`No rows found.`))),t.tr({hidden:()=>a.isExecuting||!a.result?.rows?.length||a.result.rows.length<=a.sortedResultRows.length},t.td({colSpan:99},t.button({type:`button`,className:`btn lg secondary load-more-btn`,onclick:()=>{a.maxRows=a.result?.rows?.length||250}},t.span({className:`txt`,textContent:()=>`Load remaining (${a.totalRemainingRows})`}))))))),t.footer({className:`page-footer`},t.span({className:()=>`exec-time ${a.isExecuting?`faded`:``}`},`Time: `,()=>(a.result?.execTime||0)+`ms`),t.span({hidden:()=>!a.result?.columns?.length,className:()=>`total-count ${a.isExecuting?`faded`:``}`},`Rows: `,()=>a.result?.rows?.length||0,()=>{if(a.result?.rows?.length)return[` (`,t.span({role:`button`,className:`link-hint`,textContent:`Export as CSV`,onclick:d}),`)`]}),app.components.credits())))}function Zi(){app.store.title=`File storage`;let e=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,originalFormSettings:null,get hasChanges(){return e.initSerialized!=JSON.stringify(e.formSettings)}});n();async function n(){e.isLoading=!0;try{i(await app.pb.settings.getAll()),e.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function r(){if(!(e.isSaving||!e.hasChanges)){e.isSaving=!0;try{let n=app.utils.filterRedactedProps(e.formSettings);i(await app.pb.settings.update(n)),app.toasts.success(`Successfully saved storage settings.`)}catch(e){app.checkApiError(e)}e.isSaving=!1}}function i(n={}){app.store.settings=JSON.parse(JSON.stringify(n)),e.formSettings={s3:n?.s3||{}},e.initSerialized=JSON.stringify(e.formSettings),e.originalFormSettings=JSON.parse(e.initSerialized)}function a(){e.formSettings=JSON.parse(e.initSerialized)}return t.div({pbEvent:`pageStorageSettings`,className:`page page-storage-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>e.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`storageSettingsForm`,className:`grid storage-settings-form`,inert:()=>e.isSaving,onsubmit:e=>{e.preventDefault(),r()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`By default PocketBase uses and recommends the local file system to store uploaded files because it is more performant, easier to manage and backup.`),t.p(null,`Alternatively, if you have limited disk space available, you could opt to an S3 compatible external storage.`)),t.div({className:`col-lg-12`},app.components.s3ConfigFields({config:()=>e.formSettings.s3,before:()=>{let n=e.originalFormSettings.s3?.enabled;if(n!=e.formSettings.s3?.enabled)return t.div({className:`alert info m-t-sm`},`If you have existing uploaded files, you'll have to migrate them manually from the `,t.strong(null,n?`S3 storage`:`local file system`),` to the `,t.strong(null,e.formSettings.s3?.enabled?`S3 storage`:`local file system`),`.`,t.br(),`There are several command line tools that can help you, such as: `,t.a({href:`https://github.com/rclone/rclone`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`rclone`}),`, `,t.a({href:`https://github.com/peak/s5cmd`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`s5cmd`}),`, etc.`)}})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!e.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:a},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${e.isSaving?`loading`:``}`,disabled:()=>!e.hasChanges||e.isSaving},t.span({className:`txt`},`Save changes`)))))),t.footer({className:`page-footer`},app.components.credits())))}function Qi(e){app.store.title=`Export collections`;let n=`export_`+app.utils.randomString(),r=store({isLoading:!1,collections:[],bulkSelected:{},get bulkSelectStr(){return JSON.stringify(app.utils.sortedCollectionsByType(Object.values(r.bulkSelected)),null,2)},get totalSelected(){return Object.keys(r.bulkSelected).length},get areAllSelected(){return r.collections.length&&r.collections.length==r.totalSelected}});i();async function i(){r.isLoading=!0;try{let e=await app.pb.collections.getFullList({requestKey:n});for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;r.collections=app.utils.sortedCollectionsByType(e),c(),r.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoading=!1)}}function a(){let e=app.utils.sortedCollectionsByType(Object.values(r.bulkSelected));app.utils.downloadJSON(e,`pb_schema`)}function o(){r.areAllSelected?s():c()}function s(){r.bulkSelected={}}function c(){r.bulkSelected={};for(let e of r.collections)r.bulkSelected[e.id]=e}return t.div({pbEvent:`pageExportCollections`,className:`page page-export-collections`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>r.isLoading?t.div({className:`txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`txt-lg`},`Below you'll find your current collections configuration that you could import in another PocketBase environment.`)),t.div({className:`col-lg-12`},t.div({className:`export-panel`},t.aside({className:`export-list`},t.div({className:`list-item`},t.div({className:`field`},t.input({id:n+`.select_all`,type:`checkbox`,checked:()=>r.areAllSelected,onchange:()=>o()}),t.label({htmlFor:n+`.select_all`},`Select all`))),()=>r.collections.map(e=>{let i=n+`_c_`+e.id;return t.div({className:`list-item`},t.div({className:`field`},t.input({id:i,type:`checkbox`,checked:()=>!!r.bulkSelected[e.id],onchange:n=>{let i=Object.assign({},r.bulkSelected);n.target.__shiftKey&&(n.target.__shiftKey=!1,app.utils.bulkSelectRange(r.collections,i,e,n.target.checked)),n.target.checked?i[e.id]=e:delete i[e.id],r.bulkSelected=i}}),t.label({htmlFor:i,textContent:()=>e.name,onclick:e=>{e.preventDefault();let n=document.getElementById(e.target.htmlFor);n&&(n.__shiftKey=e.shiftKey,n.click())}})))})),t.output({className:`export-preview`},app.components.codeBlock({value:()=>r.bulkSelectStr,language:`plain`}),t.nav({className:`ctrls`},app.components.copyButton(()=>r.bulkSelectStr))))),t.div({className:`col-lg-12 txt-right`},t.button({className:`btn`,onclick:a},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download as JSON`))))),t.footer({className:`page-footer`},app.components.credits())))}function $i(e){app.store.title=`Import collections`;let n=`import_`+app.utils.randomString(),r=[],i=store({rawNewCollections:``,oldCollections:[],newCollections:[],collectionsToUpdate:[],deleteMissing:!0,isLoadingFile:!1,isLoadingOldCollections:!1,mergeWithOldCollections:!1,get isRawValid(){return!!i.rawNewCollections&&i.newCollections?.length>0&&i.newCollections.length==i.newCollections.filter(e=>!!e.id&&!!e.name).length},get collectionsToDelete(){return i.oldCollections.filter(e=>i.isRawValid&&!i.mergeWithOldCollections&&i.deleteMissing&&!i.newCollections.find(n=>n.id==e.id))},get collectionsToAdd(){return i.newCollections.filter(e=>i.isRawValid&&!i.oldCollections.find(n=>n.id==e.id))},get idReplacableCollections(){return i.newCollections.filter(e=>{let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)return!1;if(n.id!=e.id)return!0;let r=Array.isArray(n.fields)?n.fields:[],a=Array.isArray(e.fields)?e.fields:[];for(let e of a){if(r.find(n=>n.id==e.id))continue;let n=r.find(n=>n.name==e.name);if(n&&e.id!=n.id)return!0}return!1})},get hasChanges(){return!!i.rawNewCollections&&!!(i.collectionsToDelete.length||i.collectionsToAdd.length||i.collectionsToUpdate.length)},get canReview(){return!i.isLoadingOldCollections&&i.isRawValid&&i.hasChanges}}),a=t.input({id:n+`_load_json`,type:`file`,className:`hidden`,accept:`.json`,onchange:()=>{d(a.files?.[0])}});o();async function o(){i.isLoadingOldCollections=!0;try{let e=await app.pb.collections.getFullList();for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;i.oldCollections=e,i.isLoadingOldCollections=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoadingOldCollections=!1)}}r.push(watch(()=>i.rawNewCollections,()=>{s()}));function s(){let e=[];try{e=JSON.parse(i.rawNewCollections),e=Array.isArray(e)?app.utils.filterDuplicatesByKey(e):[];for(let n of e)delete n.created,delete n.updated,n.fields&&=app.utils.filterDuplicatesByKey(n.fields)}catch{}i.newCollections=e}r.push(watch(()=>[i.newCollections,i.deleteMissing],()=>{c()}));function c(){if(i.collectionsToUpdate=[],i.isRawValid)for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.id==e.id);!n?.id||!app.utils.hasCollectionChanges(n,e,i.deleteMissing)||i.collectionsToUpdate.push({new:e,old:n})}}function l(){for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)continue;let r=e.id,a=n.id;e.id=a;let o=Array.isArray(n.fields)?n.fields:[],s=Array.isArray(e.fields)?e.fields:[];for(let e of s){let n=o.find(n=>n.name==e.name);n&&n.id&&(e.id=n.id)}for(let e of i.newCollections)if(Array.isArray(e.fields))for(let n of e.fields)n.collectionId&&n.collectionId===r&&(n.collectionId=a);for(let n=0;ne.replace(r,a))}i.rawNewCollections=JSON.stringify(i.newCollections,null,2)}function u(){i.rawNewCollections=``,a.value=``,app.store.errors=null}function d(e){i.isLoadingFile=!0;let n=new FileReader;n.onload=async e=>{i.isLoadingFile=!1,a.value=``,i.rawNewCollections=e.target.result,await new Promise(e=>setTimeout(e,0)),i.newCollections.length||(app.toasts.error(`Invalid collections configuration.`),u())},n.onerror=e=>{app.toasts.error(`Failed to load the imported JSON.`),console.warn(e),i.isLoadingFile=!1,a.value=``},n.readAsText(e)}function f(){let e=i.mergeWithOldCollections?app.utils.filterDuplicatesByKey(i.oldCollections.concat(i.newCollections)):i.newCollections;app.modals.openImportCollectionsReview(i.oldCollections,e,{deleteMissing:i.deleteMissing,onsubmit:()=>{u(),o()}})}return t.div({pbEvent:`pageImportCollections`,className:`page page-import-collections`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoadingOldCollections?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.span({className:`txt-lg m-r-5`},`Paste below the collections configuration you want to import or`),t.label({htmlFor:a.id,className:()=>`btn sm outline ${i.isLoadingFile?`loading`:``}`},t.span({className:`txt`},`Load from JSON file`)),a,t.p({className:`txt-hint`},t.em(null,`You can use the `,t.a({href:`https://pocketbase.io/docs/go-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JS`}),` migrations to manage your collections programmatically in more granular and version controlled manner.`))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:n+`_collections_field`},`Collections`),t.textarea({id:n+`_collections_field`,name:`collections`,rows:12,className:`txt-code`,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,value:()=>i.rawNewCollections,oninput:e=>i.rawNewCollections=e.target.value})),t.div({className:()=>`field-help error ${i.rawNewCollections&&!i.isRawValid?``:`hidden`}`},`Invalid collections configuration.`)),t.div({className:()=>`col-lg-12 ${i.isRawValid?``:`hidden`}`},t.div({className:`field`},t.input({id:n+`_merge_checkbox`,type:`checkbox`,className:`switch`,checked:()=>i.mergeWithOldCollections,onchange:e=>i.mergeWithOldCollections=e.target.checked}),t.label({htmlFor:n+`_merge_checkbox`},`Merge with the existing collections`))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&!i.hasChanges?``:`hidden`}`},t.div({className:`alert info`},t.div({className:`content`},t.p(null,`Your collections configuration is already up-to-date!`)))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&i.hasChanges?``:`hidden`}`},t.p({className:`txt-hint txt-bold`},`Detected changes`),t.div({className:`list`},()=>i.collectionsToDelete.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))),()=>i.collectionsToUpdate.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(e.old.name!=e.new.name)return[t.span({className:`txt-strikethrough txt-hint`,textContent:e.old.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>e.new.name}),t.small({className:()=>`txt-hint ${e.new.id?``:`hidden`}`,textContent:()=>e.new.id})))),()=>i.collectionsToAdd.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label success`,textContent:`Added`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))))),t.div({className:()=>`col-lg-12 ${i.idReplacableCollections?.length?``:`hidden`}`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Some of the imported collections share the same name and/or fields but are imported with different IDs.`),t.p(null,`You can replace them in the import if you want to:`,t.button({type:`button`,className:`btn warning sm m-l-10`,textContent:`Replace with original IDs`,onclick:l}))))),t.div({className:`col-lg-12`},t.div({className:`flex`},t.button({type:`button`,className:()=>`btn secondary ${i.rawNewCollections?``:`hidden`}`,onclick:u},t.span({className:`txt`},`Clear`)),t.button({type:`button`,className:`btn expanded-lg m-l-auto`,disabled:()=>!i.canReview,onclick:f},t.span({className:`txt`},`Review`)))))),t.footer({className:`page-footer`},app.components.credits())))}window.app=window.app||{},window.app.routes=window.app.routes||{},window.app.routes.fallbackPath=`#/collections`,app.routes.guestOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(app.pb.authStore.isValid&&app.pb.authStore.record?.id){window.location.hash=`#/`;return}app.store.showHeader=!1,app.store.page=await n(e)}},app.routes.superuserOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(!app.pb.authStore.isValid||!app.pb.authStore.record?.id){window.location.hash=`#/login`;return}app.store.showHeader=!0,app.store.page=await n(e)}},app.routes.blank=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{app.store.showHeader=!1,app.store.page=await n(e)}};var ea={},ta;function na(){ta&&ta(),ta=router(ea,{fallbackPath:app.routes.fallbackPath})}app.routes.guestOnly(`#/pbinstall/{token}`,async e=>{let{pageInstaller:n}=await G(async()=>{let{pageInstaller:e}=await import(`./pageInstaller-2TD7r9Pz.js`);return{pageInstaller:e}},[],import.meta.url);return n(e)}),app.routes.guestOnly(`#/login`,e=>$r(e)),app.routes.guestOnly(`#/request-password-reset`,async e=>{let{pageRequestSuperuserPasswordReset:n}=await G(async()=>{let{pageRequestSuperuserPasswordReset:e}=await import(`./pageRequestSuperuserPasswordReset-C39AMhGf.js`);return{pageRequestSuperuserPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-password-reset/{token}`,async e=>{let{pageConfirmPasswordReset:n}=await G(async()=>{let{pageConfirmPasswordReset:e}=await import(`./pageConfirmPasswordReset-UQX1jz2S.js`);return{pageConfirmPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-verification/{token}`,async e=>{let{pageConfirmVerification:n}=await G(async()=>{let{pageConfirmVerification:e}=await import(`./pageConfirmVerification-Bc6dMZfz.js`);return{pageConfirmVerification:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-email-change/{token}`,async e=>{let{pageConfirmEmailChange:n}=await G(async()=>{let{pageConfirmEmailChange:e}=await import(`./pageConfirmEmailChange-l_DOk6UT.js`);return{pageConfirmEmailChange:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-success`,async e=>{let{pageOAuth2RedirectSuccess:n}=await G(async()=>{let{pageOAuth2RedirectSuccess:e}=await import(`./pageOAuth2RedirectSuccess-DmZV1eyz.js`);return{pageOAuth2RedirectSuccess:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-failure`,async e=>{let{pageOAuth2RedirectFailure:n}=await G(async()=>{let{pageOAuth2RedirectFailure:e}=await import(`./pageOAuth2RedirectFailure-CRvz4PXa.js`);return{pageOAuth2RedirectFailure:e}},[],import.meta.url);return n(e)}),app.routes.superuserOnly(`#/collections`,hi),app.routes.superuserOnly(`#/logs`,Ei),app.routes.superuserOnly(`#/settings`,Ii),app.routes.superuserOnly(`#/settings/mail`,Ji),app.routes.superuserOnly(`#/settings/storage`,Zi),app.routes.superuserOnly(`#/settings/backups`,Gi),app.routes.superuserOnly(`#/settings/crons`,qi),app.routes.superuserOnly(`#/settings/export-collections`,Qi),app.routes.superuserOnly(`#/settings/import-collections`,$i),app.routes.superuserOnly(`#/settings/sql`,Xi);var ra=t;t=new Proxy({},{get(e,n){return function(){let e=arguments?.[0];if(e&&e.pbEvent){let n=e.onmount;e.onmount=r=>{n?.(r),r.dataset.pb=e.pbEvent,document.dispatchEvent(new CustomEvent(`mount:`+e.pbEvent,{detail:r}))};let r=e.onunmount;e.onunmount=n=>{document.dispatchEvent(new CustomEvent(`unmount:`+e.pbEvent,{detail:n})),r?.(n)}}return ra[n](...arguments)}}}),document.body.prepend(t.main({"html-class":`app`,className:()=>`app ${app.store.settings?.meta?.hideControls?`hide-controls`:``}`},Fe(),e=>(typeof app.store.page==`function`&&app.store.page(e),app.store.page))),watch(()=>app.store._ready,e=>{e&&na()}),document.body.appendChild(t.script({type:`module`,src:app.pb.buildURL(`/_/extensions.js`),onload:()=>{app.store._ready=!0},onerror:e=>{console.warn(`Failed to load extensions:`,e),app.store._ready=!0}}));export{S as n,se as r,Ee as t}; \ No newline at end of file +@hourly`)},`macros`),`.`,t.br(),`By default the timezone is in UTC.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`backups.cronMaxKeep`},`Max @auto backups to keep`),t.input({id:`backups.cronMaxKeep`,name:`backups.cronMaxKeep`,type:`number`,required:()=>a.enableAutoBackups,min:1,value:()=>a.formSettings.backups.cronMaxKeep,oninput:e=>{a.formSettings.backups.cronMaxKeep=parseInt(e.target.value,10)}})))))),t.div({className:`col-lg-12`},app.components.s3ConfigFields({toggleLabel:`Store backups in S3 storage`,testFilesystem:`backups`,config:()=>a.formSettings.backups.s3})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!a.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:l},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${a.isSaving?`loading`:``}`,disabled:()=>!a.hasChanges||a.isSaving},t.span({className:`txt`},`Save changes`))))])))}function zi(e={oncreated:null}){let n=Bi(e);n&&(document.body.appendChild(n),app.modals.open(n))}function Bi(e){let n,r=`backup_create_`+app.utils.randomString(),i=store({name:``,isSubmitting:!1}),a;async function o(){if(!i.isSubmitting){i.isSubmitting=!0,clearTimeout(a),a=setTimeout(()=>{app.modals.close(n)},1500);try{await app.pb.backups.create(i.name,{requestKey:r}),i.isSubmitting=!1,e.oncreated&&e.oncreated(i.name),app.toasts.success(`Successfully generated new backup.`),app.modals.close(n)}catch(e){e.isAbort||(clearTimeout(a),i.isSubmitting=!1,app.checkApiError(e))}}}return n=t.div({pbEvent:`backupCreateModal`,className:`modal popup backup-create-modal`,onbeforeclose:()=>{i.isSubmitting&&app.toasts.info(`The backup was started but may take a while to complete. You can come back later.`)},onafterclose:e=>{clearTimeout(a),e?.remove()}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Initialize new backup`)),t.form({id:r,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Please note that during the backup other concurrent write requests may fail since the database will be temporary "locked" (this usually happens only during the ZIP generation).`),t.p({className:`txt-bold`},`If you are using S3 storage for the collections file upload, you'll have to backup them separately since they are not locally stored and they will not be included in the generated backup!`)))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`_name`},`Backup name`),t.input({id:r+`_name`,name:`name`,type:`text`,pattern:`^[a-z0-9_-]+.zip$`,placeholder:`Leave empty to autogenerate`,value:()=>i.name,oninput:e=>i.name=e.target.value})),t.div({className:`field-help`},`Must be in the format [a-z0-9_-].zip`)))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>i.isSubmitting,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Cancel`)),t.button({"html-form":r,type:`submit`,className:()=>`btn ${i.isSubmitting?`loading`:``}`,disabled:()=>i.isSubmitting},t.span({className:`txt`},`Start backup`)))),n}function Vi(e){let n=Hi(e);document.body.appendChild(n),app.modals.open(n)}function Hi(e){let n=`backup_restore_`+app.utils.randomString(),r=store({key:e,keyConfirm:``,isSubmitting:!1,get canSubmit(){return r.key&&r.key==r.keyConfirm}}),i;async function a(){if(!(r.isSubmitting||!r.canSubmit)){clearTimeout(i),r.isSubmitting=!0;try{await app.pb.backups.restore(r.keyConfirm),i=setTimeout(()=>{window.location.reload(),r.isSubmitting=!1},2e3)}catch(e){clearTimeout(i),e?.isAbort||(r.isSubmitting=!1,app.checkApiError(e))}}}return t.div({pbEvent:`backupRestoreModal`,className:`modal popup backup-restore-modal`,onbeforeclose:()=>!r.isSubmitting,onafterclose:e=>{e?.remove()},onunmount:()=>{clearTimeout(i)}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Restore `,t.strong(null,()=>r.key))),t.form({id:n,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert danger`},t.div({className:`content`},t.p({className:`txt-bold`},`Please proceed with extreme caution and use it only with trusted backups!`),t.p(null,`Backup restore currently works only on UNIX based systems.`),t.p(null,`The restore operation will attempt to replace your existing `,t.code(null,`pb_data`),` with the one from the backup and will restart the application process.`),t.p(null,`This means that on success all of your data (including app settings, users, superusers, etc.) will be replaced with the ones from the backup.`),t.p(null,`The operation will be reverted if the backup is invalid (ex. missing `,t.code(null,`data.db`),` file).`),t.p(null,`Below is an oversimplified version of the restore flow:`),t.ol(null,t.li(null,`Replaces the current `,t.code(null,`pb_data`),` with the content from the backup.`),t.li(null,`Triggers app restart.`),t.li(null,`Applies all migrations that are missing in the restored `,t.code(null,`pb_data`),`.`),t.li(null,`Initializes the app server as usual.`))))),t.div({className:`col-lg-12`},t.div({className:`confirm-key-label m-b-sm`},`Type the backup name `,t.div({className:`label`},()=>r.key,app.components.copyButton(()=>r.key)),` to confirm:`),t.div({className:`field`},t.label({htmlFor:n+`_key`},`Backup name`),t.input({id:n+`_key`,name:`key`,type:`text`,required:!0,value:()=>r.keyConfirm,oninput:e=>r.keyConfirm=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>r.isSubmitting},t.span({className:`txt`},`Cancel`)),t.button({"html-form":n,type:`submit`,className:()=>`btn ${r.isSubmitting?`loading`:``}`,disabled:()=>r.isSubmitting||!r.canSubmit},t.span({className:`txt`},`Restore backup`))))}function Ui(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({canBackup:!0,isLoading:!1,isDownloading:{},isDeleting:{},backups:[]});async function a(){i.isLoading=!0;try{i.backups=await app.pb.backups.getFullList(),i.backups.sort((e,n)=>e.modifiedn.modified?-1:0),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){app.modals.confirm(`Do you really want to delete ${e}?`,()=>s(e))}async function s(e){if(!i.isDeleting[e]){i.isDeleting[e]=!0;try{await app.pb.backups.delete(e),a(),app.toasts.success(`Successfully deleted ${e}.`)}catch(e){app.checkApiError(e)}delete i.isDeleting[e]}}async function c(){try{let e=await app.pb.health.check({requestKey:null}),n=i.canBackup;i.canBackup=e?.data?.canBackup||!1,i.canBackup&&n!=i.canBackup&&a()}catch(e){console.warn(`failed to load canBackup checks`,e)}}async function l(e){if(!i.isDownloading[e]){i.isDownloading[e]=!0;try{let n=await app.pb.files.getToken({requestKey:null});app.utils.download(app.pb.backups.getDownloadURL(n,e))}catch(e){app.checkApiError(e)}delete i.isDownloading[e]}}return t.div({pbEvent:`backupsList`,className:`list backups-list`,onmount:e=>{r.push(watch(()=>n.reset,()=>{a()})),e._canBackupIntervalId=setInterval(()=>{c()},3500)},onunmount:e=>{clearInterval(e._canBackupIntervalId),r.forEach(e=>e?.unwatch())}},t.div({className:`list-content`},t.div({hidden:()=>!i.isLoading||i.backups.length,className:`list-item`},t.div({className:`skeleton-loader`})),t.div({hidden:()=>i.isLoading||i.backups.length,className:()=>`list-item`},t.div({className:`content block txt-hint`},`No backups found.`)),()=>i.backups.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.i({className:`ri-folder-zip-line`,ariaHidden:!0}),t.div({className:`content`},t.span({className:`backup-name txt-ellipsis`,title:()=>e.key,textContent:()=>e.key}),t.small({className:`backup-size txt-hint txt-nowrap`},`(`,()=>app.utils.formattedFileSize(e.size),`)`)),t.nav({hidden:()=>i.isLoading,className:`actions autohide`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Download`),className:()=>`btn sm circle secondary transparent ${i.isDownloading[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>l(e.key)},t.i({className:`ri-download-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Restore`),className:()=>`btn sm circle secondary transparent`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>Vi(e.key)},t.i({className:`ri-restart-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Delete`),className:()=>`btn sm circle secondary transparent ${i.isDeleting[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>o(e.key)},t.i({className:`ri-delete-bin-7-line`,ariaHidden:!0})))))),t.div({className:`list-item`},t.button({type:`button`,className:()=>`btn secondary block ${i.isLoading?`loading`:``}`,disabled:()=>!i.canBackup||i.isLoading,onclick:()=>{zi({oncreated:()=>a()})}},()=>i.canBackup?[t.i({className:`ri-play-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Initialize new backup`)]:[t.span({className:`loader sm`}),t.span({className:`txt`},`Backup/restore operation is in process`)])))}function Wi(e=null){let n=`backup_upload_`+app.utils.randomString(),r=store({isUploading:!1});function i(e){e&&app.modals.confirm(`Note that we don't perform validations for the uploaded backup files. Proceed with extreme caution and only if you trust the source.\n\nDo you really want to upload "${e.name}"?`,()=>{a(e)},()=>{o()})}async function a(i){if(!(!i||r.isUploading)){r.isUploading=!0;try{let a=new FormData;a.set(`file`,i),await app.pb.backups.upload(a,{requestKey:n}),r.isUploading=!1,e(i),app.toasts.success(`Successfully uploaded a new backup.`)}catch(e){e.isAbort||(r.isUploading=!1,e.response?.formData?.file?.message?app.toasts.error(e.response.formData.file.message):app.checkApiError(e))}o()}}function o(){s&&(s.value=``)}let s=t.input({type:`file`,accept:`application/zip`,className:`hidden`,onchange:e=>{i(e.target?.files?.[0])}});return t.div(null,t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Upload backup`),className:()=>`btn sm transparent secondary circle ${r.isUploading?`loading`:``}`,disabled:()=>r.isUploading,onclick:()=>s?.click(),onunmount:()=>{app.pb.cancelRequest(n)}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0})),s)}function Gi(e){app.store.title=`Backups`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageBackupsSettings`,className:`page page-backups-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Backup and restore your PocketBase data`),app.components.refreshButton({className:`btn sm transparent secondary circle tooltip-bottom`,onclick:r}),Wi(r)),Ui({reset:()=>n.resetList})),t.div({className:`col-lg-12`},Ri({onsave:()=>r()})))),t.footer({className:`page-footer`},app.components.credits())))}function Ki(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({isLoading:!1,isRunning:{},crons:[]});async function a(){i.isLoading=!0;try{i.crons=await app.pb.crons.getFullList(),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){if(!(!e||i.isRunning[e])){i.isRunning[e]=!0;try{await app.pb.crons.run(e),app.toasts.success(`Successfully triggered "${e}".`),i.isRunning[e]=!1}catch(n){n.isAbort||(ApiClient.error(n),i.isRunning[e]=!1)}}}return t.div({pbEvent:`cronsList`,className:`list`,onmount:()=>{r.push(watch(()=>n.reset,()=>{a()}))},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!i.isLoading||i.crons.length)return;let e=[];for(let n=0;n<4;n++)e.push(t.div({rid:`skeleton_`+n,className:`list-item`},t.div({className:`skeleton-loader`})));return e},t.div({hidden:()=>i.isLoading||i.crons.length,className:`list-item`},t.div({className:`content block txt-hint`},`No registered crons found.`)),()=>i.crons.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.div({className:`content`},t.span({className:`cron-id txt-code txt-ellipsis`,title:()=>e.id,textContent:()=>e.id})),t.small({className:`cron-expression txt-hint txt-nowrap txt-code`},()=>e.expression),t.nav({hidden:()=>i.isLoading,className:`actions`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Run`),className:()=>`btn sm circle secondary transparent ${i.isRunning[e.id]?`loading`:``}`,disabled:()=>i.isRunning[e.id],onclick:()=>o(e.id)},t.i({className:`ri-play-large-line`,ariaHidden:!0}))))))}function qi(e){app.store.title=`Crons`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageCronsSettings`,className:`page`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Registered app cron jobs`),app.components.refreshButton({className:`btn sm transparent secondary circle`,onclick:r})),Ki({reset:()=>n.resetList}),t.div({className:`txt-sm txt-hint m-t-sm`},`App cron jobs can be registered only programmatically with `,t.a({href:`https://pocketbase.io/docs/go-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JavaScript`}),`.`)),t.footer({className:`page-footer`},app.components.credits())))}function Ji(e){app.store.title=`Mail settings`;let n=[{label:`Auto (StartTLS)`,value:!1},{label:`Always`,value:!0}],r=[{label:`PLAIN (default)`,value:`PLAIN`},{label:`LOGIN`,value:`LOGIN`}],i=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,showMoreOptions:!1,get hasChanges(){return i.initSerialized!=JSON.stringify(i.formSettings)}});a();async function a(){i.isLoading=!0;try{s(await app.pb.settings.getAll()),i.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function o(){if(!(i.isSaving||!i.hasChanges)){i.isSaving=!0;try{let e=app.utils.filterRedactedProps(i.formSettings);s(await app.pb.settings.update(e)),app.toasts.success(`Successfully saved mail settings.`)}catch(e){app.checkApiError(e)}i.isSaving=!1}}function s(e={}){app.store.settings=JSON.parse(JSON.stringify(e)),i.formSettings={meta:e?.meta||{},smtp:e?.smtp||{}},i.formSettings.smtp.authMethod||(i.formSettings.smtp.authMethod=r[0].value),i.initSerialized=JSON.stringify(i.formSettings)}function c(){i.formSettings=JSON.parse(i.initSerialized)}return t.div({pbEvent:`pageMailSettings`,className:`page page-mail-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`mailSettingsForm`,className:`grid mail-settings-form`,inert:()=>i.isSaving,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`Configure common settings for sending emails.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderName`},`Sender name`),t.input({id:`meta.senderName`,name:`meta.senderName`,type:`text`,required:!0,value:()=>i.formSettings.meta.senderName||``,oninput:e=>i.formSettings.meta.senderName=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderAddress`},`Sender address`),t.input({id:`meta.senderAddress`,name:`meta.senderAddress`,type:`email`,required:!0,value:()=>i.formSettings.meta.senderAddress||``,oninput:e=>i.formSettings.meta.senderAddress=e.target.value}))),t.div({className:`col-lg-12`},t.div({className:`field`},t.input({id:`smtp.enabled`,name:`smtp.enabled`,type:`checkbox`,className:`switch`,checked:()=>!!i.formSettings.smtp.enabled,onchange:e=>i.formSettings.smtp.enabled=e.target.checked}),t.label({htmlFor:`smtp.enabled`},t.span({className:`txt`},`Use SMTP mail server `,t.strong(null,`(recommended)`)),t.i({className:`ri-information-line link-faded`,ariaDescription:app.attrs.tooltip(`By default PocketBase uses the unix "sendmail" command for sending emails. For better emails deliverability it is recommended to use a SMTP mail server.`)}))),app.components.slide(()=>i.formSettings.smtp.enabled,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-4`},t.div({className:`field`},t.label({htmlFor:`smtp.host`},`SMTP server host`),t.input({id:`smtp.host`,name:`smtp.host`,type:`text`,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.host||``,oninput:e=>i.formSettings.smtp.host=e.target.value}))),t.div({className:`col-lg-2`},t.div({className:`field`},t.label({htmlFor:`smtp.port`},`Port`),t.input({id:`smtp.port`,name:`smtp.port`,type:`number`,min:0,step:1,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.port||``,oninput:e=>i.formSettings.smtp.port=parseInt(e.target.value,10)}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.username`},`Username`),t.input({id:`smtp.username`,name:`smtp.username`,type:`text`,autocomplete:`off`,value:()=>i.formSettings.smtp.username||``,oninput:e=>i.formSettings.smtp.username=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.password`},`Password`),t.input({id:`smtp.password`,name:`smtp.password`,type:`password`,autocomplete:`new-password`,value:()=>i.formSettings.smtp.password||``,oninput:e=>i.formSettings.smtp.password=e.target.value,onkeyup:e=>{e.key==`Backspace`&&i.formSettings.smtp.password===void 0&&(i.formSettings.smtp.password=``)},placeholder:()=>i.formSettings.smtp.password===void 0?`* * * * * *`:``})))),t.button({type:`button`,className:`btn secondary sm m-t-sm`,onclick:()=>i.showMoreOptions=!i.showMoreOptions},t.span({className:`txt`},()=>i.showMoreOptions?`Hide more options`:`Show more options`),t.i({className:()=>i.showMoreOptions?`ri-arrow-drop-up-line`:`ri-arrow-drop-down-line`})),app.components.slide(()=>i.showMoreOptions,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.tls`},`TLS encryption`),app.components.select({id:`smtp.tls`,name:`smtp.tls`,required:!0,options:n,value:()=>i.formSettings.smtp.tls||!1,onchange:e=>{i.formSettings.smtp.tls=e?.[0]?.value}}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.authMethod`},`AUTH method`),app.components.select({id:`smtp.authMethod`,name:`smtp.authMethod`,required:!0,options:r,value:()=>i.formSettings.smtp.authMethod||r[0].value,onchange:e=>{i.formSettings.smtp.authMethod=e?.[0]?.value}}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`smtp.localName`},t.span({className:`txt`},`EHLO/HELO domain`),t.i({className:`ri-information-line link-hint tooltip-top`,ariaDescription:app.attrs.tooltip(`Some SMTP servers, such as the Gmail SMTP-relay, requires a proper domain name in the inital EHLO/HELO exchange and will reject attempts to use localhost.`)})),t.input({id:`smtp.localName`,name:`smtp.localName`,type:`text`,placeholder:`Default to localhost`,value:()=>i.formSettings.smtp.localName||``,oninput:e=>i.formSettings.smtp.localName=e.target.value}))))))),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),()=>i.hasChanges?[t.button({type:`button`,className:`btn transparent secondary`,onclick:c},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${i.isSaving?`loading`:``}`,disabled:()=>!i.hasChanges||i.isSaving},t.span({className:`txt`},`Save changes`))]:t.button({type:`button`,className:()=>`btn expanded-lg outline`,onclick:()=>app.modals.openMailTest()},t.i({className:`ri-mail-check-line`,ariaHidden:!0}),t.span({className:`txt`},`Send test email`)))))),t.footer({className:`page-footer`},app.components.credits())))}var Yi=`pbSQLConsoleHistory`;function Xi(e){app.store.title=`SQL console`;let n=`sql_console_`+app.utils.randomString(),r=n+`editor`,i=n+`executeSQL`,a=store({askedForConfirmationAtLeastOnce:!1,isExecuting:!1,maxRows:250,query:``,result:{},sort:{},errorMsg:``,executedHistory:app.utils.getLocalHistory(Yi,[]),get sortedResultRows(){if(a.sort?.index===void 0){let e=a.result?.rows||[];return a.maxRows>=e.length?e:e.slice(0,a.maxRows)}let e=!!a.sort?.asc,n=a.result?.rows?.toSorted((n,r)=>{let i=n[a.sort.index],o=r[a.sort.index];return e||(i=r[a.sort.index],o=n[a.sort.index]),i==o?0:i==null?-1:o==null?1:i.localeCompare(o)})||[];return a.maxRows>=n.length?n:n.slice(0,a.maxRows)},get totalRemainingRows(){return(a.result?.rows?.length<<0)-a.sortedResultRows.length}});function o(e){return e?.trim()?!a.askedForConfirmationAtLeastOnce&&app.store.settings?.meta?.hideControls?!0:(e=e?.replace(/[\s\;]/gm,` `).toUpperCase()+` `,!![`ALTER `,`REPLACE `,`INSERT `,`CREATE `,`UPDATE `,`DELETE `,`DROP `,`DETACH `,`PRAGMA `].find(n=>e.includes(n))):!1}async function s(){return o(a.query)?(a.askedForConfirmationAtLeastOnce=!0,app.modals.confirm(t.div({className:`txt-center`},t.h6(null,`Be careful and continue only if you really know what you are doing because, depending on the query, the operation could break your application and may not be reversible.`)),()=>c(),null,{yesButton:`Execute`,noButton:`Cancel`})):c()}async function c(){a.isExecuting=!0,a.maxRows=250,a.result={},a.sort={},a.errorMsg=``;let e=a.query.trim();if(!e){app.pb.cancelRequest(i),a.isExecuting=!1;return}try{a.result=await app.pb.sql.run(e,{requestKey:i}),u(e),a.isExecuting=!1}catch(e){e?.isAbort||(a.isExecuting=!1,a.errorMsg=e?.response?.message||e?.message||`Failed to execute query.`)}}function l(e){function n(e){return e.replace(/[\s\;]/gm,``).toUpperCase()}let r=n(e);for(let i=a.executedHistory.length-1;i>=0;i--)(a.executedHistory[i]==e||n(a.executedHistory[i])==r)&&a.executedHistory.splice(i,1)}function u(e){l(e),a.executedHistory.unshift(a.query),a.executedHistory.length>10&&a.executedHistory.splice(10)}function d(){if(!a.sortedResultRows.length)return;let e=[a.result.columns.map(e=>e.name)].concat(a.sortedResultRows),n=`export_`+new Date().toISOString().replace(/[\-\:\.]/g,``)+`.csv`;app.utils.downloadCSV(e,n)}function f(e){a.sort?.index==e?a.sort={index:e,asc:!a.sort.asc}:a.sort={index:e,asc:!0}}let p=[watch(()=>JSON.stringify(a.executedHistory),(e,n)=>{n!==void 0&&window.localStorage.setItem(Yi,e)})];return t.div({pbEvent:`pageSQLConsole`,className:`page`,onunmount:()=>{app.pb.cancelRequest(i),p.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title)),t.div({className:`page-header-secondary-btns`},t.button({type:`button`,className:`btn circle transparent secondary`,ariaDescription:app.attrs.tooltip(`Recently executed queries`,`right`),"html-popovertarget":`sql-console-history-dropdown`},t.i({className:`ri-history-line`,ariaHidden:!0})),t.div({id:`sql-console-history-dropdown`,className:()=>`dropdown left sql-console-history-dropdown ${a.executedHistory.length?``:`no-items`}`,popover:`auto`},()=>a.executedHistory.length?a.executedHistory.map(e=>t.button({role:`button`,className:`dropdown-item`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),a.query=e,document.getElementById(r)?.click()}},t.span({className:`query`},()=>app.utils.truncate(e,500)),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),l(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.span({className:`txt txt-hint p-5`},`No recently executed queries.`))),t.div({className:`page-header-primary-btns`},t.button({type:`button`,className:()=>`btn expanded-lg ${a.isExecuting?`loading`:``}`,disabled:()=>a.isExecuting,onclick:()=>s()},t.i({className:`ri-play-large-line`,ariaHidden:!0}),t.span({className:`txt`},`Execute`)))),t.div({className:`field sql-console-field`},app.components.codeEditor({id:r,language:`sql`,required:!0,name:`query`,placeholder:`e.g. EXPLAIN QUERY PLAN SELECT * from users WHERE verified=true`,value:()=>a.query,oninput:e=>a.query=e,onblur:e=>a.query=e.trim()})),t.div({className:`flex field-help m-b-sm`},t.button({type:`button`,className:`link-hint m-l-auto`,"html-popovertarget":n+`caveats_dropdown`},()=>`SQL console caveats`),t.div({id:n+`caveats_dropdown`,className:`dropdown sm query-caveats-dropdown`,popover:`auto`},t.ul(null,t.li(null,`The returned rows are limited up to 1000.`),t.li(null,`The executed queries have a max timeout of 3 minutes.`),t.li(null,`The data is returned as byte strings without any additional formatting.`),t.li(null,`Multiple queries are supported but only the result of the last one is returned.`)))),t.div({hidden:()=>a.isExecuting||!a.errorMsg,className:`alert danger m-b-sm`},t.pre(null,()=>a.errorMsg)),t.div({hidden:()=>a.isExecuting||a.errorMsg||a.result?.columns?.length||app.utils.isEmpty(a.result),className:`alert success m-b-sm`},t.p({className:`txt-bold`},`Query executed successfully!`),()=>{if(a.result?.affectedRows)return t.p(null,`Affected rows: `,a.result?.affectedRows)}),t.div({hidden:()=>a.isExecuting||!a.result?.columns?.length,className:`page-table-wrapper`},t.table({className:`sql-console-table responsive-table optimize`},t.thead({className:`sticky`},t.tr(null,()=>a.result?.columns?.map((e,n)=>t.th({textContent:e.name,className:()=>{let e=`sort-handle`;return a.sort?.index==n&&(e+=a.sort.asc?` asc`:` desc`),e},onclick:()=>f(n)})))),t.tbody(null,()=>a.sortedResultRows.length?a.sortedResultRows.map(e=>t.tr(null,()=>a.result?.columns?.map((n,r)=>{let i=e[r];return t.td({"html-data-name":n.name},i==null?`NULL`:app.utils.truncate(i,2e3))}))):t.tr(null,t.td({colSpan:a.result?.columns?.length||1,className:`txt-center`},t.span({className:`txt-hint`},`No rows found.`))),t.tr({hidden:()=>a.isExecuting||!a.result?.rows?.length||a.result.rows.length<=a.sortedResultRows.length},t.td({colSpan:99},t.button({type:`button`,className:`btn lg secondary load-more-btn`,onclick:()=>{a.maxRows=a.result?.rows?.length||250}},t.span({className:`txt`,textContent:()=>`Load remaining (${a.totalRemainingRows})`}))))))),t.footer({className:`page-footer`},t.span({className:()=>`exec-time ${a.isExecuting?`faded`:``}`},`Time: `,()=>(a.result?.execTime||0)+`ms`),t.span({hidden:()=>!a.result?.columns?.length,className:()=>`total-count ${a.isExecuting?`faded`:``}`},`Rows: `,()=>a.result?.rows?.length||0,()=>{if(a.result?.rows?.length)return[` (`,t.span({role:`button`,className:`link-hint`,textContent:`Export as CSV`,onclick:d}),`)`]}),app.components.credits())))}function Zi(){app.store.title=`File storage`;let e=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,originalFormSettings:null,get hasChanges(){return e.initSerialized!=JSON.stringify(e.formSettings)}});n();async function n(){e.isLoading=!0;try{i(await app.pb.settings.getAll()),e.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function r(){if(!(e.isSaving||!e.hasChanges)){e.isSaving=!0;try{let n=app.utils.filterRedactedProps(e.formSettings);i(await app.pb.settings.update(n)),app.toasts.success(`Successfully saved storage settings.`)}catch(e){app.checkApiError(e)}e.isSaving=!1}}function i(n={}){app.store.settings=JSON.parse(JSON.stringify(n)),e.formSettings={s3:n?.s3||{}},e.initSerialized=JSON.stringify(e.formSettings),e.originalFormSettings=JSON.parse(e.initSerialized)}function a(){e.formSettings=JSON.parse(e.initSerialized)}return t.div({pbEvent:`pageStorageSettings`,className:`page page-storage-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>e.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`storageSettingsForm`,className:`grid storage-settings-form`,inert:()=>e.isSaving,onsubmit:e=>{e.preventDefault(),r()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`By default PocketBase uses and recommends the local file system to store uploaded files because it is more performant, easier to manage and backup.`),t.p(null,`Alternatively, if you have limited disk space available, you could opt to an S3 compatible external storage.`)),t.div({className:`col-lg-12`},app.components.s3ConfigFields({config:()=>e.formSettings.s3,before:()=>{let n=e.originalFormSettings.s3?.enabled;if(n!=e.formSettings.s3?.enabled)return t.div({className:`alert info m-t-sm`},`If you have existing uploaded files, you'll have to migrate them manually from the `,t.strong(null,n?`S3 storage`:`local file system`),` to the `,t.strong(null,e.formSettings.s3?.enabled?`S3 storage`:`local file system`),`.`,t.br(),`There are several command line tools that can help you, such as: `,t.a({href:`https://github.com/rclone/rclone`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`rclone`}),`, `,t.a({href:`https://github.com/peak/s5cmd`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`s5cmd`}),`, etc.`)}})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!e.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:a},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${e.isSaving?`loading`:``}`,disabled:()=>!e.hasChanges||e.isSaving},t.span({className:`txt`},`Save changes`)))))),t.footer({className:`page-footer`},app.components.credits())))}function Qi(e){app.store.title=`Export collections`;let n=`export_`+app.utils.randomString(),r=store({isLoading:!1,collections:[],bulkSelected:{},get bulkSelectStr(){return JSON.stringify(app.utils.sortedCollectionsByType(Object.values(r.bulkSelected)),null,2)},get totalSelected(){return Object.keys(r.bulkSelected).length},get areAllSelected(){return r.collections.length&&r.collections.length==r.totalSelected}});i();async function i(){r.isLoading=!0;try{let e=await app.pb.collections.getFullList({requestKey:n});for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;r.collections=app.utils.sortedCollectionsByType(e),c(),r.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoading=!1)}}function a(){let e=app.utils.sortedCollectionsByType(Object.values(r.bulkSelected));app.utils.downloadJSON(e,`pb_schema`)}function o(){r.areAllSelected?s():c()}function s(){r.bulkSelected={}}function c(){r.bulkSelected={};for(let e of r.collections)r.bulkSelected[e.id]=e}return t.div({pbEvent:`pageExportCollections`,className:`page page-export-collections`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>r.isLoading?t.div({className:`txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`txt-lg`},`Below you'll find your current collections configuration that you could import in another PocketBase environment.`)),t.div({className:`col-lg-12`},t.div({className:`export-panel`},t.aside({className:`export-list`},t.div({className:`list-item`},t.div({className:`field`},t.input({id:n+`.select_all`,type:`checkbox`,checked:()=>r.areAllSelected,onchange:()=>o()}),t.label({htmlFor:n+`.select_all`},`Select all`))),()=>r.collections.map(e=>{let i=n+`_c_`+e.id;return t.div({className:`list-item`},t.div({className:`field`},t.input({id:i,type:`checkbox`,checked:()=>!!r.bulkSelected[e.id],onchange:n=>{let i=Object.assign({},r.bulkSelected);n.target.__shiftKey&&(n.target.__shiftKey=!1,app.utils.bulkSelectRange(r.collections,i,e,n.target.checked)),n.target.checked?i[e.id]=e:delete i[e.id],r.bulkSelected=i}}),t.label({htmlFor:i,textContent:()=>e.name,onclick:e=>{e.preventDefault();let n=document.getElementById(e.target.htmlFor);n&&(n.__shiftKey=e.shiftKey,n.click())}})))})),t.output({className:`export-preview`},app.components.codeBlock({value:()=>r.bulkSelectStr,language:`plain`}),t.nav({className:`ctrls`},app.components.copyButton(()=>r.bulkSelectStr))))),t.div({className:`col-lg-12 txt-right`},t.button({className:`btn`,onclick:a},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download as JSON`))))),t.footer({className:`page-footer`},app.components.credits())))}function $i(e){app.store.title=`Import collections`;let n=`import_`+app.utils.randomString(),r=[],i=store({rawNewCollections:``,oldCollections:[],newCollections:[],collectionsToUpdate:[],deleteMissing:!0,isLoadingFile:!1,isLoadingOldCollections:!1,mergeWithOldCollections:!1,get isRawValid(){return!!i.rawNewCollections&&i.newCollections?.length>0&&i.newCollections.length==i.newCollections.filter(e=>!!e.id&&!!e.name).length},get collectionsToDelete(){return i.oldCollections.filter(e=>i.isRawValid&&!i.mergeWithOldCollections&&i.deleteMissing&&!i.newCollections.find(n=>n.id==e.id))},get collectionsToAdd(){return i.newCollections.filter(e=>i.isRawValid&&!i.oldCollections.find(n=>n.id==e.id))},get idReplacableCollections(){return i.newCollections.filter(e=>{let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)return!1;if(n.id!=e.id)return!0;let r=Array.isArray(n.fields)?n.fields:[],a=Array.isArray(e.fields)?e.fields:[];for(let e of a){if(r.find(n=>n.id==e.id))continue;let n=r.find(n=>n.name==e.name);if(n&&e.id!=n.id)return!0}return!1})},get hasChanges(){return!!i.rawNewCollections&&!!(i.collectionsToDelete.length||i.collectionsToAdd.length||i.collectionsToUpdate.length)},get canReview(){return!i.isLoadingOldCollections&&i.isRawValid&&i.hasChanges}}),a=t.input({id:n+`_load_json`,type:`file`,className:`hidden`,accept:`.json`,onchange:()=>{d(a.files?.[0])}});o();async function o(){i.isLoadingOldCollections=!0;try{let e=await app.pb.collections.getFullList();for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;i.oldCollections=e,i.isLoadingOldCollections=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoadingOldCollections=!1)}}r.push(watch(()=>i.rawNewCollections,()=>{s()}));function s(){let e=[];try{e=JSON.parse(i.rawNewCollections),e=Array.isArray(e)?app.utils.filterDuplicatesByKey(e):[];for(let n of e)delete n.created,delete n.updated,n.fields&&=app.utils.filterDuplicatesByKey(n.fields)}catch{}i.newCollections=e}r.push(watch(()=>[i.newCollections,i.deleteMissing],()=>{c()}));function c(){if(i.collectionsToUpdate=[],i.isRawValid)for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.id==e.id);!n?.id||!app.utils.hasCollectionChanges(n,e,i.deleteMissing)||i.collectionsToUpdate.push({new:e,old:n})}}function l(){for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)continue;let r=e.id,a=n.id;e.id=a;let o=Array.isArray(n.fields)?n.fields:[],s=Array.isArray(e.fields)?e.fields:[];for(let e of s){let n=o.find(n=>n.name==e.name);n&&n.id&&(e.id=n.id)}for(let e of i.newCollections)if(Array.isArray(e.fields))for(let n of e.fields)n.collectionId&&n.collectionId===r&&(n.collectionId=a);for(let n=0;ne.replace(r,a))}i.rawNewCollections=JSON.stringify(i.newCollections,null,2)}function u(){i.rawNewCollections=``,a.value=``,app.store.errors=null}function d(e){i.isLoadingFile=!0;let n=new FileReader;n.onload=async e=>{i.isLoadingFile=!1,a.value=``,i.rawNewCollections=e.target.result,await new Promise(e=>setTimeout(e,0)),i.newCollections.length||(app.toasts.error(`Invalid collections configuration.`),u())},n.onerror=e=>{app.toasts.error(`Failed to load the imported JSON.`),console.warn(e),i.isLoadingFile=!1,a.value=``},n.readAsText(e)}function f(){let e=i.mergeWithOldCollections?app.utils.filterDuplicatesByKey(i.oldCollections.concat(i.newCollections)):i.newCollections;app.modals.openImportCollectionsReview(i.oldCollections,e,{deleteMissing:i.deleteMissing,onsubmit:()=>{u(),o()}})}return t.div({pbEvent:`pageImportCollections`,className:`page page-import-collections`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoadingOldCollections?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.span({className:`txt-lg m-r-5`},`Paste below the collections configuration you want to import or`),t.label({htmlFor:a.id,className:()=>`btn sm outline ${i.isLoadingFile?`loading`:``}`},t.span({className:`txt`},`Load from JSON file`)),a,t.p({className:`txt-hint`},t.em(null,`You can use the `,t.a({href:`https://pocketbase.io/docs/go-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JS`}),` migrations to manage your collections programmatically in more granular and version controlled manner.`))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:n+`_collections_field`},`Collections`),t.textarea({id:n+`_collections_field`,name:`collections`,rows:12,className:`txt-code`,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,value:()=>i.rawNewCollections,oninput:e=>i.rawNewCollections=e.target.value})),t.div({className:()=>`field-help error ${i.rawNewCollections&&!i.isRawValid?``:`hidden`}`},`Invalid collections configuration.`)),t.div({className:()=>`col-lg-12 ${i.isRawValid?``:`hidden`}`},t.div({className:`field`},t.input({id:n+`_merge_checkbox`,type:`checkbox`,className:`switch`,checked:()=>i.mergeWithOldCollections,onchange:e=>i.mergeWithOldCollections=e.target.checked}),t.label({htmlFor:n+`_merge_checkbox`},`Merge with the existing collections`))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&!i.hasChanges?``:`hidden`}`},t.div({className:`alert info`},t.div({className:`content`},t.p(null,`Your collections configuration is already up-to-date!`)))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&i.hasChanges?``:`hidden`}`},t.p({className:`txt-hint txt-bold`},`Detected changes`),t.div({className:`list`},()=>i.collectionsToDelete.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))),()=>i.collectionsToUpdate.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(e.old.name!=e.new.name)return[t.span({className:`txt-strikethrough txt-hint`,textContent:e.old.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>e.new.name}),t.small({className:()=>`txt-hint ${e.new.id?``:`hidden`}`,textContent:()=>e.new.id})))),()=>i.collectionsToAdd.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label success`,textContent:`Added`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))))),t.div({className:()=>`col-lg-12 ${i.idReplacableCollections?.length?``:`hidden`}`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Some of the imported collections share the same name and/or fields but are imported with different IDs.`),t.p(null,`You can replace them in the import if you want to:`,t.button({type:`button`,className:`btn warning sm m-l-10`,textContent:`Replace with original IDs`,onclick:l}))))),t.div({className:`col-lg-12`},t.div({className:`flex`},t.button({type:`button`,className:()=>`btn secondary ${i.rawNewCollections?``:`hidden`}`,onclick:u},t.span({className:`txt`},`Clear`)),t.button({type:`button`,className:`btn expanded-lg m-l-auto`,disabled:()=>!i.canReview,onclick:f},t.span({className:`txt`},`Review`)))))),t.footer({className:`page-footer`},app.components.credits())))}window.app=window.app||{},window.app.routes=window.app.routes||{},window.app.routes.fallbackPath=`#/collections`,app.routes.guestOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(app.pb.authStore.isValid&&app.pb.authStore.record?.id){window.location.hash=`#/`;return}app.store.showHeader=!1,app.store.page=await n(e)}},app.routes.superuserOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(!app.pb.authStore.isValid||!app.pb.authStore.record?.id){window.location.hash=`#/login`;return}app.store.showHeader=!0,app.store.page=await n(e)}},app.routes.blank=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{app.store.showHeader=!1,app.store.page=await n(e)}};var ea={},ta;function na(){ta&&ta(),ta=router(ea,{fallbackPath:app.routes.fallbackPath})}app.routes.guestOnly(`#/pbinstall/{token}`,async e=>{let{pageInstaller:n}=await G(async()=>{let{pageInstaller:e}=await import(`./pageInstaller-Btd_kQ3V.js`);return{pageInstaller:e}},[],import.meta.url);return n(e)}),app.routes.guestOnly(`#/login`,e=>$r(e)),app.routes.guestOnly(`#/request-password-reset`,async e=>{let{pageRequestSuperuserPasswordReset:n}=await G(async()=>{let{pageRequestSuperuserPasswordReset:e}=await import(`./pageRequestSuperuserPasswordReset-C39AMhGf.js`);return{pageRequestSuperuserPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-password-reset/{token}`,async e=>{let{pageConfirmPasswordReset:n}=await G(async()=>{let{pageConfirmPasswordReset:e}=await import(`./pageConfirmPasswordReset-DDVg4sJm.js`);return{pageConfirmPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-verification/{token}`,async e=>{let{pageConfirmVerification:n}=await G(async()=>{let{pageConfirmVerification:e}=await import(`./pageConfirmVerification-DePQEvON.js`);return{pageConfirmVerification:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-email-change/{token}`,async e=>{let{pageConfirmEmailChange:n}=await G(async()=>{let{pageConfirmEmailChange:e}=await import(`./pageConfirmEmailChange-BY7xJuWX.js`);return{pageConfirmEmailChange:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-success`,async e=>{let{pageOAuth2RedirectSuccess:n}=await G(async()=>{let{pageOAuth2RedirectSuccess:e}=await import(`./pageOAuth2RedirectSuccess-DmZV1eyz.js`);return{pageOAuth2RedirectSuccess:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-failure`,async e=>{let{pageOAuth2RedirectFailure:n}=await G(async()=>{let{pageOAuth2RedirectFailure:e}=await import(`./pageOAuth2RedirectFailure-CRvz4PXa.js`);return{pageOAuth2RedirectFailure:e}},[],import.meta.url);return n(e)}),app.routes.superuserOnly(`#/collections`,hi),app.routes.superuserOnly(`#/logs`,Ei),app.routes.superuserOnly(`#/settings`,Ii),app.routes.superuserOnly(`#/settings/mail`,Ji),app.routes.superuserOnly(`#/settings/storage`,Zi),app.routes.superuserOnly(`#/settings/backups`,Gi),app.routes.superuserOnly(`#/settings/crons`,qi),app.routes.superuserOnly(`#/settings/export-collections`,Qi),app.routes.superuserOnly(`#/settings/import-collections`,$i),app.routes.superuserOnly(`#/settings/sql`,Xi);var ra=t;t=new Proxy({},{get(e,n){return function(){let e=arguments?.[0];if(e&&e.pbEvent){let n=e.onmount;e.onmount=r=>{n?.(r),r.dataset.pb=e.pbEvent,document.dispatchEvent(new CustomEvent(`mount:`+e.pbEvent,{detail:r}))};let r=e.onunmount;e.onunmount=n=>{document.dispatchEvent(new CustomEvent(`unmount:`+e.pbEvent,{detail:n})),r?.(n)}}return ra[n](...arguments)}}}),document.body.prepend(t.main({"html-class":`app`,className:()=>`app ${app.store.settings?.meta?.hideControls?`hide-controls`:``}`},Fe(),e=>(typeof app.store.page==`function`&&app.store.page(e),app.store.page))),watch(()=>app.store._ready,e=>{e&&na()}),document.body.appendChild(t.script({type:`module`,src:app.pb.buildURL(`/_/extensions.js`),onload:()=>{app.store._ready=!0},onerror:e=>{console.warn(`Failed to load extensions:`,e),app.store._ready=!0}}));export{S as n,se as r,Ee as t}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmEmailChange-l_DOk6UT.js b/ui/dist/assets/pageConfirmEmailChange-BY7xJuWX.js similarity index 97% rename from ui/dist/assets/pageConfirmEmailChange-l_DOk6UT.js rename to ui/dist/assets/pageConfirmEmailChange-BY7xJuWX.js index 21b9218523..16d2900673 100644 --- a/ui/dist/assets/pageConfirmEmailChange-l_DOk6UT.js +++ b/ui/dist/assets/pageConfirmEmailChange-BY7xJuWX.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.newEmail||!a.collectionId){app.toasts.error(`Invalid or expired email change token.`),window.location.hash=`#/`;return}app.store.title=`Confirm email change`;let o=store({password:``,isSubmitting:!1,isSuccess:!1,showPassword:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmEmailChange(i,o.password),o.isSuccess=!0}catch(e){app.checkApiError(e),o.isSuccess=!1}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmEmailChange`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmEmailChangeAlert`,className:`alert success txt-center`},t.p(null,`The email was successfully changed.`),t.p(null,`You can go back and sign in with your new email address.`)):t.form({pbEvent:`confirmEmailChangeForm`,className:`grid confirm-email-change-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your password to confirm changing your email address to `,t.strong(null,a.newEmail),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`password_confirm`},`Password`),t.input({id:`password_confirm`,name:`password`,required:!0,autofocus:!0,type:()=>o.showPassword?`text`:`password`,value:()=>o.password,oninput:e=>o.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showPassword?`Hide password`:`Show password`),onclick:()=>o.showPassword=!o.showPassword},t.i({className:()=>o.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Confirm new email`)))))}export{r as pageConfirmEmailChange}; \ No newline at end of file +import{n as e,t as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.newEmail||!a.collectionId){app.toasts.error(`Invalid or expired email change token.`),window.location.hash=`#/`;return}app.store.title=`Confirm email change`;let o=store({password:``,isSubmitting:!1,isSuccess:!1,showPassword:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmEmailChange(i,o.password),o.isSuccess=!0}catch(e){app.checkApiError(e),o.isSuccess=!1}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmEmailChange`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmEmailChangeAlert`,className:`alert success txt-center`},t.p(null,`The email was successfully changed.`),t.p(null,`You can go back and sign in with your new email address.`)):t.form({pbEvent:`confirmEmailChangeForm`,className:`grid confirm-email-change-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your password to confirm changing your email address to `,t.strong(null,a.newEmail),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`password_confirm`},`Password`),t.input({id:`password_confirm`,name:`password`,required:!0,autofocus:!0,type:()=>o.showPassword?`text`:`password`,value:()=>o.password,oninput:e=>o.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showPassword?`Hide password`:`Show password`),onclick:()=>o.showPassword=!o.showPassword},t.i({className:()=>o.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Confirm new email`)))))}export{r as pageConfirmEmailChange}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmPasswordReset-UQX1jz2S.js b/ui/dist/assets/pageConfirmPasswordReset-DDVg4sJm.js similarity index 97% rename from ui/dist/assets/pageConfirmPasswordReset-UQX1jz2S.js rename to ui/dist/assets/pageConfirmPasswordReset-DDVg4sJm.js index 61719216b6..0409385cfc 100644 --- a/ui/dist/assets/pageConfirmPasswordReset-UQX1jz2S.js +++ b/ui/dist/assets/pageConfirmPasswordReset-DDVg4sJm.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired password reset token.`),window.location.hash=`#/`;return}app.store.title=`Confirm password reset`;let o=store({newPassword:``,newPasswordConfirm:``,showNewPassword:!1,showNewPasswordConfirm:!1,isSubmitting:!1,isSuccess:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmPasswordReset(i,o.newPassword,o.newPasswordConfirm),o.isSuccess=!0}catch(e){app.checkApiError(e)}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmPasswordReset`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmPasswordResetAlert`,className:`alert success txt-center`},t.p(null,`The password was successfully changed.`),t.p(null,`You can go back to sign in with your new password.`)):t.form({pbEvent:`confirmPasswordResetForm`,className:`grid confirm-password-reset-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your new password for `,t.strong(null,a.email),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPassword`},`New password`),t.input({id:`newPassword`,name:`password`,required:!0,autofocus:!0,autocomplete:`new-password`,type:()=>o.showNewPassword?`text`:`password`,value:()=>o.newPassword,oninput:e=>o.newPassword=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPassword?`Hide password`:`Show password`),onclick:()=>o.showNewPassword=!o.showNewPassword},t.i({className:()=>o.showNewPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPasswordConfirm`},`New password confirm`),t.input({id:`newPasswordConfirm`,name:`passwordConfirm`,required:!0,autocomplete:`new-password`,type:()=>o.showNewPasswordConfirm?`text`:`password`,value:()=>o.newPasswordConfirm,oninput:e=>o.newPasswordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPasswordConfirm?`Hide password`:`Show password`),onclick:()=>o.showNewPasswordConfirm=!o.showNewPasswordConfirm},t.i({className:()=>o.showNewPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Set new password`)))))}export{r as pageConfirmPasswordReset}; \ No newline at end of file +import{n as e,t as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired password reset token.`),window.location.hash=`#/`;return}app.store.title=`Confirm password reset`;let o=store({newPassword:``,newPasswordConfirm:``,showNewPassword:!1,showNewPasswordConfirm:!1,isSubmitting:!1,isSuccess:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmPasswordReset(i,o.newPassword,o.newPasswordConfirm),o.isSuccess=!0}catch(e){app.checkApiError(e)}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmPasswordReset`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmPasswordResetAlert`,className:`alert success txt-center`},t.p(null,`The password was successfully changed.`),t.p(null,`You can go back to sign in with your new password.`)):t.form({pbEvent:`confirmPasswordResetForm`,className:`grid confirm-password-reset-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your new password for `,t.strong(null,a.email),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPassword`},`New password`),t.input({id:`newPassword`,name:`password`,required:!0,autofocus:!0,autocomplete:`new-password`,type:()=>o.showNewPassword?`text`:`password`,value:()=>o.newPassword,oninput:e=>o.newPassword=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPassword?`Hide password`:`Show password`),onclick:()=>o.showNewPassword=!o.showNewPassword},t.i({className:()=>o.showNewPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPasswordConfirm`},`New password confirm`),t.input({id:`newPasswordConfirm`,name:`passwordConfirm`,required:!0,autocomplete:`new-password`,type:()=>o.showNewPasswordConfirm?`text`:`password`,value:()=>o.newPasswordConfirm,oninput:e=>o.newPasswordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPasswordConfirm?`Hide password`:`Show password`),onclick:()=>o.showNewPasswordConfirm=!o.showNewPasswordConfirm},t.i({className:()=>o.showNewPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Set new password`)))))}export{r as pageConfirmPasswordReset}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmVerification-Bc6dMZfz.js b/ui/dist/assets/pageConfirmVerification-DePQEvON.js similarity index 96% rename from ui/dist/assets/pageConfirmVerification-Bc6dMZfz.js rename to ui/dist/assets/pageConfirmVerification-DePQEvON.js index b92b506473..e5a2e648fb 100644 --- a/ui/dist/assets/pageConfirmVerification-Bc6dMZfz.js +++ b/ui/dist/assets/pageConfirmVerification-DePQEvON.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired verification token.`),window.location.hash=`#/`;return}app.store.title=`Confirm verification`;let o=store({isConfirming:!1,isConfirmSuccess:!1,isResending:!1,isResendSuccess:!1});s();async function s(){if(o.isConfirming)return;o.isConfirming=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmVerification(i),o.isConfirmSuccess=!0}catch{o.isConfirmSuccess=!1}o.isConfirming=!1}async function c(){if(o.isResending)return;o.isResending=!0;let e=new n(`../`);try{await e.collection(a.collectionId).requestVerification(a.email),o.isResendSuccess=!0}catch(e){app.checkApiError(e),o.isResendSuccess=!1}o.isResending=!1}return t.div({pbEvent:`pageConfirmVerification`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isConfirming?t.div({className:`block txt-center`},t.span({className:`loader`},`Please wait...`)):o.isConfirmSuccess?t.div({pbEvent:`confirmVerificationSuccessAlert`,className:`alert success txt-center`},t.p(null,`Successfully verified `,t.strong(null,a.email),`.`)):o.isResendSuccess?t.div({pbEvent:`confirmVerificationResendAlert`,className:`alert success txt-center`},t.p(null,`Please check your email for the new verification link.`)):[t.div({pbEvent:`confirmVerificationErrorAlert`,className:`alert danger txt-center m-b-base`},t.p(null,`Invalid or expired verification token.`)),t.button({type:`button`,className:()=>`btn transparent lg block ${o.isResending?`loading`:``}`,disabled:()=>o.isResending,onclick:()=>c()},t.span({className:`txt`},`Resend`))])}export{r as pageConfirmVerification}; \ No newline at end of file +import{n as e,t as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired verification token.`),window.location.hash=`#/`;return}app.store.title=`Confirm verification`;let o=store({isConfirming:!1,isConfirmSuccess:!1,isResending:!1,isResendSuccess:!1});s();async function s(){if(o.isConfirming)return;o.isConfirming=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmVerification(i),o.isConfirmSuccess=!0}catch{o.isConfirmSuccess=!1}o.isConfirming=!1}async function c(){if(o.isResending)return;o.isResending=!0;let e=new n(`../`);try{await e.collection(a.collectionId).requestVerification(a.email),o.isResendSuccess=!0}catch(e){app.checkApiError(e),o.isResendSuccess=!1}o.isResending=!1}return t.div({pbEvent:`pageConfirmVerification`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isConfirming?t.div({className:`block txt-center`},t.span({className:`loader`},`Please wait...`)):o.isConfirmSuccess?t.div({pbEvent:`confirmVerificationSuccessAlert`,className:`alert success txt-center`},t.p(null,`Successfully verified `,t.strong(null,a.email),`.`)):o.isResendSuccess?t.div({pbEvent:`confirmVerificationResendAlert`,className:`alert success txt-center`},t.p(null,`Please check your email for the new verification link.`)):[t.div({pbEvent:`confirmVerificationErrorAlert`,className:`alert danger txt-center m-b-base`},t.p(null,`Invalid or expired verification token.`)),t.button({type:`button`,className:()=>`btn transparent lg block ${o.isResending?`loading`:``}`,disabled:()=>o.isResending,onclick:()=>c()},t.span({className:`txt`},`Resend`))])}export{r as pageConfirmVerification}; \ No newline at end of file diff --git a/ui/dist/assets/pageInstaller-2TD7r9Pz.js b/ui/dist/assets/pageInstaller-Btd_kQ3V.js similarity index 98% rename from ui/dist/assets/pageInstaller-2TD7r9Pz.js rename to ui/dist/assets/pageInstaller-Btd_kQ3V.js index 73da7f72d4..3cebb6a2c9 100644 --- a/ui/dist/assets/pageInstaller-2TD7r9Pz.js +++ b/ui/dist/assets/pageInstaller-Btd_kQ3V.js @@ -1 +1 @@ -import{n as e,r as n}from"./index-BQ-53gTd.js";function r(r){let i=r.params?.token||``;if(e(i).type!=`auth`||n(i)){app.toasts.error(`The installer token is invalid or has expired.`),window.location.hash=`#/`;return}app.store.title=`Setup your PocketBase instance`;let a=store({email:``,password:``,passwordConfirm:``,showPassword:!1,showPasswordConfirm:!1,isSubmitting:!1,isUploading:!1,get isBusy(){return a.isSubmitting||a.isUploading}});async function o(){if(!a.isBusy){a.isSubmitting=!0;try{await app.pb.collection(`_superusers`).create({email:a.email,password:a.password,passwordConfirm:a.passwordConfirm},{headers:{Authorization:i}}),await app.pb.collection(`_superusers`).authWithPassword(a.email,a.password),window.location.hash=`#/`}catch(e){app.checkApiError(e)}a.isSubmitting=!1}}let s=`backupFileInput`;function c(){let e=document.getElementById(s);e&&(e.value=``)}function l(e){e&&app.modals.confirm(t.h6(null,`Note that we don't perform validations for the uploaded backup files. Proceed with caution and only if you trust the file source.\n\nDo you really want to upload and initialize "${e.name}"?`),()=>{u(e)},()=>{c()})}async function u(e){if(!(!e||a.isBusy)){a.isUploading=!0;try{await app.pb.backups.upload({file:e},{headers:{Authorization:i}}),await app.pb.backups.restore(e.name,{headers:{Authorization:i}}),app.toasts.info(`Please wait while extracting the uploaded archive!`),await new Promise(e=>setTimeout(e,3e3)),window.location.href=`#/`}catch(e){app.checkApiError(e)}c(),a.isUploading=!1}}return t.div({pbEvent:`pageInstaller`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),t.form({pbEvent:`installerForm`,className:`grid installer-form`,onsubmit:e=>{e.preventDefault(),o(a)}},t.div({className:`col-12 txt-center`},`Create your first superuser account in order to continue:`),t.div({className:`col-12`},t.div({className:`field`},t.label({htmlFor:`superuser_email`},`Email`),t.input({id:`superuser_email`,name:`email`,type:`email`,required:!0,autofocus:!0,autocomplete:`off`,disabled:()=>a.isBusy,value:()=>a.email,oninput:e=>a.email=e.target.value}))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password`},`Password`),t.input({id:`superuser_password`,name:`password`,min:10,required:!0,disabled:()=>a.isBusy,type:()=>a.showPassword?`text`:`password`,value:()=>a.password,oninput:e=>a.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPassword?`Hide password`:`Show password`),onclick:()=>a.showPassword=!a.showPassword},t.i({className:()=>a.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0})))),t.div({className:`field-help`},`Recommended at least 10 characters.`)),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password_confirm`},`Password confirm`),t.input({id:`superuser_password_confirm`,name:`passwordConfirm`,required:!0,disabled:()=>a.isBusy,type:()=>a.showPasswordConfirm?`text`:`password`,value:()=>a.passwordConfirm,oninput:e=>a.passwordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPasswordConfirm?`Hide password`:`Show password`),onclick:()=>a.showPasswordConfirm=!a.showPasswordConfirm},t.i({className:()=>a.showPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg next block ${a.isSubmitting?`loading`:``}`,disabled:()=>a.isBusy},t.span({className:`txt`},`Create superuser and login`),t.i({className:`ri-arrow-right-line`,ariaHidden:!0})))),t.hr(),t.label({htmlFor:s,className:()=>`btn secondary transparent lg block ${a.isBusy?`disabled`:``} ${a.isUploading?`loading`:``}`},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Or initialize from backup`)),t.input({id:s,type:`file`,className:`hidden`,accept:`.zip`,onchange:e=>{l(e.target?.files?.[0])}}))}export{r as pageInstaller}; \ No newline at end of file +import{n as e,r as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``;if(e(i).type!=`auth`||n(i)){app.toasts.error(`The installer token is invalid or has expired.`),window.location.hash=`#/`;return}app.store.title=`Setup your PocketBase instance`;let a=store({email:``,password:``,passwordConfirm:``,showPassword:!1,showPasswordConfirm:!1,isSubmitting:!1,isUploading:!1,get isBusy(){return a.isSubmitting||a.isUploading}});async function o(){if(!a.isBusy){a.isSubmitting=!0;try{await app.pb.collection(`_superusers`).create({email:a.email,password:a.password,passwordConfirm:a.passwordConfirm},{headers:{Authorization:i}}),await app.pb.collection(`_superusers`).authWithPassword(a.email,a.password),window.location.hash=`#/`}catch(e){app.checkApiError(e)}a.isSubmitting=!1}}let s=`backupFileInput`;function c(){let e=document.getElementById(s);e&&(e.value=``)}function l(e){e&&app.modals.confirm(t.h6(null,`Note that we don't perform validations for the uploaded backup files. Proceed with caution and only if you trust the file source.\n\nDo you really want to upload and initialize "${e.name}"?`),()=>{u(e)},()=>{c()})}async function u(e){if(!(!e||a.isBusy)){a.isUploading=!0;try{await app.pb.backups.upload({file:e},{headers:{Authorization:i}}),await app.pb.backups.restore(e.name,{headers:{Authorization:i}}),app.toasts.info(`Please wait while extracting the uploaded archive!`),await new Promise(e=>setTimeout(e,3e3)),window.location.href=`#/`}catch(e){app.checkApiError(e)}c(),a.isUploading=!1}}return t.div({pbEvent:`pageInstaller`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),t.form({pbEvent:`installerForm`,className:`grid installer-form`,onsubmit:e=>{e.preventDefault(),o(a)}},t.div({className:`col-12 txt-center`},`Create your first superuser account in order to continue:`),t.div({className:`col-12`},t.div({className:`field`},t.label({htmlFor:`superuser_email`},`Email`),t.input({id:`superuser_email`,name:`email`,type:`email`,required:!0,autofocus:!0,autocomplete:`off`,disabled:()=>a.isBusy,value:()=>a.email,oninput:e=>a.email=e.target.value}))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password`},`Password`),t.input({id:`superuser_password`,name:`password`,min:10,required:!0,disabled:()=>a.isBusy,type:()=>a.showPassword?`text`:`password`,value:()=>a.password,oninput:e=>a.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPassword?`Hide password`:`Show password`),onclick:()=>a.showPassword=!a.showPassword},t.i({className:()=>a.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0})))),t.div({className:`field-help`},`Recommended at least 10 characters.`)),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password_confirm`},`Password confirm`),t.input({id:`superuser_password_confirm`,name:`passwordConfirm`,required:!0,disabled:()=>a.isBusy,type:()=>a.showPasswordConfirm?`text`:`password`,value:()=>a.passwordConfirm,oninput:e=>a.passwordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPasswordConfirm?`Hide password`:`Show password`),onclick:()=>a.showPasswordConfirm=!a.showPasswordConfirm},t.i({className:()=>a.showPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg next block ${a.isSubmitting?`loading`:``}`,disabled:()=>a.isBusy},t.span({className:`txt`},`Create superuser and login`),t.i({className:`ri-arrow-right-line`,ariaHidden:!0})))),t.hr(),t.label({htmlFor:s,className:()=>`btn secondary transparent lg block ${a.isBusy?`disabled`:``} ${a.isUploading?`loading`:``}`},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Or initialize from backup`)),t.input({id:s,type:`file`,className:`hidden`,accept:`.zip`,onchange:e=>{l(e.target?.files?.[0])}}))}export{r as pageInstaller}; \ No newline at end of file diff --git a/ui/dist/index.html b/ui/dist/index.html index c85e1343ec..7a2cfe0d69 100644 --- a/ui/dist/index.html +++ b/ui/dist/index.html @@ -13,7 +13,7 @@ - + diff --git a/ui/src/fields/file/input.js b/ui/src/fields/file/input.js index 442e861657..09825691d7 100644 --- a/ui/src/fields/file/input.js +++ b/ui/src/fields/file/input.js @@ -105,7 +105,6 @@ export function input(props) { className: "field-content", name: () => props.field.name, }, - // @todo enable ordering new files before/inbetween existing app.components.sortable({ className: "list", data: () => { @@ -130,6 +129,23 @@ export function input(props) { return vals; }, onchange: (sortedList) => { + // sort existing files first because at the moment we don't + // support putting new files between old ones + sortedList.sort((a, b) => { + const aIsString = typeof a == "string"; + const bIsString = typeof b == "string"; + + if (aIsString && !bIsString) { + return -1; + } + + if (!aIsString && bIsString) { + return 1; + } + + return 0; + }); + props.record[props.field.name] = sortedList; triggerChangeEvent(); }, diff --git a/ui/src/records/recordFilePickerModal.js b/ui/src/records/recordFilePickerModal.js index 2e9269c8ee..e0a8aeaa29 100644 --- a/ui/src/records/recordFilePickerModal.js +++ b/ui/src/records/recordFilePickerModal.js @@ -5,7 +5,7 @@ const recordsPerPage = 100; const defaultSettings = { btnText: "Insert", - fileTypes: [], // "image", "document", "video", "audio", "file" + fileTypes: [], // "image", "document", "video", "audio", "archive", "file" onselect: function(selectedFile) {}, }; From b259534df7dc58fc66605bd2cddb2c73f3b7260d Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sun, 2 Aug 2026 20:17:46 +0300 Subject: [PATCH 04/37] added quotes for the default Content-Disposition serving filename in case custom name with special characters is provided --- CHANGELOG.md | 2 ++ tools/filesystem/filesystem.go | 2 +- tools/filesystem/filesystem_test.go | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b928bcf485..f7b146c24b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Fixed "API preview" examples ([#7782](https://github.com/pocketbase/pocketbase/issues/7782)). +- Added quotes around the default `Content-Disposition` serving filename in case custom name with special characters is provided. + ## v0.39.10 diff --git a/tools/filesystem/filesystem.go b/tools/filesystem/filesystem.go index 319ed8c447..50b602f99e 100644 --- a/tools/filesystem/filesystem.go +++ b/tools/filesystem/filesystem.go @@ -464,7 +464,7 @@ func (s *System) Serve(res http.ResponseWriter, req *http.Request, fileKey strin extContentType = ct } - setHeaderIfMissing(res, "Content-Disposition", disposition+"; filename="+name) + setHeaderIfMissing(res, "Content-Disposition", disposition+"; filename="+strconv.Quote(name)) setHeaderIfMissing(res, "Content-Type", extContentType) setHeaderIfMissing(res, "Content-Security-Policy", "default-src 'none'; media-src 'self'; style-src 'unsafe-inline'; sandbox") diff --git a/tools/filesystem/filesystem_test.go b/tools/filesystem/filesystem_test.go index f3b4d5401e..f3e2063438 100644 --- a/tools/filesystem/filesystem_test.go +++ b/tools/filesystem/filesystem_test.go @@ -365,7 +365,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name.txt", + "Content-Disposition": `attachment; filename="test_name.txt"`, "Content-Type": "application/octet-stream", "Content-Length": "4", "Content-Security-Policy": csp, @@ -380,7 +380,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "inline; filename=test_name.png", + "Content-Disposition": `inline; filename="test_name.png"`, "Content-Type": "image/png", "Content-Length": "73", "Content-Security-Policy": csp, @@ -395,7 +395,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name_download.png", + "Content-Disposition": `attachment; filename="test_name_download.png"`, "Content-Type": "image/png", "Content-Length": "73", "Content-Security-Policy": csp, @@ -410,7 +410,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name.abc", + "Content-Disposition": `attachment; filename="test_name.abc"`, "Content-Type": "image/svg+xml", "Content-Length": "0", "Content-Security-Policy": csp, @@ -425,7 +425,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name", + "Content-Disposition": `attachment; filename="test_name"`, "Content-Type": "text/css", "Content-Length": "0", "Content-Security-Policy": csp, @@ -440,7 +440,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name.abc", + "Content-Disposition": `attachment; filename="test_name.abc"`, "Content-Type": "text/javascript", "Content-Length": "0", "Content-Security-Policy": csp, @@ -455,7 +455,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name.abc", + "Content-Disposition": `attachment; filename="test_name.abc"`, "Content-Type": "text/javascript", "Content-Length": "0", "Content-Security-Policy": csp, @@ -470,7 +470,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name.abc", + "Content-Disposition": `attachment; filename="test_name.abc"`, "Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Content-Length": "0", "Content-Security-Policy": csp, @@ -485,7 +485,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name.abc", + "Content-Disposition": `attachment; filename="test_name.abc"`, "Content-Type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Content-Length": "0", "Content-Security-Policy": csp, @@ -500,7 +500,7 @@ func TestFileSystemServe(t *testing.T) { nil, false, map[string]string{ - "Content-Disposition": "attachment; filename=test_name.abc", + "Content-Disposition": `attachment; filename="test_name.abc"`, "Content-Type": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "Content-Length": "0", "Content-Security-Policy": csp, From dc7482ea6788ae559aeddbf85800148bc7efad19 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Mon, 3 Aug 2026 15:58:36 +0300 Subject: [PATCH 05/37] [#7785] fixed realtime API preview examples --- CHANGELOG.md | 2 +- ...e-pRgUAX2q.js => docsRealtime-BR9-cDED.js} | 24 +++++++++---------- .../{index-C9WMzSfg.js => index-Kt84cKKj.js} | 4 ++-- ....js => pageConfirmEmailChange-BXaDVeUb.js} | 2 +- ...s => pageConfirmPasswordReset-DY_-cIrh.js} | 2 +- ...js => pageConfirmVerification-Bo-r9bV_.js} | 2 +- ...-Btd_kQ3V.js => pageInstaller-D0gTHS34.js} | 2 +- ui/dist/index.html | 2 +- ui/src/apiPreview/docsRealtime.js | 24 +++++++++---------- 9 files changed, 32 insertions(+), 32 deletions(-) rename ui/dist/assets/{docsRealtime-pRgUAX2q.js => docsRealtime-BR9-cDED.js} (85%) rename ui/dist/assets/{index-C9WMzSfg.js => index-Kt84cKKj.js} (99%) rename ui/dist/assets/{pageConfirmEmailChange-BY7xJuWX.js => pageConfirmEmailChange-BXaDVeUb.js} (97%) rename ui/dist/assets/{pageConfirmPasswordReset-DDVg4sJm.js => pageConfirmPasswordReset-DY_-cIrh.js} (97%) rename ui/dist/assets/{pageConfirmVerification-DePQEvON.js => pageConfirmVerification-Bo-r9bV_.js} (96%) rename ui/dist/assets/{pageInstaller-Btd_kQ3V.js => pageInstaller-D0gTHS34.js} (98%) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7b146c24b..12a18a400a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ - Propagate console command errors and recovered panics to `app.Start()` so that the program can exit with non-zero code while still ensuring that `app.OnTerminate` hook (responsible for the app graceful shutdown handling) was triggered. _⚠️ Note that this could be a slight breaking change in case you are chaining PocketBase commands and relied on the previous `0` exit status for `Command.RunE` returned errors._ -- Fixed "API preview" examples ([#7782](https://github.com/pocketbase/pocketbase/issues/7782)). +- Fixed "API preview" examples ([#7782](https://github.com/pocketbase/pocketbase/issues/7782), [#7785](https://github.com/pocketbase/pocketbase/issues/7785)). - Added quotes around the default `Content-Disposition` serving filename in case custom name with special characters is provided. diff --git a/ui/dist/assets/docsRealtime-pRgUAX2q.js b/ui/dist/assets/docsRealtime-BR9-cDED.js similarity index 85% rename from ui/dist/assets/docsRealtime-pRgUAX2q.js rename to ui/dist/assets/docsRealtime-BR9-cDED.js index 480e85d811..ba8d9f34d1 100644 --- a/ui/dist/assets/docsRealtime-pRgUAX2q.js +++ b/ui/dist/assets/docsRealtime-BR9-cDED.js @@ -8,14 +8,14 @@ function e(e){let n=app.utils.getApiExampleURL(),r=Object.assign({collectionId:e // (optionally) authenticate await pb.collection('users').authWithPassword('test@example.com', '123456'); - // subscribe to changes in any ${n} record - pb.collection('${n}').subscribe('*', function (e) { + // subscribe to changes in any ${e.name} record + pb.collection('${e.name}').subscribe('*', function (e) { console.log(e.action); console.log(e.record); }, { /* other options like: filter, expand, custom headers, etc. */ }); // subscribe to changes only in the specified record - pb.collection('${n}').subscribe('RECORD_ID', function (e) { + pb.collection('${e.name}').subscribe('RECORD_ID', function (e) { console.log(e.action); console.log(e.record); }, { /* other options like: filter, expand, custom headers, etc. */ }); @@ -23,13 +23,13 @@ function e(e){let n=app.utils.getApiExampleURL(),r=Object.assign({collectionId:e ... // unsubscribe - remove all 'RECORD_ID' subscriptions - pb.collection('${n}').unsubscribe('RECORD_ID'); + pb.collection('${e.name}').unsubscribe('RECORD_ID'); // unsubscribe - remove all '*' topic subscriptions - pb.collection('${n}').unsubscribe('*'); + pb.collection('${e.name}').unsubscribe('*'); // unsubscribe - remove all collection subscriptions - pb.collection('${n}').unsubscribe(); + pb.collection('${e.name}').unsubscribe(); `,footnote:t.div({className:`txt-right`},t.a({href:`https://github.com/pocketbase/js-sdk`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JS SDK docs`}))},{title:`Dart SDK`,language:`dart`,value:` import 'package:pocketbase/pocketbase.dart'; @@ -40,14 +40,14 @@ function e(e){let n=app.utils.getApiExampleURL(),r=Object.assign({collectionId:e // (optionally) authenticate await pb.collection('users').authWithPassword('test@example.com', '123456'); - // subscribe to changes in any ${n} record - pb.collection('${n}').subscribe('*', (e) { + // subscribe to changes in any ${e.name} record + pb.collection('${e.name}').subscribe('*', (e) { print(e.action); print(e.record); }, /* other options like: filter, expand, custom headers, etc. */); // subscribe to changes only in the specified record - pb.collection('${n}').subscribe('RECORD_ID', (e) { + pb.collection('${e.name}').subscribe('RECORD_ID', (e) { print(e.action); print(e.record); }, /* other options like: filter, expand, custom headers, etc. */); @@ -55,13 +55,13 @@ function e(e){let n=app.utils.getApiExampleURL(),r=Object.assign({collectionId:e ... // unsubscribe - remove all 'RECORD_ID' subscriptions - pb.collection('${n}').unsubscribe('RECORD_ID'); + pb.collection('${e.name}').unsubscribe('RECORD_ID'); // unsubscribe - remove all '*' topic subscriptions - pb.collection('${n}').unsubscribe('*'); + pb.collection('${e.name}').unsubscribe('*'); // unsubscribe - remove all collection subscriptions - pb.collection('${n}').unsubscribe(); + pb.collection('${e.name}').unsubscribe(); `,footnote:t.div({className:`txt-right`},t.a({href:`https://github.com/pocketbase/dart-sdk`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Dart SDK docs`}))},{title:`curl`,language:`bash`,value:` # init an SSE connection and start listening for messages # (the first message is always PB_CONNECT with the connection "clientId") diff --git a/ui/dist/assets/index-C9WMzSfg.js b/ui/dist/assets/index-Kt84cKKj.js similarity index 99% rename from ui/dist/assets/index-C9WMzSfg.js rename to ui/dist/assets/index-Kt84cKKj.js index 9d20ef053e..606aa924e2 100644 --- a/ui/dist/assets/index-C9WMzSfg.js +++ b/ui/dist/assets/index-Kt84cKKj.js @@ -27,7 +27,7 @@ var e=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i= `;let _=g.querySelector(`.paths-group`);return a=t.div({tabIndex:-1,rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`erd ${n.className} ${i.isUpdating?`updating`:``} ${i.isPanning?`panning`:``} ${i.activeCollection?`active`:``}`,onkeydown:e=>{(e.ctrlKey||e.metaKey)&&e.key==`0`&&f()},onmount:async e=>{e.addEventListener(`wheel`,r=>{r.preventDefault();let a=e.getBoundingClientRect(),o=r.clientX-a.left,s=r.clientY-a.top,c=(o-i.viewX)/n.scale,l=(s-i.viewY)/n.scale,u=Math.min(Math.max(-r.deltaY*.001+n.scale,kt),Ot);i.viewX=o-c*u,i.viewY=s-l*u,n.scale=u}),e.addEventListener(`pointerdown`,e=>{e.buttons==1&&(i.isPanning=!0,i.panStartX=e.clientX-i.viewX,i.panStartY=e.clientY-i.viewY)}),e._ondragging=function(e){i.isPanning&&(i.viewX=e.clientX-i.panStartX,i.viewY=e.clientY-i.panStartY)},e._ondragstop=function(){i.isPanning=!1},window.addEventListener(`pointermove`,e._ondragging),window.addEventListener(`pointerup`,e._ondragstop),c()},onunmount:e=>{window.removeEventListener(`pointermove`,e._ondragging),window.removeEventListener(`pointerup`,e._ondragstop),r.forEach(e=>e?.unwatch())}},t.div({className:`erd-area`,style:()=>`transform: translate(${i.viewX}px, ${i.viewY}px) scale(${n.scale});`},m,t.div({className:`erd-tables`},()=>n.collections.map(e=>t.div({style:()=>`left:${i.positions[e.id]?.x||0}px;top:${i.positions[e.id]?.y||0}px`,className:()=>`erd-table type-${e.type} ${p(e)?`active`:``} ${e.system?`system`:``}`,"html-data-collection-id":()=>e.id,"html-data-collection-name":()=>e.name,onmouseenter:()=>{h.querySelectorAll(`[data-to="${e.id}"]`)?.forEach(e=>{e.classList.add(`active-to`),_.append(e)}),h.querySelectorAll(`[data-from="${e.id}"]`)?.forEach(e=>{e.classList.add(`active-from`),_.append(e)}),i.activeCollection=e},onmouseleave:()=>{for(let e of _.children)e.classList.remove(`active-from`,`active-to`);h.append(..._.children),i.activeCollection=null}},t.div({className:`erd-table-row header`},()=>e.name),()=>e.fields?.map(e=>t.div({className:`erd-table-row type-${e.type} ${e.primaryKey?`primary-key`:``}`,"html-data-field-id":()=>e.id,"html-data-field-name":()=>e.name},t.i({ariaHidden:!0,title:()=>e.type,className:()=>`field-icon ${app.fieldTypes[e.type].icon||app.utils.fallbackFieldIcon}`}),t.span({className:`field-name`},()=>e.name),()=>{if(e.hidden)return t.span({className:`label danger field-hidden-label`},`Hidden`)},()=>{if(e.maxSelect!==void 0)return t.span({className:`meta`},e.maxSelect>1?`multiple`:`single`)}))))),g),t.nav({className:`erd-nav`,onmousedown:e=>{e.stopImmediatePropagation()}},t.button({type:`button`,className:`btn sm circle secondary`,title:`Zoom in`,onclick:()=>{n.scale+=.05}},t.i({className:`ri-add-line`,ariaHidden:!0})),t.button({type:`button`,className:`btn sm circle secondary`,title:`Zoom out`,onclick:()=>{n.scale-=.05}},t.i({className:`ri-subtract-line`,ariaHidden:!0})))),a};function At(e,n,r=1,i=``,a=``,o=2){if(!e||!n)return;let s=e.closest(`.erd-area`).getBoundingClientRect(),c=e.getBoundingClientRect(),l=n.getBoundingClientRect();o*=r;let u=c.top-s.top+c.height/2,d=l.top-s.top+l.height/2,f,p;c.leftl.left?(f=c.left-s.left-o,p=l.left-s.left+l.width+o):(f=c.left-s.left-o,p=l.left-s.left-o),f/=r,p/=r,u/=r,d/=r;let m=f+(p-f)/2;f==p&&(m-=20);let h=`M ${f} ${u} L ${m} ${u} L ${m} ${d} - L ${p} ${d}`,g=document.createElementNS(`http://www.w3.org/2000/svg`,`path`);return g.setAttribute(`class`,`relation-path`),g.setAttribute(`data-from`,i||``),g.setAttribute(`data-to`,a||``),g.setAttribute(`d`,h),g}window.app=window.app||{},window.app.components=window.app.components||{};var jt=1e3;window.app.components.pageSidebar=function(e={},...n){let r,i=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,widthHistoryKey:`pbPageSidebarWidth`,onmount:void 0,onunmount:void 0}),a=app.utils.extendStore(i,e),o=store({responsiveShow:!1}),s;function c(){if(r){if(window.innerWidth>jt){o.responsiveShow=!1,r.dataset.responsive=!1,s?.remove(),s=null;return}r.dataset.responsive=!0,s||(s=t.button({type:`button`,className:`btn transparent secondary responsive-sidebar-btn`,title:`Toggle sidebar`,onclick:e=>{e.stopPropagation(),o.responsiveShow=!o.responsiveShow}},t.i({className:`ri-menu-2-line`,ariaHidden:!0})),document.body.querySelector(`.page-header .breadcrumbs`).before(s))}}function l(e){if(e.target.closest(`.responsive-close`)){o.responsiveShow=!1;return}if(!(e.target.closest(`.page-sidebar`)||e.target.closest(`.app-header`)||e.target.closest(`.modal`)))return e.preventDefault(),e.stopImmediatePropagation(),o.responsiveShow=!1,!1}return a.push(watch(()=>o.responsiveShow,e=>{e?window.addEventListener(`click`,l,!0):window.removeEventListener(`click`,l,!0)})),r=t.aside({pbEvent:`pageSidebar`,rid:i.rid,id:()=>i.id,hidden:()=>i.hidden,inert:()=>i.inert,className:()=>`page-sidebar ${i.className} ${o.responsiveShow?`active`:``}`,onmount:e=>{c(e),window.addEventListener(`resize`,c),i.onmount?.(e)},onunmount:e=>{i.onunmount?.(e),window.removeEventListener(`click`,l,!0),window.removeEventListener(`resize`,c),s?.remove(),a.forEach(e=>e?.unwatch())}},e=>{let n;return i.widthHistoryKey&&(n=localStorage.getItem(i.widthHistoryKey),n&&(e.style.width=n)),app.components.dragline({ondragstart:n=>{e._startWidth=e.offsetWidth},ondragging:(r,a,o)=>{n=e._startWidth+a+`px`,e.style.width=n,i.widthHistoryKey&&localStorage.setItem(i.widthHistoryKey,n)}})},...n),r};var Mt=`modulepreload`,W=function(e,n){return new URL(e,n).href},Nt={},G=function(e,n,r){let i=Promise.resolve();if(n&&n.length>0){let e=document.getElementsByTagName(`link`),a=document.querySelector(`meta[property=csp-nonce]`),o=a?.nonce||a?.getAttribute(`nonce`);function s(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function c(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}i=s(n.map(n=>{if(n=W(n,r),n=c(n),n in Nt)return;Nt[n]=!0;let i=n.endsWith(`.css`);for(let r=e.length-1;r>=0;r--){let a=e[r];if(a.href===n&&(!i||a.rel===`stylesheet`))return}let a=document.createElement(`link`);if(a.rel=i?`stylesheet`:Mt,i||(a.as=`script`),a.crossOrigin=``,a.href=n,o&&a.setAttribute(`nonce`,o),document.head.appendChild(a),i)return new Promise((e,r)=>{a.addEventListener(`load`,e),a.addEventListener(`error`,()=>r(Error(`Unable to preload CSS for ${n}`)))})}))}function a(e){let n=new Event(`vite:preloadError`,{cancelable:!0});if(n.payload=e,window.dispatchEvent(n),!n.defaultPrevented)throw e}return i.then(n=>{for(let e of n||[])e.status===`rejected`&&a(e.reason);return e().catch(a)})};window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openApiPreview=function(e,n={onbeforeopen:null,onafteropen:null,onbeforeclose:null,onafterclose:null}){let r=Pt(e,n);r&&(document.body.appendChild(r),app.modals.open(r))};function Pt(e,n){if(!e){console.warn(`[apiPreviewModal] missing required collection`);return}let r,i=store({activeTab:`List/Search`,tabEl:null,isLoading:!1}),a={"List/Search":async e=>{let{docsList:n}=await G(async()=>{let{docsList:e}=await import(`./docsList-DsIHfo2q.js`);return{docsList:e}},__vite__mapDeps([0,1,2]),import.meta.url);return i.tabEl=n(e)},View:async e=>{let{docsView:n}=await G(async()=>{let{docsView:e}=await import(`./docsView-oyuvqZP8.js`);return{docsView:e}},__vite__mapDeps([3,1,2]),import.meta.url);return i.tabEl=n(e)}};e.type!=`view`&&(a.Create=async e=>{let{docsCreate:n}=await G(async()=>{let{docsCreate:e}=await import(`./docsCreate-Ap21j9FE.js`);return{docsCreate:e}},__vite__mapDeps([4,1,2]),import.meta.url);return i.tabEl=n(e)},a.Update=async e=>{let{docsUpdate:n}=await G(async()=>{let{docsUpdate:e}=await import(`./docsUpdate-DAnNYWFv.js`);return{docsUpdate:e}},__vite__mapDeps([5,1,2,4]),import.meta.url);return i.tabEl=n(e)},a.Delete=async e=>{let{docsDelete:n}=await G(async()=>{let{docsDelete:e}=await import(`./docsDelete-CeK6pY9P.js`);return{docsDelete:e}},[],import.meta.url);return i.tabEl=n(e)},a.Realtime=async e=>{let{docsRealtime:n}=await G(async()=>{let{docsRealtime:e}=await import(`./docsRealtime-pRgUAX2q.js`);return{docsRealtime:e}},[],import.meta.url);return i.tabEl=n(e)},a.Batch=async e=>{let{docsBatch:n}=await G(async()=>{let{docsBatch:e}=await import(`./docsBatch-CQUyIsim.js`);return{docsBatch:e}},[],import.meta.url);return i.tabEl=n(e)}),e.type==`auth`&&(a[``]=null,a[`List auth methods`]=async e=>{let{docsListAuthMethods:n}=await G(async()=>{let{docsListAuthMethods:e}=await import(`./docsListAuthMethods-CYETXzX7.js`);return{docsListAuthMethods:e}},__vite__mapDeps([6,2]),import.meta.url);return i.tabEl=n(e)},a[`Auth with password`]=e.passwordAuth?.enabled?async e=>{let{docsAuthWithPassword:n}=await G(async()=>{let{docsAuthWithPassword:e}=await import(`./docsAuthWithPassword-NXiq7pZI.js`);return{docsAuthWithPassword:e}},__vite__mapDeps([7,1,2]),import.meta.url);return i.tabEl=n(e)}:null,e.name!=`_superusers`&&(a[`Auth with OAuth2`]=e.oauth2?.enabled?async e=>{let{docsAuthWithOAuth2:n}=await G(async()=>{let{docsAuthWithOAuth2:e}=await import(`./docsAuthWithOAuth2-qI6si9uJ.js`);return{docsAuthWithOAuth2:e}},__vite__mapDeps([8,1,2]),import.meta.url);return i.tabEl=n(e)}:null),a[`Auth with OTP`]=e.otp?.enabled?async e=>{let{docsAuthWithOTP:n}=await G(async()=>{let{docsAuthWithOTP:e}=await import(`./docsAuthWithOTP-75iz1Xmg.js`);return{docsAuthWithOTP:e}},__vite__mapDeps([9,1,2]),import.meta.url);return i.tabEl=n(e)}:null,a[`Auth refresh`]=async e=>{let{docsAuthRefresh:n}=await G(async()=>{let{docsAuthRefresh:e}=await import(`./docsAuthRefresh-Cq3xTY6M.js`);return{docsAuthRefresh:e}},__vite__mapDeps([10,1,2]),import.meta.url);return i.tabEl=n(e)},e.name!=`_superusers`&&(a.Verification=async e=>{let{docsVerification:n}=await G(async()=>{let{docsVerification:e}=await import(`./docsVerification-CIbF1DIL.js`);return{docsVerification:e}},[],import.meta.url);return i.tabEl=n(e)}),a[`Password reset`]=async e=>{let{docsPasswordReset:n}=await G(async()=>{let{docsPasswordReset:e}=await import(`./docsPasswordReset-UqmNW8HA.js`);return{docsPasswordReset:e}},[],import.meta.url);return i.tabEl=n(e)},a[`Email change`]=async e=>{let{docsEmailChange:n}=await G(async()=>{let{docsEmailChange:e}=await import(`./docsEmailChange-VWbqXOVy.js`);return{docsEmailChange:e}},[],import.meta.url);return i.tabEl=n(e)});let o=[watch(()=>i.activeTab,async()=>{i.isLoading=!0,await a[i.activeTab]?.(e),i.isLoading=!1})];return r=t.div({pbEvent:`apiPreviewModal`,className:`modal api-preview-modal`,onbeforeopen:e=>n.onbeforeopen?.(e),onafteropen:e=>{n.onafteropen?.(e)},onbeforeclose:e=>n.onbeforeclose?.(e),onafterclose:e=>{n.onafterclose?.(e),o.forEach(e=>e?.unwatch()),e?.remove()},onmount:e=>{},onunmount:e=>{o.forEach(e=>e?.unwatch())}},t.div({className:`modal-content`},t.aside({className:`api-preview-sidebar`},t.nav({className:`api-preview-nav`},()=>{let e=[];for(let n in a){if(!n){e.push(t.hr());continue}let r=!a[n];e.push(t.button({type:`button`,className:()=>`nav-item ${i.activeTab==n?`active`:``}`,disabled:r,ariaDescription:app.attrs.tooltip(()=>r?`Not enabled for the collection`:``,`left`),onclick:()=>{r||(i.activeTab=n)}},n))}return e})),t.div({className:()=>`api-preview-content ${i.isLoading?`faded`:``}`,scrollTop:()=>i.activeTab?0:null},t.header({className:`api-preview-content-header`},t.h6(null,()=>i.activeTab+` (${e.name})`),t.button({type:`button`,className:()=>`btn sm circle transparent secondary m-l-auto preview-close-btn ${i.isLoading?`loading`:``}`,title:`Close`,onclick:()=>app.modals.close(r)},t.i({className:`ri-close-line`,ariaHidden:!0}))),()=>i.tabEl))),r}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openMailTest=function(e=``,n=``){let r=Ft(e,n);document.body.appendChild(r),app.modals.open(r)};function Ft(e=``,n=``){let r=`mail_test_`+app.utils.randomString(),i=`pbLastTestEmail`,a=`email_test_request`,o=[{label:`Verification`,value:`verification`},{label:`Password reset`,value:`password-reset`},{label:`Confirm email change`,value:`email-change`},{label:`OTP`,value:`otp`},{label:`Login alert`,value:`login-alert`}],s=store({email:localStorage.getItem(i)||app.store.superuser?.email||``,template:n||o[0].value,isSending:!1,collectionIdOrName:e,get isAuthCollectionsLoading(){return app.store.isCollectionsLoading},get authCollections(){return app.utils.sortedCollections(app.store.collections.filter(e=>e.type==`auth`))},get canSubmit(){return!!s.email&&!!s.template&&!!s.collectionIdOrName}}),c;async function l(){if(!(s.isSending||!s.canSubmit)){s.isSending=!0,clearTimeout(c),c=setTimeout(()=>{s.isSending=!1,app.pb.cancelRequest(a),app.modals.close(),app.toasts.error(`Test email send timeout.`)},15e3);try{s.email!=app.pb.authStore.record?.email&&localStorage.setItem(i,s.email),await app.pb.settings.testEmail(s.collectionIdOrName,s.email,s.template,{requestKey:a}),app.toasts.success(`Successfully sent test email.`),app.modals.close()}catch(e){app.checkApiError(e)}s.isSending=!1,clearTimeout(c)}}let u=[];return t.div({className:`modal popup sm`,onbeforeopen:e=>{u.push(watch(()=>s.isAuthCollectionsLoading,e=>{!e&&!s.collectionIdOrName&&(s.collectionIdOrName=s.authCollections[0]?.id||``)}))},onafterclose:e=>{clearTimeout(c),e?.remove()},onunmount:()=>{clearTimeout(c),u.forEach(e=>e?.unwatch())}},t.header({className:`modal-header`},t.h5({className:`m-auto`},`Send test email`)),t.form({id:r,className:`modal-content mail-settings-test-form`,onsubmit:e=>{e.preventDefault(),l()}},t.div({className:`grid`},t.div({className:`col-lg-12`},()=>o.map((e,n)=>t.field({className:()=>`field ${n>0?`m-t-10`:``}`},t.input({type:`radio`,id:r+`.template.`+e.value,name:`template`,checked:()=>s.template==e.value,onchange:n=>s.template=e.value}),t.label({htmlFor:r+`.template.`+e.value},e.label||e.value)))),()=>{if(!e)return t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`.collection`},`Auth collection`),app.components.select({id:r+`.collection`,name:`collection`,required:!0,placeholder:()=>s.isAuthCollectionsLoading?`Loading auth collections...`:`Select auth collection`,options:()=>s.authCollections.map(e=>({value:e.id,label:e.name})),value:()=>s.collectionIdOrName||``,onchange:e=>{s.collectionIdOrName=e?.[0]?.value}})))},t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`.email`},`To email address`),t.input({id:r+`.email`,name:`email`,type:`email`,required:!0,value:()=>s.email||``,oninput:e=>s.email=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>s.isSending},t.span({className:`txt`},`Close`)),t.button({"html-form":r,type:`submit`,className:()=>`btn expanded ${s.isSending?`loading`:``}`,disabled:()=>s.isSending||!s.canSubmit},t.i({className:`ri-mail-send-line`,ariaHidden:!0}),t.span({className:`txt`},`Send`))))}function It(e={}){let n=store({rid:void 0,collectionA:null,collectionB:null,deleteMissing:!1,className:``}),r=app.utils.extendStore(n,e),i=store({hasAnyChange:!1,get isDeleteDiff(){return!n.collectionB?.id&&!n.collectionB?.name},get isCreateDiff(){return!i.isDeleteDiff&&!n.collectionA?.id},get hasAnyChange(){return app.utils.hasCollectionChanges(n.collectionA,n.collectionB,n.deleteMissing)},get fieldsListA(){return Array.isArray(n.collectionA?.fields)?n.collectionA?.fields:[]},get fieldsListB(){let e=Array.isArray(n.collectionB?.fields)?n.collectionB?.fields:[];return n.deleteMissing||(e=e.concat(n.collectionA?.fields?.filter(n=>!e.find(e=>n.id==e.id))||[])),e},get mainModelProps(){return app.utils.mergeUnique(Object.keys(n.collectionA||{}),Object.keys(n.collectionB||{})).filter(e=>![`fields`,`created`,`updated`].includes(e))},get removedFields(){return i.fieldsListA.filter(e=>!i.fieldsListB.find(n=>e.id==n.id))},get sharedFields(){return i.fieldsListB.filter(e=>i.fieldsListA.find(n=>n.id==e.id))},get addedFields(){return i.fieldsListB.filter(e=>!i.fieldsListA.find(n=>n.id==e.id))}});function a(e){return e===void 0?``:app.utils.isObject(e)?JSON.stringify(e,null,4):``+e}function o(e,n){return e!==n&&JSON.stringify(e)!=JSON.stringify(n)}function s(e,n){return(e||[]).find(e=>e.id==n)}return t.div({rid:n.rid,pbEvent:`collectionsDiffTableWrapper`,className:()=>`collections-diff-table-wrapper ${n.className}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.div({className:`collections-diff-table-title`},()=>n.collectionA?.id?n.collectionB?.id?[t.span({hidden:()=>!i.hasAnyChange,className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(n.collectionA?.name!=n.collectionB?.name)return[t.strong({className:`txt-strikethrough txt-hint`,textContent:n.collectionA?.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>n.collectionB?.name}))]:[t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.strong({textContent:()=>n.collectionA?.name})]:[t.span({className:`label import-change-label success`,textContent:`Added`}),t.strong({textContent:()=>n.collectionB?.name})]),t.table({className:`collections-diff-table`},t.thead(null,t.tr(null,t.th({className:`min-width`},`Props`),t.th({width:`40%`},`Old`),t.th({width:`40%`},`New`))),t.tbody(null,()=>i.mainModelProps.map(e=>{let r=o(n.collectionA?.[e],n.collectionB?.[e]);return t.tr({className:r?`txt-primary`:``},t.td({className:`min-width`},e),t.td({className:()=>i.isCreateDiff?`changed-non-col`:r?`changed-old-col`:``},t.pre({className:`txt diff-value`},a(n.collectionA?.[e]))),t.td({className:()=>i.isDeleteDiff?`changed-non-col`:r?`changed-new-col`:``},t.pre({className:`txt diff-value`},a(n.collectionB?.[e]))))}),()=>{if(!n.deleteMissing&&!i.isDeleteDiff)return;let e=[];for(let n of i.removedFields){e.push(t.tr(null,t.th({className:`min-width`,colSpan:3},t.span({className:`txt`},`field: `,n.name),t.span({className:`label danger m-l-5`},`Deleted - `,t.small(null,`All stored data related to '${n.name}' will be deleted!`)))));for(let r in n){let i=n[r];e.push(t.tr(null,t.td({className:`min-width field-key-col`},r),t.td({className:`changed-old-col`},t.pre({className:`txt`},a(i))),t.td({className:`changed-none-col`})))}}return e},()=>{let e=[];for(let n of i.sharedFields){let r=s(i.fieldsListA,n.id),c=o(r,s(i.fieldsListB,n.id));e.push(t.tr(null,t.th({className:`min-width`,colSpan:3},t.span({className:`txt`},`field: `,n.name),t.span({className:`label warning m-l-5 ${c?``:`hidden`}`,textContent:`Changed`}))));for(let i in n){let s=n[i],c=o(r?.[i],s);e.push(t.tr({className:c?`txt-primary`:``},t.td({className:`min-width field-key-col`},i),t.td({className:c?`changed-old-col`:``},t.pre({className:`txt`},a(r?.[i]))),t.td({className:c?`changed-new-col`:``},t.pre({className:`txt`},a(s)))))}}return e},()=>{let e=[];for(let n of i.addedFields){e.push(t.tr(null,t.th({className:`min-width`,colSpan:3},t.span({className:`txt`},`field: `,n.name),t.span({className:`label success m-l-5`},`Added`))));for(let r in n){let i=n[r];e.push(t.tr({className:`txt-primary`},t.td({className:`min-width field-key-col`},r),t.td({className:`changed-none-col`}),t.td({className:`changed-new-col`},t.pre({className:`txt`},a(i)))))}}return e})))}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openImportCollectionsReview=function(e,n,r={deleteMissing:!1,onsubmit:null}){let i=Lt(e,n,r);i&&(document.body.appendChild(i),app.modals.open(i))};function Lt(e,n,r){let i,a=store({deleteMissing:!1,onsubmit:function(e){}}),o=app.utils.extendStore(a,r),s=store({isImporting:!1,pairs:[]});function c(){let r=[];for(let i of e){let e=n.find(e=>e.id==i.id);(a.deleteMissing&&!e?.id||e?.id&&app.utils.hasCollectionChanges(i,e,a.deleteMissing))&&r.push({old:i,new:e})}for(let i of n){let n=e.find(e=>e.id==i.id);n?.id||r.push({old:n,new:i})}s.pairs=r}function l(){let r=[];if(a.deleteMissing)for(let i of e){let e=n.find(e=>e.id==i.id);if(!e)r.push(i.name+`.*`);else{let n=Array.isArray(i.fields)?i.fields:[];for(let a of n)e.fields?.find(e=>e.id==a.id)||r.push(`${i.name}.${a.name} (${a.id})`)}}r.length?app.modals.confirm([t.h6(null,`Do you really want to delete the following collection fields and their related records data:`),t.ul(null,()=>r.map(e=>t.li(null,e)))],()=>u()):u()}async function u(){if(!s.isImporting){s.isImporting=!0;try{await app.pb.collections.import(n,a.deleteMissing),await app.store.loadCollections(),a.onsubmit?.(JSON.parse(JSON.stringify(app.store.collections))),app.toasts.success(`Successfully imported collections configuration.`)}catch(e){app.checkApiError(e)}s.isImporting=!1,app.modals.close(i)}}return i=t.div({pbEvent:`importCollectionsReviewModal`,className:`modal popup full import-collections-review-modal`,onbeforeopen:()=>{c()},onbeforeclose:()=>!s.isImporting,onafterclose:e=>{e?.remove()},onunmount:()=>{o.forEach(e=>e?.unwatch())}},t.header({className:`modal-header`},t.h5(null,`Side-by-side diff`)),t.div({className:`modal-content`},()=>s.pairs.map(e=>It({collectionA:e.old,collectionB:e.new,deleteMissing:a.deleteMissing}))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>s.isImporting,onclick:()=>app.modals.close(i)},t.span({className:`txt`},`Close`)),t.button({type:`button`,className:()=>`btn expanded ${s.isImporting?`loading`:``}`,disabled:()=>s.isImporting,onclick:()=>l()},t.span({className:`txt`},`Confirm and import`)))),i}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.recordSummary=function(e,n=null){let r=store({get collection(){return app.store.collections.find(n=>n.id==e.collectionId||n.name==e.collectionName)},get presentableFields(){if(!r.collection?.id)return[];let e=r.collection.fields.filter(e=>e.presentable).sort((e,n)=>{let r=app.fieldTypes[e.type].summaryPriority||0,i=app.fieldTypes[n.type].summaryPriority||0;return r>i?1:re.name==n);if(i){e.push(i);break}}return e}});return t.div({className:`label record-summary`},t.i({ariaHidden:!0,className:`ri-eye-line link-hint record-preview-icon`,onclick:e=>{e.stopImmediatePropagation(),e.preventDefault()},onmouseenter:n=>{zt(n.target,e,100)},onmouseleave:e=>{Rt(e.target,100)},onunmount:e=>{Rt(e,0)}}),()=>{let i=[];function a(e){(e==null||e==``)&&(e=t.span({className:`missing-value`})),i.push(e)}for(let i of r.presentableFields){let r=app.fieldTypes[i.type]?.view;if(r)a(r({short:!0,get record(){return e},get field(){return i},get meta(){return n}}));else{let n=app.utils.toArray(e[i.name]).splice(0,3);for(let e of n)a(e)}}return i})};function Rt(e,n=150){if(e){if(clearTimeout(e._summaryDropdownTimeoutId),n<=0){e?._summaryDropdown?.hidePopover?.();return}e._summaryDropdownTimeoutId=setTimeout(()=>{e?._summaryDropdown?.hidePopover?.()},n)}}function zt(e,n,r=150){if(e){if(clearTimeout(e._summaryDropdownTimeoutId),r<=0){Bt(e,n);return}e._summaryDropdownTimeoutId=setTimeout(()=>{Bt(e,n)},r)}}var Bt=function(e,n){e&&(e._summaryDropdown||(e._summaryDropdown=t.div({className:`dropdown record-summary-dropdown`,popover:`manual`,onclick:e=>{e.stopImmediatePropagation(),e.preventDefault()}},t.div({className:`record-header`},t.a({className:`link-hint txt-bold m-r-auto`,target:`_blank`,href:`#/collections?collection=${n.collectionName}&record=${n.id}`,onclick:e=>{e.stopImmediatePropagation()}},t.span({className:`txt`},`Edit relation record`),t.i({className:`ri-external-link-line`,ariaHidden:!0})),t.button({type:`button`,className:`link-hint`,title:`Close`,onclick:()=>Rt(e,0)},t.i({className:`ri-close-line`,ariaHidden:!0}))),t.hr(),t.pre({className:`record-json`},()=>{let e=app.store.collections.find(e=>e.id==n.collectionId||e.name==n.collectionName)?.fields||[];if(!e.length)return;let r={collectionId:n.collectionId,collectionName:n.collectionName};for(let i of e)r[i.name]=n[i.name];return JSON.stringify(app.utils.truncateObject(r,27),null,2)})),e.appendChild(e._summaryDropdown)),e._summaryDropdown?.showPopover({source:e}))};window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.recordsSearchbar=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,disabled:void 0,value:``,className:``,collection:void 0,onsubmit:e=>{}}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`full-width records-searchbar-wrapper ${n.className}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},app.components.searchbar({placeholder:()=>!n.disabled&&!n.collection?.id?`Loading...`:`Search term or filter...`,historyKey:()=>`pbRecordsSearchHistory_`+n.collection?.id,disabled:()=>n.disabled||!n.collection,value:()=>n.value,autocomplete:e=>app.utils.collectionAutocompleteKeys(n.collection,e,{requestKeys:!1,collectionJoinKeys:!1}),onsubmit:n.onsubmit}))},window.app=window.app||{},window.app.components=window.app.components||{};var K={max:10,pending:new Set,processing:new Set};function Vt(e){return K.pending.add(e),K.processing.size<=K.max&&Ht(),()=>{K.pending.delete(e),K.processing.delete(e),K.processing.sizen.id,hidden:()=>n.hidden,inert:()=>n.inert,type:`button`,draggable:!1,className:()=>`thumb ${n.extraClasses} ${i.isPreviewLoading?`loading`:``}`,title:()=>(i.hasPreview?`Preview`:`Download`)+` `+n.filename,onclick:async e=>{e.stopPropagation();async function r(){let e=await app.getFileToken(n.record.collectionId);return app.pb.files.getURL(n.record,n.filename,{token:e})}if(i.hasPreview)app.modals.openFilePreview(r);else{let e=await r();app.utils.download(e,n.filename)}},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(i.fileType==`image`){let e=t.img({draggable:!1,alt:()=>`Thumb of `+n.filename,src:()=>i.previewURL,onerror:n=>{console.warn(`[recordFileThumb] load err:`,n),i.isPreviewLoading=!1,e?._semaphoreRelease?.()},onload:()=>{i.isPreviewLoading=!1,e?._semaphoreRelease?.()},onmount:e=>{i.isPreviewLoading=!0,e._semaphoreRelease=Vt(async()=>{try{i.previewToken=await app.getFileToken(n.record.collectionId),i.previewURL=app.pb.files.getURL(n.record,n.filename,{thumb:`100x100`,token:i.previewToken})}catch(e){console.warn(e)}})},onunmount:e=>{i.isPreviewLoading=!1,e._semaphoreRelease?.()}});return e}return t.i({className:app.utils.fileTypeIcons[i.fileType]||`ri-file-line`,ariaHidden:!0})})},window.app=window.app||{},window.app.modals=window.app.modals||{};var Ut=100,Wt={btnText:`Insert`,fileTypes:[],onselect:function(e){}},q=`pbLastRecordFilePickerCollection`,J=`listFilePickerRecords`;window.app.modals.openRecordFilePicker=function(e={}){e=Object.assign({},Wt,e);let n=Y(e);document.body.appendChild(n),app.modals.open(n)};function Y(e=Wt){let n,r=`file_picker_`+app.utils.randomString(),i=store({selectedFile:{},records:[],activeCollectionId:``,searchTerm:``,lastRecordsPage:1,lastTotalRecords:0,isLoadingRecords:!1,get collections(){return app.utils.sortedCollections(app.store.collections.filter(e=>e.type!=`view`&&!!e.fields?.find(e=>e.type===`file`&&!e.protected)))},get activeCollection(){return i.collections.find(e=>e.id==i.activeCollectionId)||i.collections[0]},get activeCollectionFileFields(){return i.activeCollection?.fields?.filter(e=>e.type===`file`&&!e.protected)||[]},get isLoading(){return app.store.isLoadingCollections||i.isLoadingRecords},get canLoadMore(){return!i.isLoadingRecords&&i.lastTotalRecords==Ut},get hasAtleastOneFile(){return!!i.records.find(e=>c(e).length>0)}}),a=[];a.push(watch(()=>{i.activeCollectionId?(window.localStorage.setItem(q,i.activeCollectionId),i.searchTerm=``):i.activeCollectionId=window.localStorage.getItem(q)})),a.push(watch(()=>[i.activeCollection,i.searchTerm],()=>s(!0)));function o(){app.pb.cancelRequest(J),i.isLoadingRecords=!1,i.records=[],i.lastTotalRecords=0,i.lastRecordsPage=1,i.selectedFile={}}async function s(e=!1){if(!i.activeCollection){o();return}e&&o(),i.isLoadingRecords=!0;try{let n=e?1:i.lastRecordsPage+1,r=app.utils.getAllCollectionIdentifiers(i.activeCollection),a=app.utils.normalizeSearchFilter(i.searchTerm,r)||``;a&&(a+=` && `),a+=`(`+i.activeCollectionFileFields.map(e=>`${e.name}:length>0`).join(`||`)+`)`;let o=await app.pb.collection(i.activeCollection.id).getList(n,Ut,{requestKey:J,filter:a,skipTotal:1,sort:i.activeCollection.type==`view`?``:`-@rowid`});i.lastRecordsPage=o.page,i.lastTotalRecords=o.items.length,i.records=app.utils.filterDuplicatesByKey(i.records.concat(o.items)),i.isLoadingRecords=!1}catch(e){e.isAbort||(i.isLoadingRecords=!1,app.checkApiError(e))}}function c(n){let r=[];for(let a of i.activeCollectionFileFields){let i=app.utils.toArray(n[a.name]);for(let n of i)(app.utils.isEmpty(e.fileTypes)||e.fileTypes?.includes(app.utils.getFileType(n)))&&r.push(n)}return r}function l(e,n){i.selectedFile={record:e,name:n,thumb:``}}function u(e,n){return i.selectedFile?.name==n&&i.selectedFile?.record?.id==e?.id}let d={"record:create":e=>{e.detail.collectionId==i.activeCollection?.id&&(i.selectedFile?.record?.id==e.detail.id&&(i.selectedFile.record=e.detail),s(!0))},"record:delete":e=>{e.detail.collectionId!=i.activeCollection?.id&&e.detail.collectionName!=i.activeCollection?.name||(i.selectedFile?.record?.id==e.detail.id&&(i.selectedFile={}),s(!0))}};return n=t.div({className:`modal popup record-file-picker-modal`,onafterclose:e=>{e?.remove()},onmount:e=>{for(let e in d)document.addEventListener(e,d[e])},onunmount:e=>{a.forEach(e=>e?.unwatch());for(let e in d)document.removeEventListener(e,d[e])}},t.header({className:`modal-header`},t.button({className:()=>`btn primary outline record-file-picker-collection-select-btn ${app.store.isLoadingCollections?`loading`:``}`,disabled:()=>app.store.isLoadingCollections,"html-popovertarget":`collections_dropdown`+r},t.span({className:`txt-lg collection-name m-r-auto`},()=>i.activeCollection?.name||`Select collection`),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0})),t.div({id:`collections_dropdown`+r,className:`dropdown`,popover:`hint`},()=>i.collections.map(e=>t.button({type:`button`,className:()=>`dropdown-item ${i.activeCollectionId==e.id?`active`:``}`,onclick:n=>{i.activeCollectionId=e.id,n.target?.closest(`.dropdown`)?.hidePopover()}},e.name))),app.components.recordsSearchbar({disabled:()=>!i.activeCollection?.id,collection:()=>i.activeCollection,value:()=>i.searchTerm,onsubmit:e=>i.searchTerm=e}),t.button({type:`button`,className:`btn circle transparent`,ariaLabel:app.attrs.tooltip(`Add new record`),onclick:()=>app.modals.openRecordUpsert(i.activeCollection)},t.i({className:`ri-add-line txt-hint`,ariaHidden:!0}))),t.div({className:`modal-content`},t.div({className:`block txt-center`,hidden:()=>i.hasAtleastOneFile||!i.isLoading},t.span({className:`loader`})),t.div({className:`record-file-picker-list`},()=>{let e=[];for(let n of i.records){let r=c(n);for(let i of r)e.push(t.button({rid:n.id+`:`+i,className:()=>`list-item thumb ${u(n,i)?`success`:``}`,ariaDescription:app.attrs.tooltip(i,`bottom`),onclick:()=>l(n,i)},()=>{if(app.utils.hasImageExtension(i))return t.img({loading:`lazy`,src:app.pb.files.getURL(n,i,{thumb:`100x100`}),alt:i});let e=app.utils.getFileType(i);return t.i({className:app.utils.fileTypeIcons[e]||`ri-file-line`,ariaHidden:!0})}))}return e}),t.div({hidden:()=>!i.canLoadMore||!i.hasAtleastOneFile,className:`block txt-center`},t.button({className:()=>`btn secondary expanded-lg m-t-base ${i.isLoadingRecords?`loading`:``}`,disabled:()=>i.isLoadingRecords,onclick:()=>s()},t.span({className:`txt`},`Load more`))),t.div({className:`block txt-center txt-hint p-t-10 p-b-10`,hidden:()=>i.hasAtleastOneFile||i.isLoading},()=>app.utils.isEmpty(e.fileTypes)?t.p(null,`No records with selectable files found.`):t.p(null,`No "${e.fileTypes.join(`", "`)}" files found.`),t.button({type:`button`,className:`btn sm secondary`,textContent:`Clear search`,hidden:()=>!i.searchTerm?.length,onclick:()=>{i.searchTerm=``}}))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Close`)),()=>{if(!i.selectedFile?.name||!app.utils.hasImageExtension(i.selectedFile.name))return;let e=[{value:``,label:`Original size`},{value:`100x100`,label:`100x100 thumb`}],n=i.activeCollectionFileFields.find(e=>i.selectedFile.record[e.name].includes(i.selectedFile.name)),r=app.utils.toArray(n.thumbs);for(let n of r)e.push({value:n,label:`${n} thumb`});return t.div({className:`record-file-picker-thumb-select`},app.components.select({required:!0,value:i.selectedFile.thumb||``,options:e,onchange:e=>{i.selectedFile.thumb=e?.[0].value}}))},t.button({type:`button`,className:`btn expanded`,disabled:()=>i.isLoading||!i.selectedFile?.name,onclick:()=>{let r=JSON.parse(JSON.stringify(i.selectedFile));if(e.onselect&&e.onselect(r)===!1)return!1;app.modals.close(n)}},t.span({className:`txt`},()=>e.btnText||Wt.btnText)))),n}window.app=window.app||{},window.app.modals=window.app.modals||{};var Gt=50,Kt=100,qt=`listRelationPickerRecords`,Jt={collection:``,selectedIds:[],maxSelect:1,btnText:`Set selection`,onselect:function(e){}};window.app.modals.openRecordsPicker=function(e={}){e=Object.assign({},Jt,e);let n=Yt(e);document.body.appendChild(n),app.modals.open(n)};function Yt(e=Jt){let n,r=store({searchTerm:``,selected:[],preselected:[],isLoadingPreselected:!1,records:[],isLoadingRecords:!1,lastRecordsPage:1,lastRecordsTotal:0,get collection(){let n=e.collection;return typeof e.collection==`object`&&e.collection?.id&&(n=e.collection?.id),app.store.collections.find(e=>e.id==n||e.name==n)},get isLoading(){return r.isLoadingPreselected||r.isLoadingRecords},get canLoadMore(){return!r.isLoadingRecords&&r.lastRecordsTotal==Gt}}),i=[watch(()=>[e.collection,e.selectedIds],()=>{o()}),watch(()=>[r.collection,r.searchTerm],()=>{s(!0)})];function a(){setTimeout(()=>app.modals.close(n),0)}async function o(){let n=app.utils.toArray(e.selectedIds),i=e.collection?.id||e.collection;if(!i||!n.length)return;r.isLoadingSelected=!0;let a=[],o=n.slice(),s=[];for(;o.length>0;){let e=[],n=o.splice(0,Kt);for(let r of n)e.push(`id="${r}"`);s.push(app.pb.collection(i).getFullList({requestKey:null,filter:e.join(`||`)}))}try{await Promise.all(s).then(e=>{a=a.concat(...e)});let e=[];for(let r of n){let n=a.find(e=>e.id==r);n&&e.push(n)}r.searchTerm.trim()||(r.records=app.utils.filterDuplicatesByKey(e.concat(r.records))),r.selected=e,r.isLoadingSelected=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoadingSelected=!1)}}async function s(e=!1){if(r.collection?.id){e&&(c(),r.searchTerm.trim()||(r.records=r.selected.slice())),r.isLoadingRecords=!0;try{let n=e?1:r.lastRecordsPage+1,i=app.utils.getAllCollectionIdentifiers(r.collection),a=app.utils.normalizeSearchFilter(r.searchTerm,i)||``,o=await app.pb.collection(r.collection.id).getList(n,Gt,{requestKey:qt,filter:a,skipTotal:1,sort:r.collection.type==`view`?``:`-@rowid`});r.lastRecordsPage=o.page,r.lastRecordsTotal=o.items.length,r.records=app.utils.filterDuplicatesByKey(r.records.concat(o.items)),r.isLoadingRecords=!1}catch(e){e.isAbort||(r.isLoadingRecords=!1,app.checkApiError(e))}}}function c(){app.pb.cancelRequest(qt),r.isLoadingRecords=!1,r.records=[],r.lastTotalRecords=0,r.lastRecordsPage=1}function l(e){e.target.scrollHeight-e.target.clientHeight-e.target.scrollTop<=100&&r.canLoadMore&&s()}function u(n){let i=r.selected.findIndex(e=>e.id==n.id);if(i>=0)r.selected.splice(i,1);else{let i=e.maxSelect||1,a=r.selected.length-i;for(;a>=0;)r.selected.pop(),a--;r.selected.push(n)}}function d(e){return r.selected.findIndex(n=>n.id==e.id)>=0}let f={"record:save":e=>{if(e.detail.collectionId!=r.collection?.id)return;let n=r.selected?.findIndex(n=>n.id==e.detail.id);n>=0&&(r.selected[n]=e.detail),app.utils.pushOrReplaceObject(r.records,e.detail),s(!0)},"record:delete":e=>{e.detail.collectionId!=r.collection?.id&&e.detail.collectionName!=r.collection?.name||(d(e.detail)&&u(e.detail),app.utils.removeByKey(r.records,`id`,e.detail.id),s(!0))}};return n=t.div({className:`modal popup lg records-picker-modal`,onafterclose:e=>{e.remove()},onmount:e=>{for(let e in f)document.addEventListener(e,f[e])},onunmount:e=>{i.forEach(e=>e?.unwatch());for(let e in f)document.removeEventListener(e,f[e])}},t.header({className:`modal-header`},t.h6({className:`collection-name`},()=>r.collection.name),app.components.recordsSearchbar({disabled:()=>!r.collection?.id,collection:()=>r.collection,value:()=>r.searchTerm,onsubmit:e=>r.searchTerm=e}),t.button({type:`button`,className:`btn circle transparent`,ariaLabel:app.attrs.tooltip(`Add new record`),onclick:()=>{app.modals.openRecordUpsert(r.collection)}},t.i({className:`ri-add-line txt-hint`,ariaHidden:!0}))),t.div({className:`modal-content`,hidden:()=>r.isLoadingCollection},t.div({className:`list records-picker-list`,onscroll:l,onresize:l},()=>r.records.map(e=>t.div({tabIndex:0,className:`list-item handle`,onclick:()=>{u(e),document.activeElement?.blur()}},t.div({className:`content`},t.span({className:`state-icon`},t.i({ariaHidden:!0,className:()=>d(e)?`ri-checkbox-circle-fill txt-success`:`ri-checkbox-blank-circle-line txt-disabled`})),()=>app.components.recordSummary(e)),t.div({className:`actions autohide`},t.button({className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Edit`),onclick:n=>{n.stopPropagation(),app.modals.openRecordUpsert(r.collection,e)}},t.i({className:`ri-pencil-line`,ariaHidden:!0}))))),t.div({className:`list-item`,hidden:()=>!r.isLoading},t.div({className:`skeleton-loader`})),t.div({className:`list-item`,hidden:()=>r.records.length||r.isLoading},t.div({className:`content txt-hint`},t.span({className:`txt`},`No records found.`),t.button({type:`button`,className:`btn sm secondary`,textContent:`Clear search`,hidden:()=>!r.searchTerm.trim().length,onclick:()=>{r.searchTerm=``}})))),t.div({className:`block m-t-base`},t.p({className:`txt-bold`},()=>`Selected (${r.selected.length} of max ${e.maxSelect||1})`),t.span({className:`txt-hint`,hidden:()=>r.selected},`No selected records.`),app.components.sortable({className:`records-picker-selected-list`,data:()=>r.selected,dataItem:(e,n)=>t.div({rid:e,className:`label handle`},()=>app.components.recordSummary(e,[],!0),t.span({className:`link-hint`,title:`Remove`,role:`button`,onclick:()=>u(e)},t.i({className:`ri-close-line`,ariaHidden:!0}))),onchange:(e,n,i)=>{r.selected=e}}))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>a()},t.span({className:`txt`},`Close`)),()=>{if(!r.selectedFile?.name||!app.utils.hasImageExtension(r.selectedFile.name))return;let e=[{value:``,label:`Original size`},{value:`100x100`,label:`100x100 thumb`}],n=r.activeCollectionFileFields.find(e=>r.selectedFile.record[e.name].includes(r.selectedFile.name)),i=app.utils.toArray(n.thumbs);for(let n of i)e.push({value:n,label:`${n} thumb`});return t.div({className:`record-file-picker-thumb-select`},app.components.select({required:!0,value:r.selectedFile.thumb||``,options:e,onchange:e=>{r.selectedFile.thumb=e?.[0].value}}))},t.button({type:`button`,className:`btn expanded`,disabled:()=>r.isLoadingCollection,onclick:()=>{let n=JSON.parse(JSON.stringify(r.selected));if(e.onselect&&e.onselect(n)===!1)return!1;a()}},t.span({className:`txt`},e.btnText||Jt.btnText)))),n}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openRecordPreview=function(e,n={onbeforeopen:null,onafteropen:null,onbeforeclose:null,onafterclose:null}){let r=X(e,n);r&&(document.body.appendChild(r),app.modals.open(r))};function Xt(e){e.expand&&(e=Object.assign({},e),delete e.expand),app.utils.downloadJSON(e,e.collectionName+`_`+e.id+`.json`)}function Zt(e){e.expand&&(e=Object.assign({},e),delete e.expand),app.utils.copyToClipboard(JSON.stringify(e,null,2)),app.toasts.success(`Record copied to clipboard!`)}function X(e,n){if(!e?.id){app.toasts.error(`Failed to load record.`),console.warn(`[recordPreviewModal] missing required record id field:`,e);return}if(!e.collectionId&&!e.collectionName){app.toasts.error(`Failed to load record.`),console.warn(`[recordPreviewModal] missing required collectionId or collectionName field:`,e);return}let r,i=app.utils.randomString(),a=store({isLoading:!1,record:null,get collection(){return app.store.collections.find(n=>n.id==e.collectionId||n.name==e.collectionName)}});async function o(){a.isLoading=!0;try{a.record=JSON.parse(JSON.stringify(e));let n=[],r=a.collection?.fields?.filter(e=>!e.hidden&&e.type==`relation`)||[];for(let e of r)n.push(e.name);let i=await app.pb.collection(e.collectionName||e.collectionId).getOne(e.id,{requestKey:`record_preview_`+e.id,expand:n.join(`,`)||void 0});Object.assign(a.record,i),a.isLoading=!1}catch(e){e?.isAbort||(a.isLoading=!1,app.checkApiError(e),setTimeout(()=>app.modals.close(r),0))}}return r=t.div({pbEvent:`recordPreviewModal`,className:`modal record-preview-modal`,onbeforeopen:e=>(o(),n.onbeforeopen?.(e)),onafteropen:e=>{n.onafteropen?.(e)},onbeforeclose:e=>n.onbeforeclose?.(e),onafterclose:e=>{n.onafterclose?.(e),e?.remove()}},t.header({className:`modal-header`},t.h6(null,t.strong(null,()=>e?.collectionName||a.collection?.name),` record preview`),t.button({title:`More options`,className:()=>`btn sm circle transparent m-l-auto ${a.isLoading?`loading`:``}`,disabled:()=>a.isLoading,"html-popovertarget":i+`preview-dropdown`},t.i({className:`ri-more-line`,ariaHidden:!0})),t.div({id:i+`preview-dropdown`,className:`dropdown`,popover:`auto`},e=>t.button({className:`dropdown-item`,onclick:()=>{Zt(a.record),e.hidePopover()}},t.i({className:`ri-braces-line`,ariaHidden:!0}),t.span({className:`txt`},`Copy JSON`)))),t.div({className:`modal-content`},t.table({pbEvent:`recordPreviewTable`,className:`record-preview-table responsive-table`},t.tbody(null,()=>(a.collection?.fields?.filter(e=>e.type!=`password`)||[]).map(e=>t.tr(null,t.th({className:()=>`min-width p-r-0 col-field-name-${e.name}`},e.name),t.td({className:()=>`col-field-name-${e.name}`},()=>app.fieldTypes[e.type]?.view?app.fieldTypes[e.type].view({short:!1,get record(){return a.record},get field(){return e}}):app.utils.displayValue(a.record[e.name],1e3))))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(r)},t.span({className:`txt`},`Close`)),t.button({type:`button`,className:()=>`btn ${a.isLoading?`loading`:``}`,disabled:()=>a.isLoading,onclick:()=>Xt(a.record)},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download JSON`)))),r}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openRecordImpersontate=function(e){let n=Qt(e);document.body.appendChild(n),app.modals.open(n)};function Qt(e){let n=`impersonate_`+app.utils.randomString(),r=store({isLoading:!1,token:``,duration:0,get collection(){return app.store.collections.find(n=>n.id==e.collectionId||n.name==e.collectionName)}}),i=app.utils.getApiExampleURL();async function a(){if(!r.isLoading){r.isLoading=!0;try{let n=await app.pb.collection(r.collection.name).impersonate(e.id,r.duration);r.token=n.authStore.token}catch(e){app.checkApiError(e)}r.isLoading=!1}}function o(){r.token=``,r.duration=0}return t.div({className:`modal popup record-impersonate-auth-modal`,onbeforeclose:()=>!r.isLoading,onafterclose:e=>{e?.remove()}},t.header({className:`modal-header`},t.h6(null,`Generate nonrenewable auth token for `,t.strong(null,()=>e.email||e.id))),t.div({className:`modal-content`},t.form({id:n+`_form`,hidden:()=>r.token,className:`block`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`field`},t.label({htmlFor:n+`_duration`},`Token duration (in seconds)`),t.input({id:n+`_duration`,type:`number`,name:`duration`,min:0,step:1,placeholder:()=>`Default to the collection settings (${r.collection?.authToken?.duration||0}s)`,value:e=>r.duration||``,oninput:e=>r.duration=parseInt(e.target.value,10)}))),t.div({hidden:()=>!r.token,className:`alert success impersonate-success`},t.strong(null,()=>r.token),` `,app.components.copyButton(()=>r.token)),app.components.codeBlockTabs({hidden:()=>!r.token,className:`sdk-examples m-t-base`,tabs:[{title:`JS SDK`,language:`js`,value:` + L ${p} ${d}`,g=document.createElementNS(`http://www.w3.org/2000/svg`,`path`);return g.setAttribute(`class`,`relation-path`),g.setAttribute(`data-from`,i||``),g.setAttribute(`data-to`,a||``),g.setAttribute(`d`,h),g}window.app=window.app||{},window.app.components=window.app.components||{};var jt=1e3;window.app.components.pageSidebar=function(e={},...n){let r,i=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,widthHistoryKey:`pbPageSidebarWidth`,onmount:void 0,onunmount:void 0}),a=app.utils.extendStore(i,e),o=store({responsiveShow:!1}),s;function c(){if(r){if(window.innerWidth>jt){o.responsiveShow=!1,r.dataset.responsive=!1,s?.remove(),s=null;return}r.dataset.responsive=!0,s||(s=t.button({type:`button`,className:`btn transparent secondary responsive-sidebar-btn`,title:`Toggle sidebar`,onclick:e=>{e.stopPropagation(),o.responsiveShow=!o.responsiveShow}},t.i({className:`ri-menu-2-line`,ariaHidden:!0})),document.body.querySelector(`.page-header .breadcrumbs`).before(s))}}function l(e){if(e.target.closest(`.responsive-close`)){o.responsiveShow=!1;return}if(!(e.target.closest(`.page-sidebar`)||e.target.closest(`.app-header`)||e.target.closest(`.modal`)))return e.preventDefault(),e.stopImmediatePropagation(),o.responsiveShow=!1,!1}return a.push(watch(()=>o.responsiveShow,e=>{e?window.addEventListener(`click`,l,!0):window.removeEventListener(`click`,l,!0)})),r=t.aside({pbEvent:`pageSidebar`,rid:i.rid,id:()=>i.id,hidden:()=>i.hidden,inert:()=>i.inert,className:()=>`page-sidebar ${i.className} ${o.responsiveShow?`active`:``}`,onmount:e=>{c(e),window.addEventListener(`resize`,c),i.onmount?.(e)},onunmount:e=>{i.onunmount?.(e),window.removeEventListener(`click`,l,!0),window.removeEventListener(`resize`,c),s?.remove(),a.forEach(e=>e?.unwatch())}},e=>{let n;return i.widthHistoryKey&&(n=localStorage.getItem(i.widthHistoryKey),n&&(e.style.width=n)),app.components.dragline({ondragstart:n=>{e._startWidth=e.offsetWidth},ondragging:(r,a,o)=>{n=e._startWidth+a+`px`,e.style.width=n,i.widthHistoryKey&&localStorage.setItem(i.widthHistoryKey,n)}})},...n),r};var Mt=`modulepreload`,W=function(e,n){return new URL(e,n).href},Nt={},G=function(e,n,r){let i=Promise.resolve();if(n&&n.length>0){let e=document.getElementsByTagName(`link`),a=document.querySelector(`meta[property=csp-nonce]`),o=a?.nonce||a?.getAttribute(`nonce`);function s(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function c(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}i=s(n.map(n=>{if(n=W(n,r),n=c(n),n in Nt)return;Nt[n]=!0;let i=n.endsWith(`.css`);for(let r=e.length-1;r>=0;r--){let a=e[r];if(a.href===n&&(!i||a.rel===`stylesheet`))return}let a=document.createElement(`link`);if(a.rel=i?`stylesheet`:Mt,i||(a.as=`script`),a.crossOrigin=``,a.href=n,o&&a.setAttribute(`nonce`,o),document.head.appendChild(a),i)return new Promise((e,r)=>{a.addEventListener(`load`,e),a.addEventListener(`error`,()=>r(Error(`Unable to preload CSS for ${n}`)))})}))}function a(e){let n=new Event(`vite:preloadError`,{cancelable:!0});if(n.payload=e,window.dispatchEvent(n),!n.defaultPrevented)throw e}return i.then(n=>{for(let e of n||[])e.status===`rejected`&&a(e.reason);return e().catch(a)})};window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openApiPreview=function(e,n={onbeforeopen:null,onafteropen:null,onbeforeclose:null,onafterclose:null}){let r=Pt(e,n);r&&(document.body.appendChild(r),app.modals.open(r))};function Pt(e,n){if(!e){console.warn(`[apiPreviewModal] missing required collection`);return}let r,i=store({activeTab:`List/Search`,tabEl:null,isLoading:!1}),a={"List/Search":async e=>{let{docsList:n}=await G(async()=>{let{docsList:e}=await import(`./docsList-DsIHfo2q.js`);return{docsList:e}},__vite__mapDeps([0,1,2]),import.meta.url);return i.tabEl=n(e)},View:async e=>{let{docsView:n}=await G(async()=>{let{docsView:e}=await import(`./docsView-oyuvqZP8.js`);return{docsView:e}},__vite__mapDeps([3,1,2]),import.meta.url);return i.tabEl=n(e)}};e.type!=`view`&&(a.Create=async e=>{let{docsCreate:n}=await G(async()=>{let{docsCreate:e}=await import(`./docsCreate-Ap21j9FE.js`);return{docsCreate:e}},__vite__mapDeps([4,1,2]),import.meta.url);return i.tabEl=n(e)},a.Update=async e=>{let{docsUpdate:n}=await G(async()=>{let{docsUpdate:e}=await import(`./docsUpdate-DAnNYWFv.js`);return{docsUpdate:e}},__vite__mapDeps([5,1,2,4]),import.meta.url);return i.tabEl=n(e)},a.Delete=async e=>{let{docsDelete:n}=await G(async()=>{let{docsDelete:e}=await import(`./docsDelete-CeK6pY9P.js`);return{docsDelete:e}},[],import.meta.url);return i.tabEl=n(e)},a.Realtime=async e=>{let{docsRealtime:n}=await G(async()=>{let{docsRealtime:e}=await import(`./docsRealtime-BR9-cDED.js`);return{docsRealtime:e}},[],import.meta.url);return i.tabEl=n(e)},a.Batch=async e=>{let{docsBatch:n}=await G(async()=>{let{docsBatch:e}=await import(`./docsBatch-CQUyIsim.js`);return{docsBatch:e}},[],import.meta.url);return i.tabEl=n(e)}),e.type==`auth`&&(a[``]=null,a[`List auth methods`]=async e=>{let{docsListAuthMethods:n}=await G(async()=>{let{docsListAuthMethods:e}=await import(`./docsListAuthMethods-CYETXzX7.js`);return{docsListAuthMethods:e}},__vite__mapDeps([6,2]),import.meta.url);return i.tabEl=n(e)},a[`Auth with password`]=e.passwordAuth?.enabled?async e=>{let{docsAuthWithPassword:n}=await G(async()=>{let{docsAuthWithPassword:e}=await import(`./docsAuthWithPassword-NXiq7pZI.js`);return{docsAuthWithPassword:e}},__vite__mapDeps([7,1,2]),import.meta.url);return i.tabEl=n(e)}:null,e.name!=`_superusers`&&(a[`Auth with OAuth2`]=e.oauth2?.enabled?async e=>{let{docsAuthWithOAuth2:n}=await G(async()=>{let{docsAuthWithOAuth2:e}=await import(`./docsAuthWithOAuth2-qI6si9uJ.js`);return{docsAuthWithOAuth2:e}},__vite__mapDeps([8,1,2]),import.meta.url);return i.tabEl=n(e)}:null),a[`Auth with OTP`]=e.otp?.enabled?async e=>{let{docsAuthWithOTP:n}=await G(async()=>{let{docsAuthWithOTP:e}=await import(`./docsAuthWithOTP-75iz1Xmg.js`);return{docsAuthWithOTP:e}},__vite__mapDeps([9,1,2]),import.meta.url);return i.tabEl=n(e)}:null,a[`Auth refresh`]=async e=>{let{docsAuthRefresh:n}=await G(async()=>{let{docsAuthRefresh:e}=await import(`./docsAuthRefresh-Cq3xTY6M.js`);return{docsAuthRefresh:e}},__vite__mapDeps([10,1,2]),import.meta.url);return i.tabEl=n(e)},e.name!=`_superusers`&&(a.Verification=async e=>{let{docsVerification:n}=await G(async()=>{let{docsVerification:e}=await import(`./docsVerification-CIbF1DIL.js`);return{docsVerification:e}},[],import.meta.url);return i.tabEl=n(e)}),a[`Password reset`]=async e=>{let{docsPasswordReset:n}=await G(async()=>{let{docsPasswordReset:e}=await import(`./docsPasswordReset-UqmNW8HA.js`);return{docsPasswordReset:e}},[],import.meta.url);return i.tabEl=n(e)},a[`Email change`]=async e=>{let{docsEmailChange:n}=await G(async()=>{let{docsEmailChange:e}=await import(`./docsEmailChange-VWbqXOVy.js`);return{docsEmailChange:e}},[],import.meta.url);return i.tabEl=n(e)});let o=[watch(()=>i.activeTab,async()=>{i.isLoading=!0,await a[i.activeTab]?.(e),i.isLoading=!1})];return r=t.div({pbEvent:`apiPreviewModal`,className:`modal api-preview-modal`,onbeforeopen:e=>n.onbeforeopen?.(e),onafteropen:e=>{n.onafteropen?.(e)},onbeforeclose:e=>n.onbeforeclose?.(e),onafterclose:e=>{n.onafterclose?.(e),o.forEach(e=>e?.unwatch()),e?.remove()},onmount:e=>{},onunmount:e=>{o.forEach(e=>e?.unwatch())}},t.div({className:`modal-content`},t.aside({className:`api-preview-sidebar`},t.nav({className:`api-preview-nav`},()=>{let e=[];for(let n in a){if(!n){e.push(t.hr());continue}let r=!a[n];e.push(t.button({type:`button`,className:()=>`nav-item ${i.activeTab==n?`active`:``}`,disabled:r,ariaDescription:app.attrs.tooltip(()=>r?`Not enabled for the collection`:``,`left`),onclick:()=>{r||(i.activeTab=n)}},n))}return e})),t.div({className:()=>`api-preview-content ${i.isLoading?`faded`:``}`,scrollTop:()=>i.activeTab?0:null},t.header({className:`api-preview-content-header`},t.h6(null,()=>i.activeTab+` (${e.name})`),t.button({type:`button`,className:()=>`btn sm circle transparent secondary m-l-auto preview-close-btn ${i.isLoading?`loading`:``}`,title:`Close`,onclick:()=>app.modals.close(r)},t.i({className:`ri-close-line`,ariaHidden:!0}))),()=>i.tabEl))),r}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openMailTest=function(e=``,n=``){let r=Ft(e,n);document.body.appendChild(r),app.modals.open(r)};function Ft(e=``,n=``){let r=`mail_test_`+app.utils.randomString(),i=`pbLastTestEmail`,a=`email_test_request`,o=[{label:`Verification`,value:`verification`},{label:`Password reset`,value:`password-reset`},{label:`Confirm email change`,value:`email-change`},{label:`OTP`,value:`otp`},{label:`Login alert`,value:`login-alert`}],s=store({email:localStorage.getItem(i)||app.store.superuser?.email||``,template:n||o[0].value,isSending:!1,collectionIdOrName:e,get isAuthCollectionsLoading(){return app.store.isCollectionsLoading},get authCollections(){return app.utils.sortedCollections(app.store.collections.filter(e=>e.type==`auth`))},get canSubmit(){return!!s.email&&!!s.template&&!!s.collectionIdOrName}}),c;async function l(){if(!(s.isSending||!s.canSubmit)){s.isSending=!0,clearTimeout(c),c=setTimeout(()=>{s.isSending=!1,app.pb.cancelRequest(a),app.modals.close(),app.toasts.error(`Test email send timeout.`)},15e3);try{s.email!=app.pb.authStore.record?.email&&localStorage.setItem(i,s.email),await app.pb.settings.testEmail(s.collectionIdOrName,s.email,s.template,{requestKey:a}),app.toasts.success(`Successfully sent test email.`),app.modals.close()}catch(e){app.checkApiError(e)}s.isSending=!1,clearTimeout(c)}}let u=[];return t.div({className:`modal popup sm`,onbeforeopen:e=>{u.push(watch(()=>s.isAuthCollectionsLoading,e=>{!e&&!s.collectionIdOrName&&(s.collectionIdOrName=s.authCollections[0]?.id||``)}))},onafterclose:e=>{clearTimeout(c),e?.remove()},onunmount:()=>{clearTimeout(c),u.forEach(e=>e?.unwatch())}},t.header({className:`modal-header`},t.h5({className:`m-auto`},`Send test email`)),t.form({id:r,className:`modal-content mail-settings-test-form`,onsubmit:e=>{e.preventDefault(),l()}},t.div({className:`grid`},t.div({className:`col-lg-12`},()=>o.map((e,n)=>t.field({className:()=>`field ${n>0?`m-t-10`:``}`},t.input({type:`radio`,id:r+`.template.`+e.value,name:`template`,checked:()=>s.template==e.value,onchange:n=>s.template=e.value}),t.label({htmlFor:r+`.template.`+e.value},e.label||e.value)))),()=>{if(!e)return t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`.collection`},`Auth collection`),app.components.select({id:r+`.collection`,name:`collection`,required:!0,placeholder:()=>s.isAuthCollectionsLoading?`Loading auth collections...`:`Select auth collection`,options:()=>s.authCollections.map(e=>({value:e.id,label:e.name})),value:()=>s.collectionIdOrName||``,onchange:e=>{s.collectionIdOrName=e?.[0]?.value}})))},t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`.email`},`To email address`),t.input({id:r+`.email`,name:`email`,type:`email`,required:!0,value:()=>s.email||``,oninput:e=>s.email=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>s.isSending},t.span({className:`txt`},`Close`)),t.button({"html-form":r,type:`submit`,className:()=>`btn expanded ${s.isSending?`loading`:``}`,disabled:()=>s.isSending||!s.canSubmit},t.i({className:`ri-mail-send-line`,ariaHidden:!0}),t.span({className:`txt`},`Send`))))}function It(e={}){let n=store({rid:void 0,collectionA:null,collectionB:null,deleteMissing:!1,className:``}),r=app.utils.extendStore(n,e),i=store({hasAnyChange:!1,get isDeleteDiff(){return!n.collectionB?.id&&!n.collectionB?.name},get isCreateDiff(){return!i.isDeleteDiff&&!n.collectionA?.id},get hasAnyChange(){return app.utils.hasCollectionChanges(n.collectionA,n.collectionB,n.deleteMissing)},get fieldsListA(){return Array.isArray(n.collectionA?.fields)?n.collectionA?.fields:[]},get fieldsListB(){let e=Array.isArray(n.collectionB?.fields)?n.collectionB?.fields:[];return n.deleteMissing||(e=e.concat(n.collectionA?.fields?.filter(n=>!e.find(e=>n.id==e.id))||[])),e},get mainModelProps(){return app.utils.mergeUnique(Object.keys(n.collectionA||{}),Object.keys(n.collectionB||{})).filter(e=>![`fields`,`created`,`updated`].includes(e))},get removedFields(){return i.fieldsListA.filter(e=>!i.fieldsListB.find(n=>e.id==n.id))},get sharedFields(){return i.fieldsListB.filter(e=>i.fieldsListA.find(n=>n.id==e.id))},get addedFields(){return i.fieldsListB.filter(e=>!i.fieldsListA.find(n=>n.id==e.id))}});function a(e){return e===void 0?``:app.utils.isObject(e)?JSON.stringify(e,null,4):``+e}function o(e,n){return e!==n&&JSON.stringify(e)!=JSON.stringify(n)}function s(e,n){return(e||[]).find(e=>e.id==n)}return t.div({rid:n.rid,pbEvent:`collectionsDiffTableWrapper`,className:()=>`collections-diff-table-wrapper ${n.className}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.div({className:`collections-diff-table-title`},()=>n.collectionA?.id?n.collectionB?.id?[t.span({hidden:()=>!i.hasAnyChange,className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(n.collectionA?.name!=n.collectionB?.name)return[t.strong({className:`txt-strikethrough txt-hint`,textContent:n.collectionA?.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>n.collectionB?.name}))]:[t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.strong({textContent:()=>n.collectionA?.name})]:[t.span({className:`label import-change-label success`,textContent:`Added`}),t.strong({textContent:()=>n.collectionB?.name})]),t.table({className:`collections-diff-table`},t.thead(null,t.tr(null,t.th({className:`min-width`},`Props`),t.th({width:`40%`},`Old`),t.th({width:`40%`},`New`))),t.tbody(null,()=>i.mainModelProps.map(e=>{let r=o(n.collectionA?.[e],n.collectionB?.[e]);return t.tr({className:r?`txt-primary`:``},t.td({className:`min-width`},e),t.td({className:()=>i.isCreateDiff?`changed-non-col`:r?`changed-old-col`:``},t.pre({className:`txt diff-value`},a(n.collectionA?.[e]))),t.td({className:()=>i.isDeleteDiff?`changed-non-col`:r?`changed-new-col`:``},t.pre({className:`txt diff-value`},a(n.collectionB?.[e]))))}),()=>{if(!n.deleteMissing&&!i.isDeleteDiff)return;let e=[];for(let n of i.removedFields){e.push(t.tr(null,t.th({className:`min-width`,colSpan:3},t.span({className:`txt`},`field: `,n.name),t.span({className:`label danger m-l-5`},`Deleted - `,t.small(null,`All stored data related to '${n.name}' will be deleted!`)))));for(let r in n){let i=n[r];e.push(t.tr(null,t.td({className:`min-width field-key-col`},r),t.td({className:`changed-old-col`},t.pre({className:`txt`},a(i))),t.td({className:`changed-none-col`})))}}return e},()=>{let e=[];for(let n of i.sharedFields){let r=s(i.fieldsListA,n.id),c=o(r,s(i.fieldsListB,n.id));e.push(t.tr(null,t.th({className:`min-width`,colSpan:3},t.span({className:`txt`},`field: `,n.name),t.span({className:`label warning m-l-5 ${c?``:`hidden`}`,textContent:`Changed`}))));for(let i in n){let s=n[i],c=o(r?.[i],s);e.push(t.tr({className:c?`txt-primary`:``},t.td({className:`min-width field-key-col`},i),t.td({className:c?`changed-old-col`:``},t.pre({className:`txt`},a(r?.[i]))),t.td({className:c?`changed-new-col`:``},t.pre({className:`txt`},a(s)))))}}return e},()=>{let e=[];for(let n of i.addedFields){e.push(t.tr(null,t.th({className:`min-width`,colSpan:3},t.span({className:`txt`},`field: `,n.name),t.span({className:`label success m-l-5`},`Added`))));for(let r in n){let i=n[r];e.push(t.tr({className:`txt-primary`},t.td({className:`min-width field-key-col`},r),t.td({className:`changed-none-col`}),t.td({className:`changed-new-col`},t.pre({className:`txt`},a(i)))))}}return e})))}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openImportCollectionsReview=function(e,n,r={deleteMissing:!1,onsubmit:null}){let i=Lt(e,n,r);i&&(document.body.appendChild(i),app.modals.open(i))};function Lt(e,n,r){let i,a=store({deleteMissing:!1,onsubmit:function(e){}}),o=app.utils.extendStore(a,r),s=store({isImporting:!1,pairs:[]});function c(){let r=[];for(let i of e){let e=n.find(e=>e.id==i.id);(a.deleteMissing&&!e?.id||e?.id&&app.utils.hasCollectionChanges(i,e,a.deleteMissing))&&r.push({old:i,new:e})}for(let i of n){let n=e.find(e=>e.id==i.id);n?.id||r.push({old:n,new:i})}s.pairs=r}function l(){let r=[];if(a.deleteMissing)for(let i of e){let e=n.find(e=>e.id==i.id);if(!e)r.push(i.name+`.*`);else{let n=Array.isArray(i.fields)?i.fields:[];for(let a of n)e.fields?.find(e=>e.id==a.id)||r.push(`${i.name}.${a.name} (${a.id})`)}}r.length?app.modals.confirm([t.h6(null,`Do you really want to delete the following collection fields and their related records data:`),t.ul(null,()=>r.map(e=>t.li(null,e)))],()=>u()):u()}async function u(){if(!s.isImporting){s.isImporting=!0;try{await app.pb.collections.import(n,a.deleteMissing),await app.store.loadCollections(),a.onsubmit?.(JSON.parse(JSON.stringify(app.store.collections))),app.toasts.success(`Successfully imported collections configuration.`)}catch(e){app.checkApiError(e)}s.isImporting=!1,app.modals.close(i)}}return i=t.div({pbEvent:`importCollectionsReviewModal`,className:`modal popup full import-collections-review-modal`,onbeforeopen:()=>{c()},onbeforeclose:()=>!s.isImporting,onafterclose:e=>{e?.remove()},onunmount:()=>{o.forEach(e=>e?.unwatch())}},t.header({className:`modal-header`},t.h5(null,`Side-by-side diff`)),t.div({className:`modal-content`},()=>s.pairs.map(e=>It({collectionA:e.old,collectionB:e.new,deleteMissing:a.deleteMissing}))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>s.isImporting,onclick:()=>app.modals.close(i)},t.span({className:`txt`},`Close`)),t.button({type:`button`,className:()=>`btn expanded ${s.isImporting?`loading`:``}`,disabled:()=>s.isImporting,onclick:()=>l()},t.span({className:`txt`},`Confirm and import`)))),i}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.recordSummary=function(e,n=null){let r=store({get collection(){return app.store.collections.find(n=>n.id==e.collectionId||n.name==e.collectionName)},get presentableFields(){if(!r.collection?.id)return[];let e=r.collection.fields.filter(e=>e.presentable).sort((e,n)=>{let r=app.fieldTypes[e.type].summaryPriority||0,i=app.fieldTypes[n.type].summaryPriority||0;return r>i?1:re.name==n);if(i){e.push(i);break}}return e}});return t.div({className:`label record-summary`},t.i({ariaHidden:!0,className:`ri-eye-line link-hint record-preview-icon`,onclick:e=>{e.stopImmediatePropagation(),e.preventDefault()},onmouseenter:n=>{zt(n.target,e,100)},onmouseleave:e=>{Rt(e.target,100)},onunmount:e=>{Rt(e,0)}}),()=>{let i=[];function a(e){(e==null||e==``)&&(e=t.span({className:`missing-value`})),i.push(e)}for(let i of r.presentableFields){let r=app.fieldTypes[i.type]?.view;if(r)a(r({short:!0,get record(){return e},get field(){return i},get meta(){return n}}));else{let n=app.utils.toArray(e[i.name]).splice(0,3);for(let e of n)a(e)}}return i})};function Rt(e,n=150){if(e){if(clearTimeout(e._summaryDropdownTimeoutId),n<=0){e?._summaryDropdown?.hidePopover?.();return}e._summaryDropdownTimeoutId=setTimeout(()=>{e?._summaryDropdown?.hidePopover?.()},n)}}function zt(e,n,r=150){if(e){if(clearTimeout(e._summaryDropdownTimeoutId),r<=0){Bt(e,n);return}e._summaryDropdownTimeoutId=setTimeout(()=>{Bt(e,n)},r)}}var Bt=function(e,n){e&&(e._summaryDropdown||(e._summaryDropdown=t.div({className:`dropdown record-summary-dropdown`,popover:`manual`,onclick:e=>{e.stopImmediatePropagation(),e.preventDefault()}},t.div({className:`record-header`},t.a({className:`link-hint txt-bold m-r-auto`,target:`_blank`,href:`#/collections?collection=${n.collectionName}&record=${n.id}`,onclick:e=>{e.stopImmediatePropagation()}},t.span({className:`txt`},`Edit relation record`),t.i({className:`ri-external-link-line`,ariaHidden:!0})),t.button({type:`button`,className:`link-hint`,title:`Close`,onclick:()=>Rt(e,0)},t.i({className:`ri-close-line`,ariaHidden:!0}))),t.hr(),t.pre({className:`record-json`},()=>{let e=app.store.collections.find(e=>e.id==n.collectionId||e.name==n.collectionName)?.fields||[];if(!e.length)return;let r={collectionId:n.collectionId,collectionName:n.collectionName};for(let i of e)r[i.name]=n[i.name];return JSON.stringify(app.utils.truncateObject(r,27),null,2)})),e.appendChild(e._summaryDropdown)),e._summaryDropdown?.showPopover({source:e}))};window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.recordsSearchbar=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,disabled:void 0,value:``,className:``,collection:void 0,onsubmit:e=>{}}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`full-width records-searchbar-wrapper ${n.className}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},app.components.searchbar({placeholder:()=>!n.disabled&&!n.collection?.id?`Loading...`:`Search term or filter...`,historyKey:()=>`pbRecordsSearchHistory_`+n.collection?.id,disabled:()=>n.disabled||!n.collection,value:()=>n.value,autocomplete:e=>app.utils.collectionAutocompleteKeys(n.collection,e,{requestKeys:!1,collectionJoinKeys:!1}),onsubmit:n.onsubmit}))},window.app=window.app||{},window.app.components=window.app.components||{};var K={max:10,pending:new Set,processing:new Set};function Vt(e){return K.pending.add(e),K.processing.size<=K.max&&Ht(),()=>{K.pending.delete(e),K.processing.delete(e),K.processing.sizen.id,hidden:()=>n.hidden,inert:()=>n.inert,type:`button`,draggable:!1,className:()=>`thumb ${n.extraClasses} ${i.isPreviewLoading?`loading`:``}`,title:()=>(i.hasPreview?`Preview`:`Download`)+` `+n.filename,onclick:async e=>{e.stopPropagation();async function r(){let e=await app.getFileToken(n.record.collectionId);return app.pb.files.getURL(n.record,n.filename,{token:e})}if(i.hasPreview)app.modals.openFilePreview(r);else{let e=await r();app.utils.download(e,n.filename)}},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(i.fileType==`image`){let e=t.img({draggable:!1,alt:()=>`Thumb of `+n.filename,src:()=>i.previewURL,onerror:n=>{console.warn(`[recordFileThumb] load err:`,n),i.isPreviewLoading=!1,e?._semaphoreRelease?.()},onload:()=>{i.isPreviewLoading=!1,e?._semaphoreRelease?.()},onmount:e=>{i.isPreviewLoading=!0,e._semaphoreRelease=Vt(async()=>{try{i.previewToken=await app.getFileToken(n.record.collectionId),i.previewURL=app.pb.files.getURL(n.record,n.filename,{thumb:`100x100`,token:i.previewToken})}catch(e){console.warn(e)}})},onunmount:e=>{i.isPreviewLoading=!1,e._semaphoreRelease?.()}});return e}return t.i({className:app.utils.fileTypeIcons[i.fileType]||`ri-file-line`,ariaHidden:!0})})},window.app=window.app||{},window.app.modals=window.app.modals||{};var Ut=100,Wt={btnText:`Insert`,fileTypes:[],onselect:function(e){}},q=`pbLastRecordFilePickerCollection`,J=`listFilePickerRecords`;window.app.modals.openRecordFilePicker=function(e={}){e=Object.assign({},Wt,e);let n=Y(e);document.body.appendChild(n),app.modals.open(n)};function Y(e=Wt){let n,r=`file_picker_`+app.utils.randomString(),i=store({selectedFile:{},records:[],activeCollectionId:``,searchTerm:``,lastRecordsPage:1,lastTotalRecords:0,isLoadingRecords:!1,get collections(){return app.utils.sortedCollections(app.store.collections.filter(e=>e.type!=`view`&&!!e.fields?.find(e=>e.type===`file`&&!e.protected)))},get activeCollection(){return i.collections.find(e=>e.id==i.activeCollectionId)||i.collections[0]},get activeCollectionFileFields(){return i.activeCollection?.fields?.filter(e=>e.type===`file`&&!e.protected)||[]},get isLoading(){return app.store.isLoadingCollections||i.isLoadingRecords},get canLoadMore(){return!i.isLoadingRecords&&i.lastTotalRecords==Ut},get hasAtleastOneFile(){return!!i.records.find(e=>c(e).length>0)}}),a=[];a.push(watch(()=>{i.activeCollectionId?(window.localStorage.setItem(q,i.activeCollectionId),i.searchTerm=``):i.activeCollectionId=window.localStorage.getItem(q)})),a.push(watch(()=>[i.activeCollection,i.searchTerm],()=>s(!0)));function o(){app.pb.cancelRequest(J),i.isLoadingRecords=!1,i.records=[],i.lastTotalRecords=0,i.lastRecordsPage=1,i.selectedFile={}}async function s(e=!1){if(!i.activeCollection){o();return}e&&o(),i.isLoadingRecords=!0;try{let n=e?1:i.lastRecordsPage+1,r=app.utils.getAllCollectionIdentifiers(i.activeCollection),a=app.utils.normalizeSearchFilter(i.searchTerm,r)||``;a&&(a+=` && `),a+=`(`+i.activeCollectionFileFields.map(e=>`${e.name}:length>0`).join(`||`)+`)`;let o=await app.pb.collection(i.activeCollection.id).getList(n,Ut,{requestKey:J,filter:a,skipTotal:1,sort:i.activeCollection.type==`view`?``:`-@rowid`});i.lastRecordsPage=o.page,i.lastTotalRecords=o.items.length,i.records=app.utils.filterDuplicatesByKey(i.records.concat(o.items)),i.isLoadingRecords=!1}catch(e){e.isAbort||(i.isLoadingRecords=!1,app.checkApiError(e))}}function c(n){let r=[];for(let a of i.activeCollectionFileFields){let i=app.utils.toArray(n[a.name]);for(let n of i)(app.utils.isEmpty(e.fileTypes)||e.fileTypes?.includes(app.utils.getFileType(n)))&&r.push(n)}return r}function l(e,n){i.selectedFile={record:e,name:n,thumb:``}}function u(e,n){return i.selectedFile?.name==n&&i.selectedFile?.record?.id==e?.id}let d={"record:create":e=>{e.detail.collectionId==i.activeCollection?.id&&(i.selectedFile?.record?.id==e.detail.id&&(i.selectedFile.record=e.detail),s(!0))},"record:delete":e=>{e.detail.collectionId!=i.activeCollection?.id&&e.detail.collectionName!=i.activeCollection?.name||(i.selectedFile?.record?.id==e.detail.id&&(i.selectedFile={}),s(!0))}};return n=t.div({className:`modal popup record-file-picker-modal`,onafterclose:e=>{e?.remove()},onmount:e=>{for(let e in d)document.addEventListener(e,d[e])},onunmount:e=>{a.forEach(e=>e?.unwatch());for(let e in d)document.removeEventListener(e,d[e])}},t.header({className:`modal-header`},t.button({className:()=>`btn primary outline record-file-picker-collection-select-btn ${app.store.isLoadingCollections?`loading`:``}`,disabled:()=>app.store.isLoadingCollections,"html-popovertarget":`collections_dropdown`+r},t.span({className:`txt-lg collection-name m-r-auto`},()=>i.activeCollection?.name||`Select collection`),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0})),t.div({id:`collections_dropdown`+r,className:`dropdown`,popover:`hint`},()=>i.collections.map(e=>t.button({type:`button`,className:()=>`dropdown-item ${i.activeCollectionId==e.id?`active`:``}`,onclick:n=>{i.activeCollectionId=e.id,n.target?.closest(`.dropdown`)?.hidePopover()}},e.name))),app.components.recordsSearchbar({disabled:()=>!i.activeCollection?.id,collection:()=>i.activeCollection,value:()=>i.searchTerm,onsubmit:e=>i.searchTerm=e}),t.button({type:`button`,className:`btn circle transparent`,ariaLabel:app.attrs.tooltip(`Add new record`),onclick:()=>app.modals.openRecordUpsert(i.activeCollection)},t.i({className:`ri-add-line txt-hint`,ariaHidden:!0}))),t.div({className:`modal-content`},t.div({className:`block txt-center`,hidden:()=>i.hasAtleastOneFile||!i.isLoading},t.span({className:`loader`})),t.div({className:`record-file-picker-list`},()=>{let e=[];for(let n of i.records){let r=c(n);for(let i of r)e.push(t.button({rid:n.id+`:`+i,className:()=>`list-item thumb ${u(n,i)?`success`:``}`,ariaDescription:app.attrs.tooltip(i,`bottom`),onclick:()=>l(n,i)},()=>{if(app.utils.hasImageExtension(i))return t.img({loading:`lazy`,src:app.pb.files.getURL(n,i,{thumb:`100x100`}),alt:i});let e=app.utils.getFileType(i);return t.i({className:app.utils.fileTypeIcons[e]||`ri-file-line`,ariaHidden:!0})}))}return e}),t.div({hidden:()=>!i.canLoadMore||!i.hasAtleastOneFile,className:`block txt-center`},t.button({className:()=>`btn secondary expanded-lg m-t-base ${i.isLoadingRecords?`loading`:``}`,disabled:()=>i.isLoadingRecords,onclick:()=>s()},t.span({className:`txt`},`Load more`))),t.div({className:`block txt-center txt-hint p-t-10 p-b-10`,hidden:()=>i.hasAtleastOneFile||i.isLoading},()=>app.utils.isEmpty(e.fileTypes)?t.p(null,`No records with selectable files found.`):t.p(null,`No "${e.fileTypes.join(`", "`)}" files found.`),t.button({type:`button`,className:`btn sm secondary`,textContent:`Clear search`,hidden:()=>!i.searchTerm?.length,onclick:()=>{i.searchTerm=``}}))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Close`)),()=>{if(!i.selectedFile?.name||!app.utils.hasImageExtension(i.selectedFile.name))return;let e=[{value:``,label:`Original size`},{value:`100x100`,label:`100x100 thumb`}],n=i.activeCollectionFileFields.find(e=>i.selectedFile.record[e.name].includes(i.selectedFile.name)),r=app.utils.toArray(n.thumbs);for(let n of r)e.push({value:n,label:`${n} thumb`});return t.div({className:`record-file-picker-thumb-select`},app.components.select({required:!0,value:i.selectedFile.thumb||``,options:e,onchange:e=>{i.selectedFile.thumb=e?.[0].value}}))},t.button({type:`button`,className:`btn expanded`,disabled:()=>i.isLoading||!i.selectedFile?.name,onclick:()=>{let r=JSON.parse(JSON.stringify(i.selectedFile));if(e.onselect&&e.onselect(r)===!1)return!1;app.modals.close(n)}},t.span({className:`txt`},()=>e.btnText||Wt.btnText)))),n}window.app=window.app||{},window.app.modals=window.app.modals||{};var Gt=50,Kt=100,qt=`listRelationPickerRecords`,Jt={collection:``,selectedIds:[],maxSelect:1,btnText:`Set selection`,onselect:function(e){}};window.app.modals.openRecordsPicker=function(e={}){e=Object.assign({},Jt,e);let n=Yt(e);document.body.appendChild(n),app.modals.open(n)};function Yt(e=Jt){let n,r=store({searchTerm:``,selected:[],preselected:[],isLoadingPreselected:!1,records:[],isLoadingRecords:!1,lastRecordsPage:1,lastRecordsTotal:0,get collection(){let n=e.collection;return typeof e.collection==`object`&&e.collection?.id&&(n=e.collection?.id),app.store.collections.find(e=>e.id==n||e.name==n)},get isLoading(){return r.isLoadingPreselected||r.isLoadingRecords},get canLoadMore(){return!r.isLoadingRecords&&r.lastRecordsTotal==Gt}}),i=[watch(()=>[e.collection,e.selectedIds],()=>{o()}),watch(()=>[r.collection,r.searchTerm],()=>{s(!0)})];function a(){setTimeout(()=>app.modals.close(n),0)}async function o(){let n=app.utils.toArray(e.selectedIds),i=e.collection?.id||e.collection;if(!i||!n.length)return;r.isLoadingSelected=!0;let a=[],o=n.slice(),s=[];for(;o.length>0;){let e=[],n=o.splice(0,Kt);for(let r of n)e.push(`id="${r}"`);s.push(app.pb.collection(i).getFullList({requestKey:null,filter:e.join(`||`)}))}try{await Promise.all(s).then(e=>{a=a.concat(...e)});let e=[];for(let r of n){let n=a.find(e=>e.id==r);n&&e.push(n)}r.searchTerm.trim()||(r.records=app.utils.filterDuplicatesByKey(e.concat(r.records))),r.selected=e,r.isLoadingSelected=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoadingSelected=!1)}}async function s(e=!1){if(r.collection?.id){e&&(c(),r.searchTerm.trim()||(r.records=r.selected.slice())),r.isLoadingRecords=!0;try{let n=e?1:r.lastRecordsPage+1,i=app.utils.getAllCollectionIdentifiers(r.collection),a=app.utils.normalizeSearchFilter(r.searchTerm,i)||``,o=await app.pb.collection(r.collection.id).getList(n,Gt,{requestKey:qt,filter:a,skipTotal:1,sort:r.collection.type==`view`?``:`-@rowid`});r.lastRecordsPage=o.page,r.lastRecordsTotal=o.items.length,r.records=app.utils.filterDuplicatesByKey(r.records.concat(o.items)),r.isLoadingRecords=!1}catch(e){e.isAbort||(r.isLoadingRecords=!1,app.checkApiError(e))}}}function c(){app.pb.cancelRequest(qt),r.isLoadingRecords=!1,r.records=[],r.lastTotalRecords=0,r.lastRecordsPage=1}function l(e){e.target.scrollHeight-e.target.clientHeight-e.target.scrollTop<=100&&r.canLoadMore&&s()}function u(n){let i=r.selected.findIndex(e=>e.id==n.id);if(i>=0)r.selected.splice(i,1);else{let i=e.maxSelect||1,a=r.selected.length-i;for(;a>=0;)r.selected.pop(),a--;r.selected.push(n)}}function d(e){return r.selected.findIndex(n=>n.id==e.id)>=0}let f={"record:save":e=>{if(e.detail.collectionId!=r.collection?.id)return;let n=r.selected?.findIndex(n=>n.id==e.detail.id);n>=0&&(r.selected[n]=e.detail),app.utils.pushOrReplaceObject(r.records,e.detail),s(!0)},"record:delete":e=>{e.detail.collectionId!=r.collection?.id&&e.detail.collectionName!=r.collection?.name||(d(e.detail)&&u(e.detail),app.utils.removeByKey(r.records,`id`,e.detail.id),s(!0))}};return n=t.div({className:`modal popup lg records-picker-modal`,onafterclose:e=>{e.remove()},onmount:e=>{for(let e in f)document.addEventListener(e,f[e])},onunmount:e=>{i.forEach(e=>e?.unwatch());for(let e in f)document.removeEventListener(e,f[e])}},t.header({className:`modal-header`},t.h6({className:`collection-name`},()=>r.collection.name),app.components.recordsSearchbar({disabled:()=>!r.collection?.id,collection:()=>r.collection,value:()=>r.searchTerm,onsubmit:e=>r.searchTerm=e}),t.button({type:`button`,className:`btn circle transparent`,ariaLabel:app.attrs.tooltip(`Add new record`),onclick:()=>{app.modals.openRecordUpsert(r.collection)}},t.i({className:`ri-add-line txt-hint`,ariaHidden:!0}))),t.div({className:`modal-content`,hidden:()=>r.isLoadingCollection},t.div({className:`list records-picker-list`,onscroll:l,onresize:l},()=>r.records.map(e=>t.div({tabIndex:0,className:`list-item handle`,onclick:()=>{u(e),document.activeElement?.blur()}},t.div({className:`content`},t.span({className:`state-icon`},t.i({ariaHidden:!0,className:()=>d(e)?`ri-checkbox-circle-fill txt-success`:`ri-checkbox-blank-circle-line txt-disabled`})),()=>app.components.recordSummary(e)),t.div({className:`actions autohide`},t.button({className:`btn sm secondary transparent circle`,ariaLabel:app.attrs.tooltip(`Edit`),onclick:n=>{n.stopPropagation(),app.modals.openRecordUpsert(r.collection,e)}},t.i({className:`ri-pencil-line`,ariaHidden:!0}))))),t.div({className:`list-item`,hidden:()=>!r.isLoading},t.div({className:`skeleton-loader`})),t.div({className:`list-item`,hidden:()=>r.records.length||r.isLoading},t.div({className:`content txt-hint`},t.span({className:`txt`},`No records found.`),t.button({type:`button`,className:`btn sm secondary`,textContent:`Clear search`,hidden:()=>!r.searchTerm.trim().length,onclick:()=>{r.searchTerm=``}})))),t.div({className:`block m-t-base`},t.p({className:`txt-bold`},()=>`Selected (${r.selected.length} of max ${e.maxSelect||1})`),t.span({className:`txt-hint`,hidden:()=>r.selected},`No selected records.`),app.components.sortable({className:`records-picker-selected-list`,data:()=>r.selected,dataItem:(e,n)=>t.div({rid:e,className:`label handle`},()=>app.components.recordSummary(e,[],!0),t.span({className:`link-hint`,title:`Remove`,role:`button`,onclick:()=>u(e)},t.i({className:`ri-close-line`,ariaHidden:!0}))),onchange:(e,n,i)=>{r.selected=e}}))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>a()},t.span({className:`txt`},`Close`)),()=>{if(!r.selectedFile?.name||!app.utils.hasImageExtension(r.selectedFile.name))return;let e=[{value:``,label:`Original size`},{value:`100x100`,label:`100x100 thumb`}],n=r.activeCollectionFileFields.find(e=>r.selectedFile.record[e.name].includes(r.selectedFile.name)),i=app.utils.toArray(n.thumbs);for(let n of i)e.push({value:n,label:`${n} thumb`});return t.div({className:`record-file-picker-thumb-select`},app.components.select({required:!0,value:r.selectedFile.thumb||``,options:e,onchange:e=>{r.selectedFile.thumb=e?.[0].value}}))},t.button({type:`button`,className:`btn expanded`,disabled:()=>r.isLoadingCollection,onclick:()=>{let n=JSON.parse(JSON.stringify(r.selected));if(e.onselect&&e.onselect(n)===!1)return!1;a()}},t.span({className:`txt`},e.btnText||Jt.btnText)))),n}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openRecordPreview=function(e,n={onbeforeopen:null,onafteropen:null,onbeforeclose:null,onafterclose:null}){let r=X(e,n);r&&(document.body.appendChild(r),app.modals.open(r))};function Xt(e){e.expand&&(e=Object.assign({},e),delete e.expand),app.utils.downloadJSON(e,e.collectionName+`_`+e.id+`.json`)}function Zt(e){e.expand&&(e=Object.assign({},e),delete e.expand),app.utils.copyToClipboard(JSON.stringify(e,null,2)),app.toasts.success(`Record copied to clipboard!`)}function X(e,n){if(!e?.id){app.toasts.error(`Failed to load record.`),console.warn(`[recordPreviewModal] missing required record id field:`,e);return}if(!e.collectionId&&!e.collectionName){app.toasts.error(`Failed to load record.`),console.warn(`[recordPreviewModal] missing required collectionId or collectionName field:`,e);return}let r,i=app.utils.randomString(),a=store({isLoading:!1,record:null,get collection(){return app.store.collections.find(n=>n.id==e.collectionId||n.name==e.collectionName)}});async function o(){a.isLoading=!0;try{a.record=JSON.parse(JSON.stringify(e));let n=[],r=a.collection?.fields?.filter(e=>!e.hidden&&e.type==`relation`)||[];for(let e of r)n.push(e.name);let i=await app.pb.collection(e.collectionName||e.collectionId).getOne(e.id,{requestKey:`record_preview_`+e.id,expand:n.join(`,`)||void 0});Object.assign(a.record,i),a.isLoading=!1}catch(e){e?.isAbort||(a.isLoading=!1,app.checkApiError(e),setTimeout(()=>app.modals.close(r),0))}}return r=t.div({pbEvent:`recordPreviewModal`,className:`modal record-preview-modal`,onbeforeopen:e=>(o(),n.onbeforeopen?.(e)),onafteropen:e=>{n.onafteropen?.(e)},onbeforeclose:e=>n.onbeforeclose?.(e),onafterclose:e=>{n.onafterclose?.(e),e?.remove()}},t.header({className:`modal-header`},t.h6(null,t.strong(null,()=>e?.collectionName||a.collection?.name),` record preview`),t.button({title:`More options`,className:()=>`btn sm circle transparent m-l-auto ${a.isLoading?`loading`:``}`,disabled:()=>a.isLoading,"html-popovertarget":i+`preview-dropdown`},t.i({className:`ri-more-line`,ariaHidden:!0})),t.div({id:i+`preview-dropdown`,className:`dropdown`,popover:`auto`},e=>t.button({className:`dropdown-item`,onclick:()=>{Zt(a.record),e.hidePopover()}},t.i({className:`ri-braces-line`,ariaHidden:!0}),t.span({className:`txt`},`Copy JSON`)))),t.div({className:`modal-content`},t.table({pbEvent:`recordPreviewTable`,className:`record-preview-table responsive-table`},t.tbody(null,()=>(a.collection?.fields?.filter(e=>e.type!=`password`)||[]).map(e=>t.tr(null,t.th({className:()=>`min-width p-r-0 col-field-name-${e.name}`},e.name),t.td({className:()=>`col-field-name-${e.name}`},()=>app.fieldTypes[e.type]?.view?app.fieldTypes[e.type].view({short:!1,get record(){return a.record},get field(){return e}}):app.utils.displayValue(a.record[e.name],1e3))))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(r)},t.span({className:`txt`},`Close`)),t.button({type:`button`,className:()=>`btn ${a.isLoading?`loading`:``}`,disabled:()=>a.isLoading,onclick:()=>Xt(a.record)},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download JSON`)))),r}window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.openRecordImpersontate=function(e){let n=Qt(e);document.body.appendChild(n),app.modals.open(n)};function Qt(e){let n=`impersonate_`+app.utils.randomString(),r=store({isLoading:!1,token:``,duration:0,get collection(){return app.store.collections.find(n=>n.id==e.collectionId||n.name==e.collectionName)}}),i=app.utils.getApiExampleURL();async function a(){if(!r.isLoading){r.isLoading=!0;try{let n=await app.pb.collection(r.collection.name).impersonate(e.id,r.duration);r.token=n.authStore.token}catch(e){app.checkApiError(e)}r.isLoading=!1}}function o(){r.token=``,r.duration=0}return t.div({className:`modal popup record-impersonate-auth-modal`,onbeforeclose:()=>!r.isLoading,onafterclose:e=>{e?.remove()}},t.header({className:`modal-header`},t.h6(null,`Generate nonrenewable auth token for `,t.strong(null,()=>e.email||e.id))),t.div({className:`modal-content`},t.form({id:n+`_form`,hidden:()=>r.token,className:`block`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`field`},t.label({htmlFor:n+`_duration`},`Token duration (in seconds)`),t.input({id:n+`_duration`,type:`number`,name:`duration`,min:0,step:1,placeholder:()=>`Default to the collection settings (${r.collection?.authToken?.duration||0}s)`,value:e=>r.duration||``,oninput:e=>r.duration=parseInt(e.target.value,10)}))),t.div({hidden:()=>!r.token,className:`alert success impersonate-success`},t.strong(null,()=>r.token),` `,app.components.copyButton(()=>r.token)),app.components.codeBlockTabs({hidden:()=>!r.token,className:`sdk-examples m-t-base`,tabs:[{title:`JS SDK`,language:`js`,value:` import PocketBase from 'pocketbase'; const pb = new PocketBase('${i}'); @@ -83,4 +83,4 @@ Records update will also require an extra unlock step before save.`)})))),t.div( @weekly @daily @midnight -@hourly`)},`macros`),`.`,t.br(),`By default the timezone is in UTC.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`backups.cronMaxKeep`},`Max @auto backups to keep`),t.input({id:`backups.cronMaxKeep`,name:`backups.cronMaxKeep`,type:`number`,required:()=>a.enableAutoBackups,min:1,value:()=>a.formSettings.backups.cronMaxKeep,oninput:e=>{a.formSettings.backups.cronMaxKeep=parseInt(e.target.value,10)}})))))),t.div({className:`col-lg-12`},app.components.s3ConfigFields({toggleLabel:`Store backups in S3 storage`,testFilesystem:`backups`,config:()=>a.formSettings.backups.s3})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!a.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:l},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${a.isSaving?`loading`:``}`,disabled:()=>!a.hasChanges||a.isSaving},t.span({className:`txt`},`Save changes`))))])))}function zi(e={oncreated:null}){let n=Bi(e);n&&(document.body.appendChild(n),app.modals.open(n))}function Bi(e){let n,r=`backup_create_`+app.utils.randomString(),i=store({name:``,isSubmitting:!1}),a;async function o(){if(!i.isSubmitting){i.isSubmitting=!0,clearTimeout(a),a=setTimeout(()=>{app.modals.close(n)},1500);try{await app.pb.backups.create(i.name,{requestKey:r}),i.isSubmitting=!1,e.oncreated&&e.oncreated(i.name),app.toasts.success(`Successfully generated new backup.`),app.modals.close(n)}catch(e){e.isAbort||(clearTimeout(a),i.isSubmitting=!1,app.checkApiError(e))}}}return n=t.div({pbEvent:`backupCreateModal`,className:`modal popup backup-create-modal`,onbeforeclose:()=>{i.isSubmitting&&app.toasts.info(`The backup was started but may take a while to complete. You can come back later.`)},onafterclose:e=>{clearTimeout(a),e?.remove()}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Initialize new backup`)),t.form({id:r,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Please note that during the backup other concurrent write requests may fail since the database will be temporary "locked" (this usually happens only during the ZIP generation).`),t.p({className:`txt-bold`},`If you are using S3 storage for the collections file upload, you'll have to backup them separately since they are not locally stored and they will not be included in the generated backup!`)))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`_name`},`Backup name`),t.input({id:r+`_name`,name:`name`,type:`text`,pattern:`^[a-z0-9_-]+.zip$`,placeholder:`Leave empty to autogenerate`,value:()=>i.name,oninput:e=>i.name=e.target.value})),t.div({className:`field-help`},`Must be in the format [a-z0-9_-].zip`)))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>i.isSubmitting,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Cancel`)),t.button({"html-form":r,type:`submit`,className:()=>`btn ${i.isSubmitting?`loading`:``}`,disabled:()=>i.isSubmitting},t.span({className:`txt`},`Start backup`)))),n}function Vi(e){let n=Hi(e);document.body.appendChild(n),app.modals.open(n)}function Hi(e){let n=`backup_restore_`+app.utils.randomString(),r=store({key:e,keyConfirm:``,isSubmitting:!1,get canSubmit(){return r.key&&r.key==r.keyConfirm}}),i;async function a(){if(!(r.isSubmitting||!r.canSubmit)){clearTimeout(i),r.isSubmitting=!0;try{await app.pb.backups.restore(r.keyConfirm),i=setTimeout(()=>{window.location.reload(),r.isSubmitting=!1},2e3)}catch(e){clearTimeout(i),e?.isAbort||(r.isSubmitting=!1,app.checkApiError(e))}}}return t.div({pbEvent:`backupRestoreModal`,className:`modal popup backup-restore-modal`,onbeforeclose:()=>!r.isSubmitting,onafterclose:e=>{e?.remove()},onunmount:()=>{clearTimeout(i)}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Restore `,t.strong(null,()=>r.key))),t.form({id:n,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert danger`},t.div({className:`content`},t.p({className:`txt-bold`},`Please proceed with extreme caution and use it only with trusted backups!`),t.p(null,`Backup restore currently works only on UNIX based systems.`),t.p(null,`The restore operation will attempt to replace your existing `,t.code(null,`pb_data`),` with the one from the backup and will restart the application process.`),t.p(null,`This means that on success all of your data (including app settings, users, superusers, etc.) will be replaced with the ones from the backup.`),t.p(null,`The operation will be reverted if the backup is invalid (ex. missing `,t.code(null,`data.db`),` file).`),t.p(null,`Below is an oversimplified version of the restore flow:`),t.ol(null,t.li(null,`Replaces the current `,t.code(null,`pb_data`),` with the content from the backup.`),t.li(null,`Triggers app restart.`),t.li(null,`Applies all migrations that are missing in the restored `,t.code(null,`pb_data`),`.`),t.li(null,`Initializes the app server as usual.`))))),t.div({className:`col-lg-12`},t.div({className:`confirm-key-label m-b-sm`},`Type the backup name `,t.div({className:`label`},()=>r.key,app.components.copyButton(()=>r.key)),` to confirm:`),t.div({className:`field`},t.label({htmlFor:n+`_key`},`Backup name`),t.input({id:n+`_key`,name:`key`,type:`text`,required:!0,value:()=>r.keyConfirm,oninput:e=>r.keyConfirm=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>r.isSubmitting},t.span({className:`txt`},`Cancel`)),t.button({"html-form":n,type:`submit`,className:()=>`btn ${r.isSubmitting?`loading`:``}`,disabled:()=>r.isSubmitting||!r.canSubmit},t.span({className:`txt`},`Restore backup`))))}function Ui(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({canBackup:!0,isLoading:!1,isDownloading:{},isDeleting:{},backups:[]});async function a(){i.isLoading=!0;try{i.backups=await app.pb.backups.getFullList(),i.backups.sort((e,n)=>e.modifiedn.modified?-1:0),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){app.modals.confirm(`Do you really want to delete ${e}?`,()=>s(e))}async function s(e){if(!i.isDeleting[e]){i.isDeleting[e]=!0;try{await app.pb.backups.delete(e),a(),app.toasts.success(`Successfully deleted ${e}.`)}catch(e){app.checkApiError(e)}delete i.isDeleting[e]}}async function c(){try{let e=await app.pb.health.check({requestKey:null}),n=i.canBackup;i.canBackup=e?.data?.canBackup||!1,i.canBackup&&n!=i.canBackup&&a()}catch(e){console.warn(`failed to load canBackup checks`,e)}}async function l(e){if(!i.isDownloading[e]){i.isDownloading[e]=!0;try{let n=await app.pb.files.getToken({requestKey:null});app.utils.download(app.pb.backups.getDownloadURL(n,e))}catch(e){app.checkApiError(e)}delete i.isDownloading[e]}}return t.div({pbEvent:`backupsList`,className:`list backups-list`,onmount:e=>{r.push(watch(()=>n.reset,()=>{a()})),e._canBackupIntervalId=setInterval(()=>{c()},3500)},onunmount:e=>{clearInterval(e._canBackupIntervalId),r.forEach(e=>e?.unwatch())}},t.div({className:`list-content`},t.div({hidden:()=>!i.isLoading||i.backups.length,className:`list-item`},t.div({className:`skeleton-loader`})),t.div({hidden:()=>i.isLoading||i.backups.length,className:()=>`list-item`},t.div({className:`content block txt-hint`},`No backups found.`)),()=>i.backups.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.i({className:`ri-folder-zip-line`,ariaHidden:!0}),t.div({className:`content`},t.span({className:`backup-name txt-ellipsis`,title:()=>e.key,textContent:()=>e.key}),t.small({className:`backup-size txt-hint txt-nowrap`},`(`,()=>app.utils.formattedFileSize(e.size),`)`)),t.nav({hidden:()=>i.isLoading,className:`actions autohide`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Download`),className:()=>`btn sm circle secondary transparent ${i.isDownloading[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>l(e.key)},t.i({className:`ri-download-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Restore`),className:()=>`btn sm circle secondary transparent`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>Vi(e.key)},t.i({className:`ri-restart-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Delete`),className:()=>`btn sm circle secondary transparent ${i.isDeleting[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>o(e.key)},t.i({className:`ri-delete-bin-7-line`,ariaHidden:!0})))))),t.div({className:`list-item`},t.button({type:`button`,className:()=>`btn secondary block ${i.isLoading?`loading`:``}`,disabled:()=>!i.canBackup||i.isLoading,onclick:()=>{zi({oncreated:()=>a()})}},()=>i.canBackup?[t.i({className:`ri-play-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Initialize new backup`)]:[t.span({className:`loader sm`}),t.span({className:`txt`},`Backup/restore operation is in process`)])))}function Wi(e=null){let n=`backup_upload_`+app.utils.randomString(),r=store({isUploading:!1});function i(e){e&&app.modals.confirm(`Note that we don't perform validations for the uploaded backup files. Proceed with extreme caution and only if you trust the source.\n\nDo you really want to upload "${e.name}"?`,()=>{a(e)},()=>{o()})}async function a(i){if(!(!i||r.isUploading)){r.isUploading=!0;try{let a=new FormData;a.set(`file`,i),await app.pb.backups.upload(a,{requestKey:n}),r.isUploading=!1,e(i),app.toasts.success(`Successfully uploaded a new backup.`)}catch(e){e.isAbort||(r.isUploading=!1,e.response?.formData?.file?.message?app.toasts.error(e.response.formData.file.message):app.checkApiError(e))}o()}}function o(){s&&(s.value=``)}let s=t.input({type:`file`,accept:`application/zip`,className:`hidden`,onchange:e=>{i(e.target?.files?.[0])}});return t.div(null,t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Upload backup`),className:()=>`btn sm transparent secondary circle ${r.isUploading?`loading`:``}`,disabled:()=>r.isUploading,onclick:()=>s?.click(),onunmount:()=>{app.pb.cancelRequest(n)}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0})),s)}function Gi(e){app.store.title=`Backups`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageBackupsSettings`,className:`page page-backups-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Backup and restore your PocketBase data`),app.components.refreshButton({className:`btn sm transparent secondary circle tooltip-bottom`,onclick:r}),Wi(r)),Ui({reset:()=>n.resetList})),t.div({className:`col-lg-12`},Ri({onsave:()=>r()})))),t.footer({className:`page-footer`},app.components.credits())))}function Ki(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({isLoading:!1,isRunning:{},crons:[]});async function a(){i.isLoading=!0;try{i.crons=await app.pb.crons.getFullList(),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){if(!(!e||i.isRunning[e])){i.isRunning[e]=!0;try{await app.pb.crons.run(e),app.toasts.success(`Successfully triggered "${e}".`),i.isRunning[e]=!1}catch(n){n.isAbort||(ApiClient.error(n),i.isRunning[e]=!1)}}}return t.div({pbEvent:`cronsList`,className:`list`,onmount:()=>{r.push(watch(()=>n.reset,()=>{a()}))},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!i.isLoading||i.crons.length)return;let e=[];for(let n=0;n<4;n++)e.push(t.div({rid:`skeleton_`+n,className:`list-item`},t.div({className:`skeleton-loader`})));return e},t.div({hidden:()=>i.isLoading||i.crons.length,className:`list-item`},t.div({className:`content block txt-hint`},`No registered crons found.`)),()=>i.crons.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.div({className:`content`},t.span({className:`cron-id txt-code txt-ellipsis`,title:()=>e.id,textContent:()=>e.id})),t.small({className:`cron-expression txt-hint txt-nowrap txt-code`},()=>e.expression),t.nav({hidden:()=>i.isLoading,className:`actions`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Run`),className:()=>`btn sm circle secondary transparent ${i.isRunning[e.id]?`loading`:``}`,disabled:()=>i.isRunning[e.id],onclick:()=>o(e.id)},t.i({className:`ri-play-large-line`,ariaHidden:!0}))))))}function qi(e){app.store.title=`Crons`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageCronsSettings`,className:`page`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Registered app cron jobs`),app.components.refreshButton({className:`btn sm transparent secondary circle`,onclick:r})),Ki({reset:()=>n.resetList}),t.div({className:`txt-sm txt-hint m-t-sm`},`App cron jobs can be registered only programmatically with `,t.a({href:`https://pocketbase.io/docs/go-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JavaScript`}),`.`)),t.footer({className:`page-footer`},app.components.credits())))}function Ji(e){app.store.title=`Mail settings`;let n=[{label:`Auto (StartTLS)`,value:!1},{label:`Always`,value:!0}],r=[{label:`PLAIN (default)`,value:`PLAIN`},{label:`LOGIN`,value:`LOGIN`}],i=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,showMoreOptions:!1,get hasChanges(){return i.initSerialized!=JSON.stringify(i.formSettings)}});a();async function a(){i.isLoading=!0;try{s(await app.pb.settings.getAll()),i.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function o(){if(!(i.isSaving||!i.hasChanges)){i.isSaving=!0;try{let e=app.utils.filterRedactedProps(i.formSettings);s(await app.pb.settings.update(e)),app.toasts.success(`Successfully saved mail settings.`)}catch(e){app.checkApiError(e)}i.isSaving=!1}}function s(e={}){app.store.settings=JSON.parse(JSON.stringify(e)),i.formSettings={meta:e?.meta||{},smtp:e?.smtp||{}},i.formSettings.smtp.authMethod||(i.formSettings.smtp.authMethod=r[0].value),i.initSerialized=JSON.stringify(i.formSettings)}function c(){i.formSettings=JSON.parse(i.initSerialized)}return t.div({pbEvent:`pageMailSettings`,className:`page page-mail-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`mailSettingsForm`,className:`grid mail-settings-form`,inert:()=>i.isSaving,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`Configure common settings for sending emails.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderName`},`Sender name`),t.input({id:`meta.senderName`,name:`meta.senderName`,type:`text`,required:!0,value:()=>i.formSettings.meta.senderName||``,oninput:e=>i.formSettings.meta.senderName=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderAddress`},`Sender address`),t.input({id:`meta.senderAddress`,name:`meta.senderAddress`,type:`email`,required:!0,value:()=>i.formSettings.meta.senderAddress||``,oninput:e=>i.formSettings.meta.senderAddress=e.target.value}))),t.div({className:`col-lg-12`},t.div({className:`field`},t.input({id:`smtp.enabled`,name:`smtp.enabled`,type:`checkbox`,className:`switch`,checked:()=>!!i.formSettings.smtp.enabled,onchange:e=>i.formSettings.smtp.enabled=e.target.checked}),t.label({htmlFor:`smtp.enabled`},t.span({className:`txt`},`Use SMTP mail server `,t.strong(null,`(recommended)`)),t.i({className:`ri-information-line link-faded`,ariaDescription:app.attrs.tooltip(`By default PocketBase uses the unix "sendmail" command for sending emails. For better emails deliverability it is recommended to use a SMTP mail server.`)}))),app.components.slide(()=>i.formSettings.smtp.enabled,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-4`},t.div({className:`field`},t.label({htmlFor:`smtp.host`},`SMTP server host`),t.input({id:`smtp.host`,name:`smtp.host`,type:`text`,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.host||``,oninput:e=>i.formSettings.smtp.host=e.target.value}))),t.div({className:`col-lg-2`},t.div({className:`field`},t.label({htmlFor:`smtp.port`},`Port`),t.input({id:`smtp.port`,name:`smtp.port`,type:`number`,min:0,step:1,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.port||``,oninput:e=>i.formSettings.smtp.port=parseInt(e.target.value,10)}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.username`},`Username`),t.input({id:`smtp.username`,name:`smtp.username`,type:`text`,autocomplete:`off`,value:()=>i.formSettings.smtp.username||``,oninput:e=>i.formSettings.smtp.username=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.password`},`Password`),t.input({id:`smtp.password`,name:`smtp.password`,type:`password`,autocomplete:`new-password`,value:()=>i.formSettings.smtp.password||``,oninput:e=>i.formSettings.smtp.password=e.target.value,onkeyup:e=>{e.key==`Backspace`&&i.formSettings.smtp.password===void 0&&(i.formSettings.smtp.password=``)},placeholder:()=>i.formSettings.smtp.password===void 0?`* * * * * *`:``})))),t.button({type:`button`,className:`btn secondary sm m-t-sm`,onclick:()=>i.showMoreOptions=!i.showMoreOptions},t.span({className:`txt`},()=>i.showMoreOptions?`Hide more options`:`Show more options`),t.i({className:()=>i.showMoreOptions?`ri-arrow-drop-up-line`:`ri-arrow-drop-down-line`})),app.components.slide(()=>i.showMoreOptions,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.tls`},`TLS encryption`),app.components.select({id:`smtp.tls`,name:`smtp.tls`,required:!0,options:n,value:()=>i.formSettings.smtp.tls||!1,onchange:e=>{i.formSettings.smtp.tls=e?.[0]?.value}}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.authMethod`},`AUTH method`),app.components.select({id:`smtp.authMethod`,name:`smtp.authMethod`,required:!0,options:r,value:()=>i.formSettings.smtp.authMethod||r[0].value,onchange:e=>{i.formSettings.smtp.authMethod=e?.[0]?.value}}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`smtp.localName`},t.span({className:`txt`},`EHLO/HELO domain`),t.i({className:`ri-information-line link-hint tooltip-top`,ariaDescription:app.attrs.tooltip(`Some SMTP servers, such as the Gmail SMTP-relay, requires a proper domain name in the inital EHLO/HELO exchange and will reject attempts to use localhost.`)})),t.input({id:`smtp.localName`,name:`smtp.localName`,type:`text`,placeholder:`Default to localhost`,value:()=>i.formSettings.smtp.localName||``,oninput:e=>i.formSettings.smtp.localName=e.target.value}))))))),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),()=>i.hasChanges?[t.button({type:`button`,className:`btn transparent secondary`,onclick:c},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${i.isSaving?`loading`:``}`,disabled:()=>!i.hasChanges||i.isSaving},t.span({className:`txt`},`Save changes`))]:t.button({type:`button`,className:()=>`btn expanded-lg outline`,onclick:()=>app.modals.openMailTest()},t.i({className:`ri-mail-check-line`,ariaHidden:!0}),t.span({className:`txt`},`Send test email`)))))),t.footer({className:`page-footer`},app.components.credits())))}var Yi=`pbSQLConsoleHistory`;function Xi(e){app.store.title=`SQL console`;let n=`sql_console_`+app.utils.randomString(),r=n+`editor`,i=n+`executeSQL`,a=store({askedForConfirmationAtLeastOnce:!1,isExecuting:!1,maxRows:250,query:``,result:{},sort:{},errorMsg:``,executedHistory:app.utils.getLocalHistory(Yi,[]),get sortedResultRows(){if(a.sort?.index===void 0){let e=a.result?.rows||[];return a.maxRows>=e.length?e:e.slice(0,a.maxRows)}let e=!!a.sort?.asc,n=a.result?.rows?.toSorted((n,r)=>{let i=n[a.sort.index],o=r[a.sort.index];return e||(i=r[a.sort.index],o=n[a.sort.index]),i==o?0:i==null?-1:o==null?1:i.localeCompare(o)})||[];return a.maxRows>=n.length?n:n.slice(0,a.maxRows)},get totalRemainingRows(){return(a.result?.rows?.length<<0)-a.sortedResultRows.length}});function o(e){return e?.trim()?!a.askedForConfirmationAtLeastOnce&&app.store.settings?.meta?.hideControls?!0:(e=e?.replace(/[\s\;]/gm,` `).toUpperCase()+` `,!![`ALTER `,`REPLACE `,`INSERT `,`CREATE `,`UPDATE `,`DELETE `,`DROP `,`DETACH `,`PRAGMA `].find(n=>e.includes(n))):!1}async function s(){return o(a.query)?(a.askedForConfirmationAtLeastOnce=!0,app.modals.confirm(t.div({className:`txt-center`},t.h6(null,`Be careful and continue only if you really know what you are doing because, depending on the query, the operation could break your application and may not be reversible.`)),()=>c(),null,{yesButton:`Execute`,noButton:`Cancel`})):c()}async function c(){a.isExecuting=!0,a.maxRows=250,a.result={},a.sort={},a.errorMsg=``;let e=a.query.trim();if(!e){app.pb.cancelRequest(i),a.isExecuting=!1;return}try{a.result=await app.pb.sql.run(e,{requestKey:i}),u(e),a.isExecuting=!1}catch(e){e?.isAbort||(a.isExecuting=!1,a.errorMsg=e?.response?.message||e?.message||`Failed to execute query.`)}}function l(e){function n(e){return e.replace(/[\s\;]/gm,``).toUpperCase()}let r=n(e);for(let i=a.executedHistory.length-1;i>=0;i--)(a.executedHistory[i]==e||n(a.executedHistory[i])==r)&&a.executedHistory.splice(i,1)}function u(e){l(e),a.executedHistory.unshift(a.query),a.executedHistory.length>10&&a.executedHistory.splice(10)}function d(){if(!a.sortedResultRows.length)return;let e=[a.result.columns.map(e=>e.name)].concat(a.sortedResultRows),n=`export_`+new Date().toISOString().replace(/[\-\:\.]/g,``)+`.csv`;app.utils.downloadCSV(e,n)}function f(e){a.sort?.index==e?a.sort={index:e,asc:!a.sort.asc}:a.sort={index:e,asc:!0}}let p=[watch(()=>JSON.stringify(a.executedHistory),(e,n)=>{n!==void 0&&window.localStorage.setItem(Yi,e)})];return t.div({pbEvent:`pageSQLConsole`,className:`page`,onunmount:()=>{app.pb.cancelRequest(i),p.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title)),t.div({className:`page-header-secondary-btns`},t.button({type:`button`,className:`btn circle transparent secondary`,ariaDescription:app.attrs.tooltip(`Recently executed queries`,`right`),"html-popovertarget":`sql-console-history-dropdown`},t.i({className:`ri-history-line`,ariaHidden:!0})),t.div({id:`sql-console-history-dropdown`,className:()=>`dropdown left sql-console-history-dropdown ${a.executedHistory.length?``:`no-items`}`,popover:`auto`},()=>a.executedHistory.length?a.executedHistory.map(e=>t.button({role:`button`,className:`dropdown-item`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),a.query=e,document.getElementById(r)?.click()}},t.span({className:`query`},()=>app.utils.truncate(e,500)),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),l(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.span({className:`txt txt-hint p-5`},`No recently executed queries.`))),t.div({className:`page-header-primary-btns`},t.button({type:`button`,className:()=>`btn expanded-lg ${a.isExecuting?`loading`:``}`,disabled:()=>a.isExecuting,onclick:()=>s()},t.i({className:`ri-play-large-line`,ariaHidden:!0}),t.span({className:`txt`},`Execute`)))),t.div({className:`field sql-console-field`},app.components.codeEditor({id:r,language:`sql`,required:!0,name:`query`,placeholder:`e.g. EXPLAIN QUERY PLAN SELECT * from users WHERE verified=true`,value:()=>a.query,oninput:e=>a.query=e,onblur:e=>a.query=e.trim()})),t.div({className:`flex field-help m-b-sm`},t.button({type:`button`,className:`link-hint m-l-auto`,"html-popovertarget":n+`caveats_dropdown`},()=>`SQL console caveats`),t.div({id:n+`caveats_dropdown`,className:`dropdown sm query-caveats-dropdown`,popover:`auto`},t.ul(null,t.li(null,`The returned rows are limited up to 1000.`),t.li(null,`The executed queries have a max timeout of 3 minutes.`),t.li(null,`The data is returned as byte strings without any additional formatting.`),t.li(null,`Multiple queries are supported but only the result of the last one is returned.`)))),t.div({hidden:()=>a.isExecuting||!a.errorMsg,className:`alert danger m-b-sm`},t.pre(null,()=>a.errorMsg)),t.div({hidden:()=>a.isExecuting||a.errorMsg||a.result?.columns?.length||app.utils.isEmpty(a.result),className:`alert success m-b-sm`},t.p({className:`txt-bold`},`Query executed successfully!`),()=>{if(a.result?.affectedRows)return t.p(null,`Affected rows: `,a.result?.affectedRows)}),t.div({hidden:()=>a.isExecuting||!a.result?.columns?.length,className:`page-table-wrapper`},t.table({className:`sql-console-table responsive-table optimize`},t.thead({className:`sticky`},t.tr(null,()=>a.result?.columns?.map((e,n)=>t.th({textContent:e.name,className:()=>{let e=`sort-handle`;return a.sort?.index==n&&(e+=a.sort.asc?` asc`:` desc`),e},onclick:()=>f(n)})))),t.tbody(null,()=>a.sortedResultRows.length?a.sortedResultRows.map(e=>t.tr(null,()=>a.result?.columns?.map((n,r)=>{let i=e[r];return t.td({"html-data-name":n.name},i==null?`NULL`:app.utils.truncate(i,2e3))}))):t.tr(null,t.td({colSpan:a.result?.columns?.length||1,className:`txt-center`},t.span({className:`txt-hint`},`No rows found.`))),t.tr({hidden:()=>a.isExecuting||!a.result?.rows?.length||a.result.rows.length<=a.sortedResultRows.length},t.td({colSpan:99},t.button({type:`button`,className:`btn lg secondary load-more-btn`,onclick:()=>{a.maxRows=a.result?.rows?.length||250}},t.span({className:`txt`,textContent:()=>`Load remaining (${a.totalRemainingRows})`}))))))),t.footer({className:`page-footer`},t.span({className:()=>`exec-time ${a.isExecuting?`faded`:``}`},`Time: `,()=>(a.result?.execTime||0)+`ms`),t.span({hidden:()=>!a.result?.columns?.length,className:()=>`total-count ${a.isExecuting?`faded`:``}`},`Rows: `,()=>a.result?.rows?.length||0,()=>{if(a.result?.rows?.length)return[` (`,t.span({role:`button`,className:`link-hint`,textContent:`Export as CSV`,onclick:d}),`)`]}),app.components.credits())))}function Zi(){app.store.title=`File storage`;let e=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,originalFormSettings:null,get hasChanges(){return e.initSerialized!=JSON.stringify(e.formSettings)}});n();async function n(){e.isLoading=!0;try{i(await app.pb.settings.getAll()),e.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function r(){if(!(e.isSaving||!e.hasChanges)){e.isSaving=!0;try{let n=app.utils.filterRedactedProps(e.formSettings);i(await app.pb.settings.update(n)),app.toasts.success(`Successfully saved storage settings.`)}catch(e){app.checkApiError(e)}e.isSaving=!1}}function i(n={}){app.store.settings=JSON.parse(JSON.stringify(n)),e.formSettings={s3:n?.s3||{}},e.initSerialized=JSON.stringify(e.formSettings),e.originalFormSettings=JSON.parse(e.initSerialized)}function a(){e.formSettings=JSON.parse(e.initSerialized)}return t.div({pbEvent:`pageStorageSettings`,className:`page page-storage-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>e.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`storageSettingsForm`,className:`grid storage-settings-form`,inert:()=>e.isSaving,onsubmit:e=>{e.preventDefault(),r()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`By default PocketBase uses and recommends the local file system to store uploaded files because it is more performant, easier to manage and backup.`),t.p(null,`Alternatively, if you have limited disk space available, you could opt to an S3 compatible external storage.`)),t.div({className:`col-lg-12`},app.components.s3ConfigFields({config:()=>e.formSettings.s3,before:()=>{let n=e.originalFormSettings.s3?.enabled;if(n!=e.formSettings.s3?.enabled)return t.div({className:`alert info m-t-sm`},`If you have existing uploaded files, you'll have to migrate them manually from the `,t.strong(null,n?`S3 storage`:`local file system`),` to the `,t.strong(null,e.formSettings.s3?.enabled?`S3 storage`:`local file system`),`.`,t.br(),`There are several command line tools that can help you, such as: `,t.a({href:`https://github.com/rclone/rclone`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`rclone`}),`, `,t.a({href:`https://github.com/peak/s5cmd`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`s5cmd`}),`, etc.`)}})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!e.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:a},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${e.isSaving?`loading`:``}`,disabled:()=>!e.hasChanges||e.isSaving},t.span({className:`txt`},`Save changes`)))))),t.footer({className:`page-footer`},app.components.credits())))}function Qi(e){app.store.title=`Export collections`;let n=`export_`+app.utils.randomString(),r=store({isLoading:!1,collections:[],bulkSelected:{},get bulkSelectStr(){return JSON.stringify(app.utils.sortedCollectionsByType(Object.values(r.bulkSelected)),null,2)},get totalSelected(){return Object.keys(r.bulkSelected).length},get areAllSelected(){return r.collections.length&&r.collections.length==r.totalSelected}});i();async function i(){r.isLoading=!0;try{let e=await app.pb.collections.getFullList({requestKey:n});for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;r.collections=app.utils.sortedCollectionsByType(e),c(),r.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoading=!1)}}function a(){let e=app.utils.sortedCollectionsByType(Object.values(r.bulkSelected));app.utils.downloadJSON(e,`pb_schema`)}function o(){r.areAllSelected?s():c()}function s(){r.bulkSelected={}}function c(){r.bulkSelected={};for(let e of r.collections)r.bulkSelected[e.id]=e}return t.div({pbEvent:`pageExportCollections`,className:`page page-export-collections`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>r.isLoading?t.div({className:`txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`txt-lg`},`Below you'll find your current collections configuration that you could import in another PocketBase environment.`)),t.div({className:`col-lg-12`},t.div({className:`export-panel`},t.aside({className:`export-list`},t.div({className:`list-item`},t.div({className:`field`},t.input({id:n+`.select_all`,type:`checkbox`,checked:()=>r.areAllSelected,onchange:()=>o()}),t.label({htmlFor:n+`.select_all`},`Select all`))),()=>r.collections.map(e=>{let i=n+`_c_`+e.id;return t.div({className:`list-item`},t.div({className:`field`},t.input({id:i,type:`checkbox`,checked:()=>!!r.bulkSelected[e.id],onchange:n=>{let i=Object.assign({},r.bulkSelected);n.target.__shiftKey&&(n.target.__shiftKey=!1,app.utils.bulkSelectRange(r.collections,i,e,n.target.checked)),n.target.checked?i[e.id]=e:delete i[e.id],r.bulkSelected=i}}),t.label({htmlFor:i,textContent:()=>e.name,onclick:e=>{e.preventDefault();let n=document.getElementById(e.target.htmlFor);n&&(n.__shiftKey=e.shiftKey,n.click())}})))})),t.output({className:`export-preview`},app.components.codeBlock({value:()=>r.bulkSelectStr,language:`plain`}),t.nav({className:`ctrls`},app.components.copyButton(()=>r.bulkSelectStr))))),t.div({className:`col-lg-12 txt-right`},t.button({className:`btn`,onclick:a},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download as JSON`))))),t.footer({className:`page-footer`},app.components.credits())))}function $i(e){app.store.title=`Import collections`;let n=`import_`+app.utils.randomString(),r=[],i=store({rawNewCollections:``,oldCollections:[],newCollections:[],collectionsToUpdate:[],deleteMissing:!0,isLoadingFile:!1,isLoadingOldCollections:!1,mergeWithOldCollections:!1,get isRawValid(){return!!i.rawNewCollections&&i.newCollections?.length>0&&i.newCollections.length==i.newCollections.filter(e=>!!e.id&&!!e.name).length},get collectionsToDelete(){return i.oldCollections.filter(e=>i.isRawValid&&!i.mergeWithOldCollections&&i.deleteMissing&&!i.newCollections.find(n=>n.id==e.id))},get collectionsToAdd(){return i.newCollections.filter(e=>i.isRawValid&&!i.oldCollections.find(n=>n.id==e.id))},get idReplacableCollections(){return i.newCollections.filter(e=>{let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)return!1;if(n.id!=e.id)return!0;let r=Array.isArray(n.fields)?n.fields:[],a=Array.isArray(e.fields)?e.fields:[];for(let e of a){if(r.find(n=>n.id==e.id))continue;let n=r.find(n=>n.name==e.name);if(n&&e.id!=n.id)return!0}return!1})},get hasChanges(){return!!i.rawNewCollections&&!!(i.collectionsToDelete.length||i.collectionsToAdd.length||i.collectionsToUpdate.length)},get canReview(){return!i.isLoadingOldCollections&&i.isRawValid&&i.hasChanges}}),a=t.input({id:n+`_load_json`,type:`file`,className:`hidden`,accept:`.json`,onchange:()=>{d(a.files?.[0])}});o();async function o(){i.isLoadingOldCollections=!0;try{let e=await app.pb.collections.getFullList();for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;i.oldCollections=e,i.isLoadingOldCollections=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoadingOldCollections=!1)}}r.push(watch(()=>i.rawNewCollections,()=>{s()}));function s(){let e=[];try{e=JSON.parse(i.rawNewCollections),e=Array.isArray(e)?app.utils.filterDuplicatesByKey(e):[];for(let n of e)delete n.created,delete n.updated,n.fields&&=app.utils.filterDuplicatesByKey(n.fields)}catch{}i.newCollections=e}r.push(watch(()=>[i.newCollections,i.deleteMissing],()=>{c()}));function c(){if(i.collectionsToUpdate=[],i.isRawValid)for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.id==e.id);!n?.id||!app.utils.hasCollectionChanges(n,e,i.deleteMissing)||i.collectionsToUpdate.push({new:e,old:n})}}function l(){for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)continue;let r=e.id,a=n.id;e.id=a;let o=Array.isArray(n.fields)?n.fields:[],s=Array.isArray(e.fields)?e.fields:[];for(let e of s){let n=o.find(n=>n.name==e.name);n&&n.id&&(e.id=n.id)}for(let e of i.newCollections)if(Array.isArray(e.fields))for(let n of e.fields)n.collectionId&&n.collectionId===r&&(n.collectionId=a);for(let n=0;ne.replace(r,a))}i.rawNewCollections=JSON.stringify(i.newCollections,null,2)}function u(){i.rawNewCollections=``,a.value=``,app.store.errors=null}function d(e){i.isLoadingFile=!0;let n=new FileReader;n.onload=async e=>{i.isLoadingFile=!1,a.value=``,i.rawNewCollections=e.target.result,await new Promise(e=>setTimeout(e,0)),i.newCollections.length||(app.toasts.error(`Invalid collections configuration.`),u())},n.onerror=e=>{app.toasts.error(`Failed to load the imported JSON.`),console.warn(e),i.isLoadingFile=!1,a.value=``},n.readAsText(e)}function f(){let e=i.mergeWithOldCollections?app.utils.filterDuplicatesByKey(i.oldCollections.concat(i.newCollections)):i.newCollections;app.modals.openImportCollectionsReview(i.oldCollections,e,{deleteMissing:i.deleteMissing,onsubmit:()=>{u(),o()}})}return t.div({pbEvent:`pageImportCollections`,className:`page page-import-collections`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoadingOldCollections?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.span({className:`txt-lg m-r-5`},`Paste below the collections configuration you want to import or`),t.label({htmlFor:a.id,className:()=>`btn sm outline ${i.isLoadingFile?`loading`:``}`},t.span({className:`txt`},`Load from JSON file`)),a,t.p({className:`txt-hint`},t.em(null,`You can use the `,t.a({href:`https://pocketbase.io/docs/go-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JS`}),` migrations to manage your collections programmatically in more granular and version controlled manner.`))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:n+`_collections_field`},`Collections`),t.textarea({id:n+`_collections_field`,name:`collections`,rows:12,className:`txt-code`,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,value:()=>i.rawNewCollections,oninput:e=>i.rawNewCollections=e.target.value})),t.div({className:()=>`field-help error ${i.rawNewCollections&&!i.isRawValid?``:`hidden`}`},`Invalid collections configuration.`)),t.div({className:()=>`col-lg-12 ${i.isRawValid?``:`hidden`}`},t.div({className:`field`},t.input({id:n+`_merge_checkbox`,type:`checkbox`,className:`switch`,checked:()=>i.mergeWithOldCollections,onchange:e=>i.mergeWithOldCollections=e.target.checked}),t.label({htmlFor:n+`_merge_checkbox`},`Merge with the existing collections`))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&!i.hasChanges?``:`hidden`}`},t.div({className:`alert info`},t.div({className:`content`},t.p(null,`Your collections configuration is already up-to-date!`)))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&i.hasChanges?``:`hidden`}`},t.p({className:`txt-hint txt-bold`},`Detected changes`),t.div({className:`list`},()=>i.collectionsToDelete.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))),()=>i.collectionsToUpdate.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(e.old.name!=e.new.name)return[t.span({className:`txt-strikethrough txt-hint`,textContent:e.old.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>e.new.name}),t.small({className:()=>`txt-hint ${e.new.id?``:`hidden`}`,textContent:()=>e.new.id})))),()=>i.collectionsToAdd.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label success`,textContent:`Added`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))))),t.div({className:()=>`col-lg-12 ${i.idReplacableCollections?.length?``:`hidden`}`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Some of the imported collections share the same name and/or fields but are imported with different IDs.`),t.p(null,`You can replace them in the import if you want to:`,t.button({type:`button`,className:`btn warning sm m-l-10`,textContent:`Replace with original IDs`,onclick:l}))))),t.div({className:`col-lg-12`},t.div({className:`flex`},t.button({type:`button`,className:()=>`btn secondary ${i.rawNewCollections?``:`hidden`}`,onclick:u},t.span({className:`txt`},`Clear`)),t.button({type:`button`,className:`btn expanded-lg m-l-auto`,disabled:()=>!i.canReview,onclick:f},t.span({className:`txt`},`Review`)))))),t.footer({className:`page-footer`},app.components.credits())))}window.app=window.app||{},window.app.routes=window.app.routes||{},window.app.routes.fallbackPath=`#/collections`,app.routes.guestOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(app.pb.authStore.isValid&&app.pb.authStore.record?.id){window.location.hash=`#/`;return}app.store.showHeader=!1,app.store.page=await n(e)}},app.routes.superuserOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(!app.pb.authStore.isValid||!app.pb.authStore.record?.id){window.location.hash=`#/login`;return}app.store.showHeader=!0,app.store.page=await n(e)}},app.routes.blank=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{app.store.showHeader=!1,app.store.page=await n(e)}};var ea={},ta;function na(){ta&&ta(),ta=router(ea,{fallbackPath:app.routes.fallbackPath})}app.routes.guestOnly(`#/pbinstall/{token}`,async e=>{let{pageInstaller:n}=await G(async()=>{let{pageInstaller:e}=await import(`./pageInstaller-Btd_kQ3V.js`);return{pageInstaller:e}},[],import.meta.url);return n(e)}),app.routes.guestOnly(`#/login`,e=>$r(e)),app.routes.guestOnly(`#/request-password-reset`,async e=>{let{pageRequestSuperuserPasswordReset:n}=await G(async()=>{let{pageRequestSuperuserPasswordReset:e}=await import(`./pageRequestSuperuserPasswordReset-C39AMhGf.js`);return{pageRequestSuperuserPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-password-reset/{token}`,async e=>{let{pageConfirmPasswordReset:n}=await G(async()=>{let{pageConfirmPasswordReset:e}=await import(`./pageConfirmPasswordReset-DDVg4sJm.js`);return{pageConfirmPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-verification/{token}`,async e=>{let{pageConfirmVerification:n}=await G(async()=>{let{pageConfirmVerification:e}=await import(`./pageConfirmVerification-DePQEvON.js`);return{pageConfirmVerification:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-email-change/{token}`,async e=>{let{pageConfirmEmailChange:n}=await G(async()=>{let{pageConfirmEmailChange:e}=await import(`./pageConfirmEmailChange-BY7xJuWX.js`);return{pageConfirmEmailChange:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-success`,async e=>{let{pageOAuth2RedirectSuccess:n}=await G(async()=>{let{pageOAuth2RedirectSuccess:e}=await import(`./pageOAuth2RedirectSuccess-DmZV1eyz.js`);return{pageOAuth2RedirectSuccess:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-failure`,async e=>{let{pageOAuth2RedirectFailure:n}=await G(async()=>{let{pageOAuth2RedirectFailure:e}=await import(`./pageOAuth2RedirectFailure-CRvz4PXa.js`);return{pageOAuth2RedirectFailure:e}},[],import.meta.url);return n(e)}),app.routes.superuserOnly(`#/collections`,hi),app.routes.superuserOnly(`#/logs`,Ei),app.routes.superuserOnly(`#/settings`,Ii),app.routes.superuserOnly(`#/settings/mail`,Ji),app.routes.superuserOnly(`#/settings/storage`,Zi),app.routes.superuserOnly(`#/settings/backups`,Gi),app.routes.superuserOnly(`#/settings/crons`,qi),app.routes.superuserOnly(`#/settings/export-collections`,Qi),app.routes.superuserOnly(`#/settings/import-collections`,$i),app.routes.superuserOnly(`#/settings/sql`,Xi);var ra=t;t=new Proxy({},{get(e,n){return function(){let e=arguments?.[0];if(e&&e.pbEvent){let n=e.onmount;e.onmount=r=>{n?.(r),r.dataset.pb=e.pbEvent,document.dispatchEvent(new CustomEvent(`mount:`+e.pbEvent,{detail:r}))};let r=e.onunmount;e.onunmount=n=>{document.dispatchEvent(new CustomEvent(`unmount:`+e.pbEvent,{detail:n})),r?.(n)}}return ra[n](...arguments)}}}),document.body.prepend(t.main({"html-class":`app`,className:()=>`app ${app.store.settings?.meta?.hideControls?`hide-controls`:``}`},Fe(),e=>(typeof app.store.page==`function`&&app.store.page(e),app.store.page))),watch(()=>app.store._ready,e=>{e&&na()}),document.body.appendChild(t.script({type:`module`,src:app.pb.buildURL(`/_/extensions.js`),onload:()=>{app.store._ready=!0},onerror:e=>{console.warn(`Failed to load extensions:`,e),app.store._ready=!0}}));export{S as n,se as r,Ee as t}; \ No newline at end of file +@hourly`)},`macros`),`.`,t.br(),`By default the timezone is in UTC.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`backups.cronMaxKeep`},`Max @auto backups to keep`),t.input({id:`backups.cronMaxKeep`,name:`backups.cronMaxKeep`,type:`number`,required:()=>a.enableAutoBackups,min:1,value:()=>a.formSettings.backups.cronMaxKeep,oninput:e=>{a.formSettings.backups.cronMaxKeep=parseInt(e.target.value,10)}})))))),t.div({className:`col-lg-12`},app.components.s3ConfigFields({toggleLabel:`Store backups in S3 storage`,testFilesystem:`backups`,config:()=>a.formSettings.backups.s3})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!a.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:l},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${a.isSaving?`loading`:``}`,disabled:()=>!a.hasChanges||a.isSaving},t.span({className:`txt`},`Save changes`))))])))}function zi(e={oncreated:null}){let n=Bi(e);n&&(document.body.appendChild(n),app.modals.open(n))}function Bi(e){let n,r=`backup_create_`+app.utils.randomString(),i=store({name:``,isSubmitting:!1}),a;async function o(){if(!i.isSubmitting){i.isSubmitting=!0,clearTimeout(a),a=setTimeout(()=>{app.modals.close(n)},1500);try{await app.pb.backups.create(i.name,{requestKey:r}),i.isSubmitting=!1,e.oncreated&&e.oncreated(i.name),app.toasts.success(`Successfully generated new backup.`),app.modals.close(n)}catch(e){e.isAbort||(clearTimeout(a),i.isSubmitting=!1,app.checkApiError(e))}}}return n=t.div({pbEvent:`backupCreateModal`,className:`modal popup backup-create-modal`,onbeforeclose:()=>{i.isSubmitting&&app.toasts.info(`The backup was started but may take a while to complete. You can come back later.`)},onafterclose:e=>{clearTimeout(a),e?.remove()}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Initialize new backup`)),t.form({id:r,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Please note that during the backup other concurrent write requests may fail since the database will be temporary "locked" (this usually happens only during the ZIP generation).`),t.p({className:`txt-bold`},`If you are using S3 storage for the collections file upload, you'll have to backup them separately since they are not locally stored and they will not be included in the generated backup!`)))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:r+`_name`},`Backup name`),t.input({id:r+`_name`,name:`name`,type:`text`,pattern:`^[a-z0-9_-]+.zip$`,placeholder:`Leave empty to autogenerate`,value:()=>i.name,oninput:e=>i.name=e.target.value})),t.div({className:`field-help`},`Must be in the format [a-z0-9_-].zip`)))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,disabled:()=>i.isSubmitting,onclick:()=>app.modals.close(n)},t.span({className:`txt`},`Cancel`)),t.button({"html-form":r,type:`submit`,className:()=>`btn ${i.isSubmitting?`loading`:``}`,disabled:()=>i.isSubmitting},t.span({className:`txt`},`Start backup`)))),n}function Vi(e){let n=Hi(e);document.body.appendChild(n),app.modals.open(n)}function Hi(e){let n=`backup_restore_`+app.utils.randomString(),r=store({key:e,keyConfirm:``,isSubmitting:!1,get canSubmit(){return r.key&&r.key==r.keyConfirm}}),i;async function a(){if(!(r.isSubmitting||!r.canSubmit)){clearTimeout(i),r.isSubmitting=!0;try{await app.pb.backups.restore(r.keyConfirm),i=setTimeout(()=>{window.location.reload(),r.isSubmitting=!1},2e3)}catch(e){clearTimeout(i),e?.isAbort||(r.isSubmitting=!1,app.checkApiError(e))}}}return t.div({pbEvent:`backupRestoreModal`,className:`modal popup backup-restore-modal`,onbeforeclose:()=>!r.isSubmitting,onafterclose:e=>{e?.remove()},onunmount:()=>{clearTimeout(i)}},t.header({className:`modal-header`},t.h5({className:`m-auto txt-center`},`Restore `,t.strong(null,()=>r.key))),t.form({id:n,className:`modal-content backup-restore-form`,autocomplete:`off`,onsubmit:e=>{e.preventDefault(),a()}},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`alert danger`},t.div({className:`content`},t.p({className:`txt-bold`},`Please proceed with extreme caution and use it only with trusted backups!`),t.p(null,`Backup restore currently works only on UNIX based systems.`),t.p(null,`The restore operation will attempt to replace your existing `,t.code(null,`pb_data`),` with the one from the backup and will restart the application process.`),t.p(null,`This means that on success all of your data (including app settings, users, superusers, etc.) will be replaced with the ones from the backup.`),t.p(null,`The operation will be reverted if the backup is invalid (ex. missing `,t.code(null,`data.db`),` file).`),t.p(null,`Below is an oversimplified version of the restore flow:`),t.ol(null,t.li(null,`Replaces the current `,t.code(null,`pb_data`),` with the content from the backup.`),t.li(null,`Triggers app restart.`),t.li(null,`Applies all migrations that are missing in the restored `,t.code(null,`pb_data`),`.`),t.li(null,`Initializes the app server as usual.`))))),t.div({className:`col-lg-12`},t.div({className:`confirm-key-label m-b-sm`},`Type the backup name `,t.div({className:`label`},()=>r.key,app.components.copyButton(()=>r.key)),` to confirm:`),t.div({className:`field`},t.label({htmlFor:n+`_key`},`Backup name`),t.input({id:n+`_key`,name:`key`,type:`text`,required:!0,value:()=>r.keyConfirm,oninput:e=>r.keyConfirm=e.target.value}))))),t.footer({className:`modal-footer`},t.button({type:`button`,className:`btn transparent m-r-auto`,onclick:()=>app.modals.close(),disabled:()=>r.isSubmitting},t.span({className:`txt`},`Cancel`)),t.button({"html-form":n,type:`submit`,className:()=>`btn ${r.isSubmitting?`loading`:``}`,disabled:()=>r.isSubmitting||!r.canSubmit},t.span({className:`txt`},`Restore backup`))))}function Ui(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({canBackup:!0,isLoading:!1,isDownloading:{},isDeleting:{},backups:[]});async function a(){i.isLoading=!0;try{i.backups=await app.pb.backups.getFullList(),i.backups.sort((e,n)=>e.modifiedn.modified?-1:0),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){app.modals.confirm(`Do you really want to delete ${e}?`,()=>s(e))}async function s(e){if(!i.isDeleting[e]){i.isDeleting[e]=!0;try{await app.pb.backups.delete(e),a(),app.toasts.success(`Successfully deleted ${e}.`)}catch(e){app.checkApiError(e)}delete i.isDeleting[e]}}async function c(){try{let e=await app.pb.health.check({requestKey:null}),n=i.canBackup;i.canBackup=e?.data?.canBackup||!1,i.canBackup&&n!=i.canBackup&&a()}catch(e){console.warn(`failed to load canBackup checks`,e)}}async function l(e){if(!i.isDownloading[e]){i.isDownloading[e]=!0;try{let n=await app.pb.files.getToken({requestKey:null});app.utils.download(app.pb.backups.getDownloadURL(n,e))}catch(e){app.checkApiError(e)}delete i.isDownloading[e]}}return t.div({pbEvent:`backupsList`,className:`list backups-list`,onmount:e=>{r.push(watch(()=>n.reset,()=>{a()})),e._canBackupIntervalId=setInterval(()=>{c()},3500)},onunmount:e=>{clearInterval(e._canBackupIntervalId),r.forEach(e=>e?.unwatch())}},t.div({className:`list-content`},t.div({hidden:()=>!i.isLoading||i.backups.length,className:`list-item`},t.div({className:`skeleton-loader`})),t.div({hidden:()=>i.isLoading||i.backups.length,className:()=>`list-item`},t.div({className:`content block txt-hint`},`No backups found.`)),()=>i.backups.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.i({className:`ri-folder-zip-line`,ariaHidden:!0}),t.div({className:`content`},t.span({className:`backup-name txt-ellipsis`,title:()=>e.key,textContent:()=>e.key}),t.small({className:`backup-size txt-hint txt-nowrap`},`(`,()=>app.utils.formattedFileSize(e.size),`)`)),t.nav({hidden:()=>i.isLoading,className:`actions autohide`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Download`),className:()=>`btn sm circle secondary transparent ${i.isDownloading[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>l(e.key)},t.i({className:`ri-download-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Restore`),className:()=>`btn sm circle secondary transparent`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>Vi(e.key)},t.i({className:`ri-restart-line`,ariaHidden:!0})),t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Delete`),className:()=>`btn sm circle secondary transparent ${i.isDeleting[e.key]?`loading`:``}`,disabled:()=>i.isDeleting[e.key]||i.isDownloading[e.key],onclick:()=>o(e.key)},t.i({className:`ri-delete-bin-7-line`,ariaHidden:!0})))))),t.div({className:`list-item`},t.button({type:`button`,className:()=>`btn secondary block ${i.isLoading?`loading`:``}`,disabled:()=>!i.canBackup||i.isLoading,onclick:()=>{zi({oncreated:()=>a()})}},()=>i.canBackup?[t.i({className:`ri-play-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Initialize new backup`)]:[t.span({className:`loader sm`}),t.span({className:`txt`},`Backup/restore operation is in process`)])))}function Wi(e=null){let n=`backup_upload_`+app.utils.randomString(),r=store({isUploading:!1});function i(e){e&&app.modals.confirm(`Note that we don't perform validations for the uploaded backup files. Proceed with extreme caution and only if you trust the source.\n\nDo you really want to upload "${e.name}"?`,()=>{a(e)},()=>{o()})}async function a(i){if(!(!i||r.isUploading)){r.isUploading=!0;try{let a=new FormData;a.set(`file`,i),await app.pb.backups.upload(a,{requestKey:n}),r.isUploading=!1,e(i),app.toasts.success(`Successfully uploaded a new backup.`)}catch(e){e.isAbort||(r.isUploading=!1,e.response?.formData?.file?.message?app.toasts.error(e.response.formData.file.message):app.checkApiError(e))}o()}}function o(){s&&(s.value=``)}let s=t.input({type:`file`,accept:`application/zip`,className:`hidden`,onchange:e=>{i(e.target?.files?.[0])}});return t.div(null,t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Upload backup`),className:()=>`btn sm transparent secondary circle ${r.isUploading?`loading`:``}`,disabled:()=>r.isUploading,onclick:()=>s?.click(),onunmount:()=>{app.pb.cancelRequest(n)}},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0})),s)}function Gi(e){app.store.title=`Backups`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageBackupsSettings`,className:`page page-backups-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Backup and restore your PocketBase data`),app.components.refreshButton({className:`btn sm transparent secondary circle tooltip-bottom`,onclick:r}),Wi(r)),Ui({reset:()=>n.resetList})),t.div({className:`col-lg-12`},Ri({onsave:()=>r()})))),t.footer({className:`page-footer`},app.components.credits())))}function Ki(e={}){let n=store({reset:null}),r=app.utils.extendStore(n,e),i=store({isLoading:!1,isRunning:{},crons:[]});async function a(){i.isLoading=!0;try{i.crons=await app.pb.crons.getFullList(),i.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoading=!1)}}async function o(e){if(!(!e||i.isRunning[e])){i.isRunning[e]=!0;try{await app.pb.crons.run(e),app.toasts.success(`Successfully triggered "${e}".`),i.isRunning[e]=!1}catch(n){n.isAbort||(ApiClient.error(n),i.isRunning[e]=!1)}}}return t.div({pbEvent:`cronsList`,className:`list`,onmount:()=>{r.push(watch(()=>n.reset,()=>{a()}))},onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!i.isLoading||i.crons.length)return;let e=[];for(let n=0;n<4;n++)e.push(t.div({rid:`skeleton_`+n,className:`list-item`},t.div({className:`skeleton-loader`})));return e},t.div({hidden:()=>i.isLoading||i.crons.length,className:`list-item`},t.div({className:`content block txt-hint`},`No registered crons found.`)),()=>i.crons.map(e=>t.div({className:()=>`list-item ${i.isLoading?`faded`:``}`},t.div({className:`content`},t.span({className:`cron-id txt-code txt-ellipsis`,title:()=>e.id,textContent:()=>e.id})),t.small({className:`cron-expression txt-hint txt-nowrap txt-code`},()=>e.expression),t.nav({hidden:()=>i.isLoading,className:`actions`},t.button({type:`button`,ariaLabel:app.attrs.tooltip(`Run`),className:()=>`btn sm circle secondary transparent ${i.isRunning[e.id]?`loading`:``}`,disabled:()=>i.isRunning[e.id],onclick:()=>o(e.id)},t.i({className:`ri-play-large-line`,ariaHidden:!0}))))))}function qi(e){app.store.title=`Crons`;let n=store({resetList:null});function r(){n.resetList=Date.now()}return t.div({pbEvent:`pageCronsSettings`,className:`page`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},t.div({className:`flex gap-10 m-b-sm`},t.div({className:`txt-lg`},`Registered app cron jobs`),app.components.refreshButton({className:`btn sm transparent secondary circle`,onclick:r})),Ki({reset:()=>n.resetList}),t.div({className:`txt-sm txt-hint m-t-sm`},`App cron jobs can be registered only programmatically with `,t.a({href:`https://pocketbase.io/docs/go-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-jobs-scheduling/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JavaScript`}),`.`)),t.footer({className:`page-footer`},app.components.credits())))}function Ji(e){app.store.title=`Mail settings`;let n=[{label:`Auto (StartTLS)`,value:!1},{label:`Always`,value:!0}],r=[{label:`PLAIN (default)`,value:`PLAIN`},{label:`LOGIN`,value:`LOGIN`}],i=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,showMoreOptions:!1,get hasChanges(){return i.initSerialized!=JSON.stringify(i.formSettings)}});a();async function a(){i.isLoading=!0;try{s(await app.pb.settings.getAll()),i.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function o(){if(!(i.isSaving||!i.hasChanges)){i.isSaving=!0;try{let e=app.utils.filterRedactedProps(i.formSettings);s(await app.pb.settings.update(e)),app.toasts.success(`Successfully saved mail settings.`)}catch(e){app.checkApiError(e)}i.isSaving=!1}}function s(e={}){app.store.settings=JSON.parse(JSON.stringify(e)),i.formSettings={meta:e?.meta||{},smtp:e?.smtp||{}},i.formSettings.smtp.authMethod||(i.formSettings.smtp.authMethod=r[0].value),i.initSerialized=JSON.stringify(i.formSettings)}function c(){i.formSettings=JSON.parse(i.initSerialized)}return t.div({pbEvent:`pageMailSettings`,className:`page page-mail-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`mailSettingsForm`,className:`grid mail-settings-form`,inert:()=>i.isSaving,onsubmit:e=>{e.preventDefault(),o()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`Configure common settings for sending emails.`)),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderName`},`Sender name`),t.input({id:`meta.senderName`,name:`meta.senderName`,type:`text`,required:!0,value:()=>i.formSettings.meta.senderName||``,oninput:e=>i.formSettings.meta.senderName=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`meta.senderAddress`},`Sender address`),t.input({id:`meta.senderAddress`,name:`meta.senderAddress`,type:`email`,required:!0,value:()=>i.formSettings.meta.senderAddress||``,oninput:e=>i.formSettings.meta.senderAddress=e.target.value}))),t.div({className:`col-lg-12`},t.div({className:`field`},t.input({id:`smtp.enabled`,name:`smtp.enabled`,type:`checkbox`,className:`switch`,checked:()=>!!i.formSettings.smtp.enabled,onchange:e=>i.formSettings.smtp.enabled=e.target.checked}),t.label({htmlFor:`smtp.enabled`},t.span({className:`txt`},`Use SMTP mail server `,t.strong(null,`(recommended)`)),t.i({className:`ri-information-line link-faded`,ariaDescription:app.attrs.tooltip(`By default PocketBase uses the unix "sendmail" command for sending emails. For better emails deliverability it is recommended to use a SMTP mail server.`)}))),app.components.slide(()=>i.formSettings.smtp.enabled,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-4`},t.div({className:`field`},t.label({htmlFor:`smtp.host`},`SMTP server host`),t.input({id:`smtp.host`,name:`smtp.host`,type:`text`,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.host||``,oninput:e=>i.formSettings.smtp.host=e.target.value}))),t.div({className:`col-lg-2`},t.div({className:`field`},t.label({htmlFor:`smtp.port`},`Port`),t.input({id:`smtp.port`,name:`smtp.port`,type:`number`,min:0,step:1,required:()=>i.formSettings.smtp.enabled,value:()=>i.formSettings.smtp.port||``,oninput:e=>i.formSettings.smtp.port=parseInt(e.target.value,10)}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.username`},`Username`),t.input({id:`smtp.username`,name:`smtp.username`,type:`text`,autocomplete:`off`,value:()=>i.formSettings.smtp.username||``,oninput:e=>i.formSettings.smtp.username=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.password`},`Password`),t.input({id:`smtp.password`,name:`smtp.password`,type:`password`,autocomplete:`new-password`,value:()=>i.formSettings.smtp.password||``,oninput:e=>i.formSettings.smtp.password=e.target.value,onkeyup:e=>{e.key==`Backspace`&&i.formSettings.smtp.password===void 0&&(i.formSettings.smtp.password=``)},placeholder:()=>i.formSettings.smtp.password===void 0?`* * * * * *`:``})))),t.button({type:`button`,className:`btn secondary sm m-t-sm`,onclick:()=>i.showMoreOptions=!i.showMoreOptions},t.span({className:`txt`},()=>i.showMoreOptions?`Hide more options`:`Show more options`),t.i({className:()=>i.showMoreOptions?`ri-arrow-drop-up-line`:`ri-arrow-drop-down-line`})),app.components.slide(()=>i.showMoreOptions,t.div({className:`grid m-t-sm`},t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.tls`},`TLS encryption`),app.components.select({id:`smtp.tls`,name:`smtp.tls`,required:!0,options:n,value:()=>i.formSettings.smtp.tls||!1,onchange:e=>{i.formSettings.smtp.tls=e?.[0]?.value}}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:`smtp.authMethod`},`AUTH method`),app.components.select({id:`smtp.authMethod`,name:`smtp.authMethod`,required:!0,options:r,value:()=>i.formSettings.smtp.authMethod||r[0].value,onchange:e=>{i.formSettings.smtp.authMethod=e?.[0]?.value}}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:`smtp.localName`},t.span({className:`txt`},`EHLO/HELO domain`),t.i({className:`ri-information-line link-hint tooltip-top`,ariaDescription:app.attrs.tooltip(`Some SMTP servers, such as the Gmail SMTP-relay, requires a proper domain name in the inital EHLO/HELO exchange and will reject attempts to use localhost.`)})),t.input({id:`smtp.localName`,name:`smtp.localName`,type:`text`,placeholder:`Default to localhost`,value:()=>i.formSettings.smtp.localName||``,oninput:e=>i.formSettings.smtp.localName=e.target.value}))))))),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),()=>i.hasChanges?[t.button({type:`button`,className:`btn transparent secondary`,onclick:c},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${i.isSaving?`loading`:``}`,disabled:()=>!i.hasChanges||i.isSaving},t.span({className:`txt`},`Save changes`))]:t.button({type:`button`,className:()=>`btn expanded-lg outline`,onclick:()=>app.modals.openMailTest()},t.i({className:`ri-mail-check-line`,ariaHidden:!0}),t.span({className:`txt`},`Send test email`)))))),t.footer({className:`page-footer`},app.components.credits())))}var Yi=`pbSQLConsoleHistory`;function Xi(e){app.store.title=`SQL console`;let n=`sql_console_`+app.utils.randomString(),r=n+`editor`,i=n+`executeSQL`,a=store({askedForConfirmationAtLeastOnce:!1,isExecuting:!1,maxRows:250,query:``,result:{},sort:{},errorMsg:``,executedHistory:app.utils.getLocalHistory(Yi,[]),get sortedResultRows(){if(a.sort?.index===void 0){let e=a.result?.rows||[];return a.maxRows>=e.length?e:e.slice(0,a.maxRows)}let e=!!a.sort?.asc,n=a.result?.rows?.toSorted((n,r)=>{let i=n[a.sort.index],o=r[a.sort.index];return e||(i=r[a.sort.index],o=n[a.sort.index]),i==o?0:i==null?-1:o==null?1:i.localeCompare(o)})||[];return a.maxRows>=n.length?n:n.slice(0,a.maxRows)},get totalRemainingRows(){return(a.result?.rows?.length<<0)-a.sortedResultRows.length}});function o(e){return e?.trim()?!a.askedForConfirmationAtLeastOnce&&app.store.settings?.meta?.hideControls?!0:(e=e?.replace(/[\s\;]/gm,` `).toUpperCase()+` `,!![`ALTER `,`REPLACE `,`INSERT `,`CREATE `,`UPDATE `,`DELETE `,`DROP `,`DETACH `,`PRAGMA `].find(n=>e.includes(n))):!1}async function s(){return o(a.query)?(a.askedForConfirmationAtLeastOnce=!0,app.modals.confirm(t.div({className:`txt-center`},t.h6(null,`Be careful and continue only if you really know what you are doing because, depending on the query, the operation could break your application and may not be reversible.`)),()=>c(),null,{yesButton:`Execute`,noButton:`Cancel`})):c()}async function c(){a.isExecuting=!0,a.maxRows=250,a.result={},a.sort={},a.errorMsg=``;let e=a.query.trim();if(!e){app.pb.cancelRequest(i),a.isExecuting=!1;return}try{a.result=await app.pb.sql.run(e,{requestKey:i}),u(e),a.isExecuting=!1}catch(e){e?.isAbort||(a.isExecuting=!1,a.errorMsg=e?.response?.message||e?.message||`Failed to execute query.`)}}function l(e){function n(e){return e.replace(/[\s\;]/gm,``).toUpperCase()}let r=n(e);for(let i=a.executedHistory.length-1;i>=0;i--)(a.executedHistory[i]==e||n(a.executedHistory[i])==r)&&a.executedHistory.splice(i,1)}function u(e){l(e),a.executedHistory.unshift(a.query),a.executedHistory.length>10&&a.executedHistory.splice(10)}function d(){if(!a.sortedResultRows.length)return;let e=[a.result.columns.map(e=>e.name)].concat(a.sortedResultRows),n=`export_`+new Date().toISOString().replace(/[\-\:\.]/g,``)+`.csv`;app.utils.downloadCSV(e,n)}function f(e){a.sort?.index==e?a.sort={index:e,asc:!a.sort.asc}:a.sort={index:e,asc:!0}}let p=[watch(()=>JSON.stringify(a.executedHistory),(e,n)=>{n!==void 0&&window.localStorage.setItem(Yi,e)})];return t.div({pbEvent:`pageSQLConsole`,className:`page`,onunmount:()=>{app.pb.cancelRequest(i),p.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title)),t.div({className:`page-header-secondary-btns`},t.button({type:`button`,className:`btn circle transparent secondary`,ariaDescription:app.attrs.tooltip(`Recently executed queries`,`right`),"html-popovertarget":`sql-console-history-dropdown`},t.i({className:`ri-history-line`,ariaHidden:!0})),t.div({id:`sql-console-history-dropdown`,className:()=>`dropdown left sql-console-history-dropdown ${a.executedHistory.length?``:`no-items`}`,popover:`auto`},()=>a.executedHistory.length?a.executedHistory.map(e=>t.button({role:`button`,className:`dropdown-item`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),a.query=e,document.getElementById(r)?.click()}},t.span({className:`query`},()=>app.utils.truncate(e,500)),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),l(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.span({className:`txt txt-hint p-5`},`No recently executed queries.`))),t.div({className:`page-header-primary-btns`},t.button({type:`button`,className:()=>`btn expanded-lg ${a.isExecuting?`loading`:``}`,disabled:()=>a.isExecuting,onclick:()=>s()},t.i({className:`ri-play-large-line`,ariaHidden:!0}),t.span({className:`txt`},`Execute`)))),t.div({className:`field sql-console-field`},app.components.codeEditor({id:r,language:`sql`,required:!0,name:`query`,placeholder:`e.g. EXPLAIN QUERY PLAN SELECT * from users WHERE verified=true`,value:()=>a.query,oninput:e=>a.query=e,onblur:e=>a.query=e.trim()})),t.div({className:`flex field-help m-b-sm`},t.button({type:`button`,className:`link-hint m-l-auto`,"html-popovertarget":n+`caveats_dropdown`},()=>`SQL console caveats`),t.div({id:n+`caveats_dropdown`,className:`dropdown sm query-caveats-dropdown`,popover:`auto`},t.ul(null,t.li(null,`The returned rows are limited up to 1000.`),t.li(null,`The executed queries have a max timeout of 3 minutes.`),t.li(null,`The data is returned as byte strings without any additional formatting.`),t.li(null,`Multiple queries are supported but only the result of the last one is returned.`)))),t.div({hidden:()=>a.isExecuting||!a.errorMsg,className:`alert danger m-b-sm`},t.pre(null,()=>a.errorMsg)),t.div({hidden:()=>a.isExecuting||a.errorMsg||a.result?.columns?.length||app.utils.isEmpty(a.result),className:`alert success m-b-sm`},t.p({className:`txt-bold`},`Query executed successfully!`),()=>{if(a.result?.affectedRows)return t.p(null,`Affected rows: `,a.result?.affectedRows)}),t.div({hidden:()=>a.isExecuting||!a.result?.columns?.length,className:`page-table-wrapper`},t.table({className:`sql-console-table responsive-table optimize`},t.thead({className:`sticky`},t.tr(null,()=>a.result?.columns?.map((e,n)=>t.th({textContent:e.name,className:()=>{let e=`sort-handle`;return a.sort?.index==n&&(e+=a.sort.asc?` asc`:` desc`),e},onclick:()=>f(n)})))),t.tbody(null,()=>a.sortedResultRows.length?a.sortedResultRows.map(e=>t.tr(null,()=>a.result?.columns?.map((n,r)=>{let i=e[r];return t.td({"html-data-name":n.name},i==null?`NULL`:app.utils.truncate(i,2e3))}))):t.tr(null,t.td({colSpan:a.result?.columns?.length||1,className:`txt-center`},t.span({className:`txt-hint`},`No rows found.`))),t.tr({hidden:()=>a.isExecuting||!a.result?.rows?.length||a.result.rows.length<=a.sortedResultRows.length},t.td({colSpan:99},t.button({type:`button`,className:`btn lg secondary load-more-btn`,onclick:()=>{a.maxRows=a.result?.rows?.length||250}},t.span({className:`txt`,textContent:()=>`Load remaining (${a.totalRemainingRows})`}))))))),t.footer({className:`page-footer`},t.span({className:()=>`exec-time ${a.isExecuting?`faded`:``}`},`Time: `,()=>(a.result?.execTime||0)+`ms`),t.span({hidden:()=>!a.result?.columns?.length,className:()=>`total-count ${a.isExecuting?`faded`:``}`},`Rows: `,()=>a.result?.rows?.length||0,()=>{if(a.result?.rows?.length)return[` (`,t.span({role:`button`,className:`link-hint`,textContent:`Export as CSV`,onclick:d}),`)`]}),app.components.credits())))}function Zi(){app.store.title=`File storage`;let e=store({isLoading:!1,isSaving:!1,formSettings:null,initSerialized:`null`,originalFormSettings:null,get hasChanges(){return e.initSerialized!=JSON.stringify(e.formSettings)}});n();async function n(){e.isLoading=!0;try{i(await app.pb.settings.getAll()),e.isLoading=!1}catch(e){e.isAbort||app.checkApiError(e)}}async function r(){if(!(e.isSaving||!e.hasChanges)){e.isSaving=!0;try{let n=app.utils.filterRedactedProps(e.formSettings);i(await app.pb.settings.update(n)),app.toasts.success(`Successfully saved storage settings.`)}catch(e){app.checkApiError(e)}e.isSaving=!1}}function i(n={}){app.store.settings=JSON.parse(JSON.stringify(n)),e.formSettings={s3:n?.s3||{}},e.initSerialized=JSON.stringify(e.formSettings),e.originalFormSettings=JSON.parse(e.initSerialized)}function a(){e.formSettings=JSON.parse(e.initSerialized)}return t.div({pbEvent:`pageStorageSettings`,className:`page page-storage-settings`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>e.isLoading?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.form({pbEvent:`storageSettingsForm`,className:`grid storage-settings-form`,inert:()=>e.isSaving,onsubmit:e=>{e.preventDefault(),r()}},t.div({className:`col-lg-12 txt-lg`},t.p(null,`By default PocketBase uses and recommends the local file system to store uploaded files because it is more performant, easier to manage and backup.`),t.p(null,`Alternatively, if you have limited disk space available, you could opt to an S3 compatible external storage.`)),t.div({className:`col-lg-12`},app.components.s3ConfigFields({config:()=>e.formSettings.s3,before:()=>{let n=e.originalFormSettings.s3?.enabled;if(n!=e.formSettings.s3?.enabled)return t.div({className:`alert info m-t-sm`},`If you have existing uploaded files, you'll have to migrate them manually from the `,t.strong(null,n?`S3 storage`:`local file system`),` to the `,t.strong(null,e.formSettings.s3?.enabled?`S3 storage`:`local file system`),`.`,t.br(),`There are several command line tools that can help you, such as: `,t.a({href:`https://github.com/rclone/rclone`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`rclone`}),`, `,t.a({href:`https://github.com/peak/s5cmd`,target:`_blank`,rel:`noopener noreferrer`,className:`txt-bold`,textContent:`s5cmd`}),`, etc.`)}})),t.div({className:`col-lg-12`},t.hr()),t.div({className:`col-lg-12`},t.div({className:`flex`},t.div({className:`m-r-auto`}),t.button({hidden:()=>!e.hasChanges,type:`button`,className:`btn transparent secondary`,onclick:a},t.span({className:`txt`},`Cancel`)),t.button({className:()=>`btn expanded-lg ${e.isSaving?`loading`:``}`,disabled:()=>!e.hasChanges||e.isSaving},t.span({className:`txt`},`Save changes`)))))),t.footer({className:`page-footer`},app.components.credits())))}function Qi(e){app.store.title=`Export collections`;let n=`export_`+app.utils.randomString(),r=store({isLoading:!1,collections:[],bulkSelected:{},get bulkSelectStr(){return JSON.stringify(app.utils.sortedCollectionsByType(Object.values(r.bulkSelected)),null,2)},get totalSelected(){return Object.keys(r.bulkSelected).length},get areAllSelected(){return r.collections.length&&r.collections.length==r.totalSelected}});i();async function i(){r.isLoading=!0;try{let e=await app.pb.collections.getFullList({requestKey:n});for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;r.collections=app.utils.sortedCollectionsByType(e),c(),r.isLoading=!1}catch(e){e.isAbort||(app.checkApiError(e),r.isLoading=!1)}}function a(){let e=app.utils.sortedCollectionsByType(Object.values(r.bulkSelected));app.utils.downloadJSON(e,`pb_schema`)}function o(){r.areAllSelected?s():c()}function s(){r.bulkSelected={}}function c(){r.bulkSelected={};for(let e of r.collections)r.bulkSelected[e.id]=e}return t.div({pbEvent:`pageExportCollections`,className:`page page-export-collections`},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>r.isLoading?t.div({className:`txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.div({className:`txt-lg`},`Below you'll find your current collections configuration that you could import in another PocketBase environment.`)),t.div({className:`col-lg-12`},t.div({className:`export-panel`},t.aside({className:`export-list`},t.div({className:`list-item`},t.div({className:`field`},t.input({id:n+`.select_all`,type:`checkbox`,checked:()=>r.areAllSelected,onchange:()=>o()}),t.label({htmlFor:n+`.select_all`},`Select all`))),()=>r.collections.map(e=>{let i=n+`_c_`+e.id;return t.div({className:`list-item`},t.div({className:`field`},t.input({id:i,type:`checkbox`,checked:()=>!!r.bulkSelected[e.id],onchange:n=>{let i=Object.assign({},r.bulkSelected);n.target.__shiftKey&&(n.target.__shiftKey=!1,app.utils.bulkSelectRange(r.collections,i,e,n.target.checked)),n.target.checked?i[e.id]=e:delete i[e.id],r.bulkSelected=i}}),t.label({htmlFor:i,textContent:()=>e.name,onclick:e=>{e.preventDefault();let n=document.getElementById(e.target.htmlFor);n&&(n.__shiftKey=e.shiftKey,n.click())}})))})),t.output({className:`export-preview`},app.components.codeBlock({value:()=>r.bulkSelectStr,language:`plain`}),t.nav({className:`ctrls`},app.components.copyButton(()=>r.bulkSelectStr))))),t.div({className:`col-lg-12 txt-right`},t.button({className:`btn`,onclick:a},t.i({className:`ri-download-line`,ariaHidden:!0}),t.span({className:`txt`},`Download as JSON`))))),t.footer({className:`page-footer`},app.components.credits())))}function $i(e){app.store.title=`Import collections`;let n=`import_`+app.utils.randomString(),r=[],i=store({rawNewCollections:``,oldCollections:[],newCollections:[],collectionsToUpdate:[],deleteMissing:!0,isLoadingFile:!1,isLoadingOldCollections:!1,mergeWithOldCollections:!1,get isRawValid(){return!!i.rawNewCollections&&i.newCollections?.length>0&&i.newCollections.length==i.newCollections.filter(e=>!!e.id&&!!e.name).length},get collectionsToDelete(){return i.oldCollections.filter(e=>i.isRawValid&&!i.mergeWithOldCollections&&i.deleteMissing&&!i.newCollections.find(n=>n.id==e.id))},get collectionsToAdd(){return i.newCollections.filter(e=>i.isRawValid&&!i.oldCollections.find(n=>n.id==e.id))},get idReplacableCollections(){return i.newCollections.filter(e=>{let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)return!1;if(n.id!=e.id)return!0;let r=Array.isArray(n.fields)?n.fields:[],a=Array.isArray(e.fields)?e.fields:[];for(let e of a){if(r.find(n=>n.id==e.id))continue;let n=r.find(n=>n.name==e.name);if(n&&e.id!=n.id)return!0}return!1})},get hasChanges(){return!!i.rawNewCollections&&!!(i.collectionsToDelete.length||i.collectionsToAdd.length||i.collectionsToUpdate.length)},get canReview(){return!i.isLoadingOldCollections&&i.isRawValid&&i.hasChanges}}),a=t.input({id:n+`_load_json`,type:`file`,className:`hidden`,accept:`.json`,onchange:()=>{d(a.files?.[0])}});o();async function o(){i.isLoadingOldCollections=!0;try{let e=await app.pb.collections.getFullList();for(let n of e)delete n.created,delete n.updated,delete n.oauth2?.providers;i.oldCollections=e,i.isLoadingOldCollections=!1}catch(e){e.isAbort||(app.checkApiError(e),i.isLoadingOldCollections=!1)}}r.push(watch(()=>i.rawNewCollections,()=>{s()}));function s(){let e=[];try{e=JSON.parse(i.rawNewCollections),e=Array.isArray(e)?app.utils.filterDuplicatesByKey(e):[];for(let n of e)delete n.created,delete n.updated,n.fields&&=app.utils.filterDuplicatesByKey(n.fields)}catch{}i.newCollections=e}r.push(watch(()=>[i.newCollections,i.deleteMissing],()=>{c()}));function c(){if(i.collectionsToUpdate=[],i.isRawValid)for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.id==e.id);!n?.id||!app.utils.hasCollectionChanges(n,e,i.deleteMissing)||i.collectionsToUpdate.push({new:e,old:n})}}function l(){for(let e of i.newCollections){let n=i.oldCollections.find(n=>n.name==e.name||n.id==e.id);if(!n)continue;let r=e.id,a=n.id;e.id=a;let o=Array.isArray(n.fields)?n.fields:[],s=Array.isArray(e.fields)?e.fields:[];for(let e of s){let n=o.find(n=>n.name==e.name);n&&n.id&&(e.id=n.id)}for(let e of i.newCollections)if(Array.isArray(e.fields))for(let n of e.fields)n.collectionId&&n.collectionId===r&&(n.collectionId=a);for(let n=0;ne.replace(r,a))}i.rawNewCollections=JSON.stringify(i.newCollections,null,2)}function u(){i.rawNewCollections=``,a.value=``,app.store.errors=null}function d(e){i.isLoadingFile=!0;let n=new FileReader;n.onload=async e=>{i.isLoadingFile=!1,a.value=``,i.rawNewCollections=e.target.result,await new Promise(e=>setTimeout(e,0)),i.newCollections.length||(app.toasts.error(`Invalid collections configuration.`),u())},n.onerror=e=>{app.toasts.error(`Failed to load the imported JSON.`),console.warn(e),i.isLoadingFile=!1,a.value=``},n.readAsText(e)}function f(){let e=i.mergeWithOldCollections?app.utils.filterDuplicatesByKey(i.oldCollections.concat(i.newCollections)):i.newCollections;app.modals.openImportCollectionsReview(i.oldCollections,e,{deleteMissing:i.deleteMissing,onsubmit:()=>{u(),o()}})}return t.div({pbEvent:`pageImportCollections`,className:`page page-import-collections`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},Di(),t.div({className:`page-content full-height`},t.header({className:`page-header`},t.nav({className:`breadcrumbs`},t.div({className:`breadcrumb-item`},`Settings`),t.div({className:`breadcrumb-item`},()=>app.store.title))),t.div({className:`wrapper m-b-base`},()=>i.isLoadingOldCollections?t.div({className:`block txt-center`},t.span({className:`loader lg`})):t.div({className:`grid`},t.div({className:`col-lg-12`},t.span({className:`txt-lg m-r-5`},`Paste below the collections configuration you want to import or`),t.label({htmlFor:a.id,className:()=>`btn sm outline ${i.isLoadingFile?`loading`:``}`},t.span({className:`txt`},`Load from JSON file`)),a,t.p({className:`txt-hint`},t.em(null,`You can use the `,t.a({href:`https://pocketbase.io/docs/go-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`Go`}),` or `,t.a({href:`https://pocketbase.io/docs/js-migrations/`,target:`_blank`,rel:`noopener noreferrer`,textContent:`JS`}),` migrations to manage your collections programmatically in more granular and version controlled manner.`))),t.div({className:`col-lg-12`},t.div({className:`field`},t.label({htmlFor:n+`_collections_field`},`Collections`),t.textarea({id:n+`_collections_field`,name:`collections`,rows:12,className:`txt-code`,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,value:()=>i.rawNewCollections,oninput:e=>i.rawNewCollections=e.target.value})),t.div({className:()=>`field-help error ${i.rawNewCollections&&!i.isRawValid?``:`hidden`}`},`Invalid collections configuration.`)),t.div({className:()=>`col-lg-12 ${i.isRawValid?``:`hidden`}`},t.div({className:`field`},t.input({id:n+`_merge_checkbox`,type:`checkbox`,className:`switch`,checked:()=>i.mergeWithOldCollections,onchange:e=>i.mergeWithOldCollections=e.target.checked}),t.label({htmlFor:n+`_merge_checkbox`},`Merge with the existing collections`))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&!i.hasChanges?``:`hidden`}`},t.div({className:`alert info`},t.div({className:`content`},t.p(null,`Your collections configuration is already up-to-date!`)))),t.div({className:()=>`col-lg-12 ${i.isRawValid&&i.hasChanges?``:`hidden`}`},t.p({className:`txt-hint txt-bold`},`Detected changes`),t.div({className:`list`},()=>i.collectionsToDelete.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label danger`,textContent:`Deleted`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))),()=>i.collectionsToUpdate.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label warning`,textContent:`Changed`}),t.div({className:`inline-flex gap-5`},()=>{if(e.old.name!=e.new.name)return[t.span({className:`txt-strikethrough txt-hint`,textContent:e.old.name}),t.i({className:`ri-arrow-right-line txt-sm`,ariaHidden:!0})]},t.strong({textContent:()=>e.new.name}),t.small({className:()=>`txt-hint ${e.new.id?``:`hidden`}`,textContent:()=>e.new.id})))),()=>i.collectionsToAdd.map(e=>t.div({className:`list-item`},t.span({className:`label import-change-label success`,textContent:`Added`}),t.div({className:`inline-flex gap-5`},t.strong({textContent:()=>e.name}),t.small({className:()=>`txt-hint ${e.id?``:`hidden`}`,textContent:()=>e.id})))))),t.div({className:()=>`col-lg-12 ${i.idReplacableCollections?.length?``:`hidden`}`},t.div({className:`alert warning`},t.div({className:`content`},t.p(null,`Some of the imported collections share the same name and/or fields but are imported with different IDs.`),t.p(null,`You can replace them in the import if you want to:`,t.button({type:`button`,className:`btn warning sm m-l-10`,textContent:`Replace with original IDs`,onclick:l}))))),t.div({className:`col-lg-12`},t.div({className:`flex`},t.button({type:`button`,className:()=>`btn secondary ${i.rawNewCollections?``:`hidden`}`,onclick:u},t.span({className:`txt`},`Clear`)),t.button({type:`button`,className:`btn expanded-lg m-l-auto`,disabled:()=>!i.canReview,onclick:f},t.span({className:`txt`},`Review`)))))),t.footer({className:`page-footer`},app.components.credits())))}window.app=window.app||{},window.app.routes=window.app.routes||{},window.app.routes.fallbackPath=`#/collections`,app.routes.guestOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(app.pb.authStore.isValid&&app.pb.authStore.record?.id){window.location.hash=`#/`;return}app.store.showHeader=!1,app.store.page=await n(e)}},app.routes.superuserOnly=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{if(!app.pb.authStore.isValid||!app.pb.authStore.record?.id){window.location.hash=`#/login`;return}app.store.showHeader=!0,app.store.page=await n(e)}},app.routes.blank=function(e,n){if(app.store._ready)throw Error(`the router is already initialized`);ea[e]=async e=>{app.store.showHeader=!1,app.store.page=await n(e)}};var ea={},ta;function na(){ta&&ta(),ta=router(ea,{fallbackPath:app.routes.fallbackPath})}app.routes.guestOnly(`#/pbinstall/{token}`,async e=>{let{pageInstaller:n}=await G(async()=>{let{pageInstaller:e}=await import(`./pageInstaller-D0gTHS34.js`);return{pageInstaller:e}},[],import.meta.url);return n(e)}),app.routes.guestOnly(`#/login`,e=>$r(e)),app.routes.guestOnly(`#/request-password-reset`,async e=>{let{pageRequestSuperuserPasswordReset:n}=await G(async()=>{let{pageRequestSuperuserPasswordReset:e}=await import(`./pageRequestSuperuserPasswordReset-C39AMhGf.js`);return{pageRequestSuperuserPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-password-reset/{token}`,async e=>{let{pageConfirmPasswordReset:n}=await G(async()=>{let{pageConfirmPasswordReset:e}=await import(`./pageConfirmPasswordReset-DY_-cIrh.js`);return{pageConfirmPasswordReset:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-verification/{token}`,async e=>{let{pageConfirmVerification:n}=await G(async()=>{let{pageConfirmVerification:e}=await import(`./pageConfirmVerification-Bo-r9bV_.js`);return{pageConfirmVerification:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/confirm-email-change/{token}`,async e=>{let{pageConfirmEmailChange:n}=await G(async()=>{let{pageConfirmEmailChange:e}=await import(`./pageConfirmEmailChange-BXaDVeUb.js`);return{pageConfirmEmailChange:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-success`,async e=>{let{pageOAuth2RedirectSuccess:n}=await G(async()=>{let{pageOAuth2RedirectSuccess:e}=await import(`./pageOAuth2RedirectSuccess-DmZV1eyz.js`);return{pageOAuth2RedirectSuccess:e}},[],import.meta.url);return n(e)}),app.routes.blank(`#/auth/oauth2-redirect-failure`,async e=>{let{pageOAuth2RedirectFailure:n}=await G(async()=>{let{pageOAuth2RedirectFailure:e}=await import(`./pageOAuth2RedirectFailure-CRvz4PXa.js`);return{pageOAuth2RedirectFailure:e}},[],import.meta.url);return n(e)}),app.routes.superuserOnly(`#/collections`,hi),app.routes.superuserOnly(`#/logs`,Ei),app.routes.superuserOnly(`#/settings`,Ii),app.routes.superuserOnly(`#/settings/mail`,Ji),app.routes.superuserOnly(`#/settings/storage`,Zi),app.routes.superuserOnly(`#/settings/backups`,Gi),app.routes.superuserOnly(`#/settings/crons`,qi),app.routes.superuserOnly(`#/settings/export-collections`,Qi),app.routes.superuserOnly(`#/settings/import-collections`,$i),app.routes.superuserOnly(`#/settings/sql`,Xi);var ra=t;t=new Proxy({},{get(e,n){return function(){let e=arguments?.[0];if(e&&e.pbEvent){let n=e.onmount;e.onmount=r=>{n?.(r),r.dataset.pb=e.pbEvent,document.dispatchEvent(new CustomEvent(`mount:`+e.pbEvent,{detail:r}))};let r=e.onunmount;e.onunmount=n=>{document.dispatchEvent(new CustomEvent(`unmount:`+e.pbEvent,{detail:n})),r?.(n)}}return ra[n](...arguments)}}}),document.body.prepend(t.main({"html-class":`app`,className:()=>`app ${app.store.settings?.meta?.hideControls?`hide-controls`:``}`},Fe(),e=>(typeof app.store.page==`function`&&app.store.page(e),app.store.page))),watch(()=>app.store._ready,e=>{e&&na()}),document.body.appendChild(t.script({type:`module`,src:app.pb.buildURL(`/_/extensions.js`),onload:()=>{app.store._ready=!0},onerror:e=>{console.warn(`Failed to load extensions:`,e),app.store._ready=!0}}));export{S as n,se as r,Ee as t}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmEmailChange-BY7xJuWX.js b/ui/dist/assets/pageConfirmEmailChange-BXaDVeUb.js similarity index 97% rename from ui/dist/assets/pageConfirmEmailChange-BY7xJuWX.js rename to ui/dist/assets/pageConfirmEmailChange-BXaDVeUb.js index 16d2900673..79b8118044 100644 --- a/ui/dist/assets/pageConfirmEmailChange-BY7xJuWX.js +++ b/ui/dist/assets/pageConfirmEmailChange-BXaDVeUb.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.newEmail||!a.collectionId){app.toasts.error(`Invalid or expired email change token.`),window.location.hash=`#/`;return}app.store.title=`Confirm email change`;let o=store({password:``,isSubmitting:!1,isSuccess:!1,showPassword:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmEmailChange(i,o.password),o.isSuccess=!0}catch(e){app.checkApiError(e),o.isSuccess=!1}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmEmailChange`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmEmailChangeAlert`,className:`alert success txt-center`},t.p(null,`The email was successfully changed.`),t.p(null,`You can go back and sign in with your new email address.`)):t.form({pbEvent:`confirmEmailChangeForm`,className:`grid confirm-email-change-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your password to confirm changing your email address to `,t.strong(null,a.newEmail),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`password_confirm`},`Password`),t.input({id:`password_confirm`,name:`password`,required:!0,autofocus:!0,type:()=>o.showPassword?`text`:`password`,value:()=>o.password,oninput:e=>o.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showPassword?`Hide password`:`Show password`),onclick:()=>o.showPassword=!o.showPassword},t.i({className:()=>o.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Confirm new email`)))))}export{r as pageConfirmEmailChange}; \ No newline at end of file +import{n as e,t as n}from"./index-Kt84cKKj.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.newEmail||!a.collectionId){app.toasts.error(`Invalid or expired email change token.`),window.location.hash=`#/`;return}app.store.title=`Confirm email change`;let o=store({password:``,isSubmitting:!1,isSuccess:!1,showPassword:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmEmailChange(i,o.password),o.isSuccess=!0}catch(e){app.checkApiError(e),o.isSuccess=!1}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmEmailChange`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmEmailChangeAlert`,className:`alert success txt-center`},t.p(null,`The email was successfully changed.`),t.p(null,`You can go back and sign in with your new email address.`)):t.form({pbEvent:`confirmEmailChangeForm`,className:`grid confirm-email-change-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your password to confirm changing your email address to `,t.strong(null,a.newEmail),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`password_confirm`},`Password`),t.input({id:`password_confirm`,name:`password`,required:!0,autofocus:!0,type:()=>o.showPassword?`text`:`password`,value:()=>o.password,oninput:e=>o.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showPassword?`Hide password`:`Show password`),onclick:()=>o.showPassword=!o.showPassword},t.i({className:()=>o.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Confirm new email`)))))}export{r as pageConfirmEmailChange}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmPasswordReset-DDVg4sJm.js b/ui/dist/assets/pageConfirmPasswordReset-DY_-cIrh.js similarity index 97% rename from ui/dist/assets/pageConfirmPasswordReset-DDVg4sJm.js rename to ui/dist/assets/pageConfirmPasswordReset-DY_-cIrh.js index 0409385cfc..2a95e5fee8 100644 --- a/ui/dist/assets/pageConfirmPasswordReset-DDVg4sJm.js +++ b/ui/dist/assets/pageConfirmPasswordReset-DY_-cIrh.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired password reset token.`),window.location.hash=`#/`;return}app.store.title=`Confirm password reset`;let o=store({newPassword:``,newPasswordConfirm:``,showNewPassword:!1,showNewPasswordConfirm:!1,isSubmitting:!1,isSuccess:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmPasswordReset(i,o.newPassword,o.newPasswordConfirm),o.isSuccess=!0}catch(e){app.checkApiError(e)}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmPasswordReset`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmPasswordResetAlert`,className:`alert success txt-center`},t.p(null,`The password was successfully changed.`),t.p(null,`You can go back to sign in with your new password.`)):t.form({pbEvent:`confirmPasswordResetForm`,className:`grid confirm-password-reset-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your new password for `,t.strong(null,a.email),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPassword`},`New password`),t.input({id:`newPassword`,name:`password`,required:!0,autofocus:!0,autocomplete:`new-password`,type:()=>o.showNewPassword?`text`:`password`,value:()=>o.newPassword,oninput:e=>o.newPassword=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPassword?`Hide password`:`Show password`),onclick:()=>o.showNewPassword=!o.showNewPassword},t.i({className:()=>o.showNewPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPasswordConfirm`},`New password confirm`),t.input({id:`newPasswordConfirm`,name:`passwordConfirm`,required:!0,autocomplete:`new-password`,type:()=>o.showNewPasswordConfirm?`text`:`password`,value:()=>o.newPasswordConfirm,oninput:e=>o.newPasswordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPasswordConfirm?`Hide password`:`Show password`),onclick:()=>o.showNewPasswordConfirm=!o.showNewPasswordConfirm},t.i({className:()=>o.showNewPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Set new password`)))))}export{r as pageConfirmPasswordReset}; \ No newline at end of file +import{n as e,t as n}from"./index-Kt84cKKj.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired password reset token.`),window.location.hash=`#/`;return}app.store.title=`Confirm password reset`;let o=store({newPassword:``,newPasswordConfirm:``,showNewPassword:!1,showNewPasswordConfirm:!1,isSubmitting:!1,isSuccess:!1});async function s(){if(o.isSubmitting)return;o.isSubmitting=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmPasswordReset(i,o.newPassword,o.newPasswordConfirm),o.isSuccess=!0}catch(e){app.checkApiError(e)}o.isSubmitting=!1}return t.div({pbEvent:`pageConfirmPasswordReset`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isSuccess?t.div({pbEvent:`confirmPasswordResetAlert`,className:`alert success txt-center`},t.p(null,`The password was successfully changed.`),t.p(null,`You can go back to sign in with your new password.`)):t.form({pbEvent:`confirmPasswordResetForm`,className:`grid confirm-password-reset-form`,onsubmit:e=>{e.preventDefault(),s()}},t.div({className:`col-12`},t.div({className:`content txt-center m-b-sm`},`Type your new password for `,t.strong(null,a.email),`:`),t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPassword`},`New password`),t.input({id:`newPassword`,name:`password`,required:!0,autofocus:!0,autocomplete:`new-password`,type:()=>o.showNewPassword?`text`:`password`,value:()=>o.newPassword,oninput:e=>o.newPassword=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPassword?`Hide password`:`Show password`),onclick:()=>o.showNewPassword=!o.showNewPassword},t.i({className:()=>o.showNewPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`newPasswordConfirm`},`New password confirm`),t.input({id:`newPasswordConfirm`,name:`passwordConfirm`,required:!0,autocomplete:`new-password`,type:()=>o.showNewPasswordConfirm?`text`:`password`,value:()=>o.newPasswordConfirm,oninput:e=>o.newPasswordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>o.showNewPasswordConfirm?`Hide password`:`Show password`),onclick:()=>o.showNewPasswordConfirm=!o.showNewPasswordConfirm},t.i({className:()=>o.showNewPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg block ${o.isSubmitting?`loading`:``}`,disabled:()=>o.isSubmitting},t.span({className:`txt`},`Set new password`)))))}export{r as pageConfirmPasswordReset}; \ No newline at end of file diff --git a/ui/dist/assets/pageConfirmVerification-DePQEvON.js b/ui/dist/assets/pageConfirmVerification-Bo-r9bV_.js similarity index 96% rename from ui/dist/assets/pageConfirmVerification-DePQEvON.js rename to ui/dist/assets/pageConfirmVerification-Bo-r9bV_.js index e5a2e648fb..9f3aba7e23 100644 --- a/ui/dist/assets/pageConfirmVerification-DePQEvON.js +++ b/ui/dist/assets/pageConfirmVerification-Bo-r9bV_.js @@ -1 +1 @@ -import{n as e,t as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired verification token.`),window.location.hash=`#/`;return}app.store.title=`Confirm verification`;let o=store({isConfirming:!1,isConfirmSuccess:!1,isResending:!1,isResendSuccess:!1});s();async function s(){if(o.isConfirming)return;o.isConfirming=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmVerification(i),o.isConfirmSuccess=!0}catch{o.isConfirmSuccess=!1}o.isConfirming=!1}async function c(){if(o.isResending)return;o.isResending=!0;let e=new n(`../`);try{await e.collection(a.collectionId).requestVerification(a.email),o.isResendSuccess=!0}catch(e){app.checkApiError(e),o.isResendSuccess=!1}o.isResending=!1}return t.div({pbEvent:`pageConfirmVerification`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isConfirming?t.div({className:`block txt-center`},t.span({className:`loader`},`Please wait...`)):o.isConfirmSuccess?t.div({pbEvent:`confirmVerificationSuccessAlert`,className:`alert success txt-center`},t.p(null,`Successfully verified `,t.strong(null,a.email),`.`)):o.isResendSuccess?t.div({pbEvent:`confirmVerificationResendAlert`,className:`alert success txt-center`},t.p(null,`Please check your email for the new verification link.`)):[t.div({pbEvent:`confirmVerificationErrorAlert`,className:`alert danger txt-center m-b-base`},t.p(null,`Invalid or expired verification token.`)),t.button({type:`button`,className:()=>`btn transparent lg block ${o.isResending?`loading`:``}`,disabled:()=>o.isResending,onclick:()=>c()},t.span({className:`txt`},`Resend`))])}export{r as pageConfirmVerification}; \ No newline at end of file +import{n as e,t as n}from"./index-Kt84cKKj.js";function r(r){let i=r.params?.token||``,a=e(i);if(!a.email||!a.collectionId){app.toasts.error(`Invalid or expired verification token.`),window.location.hash=`#/`;return}app.store.title=`Confirm verification`;let o=store({isConfirming:!1,isConfirmSuccess:!1,isResending:!1,isResendSuccess:!1});s();async function s(){if(o.isConfirming)return;o.isConfirming=!0;let e=new n(app.pb.baseURL);try{await e.collection(a.collectionId).confirmVerification(i),o.isConfirmSuccess=!0}catch{o.isConfirmSuccess=!1}o.isConfirming=!1}async function c(){if(o.isResending)return;o.isResending=!0;let e=new n(`../`);try{await e.collection(a.collectionId).requestVerification(a.email),o.isResendSuccess=!0}catch(e){app.checkApiError(e),o.isResendSuccess=!1}o.isResending=!1}return t.div({pbEvent:`pageConfirmVerification`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),()=>o.isConfirming?t.div({className:`block txt-center`},t.span({className:`loader`},`Please wait...`)):o.isConfirmSuccess?t.div({pbEvent:`confirmVerificationSuccessAlert`,className:`alert success txt-center`},t.p(null,`Successfully verified `,t.strong(null,a.email),`.`)):o.isResendSuccess?t.div({pbEvent:`confirmVerificationResendAlert`,className:`alert success txt-center`},t.p(null,`Please check your email for the new verification link.`)):[t.div({pbEvent:`confirmVerificationErrorAlert`,className:`alert danger txt-center m-b-base`},t.p(null,`Invalid or expired verification token.`)),t.button({type:`button`,className:()=>`btn transparent lg block ${o.isResending?`loading`:``}`,disabled:()=>o.isResending,onclick:()=>c()},t.span({className:`txt`},`Resend`))])}export{r as pageConfirmVerification}; \ No newline at end of file diff --git a/ui/dist/assets/pageInstaller-Btd_kQ3V.js b/ui/dist/assets/pageInstaller-D0gTHS34.js similarity index 98% rename from ui/dist/assets/pageInstaller-Btd_kQ3V.js rename to ui/dist/assets/pageInstaller-D0gTHS34.js index 3cebb6a2c9..797b67a1e6 100644 --- a/ui/dist/assets/pageInstaller-Btd_kQ3V.js +++ b/ui/dist/assets/pageInstaller-D0gTHS34.js @@ -1 +1 @@ -import{n as e,r as n}from"./index-C9WMzSfg.js";function r(r){let i=r.params?.token||``;if(e(i).type!=`auth`||n(i)){app.toasts.error(`The installer token is invalid or has expired.`),window.location.hash=`#/`;return}app.store.title=`Setup your PocketBase instance`;let a=store({email:``,password:``,passwordConfirm:``,showPassword:!1,showPasswordConfirm:!1,isSubmitting:!1,isUploading:!1,get isBusy(){return a.isSubmitting||a.isUploading}});async function o(){if(!a.isBusy){a.isSubmitting=!0;try{await app.pb.collection(`_superusers`).create({email:a.email,password:a.password,passwordConfirm:a.passwordConfirm},{headers:{Authorization:i}}),await app.pb.collection(`_superusers`).authWithPassword(a.email,a.password),window.location.hash=`#/`}catch(e){app.checkApiError(e)}a.isSubmitting=!1}}let s=`backupFileInput`;function c(){let e=document.getElementById(s);e&&(e.value=``)}function l(e){e&&app.modals.confirm(t.h6(null,`Note that we don't perform validations for the uploaded backup files. Proceed with caution and only if you trust the file source.\n\nDo you really want to upload and initialize "${e.name}"?`),()=>{u(e)},()=>{c()})}async function u(e){if(!(!e||a.isBusy)){a.isUploading=!0;try{await app.pb.backups.upload({file:e},{headers:{Authorization:i}}),await app.pb.backups.restore(e.name,{headers:{Authorization:i}}),app.toasts.info(`Please wait while extracting the uploaded archive!`),await new Promise(e=>setTimeout(e,3e3)),window.location.href=`#/`}catch(e){app.checkApiError(e)}c(),a.isUploading=!1}}return t.div({pbEvent:`pageInstaller`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),t.form({pbEvent:`installerForm`,className:`grid installer-form`,onsubmit:e=>{e.preventDefault(),o(a)}},t.div({className:`col-12 txt-center`},`Create your first superuser account in order to continue:`),t.div({className:`col-12`},t.div({className:`field`},t.label({htmlFor:`superuser_email`},`Email`),t.input({id:`superuser_email`,name:`email`,type:`email`,required:!0,autofocus:!0,autocomplete:`off`,disabled:()=>a.isBusy,value:()=>a.email,oninput:e=>a.email=e.target.value}))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password`},`Password`),t.input({id:`superuser_password`,name:`password`,min:10,required:!0,disabled:()=>a.isBusy,type:()=>a.showPassword?`text`:`password`,value:()=>a.password,oninput:e=>a.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPassword?`Hide password`:`Show password`),onclick:()=>a.showPassword=!a.showPassword},t.i({className:()=>a.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0})))),t.div({className:`field-help`},`Recommended at least 10 characters.`)),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password_confirm`},`Password confirm`),t.input({id:`superuser_password_confirm`,name:`passwordConfirm`,required:!0,disabled:()=>a.isBusy,type:()=>a.showPasswordConfirm?`text`:`password`,value:()=>a.passwordConfirm,oninput:e=>a.passwordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPasswordConfirm?`Hide password`:`Show password`),onclick:()=>a.showPasswordConfirm=!a.showPasswordConfirm},t.i({className:()=>a.showPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg next block ${a.isSubmitting?`loading`:``}`,disabled:()=>a.isBusy},t.span({className:`txt`},`Create superuser and login`),t.i({className:`ri-arrow-right-line`,ariaHidden:!0})))),t.hr(),t.label({htmlFor:s,className:()=>`btn secondary transparent lg block ${a.isBusy?`disabled`:``} ${a.isUploading?`loading`:``}`},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Or initialize from backup`)),t.input({id:s,type:`file`,className:`hidden`,accept:`.zip`,onchange:e=>{l(e.target?.files?.[0])}}))}export{r as pageInstaller}; \ No newline at end of file +import{n as e,r as n}from"./index-Kt84cKKj.js";function r(r){let i=r.params?.token||``;if(e(i).type!=`auth`||n(i)){app.toasts.error(`The installer token is invalid or has expired.`),window.location.hash=`#/`;return}app.store.title=`Setup your PocketBase instance`;let a=store({email:``,password:``,passwordConfirm:``,showPassword:!1,showPasswordConfirm:!1,isSubmitting:!1,isUploading:!1,get isBusy(){return a.isSubmitting||a.isUploading}});async function o(){if(!a.isBusy){a.isSubmitting=!0;try{await app.pb.collection(`_superusers`).create({email:a.email,password:a.password,passwordConfirm:a.passwordConfirm},{headers:{Authorization:i}}),await app.pb.collection(`_superusers`).authWithPassword(a.email,a.password),window.location.hash=`#/`}catch(e){app.checkApiError(e)}a.isSubmitting=!1}}let s=`backupFileInput`;function c(){let e=document.getElementById(s);e&&(e.value=``)}function l(e){e&&app.modals.confirm(t.h6(null,`Note that we don't perform validations for the uploaded backup files. Proceed with caution and only if you trust the file source.\n\nDo you really want to upload and initialize "${e.name}"?`),()=>{u(e)},()=>{c()})}async function u(e){if(!(!e||a.isBusy)){a.isUploading=!0;try{await app.pb.backups.upload({file:e},{headers:{Authorization:i}}),await app.pb.backups.restore(e.name,{headers:{Authorization:i}}),app.toasts.info(`Please wait while extracting the uploaded archive!`),await new Promise(e=>setTimeout(e,3e3)),window.location.href=`#/`}catch(e){app.checkApiError(e)}c(),a.isUploading=!1}}return t.div({pbEvent:`pageInstaller`,className:`wrapper sm m-auto p-b-base`},t.header({className:`txt-center m-b-base`},t.img({className:`main-logo`,src:()=>app.store.mainLogo,ariaHidden:!0,alt:`App logo`}),t.h5({className:`m-t-10`},()=>app.store.title)),t.form({pbEvent:`installerForm`,className:`grid installer-form`,onsubmit:e=>{e.preventDefault(),o(a)}},t.div({className:`col-12 txt-center`},`Create your first superuser account in order to continue:`),t.div({className:`col-12`},t.div({className:`field`},t.label({htmlFor:`superuser_email`},`Email`),t.input({id:`superuser_email`,name:`email`,type:`email`,required:!0,autofocus:!0,autocomplete:`off`,disabled:()=>a.isBusy,value:()=>a.email,oninput:e=>a.email=e.target.value}))),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password`},`Password`),t.input({id:`superuser_password`,name:`password`,min:10,required:!0,disabled:()=>a.isBusy,type:()=>a.showPassword?`text`:`password`,value:()=>a.password,oninput:e=>a.password=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPassword?`Hide password`:`Show password`),onclick:()=>a.showPassword=!a.showPassword},t.i({className:()=>a.showPassword?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0})))),t.div({className:`field-help`},`Recommended at least 10 characters.`)),t.div({className:`col-12`},t.div({className:`fields`},t.div({className:`field`},t.label({htmlFor:`superuser_password_confirm`},`Password confirm`),t.input({id:`superuser_password_confirm`,name:`passwordConfirm`,required:!0,disabled:()=>a.isBusy,type:()=>a.showPasswordConfirm?`text`:`password`,value:()=>a.passwordConfirm,oninput:e=>a.passwordConfirm=e.target.value})),t.div({className:`field addon`},t.button({type:`button`,tabIndex:-1,className:`btn sm transparent secondary circle tooltip-right`,ariaLabel:app.attrs.tooltip(()=>a.showPasswordConfirm?`Hide password`:`Show password`),onclick:()=>a.showPasswordConfirm=!a.showPasswordConfirm},t.i({className:()=>a.showPasswordConfirm?`ri-eye-off-line`:`ri-eye-line`,ariaHidden:!0}))))),t.div({className:`col-12`},t.button({className:()=>`btn lg next block ${a.isSubmitting?`loading`:``}`,disabled:()=>a.isBusy},t.span({className:`txt`},`Create superuser and login`),t.i({className:`ri-arrow-right-line`,ariaHidden:!0})))),t.hr(),t.label({htmlFor:s,className:()=>`btn secondary transparent lg block ${a.isBusy?`disabled`:``} ${a.isUploading?`loading`:``}`},t.i({className:`ri-upload-cloud-line`,ariaHidden:!0}),t.span({className:`txt`},`Or initialize from backup`)),t.input({id:s,type:`file`,className:`hidden`,accept:`.zip`,onchange:e=>{l(e.target?.files?.[0])}}))}export{r as pageInstaller}; \ No newline at end of file diff --git a/ui/dist/index.html b/ui/dist/index.html index 7a2cfe0d69..823baef36b 100644 --- a/ui/dist/index.html +++ b/ui/dist/index.html @@ -13,7 +13,7 @@ - + diff --git a/ui/src/apiPreview/docsRealtime.js b/ui/src/apiPreview/docsRealtime.js index 0c0a25f94e..b15d9da5b8 100644 --- a/ui/src/apiPreview/docsRealtime.js +++ b/ui/src/apiPreview/docsRealtime.js @@ -57,14 +57,14 @@ export function docsRealtime(collection) { // (optionally) authenticate await pb.collection('users').authWithPassword('test@example.com', '123456'); - // subscribe to changes in any ${baseURL} record - pb.collection('${baseURL}').subscribe('*', function (e) { + // subscribe to changes in any ${collection.name} record + pb.collection('${collection.name}').subscribe('*', function (e) { console.log(e.action); console.log(e.record); }, { /* other options like: filter, expand, custom headers, etc. */ }); // subscribe to changes only in the specified record - pb.collection('${baseURL}').subscribe('RECORD_ID', function (e) { + pb.collection('${collection.name}').subscribe('RECORD_ID', function (e) { console.log(e.action); console.log(e.record); }, { /* other options like: filter, expand, custom headers, etc. */ }); @@ -72,13 +72,13 @@ export function docsRealtime(collection) { ... // unsubscribe - remove all 'RECORD_ID' subscriptions - pb.collection('${baseURL}').unsubscribe('RECORD_ID'); + pb.collection('${collection.name}').unsubscribe('RECORD_ID'); // unsubscribe - remove all '*' topic subscriptions - pb.collection('${baseURL}').unsubscribe('*'); + pb.collection('${collection.name}').unsubscribe('*'); // unsubscribe - remove all collection subscriptions - pb.collection('${baseURL}').unsubscribe(); + pb.collection('${collection.name}').unsubscribe(); `, footnote: t.div( { className: "txt-right" }, @@ -103,14 +103,14 @@ export function docsRealtime(collection) { // (optionally) authenticate await pb.collection('users').authWithPassword('test@example.com', '123456'); - // subscribe to changes in any ${baseURL} record - pb.collection('${baseURL}').subscribe('*', (e) { + // subscribe to changes in any ${collection.name} record + pb.collection('${collection.name}').subscribe('*', (e) { print(e.action); print(e.record); }, /* other options like: filter, expand, custom headers, etc. */); // subscribe to changes only in the specified record - pb.collection('${baseURL}').subscribe('RECORD_ID', (e) { + pb.collection('${collection.name}').subscribe('RECORD_ID', (e) { print(e.action); print(e.record); }, /* other options like: filter, expand, custom headers, etc. */); @@ -118,13 +118,13 @@ export function docsRealtime(collection) { ... // unsubscribe - remove all 'RECORD_ID' subscriptions - pb.collection('${baseURL}').unsubscribe('RECORD_ID'); + pb.collection('${collection.name}').unsubscribe('RECORD_ID'); // unsubscribe - remove all '*' topic subscriptions - pb.collection('${baseURL}').unsubscribe('*'); + pb.collection('${collection.name}').unsubscribe('*'); // unsubscribe - remove all collection subscriptions - pb.collection('${baseURL}').unsubscribe(); + pb.collection('${collection.name}').unsubscribe(); `, footnote: t.div( { className: "txt-right" }, From 32fa2ddf7777237a6b85da8431b9d996ccabf0b0 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Mon, 3 Aug 2026 20:04:54 +0300 Subject: [PATCH 06/37] added filesystem.NewWriter helper --- CHANGELOG.md | 2 + .../jsvm/internal/types/generated/types.d.ts | 9391 +++++++++-------- tools/filesystem/filesystem.go | 32 +- tools/filesystem/filesystem_test.go | 96 +- 4 files changed, 4873 insertions(+), 4648 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12a18a400a..770e1f88c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ - Added quotes around the default `Content-Disposition` serving filename in case custom name with special characters is provided. +- Added `filesystem.NewWriter(key, opts)` low-level helper to allow direct file create from an `io.Reader` value. + ## v0.39.10 diff --git a/plugins/jsvm/internal/types/generated/types.d.ts b/plugins/jsvm/internal/types/generated/types.d.ts index 1273f77ab8..7fde760018 100644 --- a/plugins/jsvm/internal/types/generated/types.d.ts +++ b/plugins/jsvm/internal/types/generated/types.d.ts @@ -1,4 +1,4 @@ -// 1784468372 +// 1785776637 // GENERATED CODE - DO NOT MODIFY BY HAND // ------------------------------------------------------------------- @@ -1948,8 +1948,8 @@ namespace os { * than ReadFrom. This is used to permit ReadFrom to call io.Copy * without leading to a recursive call to ReadFrom. */ - type _shzlRfc = noReadFrom&File - interface fileWithoutReadFrom extends _shzlRfc { + type _sikbbDV = noReadFrom&File + interface fileWithoutReadFrom extends _sikbbDV { } interface File { /** @@ -1993,8 +1993,8 @@ namespace os { * than WriteTo. This is used to permit WriteTo to call io.Copy * without leading to a recursive call to WriteTo. */ - type _sUNqiOb = noWriteTo&File - interface fileWithoutWriteTo extends _sUNqiOb { + type _seQqNKp = noWriteTo&File + interface fileWithoutWriteTo extends _seQqNKp { } interface File { /** @@ -2940,8 +2940,8 @@ namespace os { * * The methods of File are safe for concurrent use. */ - type _seZIqsq = file - interface File extends _seZIqsq { + type _seJgMKc = file + interface File extends _seJgMKc { } /** * A FileInfo describes a file and is returned by [Stat] and [Lstat]. @@ -3333,111 +3333,6 @@ namespace filepath { } } -/** - * Package template is a thin wrapper around the standard html/template - * and text/template packages that implements a convenient registry to - * load and cache templates on the fly concurrently. - * - * It was created to assist the JSVM plugin HTML rendering, but could be used in other Go code. - * - * Example: - * - * ``` - * registry := template.NewRegistry() - * - * html1, err := registry.LoadFiles( - * // the files set wil be parsed only once and then cached - * "layout.html", - * "content.html", - * ).Render(map[string]any{"name": "John"}) - * - * html2, err := registry.LoadFiles( - * // reuse the already parsed and cached files set - * "layout.html", - * "content.html", - * ).Render(map[string]any{"name": "Jane"}) - * ``` - */ -namespace template { - interface newRegistry { - /** - * NewRegistry creates and initializes a new templates registry with - * some defaults (eg. global "raw" template function for unescaped HTML). - * - * Use the Registry.Load* methods to load templates into the registry. - */ - (): (Registry) - } - /** - * Registry defines a templates registry that is safe to be used by multiple goroutines. - * - * Use the Registry.Load* methods to load templates into the registry. - */ - interface Registry { - } - interface Registry { - /** - * AddFuncs registers new global template functions. - * - * The key of each map entry is the function name that will be used in the templates. - * If a function with the map entry name already exists it will be replaced with the new one. - * - * The value of each map entry is a function that must have either a - * single return value, or two return values of which the second has type error. - * - * Example: - * - * ``` - * r.AddFuncs(map[string]any{ - * "toUpper": func(str string) string { - * return strings.ToUppser(str) - * }, - * ... - * }) - * ``` - */ - addFuncs(funcs: _TygojaDict): (Registry) - } - interface Registry { - /** - * LoadFiles caches (if not already) the specified filenames set as a - * single template and returns a ready to use Renderer instance. - * - * There must be at least 1 filename specified. - */ - loadFiles(...filenames: string[]): (Renderer) - } - interface Registry { - /** - * LoadString caches (if not already) the specified inline string as a - * single template and returns a ready to use Renderer instance. - */ - loadString(text: string): (Renderer) - } - interface Registry { - /** - * LoadFS caches (if not already) the specified fs and globPatterns - * pair as single template and returns a ready to use Renderer instance. - * - * There must be at least 1 file matching the provided globPattern(s) - * (note that most file names serves as glob patterns matching themselves). - */ - loadFS(fsys: fs.FS, ...globPatterns: string[]): (Renderer) - } - /** - * Renderer defines a single parsed template. - */ - interface Renderer { - } - interface Renderer { - /** - * Render executes the template with the specified data as the dot object - * and returns the result as plain string. - */ - render(data: any): string - } -} - /** * Package dbx provides a set of DB-agnostic and easy-to-use query building methods for relational databases. */ @@ -3774,14 +3669,14 @@ namespace dbx { /** * MssqlBuilder is the builder for SQL Server databases. */ - type _sCtYmpp = BaseBuilder - interface MssqlBuilder extends _sCtYmpp { + type _skCOHSO = BaseBuilder + interface MssqlBuilder extends _skCOHSO { } /** * MssqlQueryBuilder is the query builder for SQL Server databases. */ - type _sYCAmRE = BaseQueryBuilder - interface MssqlQueryBuilder extends _sYCAmRE { + type _sODknnP = BaseQueryBuilder + interface MssqlQueryBuilder extends _sODknnP { } interface newMssqlBuilder { /** @@ -3852,8 +3747,8 @@ namespace dbx { /** * MysqlBuilder is the builder for MySQL databases. */ - type _skqSaQF = BaseBuilder - interface MysqlBuilder extends _skqSaQF { + type _szmANuX = BaseBuilder + interface MysqlBuilder extends _szmANuX { } interface newMysqlBuilder { /** @@ -3928,14 +3823,14 @@ namespace dbx { /** * OciBuilder is the builder for Oracle databases. */ - type _sApSsqS = BaseBuilder - interface OciBuilder extends _sApSsqS { + type _suBWVpg = BaseBuilder + interface OciBuilder extends _suBWVpg { } /** * OciQueryBuilder is the query builder for Oracle databases. */ - type _sJYIjNA = BaseQueryBuilder - interface OciQueryBuilder extends _sJYIjNA { + type _sRMcyFU = BaseQueryBuilder + interface OciQueryBuilder extends _sRMcyFU { } interface newOciBuilder { /** @@ -3998,8 +3893,8 @@ namespace dbx { /** * PgsqlBuilder is the builder for PostgreSQL databases. */ - type _sIdTpCz = BaseBuilder - interface PgsqlBuilder extends _sIdTpCz { + type _sqIihbs = BaseBuilder + interface PgsqlBuilder extends _sqIihbs { } interface newPgsqlBuilder { /** @@ -4066,8 +3961,8 @@ namespace dbx { /** * SqliteQueryBuilder is the query builder for SQLite databases. */ - type _sJNatTO = BaseQueryBuilder - interface SqliteQueryBuilder extends _sJNatTO { + type _soknzKj = BaseQueryBuilder + interface SqliteQueryBuilder extends _soknzKj { } interface SqliteQueryBuilder { /** @@ -4088,8 +3983,8 @@ namespace dbx { /** * SqliteBuilder is the builder for SQLite databases. */ - type _scleXId = BaseBuilder - interface SqliteBuilder extends _scleXId { + type _sWBjHZc = BaseBuilder + interface SqliteBuilder extends _sWBjHZc { } interface newSqliteBuilder { /** @@ -4188,8 +4083,8 @@ namespace dbx { /** * StandardBuilder is the builder that is used by DB for an unknown driver. */ - type _stvUWpF = BaseBuilder - interface StandardBuilder extends _stvUWpF { + type _splynmr = BaseBuilder + interface StandardBuilder extends _splynmr { } interface newStandardBuilder { /** @@ -4255,8 +4150,8 @@ namespace dbx { * DB enhances sql.DB by providing a set of DB-agnostic query building methods. * DB allows easier query building and population of data into Go variables. */ - type _sYxbNJq = Builder - interface DB extends _sYxbNJq { + type _saBxNOM = Builder + interface DB extends _saBxNOM { /** * FieldMapper maps struct fields to DB columns. Defaults to DefaultFieldMapFunc. */ @@ -5086,8 +4981,8 @@ namespace dbx { * Rows enhances sql.Rows by providing additional data query methods. * Rows can be obtained by calling Query.Rows(). It is mainly used to populate data row by row. */ - type _sBQwGsU = sql.Rows - interface Rows extends _sBQwGsU { + type _sfDMojk = sql.Rows + interface Rows extends _sfDMojk { } interface Rows { /** @@ -5462,8 +5357,8 @@ namespace dbx { }): string } interface structInfo { } - type _sZNoxEO = structInfo - interface structValue extends _sZNoxEO { + type _sWXZMCM = structInfo + interface structValue extends _sWXZMCM { } interface fieldInfo { } @@ -5502,8 +5397,8 @@ namespace dbx { /** * Tx enhances sql.Tx with additional querying methods. */ - type _sQEoADI = Builder - interface Tx extends _sQEoADI { + type _sSnTLsr = Builder + interface Tx extends _sSnTLsr { } interface Tx { /** @@ -5776,8 +5671,8 @@ namespace filesystem { */ open(): io.ReadSeekCloser } - type _sjpHkBo = bytes.Reader - interface bytesReadSeekCloser extends _sjpHkBo { + type _szXEdph = bytes.Reader + interface bytesReadSeekCloser extends _szXEdph { } interface bytesReadSeekCloser { /** @@ -5905,6 +5800,33 @@ namespace filesystem { */ uploadMultipart(fh: multipart.FileHeader, fileKey: string): void } + interface System { + /** + * NewWriter returns a new blob.Writer instance allowing direct file + * create from an io.Reader value. + * + * If a file with the specified fileKey already exists, it will be replaced. + * + * NB! Make sure to call `Close()` on the resulting writer after you are done working with it. + * + * Note: If you have a bytes slice, [filesystem.File], or a multipart header value, + * you can check also the Upload* related methods as they are more user-friendly. + * + * Example: + * + * ``` + * content := strings.NewReader("Lorem ipsum dolor sit amet...") + * + * fsys, _ := filesystem.NewLocal("dir") + * defer fsys.Close() + * + * w, _ := fsys.NewWriter("example/file/key", nil) + * w.ReadFrom(content) + * w.Close() + * ``` + */ + newWriter(fileKey: string, opts: blob.WriterOptions): (blob.Writer) + } interface System { /** * Delete deletes stored file at fileKey location. @@ -7761,8 +7683,8 @@ namespace core { /** * AuthOrigin defines a Record proxy for working with the authOrigins collection. */ - type _sfIinnU = Record - interface AuthOrigin extends _sfIinnU { + type _svOrHGy = Record + interface AuthOrigin extends _svOrHGy { } interface newAuthOrigin { /** @@ -8508,8 +8430,8 @@ namespace core { * @todo experiment eventually replacing the rules *string with a struct? * @todo consider changing the Indexes field to a "getter" for the sqlite_master table? */ - type _sizwTsd = BaseModel - interface baseCollection extends _sizwTsd { + type _sWReEZE = BaseModel + interface baseCollection extends _sWReEZE { listRule?: string viewRule?: string createRule?: string @@ -8536,8 +8458,8 @@ namespace core { /** * Collection defines the table, fields and various options related to a set of records. */ - type _sQAoSZt = baseCollection&collectionAuthOptions&collectionViewOptions - interface Collection extends _sQAoSZt { + type _smBlQII = baseCollection&collectionAuthOptions&collectionViewOptions + interface Collection extends _smBlQII { } interface newCollection { /** @@ -9547,8 +9469,8 @@ namespace core { /** * RequestEvent defines the PocketBase router handler event. */ - type _szVzPbI = router.Event - interface RequestEvent extends _szVzPbI { + type _slLsDtA = router.Event + interface RequestEvent extends _slLsDtA { app: App auth?: Record } @@ -9608,8 +9530,8 @@ namespace core { */ clone(): (RequestInfo) } - type _seakEUg = hook.Event&RequestEvent - interface BatchRequestEvent extends _seakEUg { + type _stZQxSp = hook.Event&RequestEvent + interface BatchRequestEvent extends _stZQxSp { batch: Array<(InternalRequest | undefined)> } interface InternalRequest { @@ -9651,24 +9573,24 @@ namespace core { */ tags(): Array } - type _smKcRqA = hook.Event - interface BootstrapEvent extends _smKcRqA { + type _sfyxJoj = hook.Event + interface BootstrapEvent extends _sfyxJoj { app: App } - type _svwsFqW = hook.Event - interface TerminateEvent extends _svwsFqW { + type _sBeYRIF = hook.Event + interface TerminateEvent extends _sBeYRIF { app: App isRestart: boolean } - type _ssZaKbo = hook.Event - interface BackupEvent extends _ssZaKbo { + type _shqxaGS = hook.Event + interface BackupEvent extends _shqxaGS { app: App context: context.Context name: string // the name of the backup to create/restore. exclude: Array // list of dir entries to exclude from the backup create/restore. } - type _sfgoTts = hook.Event - interface ServeEvent extends _sfgoTts { + type _shCdLXM = hook.Event + interface ServeEvent extends _shCdLXM { app: App router?: router.Router server?: http.Server @@ -9715,31 +9637,31 @@ namespace core { */ fs: fs.FS } - type _sVuYBri = hook.Event&RequestEvent - interface SettingsListRequestEvent extends _sVuYBri { + type _sAEwYaz = hook.Event&RequestEvent + interface SettingsListRequestEvent extends _sAEwYaz { settings?: Settings } - type _sWWCPFA = hook.Event&RequestEvent - interface SettingsUpdateRequestEvent extends _sWWCPFA { + type _sdOUeSy = hook.Event&RequestEvent + interface SettingsUpdateRequestEvent extends _sdOUeSy { oldSettings?: Settings newSettings?: Settings } - type _ssqdEPv = hook.Event - interface SettingsReloadEvent extends _ssqdEPv { + type _sMeViXY = hook.Event + interface SettingsReloadEvent extends _sMeViXY { app: App } - type _sDJmyab = hook.Event - interface MailerEvent extends _sDJmyab { + type _sFbnPmj = hook.Event + interface MailerEvent extends _sFbnPmj { app: App mailer: mailer.Mailer message?: mailer.Message } - type _sQxMSYG = MailerEvent&baseRecordEventData - interface MailerRecordEvent extends _sQxMSYG { + type _sxxjVdB = MailerEvent&baseRecordEventData + interface MailerRecordEvent extends _sxxjVdB { meta: _TygojaDict } - type _sqcQlZs = hook.Event&baseModelEventData - interface ModelEvent extends _sqcQlZs { + type _stRmFMR = hook.Event&baseModelEventData + interface ModelEvent extends _stRmFMR { app: App context: context.Context /** @@ -9751,12 +9673,12 @@ namespace core { */ type: string } - type _sXWefEA = ModelEvent - interface ModelErrorEvent extends _sXWefEA { + type _sFbHcFB = ModelEvent + interface ModelErrorEvent extends _sFbHcFB { error: Error } - type _sdozjDH = hook.Event&baseRecordEventData - interface RecordEvent extends _sdozjDH { + type _sWPvAvS = hook.Event&baseRecordEventData + interface RecordEvent extends _sWPvAvS { app: App context: context.Context /** @@ -9768,12 +9690,12 @@ namespace core { */ type: string } - type _sXvClfK = RecordEvent - interface RecordErrorEvent extends _sXvClfK { + type _sBxFjrR = RecordEvent + interface RecordErrorEvent extends _sBxFjrR { error: Error } - type _sGEatec = hook.Event&baseCollectionEventData - interface CollectionEvent extends _sGEatec { + type _sRcdPoE = hook.Event&baseCollectionEventData + interface CollectionEvent extends _sRcdPoE { app: App context: context.Context /** @@ -9785,16 +9707,16 @@ namespace core { */ type: string } - type _sDpHwEB = CollectionEvent - interface CollectionErrorEvent extends _sDpHwEB { + type _sCozCJQ = CollectionEvent + interface CollectionErrorEvent extends _sCozCJQ { error: Error } - type _sbwGQSw = hook.Event&RequestEvent&baseRecordEventData - interface FileTokenRequestEvent extends _sbwGQSw { + type _sOgdrVH = hook.Event&RequestEvent&baseRecordEventData + interface FileTokenRequestEvent extends _sOgdrVH { token: string } - type _sGCRYlR = hook.Event&RequestEvent&baseCollectionEventData - interface FileDownloadRequestEvent extends _sGCRYlR { + type _sJkCFOv = hook.Event&RequestEvent&baseCollectionEventData + interface FileDownloadRequestEvent extends _sJkCFOv { record?: Record fileField?: FileField servedPath: string @@ -9808,21 +9730,21 @@ namespace core { */ thumbError: Error } - type _skOkcdS = hook.Event&RequestEvent - interface CollectionsListRequestEvent extends _skOkcdS { + type _sXDYMLN = hook.Event&RequestEvent + interface CollectionsListRequestEvent extends _sXDYMLN { collections: Array<(Collection | undefined)> result?: search.Result } - type _sscmyEt = hook.Event&RequestEvent - interface CollectionsImportRequestEvent extends _sscmyEt { + type _sUVzLFx = hook.Event&RequestEvent + interface CollectionsImportRequestEvent extends _sUVzLFx { collectionsData: Array<_TygojaDict> deleteMissing: boolean } - type _sdKUQUV = hook.Event&RequestEvent&baseCollectionEventData - interface CollectionRequestEvent extends _sdKUQUV { + type _sboeimZ = hook.Event&RequestEvent&baseCollectionEventData + interface CollectionRequestEvent extends _sboeimZ { } - type _skGYOyZ = hook.Event&RequestEvent - interface RealtimeConnectRequestEvent extends _skGYOyZ { + type _scPvexH = hook.Event&RequestEvent + interface RealtimeConnectRequestEvent extends _scPvexH { client: subscriptions.Client /** * IdleTimeout specifies the max duration to wait for a new message @@ -9846,59 +9768,59 @@ namespace core { */ maxTimeout: time.Duration } - type _soMcVGl = hook.Event&RequestEvent - interface RealtimeMessageEvent extends _soMcVGl { + type _sEajmJm = hook.Event&RequestEvent + interface RealtimeMessageEvent extends _sEajmJm { client: subscriptions.Client message?: subscriptions.Message } - type _skSioRZ = hook.Event&RequestEvent - interface RealtimeSubscribeRequestEvent extends _skSioRZ { + type _sROsolj = hook.Event&RequestEvent + interface RealtimeSubscribeRequestEvent extends _sROsolj { client: subscriptions.Client subscriptions: Array } - type _skhQAbo = hook.Event&RequestEvent&baseCollectionEventData - interface RecordsListRequestEvent extends _skhQAbo { + type _sOhrKrm = hook.Event&RequestEvent&baseCollectionEventData + interface RecordsListRequestEvent extends _sOhrKrm { /** * @todo consider removing and maybe add as generic to the search.Result? */ records: Array<(Record | undefined)> result?: search.Result } - type _sypXmWm = hook.Event&RequestEvent&baseCollectionEventData - interface RecordRequestEvent extends _sypXmWm { + type _sKJWjvq = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestEvent extends _sKJWjvq { record?: Record } - type _sneASKg = hook.Event&baseRecordEventData - interface RecordEnrichEvent extends _sneASKg { + type _sbKpDgw = hook.Event&baseRecordEventData + interface RecordEnrichEvent extends _sbKpDgw { app: App requestInfo?: RequestInfo } - type _sEYJvyJ = hook.Event&RequestEvent&baseCollectionEventData - interface RecordCreateOTPRequestEvent extends _sEYJvyJ { + type _sfRdtYo = hook.Event&RequestEvent&baseCollectionEventData + interface RecordCreateOTPRequestEvent extends _sfRdtYo { record?: Record password: string } - type _sHQZafL = hook.Event&RequestEvent&baseCollectionEventData - interface RecordAuthWithOTPRequestEvent extends _sHQZafL { + type _sPkIBQr = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthWithOTPRequestEvent extends _sPkIBQr { record?: Record otp?: OTP } - type _sSXEIhO = hook.Event&RequestEvent&baseCollectionEventData - interface RecordAuthRequestEvent extends _sSXEIhO { + type _shtIfYY = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthRequestEvent extends _shtIfYY { record?: Record token: string meta: any authMethod: string } - type _sEqiNyr = hook.Event&RequestEvent&baseCollectionEventData - interface RecordAuthWithPasswordRequestEvent extends _sEqiNyr { + type _szbvHYi = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthWithPasswordRequestEvent extends _szbvHYi { record?: Record identity: string identityField: string password: string } - type _sGKDemR = hook.Event&RequestEvent&baseCollectionEventData - interface RecordAuthWithOAuth2RequestEvent extends _sGKDemR { + type _synLvGZ = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthWithOAuth2RequestEvent extends _synLvGZ { providerName: string providerClient: auth.Provider record?: Record @@ -9906,41 +9828,41 @@ namespace core { createData: _TygojaDict isNewRecord: boolean } - type _sMNQfUv = hook.Event&RequestEvent&baseCollectionEventData - interface RecordAuthRefreshRequestEvent extends _sMNQfUv { + type _smzxNwc = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthRefreshRequestEvent extends _smzxNwc { record?: Record } - type _sqjWSJM = hook.Event&RequestEvent&baseCollectionEventData - interface RecordRequestPasswordResetRequestEvent extends _sqjWSJM { + type _sWbQIOF = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestPasswordResetRequestEvent extends _sWbQIOF { record?: Record } - type _srdbtmn = hook.Event&RequestEvent&baseCollectionEventData - interface RecordConfirmPasswordResetRequestEvent extends _srdbtmn { + type _sFkhTbY = hook.Event&RequestEvent&baseCollectionEventData + interface RecordConfirmPasswordResetRequestEvent extends _sFkhTbY { record?: Record } - type _sJdvlvP = hook.Event&RequestEvent&baseCollectionEventData - interface RecordRequestVerificationRequestEvent extends _sJdvlvP { + type _sOTchjh = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestVerificationRequestEvent extends _sOTchjh { record?: Record } - type _sAaKczp = hook.Event&RequestEvent&baseCollectionEventData - interface RecordConfirmVerificationRequestEvent extends _sAaKczp { + type _stDMVmh = hook.Event&RequestEvent&baseCollectionEventData + interface RecordConfirmVerificationRequestEvent extends _stDMVmh { record?: Record } - type _spPLJQW = hook.Event&RequestEvent&baseCollectionEventData - interface RecordRequestEmailChangeRequestEvent extends _spPLJQW { + type _swhXiXZ = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestEmailChangeRequestEvent extends _swhXiXZ { record?: Record newEmail: string } - type _sSQGmba = hook.Event&RequestEvent&baseCollectionEventData - interface RecordConfirmEmailChangeRequestEvent extends _sSQGmba { + type _svKzDoB = hook.Event&RequestEvent&baseCollectionEventData + interface RecordConfirmEmailChangeRequestEvent extends _svKzDoB { record?: Record newEmail: string } /** * ExternalAuth defines a Record proxy for working with the externalAuths collection. */ - type _sWvgHUl = Record - interface ExternalAuth extends _sWvgHUl { + type _sLTwHAP = Record + interface ExternalAuth extends _sLTwHAP { } interface newExternalAuth { /** @@ -12483,8 +12405,8 @@ namespace core { interface onlyFieldType { type: string } - type _ssKVGAg = Field - interface fieldWithType extends _ssKVGAg { + type _sEDzqaG = Field + interface fieldWithType extends _sEDzqaG { type: string } interface fieldWithType { @@ -12516,8 +12438,8 @@ namespace core { */ scan(value: any): void } - type _swoXEdw = BaseModel - interface Log extends _swoXEdw { + type _sAqmAED = BaseModel + interface Log extends _sAqmAED { created: types.DateTime data: types.JSONMap message: string @@ -12563,8 +12485,8 @@ namespace core { /** * MFA defines a Record proxy for working with the mfas collection. */ - type _sFEvYyU = Record - interface MFA extends _sFEvYyU { + type _sYvLUTM = Record + interface MFA extends _sYvLUTM { } interface newMFA { /** @@ -12786,8 +12708,8 @@ namespace core { /** * OTP defines a Record proxy for working with the otps collection. */ - type _srsYrRx = Record - interface OTP extends _srsYrRx { + type _sXyLPQI = Record + interface OTP extends _sXyLPQI { } interface newOTP { /** @@ -13023,8 +12945,8 @@ namespace core { } interface runner { } - type _sYqnYRG = BaseModel - interface Record extends _sYqnYRG { + type _smXwsiM = BaseModel + interface Record extends _smXwsiM { } interface newRecord { /** @@ -13499,8 +13421,8 @@ namespace core { * BaseRecordProxy implements the [RecordProxy] interface and it is intended * to be used as embed to custom user provided Record proxy structs. */ - type _sMKXSwM = Record - interface BaseRecordProxy extends _sMKXSwM { + type _sZrtrJy = Record + interface BaseRecordProxy extends _sZrtrJy { } interface BaseRecordProxy { /** @@ -13754,8 +13676,8 @@ namespace core { /** * Settings defines the PocketBase app settings. */ - type _smpJHkh = settings - interface Settings extends _smpJHkh { + type _sBiSYWI = settings + interface Settings extends _sBiSYWI { } interface Settings { /** @@ -14075,8 +13997,8 @@ namespace core { */ string(): string } - type _szfByFq = BaseModel - interface Param extends _szfByFq { + type _sggnxxQ = BaseModel + interface Param extends _sggnxxQ { created: types.DateTime updated: types.DateTime value: types.JSONRaw @@ -14617,8 +14539,8 @@ namespace apis { */ (limitBytes: number): (hook.Handler) } - type _sjENuGF = io.ReadCloser - interface limitedReader extends _sjENuGF { + type _sUYdUki = io.ReadCloser + interface limitedReader extends _sUYdUki { } interface limitedReader { read(b: string|Array): number @@ -14772,8 +14694,8 @@ namespace apis { */ (config: GzipConfig): (hook.Handler) } - type _sMrEyeL = http.ResponseWriter&io.Writer - interface gzipResponseWriter extends _sMrEyeL { + type _sIFXYKn = http.ResponseWriter&io.Writer + interface gzipResponseWriter extends _sIFXYKn { } interface gzipResponseWriter { writeHeader(code: number): void @@ -14793,16 +14715,16 @@ namespace apis { interface gzipResponseWriter { unwrap(): http.ResponseWriter } - type _sIALAAM = sync.RWMutex - interface rateLimiter extends _sIALAAM { + type _szJnAhH = sync.RWMutex + interface rateLimiter extends _szJnAhH { } /** * @todo evaluate swiching to sliding window with approximation counter similar to Cloudflare. * * rateClient implements fixed window rate limit strategy. */ - type _sIHqKuj = sync.Mutex - interface rateClient extends _sIHqKuj { + type _slHtJmK = sync.Mutex + interface rateClient extends _slHtJmK { } interface realtimeSubscribeForm { clientId: string @@ -15055,6 +14977,111 @@ namespace apis { } } +/** + * Package template is a thin wrapper around the standard html/template + * and text/template packages that implements a convenient registry to + * load and cache templates on the fly concurrently. + * + * It was created to assist the JSVM plugin HTML rendering, but could be used in other Go code. + * + * Example: + * + * ``` + * registry := template.NewRegistry() + * + * html1, err := registry.LoadFiles( + * // the files set wil be parsed only once and then cached + * "layout.html", + * "content.html", + * ).Render(map[string]any{"name": "John"}) + * + * html2, err := registry.LoadFiles( + * // reuse the already parsed and cached files set + * "layout.html", + * "content.html", + * ).Render(map[string]any{"name": "Jane"}) + * ``` + */ +namespace template { + interface newRegistry { + /** + * NewRegistry creates and initializes a new templates registry with + * some defaults (eg. global "raw" template function for unescaped HTML). + * + * Use the Registry.Load* methods to load templates into the registry. + */ + (): (Registry) + } + /** + * Registry defines a templates registry that is safe to be used by multiple goroutines. + * + * Use the Registry.Load* methods to load templates into the registry. + */ + interface Registry { + } + interface Registry { + /** + * AddFuncs registers new global template functions. + * + * The key of each map entry is the function name that will be used in the templates. + * If a function with the map entry name already exists it will be replaced with the new one. + * + * The value of each map entry is a function that must have either a + * single return value, or two return values of which the second has type error. + * + * Example: + * + * ``` + * r.AddFuncs(map[string]any{ + * "toUpper": func(str string) string { + * return strings.ToUppser(str) + * }, + * ... + * }) + * ``` + */ + addFuncs(funcs: _TygojaDict): (Registry) + } + interface Registry { + /** + * LoadFiles caches (if not already) the specified filenames set as a + * single template and returns a ready to use Renderer instance. + * + * There must be at least 1 filename specified. + */ + loadFiles(...filenames: string[]): (Renderer) + } + interface Registry { + /** + * LoadString caches (if not already) the specified inline string as a + * single template and returns a ready to use Renderer instance. + */ + loadString(text: string): (Renderer) + } + interface Registry { + /** + * LoadFS caches (if not already) the specified fs and globPatterns + * pair as single template and returns a ready to use Renderer instance. + * + * There must be at least 1 file matching the provided globPattern(s) + * (note that most file names serves as glob patterns matching themselves). + */ + loadFS(fsys: fs.FS, ...globPatterns: string[]): (Renderer) + } + /** + * Renderer defines a single parsed template. + */ + interface Renderer { + } + interface Renderer { + /** + * Render executes the template with the specified data as the dot object + * and returns the result as plain string. + */ + render(data: any): string + } +} + namespace pocketbase { /** * PocketBase defines a PocketBase app launcher. @@ -15062,8 +15089,8 @@ namespace pocketbase { * It implements [CoreApp] via embedding and all of the app interface methods * could be accessed directly through the instance (eg. PocketBase.DataDir()). */ - type _stfZQeT = CoreApp - interface PocketBase extends _stfZQeT { + type _sAMyjQM = CoreApp + interface PocketBase extends _sAMyjQM { /** * RootCmd is the main console command */ @@ -15135,15 +15162,9 @@ namespace pocketbase { */ execute(): void } - /** - * coloredWriter is a small wrapper struct to construct a [color.Color] writter. - */ - interface coloredWriter { + interface nopWrite { } - interface coloredWriter { - /** - * Write writes the p bytes using the colored writer. - */ + interface nopWrite { write(p: string|Array): number } } @@ -15300,190 +15321,27 @@ namespace sync { } /** - * Package io provides basic interfaces to I/O primitives. - * Its primary job is to wrap existing implementations of such primitives, - * such as those in package os, into shared public interfaces that - * abstract the functionality, plus some other related primitives. + * Package syscall contains an interface to the low-level operating system + * primitives. The details vary depending on the underlying system, and + * by default, godoc will display the syscall documentation for the current + * system. If you want godoc to display syscall documentation for another + * system, set $GOOS and $GOARCH to the desired system. For example, if + * you want to view documentation for freebsd/arm on linux/amd64, set $GOOS + * to freebsd and $GOARCH to arm. + * The primary use of syscall is inside other packages that provide a more + * portable interface to the system, such as "os", "time" and "net". Use + * those packages rather than this one if you can. + * For details of the functions and data types in this package consult + * the manuals for the appropriate operating system. + * These calls return err == nil to indicate success; otherwise + * err is an operating system error describing the failure. + * On most systems, that error has type [Errno]. * - * Because these interfaces and primitives wrap lower-level operations with - * various implementations, unless otherwise informed clients should not - * assume they are safe for parallel execution. - */ -namespace io { - /** - * Reader is the interface that wraps the basic Read method. - * - * Read reads up to len(p) bytes into p. It returns the number of bytes - * read (0 <= n <= len(p)) and any error encountered. Even if Read - * returns n < len(p), it may use all of p as scratch space during the call. - * If some data is available but not len(p) bytes, Read conventionally - * returns what is available instead of waiting for more. - * - * When Read encounters an error or end-of-file condition after - * successfully reading n > 0 bytes, it returns the number of - * bytes read. It may return the (non-nil) error from the same call - * or return the error (and n == 0) from a subsequent call. - * An instance of this general case is that a Reader returning - * a non-zero number of bytes at the end of the input stream may - * return either err == EOF or err == nil. The next Read should - * return 0, EOF. - * - * Callers should always process the n > 0 bytes returned before - * considering the error err. Doing so correctly handles I/O errors - * that happen after reading some bytes and also both of the - * allowed EOF behaviors. - * - * If len(p) == 0, Read should always return n == 0. It may return a - * non-nil error if some error condition is known, such as EOF. - * - * Implementations of Read are discouraged from returning a - * zero byte count with a nil error, except when len(p) == 0. - * Callers should treat a return of 0 and nil as indicating that - * nothing happened; in particular it does not indicate EOF. - * - * Implementations must not retain p. - */ - interface Reader { - [key:string]: any; - read(p: string|Array): number - } - /** - * Writer is the interface that wraps the basic Write method. - * - * Write writes len(p) bytes from p to the underlying data stream. - * It returns the number of bytes written from p (0 <= n <= len(p)) - * and any error encountered that caused the write to stop early. - * Write must return a non-nil error if it returns n < len(p). - * Write must not modify the slice data, even temporarily. - * - * Implementations must not retain p. - */ - interface Writer { - [key:string]: any; - write(p: string|Array): number - } - /** - * ReadCloser is the interface that groups the basic Read and Close methods. - */ - interface ReadCloser { - [key:string]: any; - } - /** - * ReadSeekCloser is the interface that groups the basic Read, Seek and Close - * methods. - */ - interface ReadSeekCloser { - [key:string]: any; - } -} - -/** - * Package bytes implements functions for the manipulation of byte slices. - * It is analogous to the facilities of the [strings] package. - */ -namespace bytes { - /** - * A Reader implements the [io.Reader], [io.ReaderAt], [io.WriterTo], [io.Seeker], - * [io.ByteScanner], and [io.RuneScanner] interfaces by reading from - * a byte slice. - * Unlike a [Buffer], a Reader is read-only and supports seeking. - * The zero value for Reader operates like a Reader of an empty slice. - */ - interface Reader { - } - interface Reader { - /** - * Len returns the number of bytes of the unread portion of the - * slice. - */ - len(): number - } - interface Reader { - /** - * Size returns the original length of the underlying byte slice. - * Size is the number of bytes available for reading via [Reader.ReadAt]. - * The result is unaffected by any method calls except [Reader.Reset]. - */ - size(): number - } - interface Reader { - /** - * Read implements the [io.Reader] interface. - */ - read(b: string|Array): number - } - interface Reader { - /** - * ReadAt implements the [io.ReaderAt] interface. - */ - readAt(b: string|Array, off: number): number - } - interface Reader { - /** - * ReadByte implements the [io.ByteReader] interface. - */ - readByte(): number - } - interface Reader { - /** - * UnreadByte complements [Reader.ReadByte] in implementing the [io.ByteScanner] interface. - */ - unreadByte(): void - } - interface Reader { - /** - * ReadRune implements the [io.RuneReader] interface. - */ - readRune(): [number, number] - } - interface Reader { - /** - * UnreadRune complements [Reader.ReadRune] in implementing the [io.RuneScanner] interface. - */ - unreadRune(): void - } - interface Reader { - /** - * Seek implements the [io.Seeker] interface. - */ - seek(offset: number, whence: number): number - } - interface Reader { - /** - * WriteTo implements the [io.WriterTo] interface. - */ - writeTo(w: io.Writer): number - } - interface Reader { - /** - * Reset resets the [Reader] to be reading from b. - */ - reset(b: string|Array): void - } -} - -/** - * Package syscall contains an interface to the low-level operating system - * primitives. The details vary depending on the underlying system, and - * by default, godoc will display the syscall documentation for the current - * system. If you want godoc to display syscall documentation for another - * system, set $GOOS and $GOARCH to the desired system. For example, if - * you want to view documentation for freebsd/arm on linux/amd64, set $GOOS - * to freebsd and $GOARCH to arm. - * The primary use of syscall is inside other packages that provide a more - * portable interface to the system, such as "os", "time" and "net". Use - * those packages rather than this one if you can. - * For details of the functions and data types in this package consult - * the manuals for the appropriate operating system. - * These calls return err == nil to indicate success; otherwise - * err is an operating system error describing the failure. - * On most systems, that error has type [Errno]. - * - * NOTE: Most of the functions, types, and constants defined in - * this package are also available in the [golang.org/x/sys] package. - * That package has more system call support than this one, - * and most new code should prefer that package where possible. - * See https://golang.org/s/go1.4-syscall for more information. + * NOTE: Most of the functions, types, and constants defined in + * this package are also available in the [golang.org/x/sys] package. + * That package has more system call support than this one, + * and most new code should prefer that package where possible. + * See https://golang.org/s/go1.4-syscall for more information. */ namespace syscall { // @ts-ignore @@ -16214,131 +16072,472 @@ namespace time { } /** - * Package fs defines basic interfaces to a file system. - * A file system can be provided by the host operating system - * but also by other packages. + * Package io provides basic interfaces to I/O primitives. + * Its primary job is to wrap existing implementations of such primitives, + * such as those in package os, into shared public interfaces that + * abstract the functionality, plus some other related primitives. * - * See the [testing/fstest] package for support with testing - * implementations of file systems. + * Because these interfaces and primitives wrap lower-level operations with + * various implementations, unless otherwise informed clients should not + * assume they are safe for parallel execution. */ -namespace fs { +namespace io { /** - * An FS provides access to a hierarchical file system. + * Reader is the interface that wraps the basic Read method. * - * The FS interface is the minimum implementation required of the file system. - * A file system may implement additional interfaces, - * such as [ReadFileFS], to provide additional or optimized functionality. + * Read reads up to len(p) bytes into p. It returns the number of bytes + * read (0 <= n <= len(p)) and any error encountered. Even if Read + * returns n < len(p), it may use all of p as scratch space during the call. + * If some data is available but not len(p) bytes, Read conventionally + * returns what is available instead of waiting for more. * - * [testing/fstest.TestFS] may be used to test implementations of an FS for - * correctness. + * When Read encounters an error or end-of-file condition after + * successfully reading n > 0 bytes, it returns the number of + * bytes read. It may return the (non-nil) error from the same call + * or return the error (and n == 0) from a subsequent call. + * An instance of this general case is that a Reader returning + * a non-zero number of bytes at the end of the input stream may + * return either err == EOF or err == nil. The next Read should + * return 0, EOF. + * + * Callers should always process the n > 0 bytes returned before + * considering the error err. Doing so correctly handles I/O errors + * that happen after reading some bytes and also both of the + * allowed EOF behaviors. + * + * If len(p) == 0, Read should always return n == 0. It may return a + * non-nil error if some error condition is known, such as EOF. + * + * Implementations of Read are discouraged from returning a + * zero byte count with a nil error, except when len(p) == 0. + * Callers should treat a return of 0 and nil as indicating that + * nothing happened; in particular it does not indicate EOF. + * + * Implementations must not retain p. */ - interface FS { + interface Reader { [key:string]: any; - /** - * Open opens the named file. - * [File.Close] must be called to release any associated resources. - * - * When Open returns an error, it should be of type *PathError - * with the Op field set to "open", the Path field set to name, - * and the Err field describing the problem. - * - * Open should reject attempts to open names that do not satisfy - * ValidPath(name), returning a *PathError with Err set to - * ErrInvalid or ErrNotExist. - */ - open(name: string): File + read(p: string|Array): number } /** - * A File provides access to a single file. - * The File interface is the minimum implementation required of the file. - * Directory files should also implement [ReadDirFile]. - * A file may implement [io.ReaderAt] or [io.Seeker] as optimizations. + * Writer is the interface that wraps the basic Write method. + * + * Write writes len(p) bytes from p to the underlying data stream. + * It returns the number of bytes written from p (0 <= n <= len(p)) + * and any error encountered that caused the write to stop early. + * Write must return a non-nil error if it returns n < len(p). + * Write must not modify the slice data, even temporarily. + * + * Implementations must not retain p. */ - interface File { + interface Writer { [key:string]: any; - stat(): FileInfo - read(_arg0: string|Array): number - close(): void + write(p: string|Array): number } /** - * A DirEntry is an entry read from a directory - * (using the [ReadDir] function or a [ReadDirFile]'s ReadDir method). + * ReadCloser is the interface that groups the basic Read and Close methods. */ - interface DirEntry { + interface ReadCloser { [key:string]: any; - /** - * Name returns the name of the file (or subdirectory) described by the entry. - * This name is only the final element of the path (the base name), not the entire path. - * For example, Name would return "hello.go" not "home/gopher/hello.go". - */ - name(): string - /** - * IsDir reports whether the entry describes a directory. - */ - isDir(): boolean - /** - * Type returns the type bits for the entry. - * The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. - */ - type(): FileMode - /** - * Info returns the FileInfo for the file or subdirectory described by the entry. - * The returned FileInfo may be from the time of the original directory read - * or from the time of the call to Info. If the file has been removed or renamed - * since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). - * If the entry denotes a symbolic link, Info reports the information about the link itself, - * not the link's target. - */ - info(): FileInfo } /** - * A FileInfo describes a file and is returned by [Stat]. + * ReadSeekCloser is the interface that groups the basic Read, Seek and Close + * methods. */ - interface FileInfo { + interface ReadSeekCloser { [key:string]: any; - name(): string // base name of the file - size(): number // length in bytes for regular files; system-dependent for others - mode(): FileMode // file mode bits - modTime(): time.Time // modification time - isDir(): boolean // abbreviation for Mode().IsDir() - sys(): any // underlying data source (can return nil) } +} + +/** + * Package syntax parses regular expressions into parse trees and compiles + * parse trees into programs. Most clients of regular expressions will use the + * facilities of package [regexp] (such as [regexp.Compile] and [regexp.Match]) instead of this package. + * + * # Syntax + * + * The regular expression syntax understood by this package when parsing with the [Perl] flag is as follows. + * Parts of the syntax can be disabled by passing alternate flags to [Parse]. + * + * Single characters: + * + * ``` + * . any character, possibly including newline (flag s=true) + * [xyz] character class + * [^xyz] negated character class + * \d Perl character class + * \D negated Perl character class + * [[:alpha:]] ASCII character class + * [[:^alpha:]] negated ASCII character class + * \pN Unicode character class (one-letter name) + * \p{Greek} Unicode character class + * \PN negated Unicode character class (one-letter name) + * \P{Greek} negated Unicode character class + * ``` + * + * Composites: + * + * ``` + * xy x followed by y + * x|y x or y (prefer x) + * ``` + * + * Repetitions: + * + * ``` + * x* zero or more x, prefer more + * x+ one or more x, prefer more + * x? zero or one x, prefer one + * x{n,m} n or n+1 or ... or m x, prefer more + * x{n,} n or more x, prefer more + * x{n} exactly n x + * x*? zero or more x, prefer fewer + * x+? one or more x, prefer fewer + * x?? zero or one x, prefer zero + * x{n,m}? n or n+1 or ... or m x, prefer fewer + * x{n,}? n or more x, prefer fewer + * x{n}? exactly n x + * ``` + * + * Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n} + * reject forms that create a minimum or maximum repetition count above 1000. + * Unlimited repetitions are not subject to this restriction. + * + * Grouping: + * + * ``` + * (re) numbered capturing group (submatch) + * (?Pre) named & numbered capturing group (submatch) + * (?re) named & numbered capturing group (submatch) + * (?:re) non-capturing group + * (?flags) set flags within current group; non-capturing + * (?flags:re) set flags during re; non-capturing + * + * Flag syntax is xyz (set) or -xyz (clear) or xy-z (set xy, clear z). The flags are: + * + * i case-insensitive (default false) + * m multi-line mode: ^ and $ match begin/end line in addition to begin/end text (default false) + * s let . match \n (default false) + * U ungreedy: swap meaning of x* and x*?, x+ and x+?, etc (default false) + * ``` + * + * Empty strings: + * + * ``` + * ^ at beginning of text or line (flag m=true) + * $ at end of text (like \z not \Z) or line (flag m=true) + * \A at beginning of text + * \b at ASCII word boundary (\w on one side and \W, \A, or \z on the other) + * \B not at ASCII word boundary + * \z at end of text + * ``` + * + * Escape sequences: + * + * ``` + * \a bell (== \007) + * \f form feed (== \014) + * \t horizontal tab (== \011) + * \n newline (== \012) + * \r carriage return (== \015) + * \v vertical tab character (== \013) + * \* literal *, for any punctuation character * + * \123 octal character code (up to three digits) + * \x7F hex character code (exactly two digits) + * \x{10FFFF} hex character code + * \Q...\E literal text ... even if ... has punctuation + * ``` + * + * Character class elements: + * + * ``` + * x single character + * A-Z character range (inclusive) + * \d Perl character class + * [:foo:] ASCII character class foo + * \p{Foo} Unicode character class Foo + * \pF Unicode character class F (one-letter name) + * ``` + * + * Named character classes as character class elements: + * + * ``` + * [\d] digits (== \d) + * [^\d] not digits (== \D) + * [\D] not digits (== \D) + * [^\D] not not digits (== \d) + * [[:name:]] named ASCII class inside character class (== [:name:]) + * [^[:name:]] named ASCII class inside negated character class (== [:^name:]) + * [\p{Name}] named Unicode property inside character class (== \p{Name}) + * [^\p{Name}] named Unicode property inside negated character class (== \P{Name}) + * ``` + * + * Perl character classes (all ASCII-only): + * + * ``` + * \d digits (== [0-9]) + * \D not digits (== [^0-9]) + * \s whitespace (== [\t\n\f\r ]) + * \S not whitespace (== [^\t\n\f\r ]) + * \w word characters (== [0-9A-Za-z_]) + * \W not word characters (== [^0-9A-Za-z_]) + * ``` + * + * ASCII character classes: + * + * ``` + * [[:alnum:]] alphanumeric (== [0-9A-Za-z]) + * [[:alpha:]] alphabetic (== [A-Za-z]) + * [[:ascii:]] ASCII (== [\x00-\x7F]) + * [[:blank:]] blank (== [\t ]) + * [[:cntrl:]] control (== [\x00-\x1F\x7F]) + * [[:digit:]] digits (== [0-9]) + * [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]) + * [[:lower:]] lower case (== [a-z]) + * [[:print:]] printable (== [ -~] == [ [:graph:]]) + * [[:punct:]] punctuation (== [!-/:-@[-`{-~]) + * [[:space:]] whitespace (== [\t\n\v\f\r ]) + * [[:upper:]] upper case (== [A-Z]) + * [[:word:]] word characters (== [0-9A-Za-z_]) + * [[:xdigit:]] hex digit (== [0-9A-Fa-f]) + * ``` + * + * Unicode character classes are those in [unicode.Categories], + * [unicode.CategoryAliases], and [unicode.Scripts]. + */ +namespace syntax { /** - * A FileMode represents a file's mode and permission bits. - * The bits have the same definition on all systems, so that - * information about files can be moved from one system - * to another portably. Not all bits apply to all systems. - * The only required bit is [ModeDir] for directories. + * Flags control the behavior of the parser and record information about regexp context. */ - interface FileMode extends Number{} - interface FileMode { - string(): string + interface Flags extends Number{} +} + +/** + * Package bytes implements functions for the manipulation of byte slices. + * It is analogous to the facilities of the [strings] package. + */ +namespace bytes { + /** + * A Reader implements the [io.Reader], [io.ReaderAt], [io.WriterTo], [io.Seeker], + * [io.ByteScanner], and [io.RuneScanner] interfaces by reading from + * a byte slice. + * Unlike a [Buffer], a Reader is read-only and supports seeking. + * The zero value for Reader operates like a Reader of an empty slice. + */ + interface Reader { } - interface FileMode { + interface Reader { /** - * IsDir reports whether m describes a directory. - * That is, it tests for the [ModeDir] bit being set in m. + * Len returns the number of bytes of the unread portion of the + * slice. */ - isDir(): boolean + len(): number } - interface FileMode { + interface Reader { /** - * IsRegular reports whether m describes a regular file. - * That is, it tests that no mode type bits are set. + * Size returns the original length of the underlying byte slice. + * Size is the number of bytes available for reading via [Reader.ReadAt]. + * The result is unaffected by any method calls except [Reader.Reset]. */ - isRegular(): boolean + size(): number } - interface FileMode { + interface Reader { /** - * Perm returns the Unix permission bits in m (m & [ModePerm]). + * Read implements the [io.Reader] interface. */ - perm(): FileMode + read(b: string|Array): number } - interface FileMode { + interface Reader { /** - * Type returns type bits in m (m & [ModeType]). + * ReadAt implements the [io.ReaderAt] interface. */ - type(): FileMode + readAt(b: string|Array, off: number): number + } + interface Reader { + /** + * ReadByte implements the [io.ByteReader] interface. + */ + readByte(): number + } + interface Reader { + /** + * UnreadByte complements [Reader.ReadByte] in implementing the [io.ByteScanner] interface. + */ + unreadByte(): void + } + interface Reader { + /** + * ReadRune implements the [io.RuneReader] interface. + */ + readRune(): [number, number] + } + interface Reader { + /** + * UnreadRune complements [Reader.ReadRune] in implementing the [io.RuneScanner] interface. + */ + unreadRune(): void + } + interface Reader { + /** + * Seek implements the [io.Seeker] interface. + */ + seek(offset: number, whence: number): number + } + interface Reader { + /** + * WriteTo implements the [io.WriterTo] interface. + */ + writeTo(w: io.Writer): number + } + interface Reader { + /** + * Reset resets the [Reader] to be reading from b. + */ + reset(b: string|Array): void + } +} + +/** + * Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer + * object, creating another object (Reader or Writer) that also implements + * the interface but provides buffering and some help for textual I/O. + */ +namespace bufio { + /** + * ReadWriter stores pointers to a [Reader] and a [Writer]. + * It implements [io.ReadWriter]. + */ + type _sfGVtsc = Reader&Writer + interface ReadWriter extends _sfGVtsc { + } +} + +/** + * Package fs defines basic interfaces to a file system. + * A file system can be provided by the host operating system + * but also by other packages. + * + * See the [testing/fstest] package for support with testing + * implementations of file systems. + */ +namespace fs { + /** + * An FS provides access to a hierarchical file system. + * + * The FS interface is the minimum implementation required of the file system. + * A file system may implement additional interfaces, + * such as [ReadFileFS], to provide additional or optimized functionality. + * + * [testing/fstest.TestFS] may be used to test implementations of an FS for + * correctness. + */ + interface FS { + [key:string]: any; + /** + * Open opens the named file. + * [File.Close] must be called to release any associated resources. + * + * When Open returns an error, it should be of type *PathError + * with the Op field set to "open", the Path field set to name, + * and the Err field describing the problem. + * + * Open should reject attempts to open names that do not satisfy + * ValidPath(name), returning a *PathError with Err set to + * ErrInvalid or ErrNotExist. + */ + open(name: string): File + } + /** + * A File provides access to a single file. + * The File interface is the minimum implementation required of the file. + * Directory files should also implement [ReadDirFile]. + * A file may implement [io.ReaderAt] or [io.Seeker] as optimizations. + */ + interface File { + [key:string]: any; + stat(): FileInfo + read(_arg0: string|Array): number + close(): void + } + /** + * A DirEntry is an entry read from a directory + * (using the [ReadDir] function or a [ReadDirFile]'s ReadDir method). + */ + interface DirEntry { + [key:string]: any; + /** + * Name returns the name of the file (or subdirectory) described by the entry. + * This name is only the final element of the path (the base name), not the entire path. + * For example, Name would return "hello.go" not "home/gopher/hello.go". + */ + name(): string + /** + * IsDir reports whether the entry describes a directory. + */ + isDir(): boolean + /** + * Type returns the type bits for the entry. + * The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. + */ + type(): FileMode + /** + * Info returns the FileInfo for the file or subdirectory described by the entry. + * The returned FileInfo may be from the time of the original directory read + * or from the time of the call to Info. If the file has been removed or renamed + * since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). + * If the entry denotes a symbolic link, Info reports the information about the link itself, + * not the link's target. + */ + info(): FileInfo + } + /** + * A FileInfo describes a file and is returned by [Stat]. + */ + interface FileInfo { + [key:string]: any; + name(): string // base name of the file + size(): number // length in bytes for regular files; system-dependent for others + mode(): FileMode // file mode bits + modTime(): time.Time // modification time + isDir(): boolean // abbreviation for Mode().IsDir() + sys(): any // underlying data source (can return nil) + } + /** + * A FileMode represents a file's mode and permission bits. + * The bits have the same definition on all systems, so that + * information about files can be moved from one system + * to another portably. Not all bits apply to all systems. + * The only required bit is [ModeDir] for directories. + */ + interface FileMode extends Number{} + interface FileMode { + string(): string + } + interface FileMode { + /** + * IsDir reports whether m describes a directory. + * That is, it tests for the [ModeDir] bit being set in m. + */ + isDir(): boolean + } + interface FileMode { + /** + * IsRegular reports whether m describes a regular file. + * That is, it tests that no mode type bits are set. + */ + isRegular(): boolean + } + interface FileMode { + /** + * Perm returns the Unix permission bits in m (m & [ModePerm]). + */ + perm(): FileMode + } + interface FileMode { + /** + * Type returns type bits in m (m & [ModeType]). + */ + type(): FileMode } /** * PathError records an error and the operation and file path that caused it. @@ -16414,585 +16613,297 @@ namespace fs { interface WalkDirFunc {(path: string, d: DirEntry, err: Error): void } } -namespace store { +/** + * Package context defines the Context type, which carries deadlines, + * cancellation signals, and other request-scoped values across API boundaries + * and between processes. + * + * Incoming requests to a server should create a [Context], and outgoing + * calls to servers should accept a Context. The chain of function + * calls between them must propagate the Context, optionally replacing + * it with a derived Context created using [WithCancel], [WithDeadline], + * [WithTimeout], or [WithValue]. + * + * A Context may be canceled to indicate that work done on its behalf should stop. + * A Context with a deadline is canceled after the deadline passes. + * When a Context is canceled, all Contexts derived from it are also canceled. + * + * The [WithCancel], [WithDeadline], and [WithTimeout] functions take a + * Context (the parent) and return a derived Context (the child) and a + * [CancelFunc]. Calling the CancelFunc directly cancels the child and its + * children, removes the parent's reference to the child, and stops + * any associated timers. Failing to call the CancelFunc leaks the + * child and its children until the parent is canceled. The go vet tool + * checks that CancelFuncs are used on all control-flow paths. + * + * The [WithCancelCause], [WithDeadlineCause], and [WithTimeoutCause] functions + * return a [CancelCauseFunc], which takes an error and records it as + * the cancellation cause. Calling [Cause] on the canceled context + * or any of its children retrieves the cause. If no cause is specified, + * Cause(ctx) returns the same value as ctx.Err(). + * + * Programs that use Contexts should follow these rules to keep interfaces + * consistent across packages and enable static analysis tools to check context + * propagation: + * + * Do not store Contexts inside a struct type; instead, pass a Context + * explicitly to each function that needs it. This is discussed further in + * https://go.dev/blog/context-and-structs. The Context should be the first + * parameter, typically named ctx: + * + * ``` + * func DoSomething(ctx context.Context, arg Arg) error { + * // ... use ctx ... + * } + * ``` + * + * Do not pass a nil [Context], even if a function permits it. Pass [context.TODO] + * if you are unsure about which Context to use. + * + * Use context Values only for request-scoped data that transits processes and + * APIs, not for passing optional parameters to functions. + * + * The same Context may be passed to functions running in different goroutines; + * Contexts are safe for simultaneous use by multiple goroutines. + * + * See https://go.dev/blog/context for example code for a server that uses + * Contexts. + */ +namespace context { /** - * Store defines a concurrent safe in memory key-value data store. + * A Context carries a deadline, a cancellation signal, and other values across + * API boundaries. + * + * Context's methods may be called by multiple goroutines simultaneously. */ - interface Store { - } - interface Store { + interface Context { + [key:string]: any; /** - * Reset clears the store and replaces the store data with a - * shallow copy of the provided newData. - */ - reset(newData: _TygojaDict): void - } - interface Store { - /** - * Length returns the current number of elements in the store. - */ - length(): number - } - interface Store { - /** - * RemoveAll removes all the existing store entries. + * Deadline returns the time when work done on behalf of this context + * should be canceled. Deadline returns ok==false when no deadline is + * set. Successive calls to Deadline return the same results. */ - removeAll(): void - } - interface Store { + deadline(): [time.Time, boolean] /** - * Remove removes a single entry from the store. + * Done returns a channel that's closed when work done on behalf of this + * context should be canceled. Done may return nil if this context can + * never be canceled. Successive calls to Done return the same value. + * The close of the Done channel may happen asynchronously, + * after the cancel function returns. * - * Remove does nothing if key doesn't exist in the store. - */ - remove(key: K): void - } - interface Store { - /** - * Has checks if element with the specified key exist or not. - */ - has(key: K): boolean - } - interface Store { - /** - * Get returns a single element value from the store. + * WithCancel arranges for Done to be closed when cancel is called; + * WithDeadline arranges for Done to be closed when the deadline + * expires; WithTimeout arranges for Done to be closed when the timeout + * elapses. * - * If key is not set, the zero T value is returned. - */ - get(key: K): T - } - interface Store { - /** - * GetOk is similar to Get but returns also a boolean indicating whether the key exists or not. - */ - getOk(key: K): [T, boolean] - } - interface Store { - /** - * GetAll returns a shallow copy of the current store data. - */ - getAll(): _TygojaDict - } - interface Store { - /** - * Values returns a slice with all of the current store values. + * Done is provided for use in select statements: + * + * // Stream generates values with DoSomething and sends them to out + * // until DoSomething returns an error or ctx.Done is closed. + * func Stream(ctx context.Context, out chan<- Value) error { + * for { + * v, err := DoSomething(ctx) + * if err != nil { + * return err + * } + * select { + * case <-ctx.Done(): + * return ctx.Err() + * case out <- v: + * } + * } + * } + * + * See https://blog.golang.org/pipelines for more examples of how to use + * a Done channel for cancellation. */ - values(): Array - } - interface Store { + done(): undefined /** - * Set sets (or overwrite if already exists) a new value for key. + * If Done is not yet closed, Err returns nil. + * If Done is closed, Err returns a non-nil error explaining why: + * DeadlineExceeded if the context's deadline passed, + * or Canceled if the context was canceled for some other reason. + * After Err returns a non-nil error, successive calls to Err return the same error. */ - set(key: K, value: T): void - } - interface Store { + err(): void /** - * SetFunc sets (or overwrite if already exists) a new value resolved - * from the function callback for the provided key. + * Value returns the value associated with this context for key, or nil + * if no value is associated with key. Successive calls to Value with + * the same key returns the same result. * - * The function callback receives as argument the old store element value (if exists). - * If there is no old store element, the argument will be the T zero value. + * Use context values only for request-scoped data that transits + * processes and API boundaries, not for passing optional parameters to + * functions. * - * Example: + * A key identifies a specific value in a Context. Functions that wish + * to store values in Context typically allocate a key in a global + * variable then use that key as the argument to context.WithValue and + * Context.Value. A key can be any type that supports equality; + * packages should define keys as an unexported type to avoid + * collisions. + * + * Packages that define a Context key should provide type-safe accessors + * for the values stored using that key: * * ``` - * s := store.New[string, int](nil) - * s.SetFunc("count", func(old int) int { - * return old + 1 - * }) - * ``` - */ - setFunc(key: K, fn: (old: T) => T): void - } - interface Store { - /** - * GetOrSet retrieves a single existing value for the provided key - * or stores a new one if it doesn't exist. - */ - getOrSet(key: K, setFunc: () => T): T - } - interface Store { - /** - * SetIfLessThanLimit sets (or overwrite if already exist) a new value for key. + * // Package user defines a User type that's stored in Contexts. + * package user * - * This method is similar to Set() but **it will skip adding new elements** - * to the store if the store length has reached the specified limit. - * false is returned if maxAllowedElements limit is reached. - */ - setIfLessThanLimit(key: K, value: T, maxAllowedElements: number): boolean - } - interface Store { - /** - * UnmarshalJSON implements [json.Unmarshaler] and imports the - * provided JSON data into the store. + * import "context" * - * The store entries that match with the ones from the data will be overwritten with the new value. - */ - unmarshalJSON(data: string|Array): void - } - interface Store { - /** - * MarshalJSON implements [json.Marshaler] and export the current - * store data into valid JSON. + * // User is the type of value stored in the Contexts. + * type User struct {...} + * + * // key is an unexported type for keys defined in this package. + * // This prevents collisions with keys defined in other packages. + * type key int + * + * // userKey is the key for user.User values in Contexts. It is + * // unexported; clients use user.NewContext and user.FromContext + * // instead of using this key directly. + * var userKey key + * + * // NewContext returns a new Context that carries value u. + * func NewContext(ctx context.Context, u *User) context.Context { + * return context.WithValue(ctx, userKey, u) + * } + * + * // FromContext returns the User value stored in ctx, if any. + * func FromContext(ctx context.Context) (*User, bool) { + * u, ok := ctx.Value(userKey).(*User) + * return u, ok + * } + * ``` */ - marshalJSON(): string|Array + value(key: any): any } } /** - * Package syntax parses regular expressions into parse trees and compiles - * parse trees into programs. Most clients of regular expressions will use the - * facilities of package [regexp] (such as [regexp.Compile] and [regexp.Match]) instead of this package. - * - * # Syntax + * Package net provides a portable interface for network I/O, including + * TCP/IP, UDP, domain name resolution, and Unix domain sockets. * - * The regular expression syntax understood by this package when parsing with the [Perl] flag is as follows. - * Parts of the syntax can be disabled by passing alternate flags to [Parse]. + * Although the package provides access to low-level networking + * primitives, most clients will need only the basic interface provided + * by the [Dial], [Listen], and Accept functions and the associated + * [Conn] and [Listener] interfaces. The crypto/tls package uses + * the same interfaces and similar Dial and Listen functions. * - * Single characters: + * The Dial function connects to a server: * * ``` - * . any character, possibly including newline (flag s=true) - * [xyz] character class - * [^xyz] negated character class - * \d Perl character class - * \D negated Perl character class - * [[:alpha:]] ASCII character class - * [[:^alpha:]] negated ASCII character class - * \pN Unicode character class (one-letter name) - * \p{Greek} Unicode character class - * \PN negated Unicode character class (one-letter name) - * \P{Greek} negated Unicode character class + * conn, err := net.Dial("tcp", "golang.org:80") + * if err != nil { + * // handle error + * } + * fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") + * status, err := bufio.NewReader(conn).ReadString('\n') + * // ... * ``` * - * Composites: + * The Listen function creates servers: * * ``` - * xy x followed by y - * x|y x or y (prefer x) + * ln, err := net.Listen("tcp", ":8080") + * if err != nil { + * // handle error + * } + * for { + * conn, err := ln.Accept() + * if err != nil { + * // handle error + * } + * go handleConnection(conn) + * } * ``` * - * Repetitions: - * - * ``` - * x* zero or more x, prefer more - * x+ one or more x, prefer more - * x? zero or one x, prefer one - * x{n,m} n or n+1 or ... or m x, prefer more - * x{n,} n or more x, prefer more - * x{n} exactly n x - * x*? zero or more x, prefer fewer - * x+? one or more x, prefer fewer - * x?? zero or one x, prefer zero - * x{n,m}? n or n+1 or ... or m x, prefer fewer - * x{n,}? n or more x, prefer fewer - * x{n}? exactly n x - * ``` + * # Name Resolution * - * Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n} - * reject forms that create a minimum or maximum repetition count above 1000. - * Unlimited repetitions are not subject to this restriction. + * The method for resolving domain names, whether indirectly with functions like Dial + * or directly with functions like [LookupHost] and [LookupAddr], varies by operating system. * - * Grouping: + * On Unix systems, the resolver has two options for resolving names. + * It can use a pure Go resolver that sends DNS requests directly to the servers + * listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C + * library routines such as getaddrinfo and getnameinfo. * - * ``` - * (re) numbered capturing group (submatch) - * (?Pre) named & numbered capturing group (submatch) - * (?re) named & numbered capturing group (submatch) - * (?:re) non-capturing group - * (?flags) set flags within current group; non-capturing - * (?flags:re) set flags during re; non-capturing - * - * Flag syntax is xyz (set) or -xyz (clear) or xy-z (set xy, clear z). The flags are: - * - * i case-insensitive (default false) - * m multi-line mode: ^ and $ match begin/end line in addition to begin/end text (default false) - * s let . match \n (default false) - * U ungreedy: swap meaning of x* and x*?, x+ and x+?, etc (default false) - * ``` - * - * Empty strings: - * - * ``` - * ^ at beginning of text or line (flag m=true) - * $ at end of text (like \z not \Z) or line (flag m=true) - * \A at beginning of text - * \b at ASCII word boundary (\w on one side and \W, \A, or \z on the other) - * \B not at ASCII word boundary - * \z at end of text - * ``` - * - * Escape sequences: - * - * ``` - * \a bell (== \007) - * \f form feed (== \014) - * \t horizontal tab (== \011) - * \n newline (== \012) - * \r carriage return (== \015) - * \v vertical tab character (== \013) - * \* literal *, for any punctuation character * - * \123 octal character code (up to three digits) - * \x7F hex character code (exactly two digits) - * \x{10FFFF} hex character code - * \Q...\E literal text ... even if ... has punctuation - * ``` - * - * Character class elements: - * - * ``` - * x single character - * A-Z character range (inclusive) - * \d Perl character class - * [:foo:] ASCII character class foo - * \p{Foo} Unicode character class Foo - * \pF Unicode character class F (one-letter name) - * ``` - * - * Named character classes as character class elements: - * - * ``` - * [\d] digits (== \d) - * [^\d] not digits (== \D) - * [\D] not digits (== \D) - * [^\D] not not digits (== \d) - * [[:name:]] named ASCII class inside character class (== [:name:]) - * [^[:name:]] named ASCII class inside negated character class (== [:^name:]) - * [\p{Name}] named Unicode property inside character class (== \p{Name}) - * [^\p{Name}] named Unicode property inside negated character class (== \P{Name}) - * ``` - * - * Perl character classes (all ASCII-only): + * On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS + * request consumes only a goroutine, while a blocked C call consumes an operating system thread. + * When cgo is available, the cgo-based resolver is used instead under a variety of + * conditions: on systems that do not let programs make direct DNS requests (OS X), + * when the LOCALDOMAIN environment variable is present (even if empty), + * when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, + * when the ASR_CONFIG environment variable is non-empty (OpenBSD only), + * when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the + * Go resolver does not implement. * - * ``` - * \d digits (== [0-9]) - * \D not digits (== [^0-9]) - * \s whitespace (== [\t\n\f\r ]) - * \S not whitespace (== [^\t\n\f\r ]) - * \w word characters (== [0-9A-Za-z_]) - * \W not word characters (== [^0-9A-Za-z_]) - * ``` + * On all systems (except Plan 9), when the cgo resolver is being used + * this package applies a concurrent cgo lookup limit to prevent the system + * from running out of system threads. Currently, it is limited to 500 concurrent lookups. * - * ASCII character classes: + * The resolver decision can be overridden by setting the netdns value of the + * GODEBUG environment variable (see package runtime) to go or cgo, as in: * * ``` - * [[:alnum:]] alphanumeric (== [0-9A-Za-z]) - * [[:alpha:]] alphabetic (== [A-Za-z]) - * [[:ascii:]] ASCII (== [\x00-\x7F]) - * [[:blank:]] blank (== [\t ]) - * [[:cntrl:]] control (== [\x00-\x1F\x7F]) - * [[:digit:]] digits (== [0-9]) - * [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]) - * [[:lower:]] lower case (== [a-z]) - * [[:print:]] printable (== [ -~] == [ [:graph:]]) - * [[:punct:]] punctuation (== [!-/:-@[-`{-~]) - * [[:space:]] whitespace (== [\t\n\v\f\r ]) - * [[:upper:]] upper case (== [A-Z]) - * [[:word:]] word characters (== [0-9A-Za-z_]) - * [[:xdigit:]] hex digit (== [0-9A-Fa-f]) + * export GODEBUG=netdns=go # force pure Go resolver + * export GODEBUG=netdns=cgo # force native resolver (cgo, win32) * ``` * - * Unicode character classes are those in [unicode.Categories], - * [unicode.CategoryAliases], and [unicode.Scripts]. - */ -namespace syntax { - /** - * Flags control the behavior of the parser and record information about regexp context. - */ - interface Flags extends Number{} -} - -/** - * Package context defines the Context type, which carries deadlines, - * cancellation signals, and other request-scoped values across API boundaries - * and between processes. - * - * Incoming requests to a server should create a [Context], and outgoing - * calls to servers should accept a Context. The chain of function - * calls between them must propagate the Context, optionally replacing - * it with a derived Context created using [WithCancel], [WithDeadline], - * [WithTimeout], or [WithValue]. - * - * A Context may be canceled to indicate that work done on its behalf should stop. - * A Context with a deadline is canceled after the deadline passes. - * When a Context is canceled, all Contexts derived from it are also canceled. - * - * The [WithCancel], [WithDeadline], and [WithTimeout] functions take a - * Context (the parent) and return a derived Context (the child) and a - * [CancelFunc]. Calling the CancelFunc directly cancels the child and its - * children, removes the parent's reference to the child, and stops - * any associated timers. Failing to call the CancelFunc leaks the - * child and its children until the parent is canceled. The go vet tool - * checks that CancelFuncs are used on all control-flow paths. - * - * The [WithCancelCause], [WithDeadlineCause], and [WithTimeoutCause] functions - * return a [CancelCauseFunc], which takes an error and records it as - * the cancellation cause. Calling [Cause] on the canceled context - * or any of its children retrieves the cause. If no cause is specified, - * Cause(ctx) returns the same value as ctx.Err(). - * - * Programs that use Contexts should follow these rules to keep interfaces - * consistent across packages and enable static analysis tools to check context - * propagation: - * - * Do not store Contexts inside a struct type; instead, pass a Context - * explicitly to each function that needs it. This is discussed further in - * https://go.dev/blog/context-and-structs. The Context should be the first - * parameter, typically named ctx: + * The decision can also be forced while building the Go source tree + * by setting the netgo or netcgo build tag. + * The netgo build tag disables entirely the use of the native (CGO) resolver, + * meaning the Go resolver is the only one that can be used. + * With the netcgo build tag the native and the pure Go resolver are compiled into the binary, + * but the native (CGO) resolver is preferred over the Go resolver. + * With netcgo, the Go resolver can still be forced at runtime with GODEBUG=netdns=go. * - * ``` - * func DoSomething(ctx context.Context, arg Arg) error { - * // ... use ctx ... - * } - * ``` + * A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver + * to print debugging information about its decisions. + * To force a particular resolver while also printing debugging information, + * join the two settings by a plus sign, as in GODEBUG=netdns=go+1. * - * Do not pass a nil [Context], even if a function permits it. Pass [context.TODO] - * if you are unsure about which Context to use. + * The Go resolver will send an EDNS0 additional header with a DNS request, + * to signal a willingness to accept a larger DNS packet size. + * This can reportedly cause sporadic failures with the DNS server run + * by some modems and routers. Setting GODEBUG=netedns0=0 will disable + * sending the additional header. * - * Use context Values only for request-scoped data that transits processes and - * APIs, not for passing optional parameters to functions. + * On macOS, if Go code that uses the net package is built with + * -buildmode=c-archive, linking the resulting archive into a C program + * requires passing -lresolv when linking the C code. * - * The same Context may be passed to functions running in different goroutines; - * Contexts are safe for simultaneous use by multiple goroutines. + * On Plan 9, the resolver always accesses /net/cs and /net/dns. * - * See https://go.dev/blog/context for example code for a server that uses - * Contexts. + * On Windows, in Go 1.18.x and earlier, the resolver always used C + * library functions, such as GetAddrInfo and DnsQuery. */ -namespace context { +namespace net { /** - * A Context carries a deadline, a cancellation signal, and other values across - * API boundaries. + * Conn is a generic stream-oriented network connection. * - * Context's methods may be called by multiple goroutines simultaneously. + * Multiple goroutines may invoke methods on a Conn simultaneously. */ - interface Context { + interface Conn { [key:string]: any; /** - * Deadline returns the time when work done on behalf of this context - * should be canceled. Deadline returns ok==false when no deadline is - * set. Successive calls to Deadline return the same results. + * Read reads data from the connection. + * Read can be made to time out and return an error after a fixed + * time limit; see SetDeadline and SetReadDeadline. */ - deadline(): [time.Time, boolean] + read(b: string|Array): number /** - * Done returns a channel that's closed when work done on behalf of this - * context should be canceled. Done may return nil if this context can - * never be canceled. Successive calls to Done return the same value. - * The close of the Done channel may happen asynchronously, - * after the cancel function returns. - * - * WithCancel arranges for Done to be closed when cancel is called; - * WithDeadline arranges for Done to be closed when the deadline - * expires; WithTimeout arranges for Done to be closed when the timeout - * elapses. - * - * Done is provided for use in select statements: - * - * // Stream generates values with DoSomething and sends them to out - * // until DoSomething returns an error or ctx.Done is closed. - * func Stream(ctx context.Context, out chan<- Value) error { - * for { - * v, err := DoSomething(ctx) - * if err != nil { - * return err - * } - * select { - * case <-ctx.Done(): - * return ctx.Err() - * case out <- v: - * } - * } - * } - * - * See https://blog.golang.org/pipelines for more examples of how to use - * a Done channel for cancellation. + * Write writes data to the connection. + * Write can be made to time out and return an error after a fixed + * time limit; see SetDeadline and SetWriteDeadline. */ - done(): undefined + write(b: string|Array): number /** - * If Done is not yet closed, Err returns nil. - * If Done is closed, Err returns a non-nil error explaining why: - * DeadlineExceeded if the context's deadline passed, - * or Canceled if the context was canceled for some other reason. - * After Err returns a non-nil error, successive calls to Err return the same error. + * Close closes the connection. + * Any blocked Read or Write operations will be unblocked and return errors. + * Close may or may not block until any buffered data is sent; + * for TCP connections see [*TCPConn.SetLinger]. */ - err(): void - /** - * Value returns the value associated with this context for key, or nil - * if no value is associated with key. Successive calls to Value with - * the same key returns the same result. - * - * Use context values only for request-scoped data that transits - * processes and API boundaries, not for passing optional parameters to - * functions. - * - * A key identifies a specific value in a Context. Functions that wish - * to store values in Context typically allocate a key in a global - * variable then use that key as the argument to context.WithValue and - * Context.Value. A key can be any type that supports equality; - * packages should define keys as an unexported type to avoid - * collisions. - * - * Packages that define a Context key should provide type-safe accessors - * for the values stored using that key: - * - * ``` - * // Package user defines a User type that's stored in Contexts. - * package user - * - * import "context" - * - * // User is the type of value stored in the Contexts. - * type User struct {...} - * - * // key is an unexported type for keys defined in this package. - * // This prevents collisions with keys defined in other packages. - * type key int - * - * // userKey is the key for user.User values in Contexts. It is - * // unexported; clients use user.NewContext and user.FromContext - * // instead of using this key directly. - * var userKey key - * - * // NewContext returns a new Context that carries value u. - * func NewContext(ctx context.Context, u *User) context.Context { - * return context.WithValue(ctx, userKey, u) - * } - * - * // FromContext returns the User value stored in ctx, if any. - * func FromContext(ctx context.Context) (*User, bool) { - * u, ok := ctx.Value(userKey).(*User) - * return u, ok - * } - * ``` - */ - value(key: any): any - } -} - -/** - * Package net provides a portable interface for network I/O, including - * TCP/IP, UDP, domain name resolution, and Unix domain sockets. - * - * Although the package provides access to low-level networking - * primitives, most clients will need only the basic interface provided - * by the [Dial], [Listen], and Accept functions and the associated - * [Conn] and [Listener] interfaces. The crypto/tls package uses - * the same interfaces and similar Dial and Listen functions. - * - * The Dial function connects to a server: - * - * ``` - * conn, err := net.Dial("tcp", "golang.org:80") - * if err != nil { - * // handle error - * } - * fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") - * status, err := bufio.NewReader(conn).ReadString('\n') - * // ... - * ``` - * - * The Listen function creates servers: - * - * ``` - * ln, err := net.Listen("tcp", ":8080") - * if err != nil { - * // handle error - * } - * for { - * conn, err := ln.Accept() - * if err != nil { - * // handle error - * } - * go handleConnection(conn) - * } - * ``` - * - * # Name Resolution - * - * The method for resolving domain names, whether indirectly with functions like Dial - * or directly with functions like [LookupHost] and [LookupAddr], varies by operating system. - * - * On Unix systems, the resolver has two options for resolving names. - * It can use a pure Go resolver that sends DNS requests directly to the servers - * listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C - * library routines such as getaddrinfo and getnameinfo. - * - * On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS - * request consumes only a goroutine, while a blocked C call consumes an operating system thread. - * When cgo is available, the cgo-based resolver is used instead under a variety of - * conditions: on systems that do not let programs make direct DNS requests (OS X), - * when the LOCALDOMAIN environment variable is present (even if empty), - * when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, - * when the ASR_CONFIG environment variable is non-empty (OpenBSD only), - * when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the - * Go resolver does not implement. - * - * On all systems (except Plan 9), when the cgo resolver is being used - * this package applies a concurrent cgo lookup limit to prevent the system - * from running out of system threads. Currently, it is limited to 500 concurrent lookups. - * - * The resolver decision can be overridden by setting the netdns value of the - * GODEBUG environment variable (see package runtime) to go or cgo, as in: - * - * ``` - * export GODEBUG=netdns=go # force pure Go resolver - * export GODEBUG=netdns=cgo # force native resolver (cgo, win32) - * ``` - * - * The decision can also be forced while building the Go source tree - * by setting the netgo or netcgo build tag. - * The netgo build tag disables entirely the use of the native (CGO) resolver, - * meaning the Go resolver is the only one that can be used. - * With the netcgo build tag the native and the pure Go resolver are compiled into the binary, - * but the native (CGO) resolver is preferred over the Go resolver. - * With netcgo, the Go resolver can still be forced at runtime with GODEBUG=netdns=go. - * - * A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver - * to print debugging information about its decisions. - * To force a particular resolver while also printing debugging information, - * join the two settings by a plus sign, as in GODEBUG=netdns=go+1. - * - * The Go resolver will send an EDNS0 additional header with a DNS request, - * to signal a willingness to accept a larger DNS packet size. - * This can reportedly cause sporadic failures with the DNS server run - * by some modems and routers. Setting GODEBUG=netedns0=0 will disable - * sending the additional header. - * - * On macOS, if Go code that uses the net package is built with - * -buildmode=c-archive, linking the resulting archive into a C program - * requires passing -lresolv when linking the C code. - * - * On Plan 9, the resolver always accesses /net/cs and /net/dns. - * - * On Windows, in Go 1.18.x and earlier, the resolver always used C - * library functions, such as GetAddrInfo and DnsQuery. - */ -namespace net { - /** - * Conn is a generic stream-oriented network connection. - * - * Multiple goroutines may invoke methods on a Conn simultaneously. - */ - interface Conn { - [key:string]: any; - /** - * Read reads data from the connection. - * Read can be made to time out and return an error after a fixed - * time limit; see SetDeadline and SetReadDeadline. - */ - read(b: string|Array): number - /** - * Write writes data to the connection. - * Write can be made to time out and return an error after a fixed - * time limit; see SetDeadline and SetWriteDeadline. - */ - write(b: string|Array): number - /** - * Close closes the connection. - * Any blocked Read or Write operations will be unblocked and return errors. - * Close may or may not block until any buffered data is sent; - * for TCP connections see [*TCPConn.SetLinger]. - */ - close(): void + close(): void /** * LocalAddr returns the local network address, if known. */ @@ -17066,1909 +16977,2338 @@ namespace net { } /** - * Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html + * Package multipart implements MIME multipart parsing, as defined in RFC + * 2046. * - * See README.md for more info. + * The implementation is sufficient for HTTP (RFC 2388) and the multipart + * bodies generated by popular browsers. + * + * # Limits + * + * To protect against malicious inputs, this package sets limits on the size + * of the MIME data it processes. + * + * [Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a + * part to 10000 and [Reader.ReadForm] limits the total number of headers in all + * FileHeaders to 10000. + * These limits may be adjusted with the GODEBUG=multipartmaxheaders= + * setting. + * + * Reader.ReadForm further limits the number of parts in a form to 1000. + * This limit may be adjusted with the GODEBUG=multipartmaxparts= + * setting. */ -namespace jwt { +namespace multipart { /** - * MapClaims is a claims type that uses the map[string]any for JSON - * decoding. This is the default claims type if you don't supply one + * A FileHeader describes a file part of a multipart request. */ - interface MapClaims extends _TygojaDict{} - interface MapClaims { - /** - * GetExpirationTime implements the Claims interface. - */ - getExpirationTime(): (NumericDate) - } - interface MapClaims { - /** - * GetNotBefore implements the Claims interface. - */ - getNotBefore(): (NumericDate) - } - interface MapClaims { - /** - * GetIssuedAt implements the Claims interface. - */ - getIssuedAt(): (NumericDate) - } - interface MapClaims { - /** - * GetAudience implements the Claims interface. - */ - getAudience(): ClaimStrings - } - interface MapClaims { - /** - * GetIssuer implements the Claims interface. - */ - getIssuer(): string + interface FileHeader { + filename: string + header: textproto.MIMEHeader + size: number } - interface MapClaims { + interface FileHeader { /** - * GetSubject implements the Claims interface. + * Open opens and returns the [FileHeader]'s associated File. */ - getSubject(): string - } -} - -namespace subscriptions { - /** - * Broker defines a struct for managing subscriptions clients. - */ - interface Broker { - } - interface Broker { - /** - * Clients returns a shallow copy of all registered clients indexed - * with their connection id. - */ - clients(): _TygojaDict - } - interface Broker { - /** - * ChunkedClients splits the current clients into a chunked slice. - */ - chunkedClients(chunkSize: number): Array> - } - interface Broker { - /** - * TotalClients returns the total number of registered clients. - */ - totalClients(): number - } - interface Broker { - /** - * ClientById finds a registered client by its id. - * - * Returns non-nil error when client with clientId is not registered. - */ - clientById(clientId: string): Client - } - interface Broker { - /** - * Register adds a new client to the broker instance. - */ - register(client: Client): void - } - interface Broker { - /** - * Unregister removes a single client by its id and marks it as discarded. - * - * If client with clientId doesn't exist, this method does nothing. - */ - unregister(clientId: string): void - } - /** - * Client is an interface for a generic subscription client. - */ - interface Client { - [key:string]: any; - /** - * Id Returns the unique id of the client. - */ - id(): string - /** - * Channel returns the client's communication channel. - * - * NB! The channel shouldn't be used after calling Discard(). - */ - channel(): undefined - /** - * Subscriptions returns a shallow copy of the client subscriptions matching the prefixes. - * If no prefix is specified, returns all subscriptions. - */ - subscriptions(...prefixes: string[]): _TygojaDict - /** - * Subscribe subscribes the client to the provided subscriptions list. - * - * Each subscription can also have "options" (json serialized SubscriptionOptions) as query parameter. - * - * Example: - * - * ``` - * Subscribe( - * "subscriptionA", - * `subscriptionB?options={"query":{"a":1},"headers":{"x_token":"abc"}}`, - * ) - * ``` - */ - subscribe(...subs: string[]): void - /** - * Unsubscribe unsubscribes the client from the provided subscriptions list. - */ - unsubscribe(...subs: string[]): void - /** - * HasSubscription checks if the client is subscribed to `sub`. - */ - hasSubscription(sub: string): boolean - /** - * Set stores any value to the client's context. - */ - set(key: string, value: any): void - /** - * Unset removes a single value from the client's context. - */ - unset(key: string): void - /** - * Get retrieves the key value from the client's context. - */ - get(key: string): any - /** - * Discard marks the client as "discarded" (and closes its channel), - * meaning that it shouldn't be used anymore for sending new messages. - * - * It is safe to call Discard() multiple times. - */ - discard(): void - /** - * IsDiscarded indicates whether the client has been "discarded" - * and should no longer be used. - */ - isDiscarded(): boolean - /** - * Send sends the specified message to the client's channel (if not discarded). - */ - send(m: Message): void - } - /** - * Message defines a client's channel data. - */ - interface Message { - name: string - data: string|Array - } - interface Message { - /** - * WriteSSE writes the current message in a SSE format into the provided writer. - * - * For example, writing to a router.Event: - * - * ``` - * m := Message{Name: "users/create", Data: []byte{...}} - * m.WriteSSE(e.Response, "yourEventId") - * e.Flush() - * ``` - */ - writeSSE(w: io.Writer, eventId: string): void + open(): File } } /** - * Package slog provides structured logging, - * in which log records include a message, - * a severity level, and various other attributes - * expressed as key-value pairs. + * Package http provides HTTP client and server implementations. * - * It defines a type, [Logger], - * which provides several methods (such as [Logger.Info] and [Logger.Error]) - * for reporting events of interest. + * [Get], [Head], [Post], and [PostForm] make HTTP (or HTTPS) requests: * - * Each Logger is associated with a [Handler]. - * A Logger output method creates a [Record] from the method arguments - * and passes it to the Handler, which decides how to handle it. - * There is a default Logger accessible through top-level functions - * (such as [Info] and [Error]) that call the corresponding Logger methods. + * ``` + * resp, err := http.Get("http://example.com/") + * ... + * resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) + * ... + * resp, err := http.PostForm("http://example.com/form", + * url.Values{"key": {"Value"}, "id": {"123"}}) + * ``` * - * A log record consists of a time, a level, a message, and a set of key-value - * pairs, where the keys are strings and the values may be of any type. - * As an example, + * The caller must close the response body when finished with it: * * ``` - * slog.Info("hello", "count", 3) + * resp, err := http.Get("http://example.com/") + * if err != nil { + * // handle error + * } + * defer resp.Body.Close() + * body, err := io.ReadAll(resp.Body) + * // ... * ``` * - * creates a record containing the time of the call, - * a level of Info, the message "hello", and a single - * pair with key "count" and value 3. - * - * The [Info] top-level function calls the [Logger.Info] method on the default Logger. - * In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. - * Besides these convenience methods for common levels, - * there is also a [Logger.Log] method which takes the level as an argument. - * Each of these methods has a corresponding top-level function that uses the - * default logger. + * # Clients and Transports * - * The default handler formats the log record's message, time, level, and attributes - * as a string and passes it to the [log] package. + * For control over HTTP client headers, redirect policy, and other + * settings, create a [Client]: * * ``` - * 2022/11/08 15:28:26 INFO hello count=3 - * ``` + * client := &http.Client{ + * CheckRedirect: redirectPolicyFunc, + * } * - * For more control over the output format, create a logger with a different handler. - * This statement uses [New] to create a new logger with a [TextHandler] - * that writes structured records in text form to standard error: + * resp, err := client.Get("http://example.com") + * // ... * - * ``` - * logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) + * req, err := http.NewRequest("GET", "http://example.com", nil) + * // ... + * req.Header.Add("If-None-Match", `W/"wyzzy"`) + * resp, err := client.Do(req) + * // ... * ``` * - * [TextHandler] output is a sequence of key=value pairs, easily and unambiguously - * parsed by machine. This statement: + * For control over proxies, TLS configuration, keep-alives, + * compression, and other settings, create a [Transport]: * * ``` - * logger.Info("hello", "count", 3) + * tr := &http.Transport{ + * MaxIdleConns: 10, + * IdleConnTimeout: 30 * time.Second, + * DisableCompression: true, + * } + * client := &http.Client{Transport: tr} + * resp, err := client.Get("https://example.com") * ``` * - * produces this output: + * Clients and Transports are safe for concurrent use by multiple + * goroutines and for efficiency should only be created once and re-used. * - * ``` - * time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 - * ``` + * # Servers * - * The package also provides [JSONHandler], whose output is line-delimited JSON: + * ListenAndServe starts an HTTP server with a given address and handler. + * The handler is usually nil, which means to use [DefaultServeMux]. + * [Handle] and [HandleFunc] add handlers to [DefaultServeMux]: * * ``` - * logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - * logger.Info("hello", "count", 3) + * http.Handle("/foo", fooHandler) + * + * http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { + * fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) + * }) + * + * log.Fatal(http.ListenAndServe(":8080", nil)) * ``` * - * produces this output: + * More control over the server's behavior is available by creating a + * custom Server: * * ``` - * {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} + * s := &http.Server{ + * Addr: ":8080", + * Handler: myHandler, + * ReadTimeout: 10 * time.Second, + * WriteTimeout: 10 * time.Second, + * MaxHeaderBytes: 1 << 20, + * } + * log.Fatal(s.ListenAndServe()) * ``` * - * Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. - * There are options for setting the minimum level (see Levels, below), - * displaying the source file and line of the log call, and - * modifying attributes before they are logged. + * # HTTP/2 * - * Setting a logger as the default with + * Starting with Go 1.6, the http package has transparent support for the + * HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2 + * can do so by setting [Transport.TLSNextProto] (for clients) or + * [Server.TLSNextProto] (for servers) to a non-nil, empty + * map. Alternatively, the following GODEBUG settings are + * currently supported: * * ``` - * slog.SetDefault(logger) + * GODEBUG=http2client=0 # disable HTTP/2 client support + * GODEBUG=http2server=0 # disable HTTP/2 server support + * GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs + * GODEBUG=http2debug=2 # ... even more verbose, with frame dumps * ``` * - * will cause the top-level functions like [Info] to use it. - * [SetDefault] also updates the default logger used by the [log] package, - * so that existing applications that use [log.Printf] and related functions - * will send log records to the logger's handler without needing to be rewritten. + * Please report any issues before disabling HTTP/2 support: https://golang.org/s/http2bug * - * Some attributes are common to many log calls. - * For example, you may wish to include the URL or trace identifier of a server request - * with all log events arising from the request. - * Rather than repeat the attribute with every log call, you can use [Logger.With] - * to construct a new Logger containing the attributes: - * - * ``` - * logger2 := logger.With("url", r.URL) - * ``` - * - * The arguments to With are the same key-value pairs used in [Logger.Info]. - * The result is a new Logger with the same handler as the original, but additional - * attributes that will appear in the output of every call. - * - * # Levels - * - * A [Level] is an integer representing the importance or severity of a log event. - * The higher the level, the more severe the event. - * This package defines constants for the most common levels, - * but any int can be used as a level. - * - * In an application, you may wish to log messages only at a certain level or greater. - * One common configuration is to log messages at Info or higher levels, - * suppressing debug logging until it is needed. - * The built-in handlers can be configured with the minimum level to output by - * setting [HandlerOptions.Level]. - * The program's `main` function typically does this. - * The default value is LevelInfo. - * - * Setting the [HandlerOptions.Level] field to a [Level] value - * fixes the handler's minimum level throughout its lifetime. - * Setting it to a [LevelVar] allows the level to be varied dynamically. - * A LevelVar holds a Level and is safe to read or write from multiple - * goroutines. - * To vary the level dynamically for an entire program, first initialize - * a global LevelVar: - * - * ``` - * var programLevel = new(slog.LevelVar) // Info by default - * ``` - * - * Then use the LevelVar to construct a handler, and make it the default: - * - * ``` - * h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - * slog.SetDefault(slog.New(h)) - * ``` - * - * Now the program can change its logging level with a single statement: - * - * ``` - * programLevel.Set(slog.LevelDebug) - * ``` - * - * # Groups - * - * Attributes can be collected into groups. - * A group has a name that is used to qualify the names of its attributes. - * How this qualification is displayed depends on the handler. - * [TextHandler] separates the group and attribute names with a dot. - * [JSONHandler] treats each group as a separate JSON object, with the group name as the key. - * - * Use [Group] to create a Group attribute from a name and a list of key-value pairs: - * - * ``` - * slog.Group("request", - * "method", r.Method, - * "url", r.URL) - * ``` - * - * TextHandler would display this group as - * - * ``` - * request.method=GET request.url=http://example.com - * ``` - * - * JSONHandler would display it as - * - * ``` - * "request":{"method":"GET","url":"http://example.com"} - * ``` - * - * Use [Logger.WithGroup] to qualify all of a Logger's output - * with a group name. Calling WithGroup on a Logger results in a - * new Logger with the same Handler as the original, but with all - * its attributes qualified by the group name. - * - * This can help prevent duplicate attribute keys in large systems, - * where subsystems might use the same keys. - * Pass each subsystem a different Logger with its own group name so that - * potential duplicates are qualified: - * - * ``` - * logger := slog.Default().With("id", systemID) - * parserLogger := logger.WithGroup("parser") - * parseInput(input, parserLogger) - * ``` - * - * When parseInput logs with parserLogger, its keys will be qualified with "parser", - * so even if it uses the common key "id", the log line will have distinct keys. - * - * # Contexts - * - * Some handlers may wish to include information from the [context.Context] that is - * available at the call site. One example of such information - * is the identifier for the current span when tracing is enabled. - * - * The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first - * argument, as do their corresponding top-level functions. - * - * Although the convenience methods on Logger (Info and so on) and the - * corresponding top-level functions do not take a context, the alternatives ending - * in "Context" do. For example, - * - * ``` - * slog.InfoContext(ctx, "message") - * ``` - * - * It is recommended to pass a context to an output method if one is available. - * - * # Attrs and Values - * - * An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as - * alternating keys and values. The statement - * - * ``` - * slog.Info("hello", slog.Int("count", 3)) - * ``` - * - * behaves the same as - * - * ``` - * slog.Info("hello", "count", 3) - * ``` - * - * There are convenience constructors for [Attr] such as [Int], [String], and [Bool] - * for common types, as well as the function [Any] for constructing Attrs of any - * type. - * - * The value part of an Attr is a type called [Value]. - * Like an [any], a Value can hold any Go value, - * but it can represent typical values, including all numbers and strings, - * without an allocation. - * - * For the most efficient log output, use [Logger.LogAttrs]. - * It is similar to [Logger.Log] but accepts only Attrs, not alternating - * keys and values; this allows it, too, to avoid allocation. - * - * The call - * - * ``` - * logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) - * ``` - * - * is the most efficient way to achieve the same output as - * - * ``` - * slog.InfoContext(ctx, "hello", "count", 3) - * ``` - * - * # Customizing a type's logging behavior - * - * If a type implements the [LogValuer] interface, the [Value] returned from its LogValue - * method is used for logging. You can use this to control how values of the type - * appear in logs. For example, you can redact secret information like passwords, - * or gather a struct's fields in a Group. See the examples under [LogValuer] for - * details. - * - * A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] - * method handles these cases carefully, avoiding infinite loops and unbounded recursion. - * Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. - * - * # Wrapping output methods - * - * The logger functions use reflection over the call stack to find the file name - * and line number of the logging call within the application. This can produce - * incorrect source information for functions that wrap slog. For instance, if you - * define this function in file mylog.go: - * - * ``` - * func Infof(logger *slog.Logger, format string, args ...any) { - * logger.Info(fmt.Sprintf(format, args...)) - * } - * ``` - * - * and you call it like this in main.go: - * - * ``` - * Infof(slog.Default(), "hello, %s", "world") - * ``` - * - * then slog will report the source file as mylog.go, not main.go. - * - * A correct implementation of Infof will obtain the source location - * (pc) and pass it to NewRecord. - * The Infof function in the package-level example called "wrapping" - * demonstrates how to do this. - * - * # Working with Records - * - * Sometimes a Handler will need to modify a Record - * before passing it on to another Handler or backend. - * A Record contains a mixture of simple public fields (e.g. Time, Level, Message) - * and hidden fields that refer to state (such as attributes) indirectly. This - * means that modifying a simple copy of a Record (e.g. by calling - * [Record.Add] or [Record.AddAttrs] to add attributes) - * may have unexpected effects on the original. - * Before modifying a Record, use [Record.Clone] to - * create a copy that shares no state with the original, - * or create a new Record with [NewRecord] - * and build up its Attrs by traversing the old ones with [Record.Attrs]. - * - * # Performance considerations - * - * If profiling your application demonstrates that logging is taking significant time, - * the following suggestions may help. - * - * If many log lines have a common attribute, use [Logger.With] to create a Logger with - * that attribute. The built-in handlers will format that attribute only once, at the - * call to [Logger.With]. The [Handler] interface is designed to allow that optimization, - * and a well-written Handler should take advantage of it. - * - * The arguments to a log call are always evaluated, even if the log event is discarded. - * If possible, defer computation so that it happens only if the value is actually logged. - * For example, consider the call - * - * ``` - * slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily - * ``` - * - * The URL.String method will be called even if the logger discards Info-level events. - * Instead, pass the URL directly: - * - * ``` - * slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed - * ``` - * - * The built-in [TextHandler] will call its String method, but only - * if the log event is enabled. - * Avoiding the call to String also preserves the structure of the underlying value. - * For example [JSONHandler] emits the components of the parsed URL as a JSON object. - * If you want to avoid eagerly paying the cost of the String call - * without causing the handler to potentially inspect the structure of the value, - * wrap the value in a fmt.Stringer implementation that hides its Marshal methods. - * - * You can also use the [LogValuer] interface to avoid unnecessary work in disabled log - * calls. Say you need to log some expensive value: - * - * ``` - * slog.Debug("frobbing", "value", computeExpensiveValue(arg)) - * ``` - * - * Even if this line is disabled, computeExpensiveValue will be called. - * To avoid that, define a type implementing LogValuer: - * - * ``` - * type expensive struct { arg int } - * - * func (e expensive) LogValue() slog.Value { - * return slog.AnyValue(computeExpensiveValue(e.arg)) - * } - * ``` - * - * Then use a value of that type in log calls: - * - * ``` - * slog.Debug("frobbing", "value", expensive{arg}) - * ``` - * - * Now computeExpensiveValue will only be called when the line is enabled. + * The http package's [Transport] and [Server] both automatically enable + * HTTP/2 support for simple configurations. To enable HTTP/2 for more + * complex configurations, to use lower-level HTTP/2 features, or to use + * a newer version of Go's http2 package, import "golang.org/x/net/http2" + * directly and use its ConfigureTransport and/or ConfigureServer + * functions. Manually configuring HTTP/2 via the golang.org/x/net/http2 + * package takes precedence over the net/http package's built-in HTTP/2 + * support. + */ +namespace http { + // @ts-ignore + import mathrand = rand + /** + * PushOptions describes options for [Pusher.Push]. + */ + interface PushOptions { + /** + * Method specifies the HTTP method for the promised request. + * If set, it must be "GET" or "HEAD". Empty means "GET". + */ + method: string + /** + * Header specifies additional promised request headers. This cannot + * include HTTP/2 pseudo header fields like ":path" and ":scheme", + * which will be added automatically. + */ + header: Header + } + // @ts-ignore + import urlpkg = url + /** + * A Request represents an HTTP request received by a server + * or to be sent by a client. + * + * The field semantics differ slightly between client and server + * usage. In addition to the notes on the fields below, see the + * documentation for [Request.Write] and [RoundTripper]. + */ + interface Request { + /** + * Method specifies the HTTP method (GET, POST, PUT, etc.). + * For client requests, an empty string means GET. + */ + method: string + /** + * URL specifies either the URI being requested (for server + * requests) or the URL to access (for client requests). + * + * For server requests, the URL is parsed from the URI + * supplied on the Request-Line as stored in RequestURI. For + * most requests, fields other than Path and RawQuery will be + * empty. (See RFC 7230, Section 5.3) + * + * For client requests, the URL's Host specifies the server to + * connect to, while the Request's Host field optionally + * specifies the Host header value to send in the HTTP + * request. + */ + url?: url.URL + /** + * The protocol version for incoming server requests. + * + * For client requests, these fields are ignored. The HTTP + * client code always uses either HTTP/1.1 or HTTP/2. + * See the docs on Transport for details. + */ + proto: string // "HTTP/1.0" + protoMajor: number // 1 + protoMinor: number // 0 + /** + * Header contains the request header fields either received + * by the server or to be sent by the client. + * + * If a server received a request with header lines, + * + * ``` + * Host: example.com + * accept-encoding: gzip, deflate + * Accept-Language: en-us + * fOO: Bar + * foo: two + * ``` + * + * then + * + * ``` + * Header = map[string][]string{ + * "Accept-Encoding": {"gzip, deflate"}, + * "Accept-Language": {"en-us"}, + * "Foo": {"Bar", "two"}, + * } + * ``` + * + * For incoming requests, the Host header is promoted to the + * Request.Host field and removed from the Header map. + * + * HTTP defines that header names are case-insensitive. The + * request parser implements this by using CanonicalHeaderKey, + * making the first character and any characters following a + * hyphen uppercase and the rest lowercase. + * + * For client requests, certain headers such as Content-Length + * and Connection are automatically written when needed and + * values in Header may be ignored. See the documentation + * for the Request.Write method. + */ + header: Header + /** + * Body is the request's body. + * + * For client requests, a nil body means the request has no + * body, such as a GET request. The HTTP Client's Transport + * is responsible for calling the Close method. + * + * For server requests, the Request Body is always non-nil + * but will return EOF immediately when no body is present. + * The Server will close the request body. The ServeHTTP + * Handler does not need to. + * + * Body must allow Read to be called concurrently with Close. + * In particular, calling Close should unblock a Read waiting + * for input. + */ + body: io.ReadCloser + /** + * GetBody defines an optional func to return a new copy of + * Body. It is used for client requests when a redirect requires + * reading the body more than once. Use of GetBody still + * requires setting Body. + * + * For server requests, it is unused. + */ + getBody: () => io.ReadCloser + /** + * ContentLength records the length of the associated content. + * The value -1 indicates that the length is unknown. + * Values >= 0 indicate that the given number of bytes may + * be read from Body. + * + * For client requests, a value of 0 with a non-nil Body is + * also treated as unknown. + */ + contentLength: number + /** + * TransferEncoding lists the transfer encodings from outermost to + * innermost. An empty list denotes the "identity" encoding. + * TransferEncoding can usually be ignored; chunked encoding is + * automatically added and removed as necessary when sending and + * receiving requests. + */ + transferEncoding: Array + /** + * Close indicates whether to close the connection after + * replying to this request (for servers) or after sending this + * request and reading its response (for clients). + * + * For server requests, the HTTP server handles this automatically + * and this field is not needed by Handlers. + * + * For client requests, setting this field prevents re-use of + * TCP connections between requests to the same hosts, as if + * Transport.DisableKeepAlives were set. + */ + close: boolean + /** + * For server requests, Host specifies the host on which the + * URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this + * is either the value of the "Host" header or the host name + * given in the URL itself. For HTTP/2, it is the value of the + * ":authority" pseudo-header field. + * It may be of the form "host:port". For international domain + * names, Host may be in Punycode or Unicode form. Use + * golang.org/x/net/idna to convert it to either format if + * needed. + * To prevent DNS rebinding attacks, server Handlers should + * validate that the Host header has a value for which the + * Handler considers itself authoritative. The included + * ServeMux supports patterns registered to particular host + * names and thus protects its registered Handlers. + * + * For client requests, Host optionally overrides the Host + * header to send. If empty, the Request.Write method uses + * the value of URL.Host. Host may contain an international + * domain name. + */ + host: string + /** + * Form contains the parsed form data, including both the URL + * field's query parameters and the PATCH, POST, or PUT form data. + * This field is only available after ParseForm is called. + * The HTTP client ignores Form and uses Body instead. + */ + form: url.Values + /** + * PostForm contains the parsed form data from PATCH, POST + * or PUT body parameters. + * + * This field is only available after ParseForm is called. + * The HTTP client ignores PostForm and uses Body instead. + */ + postForm: url.Values + /** + * MultipartForm is the parsed multipart form, including file uploads. + * This field is only available after ParseMultipartForm is called. + * The HTTP client ignores MultipartForm and uses Body instead. + */ + multipartForm?: multipart.Form + /** + * Trailer specifies additional headers that are sent after the request + * body. + * + * For server requests, the Trailer map initially contains only the + * trailer keys, with nil values. (The client declares which trailers it + * will later send.) While the handler is reading from Body, it must + * not reference Trailer. After reading from Body returns EOF, Trailer + * can be read again and will contain non-nil values, if they were sent + * by the client. + * + * For client requests, Trailer must be initialized to a map containing + * the trailer keys to later send. The values may be nil or their final + * values. The ContentLength must be 0 or -1, to send a chunked request. + * After the HTTP request is sent the map values can be updated while + * the request body is read. Once the body returns EOF, the caller must + * not mutate Trailer. + * + * Few HTTP clients, servers, or proxies support HTTP trailers. + */ + trailer: Header + /** + * RemoteAddr allows HTTP servers and other software to record + * the network address that sent the request, usually for + * logging. This field is not filled in by ReadRequest and + * has no defined format. The HTTP server in this package + * sets RemoteAddr to an "IP:port" address before invoking a + * handler. + * This field is ignored by the HTTP client. + */ + remoteAddr: string + /** + * RequestURI is the unmodified request-target of the + * Request-Line (RFC 7230, Section 3.1.1) as sent by the client + * to a server. Usually the URL field should be used instead. + * It is an error to set this field in an HTTP client request. + */ + requestURI: string + /** + * TLS allows HTTP servers and other software to record + * information about the TLS connection on which the request + * was received. This field is not filled in by ReadRequest. + * The HTTP server in this package sets the field for + * TLS-enabled connections before invoking a handler; + * otherwise it leaves the field nil. + * This field is ignored by the HTTP client. + */ + tls?: any + /** + * Cancel is an optional channel whose closure indicates that the client + * request should be regarded as canceled. Not all implementations of + * RoundTripper may support Cancel. + * + * For server requests, this field is not applicable. + * + * Deprecated: Set the Request's context with NewRequestWithContext + * instead. If a Request's Cancel field and context are both + * set, it is undefined whether Cancel is respected. + */ + cancel: undefined + /** + * Response is the redirect response which caused this request + * to be created. This field is only populated during client + * redirects. + */ + response?: Response + /** + * Pattern is the [ServeMux] pattern that matched the request. + * It is empty if the request was not matched against a pattern. + */ + pattern: string + } + interface Request { + /** + * Context returns the request's context. To change the context, use + * [Request.Clone] or [Request.WithContext]. + * + * The returned context is always non-nil; it defaults to the + * background context. + * + * For outgoing client requests, the context controls cancellation. + * + * For incoming server requests, the context is canceled when the + * client's connection closes, the request is canceled (with HTTP/2), + * or when the ServeHTTP method returns. + */ + context(): context.Context + } + interface Request { + /** + * WithContext returns a shallow copy of r with its context changed + * to ctx. The provided ctx must be non-nil. + * + * For outgoing client request, the context controls the entire + * lifetime of a request and its response: obtaining a connection, + * sending the request, and reading the response headers and body. + * + * To create a new request with a context, use [NewRequestWithContext]. + * To make a deep copy of a request with a new context, use [Request.Clone]. + */ + withContext(ctx: context.Context): (Request) + } + interface Request { + /** + * Clone returns a deep copy of r with its context changed to ctx. + * The provided ctx must be non-nil. + * + * Clone only makes a shallow copy of the Body field. + * + * For an outgoing client request, the context controls the entire + * lifetime of a request and its response: obtaining a connection, + * sending the request, and reading the response headers and body. + */ + clone(ctx: context.Context): (Request) + } + interface Request { + /** + * ProtoAtLeast reports whether the HTTP protocol used + * in the request is at least major.minor. + */ + protoAtLeast(major: number, minor: number): boolean + } + interface Request { + /** + * UserAgent returns the client's User-Agent, if sent in the request. + */ + userAgent(): string + } + interface Request { + /** + * Cookies parses and returns the HTTP cookies sent with the request. + */ + cookies(): Array<(Cookie | undefined)> + } + interface Request { + /** + * CookiesNamed parses and returns the named HTTP cookies sent with the request + * or an empty slice if none matched. + */ + cookiesNamed(name: string): Array<(Cookie | undefined)> + } + interface Request { + /** + * Cookie returns the named cookie provided in the request or + * [ErrNoCookie] if not found. + * If multiple cookies match the given name, only one cookie will + * be returned. + */ + cookie(name: string): (Cookie) + } + interface Request { + /** + * AddCookie adds a cookie to the request. Per RFC 6265 section 5.4, + * AddCookie does not attach more than one [Cookie] header field. That + * means all cookies, if any, are written into the same line, + * separated by semicolon. + * AddCookie only sanitizes c's name and value, and does not sanitize + * a Cookie header already present in the request. + */ + addCookie(c: Cookie): void + } + interface Request { + /** + * Referer returns the referring URL, if sent in the request. + * + * Referer is misspelled as in the request itself, a mistake from the + * earliest days of HTTP. This value can also be fetched from the + * [Header] map as Header["Referer"]; the benefit of making it available + * as a method is that the compiler can diagnose programs that use the + * alternate (correct English) spelling req.Referrer() but cannot + * diagnose programs that use Header["Referrer"]. + */ + referer(): string + } + interface Request { + /** + * MultipartReader returns a MIME multipart reader if this is a + * multipart/form-data or a multipart/mixed POST request, else returns nil and an error. + * Use this function instead of [Request.ParseMultipartForm] to + * process the request body as a stream. + */ + multipartReader(): (multipart.Reader) + } + interface Request { + /** + * Write writes an HTTP/1.1 request, which is the header and body, in wire format. + * This method consults the following fields of the request: + * + * ``` + * Host + * URL + * Method (defaults to "GET") + * Header + * ContentLength + * TransferEncoding + * Body + * ``` + * + * If Body is present, Content-Length is <= 0 and [Request.TransferEncoding] + * hasn't been set to "identity", Write adds "Transfer-Encoding: + * chunked" to the header. Body is closed after it is sent. + */ + write(w: io.Writer): void + } + interface Request { + /** + * WriteProxy is like [Request.Write] but writes the request in the form + * expected by an HTTP proxy. In particular, [Request.WriteProxy] writes the + * initial Request-URI line of the request with an absolute URI, per + * section 5.3 of RFC 7230, including the scheme and host. + * In either case, WriteProxy also writes a Host header, using + * either r.Host or r.URL.Host. + */ + writeProxy(w: io.Writer): void + } + interface Request { + /** + * BasicAuth returns the username and password provided in the request's + * Authorization header, if the request uses HTTP Basic Authentication. + * See RFC 2617, Section 2. + */ + basicAuth(): [string, string, boolean] + } + interface Request { + /** + * SetBasicAuth sets the request's Authorization header to use HTTP + * Basic Authentication with the provided username and password. + * + * With HTTP Basic Authentication the provided username and password + * are not encrypted. It should generally only be used in an HTTPS + * request. + * + * The username may not contain a colon. Some protocols may impose + * additional requirements on pre-escaping the username and + * password. For instance, when used with OAuth2, both arguments must + * be URL encoded first with [url.QueryEscape]. + */ + setBasicAuth(username: string, password: string): void + } + interface Request { + /** + * ParseForm populates r.Form and r.PostForm. + * + * For all requests, ParseForm parses the raw query from the URL and updates + * r.Form. + * + * For POST, PUT, and PATCH requests, it also reads the request body, parses it + * as a form and puts the results into both r.PostForm and r.Form. Request body + * parameters take precedence over URL query string values in r.Form. + * + * If the request Body's size has not already been limited by [MaxBytesReader], + * the size is capped at 10MB. + * + * For other HTTP methods, or when the Content-Type is not + * application/x-www-form-urlencoded, the request Body is not read, and + * r.PostForm is initialized to a non-nil, empty value. + * + * [Request.ParseMultipartForm] calls ParseForm automatically. + * ParseForm is idempotent. + */ + parseForm(): void + } + interface Request { + /** + * ParseMultipartForm parses a request body as multipart/form-data. + * The whole request body is parsed and up to a total of maxMemory bytes of + * its file parts are stored in memory, with the remainder stored on + * disk in temporary files. + * ParseMultipartForm calls [Request.ParseForm] if necessary. + * If ParseForm returns an error, ParseMultipartForm returns it but also + * continues parsing the request body. + * After one call to ParseMultipartForm, subsequent calls have no effect. + */ + parseMultipartForm(maxMemory: number): void + } + interface Request { + /** + * FormValue returns the first value for the named component of the query. + * The precedence order: + * 1. application/x-www-form-urlencoded form body (POST, PUT, PATCH only) + * 2. query parameters (always) + * 3. multipart/form-data form body (always) + * + * FormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] + * if necessary and ignores any errors returned by these functions. + * If key is not present, FormValue returns the empty string. + * To access multiple values of the same key, call ParseForm and + * then inspect [Request.Form] directly. + */ + formValue(key: string): string + } + interface Request { + /** + * PostFormValue returns the first value for the named component of the POST, + * PUT, or PATCH request body. URL query parameters are ignored. + * PostFormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary and ignores + * any errors returned by these functions. + * If key is not present, PostFormValue returns the empty string. + */ + postFormValue(key: string): string + } + interface Request { + /** + * FormFile returns the first file for the provided form key. + * FormFile calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary. + */ + formFile(key: string): [multipart.File, (multipart.FileHeader)] + } + interface Request { + /** + * PathValue returns the value for the named path wildcard in the [ServeMux] pattern + * that matched the request. + * It returns the empty string if the request was not matched against a pattern + * or there is no such wildcard in the pattern. + */ + pathValue(name: string): string + } + interface Request { + /** + * SetPathValue sets name to value, so that subsequent calls to r.PathValue(name) + * return value. + */ + setPathValue(name: string, value: string): void + } + /** + * A Handler responds to an HTTP request. + * + * [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter] + * and then return. Returning signals that the request is finished; it + * is not valid to use the [ResponseWriter] or read from the + * [Request.Body] after or concurrently with the completion of the + * ServeHTTP call. + * + * Depending on the HTTP client software, HTTP protocol version, and + * any intermediaries between the client and the Go server, it may not + * be possible to read from the [Request.Body] after writing to the + * [ResponseWriter]. Cautious handlers should read the [Request.Body] + * first, and then reply. + * + * Except for reading the body, handlers should not modify the + * provided Request. + * + * If ServeHTTP panics, the server (the caller of ServeHTTP) assumes + * that the effect of the panic was isolated to the active request. + * It recovers the panic, logs a stack trace to the server error log, + * and either closes the network connection or sends an HTTP/2 + * RST_STREAM, depending on the HTTP protocol. To abort a handler so + * the client sees an interrupted response but the server doesn't log + * an error, panic with the value [ErrAbortHandler]. + */ + interface Handler { + [key:string]: any; + serveHTTP(_arg0: ResponseWriter, _arg1: Request): void + } + /** + * A ResponseWriter interface is used by an HTTP handler to + * construct an HTTP response. + * + * A ResponseWriter may not be used after [Handler.ServeHTTP] has returned. + */ + interface ResponseWriter { + [key:string]: any; + /** + * Header returns the header map that will be sent by + * [ResponseWriter.WriteHeader]. The [Header] map also is the mechanism with which + * [Handler] implementations can set HTTP trailers. + * + * Changing the header map after a call to [ResponseWriter.WriteHeader] (or + * [ResponseWriter.Write]) has no effect unless the HTTP status code was of the + * 1xx class or the modified headers are trailers. + * + * There are two ways to set Trailers. The preferred way is to + * predeclare in the headers which trailers you will later + * send by setting the "Trailer" header to the names of the + * trailer keys which will come later. In this case, those + * keys of the Header map are treated as if they were + * trailers. See the example. The second way, for trailer + * keys not known to the [Handler] until after the first [ResponseWriter.Write], + * is to prefix the [Header] map keys with the [TrailerPrefix] + * constant value. + * + * To suppress automatic response headers (such as "Date"), set + * their value to nil. + */ + header(): Header + /** + * Write writes the data to the connection as part of an HTTP reply. + * + * If [ResponseWriter.WriteHeader] has not yet been called, Write calls + * WriteHeader(http.StatusOK) before writing the data. If the Header + * does not contain a Content-Type line, Write adds a Content-Type set + * to the result of passing the initial 512 bytes of written data to + * [DetectContentType]. Additionally, if the total size of all written + * data is under a few KB and there are no Flush calls, the + * Content-Length header is added automatically. + * + * Depending on the HTTP protocol version and the client, calling + * Write or WriteHeader may prevent future reads on the + * Request.Body. For HTTP/1.x requests, handlers should read any + * needed request body data before writing the response. Once the + * headers have been flushed (due to either an explicit Flusher.Flush + * call or writing enough data to trigger a flush), the request body + * may be unavailable. For HTTP/2 requests, the Go HTTP server permits + * handlers to continue to read the request body while concurrently + * writing the response. However, such behavior may not be supported + * by all HTTP/2 clients. Handlers should read before writing if + * possible to maximize compatibility. + */ + write(_arg0: string|Array): number + /** + * WriteHeader sends an HTTP response header with the provided + * status code. + * + * If WriteHeader is not called explicitly, the first call to Write + * will trigger an implicit WriteHeader(http.StatusOK). + * Thus explicit calls to WriteHeader are mainly used to + * send error codes or 1xx informational responses. + * + * The provided code must be a valid HTTP 1xx-5xx status code. + * Any number of 1xx headers may be written, followed by at most + * one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx + * headers may be buffered. Use the Flusher interface to send + * buffered data. The header map is cleared when 2xx-5xx headers are + * sent, but not with 1xx headers. + * + * The server will automatically send a 100 (Continue) header + * on the first read from the request body if the request has + * an "Expect: 100-continue" header. + */ + writeHeader(statusCode: number): void + } + /** + * A Server defines parameters for running an HTTP server. + * The zero value for Server is a valid configuration. + */ + interface Server { + /** + * Addr optionally specifies the TCP address for the server to listen on, + * in the form "host:port". If empty, ":http" (port 80) is used. + * The service names are defined in RFC 6335 and assigned by IANA. + * See net.Dial for details of the address format. + */ + addr: string + handler: Handler // handler to invoke, http.DefaultServeMux if nil + /** + * DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler, + * otherwise responds with 200 OK and Content-Length: 0. + */ + disableGeneralOptionsHandler: boolean + /** + * TLSConfig optionally provides a TLS configuration for use + * by ServeTLS and ListenAndServeTLS. Note that this value is + * cloned by ServeTLS and ListenAndServeTLS, so it's not + * possible to modify the configuration with methods like + * tls.Config.SetSessionTicketKeys. To use + * SetSessionTicketKeys, use Server.Serve with a TLS Listener + * instead. + */ + tlsConfig?: any + /** + * ReadTimeout is the maximum duration for reading the entire + * request, including the body. A zero or negative value means + * there will be no timeout. + * + * Because ReadTimeout does not let Handlers make per-request + * decisions on each request body's acceptable deadline or + * upload rate, most users will prefer to use + * ReadHeaderTimeout. It is valid to use them both. + */ + readTimeout: time.Duration + /** + * ReadHeaderTimeout is the amount of time allowed to read + * request headers. The connection's read deadline is reset + * after reading the headers and the Handler can decide what + * is considered too slow for the body. If zero, the value of + * ReadTimeout is used. If negative, or if zero and ReadTimeout + * is zero or negative, there is no timeout. + */ + readHeaderTimeout: time.Duration + /** + * WriteTimeout is the maximum duration before timing out + * writes of the response. It is reset whenever a new + * request's header is read. Like ReadTimeout, it does not + * let Handlers make decisions on a per-request basis. + * A zero or negative value means there will be no timeout. + */ + writeTimeout: time.Duration + /** + * IdleTimeout is the maximum amount of time to wait for the + * next request when keep-alives are enabled. If zero, the value + * of ReadTimeout is used. If negative, or if zero and ReadTimeout + * is zero or negative, there is no timeout. + */ + idleTimeout: time.Duration + /** + * MaxHeaderBytes controls the maximum number of bytes the + * server will read parsing the request header's keys and + * values, including the request line. It does not limit the + * size of the request body. + * If zero, DefaultMaxHeaderBytes is used. + */ + maxHeaderBytes: number + /** + * TLSNextProto optionally specifies a function to take over + * ownership of the provided TLS connection when an ALPN + * protocol upgrade has occurred. The map key is the protocol + * name negotiated. The Handler argument should be used to + * handle HTTP requests and will initialize the Request's TLS + * and RemoteAddr if not already set. The connection is + * automatically closed when the function returns. + * If TLSNextProto is not nil, HTTP/2 support is not enabled + * automatically. + */ + tlsNextProto: _TygojaDict + /** + * ConnState specifies an optional callback function that is + * called when a client connection changes state. See the + * ConnState type and associated constants for details. + */ + connState: (_arg0: net.Conn, _arg1: ConnState) => void + /** + * ErrorLog specifies an optional logger for errors accepting + * connections, unexpected behavior from handlers, and + * underlying FileSystem errors. + * If nil, logging is done via the log package's standard logger. + */ + errorLog?: any + /** + * BaseContext optionally specifies a function that returns + * the base context for incoming requests on this server. + * The provided Listener is the specific Listener that's + * about to start accepting requests. + * If BaseContext is nil, the default is context.Background(). + * If non-nil, it must return a non-nil context. + */ + baseContext: (_arg0: net.Listener) => context.Context + /** + * ConnContext optionally specifies a function that modifies + * the context used for a new connection c. The provided ctx + * is derived from the base context and has a ServerContextKey + * value. + */ + connContext: (ctx: context.Context, c: net.Conn) => context.Context + /** + * HTTP2 configures HTTP/2 connections. + * + * This field does not yet have any effect. + * See https://go.dev/issue/67813. + */ + http2?: HTTP2Config + /** + * Protocols is the set of protocols accepted by the server. + * + * If Protocols includes UnencryptedHTTP2, the server will accept + * unencrypted HTTP/2 connections. The server can serve both + * HTTP/1 and unencrypted HTTP/2 on the same address and port. + * + * If Protocols is nil, the default is usually HTTP/1 and HTTP/2. + * If TLSNextProto is non-nil and does not contain an "h2" entry, + * the default is HTTP/1 only. + */ + protocols?: Protocols + } + interface Server { + /** + * Close immediately closes all active net.Listeners and any + * connections in state [StateNew], [StateActive], or [StateIdle]. For a + * graceful shutdown, use [Server.Shutdown]. + * + * Close does not attempt to close (and does not even know about) + * any hijacked connections, such as WebSockets. + * + * Close returns any error returned from closing the [Server]'s + * underlying Listener(s). + */ + close(): void + } + interface Server { + /** + * Shutdown gracefully shuts down the server without interrupting any + * active connections. Shutdown works by first closing all open + * listeners, then closing all idle connections, and then waiting + * indefinitely for connections to return to idle and then shut down. + * If the provided context expires before the shutdown is complete, + * Shutdown returns the context's error, otherwise it returns any + * error returned from closing the [Server]'s underlying Listener(s). + * + * When Shutdown is called, [Serve], [ServeTLS], [ListenAndServe], and + * [ListenAndServeTLS] immediately return [ErrServerClosed]. Make sure the + * program doesn't exit and waits instead for Shutdown to return. + * + * Shutdown does not attempt to close nor wait for hijacked + * connections such as WebSockets. The caller of Shutdown should + * separately notify such long-lived connections of shutdown and wait + * for them to close, if desired. See [Server.RegisterOnShutdown] for a way to + * register shutdown notification functions. + * + * Once Shutdown has been called on a server, it may not be reused; + * future calls to methods such as Serve will return ErrServerClosed. + */ + shutdown(ctx: context.Context): void + } + interface Server { + /** + * RegisterOnShutdown registers a function to call on [Server.Shutdown]. + * This can be used to gracefully shutdown connections that have + * undergone ALPN protocol upgrade or that have been hijacked. + * This function should start protocol-specific graceful shutdown, + * but should not wait for shutdown to complete. + */ + registerOnShutdown(f: () => void): void + } + interface Server { + /** + * ListenAndServe listens on the TCP network address s.Addr and then + * calls [Serve] to handle requests on incoming connections. + * Accepted connections are configured to enable TCP keep-alives. + * + * If s.Addr is blank, ":http" is used. + * + * ListenAndServe always returns a non-nil error. After [Server.Shutdown] or [Server.Close], + * the returned error is [ErrServerClosed]. + */ + listenAndServe(): void + } + interface Server { + /** + * Serve accepts incoming connections on the Listener l, creating a + * new service goroutine for each. The service goroutines read requests and + * then call s.Handler to reply to them. + * + * HTTP/2 support is only enabled if the Listener returns [*tls.Conn] + * connections and they were configured with "h2" in the TLS + * Config.NextProtos. + * + * Serve always returns a non-nil error and closes l. + * After [Server.Shutdown] or [Server.Close], the returned error is [ErrServerClosed]. + */ + serve(l: net.Listener): void + } + interface Server { + /** + * ServeTLS accepts incoming connections on the Listener l, creating a + * new service goroutine for each. The service goroutines perform TLS + * setup and then read requests, calling s.Handler to reply to them. + * + * Files containing a certificate and matching private key for the + * server must be provided if neither the [Server]'s + * TLSConfig.Certificates, TLSConfig.GetCertificate nor + * config.GetConfigForClient are populated. + * If the certificate is signed by a certificate authority, the + * certFile should be the concatenation of the server's certificate, + * any intermediates, and the CA's certificate. + * + * ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the + * returned error is [ErrServerClosed]. + */ + serveTLS(l: net.Listener, certFile: string, keyFile: string): void + } + interface Server { + /** + * SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. + * By default, keep-alives are always enabled. Only very + * resource-constrained environments or servers in the process of + * shutting down should disable them. + */ + setKeepAlivesEnabled(v: boolean): void + } + interface Server { + /** + * ListenAndServeTLS listens on the TCP network address s.Addr and + * then calls [ServeTLS] to handle requests on incoming TLS connections. + * Accepted connections are configured to enable TCP keep-alives. + * + * Filenames containing a certificate and matching private key for the + * server must be provided if neither the [Server]'s TLSConfig.Certificates + * nor TLSConfig.GetCertificate are populated. If the certificate is + * signed by a certificate authority, the certFile should be the + * concatenation of the server's certificate, any intermediates, and + * the CA's certificate. + * + * If s.Addr is blank, ":https" is used. + * + * ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or + * [Server.Close], the returned error is [ErrServerClosed]. + */ + listenAndServeTLS(certFile: string, keyFile: string): void + } +} + +/** + * Package sql provides a generic interface around SQL (or SQL-like) + * databases. * - * The built-in handlers acquire a lock before calling [io.Writer.Write] - * to ensure that exactly one [Record] is written at a time in its entirety. - * Although each log record has a timestamp, - * the built-in handlers do not use that time to sort the written records. - * User-defined handlers are responsible for their own locking and sorting. + * The sql package must be used in conjunction with a database driver. + * See https://golang.org/s/sqldrivers for a list of drivers. * - * # Writing a handler + * Drivers that do not support context cancellation will not return until + * after the query is completed. * - * For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. + * For usage examples, see the wiki page at + * https://golang.org/s/sqlwiki. */ -namespace slog { - // @ts-ignore - import loginternal = internal +namespace sql { /** - * A Logger records structured information about each call to its - * Log, Debug, Info, Warn, and Error methods. - * For each call, it creates a [Record] and passes it to a [Handler]. + * TxOptions holds the transaction options to be used in [DB.BeginTx]. + */ + interface TxOptions { + /** + * Isolation is the transaction isolation level. + * If zero, the driver or database's default level is used. + */ + isolation: IsolationLevel + readOnly: boolean + } + /** + * NullString represents a string that may be null. + * NullString implements the [Scanner] interface so + * it can be used as a scan destination: * - * To create a new Logger, call [New] or a Logger method - * that begins "With". + * ``` + * var s NullString + * err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) + * ... + * if s.Valid { + * // use s.String + * } else { + * // NULL value + * } + * ``` */ - interface Logger { + interface NullString { + string: string + valid: boolean // Valid is true if String is not NULL } - interface Logger { + interface NullString { /** - * Handler returns l's Handler. + * Scan implements the [Scanner] interface. */ - handler(): Handler + scan(value: any): void } - interface Logger { + interface NullString { /** - * With returns a Logger that includes the given attributes - * in each output operation. Arguments are converted to - * attributes as if by [Logger.Log]. + * Value implements the [driver.Valuer] interface. */ - with(...args: any[]): (Logger) + value(): any } - interface Logger { + /** + * DB is a database handle representing a pool of zero or more + * underlying connections. It's safe for concurrent use by multiple + * goroutines. + * + * The sql package creates and frees connections automatically; it + * also maintains a free pool of idle connections. If the database has + * a concept of per-connection state, such state can be reliably observed + * within a transaction ([Tx]) or connection ([Conn]). Once [DB.Begin] is called, the + * returned [Tx] is bound to a single connection. Once [Tx.Commit] or + * [Tx.Rollback] is called on the transaction, that transaction's + * connection is returned to [DB]'s idle connection pool. The pool size + * can be controlled with [DB.SetMaxIdleConns]. + */ + interface DB { + } + interface DB { /** - * WithGroup returns a Logger that starts a group, if name is non-empty. - * The keys of all attributes added to the Logger will be qualified by the given - * name. (How that qualification happens depends on the [Handler.WithGroup] - * method of the Logger's Handler.) + * PingContext verifies a connection to the database is still alive, + * establishing a connection if necessary. + */ + pingContext(ctx: context.Context): void + } + interface DB { + /** + * Ping verifies a connection to the database is still alive, + * establishing a connection if necessary. * - * If name is empty, WithGroup returns the receiver. + * Ping uses [context.Background] internally; to specify the context, use + * [DB.PingContext]. */ - withGroup(name: string): (Logger) + ping(): void } - interface Logger { + interface DB { /** - * Enabled reports whether l emits log records at the given context and level. + * Close closes the database and prevents new queries from starting. + * Close then waits for all queries that have started processing on the server + * to finish. + * + * It is rare to Close a [DB], as the [DB] handle is meant to be + * long-lived and shared between many goroutines. */ - enabled(ctx: context.Context, level: Level): boolean + close(): void } - interface Logger { + interface DB { /** - * Log emits a log record with the current time and the given level and message. - * The Record's Attrs consist of the Logger's attributes followed by - * the Attrs specified by args. + * SetMaxIdleConns sets the maximum number of connections in the idle + * connection pool. * - * The attribute arguments are processed as follows: - * ``` - * - If an argument is an Attr, it is used as is. - * - If an argument is a string and this is not the last argument, - * the following argument is treated as the value and the two are combined - * into an Attr. - * - Otherwise, the argument is treated as a value with key "!BADKEY". - * ``` + * If MaxOpenConns is greater than 0 but less than the new MaxIdleConns, + * then the new MaxIdleConns will be reduced to match the MaxOpenConns limit. + * + * If n <= 0, no idle connections are retained. + * + * The default max idle connections is currently 2. This may change in + * a future release. */ - log(ctx: context.Context, level: Level, msg: string, ...args: any[]): void + setMaxIdleConns(n: number): void } - interface Logger { + interface DB { /** - * LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs. + * SetMaxOpenConns sets the maximum number of open connections to the database. + * + * If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than + * MaxIdleConns, then MaxIdleConns will be reduced to match the new + * MaxOpenConns limit. + * + * If n <= 0, then there is no limit on the number of open connections. + * The default is 0 (unlimited). + */ + setMaxOpenConns(n: number): void + } + interface DB { + /** + * SetConnMaxLifetime sets the maximum amount of time a connection may be reused. + * + * Expired connections may be closed lazily before reuse. + * + * If d <= 0, connections are not closed due to a connection's age. */ - logAttrs(ctx: context.Context, level: Level, msg: string, ...attrs: Attr[]): void + setConnMaxLifetime(d: time.Duration): void } - interface Logger { + interface DB { /** - * Debug logs at [LevelDebug]. + * SetConnMaxIdleTime sets the maximum amount of time a connection may be idle. + * + * Expired connections may be closed lazily before reuse. + * + * If d <= 0, connections are not closed due to a connection's idle time. */ - debug(msg: string, ...args: any[]): void + setConnMaxIdleTime(d: time.Duration): void } - interface Logger { + interface DB { /** - * DebugContext logs at [LevelDebug] with the given context. + * Stats returns database statistics. */ - debugContext(ctx: context.Context, msg: string, ...args: any[]): void + stats(): DBStats } - interface Logger { + interface DB { /** - * Info logs at [LevelInfo]. + * PrepareContext creates a prepared statement for later queries or executions. + * Multiple queries or executions may be run concurrently from the + * returned statement. + * The caller must call the statement's [*Stmt.Close] method + * when the statement is no longer needed. + * + * The provided context is used for the preparation of the statement, not for the + * execution of the statement. */ - info(msg: string, ...args: any[]): void + prepareContext(ctx: context.Context, query: string): (Stmt) } - interface Logger { + interface DB { /** - * InfoContext logs at [LevelInfo] with the given context. + * Prepare creates a prepared statement for later queries or executions. + * Multiple queries or executions may be run concurrently from the + * returned statement. + * The caller must call the statement's [*Stmt.Close] method + * when the statement is no longer needed. + * + * Prepare uses [context.Background] internally; to specify the context, use + * [DB.PrepareContext]. */ - infoContext(ctx: context.Context, msg: string, ...args: any[]): void + prepare(query: string): (Stmt) } - interface Logger { + interface DB { /** - * Warn logs at [LevelWarn]. + * ExecContext executes a query without returning any rows. + * The args are for any placeholder parameters in the query. */ - warn(msg: string, ...args: any[]): void + execContext(ctx: context.Context, query: string, ...args: any[]): Result } - interface Logger { + interface DB { /** - * WarnContext logs at [LevelWarn] with the given context. + * Exec executes a query without returning any rows. + * The args are for any placeholder parameters in the query. + * + * Exec uses [context.Background] internally; to specify the context, use + * [DB.ExecContext]. */ - warnContext(ctx: context.Context, msg: string, ...args: any[]): void + exec(query: string, ...args: any[]): Result } - interface Logger { + interface DB { /** - * Error logs at [LevelError]. + * QueryContext executes a query that returns rows, typically a SELECT. + * The args are for any placeholder parameters in the query. */ - error(msg: string, ...args: any[]): void + queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) } - interface Logger { + interface DB { /** - * ErrorContext logs at [LevelError] with the given context. + * Query executes a query that returns rows, typically a SELECT. + * The args are for any placeholder parameters in the query. + * + * Query uses [context.Background] internally; to specify the context, use + * [DB.QueryContext]. */ - errorContext(ctx: context.Context, msg: string, ...args: any[]): void - } -} - -namespace hook { - /** - * Event implements [Resolver] and it is intended to be used as a base - * Hook event that you can embed in your custom typed event structs. - * - * Example: - * - * ``` - * type CustomEvent struct { - * hook.Event - * - * SomeField int - * } - * ``` - */ - interface Event { + query(query: string, ...args: any[]): (Rows) } - interface Event { + interface DB { /** - * Next calls the next hook handler. + * QueryRowContext executes a query that is expected to return at most one row. + * QueryRowContext always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, [*Row.Scan] scans the first selected row and discards + * the rest. */ - next(): void + queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) } - /** - * Handler defines a single Hook handler. - * Multiple handlers can share the same id. - * If Id is not explicitly set it will be autogenerated by Hook.Add and Hook.AddHandler. - */ - interface Handler { + interface DB { /** - * Func defines the handler function to execute. + * QueryRow executes a query that is expected to return at most one row. + * QueryRow always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, [*Row.Scan] scans the first selected row and discards + * the rest. * - * Note that users need to call e.Next() in order to proceed with - * the execution of the hook chain. + * QueryRow uses [context.Background] internally; to specify the context, use + * [DB.QueryRowContext]. */ - func: (_arg0: T) => void + queryRow(query: string, ...args: any[]): (Row) + } + interface DB { /** - * Id is the unique identifier of the handler. + * BeginTx starts a transaction. * - * It could be used later to remove the handler from a hook via [Hook.Remove]. + * The provided context is used until the transaction is committed or rolled back. + * If the context is canceled, the sql package will roll back + * the transaction. [Tx.Commit] will return an error if the context provided to + * BeginTx is canceled. * - * If missing, an autogenerated value will be assigned when adding - * the handler to a hook. + * The provided [TxOptions] is optional and may be nil if defaults should be used. + * If a non-default isolation level is used that the driver doesn't support, + * an error will be returned. */ - id: string + beginTx(ctx: context.Context, opts: TxOptions): (Tx) + } + interface DB { /** - * Priority allows changing the default exec priority of the handler within a hook. + * Begin starts a transaction. The default isolation level is dependent on + * the driver. * - * If 0, the handler will be executed in the same order it was registered. + * Begin uses [context.Background] internally; to specify the context, use + * [DB.BeginTx]. */ - priority: number - } - /** - * Hook defines a generic concurrent safe structure for managing event hooks. - * - * When using custom event it must embed the base [hook.Event]. - * - * Example: - * - * ``` - * type CustomEvent struct { - * hook.Event - * SomeField int - * } - * - * h := Hook[*CustomEvent]{} - * - * h.BindFunc(func(e *CustomEvent) error { - * println(e.SomeField) - * - * return e.Next() - * }) - * - * h.Trigger(&CustomEvent{ SomeField: 123 }) - * ``` - */ - interface Hook { + begin(): (Tx) } - interface Hook { + interface DB { /** - * Bind registers the provided handler to the current hooks queue. - * - * If handler.Id is empty it is updated with autogenerated value. - * - * If a handler from the current hook list has Id matching handler.Id - * then the old handler is replaced with the new one. + * Driver returns the database's underlying driver. */ - bind(handler: Handler): string + driver(): any } - interface Hook { + interface DB { /** - * BindFunc is similar to Bind but registers a new handler from just the provided function. - * - * The registered handler is added with a default 0 priority and the id will be autogenerated. + * Conn returns a single connection by either opening a new connection + * or returning an existing connection from the connection pool. Conn will + * block until either a connection is returned or ctx is canceled. + * Queries run on the same Conn will be run in the same database session. * - * If you want to register a handler with custom priority or id use the [Hook.Bind] method. + * Every Conn must be returned to the database pool after use by + * calling [Conn.Close]. */ - bindFunc(fn: (e: T) => void): string + conn(ctx: context.Context): (Conn) } - interface Hook { - /** - * Unbind removes one or many hook handler by their id. - */ - unbind(...idsToRemove: string[]): void + /** + * Tx is an in-progress database transaction. + * + * A transaction must end with a call to [Tx.Commit] or [Tx.Rollback]. + * + * After a call to [Tx.Commit] or [Tx.Rollback], all operations on the + * transaction fail with [ErrTxDone]. + * + * The statements prepared for a transaction by calling + * the transaction's [Tx.Prepare] or [Tx.Stmt] methods are closed + * by the call to [Tx.Commit] or [Tx.Rollback]. + */ + interface Tx { } - interface Hook { + interface Tx { /** - * UnbindAll removes all registered handlers. + * Commit commits the transaction. */ - unbindAll(): void + commit(): void } - interface Hook { + interface Tx { /** - * Length returns to total number of registered hook handlers. + * Rollback aborts the transaction. */ - length(): number + rollback(): void } - interface Hook { + interface Tx { /** - * Trigger executes all registered hook handlers one by one - * with the specified event as an argument. + * PrepareContext creates a prepared statement for use within a transaction. * - * Optionally, this method allows also to register additional one off - * handler funcs that will be temporary appended to the handlers queue. + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. * - * NB! Each hook handler must call event.Next() in order the hook chain to proceed. - */ - trigger(event: T, ...oneOffHandlerFuncs: ((_arg0: T) => void)[]): void - } - /** - * TaggedHook defines a proxy hook which register handlers that are triggered only - * if the TaggedHook.tags are empty or includes at least one of the event data tag(s). - */ - type _skDDNSt = mainHook - interface TaggedHook extends _skDDNSt { + * To use an existing prepared statement on this transaction, see [Tx.Stmt]. + * + * The provided context will be used for the preparation of the context, not + * for the execution of the returned statement. The returned statement + * will run in the transaction context. + */ + prepareContext(ctx: context.Context, query: string): (Stmt) } - interface TaggedHook { + interface Tx { /** - * CanTriggerOn checks if the current TaggedHook can be triggered with - * the provided event data tags. + * Prepare creates a prepared statement for use within a transaction. * - * It returns always true if the hook doesn't have any tags. + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. + * + * To use an existing prepared statement on this transaction, see [Tx.Stmt]. + * + * Prepare uses [context.Background] internally; to specify the context, use + * [Tx.PrepareContext]. */ - canTriggerOn(tagsToCheck: Array): boolean + prepare(query: string): (Stmt) } - interface TaggedHook { + interface Tx { /** - * Bind registers the provided handler to the current hooks queue. + * StmtContext returns a transaction-specific prepared statement from + * an existing statement. * - * It is similar to [Hook.Bind] with the difference that the handler - * function is invoked only if the event data tags satisfy h.CanTriggerOn. + * Example: + * + * ``` + * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") + * ... + * tx, err := db.Begin() + * ... + * res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203) + * ``` + * + * The provided context is used for the preparation of the statement, not for the + * execution of the statement. + * + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. */ - bind(handler: Handler): string + stmtContext(ctx: context.Context, stmt: Stmt): (Stmt) } - interface TaggedHook { + interface Tx { /** - * BindFunc registers a new handler with the specified function. + * Stmt returns a transaction-specific prepared statement from + * an existing statement. * - * It is similar to [Hook.Bind] with the difference that the handler - * function is invoked only if the event data tags satisfy h.CanTriggerOn. + * Example: + * + * ``` + * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") + * ... + * tx, err := db.Begin() + * ... + * res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203) + * ``` + * + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. + * + * Stmt uses [context.Background] internally; to specify the context, use + * [Tx.StmtContext]. */ - bindFunc(fn: (e: T) => void): string - } -} - -/** - * Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer - * object, creating another object (Reader or Writer) that also implements - * the interface but provides buffering and some help for textual I/O. - */ -namespace bufio { - /** - * ReadWriter stores pointers to a [Reader] and a [Writer]. - * It implements [io.ReadWriter]. - */ - type _sgpcBrt = Reader&Writer - interface ReadWriter extends _sgpcBrt { - } -} - -/** - * Package multipart implements MIME multipart parsing, as defined in RFC - * 2046. - * - * The implementation is sufficient for HTTP (RFC 2388) and the multipart - * bodies generated by popular browsers. - * - * # Limits - * - * To protect against malicious inputs, this package sets limits on the size - * of the MIME data it processes. - * - * [Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a - * part to 10000 and [Reader.ReadForm] limits the total number of headers in all - * FileHeaders to 10000. - * These limits may be adjusted with the GODEBUG=multipartmaxheaders= - * setting. - * - * Reader.ReadForm further limits the number of parts in a form to 1000. - * This limit may be adjusted with the GODEBUG=multipartmaxparts= - * setting. - */ -namespace multipart { - /** - * A FileHeader describes a file part of a multipart request. - */ - interface FileHeader { - filename: string - header: textproto.MIMEHeader - size: number + stmt(stmt: Stmt): (Stmt) } - interface FileHeader { + interface Tx { /** - * Open opens and returns the [FileHeader]'s associated File. + * ExecContext executes a query that doesn't return rows. + * For example: an INSERT and UPDATE. */ - open(): File + execContext(ctx: context.Context, query: string, ...args: any[]): Result } -} - -/** - * Package http provides HTTP client and server implementations. - * - * [Get], [Head], [Post], and [PostForm] make HTTP (or HTTPS) requests: - * - * ``` - * resp, err := http.Get("http://example.com/") - * ... - * resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) - * ... - * resp, err := http.PostForm("http://example.com/form", - * url.Values{"key": {"Value"}, "id": {"123"}}) - * ``` - * - * The caller must close the response body when finished with it: - * - * ``` - * resp, err := http.Get("http://example.com/") - * if err != nil { - * // handle error - * } - * defer resp.Body.Close() - * body, err := io.ReadAll(resp.Body) - * // ... - * ``` - * - * # Clients and Transports - * - * For control over HTTP client headers, redirect policy, and other - * settings, create a [Client]: - * - * ``` - * client := &http.Client{ - * CheckRedirect: redirectPolicyFunc, - * } - * - * resp, err := client.Get("http://example.com") - * // ... - * - * req, err := http.NewRequest("GET", "http://example.com", nil) - * // ... - * req.Header.Add("If-None-Match", `W/"wyzzy"`) - * resp, err := client.Do(req) - * // ... - * ``` - * - * For control over proxies, TLS configuration, keep-alives, - * compression, and other settings, create a [Transport]: - * - * ``` - * tr := &http.Transport{ - * MaxIdleConns: 10, - * IdleConnTimeout: 30 * time.Second, - * DisableCompression: true, - * } - * client := &http.Client{Transport: tr} - * resp, err := client.Get("https://example.com") - * ``` - * - * Clients and Transports are safe for concurrent use by multiple - * goroutines and for efficiency should only be created once and re-used. - * - * # Servers - * - * ListenAndServe starts an HTTP server with a given address and handler. - * The handler is usually nil, which means to use [DefaultServeMux]. - * [Handle] and [HandleFunc] add handlers to [DefaultServeMux]: - * - * ``` - * http.Handle("/foo", fooHandler) - * - * http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { - * fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) - * }) - * - * log.Fatal(http.ListenAndServe(":8080", nil)) - * ``` - * - * More control over the server's behavior is available by creating a - * custom Server: - * - * ``` - * s := &http.Server{ - * Addr: ":8080", - * Handler: myHandler, - * ReadTimeout: 10 * time.Second, - * WriteTimeout: 10 * time.Second, - * MaxHeaderBytes: 1 << 20, - * } - * log.Fatal(s.ListenAndServe()) - * ``` - * - * # HTTP/2 - * - * Starting with Go 1.6, the http package has transparent support for the - * HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2 - * can do so by setting [Transport.TLSNextProto] (for clients) or - * [Server.TLSNextProto] (for servers) to a non-nil, empty - * map. Alternatively, the following GODEBUG settings are - * currently supported: - * - * ``` - * GODEBUG=http2client=0 # disable HTTP/2 client support - * GODEBUG=http2server=0 # disable HTTP/2 server support - * GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs - * GODEBUG=http2debug=2 # ... even more verbose, with frame dumps - * ``` - * - * Please report any issues before disabling HTTP/2 support: https://golang.org/s/http2bug - * - * The http package's [Transport] and [Server] both automatically enable - * HTTP/2 support for simple configurations. To enable HTTP/2 for more - * complex configurations, to use lower-level HTTP/2 features, or to use - * a newer version of Go's http2 package, import "golang.org/x/net/http2" - * directly and use its ConfigureTransport and/or ConfigureServer - * functions. Manually configuring HTTP/2 via the golang.org/x/net/http2 - * package takes precedence over the net/http package's built-in HTTP/2 - * support. - */ -namespace http { - // @ts-ignore - import mathrand = rand - /** - * PushOptions describes options for [Pusher.Push]. - */ - interface PushOptions { + interface Tx { + /** + * Exec executes a query that doesn't return rows. + * For example: an INSERT and UPDATE. + * + * Exec uses [context.Background] internally; to specify the context, use + * [Tx.ExecContext]. + */ + exec(query: string, ...args: any[]): Result + } + interface Tx { /** - * Method specifies the HTTP method for the promised request. - * If set, it must be "GET" or "HEAD". Empty means "GET". + * QueryContext executes a query that returns rows, typically a SELECT. */ - method: string + queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) + } + interface Tx { /** - * Header specifies additional promised request headers. This cannot - * include HTTP/2 pseudo header fields like ":path" and ":scheme", - * which will be added automatically. + * Query executes a query that returns rows, typically a SELECT. + * + * Query uses [context.Background] internally; to specify the context, use + * [Tx.QueryContext]. */ - header: Header + query(query: string, ...args: any[]): (Rows) + } + interface Tx { + /** + * QueryRowContext executes a query that is expected to return at most one row. + * QueryRowContext always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. + */ + queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) + } + interface Tx { + /** + * QueryRow executes a query that is expected to return at most one row. + * QueryRow always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. + * + * QueryRow uses [context.Background] internally; to specify the context, use + * [Tx.QueryRowContext]. + */ + queryRow(query: string, ...args: any[]): (Row) } - // @ts-ignore - import urlpkg = url /** - * A Request represents an HTTP request received by a server - * or to be sent by a client. + * Stmt is a prepared statement. + * A Stmt is safe for concurrent use by multiple goroutines. * - * The field semantics differ slightly between client and server - * usage. In addition to the notes on the fields below, see the - * documentation for [Request.Write] and [RoundTripper]. + * If a Stmt is prepared on a [Tx] or [Conn], it will be bound to a single + * underlying connection forever. If the [Tx] or [Conn] closes, the Stmt will + * become unusable and all operations will return an error. + * If a Stmt is prepared on a [DB], it will remain usable for the lifetime of the + * [DB]. When the Stmt needs to execute on a new underlying connection, it will + * prepare itself on the new connection automatically. */ - interface Request { + interface Stmt { + } + interface Stmt { /** - * Method specifies the HTTP method (GET, POST, PUT, etc.). - * For client requests, an empty string means GET. + * ExecContext executes a prepared statement with the given arguments and + * returns a [Result] summarizing the effect of the statement. */ - method: string + execContext(ctx: context.Context, ...args: any[]): Result + } + interface Stmt { /** - * URL specifies either the URI being requested (for server - * requests) or the URL to access (for client requests). - * - * For server requests, the URL is parsed from the URI - * supplied on the Request-Line as stored in RequestURI. For - * most requests, fields other than Path and RawQuery will be - * empty. (See RFC 7230, Section 5.3) + * Exec executes a prepared statement with the given arguments and + * returns a [Result] summarizing the effect of the statement. * - * For client requests, the URL's Host specifies the server to - * connect to, while the Request's Host field optionally - * specifies the Host header value to send in the HTTP - * request. + * Exec uses [context.Background] internally; to specify the context, use + * [Stmt.ExecContext]. */ - url?: url.URL + exec(...args: any[]): Result + } + interface Stmt { /** - * The protocol version for incoming server requests. + * QueryContext executes a prepared query statement with the given arguments + * and returns the query results as a [*Rows]. + */ + queryContext(ctx: context.Context, ...args: any[]): (Rows) + } + interface Stmt { + /** + * Query executes a prepared query statement with the given arguments + * and returns the query results as a *Rows. * - * For client requests, these fields are ignored. The HTTP - * client code always uses either HTTP/1.1 or HTTP/2. - * See the docs on Transport for details. + * Query uses [context.Background] internally; to specify the context, use + * [Stmt.QueryContext]. */ - proto: string // "HTTP/1.0" - protoMajor: number // 1 - protoMinor: number // 0 + query(...args: any[]): (Rows) + } + interface Stmt { /** - * Header contains the request header fields either received - * by the server or to be sent by the client. + * QueryRowContext executes a prepared query statement with the given arguments. + * If an error occurs during the execution of the statement, that error will + * be returned by a call to Scan on the returned [*Row], which is always non-nil. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. + */ + queryRowContext(ctx: context.Context, ...args: any[]): (Row) + } + interface Stmt { + /** + * QueryRow executes a prepared query statement with the given arguments. + * If an error occurs during the execution of the statement, that error will + * be returned by a call to Scan on the returned [*Row], which is always non-nil. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. * - * If a server received a request with header lines, + * Example usage: * * ``` - * Host: example.com - * accept-encoding: gzip, deflate - * Accept-Language: en-us - * fOO: Bar - * foo: two + * var name string + * err := nameByUseridStmt.QueryRow(id).Scan(&name) * ``` * - * then + * QueryRow uses [context.Background] internally; to specify the context, use + * [Stmt.QueryRowContext]. + */ + queryRow(...args: any[]): (Row) + } + interface Stmt { + /** + * Close closes the statement. + */ + close(): void + } + /** + * Rows is the result of a query. Its cursor starts before the first row + * of the result set. Use [Rows.Next] to advance from row to row. + */ + interface Rows { + } + interface Rows { + /** + * Next prepares the next result row for reading with the [Rows.Scan] method. It + * returns true on success, or false if there is no next result row or an error + * happened while preparing it. [Rows.Err] should be consulted to distinguish between + * the two cases. + * + * Every call to [Rows.Scan], even the first one, must be preceded by a call to [Rows.Next]. + */ + next(): boolean + } + interface Rows { + /** + * NextResultSet prepares the next result set for reading. It reports whether + * there is further result sets, or false if there is no further result set + * or if there is an error advancing to it. The [Rows.Err] method should be consulted + * to distinguish between the two cases. + * + * After calling NextResultSet, the [Rows.Next] method should always be called before + * scanning. If there are further result sets they may not have rows in the result + * set. + */ + nextResultSet(): boolean + } + interface Rows { + /** + * Err returns the error, if any, that was encountered during iteration. + * Err may be called after an explicit or implicit [Rows.Close]. + */ + err(): void + } + interface Rows { + /** + * Columns returns the column names. + * Columns returns an error if the rows are closed. + */ + columns(): Array + } + interface Rows { + /** + * ColumnTypes returns column information such as column type, length, + * and nullable. Some information may not be available from some drivers. + */ + columnTypes(): Array<(ColumnType | undefined)> + } + interface Rows { + /** + * Scan copies the columns in the current row into the values pointed + * at by dest. The number of values in dest must be the same as the + * number of columns in [Rows]. + * + * Scan converts columns read from the database into the following + * common Go types and special types provided by the sql package: * * ``` - * Header = map[string][]string{ - * "Accept-Encoding": {"gzip, deflate"}, - * "Accept-Language": {"en-us"}, - * "Foo": {"Bar", "two"}, - * } + * *string + * *[]byte + * *int, *int8, *int16, *int32, *int64 + * *uint, *uint8, *uint16, *uint32, *uint64 + * *bool + * *float32, *float64 + * *interface{} + * *RawBytes + * *Rows (cursor value) + * any type implementing Scanner (see Scanner docs) * ``` * - * For incoming requests, the Host header is promoted to the - * Request.Host field and removed from the Header map. + * In the most simple case, if the type of the value from the source + * column is an integer, bool or string type T and dest is of type *T, + * Scan simply assigns the value through the pointer. + * + * Scan also converts between string and numeric types, as long as no + * information would be lost. While Scan stringifies all numbers + * scanned from numeric database columns into *string, scans into + * numeric types are checked for overflow. For example, a float64 with + * value 300 or a string with value "300" can scan into a uint16, but + * not into a uint8, though float64(255) or "255" can scan into a + * uint8. One exception is that scans of some float64 numbers to + * strings may lose information when stringifying. In general, scan + * floating point columns into *float64. + * + * If a dest argument has type *[]byte, Scan saves in that argument a + * copy of the corresponding data. The copy is owned by the caller and + * can be modified and held indefinitely. The copy can be avoided by + * using an argument of type [*RawBytes] instead; see the documentation + * for [RawBytes] for restrictions on its use. + * + * If an argument has type *interface{}, Scan copies the value + * provided by the underlying driver without conversion. When scanning + * from a source value of type []byte to *interface{}, a copy of the + * slice is made and the caller owns the result. + * + * Source values of type [time.Time] may be scanned into values of type + * *time.Time, *interface{}, *string, or *[]byte. When converting to + * the latter two, [time.RFC3339Nano] is used. + * + * Source values of type bool may be scanned into types *bool, + * *interface{}, *string, *[]byte, or [*RawBytes]. * - * HTTP defines that header names are case-insensitive. The - * request parser implements this by using CanonicalHeaderKey, - * making the first character and any characters following a - * hyphen uppercase and the rest lowercase. + * For scanning into *bool, the source may be true, false, 1, 0, or + * string inputs parseable by [strconv.ParseBool]. * - * For client requests, certain headers such as Content-Length - * and Connection are automatically written when needed and - * values in Header may be ignored. See the documentation - * for the Request.Write method. + * Scan can also convert a cursor returned from a query, such as + * "select cursor(select * from my_table) from dual", into a + * [*Rows] value that can itself be scanned from. The parent + * select query will close any cursor [*Rows] if the parent [*Rows] is closed. + * + * If any of the first arguments implementing [Scanner] returns an error, + * that error will be wrapped in the returned error. */ - header: Header + scan(...dest: any[]): void + } + interface Rows { /** - * Body is the request's body. - * - * For client requests, a nil body means the request has no - * body, such as a GET request. The HTTP Client's Transport - * is responsible for calling the Close method. - * - * For server requests, the Request Body is always non-nil - * but will return EOF immediately when no body is present. - * The Server will close the request body. The ServeHTTP - * Handler does not need to. - * - * Body must allow Read to be called concurrently with Close. - * In particular, calling Close should unblock a Read waiting - * for input. + * Close closes the [Rows], preventing further enumeration. If [Rows.Next] is called + * and returns false and there are no further result sets, + * the [Rows] are closed automatically and it will suffice to check the + * result of [Rows.Err]. Close is idempotent and does not affect the result of [Rows.Err]. */ - body: io.ReadCloser + close(): void + } + /** + * A Result summarizes an executed SQL command. + */ + interface Result { + [key:string]: any; /** - * GetBody defines an optional func to return a new copy of - * Body. It is used for client requests when a redirect requires - * reading the body more than once. Use of GetBody still - * requires setting Body. - * - * For server requests, it is unused. + * LastInsertId returns the integer generated by the database + * in response to a command. Typically this will be from an + * "auto increment" column when inserting a new row. Not all + * databases support this feature, and the syntax of such + * statements varies. */ - getBody: () => io.ReadCloser + lastInsertId(): number /** - * ContentLength records the length of the associated content. - * The value -1 indicates that the length is unknown. - * Values >= 0 indicate that the given number of bytes may - * be read from Body. - * - * For client requests, a value of 0 with a non-nil Body is - * also treated as unknown. + * RowsAffected returns the number of rows affected by an + * update, insert, or delete. Not every database or database + * driver may support this. */ - contentLength: number + rowsAffected(): number + } +} + +/** + * Package blob defines a lightweight abstration for interacting with + * various storage services (local filesystem, S3, etc.). + * + * NB! + * For compatibility with earlier PocketBase versions and to prevent + * unnecessary breaking changes, this package is based and implemented + * as a minimal, stripped down version of the previously used gocloud.dev/blob. + * While there is no promise that it won't diverge in the future to accommodate + * better some PocketBase specific use cases, currently it copies and + * tries to follow as close as possible the same implementations, + * conventions and rules for the key escaping/unescaping, blob read/write + * interfaces and struct options as gocloud.dev/blob, therefore the + * credits goes to the original Go Cloud Development Kit Authors. + */ +namespace blob { + /** + * ListObject represents a single blob returned from List. + */ + interface ListObject { /** - * TransferEncoding lists the transfer encodings from outermost to - * innermost. An empty list denotes the "identity" encoding. - * TransferEncoding can usually be ignored; chunked encoding is - * automatically added and removed as necessary when sending and - * receiving requests. + * Key is the key for this blob. */ - transferEncoding: Array + key: string /** - * Close indicates whether to close the connection after - * replying to this request (for servers) or after sending this - * request and reading its response (for clients). - * - * For server requests, the HTTP server handles this automatically - * and this field is not needed by Handlers. - * - * For client requests, setting this field prevents re-use of - * TCP connections between requests to the same hosts, as if - * Transport.DisableKeepAlives were set. + * ModTime is the time the blob was last modified. */ - close: boolean + modTime: time.Time /** - * For server requests, Host specifies the host on which the - * URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this - * is either the value of the "Host" header or the host name - * given in the URL itself. For HTTP/2, it is the value of the - * ":authority" pseudo-header field. - * It may be of the form "host:port". For international domain - * names, Host may be in Punycode or Unicode form. Use - * golang.org/x/net/idna to convert it to either format if - * needed. - * To prevent DNS rebinding attacks, server Handlers should - * validate that the Host header has a value for which the - * Handler considers itself authoritative. The included - * ServeMux supports patterns registered to particular host - * names and thus protects its registered Handlers. - * - * For client requests, Host optionally overrides the Host - * header to send. If empty, the Request.Write method uses - * the value of URL.Host. Host may contain an international - * domain name. + * Size is the size of the blob's content in bytes. */ - host: string + size: number /** - * Form contains the parsed form data, including both the URL - * field's query parameters and the PATCH, POST, or PUT form data. - * This field is only available after ParseForm is called. - * The HTTP client ignores Form and uses Body instead. + * MD5 is an MD5 hash of the blob contents or nil if not available. */ - form: url.Values + md5: string|Array /** - * PostForm contains the parsed form data from PATCH, POST - * or PUT body parameters. - * - * This field is only available after ParseForm is called. - * The HTTP client ignores PostForm and uses Body instead. + * IsDir indicates that this result represents a "directory" in the + * hierarchical namespace, ending in ListOptions.Delimiter. Key can be + * passed as ListOptions.Prefix to list items in the "directory". + * Fields other than Key and IsDir will not be set if IsDir is true. */ - postForm: url.Values + isDir: boolean + } + /** + * Attributes contains attributes about a blob. + */ + interface Attributes { /** - * MultipartForm is the parsed multipart form, including file uploads. - * This field is only available after ParseMultipartForm is called. - * The HTTP client ignores MultipartForm and uses Body instead. + * CacheControl specifies caching attributes that services may use + * when serving the blob. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control */ - multipartForm?: multipart.Form + cacheControl: string /** - * Trailer specifies additional headers that are sent after the request - * body. - * - * For server requests, the Trailer map initially contains only the - * trailer keys, with nil values. (The client declares which trailers it - * will later send.) While the handler is reading from Body, it must - * not reference Trailer. After reading from Body returns EOF, Trailer - * can be read again and will contain non-nil values, if they were sent - * by the client. - * - * For client requests, Trailer must be initialized to a map containing - * the trailer keys to later send. The values may be nil or their final - * values. The ContentLength must be 0 or -1, to send a chunked request. - * After the HTTP request is sent the map values can be updated while - * the request body is read. Once the body returns EOF, the caller must - * not mutate Trailer. - * - * Few HTTP clients, servers, or proxies support HTTP trailers. + * ContentDisposition specifies whether the blob content is expected to be + * displayed inline or as an attachment. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition */ - trailer: Header + contentDisposition: string /** - * RemoteAddr allows HTTP servers and other software to record - * the network address that sent the request, usually for - * logging. This field is not filled in by ReadRequest and - * has no defined format. The HTTP server in this package - * sets RemoteAddr to an "IP:port" address before invoking a - * handler. - * This field is ignored by the HTTP client. + * ContentEncoding specifies the encoding used for the blob's content, if any. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding */ - remoteAddr: string + contentEncoding: string /** - * RequestURI is the unmodified request-target of the - * Request-Line (RFC 7230, Section 3.1.1) as sent by the client - * to a server. Usually the URL field should be used instead. - * It is an error to set this field in an HTTP client request. + * ContentLanguage specifies the language used in the blob's content, if any. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language */ - requestURI: string + contentLanguage: string /** - * TLS allows HTTP servers and other software to record - * information about the TLS connection on which the request - * was received. This field is not filled in by ReadRequest. - * The HTTP server in this package sets the field for - * TLS-enabled connections before invoking a handler; - * otherwise it leaves the field nil. - * This field is ignored by the HTTP client. + * ContentType is the MIME type of the blob. It will not be empty. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type */ - tls?: any + contentType: string /** - * Cancel is an optional channel whose closure indicates that the client - * request should be regarded as canceled. Not all implementations of - * RoundTripper may support Cancel. - * - * For server requests, this field is not applicable. - * - * Deprecated: Set the Request's context with NewRequestWithContext - * instead. If a Request's Cancel field and context are both - * set, it is undefined whether Cancel is respected. + * Metadata holds key/value pairs associated with the blob. + * Keys are guaranteed to be in lowercase, even if the backend service + * has case-sensitive keys (although note that Metadata written via + * this package will always be lowercased). If there are duplicate + * case-insensitive keys (e.g., "foo" and "FOO"), only one value + * will be kept, and it is undefined which one. */ - cancel: undefined + metadata: _TygojaDict + /** + * CreateTime is the time the blob was created, if available. If not available, + * CreateTime will be the zero time. + */ + createTime: time.Time + /** + * ModTime is the time the blob was last modified. + */ + modTime: time.Time + /** + * Size is the size of the blob's content in bytes. + */ + size: number /** - * Response is the redirect response which caused this request - * to be created. This field is only populated during client - * redirects. + * MD5 is an MD5 hash of the blob contents or nil if not available. */ - response?: Response + md5: string|Array /** - * Pattern is the [ServeMux] pattern that matched the request. - * It is empty if the request was not matched against a pattern. + * ETag for the blob; see https://en.wikipedia.org/wiki/HTTP_ETag. */ - pattern: string + eTag: string } - interface Request { + /** + * WriterOptions sets options for NewWriter. + */ + interface WriterOptions { /** - * Context returns the request's context. To change the context, use - * [Request.Clone] or [Request.WithContext]. + * BufferSize changes the default size in bytes of the chunks that + * Writer will upload in a single request; larger blobs will be split into + * multiple requests. * - * The returned context is always non-nil; it defaults to the - * background context. + * This option may be ignored by some drivers. * - * For outgoing client requests, the context controls cancellation. + * If 0, the driver will choose a reasonable default. * - * For incoming server requests, the context is canceled when the - * client's connection closes, the request is canceled (with HTTP/2), - * or when the ServeHTTP method returns. + * If the Writer is used to do many small writes concurrently, using a + * smaller BufferSize may reduce memory usage. */ - context(): context.Context - } - interface Request { + bufferSize: number /** - * WithContext returns a shallow copy of r with its context changed - * to ctx. The provided ctx must be non-nil. + * MaxConcurrency changes the default concurrency for parts of an upload. * - * For outgoing client request, the context controls the entire - * lifetime of a request and its response: obtaining a connection, - * sending the request, and reading the response headers and body. + * This option may be ignored by some drivers. * - * To create a new request with a context, use [NewRequestWithContext]. - * To make a deep copy of a request with a new context, use [Request.Clone]. + * If 0, the driver will choose a reasonable default. */ - withContext(ctx: context.Context): (Request) - } - interface Request { + maxConcurrency: number /** - * Clone returns a deep copy of r with its context changed to ctx. - * The provided ctx must be non-nil. - * - * Clone only makes a shallow copy of the Body field. - * - * For an outgoing client request, the context controls the entire - * lifetime of a request and its response: obtaining a connection, - * sending the request, and reading the response headers and body. + * CacheControl specifies caching attributes that services may use + * when serving the blob. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control */ - clone(ctx: context.Context): (Request) - } - interface Request { + cacheControl: string /** - * ProtoAtLeast reports whether the HTTP protocol used - * in the request is at least major.minor. + * ContentDisposition specifies whether the blob content is expected to be + * displayed inline or as an attachment. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition */ - protoAtLeast(major: number, minor: number): boolean - } - interface Request { + contentDisposition: string /** - * UserAgent returns the client's User-Agent, if sent in the request. + * ContentEncoding specifies the encoding used for the blob's content, if any. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding */ - userAgent(): string + contentEncoding: string + /** + * ContentLanguage specifies the language used in the blob's content, if any. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language + */ + contentLanguage: string + /** + * ContentType specifies the MIME type of the blob being written. If not set, + * it will be inferred from the content using the algorithm described at + * http://mimesniff.spec.whatwg.org/. + * Set DisableContentTypeDetection to true to disable the above and force + * the ContentType to stay empty. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + */ + contentType: string + /** + * When true, if ContentType is the empty string, it will stay the empty + * string rather than being inferred from the content. + * Note that while the blob will be written with an empty string ContentType, + * most providers will fill one in during reads, so don't expect an empty + * ContentType if you read the blob back. + */ + disableContentTypeDetection: boolean + /** + * ContentMD5 is used as a message integrity check. + * If len(ContentMD5) > 0, the MD5 hash of the bytes written must match + * ContentMD5, or Close will return an error without completing the write. + * https://tools.ietf.org/html/rfc1864 + */ + contentMD5: string|Array + /** + * Metadata holds key/value strings to be associated with the blob, or nil. + * Keys may not be empty, and are lowercased before being written. + * Duplicate case-insensitive keys (e.g., "foo" and "FOO") will result in + * an error. + */ + metadata: _TygojaDict } - interface Request { + /** + * Reader reads bytes from a blob. + * It implements io.ReadSeekCloser, and must be closed after reads are finished. + */ + interface Reader { + } + interface Reader { /** - * Cookies parses and returns the HTTP cookies sent with the request. + * Read implements io.Reader (https://golang.org/pkg/io/#Reader). */ - cookies(): Array<(Cookie | undefined)> + read(p: string|Array): number } - interface Request { + interface Reader { /** - * CookiesNamed parses and returns the named HTTP cookies sent with the request - * or an empty slice if none matched. + * Seek implements io.Seeker (https://golang.org/pkg/io/#Seeker). */ - cookiesNamed(name: string): Array<(Cookie | undefined)> + seek(offset: number, whence: number): number } - interface Request { + interface Reader { /** - * Cookie returns the named cookie provided in the request or - * [ErrNoCookie] if not found. - * If multiple cookies match the given name, only one cookie will - * be returned. + * Close implements io.Closer (https://golang.org/pkg/io/#Closer). */ - cookie(name: string): (Cookie) + close(): void } - interface Request { + interface Reader { /** - * AddCookie adds a cookie to the request. Per RFC 6265 section 5.4, - * AddCookie does not attach more than one [Cookie] header field. That - * means all cookies, if any, are written into the same line, - * separated by semicolon. - * AddCookie only sanitizes c's name and value, and does not sanitize - * a Cookie header already present in the request. + * ContentType returns the MIME type of the blob. */ - addCookie(c: Cookie): void + contentType(): string } - interface Request { + interface Reader { /** - * Referer returns the referring URL, if sent in the request. - * - * Referer is misspelled as in the request itself, a mistake from the - * earliest days of HTTP. This value can also be fetched from the - * [Header] map as Header["Referer"]; the benefit of making it available - * as a method is that the compiler can diagnose programs that use the - * alternate (correct English) spelling req.Referrer() but cannot - * diagnose programs that use Header["Referrer"]. + * ModTime returns the time the blob was last modified. */ - referer(): string + modTime(): time.Time } - interface Request { + interface Reader { /** - * MultipartReader returns a MIME multipart reader if this is a - * multipart/form-data or a multipart/mixed POST request, else returns nil and an error. - * Use this function instead of [Request.ParseMultipartForm] to - * process the request body as a stream. + * Size returns the size of the blob content in bytes. */ - multipartReader(): (multipart.Reader) + size(): number } - interface Request { + interface Reader { /** - * Write writes an HTTP/1.1 request, which is the header and body, in wire format. - * This method consults the following fields of the request: - * - * ``` - * Host - * URL - * Method (defaults to "GET") - * Header - * ContentLength - * TransferEncoding - * Body - * ``` + * WriteTo reads from r and writes to w until there's no more data or + * an error occurs. + * The return value is the number of bytes written to w. * - * If Body is present, Content-Length is <= 0 and [Request.TransferEncoding] - * hasn't been set to "identity", Write adds "Transfer-Encoding: - * chunked" to the header. Body is closed after it is sent. + * It implements the io.WriterTo interface. */ - write(w: io.Writer): void + writeTo(w: io.Writer): number } - interface Request { + /** + * Writer writes bytes to a blob. + * + * It implements io.WriteCloser (https://golang.org/pkg/io/#Closer), and must be + * closed after all writes are done. + */ + interface Writer { + } + interface Writer { /** - * WriteProxy is like [Request.Write] but writes the request in the form - * expected by an HTTP proxy. In particular, [Request.WriteProxy] writes the - * initial Request-URI line of the request with an absolute URI, per - * section 5.3 of RFC 7230, including the scheme and host. - * In either case, WriteProxy also writes a Host header, using - * either r.Host or r.URL.Host. + * Write implements the io.Writer interface (https://golang.org/pkg/io/#Writer). + * + * Writes may happen asynchronously, so the returned error can be nil + * even if the actual write eventually fails. The write is only guaranteed to + * have succeeded if Close returns no error. */ - writeProxy(w: io.Writer): void + write(p: string|Array): number } - interface Request { + interface Writer { /** - * BasicAuth returns the username and password provided in the request's - * Authorization header, if the request uses HTTP Basic Authentication. - * See RFC 2617, Section 2. + * Close closes the blob writer. The write operation is not guaranteed + * to have succeeded until Close returns with no error. + * + * Close may return an error if the context provided to create the + * Writer is canceled or reaches its deadline. */ - basicAuth(): [string, string, boolean] + close(): void } - interface Request { + interface Writer { /** - * SetBasicAuth sets the request's Authorization header to use HTTP - * Basic Authentication with the provided username and password. - * - * With HTTP Basic Authentication the provided username and password - * are not encrypted. It should generally only be used in an HTTPS - * request. + * ReadFrom reads from r and writes to w until EOF or error. + * The return value is the number of bytes read from r. * - * The username may not contain a colon. Some protocols may impose - * additional requirements on pre-escaping the username and - * password. For instance, when used with OAuth2, both arguments must - * be URL encoded first with [url.QueryEscape]. + * It implements the io.ReaderFrom interface. */ - setBasicAuth(username: string, password: string): void + readFrom(r: io.Reader): number } - interface Request { +} + +namespace store { + /** + * Store defines a concurrent safe in memory key-value data store. + */ + interface Store { + } + interface Store { /** - * ParseForm populates r.Form and r.PostForm. - * - * For all requests, ParseForm parses the raw query from the URL and updates - * r.Form. - * - * For POST, PUT, and PATCH requests, it also reads the request body, parses it - * as a form and puts the results into both r.PostForm and r.Form. Request body - * parameters take precedence over URL query string values in r.Form. - * - * If the request Body's size has not already been limited by [MaxBytesReader], - * the size is capped at 10MB. - * - * For other HTTP methods, or when the Content-Type is not - * application/x-www-form-urlencoded, the request Body is not read, and - * r.PostForm is initialized to a non-nil, empty value. - * - * [Request.ParseMultipartForm] calls ParseForm automatically. - * ParseForm is idempotent. + * Reset clears the store and replaces the store data with a + * shallow copy of the provided newData. */ - parseForm(): void + reset(newData: _TygojaDict): void } - interface Request { + interface Store { /** - * ParseMultipartForm parses a request body as multipart/form-data. - * The whole request body is parsed and up to a total of maxMemory bytes of - * its file parts are stored in memory, with the remainder stored on - * disk in temporary files. - * ParseMultipartForm calls [Request.ParseForm] if necessary. - * If ParseForm returns an error, ParseMultipartForm returns it but also - * continues parsing the request body. - * After one call to ParseMultipartForm, subsequent calls have no effect. + * Length returns the current number of elements in the store. */ - parseMultipartForm(maxMemory: number): void + length(): number } - interface Request { + interface Store { + /** + * RemoveAll removes all the existing store entries. + */ + removeAll(): void + } + interface Store { /** - * FormValue returns the first value for the named component of the query. - * The precedence order: - * 1. application/x-www-form-urlencoded form body (POST, PUT, PATCH only) - * 2. query parameters (always) - * 3. multipart/form-data form body (always) + * Remove removes a single entry from the store. * - * FormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] - * if necessary and ignores any errors returned by these functions. - * If key is not present, FormValue returns the empty string. - * To access multiple values of the same key, call ParseForm and - * then inspect [Request.Form] directly. + * Remove does nothing if key doesn't exist in the store. */ - formValue(key: string): string + remove(key: K): void } - interface Request { + interface Store { /** - * PostFormValue returns the first value for the named component of the POST, - * PUT, or PATCH request body. URL query parameters are ignored. - * PostFormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary and ignores - * any errors returned by these functions. - * If key is not present, PostFormValue returns the empty string. + * Has checks if element with the specified key exist or not. */ - postFormValue(key: string): string + has(key: K): boolean } - interface Request { + interface Store { /** - * FormFile returns the first file for the provided form key. - * FormFile calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary. + * Get returns a single element value from the store. + * + * If key is not set, the zero T value is returned. */ - formFile(key: string): [multipart.File, (multipart.FileHeader)] + get(key: K): T } - interface Request { + interface Store { /** - * PathValue returns the value for the named path wildcard in the [ServeMux] pattern - * that matched the request. - * It returns the empty string if the request was not matched against a pattern - * or there is no such wildcard in the pattern. + * GetOk is similar to Get but returns also a boolean indicating whether the key exists or not. */ - pathValue(name: string): string + getOk(key: K): [T, boolean] } - interface Request { + interface Store { /** - * SetPathValue sets name to value, so that subsequent calls to r.PathValue(name) - * return value. + * GetAll returns a shallow copy of the current store data. */ - setPathValue(name: string, value: string): void - } - /** - * A Handler responds to an HTTP request. - * - * [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter] - * and then return. Returning signals that the request is finished; it - * is not valid to use the [ResponseWriter] or read from the - * [Request.Body] after or concurrently with the completion of the - * ServeHTTP call. - * - * Depending on the HTTP client software, HTTP protocol version, and - * any intermediaries between the client and the Go server, it may not - * be possible to read from the [Request.Body] after writing to the - * [ResponseWriter]. Cautious handlers should read the [Request.Body] - * first, and then reply. - * - * Except for reading the body, handlers should not modify the - * provided Request. - * - * If ServeHTTP panics, the server (the caller of ServeHTTP) assumes - * that the effect of the panic was isolated to the active request. - * It recovers the panic, logs a stack trace to the server error log, - * and either closes the network connection or sends an HTTP/2 - * RST_STREAM, depending on the HTTP protocol. To abort a handler so - * the client sees an interrupted response but the server doesn't log - * an error, panic with the value [ErrAbortHandler]. - */ - interface Handler { - [key:string]: any; - serveHTTP(_arg0: ResponseWriter, _arg1: Request): void + getAll(): _TygojaDict } - /** - * A ResponseWriter interface is used by an HTTP handler to - * construct an HTTP response. - * - * A ResponseWriter may not be used after [Handler.ServeHTTP] has returned. - */ - interface ResponseWriter { - [key:string]: any; + interface Store { /** - * Header returns the header map that will be sent by - * [ResponseWriter.WriteHeader]. The [Header] map also is the mechanism with which - * [Handler] implementations can set HTTP trailers. - * - * Changing the header map after a call to [ResponseWriter.WriteHeader] (or - * [ResponseWriter.Write]) has no effect unless the HTTP status code was of the - * 1xx class or the modified headers are trailers. - * - * There are two ways to set Trailers. The preferred way is to - * predeclare in the headers which trailers you will later - * send by setting the "Trailer" header to the names of the - * trailer keys which will come later. In this case, those - * keys of the Header map are treated as if they were - * trailers. See the example. The second way, for trailer - * keys not known to the [Handler] until after the first [ResponseWriter.Write], - * is to prefix the [Header] map keys with the [TrailerPrefix] - * constant value. - * - * To suppress automatic response headers (such as "Date"), set - * their value to nil. + * Values returns a slice with all of the current store values. */ - header(): Header + values(): Array + } + interface Store { /** - * Write writes the data to the connection as part of an HTTP reply. - * - * If [ResponseWriter.WriteHeader] has not yet been called, Write calls - * WriteHeader(http.StatusOK) before writing the data. If the Header - * does not contain a Content-Type line, Write adds a Content-Type set - * to the result of passing the initial 512 bytes of written data to - * [DetectContentType]. Additionally, if the total size of all written - * data is under a few KB and there are no Flush calls, the - * Content-Length header is added automatically. - * - * Depending on the HTTP protocol version and the client, calling - * Write or WriteHeader may prevent future reads on the - * Request.Body. For HTTP/1.x requests, handlers should read any - * needed request body data before writing the response. Once the - * headers have been flushed (due to either an explicit Flusher.Flush - * call or writing enough data to trigger a flush), the request body - * may be unavailable. For HTTP/2 requests, the Go HTTP server permits - * handlers to continue to read the request body while concurrently - * writing the response. However, such behavior may not be supported - * by all HTTP/2 clients. Handlers should read before writing if - * possible to maximize compatibility. + * Set sets (or overwrite if already exists) a new value for key. */ - write(_arg0: string|Array): number + set(key: K, value: T): void + } + interface Store { /** - * WriteHeader sends an HTTP response header with the provided - * status code. + * SetFunc sets (or overwrite if already exists) a new value resolved + * from the function callback for the provided key. * - * If WriteHeader is not called explicitly, the first call to Write - * will trigger an implicit WriteHeader(http.StatusOK). - * Thus explicit calls to WriteHeader are mainly used to - * send error codes or 1xx informational responses. + * The function callback receives as argument the old store element value (if exists). + * If there is no old store element, the argument will be the T zero value. * - * The provided code must be a valid HTTP 1xx-5xx status code. - * Any number of 1xx headers may be written, followed by at most - * one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx - * headers may be buffered. Use the Flusher interface to send - * buffered data. The header map is cleared when 2xx-5xx headers are - * sent, but not with 1xx headers. + * Example: * - * The server will automatically send a 100 (Continue) header - * on the first read from the request body if the request has - * an "Expect: 100-continue" header. + * ``` + * s := store.New[string, int](nil) + * s.SetFunc("count", func(old int) int { + * return old + 1 + * }) + * ``` */ - writeHeader(statusCode: number): void + setFunc(key: K, fn: (old: T) => T): void } - /** - * A Server defines parameters for running an HTTP server. - * The zero value for Server is a valid configuration. - */ - interface Server { - /** - * Addr optionally specifies the TCP address for the server to listen on, - * in the form "host:port". If empty, ":http" (port 80) is used. - * The service names are defined in RFC 6335 and assigned by IANA. - * See net.Dial for details of the address format. - */ - addr: string - handler: Handler // handler to invoke, http.DefaultServeMux if nil - /** - * DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler, - * otherwise responds with 200 OK and Content-Length: 0. - */ - disableGeneralOptionsHandler: boolean + interface Store { /** - * TLSConfig optionally provides a TLS configuration for use - * by ServeTLS and ListenAndServeTLS. Note that this value is - * cloned by ServeTLS and ListenAndServeTLS, so it's not - * possible to modify the configuration with methods like - * tls.Config.SetSessionTicketKeys. To use - * SetSessionTicketKeys, use Server.Serve with a TLS Listener - * instead. + * GetOrSet retrieves a single existing value for the provided key + * or stores a new one if it doesn't exist. */ - tlsConfig?: any + getOrSet(key: K, setFunc: () => T): T + } + interface Store { /** - * ReadTimeout is the maximum duration for reading the entire - * request, including the body. A zero or negative value means - * there will be no timeout. + * SetIfLessThanLimit sets (or overwrite if already exist) a new value for key. * - * Because ReadTimeout does not let Handlers make per-request - * decisions on each request body's acceptable deadline or - * upload rate, most users will prefer to use - * ReadHeaderTimeout. It is valid to use them both. + * This method is similar to Set() but **it will skip adding new elements** + * to the store if the store length has reached the specified limit. + * false is returned if maxAllowedElements limit is reached. */ - readTimeout: time.Duration + setIfLessThanLimit(key: K, value: T, maxAllowedElements: number): boolean + } + interface Store { /** - * ReadHeaderTimeout is the amount of time allowed to read - * request headers. The connection's read deadline is reset - * after reading the headers and the Handler can decide what - * is considered too slow for the body. If zero, the value of - * ReadTimeout is used. If negative, or if zero and ReadTimeout - * is zero or negative, there is no timeout. + * UnmarshalJSON implements [json.Unmarshaler] and imports the + * provided JSON data into the store. + * + * The store entries that match with the ones from the data will be overwritten with the new value. */ - readHeaderTimeout: time.Duration + unmarshalJSON(data: string|Array): void + } + interface Store { /** - * WriteTimeout is the maximum duration before timing out - * writes of the response. It is reset whenever a new - * request's header is read. Like ReadTimeout, it does not - * let Handlers make decisions on a per-request basis. - * A zero or negative value means there will be no timeout. + * MarshalJSON implements [json.Marshaler] and export the current + * store data into valid JSON. */ - writeTimeout: time.Duration + marshalJSON(): string|Array + } +} + +/** + * Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html + * + * See README.md for more info. + */ +namespace jwt { + /** + * MapClaims is a claims type that uses the map[string]any for JSON + * decoding. This is the default claims type if you don't supply one + */ + interface MapClaims extends _TygojaDict{} + interface MapClaims { /** - * IdleTimeout is the maximum amount of time to wait for the - * next request when keep-alives are enabled. If zero, the value - * of ReadTimeout is used. If negative, or if zero and ReadTimeout - * is zero or negative, there is no timeout. + * GetExpirationTime implements the Claims interface. */ - idleTimeout: time.Duration + getExpirationTime(): (NumericDate) + } + interface MapClaims { /** - * MaxHeaderBytes controls the maximum number of bytes the - * server will read parsing the request header's keys and - * values, including the request line. It does not limit the - * size of the request body. - * If zero, DefaultMaxHeaderBytes is used. + * GetNotBefore implements the Claims interface. */ - maxHeaderBytes: number + getNotBefore(): (NumericDate) + } + interface MapClaims { /** - * TLSNextProto optionally specifies a function to take over - * ownership of the provided TLS connection when an ALPN - * protocol upgrade has occurred. The map key is the protocol - * name negotiated. The Handler argument should be used to - * handle HTTP requests and will initialize the Request's TLS - * and RemoteAddr if not already set. The connection is - * automatically closed when the function returns. - * If TLSNextProto is not nil, HTTP/2 support is not enabled - * automatically. + * GetIssuedAt implements the Claims interface. */ - tlsNextProto: _TygojaDict + getIssuedAt(): (NumericDate) + } + interface MapClaims { /** - * ConnState specifies an optional callback function that is - * called when a client connection changes state. See the - * ConnState type and associated constants for details. + * GetAudience implements the Claims interface. */ - connState: (_arg0: net.Conn, _arg1: ConnState) => void + getAudience(): ClaimStrings + } + interface MapClaims { /** - * ErrorLog specifies an optional logger for errors accepting - * connections, unexpected behavior from handlers, and - * underlying FileSystem errors. - * If nil, logging is done via the log package's standard logger. + * GetIssuer implements the Claims interface. */ - errorLog?: any + getIssuer(): string + } + interface MapClaims { /** - * BaseContext optionally specifies a function that returns - * the base context for incoming requests on this server. - * The provided Listener is the specific Listener that's - * about to start accepting requests. - * If BaseContext is nil, the default is context.Background(). - * If non-nil, it must return a non-nil context. + * GetSubject implements the Claims interface. */ - baseContext: (_arg0: net.Listener) => context.Context + getSubject(): string + } +} + +namespace hook { + /** + * Event implements [Resolver] and it is intended to be used as a base + * Hook event that you can embed in your custom typed event structs. + * + * Example: + * + * ``` + * type CustomEvent struct { + * hook.Event + * + * SomeField int + * } + * ``` + */ + interface Event { + } + interface Event { /** - * ConnContext optionally specifies a function that modifies - * the context used for a new connection c. The provided ctx - * is derived from the base context and has a ServerContextKey - * value. + * Next calls the next hook handler. */ - connContext: (ctx: context.Context, c: net.Conn) => context.Context + next(): void + } + /** + * Handler defines a single Hook handler. + * Multiple handlers can share the same id. + * If Id is not explicitly set it will be autogenerated by Hook.Add and Hook.AddHandler. + */ + interface Handler { /** - * HTTP2 configures HTTP/2 connections. + * Func defines the handler function to execute. * - * This field does not yet have any effect. - * See https://go.dev/issue/67813. + * Note that users need to call e.Next() in order to proceed with + * the execution of the hook chain. */ - http2?: HTTP2Config + func: (_arg0: T) => void /** - * Protocols is the set of protocols accepted by the server. + * Id is the unique identifier of the handler. * - * If Protocols includes UnencryptedHTTP2, the server will accept - * unencrypted HTTP/2 connections. The server can serve both - * HTTP/1 and unencrypted HTTP/2 on the same address and port. + * It could be used later to remove the handler from a hook via [Hook.Remove]. * - * If Protocols is nil, the default is usually HTTP/1 and HTTP/2. - * If TLSNextProto is non-nil and does not contain an "h2" entry, - * the default is HTTP/1 only. + * If missing, an autogenerated value will be assigned when adding + * the handler to a hook. */ - protocols?: Protocols + id: string + /** + * Priority allows changing the default exec priority of the handler within a hook. + * + * If 0, the handler will be executed in the same order it was registered. + */ + priority: number } - interface Server { + /** + * Hook defines a generic concurrent safe structure for managing event hooks. + * + * When using custom event it must embed the base [hook.Event]. + * + * Example: + * + * ``` + * type CustomEvent struct { + * hook.Event + * SomeField int + * } + * + * h := Hook[*CustomEvent]{} + * + * h.BindFunc(func(e *CustomEvent) error { + * println(e.SomeField) + * + * return e.Next() + * }) + * + * h.Trigger(&CustomEvent{ SomeField: 123 }) + * ``` + */ + interface Hook { + } + interface Hook { /** - * Close immediately closes all active net.Listeners and any - * connections in state [StateNew], [StateActive], or [StateIdle]. For a - * graceful shutdown, use [Server.Shutdown]. + * Bind registers the provided handler to the current hooks queue. * - * Close does not attempt to close (and does not even know about) - * any hijacked connections, such as WebSockets. + * If handler.Id is empty it is updated with autogenerated value. * - * Close returns any error returned from closing the [Server]'s - * underlying Listener(s). + * If a handler from the current hook list has Id matching handler.Id + * then the old handler is replaced with the new one. */ - close(): void + bind(handler: Handler): string } - interface Server { + interface Hook { /** - * Shutdown gracefully shuts down the server without interrupting any - * active connections. Shutdown works by first closing all open - * listeners, then closing all idle connections, and then waiting - * indefinitely for connections to return to idle and then shut down. - * If the provided context expires before the shutdown is complete, - * Shutdown returns the context's error, otherwise it returns any - * error returned from closing the [Server]'s underlying Listener(s). - * - * When Shutdown is called, [Serve], [ServeTLS], [ListenAndServe], and - * [ListenAndServeTLS] immediately return [ErrServerClosed]. Make sure the - * program doesn't exit and waits instead for Shutdown to return. + * BindFunc is similar to Bind but registers a new handler from just the provided function. * - * Shutdown does not attempt to close nor wait for hijacked - * connections such as WebSockets. The caller of Shutdown should - * separately notify such long-lived connections of shutdown and wait - * for them to close, if desired. See [Server.RegisterOnShutdown] for a way to - * register shutdown notification functions. + * The registered handler is added with a default 0 priority and the id will be autogenerated. * - * Once Shutdown has been called on a server, it may not be reused; - * future calls to methods such as Serve will return ErrServerClosed. + * If you want to register a handler with custom priority or id use the [Hook.Bind] method. */ - shutdown(ctx: context.Context): void + bindFunc(fn: (e: T) => void): string } - interface Server { + interface Hook { /** - * RegisterOnShutdown registers a function to call on [Server.Shutdown]. - * This can be used to gracefully shutdown connections that have - * undergone ALPN protocol upgrade or that have been hijacked. - * This function should start protocol-specific graceful shutdown, - * but should not wait for shutdown to complete. + * Unbind removes one or many hook handler by their id. */ - registerOnShutdown(f: () => void): void + unbind(...idsToRemove: string[]): void } - interface Server { + interface Hook { /** - * ListenAndServe listens on the TCP network address s.Addr and then - * calls [Serve] to handle requests on incoming connections. - * Accepted connections are configured to enable TCP keep-alives. - * - * If s.Addr is blank, ":http" is used. - * - * ListenAndServe always returns a non-nil error. After [Server.Shutdown] or [Server.Close], - * the returned error is [ErrServerClosed]. + * UnbindAll removes all registered handlers. */ - listenAndServe(): void + unbindAll(): void } - interface Server { + interface Hook { /** - * Serve accepts incoming connections on the Listener l, creating a - * new service goroutine for each. The service goroutines read requests and - * then call s.Handler to reply to them. - * - * HTTP/2 support is only enabled if the Listener returns [*tls.Conn] - * connections and they were configured with "h2" in the TLS - * Config.NextProtos. - * - * Serve always returns a non-nil error and closes l. - * After [Server.Shutdown] or [Server.Close], the returned error is [ErrServerClosed]. + * Length returns to total number of registered hook handlers. */ - serve(l: net.Listener): void + length(): number } - interface Server { + interface Hook { /** - * ServeTLS accepts incoming connections on the Listener l, creating a - * new service goroutine for each. The service goroutines perform TLS - * setup and then read requests, calling s.Handler to reply to them. + * Trigger executes all registered hook handlers one by one + * with the specified event as an argument. * - * Files containing a certificate and matching private key for the - * server must be provided if neither the [Server]'s - * TLSConfig.Certificates, TLSConfig.GetCertificate nor - * config.GetConfigForClient are populated. - * If the certificate is signed by a certificate authority, the - * certFile should be the concatenation of the server's certificate, - * any intermediates, and the CA's certificate. + * Optionally, this method allows also to register additional one off + * handler funcs that will be temporary appended to the handlers queue. * - * ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the - * returned error is [ErrServerClosed]. + * NB! Each hook handler must call event.Next() in order the hook chain to proceed. */ - serveTLS(l: net.Listener, certFile: string, keyFile: string): void + trigger(event: T, ...oneOffHandlerFuncs: ((_arg0: T) => void)[]): void } - interface Server { + /** + * TaggedHook defines a proxy hook which register handlers that are triggered only + * if the TaggedHook.tags are empty or includes at least one of the event data tag(s). + */ + type _sJTSkQl = mainHook + interface TaggedHook extends _sJTSkQl { + } + interface TaggedHook { /** - * SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. - * By default, keep-alives are always enabled. Only very - * resource-constrained environments or servers in the process of - * shutting down should disable them. + * CanTriggerOn checks if the current TaggedHook can be triggered with + * the provided event data tags. + * + * It returns always true if the hook doesn't have any tags. */ - setKeepAlivesEnabled(v: boolean): void + canTriggerOn(tagsToCheck: Array): boolean } - interface Server { + interface TaggedHook { /** - * ListenAndServeTLS listens on the TCP network address s.Addr and - * then calls [ServeTLS] to handle requests on incoming TLS connections. - * Accepted connections are configured to enable TCP keep-alives. - * - * Filenames containing a certificate and matching private key for the - * server must be provided if neither the [Server]'s TLSConfig.Certificates - * nor TLSConfig.GetCertificate are populated. If the certificate is - * signed by a certificate authority, the certFile should be the - * concatenation of the server's certificate, any intermediates, and - * the CA's certificate. + * Bind registers the provided handler to the current hooks queue. * - * If s.Addr is blank, ":https" is used. + * It is similar to [Hook.Bind] with the difference that the handler + * function is invoked only if the event data tags satisfy h.CanTriggerOn. + */ + bind(handler: Handler): string + } + interface TaggedHook { + /** + * BindFunc registers a new handler with the specified function. * - * ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or - * [Server.Close], the returned error is [ErrServerClosed]. + * It is similar to [Hook.Bind] with the difference that the handler + * function is invoked only if the event data tags satisfy h.CanTriggerOn. */ - listenAndServeTLS(certFile: string, keyFile: string): void + bindFunc(fn: (e: T) => void): string } } @@ -19241,848 +19581,502 @@ namespace types { } } -namespace auth { +namespace search { /** - * @todo refactor and consider replace with a plain struct - * - * Provider defines a common interface for an OAuth2 client. + * Result defines the returned search result structure. */ - interface Provider { - [key:string]: any; - /** - * @todo temp backport - * - * Order returns the sorting order of the provider usually used in the auth methods list response. - */ - logo(): string - /** - * @todo temp backport - * - * Order returns the sorting order of the provider usually used in the auth methods list response. - */ - order(): number - /** - * Context returns the context associated with the provider (if any). - */ - context(): context.Context - /** - * SetContext assigns the specified context to the current provider. - */ - setContext(ctx: context.Context): void - /** - * PKCE indicates whether the provider can use the PKCE flow. - */ - pkce(): boolean - /** - * SetPKCE toggles the state whether the provider can use the PKCE flow or not. - */ - setPKCE(enable: boolean): void - /** - * DisplayName usually returns provider name as it is officially written - * and it could be used directly in the UI. - */ - displayName(): string - /** - * SetDisplayName sets the provider's display name. - */ - setDisplayName(displayName: string): void - /** - * Scopes returns the provider access permissions that will be requested. - */ - scopes(): Array - /** - * SetScopes sets the provider access permissions that will be requested later. - */ - setScopes(scopes: Array): void - /** - * ClientId returns the provider client's app ID. - */ - clientId(): string - /** - * SetClientId sets the provider client's ID. - */ - setClientId(clientId: string): void - /** - * ClientSecret returns the provider client's app secret. - */ - clientSecret(): string - /** - * SetClientSecret sets the provider client's app secret. - */ - setClientSecret(secret: string): void - /** - * RedirectURL returns the end address to redirect the user - * going through the OAuth flow. - */ - redirectURL(): string - /** - * SetRedirectURL sets the provider's RedirectURL. - */ - setRedirectURL(url: string): void - /** - * AuthURL returns the provider's authorization service url. - */ - authURL(): string - /** - * SetAuthURL sets the provider's AuthURL. - */ - setAuthURL(url: string): void - /** - * TokenURL returns the provider's token exchange service url. - */ - tokenURL(): string - /** - * SetTokenURL sets the provider's TokenURL. - */ - setTokenURL(url: string): void - /** - * UserInfoURL returns the provider's user info api url. - */ - userInfoURL(): string - /** - * SetUserInfoURL sets the provider's UserInfoURL. - */ - setUserInfoURL(url: string): void - /** - * Extra returns a shallow copy of any custom config data - * that the provider may need. - */ - extra(): _TygojaDict - /** - * SetExtra updates the provider's custom config data. - */ - setExtra(data: _TygojaDict): void - /** - * Client returns an http client using the provided token. - */ - client(token: oauth2.Token): (any) - /** - * BuildAuthURL returns a URL to the provider's consent page - * that asks for permissions for the required scopes explicitly. - */ - buildAuthURL(state: string, ...opts: oauth2.AuthCodeOption[]): string - /** - * FetchToken converts an authorization code to token. - */ - fetchToken(code: string, ...opts: oauth2.AuthCodeOption[]): (oauth2.Token) - /** - * FetchRawUserInfo requests and marshalizes into `result` the - * the OAuth user api response. - */ - fetchRawUserInfo(token: oauth2.Token): string|Array - /** - * FetchAuthUser is similar to FetchRawUserInfo, but normalizes and - * marshalizes the user api response into a standardized AuthUser struct. - */ - fetchAuthUser(token: oauth2.Token): (AuthUser) + interface Result { + items: any + page: number + perPage: number + totalItems: number + totalPages: number } /** - * AuthUser defines a standardized OAuth2 user data structure. + * ResolverResult defines a single FieldResolver.Resolve() successfully parsed result. */ - interface AuthUser { - expiry: types.DateTime - rawUser: _TygojaDict - id: string - name: string - username: string - avatarURL: string - accessToken: string - refreshToken: string + interface ResolverResult { /** - * The VERIFIED OAuth2 account email. - * - * It must be empty if the provider is not able to verify the email ownership. + * Identifier is the plain SQL identifier/column that will be used + * in the final db expression as left or right operand. */ - email: string + identifier: string /** - * @todo - * deprecated: use AvatarURL instead - * AvatarUrl will be removed after dropping v0.22 support + * NullFallback specify the preference for how NULL or empty values + * should be resolved (default to "auto"). + * + * Set to NullFallbackDisabled to prevent any COALESCE or NULL fallbacks. + * Set to NullFallbackEnforced to prefer COALESCE or NULL fallbacks when needed. */ - avatarUrl: string - } - interface AuthUser { + nullFallback: NullFallbackPreference /** - * MarshalJSON implements the [json.Marshaler] interface. - * - * @todo remove after dropping v0.22 support + * Params is a map with db placeholder->value pairs that will be added + * to the query when building both resolved operands/sides in a single expression. */ - marshalJSON(): string|Array - } -} - -/** - * Package sql provides a generic interface around SQL (or SQL-like) - * databases. - * - * The sql package must be used in conjunction with a database driver. - * See https://golang.org/s/sqldrivers for a list of drivers. - * - * Drivers that do not support context cancellation will not return until - * after the query is completed. - * - * For usage examples, see the wiki page at - * https://golang.org/s/sqlwiki. - */ -namespace sql { - /** - * TxOptions holds the transaction options to be used in [DB.BeginTx]. - */ - interface TxOptions { + params: dbx.Params /** - * Isolation is the transaction isolation level. - * If zero, the driver or database's default level is used. + * MultiMatchSubQuery is an optional sub query expression that will be added + * in addition to the combined ResolverResult expression during build. */ - isolation: IsolationLevel - readOnly: boolean - } - /** - * NullString represents a string that may be null. - * NullString implements the [Scanner] interface so - * it can be used as a scan destination: - * - * ``` - * var s NullString - * err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) - * ... - * if s.Valid { - * // use s.String - * } else { - * // NULL value - * } - * ``` + multiMatchSubQuery?: MultiMatchSubquery + /** + * AfterBuild is an optional function that will be called after building + * and combining the result of both resolved operands/sides in a single expression. + */ + afterBuild: (expr: dbx.Expression) => dbx.Expression + } +} + +namespace router { + // @ts-ignore + import validation = ozzo_validation + /** + * ApiError defines the struct for a basic api error response. */ - interface NullString { - string: string - valid: boolean // Valid is true if String is not NULL + interface ApiError { + data: _TygojaDict + message: string + status: number } - interface NullString { + interface ApiError { /** - * Scan implements the [Scanner] interface. + * Error makes it compatible with the `error` interface. */ - scan(value: any): void + error(): string } - interface NullString { + interface ApiError { /** - * Value implements the [driver.Valuer] interface. + * RawData returns the unformatted error data (could be an internal error, text, etc.) */ - value(): any + rawData(): any + } + interface ApiError { + /** + * Is reports whether the current ApiError wraps the target. + */ + is(target: Error): boolean } /** - * DB is a database handle representing a pool of zero or more - * underlying connections. It's safe for concurrent use by multiple - * goroutines. + * Event specifies based Route handler event that is usually intended + * to be embedded as part of a custom event struct. * - * The sql package creates and frees connections automatically; it - * also maintains a free pool of idle connections. If the database has - * a concept of per-connection state, such state can be reliably observed - * within a transaction ([Tx]) or connection ([Conn]). Once [DB.Begin] is called, the - * returned [Tx] is bound to a single connection. Once [Tx.Commit] or - * [Tx.Rollback] is called on the transaction, that transaction's - * connection is returned to [DB]'s idle connection pool. The pool size - * can be controlled with [DB.SetMaxIdleConns]. + * NB! It is expected that the Response and Request fields are always set. */ - interface DB { + type _sysyCdU = hook.Event + interface Event extends _sysyCdU { + response: http.ResponseWriter + request?: http.Request } - interface DB { + interface Event { /** - * PingContext verifies a connection to the database is still alive, - * establishing a connection if necessary. + * Written reports whether the current response has already been written. + * + * This method always returns false if e.ResponseWritter doesn't implement the WriteTracker interface + * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). */ - pingContext(ctx: context.Context): void + written(): boolean } - interface DB { + interface Event { /** - * Ping verifies a connection to the database is still alive, - * establishing a connection if necessary. + * Status reports the status code of the current response. * - * Ping uses [context.Background] internally; to specify the context, use - * [DB.PingContext]. + * This method always returns 0 if e.Response doesn't implement the StatusTracker interface + * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). */ - ping(): void + status(): number } - interface DB { + interface Event { /** - * Close closes the database and prevents new queries from starting. - * Close then waits for all queries that have started processing on the server - * to finish. + * Flush flushes buffered data to the current response. * - * It is rare to Close a [DB], as the [DB] handle is meant to be - * long-lived and shared between many goroutines. + * Returns [http.ErrNotSupported] if e.Response doesn't implement the [http.Flusher] interface + * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). */ - close(): void + flush(): void } - interface DB { + interface Event { /** - * SetMaxIdleConns sets the maximum number of connections in the idle - * connection pool. - * - * If MaxOpenConns is greater than 0 but less than the new MaxIdleConns, - * then the new MaxIdleConns will be reduced to match the MaxOpenConns limit. - * - * If n <= 0, no idle connections are retained. - * - * The default max idle connections is currently 2. This may change in - * a future release. + * IsTLS reports whether the connection on which the request was received is TLS. */ - setMaxIdleConns(n: number): void + isTLS(): boolean } - interface DB { + interface Event { /** - * SetMaxOpenConns sets the maximum number of open connections to the database. - * - * If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than - * MaxIdleConns, then MaxIdleConns will be reduced to match the new - * MaxOpenConns limit. + * SetCookie is an alias for [http.SetCookie]. * - * If n <= 0, then there is no limit on the number of open connections. - * The default is 0 (unlimited). + * SetCookie adds a Set-Cookie header to the current response's headers. + * The provided cookie must have a valid Name. + * Invalid cookies may be silently dropped. */ - setMaxOpenConns(n: number): void + setCookie(cookie: http.Cookie): void } - interface DB { + interface Event { /** - * SetConnMaxLifetime sets the maximum amount of time a connection may be reused. + * RemoteIP returns the IP address of the client that sent the request. * - * Expired connections may be closed lazily before reuse. + * IPv6 addresses are returned expanded. + * For example, "2001:db8::1" becomes "2001:0db8:0000:0000:0000:0000:0000:0001". * - * If d <= 0, connections are not closed due to a connection's age. + * Note that if you are behind reverse proxy(ies), this method returns + * the IP of the last connecting proxy. */ - setConnMaxLifetime(d: time.Duration): void + remoteIP(): string } - interface DB { + interface Event { /** - * SetConnMaxIdleTime sets the maximum amount of time a connection may be idle. - * - * Expired connections may be closed lazily before reuse. - * - * If d <= 0, connections are not closed due to a connection's idle time. + * FindUploadedFiles extracts all form files of "key" from a http request + * and returns a slice with filesystem.File instances (if any). */ - setConnMaxIdleTime(d: time.Duration): void + findUploadedFiles(key: string): Array<(filesystem.File | undefined)> } - interface DB { + interface Event { /** - * Stats returns database statistics. + * Get retrieves single value from the current event data store. */ - stats(): DBStats + get(key: string): any } - interface DB { + interface Event { /** - * PrepareContext creates a prepared statement for later queries or executions. - * Multiple queries or executions may be run concurrently from the - * returned statement. - * The caller must call the statement's [*Stmt.Close] method - * when the statement is no longer needed. - * - * The provided context is used for the preparation of the statement, not for the - * execution of the statement. + * GetAll returns a copy of the current event data store. */ - prepareContext(ctx: context.Context, query: string): (Stmt) + getAll(): _TygojaDict } - interface DB { + interface Event { /** - * Prepare creates a prepared statement for later queries or executions. - * Multiple queries or executions may be run concurrently from the - * returned statement. - * The caller must call the statement's [*Stmt.Close] method - * when the statement is no longer needed. - * - * Prepare uses [context.Background] internally; to specify the context, use - * [DB.PrepareContext]. + * Set saves single value into the current event data store. */ - prepare(query: string): (Stmt) + set(key: string, value: any): void } - interface DB { + interface Event { /** - * ExecContext executes a query without returning any rows. - * The args are for any placeholder parameters in the query. + * SetAll saves all items from m into the current event data store. */ - execContext(ctx: context.Context, query: string, ...args: any[]): Result + setAll(m: _TygojaDict): void } - interface DB { + interface Event { /** - * Exec executes a query without returning any rows. - * The args are for any placeholder parameters in the query. - * - * Exec uses [context.Background] internally; to specify the context, use - * [DB.ExecContext]. + * String writes a plain string response. */ - exec(query: string, ...args: any[]): Result + string(status: number, data: string): void } - interface DB { + interface Event { /** - * QueryContext executes a query that returns rows, typically a SELECT. - * The args are for any placeholder parameters in the query. + * HTML writes an HTML response. */ - queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) + html(status: number, data: string): void } - interface DB { + interface Event { /** - * Query executes a query that returns rows, typically a SELECT. - * The args are for any placeholder parameters in the query. + * JSON writes a JSON response. * - * Query uses [context.Background] internally; to specify the context, use - * [DB.QueryContext]. + * It also provides a generic response data fields picker if the "fields" query parameter is set. + * For example, if you are requesting `?fields=a,b` for `e.JSON(200, map[string]int{ "a":1, "b":2, "c":3 })`, + * it should result in a JSON response like: `{"a":1, "b": 2}`. */ - query(query: string, ...args: any[]): (Rows) + json(status: number, data: any): void } - interface DB { + interface Event { /** - * QueryRowContext executes a query that is expected to return at most one row. - * QueryRowContext always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, [*Row.Scan] scans the first selected row and discards - * the rest. + * XML writes an XML response. + * It automatically prepends the generic [xml.Header] string to the response. */ - queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) + xml(status: number, data: any): void } - interface DB { + interface Event { /** - * QueryRow executes a query that is expected to return at most one row. - * QueryRow always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, [*Row.Scan] scans the first selected row and discards - * the rest. - * - * QueryRow uses [context.Background] internally; to specify the context, use - * [DB.QueryRowContext]. + * Stream streams the specified reader into the response. */ - queryRow(query: string, ...args: any[]): (Row) + stream(status: number, contentType: string, reader: io.Reader): void } - interface DB { + interface Event { /** - * BeginTx starts a transaction. - * - * The provided context is used until the transaction is committed or rolled back. - * If the context is canceled, the sql package will roll back - * the transaction. [Tx.Commit] will return an error if the context provided to - * BeginTx is canceled. - * - * The provided [TxOptions] is optional and may be nil if defaults should be used. - * If a non-default isolation level is used that the driver doesn't support, - * an error will be returned. + * Blob writes a blob (bytes slice) response. */ - beginTx(ctx: context.Context, opts: TxOptions): (Tx) + blob(status: number, contentType: string, b: string|Array): void } - interface DB { + interface Event { /** - * Begin starts a transaction. The default isolation level is dependent on - * the driver. + * FileFS serves the specified filename from fsys. * - * Begin uses [context.Background] internally; to specify the context, use - * [DB.BeginTx]. + * It is similar to [echo.FileFS] for consistency with earlier versions. + */ + fileFS(fsys: fs.FS, filename: string): void + } + interface Event { + /** + * NoContent writes a response with no body (ex. 204). */ - begin(): (Tx) + noContent(status: number): void } - interface DB { + interface Event { /** - * Driver returns the database's underlying driver. + * Redirect writes a redirect response to the specified url. + * The status code must be in between 300 – 399 range. */ - driver(): any + redirect(status: number, url: string): void } - interface DB { + interface Event { + error(status: number, message: string, errData: any): (ApiError) + } + interface Event { + badRequestError(message: string, errData: any): (ApiError) + } + interface Event { + notFoundError(message: string, errData: any): (ApiError) + } + interface Event { + forbiddenError(message: string, errData: any): (ApiError) + } + interface Event { + unauthorizedError(message: string, errData: any): (ApiError) + } + interface Event { + tooManyRequestsError(message: string, errData: any): (ApiError) + } + interface Event { + internalServerError(message: string, errData: any): (ApiError) + } + interface Event { /** - * Conn returns a single connection by either opening a new connection - * or returning an existing connection from the connection pool. Conn will - * block until either a connection is returned or ctx is canceled. - * Queries run on the same Conn will be run in the same database session. + * BindBody unmarshal the request body into the provided dst. * - * Every Conn must be returned to the database pool after use by - * calling [Conn.Close]. + * dst must be either a struct pointer or map[string]any. + * + * The rules how the body will be scanned depends on the request Content-Type. + * + * Currently the following Content-Types are supported: + * ``` + * - application/json + * - text/xml, application/xml + * - multipart/form-data, application/x-www-form-urlencoded + * ``` + * + * Respectively the following struct tags are supported (again, which one will be used depends on the Content-Type): + * ``` + * - "json" (json body)- uses the builtin Go json package for unmarshaling. + * - "xml" (xml body) - uses the builtin Go xml package for unmarshaling. + * - "form" (form data) - utilizes the custom [router.UnmarshalRequestData] method. + * ``` + * + * NB! When dst is a struct make sure that it doesn't have public fields + * that shouldn't be bindable and it is advisible such fields to be unexported + * or have a separate struct just for the binding. For example: + * + * ``` + * data := struct{ + * somethingPrivate string + * + * Title string `json:"title" form:"title"` + * Total int `json:"total" form:"total"` + * }{} + * err := e.BindBody(&data) + * ``` */ - conn(ctx: context.Context): (Conn) + bindBody(dst: any): void } /** - * Tx is an in-progress database transaction. + * Router defines a thin wrapper around the standard Go [http.ServeMux] by + * adding support for routing sub-groups, middlewares and other common utils. * - * A transaction must end with a call to [Tx.Commit] or [Tx.Rollback]. + * Example: * - * After a call to [Tx.Commit] or [Tx.Rollback], all operations on the - * transaction fail with [ErrTxDone]. + * ``` + * r := NewRouter[*MyEvent](eventFactory) * - * The statements prepared for a transaction by calling - * the transaction's [Tx.Prepare] or [Tx.Stmt] methods are closed - * by the call to [Tx.Commit] or [Tx.Rollback]. + * // middlewares + * r.BindFunc(m1, m2) + * + * // routes + * r.GET("/test", handler1) + * + * // sub-routers/groups + * api := r.Group("/api") + * api.GET("/admins", handler2) + * + * // generate a http.ServeMux instance based on the router configurations + * mux, _ := r.BuildMux() + * + * http.ListenAndServe("localhost:8090", mux) + * ``` */ - interface Tx { + type _soHfHqR = RouterGroup + interface Router extends _soHfHqR { } - interface Tx { + interface Router { /** - * Commit commits the transaction. + * BuildMux constructs a new mux [http.Handler] instance from the current router configurations. */ - commit(): void + buildMux(): http.Handler } - interface Tx { +} + +namespace auth { + /** + * @todo refactor and consider replace with a plain struct + * + * Provider defines a common interface for an OAuth2 client. + */ + interface Provider { + [key:string]: any; /** - * Rollback aborts the transaction. + * @todo temp backport + * + * Order returns the sorting order of the provider usually used in the auth methods list response. */ - rollback(): void - } - interface Tx { + logo(): string /** - * PrepareContext creates a prepared statement for use within a transaction. - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. - * - * To use an existing prepared statement on this transaction, see [Tx.Stmt]. + * @todo temp backport * - * The provided context will be used for the preparation of the context, not - * for the execution of the returned statement. The returned statement - * will run in the transaction context. + * Order returns the sorting order of the provider usually used in the auth methods list response. */ - prepareContext(ctx: context.Context, query: string): (Stmt) - } - interface Tx { + order(): number /** - * Prepare creates a prepared statement for use within a transaction. - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. - * - * To use an existing prepared statement on this transaction, see [Tx.Stmt]. - * - * Prepare uses [context.Background] internally; to specify the context, use - * [Tx.PrepareContext]. + * Context returns the context associated with the provider (if any). */ - prepare(query: string): (Stmt) - } - interface Tx { + context(): context.Context /** - * StmtContext returns a transaction-specific prepared statement from - * an existing statement. - * - * Example: - * - * ``` - * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") - * ... - * tx, err := db.Begin() - * ... - * res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203) - * ``` - * - * The provided context is used for the preparation of the statement, not for the - * execution of the statement. - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. + * SetContext assigns the specified context to the current provider. */ - stmtContext(ctx: context.Context, stmt: Stmt): (Stmt) - } - interface Tx { + setContext(ctx: context.Context): void /** - * Stmt returns a transaction-specific prepared statement from - * an existing statement. - * - * Example: - * - * ``` - * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") - * ... - * tx, err := db.Begin() - * ... - * res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203) - * ``` - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. - * - * Stmt uses [context.Background] internally; to specify the context, use - * [Tx.StmtContext]. + * PKCE indicates whether the provider can use the PKCE flow. */ - stmt(stmt: Stmt): (Stmt) - } - interface Tx { + pkce(): boolean /** - * ExecContext executes a query that doesn't return rows. - * For example: an INSERT and UPDATE. + * SetPKCE toggles the state whether the provider can use the PKCE flow or not. */ - execContext(ctx: context.Context, query: string, ...args: any[]): Result - } - interface Tx { + setPKCE(enable: boolean): void /** - * Exec executes a query that doesn't return rows. - * For example: an INSERT and UPDATE. - * - * Exec uses [context.Background] internally; to specify the context, use - * [Tx.ExecContext]. + * DisplayName usually returns provider name as it is officially written + * and it could be used directly in the UI. */ - exec(query: string, ...args: any[]): Result - } - interface Tx { + displayName(): string /** - * QueryContext executes a query that returns rows, typically a SELECT. + * SetDisplayName sets the provider's display name. */ - queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) - } - interface Tx { + setDisplayName(displayName: string): void /** - * Query executes a query that returns rows, typically a SELECT. - * - * Query uses [context.Background] internally; to specify the context, use - * [Tx.QueryContext]. + * Scopes returns the provider access permissions that will be requested. */ - query(query: string, ...args: any[]): (Rows) - } - interface Tx { + scopes(): Array /** - * QueryRowContext executes a query that is expected to return at most one row. - * QueryRowContext always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. + * SetScopes sets the provider access permissions that will be requested later. + */ + setScopes(scopes: Array): void + /** + * ClientId returns the provider client's app ID. + */ + clientId(): string + /** + * SetClientId sets the provider client's ID. + */ + setClientId(clientId: string): void + /** + * ClientSecret returns the provider client's app secret. */ - queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) - } - interface Tx { + clientSecret(): string /** - * QueryRow executes a query that is expected to return at most one row. - * QueryRow always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. - * - * QueryRow uses [context.Background] internally; to specify the context, use - * [Tx.QueryRowContext]. + * SetClientSecret sets the provider client's app secret. */ - queryRow(query: string, ...args: any[]): (Row) - } - /** - * Stmt is a prepared statement. - * A Stmt is safe for concurrent use by multiple goroutines. - * - * If a Stmt is prepared on a [Tx] or [Conn], it will be bound to a single - * underlying connection forever. If the [Tx] or [Conn] closes, the Stmt will - * become unusable and all operations will return an error. - * If a Stmt is prepared on a [DB], it will remain usable for the lifetime of the - * [DB]. When the Stmt needs to execute on a new underlying connection, it will - * prepare itself on the new connection automatically. - */ - interface Stmt { - } - interface Stmt { + setClientSecret(secret: string): void /** - * ExecContext executes a prepared statement with the given arguments and - * returns a [Result] summarizing the effect of the statement. + * RedirectURL returns the end address to redirect the user + * going through the OAuth flow. */ - execContext(ctx: context.Context, ...args: any[]): Result - } - interface Stmt { + redirectURL(): string /** - * Exec executes a prepared statement with the given arguments and - * returns a [Result] summarizing the effect of the statement. - * - * Exec uses [context.Background] internally; to specify the context, use - * [Stmt.ExecContext]. + * SetRedirectURL sets the provider's RedirectURL. */ - exec(...args: any[]): Result - } - interface Stmt { + setRedirectURL(url: string): void /** - * QueryContext executes a prepared query statement with the given arguments - * and returns the query results as a [*Rows]. + * AuthURL returns the provider's authorization service url. */ - queryContext(ctx: context.Context, ...args: any[]): (Rows) - } - interface Stmt { + authURL(): string /** - * Query executes a prepared query statement with the given arguments - * and returns the query results as a *Rows. - * - * Query uses [context.Background] internally; to specify the context, use - * [Stmt.QueryContext]. + * SetAuthURL sets the provider's AuthURL. */ - query(...args: any[]): (Rows) - } - interface Stmt { + setAuthURL(url: string): void /** - * QueryRowContext executes a prepared query statement with the given arguments. - * If an error occurs during the execution of the statement, that error will - * be returned by a call to Scan on the returned [*Row], which is always non-nil. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. + * TokenURL returns the provider's token exchange service url. */ - queryRowContext(ctx: context.Context, ...args: any[]): (Row) - } - interface Stmt { + tokenURL(): string /** - * QueryRow executes a prepared query statement with the given arguments. - * If an error occurs during the execution of the statement, that error will - * be returned by a call to Scan on the returned [*Row], which is always non-nil. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. - * - * Example usage: - * - * ``` - * var name string - * err := nameByUseridStmt.QueryRow(id).Scan(&name) - * ``` - * - * QueryRow uses [context.Background] internally; to specify the context, use - * [Stmt.QueryRowContext]. + * SetTokenURL sets the provider's TokenURL. */ - queryRow(...args: any[]): (Row) - } - interface Stmt { + setTokenURL(url: string): void /** - * Close closes the statement. + * UserInfoURL returns the provider's user info api url. */ - close(): void - } - /** - * Rows is the result of a query. Its cursor starts before the first row - * of the result set. Use [Rows.Next] to advance from row to row. - */ - interface Rows { - } - interface Rows { + userInfoURL(): string /** - * Next prepares the next result row for reading with the [Rows.Scan] method. It - * returns true on success, or false if there is no next result row or an error - * happened while preparing it. [Rows.Err] should be consulted to distinguish between - * the two cases. - * - * Every call to [Rows.Scan], even the first one, must be preceded by a call to [Rows.Next]. + * SetUserInfoURL sets the provider's UserInfoURL. */ - next(): boolean - } - interface Rows { + setUserInfoURL(url: string): void /** - * NextResultSet prepares the next result set for reading. It reports whether - * there is further result sets, or false if there is no further result set - * or if there is an error advancing to it. The [Rows.Err] method should be consulted - * to distinguish between the two cases. - * - * After calling NextResultSet, the [Rows.Next] method should always be called before - * scanning. If there are further result sets they may not have rows in the result - * set. + * Extra returns a shallow copy of any custom config data + * that the provider may need. */ - nextResultSet(): boolean - } - interface Rows { + extra(): _TygojaDict /** - * Err returns the error, if any, that was encountered during iteration. - * Err may be called after an explicit or implicit [Rows.Close]. + * SetExtra updates the provider's custom config data. */ - err(): void - } - interface Rows { + setExtra(data: _TygojaDict): void /** - * Columns returns the column names. - * Columns returns an error if the rows are closed. + * Client returns an http client using the provided token. */ - columns(): Array - } - interface Rows { + client(token: oauth2.Token): (any) /** - * ColumnTypes returns column information such as column type, length, - * and nullable. Some information may not be available from some drivers. + * BuildAuthURL returns a URL to the provider's consent page + * that asks for permissions for the required scopes explicitly. */ - columnTypes(): Array<(ColumnType | undefined)> - } - interface Rows { + buildAuthURL(state: string, ...opts: oauth2.AuthCodeOption[]): string /** - * Scan copies the columns in the current row into the values pointed - * at by dest. The number of values in dest must be the same as the - * number of columns in [Rows]. - * - * Scan converts columns read from the database into the following - * common Go types and special types provided by the sql package: - * - * ``` - * *string - * *[]byte - * *int, *int8, *int16, *int32, *int64 - * *uint, *uint8, *uint16, *uint32, *uint64 - * *bool - * *float32, *float64 - * *interface{} - * *RawBytes - * *Rows (cursor value) - * any type implementing Scanner (see Scanner docs) - * ``` - * - * In the most simple case, if the type of the value from the source - * column is an integer, bool or string type T and dest is of type *T, - * Scan simply assigns the value through the pointer. - * - * Scan also converts between string and numeric types, as long as no - * information would be lost. While Scan stringifies all numbers - * scanned from numeric database columns into *string, scans into - * numeric types are checked for overflow. For example, a float64 with - * value 300 or a string with value "300" can scan into a uint16, but - * not into a uint8, though float64(255) or "255" can scan into a - * uint8. One exception is that scans of some float64 numbers to - * strings may lose information when stringifying. In general, scan - * floating point columns into *float64. - * - * If a dest argument has type *[]byte, Scan saves in that argument a - * copy of the corresponding data. The copy is owned by the caller and - * can be modified and held indefinitely. The copy can be avoided by - * using an argument of type [*RawBytes] instead; see the documentation - * for [RawBytes] for restrictions on its use. - * - * If an argument has type *interface{}, Scan copies the value - * provided by the underlying driver without conversion. When scanning - * from a source value of type []byte to *interface{}, a copy of the - * slice is made and the caller owns the result. - * - * Source values of type [time.Time] may be scanned into values of type - * *time.Time, *interface{}, *string, or *[]byte. When converting to - * the latter two, [time.RFC3339Nano] is used. - * - * Source values of type bool may be scanned into types *bool, - * *interface{}, *string, *[]byte, or [*RawBytes]. - * - * For scanning into *bool, the source may be true, false, 1, 0, or - * string inputs parseable by [strconv.ParseBool]. - * - * Scan can also convert a cursor returned from a query, such as - * "select cursor(select * from my_table) from dual", into a - * [*Rows] value that can itself be scanned from. The parent - * select query will close any cursor [*Rows] if the parent [*Rows] is closed. - * - * If any of the first arguments implementing [Scanner] returns an error, - * that error will be wrapped in the returned error. + * FetchToken converts an authorization code to token. */ - scan(...dest: any[]): void - } - interface Rows { + fetchToken(code: string, ...opts: oauth2.AuthCodeOption[]): (oauth2.Token) /** - * Close closes the [Rows], preventing further enumeration. If [Rows.Next] is called - * and returns false and there are no further result sets, - * the [Rows] are closed automatically and it will suffice to check the - * result of [Rows.Err]. Close is idempotent and does not affect the result of [Rows.Err]. + * FetchRawUserInfo requests and marshalizes into `result` the + * the OAuth user api response. */ - close(): void + fetchRawUserInfo(token: oauth2.Token): string|Array + /** + * FetchAuthUser is similar to FetchRawUserInfo, but normalizes and + * marshalizes the user api response into a standardized AuthUser struct. + */ + fetchAuthUser(token: oauth2.Token): (AuthUser) } /** - * A Result summarizes an executed SQL command. + * AuthUser defines a standardized OAuth2 user data structure. */ - interface Result { - [key:string]: any; + interface AuthUser { + expiry: types.DateTime + rawUser: _TygojaDict + id: string + name: string + username: string + avatarURL: string + accessToken: string + refreshToken: string + /** + * The VERIFIED OAuth2 account email. + * + * It must be empty if the provider is not able to verify the email ownership. + */ + email: string /** - * LastInsertId returns the integer generated by the database - * in response to a command. Typically this will be from an - * "auto increment" column when inserting a new row. Not all - * databases support this feature, and the syntax of such - * statements varies. + * @todo + * deprecated: use AvatarURL instead + * AvatarUrl will be removed after dropping v0.22 support */ - lastInsertId(): number + avatarUrl: string + } + interface AuthUser { /** - * RowsAffected returns the number of rows affected by an - * update, insert, or delete. Not every database or database - * driver may support this. + * MarshalJSON implements the [json.Marshaler] interface. + * + * @todo remove after dropping v0.22 support */ - rowsAffected(): number + marshalJSON(): string|Array } } @@ -20411,491 +20405,492 @@ namespace mailer { } /** - * Package blob defines a lightweight abstration for interacting with - * various storage services (local filesystem, S3, etc.). + * Package slog provides structured logging, + * in which log records include a message, + * a severity level, and various other attributes + * expressed as key-value pairs. + * + * It defines a type, [Logger], + * which provides several methods (such as [Logger.Info] and [Logger.Error]) + * for reporting events of interest. + * + * Each Logger is associated with a [Handler]. + * A Logger output method creates a [Record] from the method arguments + * and passes it to the Handler, which decides how to handle it. + * There is a default Logger accessible through top-level functions + * (such as [Info] and [Error]) that call the corresponding Logger methods. + * + * A log record consists of a time, a level, a message, and a set of key-value + * pairs, where the keys are strings and the values may be of any type. + * As an example, + * + * ``` + * slog.Info("hello", "count", 3) + * ``` + * + * creates a record containing the time of the call, + * a level of Info, the message "hello", and a single + * pair with key "count" and value 3. + * + * The [Info] top-level function calls the [Logger.Info] method on the default Logger. + * In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. + * Besides these convenience methods for common levels, + * there is also a [Logger.Log] method which takes the level as an argument. + * Each of these methods has a corresponding top-level function that uses the + * default logger. + * + * The default handler formats the log record's message, time, level, and attributes + * as a string and passes it to the [log] package. + * + * ``` + * 2022/11/08 15:28:26 INFO hello count=3 + * ``` + * + * For more control over the output format, create a logger with a different handler. + * This statement uses [New] to create a new logger with a [TextHandler] + * that writes structured records in text form to standard error: + * + * ``` + * logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) + * ``` + * + * [TextHandler] output is a sequence of key=value pairs, easily and unambiguously + * parsed by machine. This statement: + * + * ``` + * logger.Info("hello", "count", 3) + * ``` + * + * produces this output: + * + * ``` + * time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 + * ``` + * + * The package also provides [JSONHandler], whose output is line-delimited JSON: + * + * ``` + * logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + * logger.Info("hello", "count", 3) + * ``` + * + * produces this output: + * + * ``` + * {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} + * ``` + * + * Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. + * There are options for setting the minimum level (see Levels, below), + * displaying the source file and line of the log call, and + * modifying attributes before they are logged. + * + * Setting a logger as the default with + * + * ``` + * slog.SetDefault(logger) + * ``` + * + * will cause the top-level functions like [Info] to use it. + * [SetDefault] also updates the default logger used by the [log] package, + * so that existing applications that use [log.Printf] and related functions + * will send log records to the logger's handler without needing to be rewritten. + * + * Some attributes are common to many log calls. + * For example, you may wish to include the URL or trace identifier of a server request + * with all log events arising from the request. + * Rather than repeat the attribute with every log call, you can use [Logger.With] + * to construct a new Logger containing the attributes: + * + * ``` + * logger2 := logger.With("url", r.URL) + * ``` + * + * The arguments to With are the same key-value pairs used in [Logger.Info]. + * The result is a new Logger with the same handler as the original, but additional + * attributes that will appear in the output of every call. + * + * # Levels + * + * A [Level] is an integer representing the importance or severity of a log event. + * The higher the level, the more severe the event. + * This package defines constants for the most common levels, + * but any int can be used as a level. + * + * In an application, you may wish to log messages only at a certain level or greater. + * One common configuration is to log messages at Info or higher levels, + * suppressing debug logging until it is needed. + * The built-in handlers can be configured with the minimum level to output by + * setting [HandlerOptions.Level]. + * The program's `main` function typically does this. + * The default value is LevelInfo. + * + * Setting the [HandlerOptions.Level] field to a [Level] value + * fixes the handler's minimum level throughout its lifetime. + * Setting it to a [LevelVar] allows the level to be varied dynamically. + * A LevelVar holds a Level and is safe to read or write from multiple + * goroutines. + * To vary the level dynamically for an entire program, first initialize + * a global LevelVar: + * + * ``` + * var programLevel = new(slog.LevelVar) // Info by default + * ``` + * + * Then use the LevelVar to construct a handler, and make it the default: + * + * ``` + * h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) + * slog.SetDefault(slog.New(h)) + * ``` + * + * Now the program can change its logging level with a single statement: + * + * ``` + * programLevel.Set(slog.LevelDebug) + * ``` + * + * # Groups + * + * Attributes can be collected into groups. + * A group has a name that is used to qualify the names of its attributes. + * How this qualification is displayed depends on the handler. + * [TextHandler] separates the group and attribute names with a dot. + * [JSONHandler] treats each group as a separate JSON object, with the group name as the key. + * + * Use [Group] to create a Group attribute from a name and a list of key-value pairs: + * + * ``` + * slog.Group("request", + * "method", r.Method, + * "url", r.URL) + * ``` + * + * TextHandler would display this group as + * + * ``` + * request.method=GET request.url=http://example.com + * ``` + * + * JSONHandler would display it as + * + * ``` + * "request":{"method":"GET","url":"http://example.com"} + * ``` + * + * Use [Logger.WithGroup] to qualify all of a Logger's output + * with a group name. Calling WithGroup on a Logger results in a + * new Logger with the same Handler as the original, but with all + * its attributes qualified by the group name. + * + * This can help prevent duplicate attribute keys in large systems, + * where subsystems might use the same keys. + * Pass each subsystem a different Logger with its own group name so that + * potential duplicates are qualified: + * + * ``` + * logger := slog.Default().With("id", systemID) + * parserLogger := logger.WithGroup("parser") + * parseInput(input, parserLogger) + * ``` + * + * When parseInput logs with parserLogger, its keys will be qualified with "parser", + * so even if it uses the common key "id", the log line will have distinct keys. + * + * # Contexts + * + * Some handlers may wish to include information from the [context.Context] that is + * available at the call site. One example of such information + * is the identifier for the current span when tracing is enabled. + * + * The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first + * argument, as do their corresponding top-level functions. + * + * Although the convenience methods on Logger (Info and so on) and the + * corresponding top-level functions do not take a context, the alternatives ending + * in "Context" do. For example, + * + * ``` + * slog.InfoContext(ctx, "message") + * ``` + * + * It is recommended to pass a context to an output method if one is available. + * + * # Attrs and Values + * + * An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as + * alternating keys and values. The statement + * + * ``` + * slog.Info("hello", slog.Int("count", 3)) + * ``` + * + * behaves the same as + * + * ``` + * slog.Info("hello", "count", 3) + * ``` + * + * There are convenience constructors for [Attr] such as [Int], [String], and [Bool] + * for common types, as well as the function [Any] for constructing Attrs of any + * type. + * + * The value part of an Attr is a type called [Value]. + * Like an [any], a Value can hold any Go value, + * but it can represent typical values, including all numbers and strings, + * without an allocation. * - * NB! - * For compatibility with earlier PocketBase versions and to prevent - * unnecessary breaking changes, this package is based and implemented - * as a minimal, stripped down version of the previously used gocloud.dev/blob. - * While there is no promise that it won't diverge in the future to accommodate - * better some PocketBase specific use cases, currently it copies and - * tries to follow as close as possible the same implementations, - * conventions and rules for the key escaping/unescaping, blob read/write - * interfaces and struct options as gocloud.dev/blob, therefore the - * credits goes to the original Go Cloud Development Kit Authors. - */ -namespace blob { - /** - * ListObject represents a single blob returned from List. - */ - interface ListObject { - /** - * Key is the key for this blob. - */ - key: string - /** - * ModTime is the time the blob was last modified. - */ - modTime: time.Time - /** - * Size is the size of the blob's content in bytes. - */ - size: number - /** - * MD5 is an MD5 hash of the blob contents or nil if not available. - */ - md5: string|Array - /** - * IsDir indicates that this result represents a "directory" in the - * hierarchical namespace, ending in ListOptions.Delimiter. Key can be - * passed as ListOptions.Prefix to list items in the "directory". - * Fields other than Key and IsDir will not be set if IsDir is true. - */ - isDir: boolean - } - /** - * Attributes contains attributes about a blob. - */ - interface Attributes { - /** - * CacheControl specifies caching attributes that services may use - * when serving the blob. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control - */ - cacheControl: string - /** - * ContentDisposition specifies whether the blob content is expected to be - * displayed inline or as an attachment. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition - */ - contentDisposition: string - /** - * ContentEncoding specifies the encoding used for the blob's content, if any. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding - */ - contentEncoding: string - /** - * ContentLanguage specifies the language used in the blob's content, if any. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language - */ - contentLanguage: string - /** - * ContentType is the MIME type of the blob. It will not be empty. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type - */ - contentType: string - /** - * Metadata holds key/value pairs associated with the blob. - * Keys are guaranteed to be in lowercase, even if the backend service - * has case-sensitive keys (although note that Metadata written via - * this package will always be lowercased). If there are duplicate - * case-insensitive keys (e.g., "foo" and "FOO"), only one value - * will be kept, and it is undefined which one. - */ - metadata: _TygojaDict - /** - * CreateTime is the time the blob was created, if available. If not available, - * CreateTime will be the zero time. - */ - createTime: time.Time - /** - * ModTime is the time the blob was last modified. - */ - modTime: time.Time - /** - * Size is the size of the blob's content in bytes. - */ - size: number - /** - * MD5 is an MD5 hash of the blob contents or nil if not available. - */ - md5: string|Array - /** - * ETag for the blob; see https://en.wikipedia.org/wiki/HTTP_ETag. - */ - eTag: string - } - /** - * Reader reads bytes from a blob. - * It implements io.ReadSeekCloser, and must be closed after reads are finished. - */ - interface Reader { - } - interface Reader { - /** - * Read implements io.Reader (https://golang.org/pkg/io/#Reader). - */ - read(p: string|Array): number - } - interface Reader { - /** - * Seek implements io.Seeker (https://golang.org/pkg/io/#Seeker). - */ - seek(offset: number, whence: number): number - } - interface Reader { - /** - * Close implements io.Closer (https://golang.org/pkg/io/#Closer). - */ - close(): void - } - interface Reader { - /** - * ContentType returns the MIME type of the blob. - */ - contentType(): string - } - interface Reader { - /** - * ModTime returns the time the blob was last modified. - */ - modTime(): time.Time - } - interface Reader { - /** - * Size returns the size of the blob content in bytes. - */ - size(): number - } - interface Reader { - /** - * WriteTo reads from r and writes to w until there's no more data or - * an error occurs. - * The return value is the number of bytes written to w. - * - * It implements the io.WriterTo interface. - */ - writeTo(w: io.Writer): number - } -} - -namespace search { - /** - * Result defines the returned search result structure. - */ - interface Result { - items: any - page: number - perPage: number - totalItems: number - totalPages: number - } - /** - * ResolverResult defines a single FieldResolver.Resolve() successfully parsed result. - */ - interface ResolverResult { - /** - * Identifier is the plain SQL identifier/column that will be used - * in the final db expression as left or right operand. - */ - identifier: string - /** - * NullFallback specify the preference for how NULL or empty values - * should be resolved (default to "auto"). - * - * Set to NullFallbackDisabled to prevent any COALESCE or NULL fallbacks. - * Set to NullFallbackEnforced to prefer COALESCE or NULL fallbacks when needed. - */ - nullFallback: NullFallbackPreference - /** - * Params is a map with db placeholder->value pairs that will be added - * to the query when building both resolved operands/sides in a single expression. - */ - params: dbx.Params - /** - * MultiMatchSubQuery is an optional sub query expression that will be added - * in addition to the combined ResolverResult expression during build. - */ - multiMatchSubQuery?: MultiMatchSubquery - /** - * AfterBuild is an optional function that will be called after building - * and combining the result of both resolved operands/sides in a single expression. - */ - afterBuild: (expr: dbx.Expression) => dbx.Expression - } -} - -namespace router { + * For the most efficient log output, use [Logger.LogAttrs]. + * It is similar to [Logger.Log] but accepts only Attrs, not alternating + * keys and values; this allows it, too, to avoid allocation. + * + * The call + * + * ``` + * logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) + * ``` + * + * is the most efficient way to achieve the same output as + * + * ``` + * slog.InfoContext(ctx, "hello", "count", 3) + * ``` + * + * # Customizing a type's logging behavior + * + * If a type implements the [LogValuer] interface, the [Value] returned from its LogValue + * method is used for logging. You can use this to control how values of the type + * appear in logs. For example, you can redact secret information like passwords, + * or gather a struct's fields in a Group. See the examples under [LogValuer] for + * details. + * + * A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] + * method handles these cases carefully, avoiding infinite loops and unbounded recursion. + * Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. + * + * # Wrapping output methods + * + * The logger functions use reflection over the call stack to find the file name + * and line number of the logging call within the application. This can produce + * incorrect source information for functions that wrap slog. For instance, if you + * define this function in file mylog.go: + * + * ``` + * func Infof(logger *slog.Logger, format string, args ...any) { + * logger.Info(fmt.Sprintf(format, args...)) + * } + * ``` + * + * and you call it like this in main.go: + * + * ``` + * Infof(slog.Default(), "hello, %s", "world") + * ``` + * + * then slog will report the source file as mylog.go, not main.go. + * + * A correct implementation of Infof will obtain the source location + * (pc) and pass it to NewRecord. + * The Infof function in the package-level example called "wrapping" + * demonstrates how to do this. + * + * # Working with Records + * + * Sometimes a Handler will need to modify a Record + * before passing it on to another Handler or backend. + * A Record contains a mixture of simple public fields (e.g. Time, Level, Message) + * and hidden fields that refer to state (such as attributes) indirectly. This + * means that modifying a simple copy of a Record (e.g. by calling + * [Record.Add] or [Record.AddAttrs] to add attributes) + * may have unexpected effects on the original. + * Before modifying a Record, use [Record.Clone] to + * create a copy that shares no state with the original, + * or create a new Record with [NewRecord] + * and build up its Attrs by traversing the old ones with [Record.Attrs]. + * + * # Performance considerations + * + * If profiling your application demonstrates that logging is taking significant time, + * the following suggestions may help. + * + * If many log lines have a common attribute, use [Logger.With] to create a Logger with + * that attribute. The built-in handlers will format that attribute only once, at the + * call to [Logger.With]. The [Handler] interface is designed to allow that optimization, + * and a well-written Handler should take advantage of it. + * + * The arguments to a log call are always evaluated, even if the log event is discarded. + * If possible, defer computation so that it happens only if the value is actually logged. + * For example, consider the call + * + * ``` + * slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily + * ``` + * + * The URL.String method will be called even if the logger discards Info-level events. + * Instead, pass the URL directly: + * + * ``` + * slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed + * ``` + * + * The built-in [TextHandler] will call its String method, but only + * if the log event is enabled. + * Avoiding the call to String also preserves the structure of the underlying value. + * For example [JSONHandler] emits the components of the parsed URL as a JSON object. + * If you want to avoid eagerly paying the cost of the String call + * without causing the handler to potentially inspect the structure of the value, + * wrap the value in a fmt.Stringer implementation that hides its Marshal methods. + * + * You can also use the [LogValuer] interface to avoid unnecessary work in disabled log + * calls. Say you need to log some expensive value: + * + * ``` + * slog.Debug("frobbing", "value", computeExpensiveValue(arg)) + * ``` + * + * Even if this line is disabled, computeExpensiveValue will be called. + * To avoid that, define a type implementing LogValuer: + * + * ``` + * type expensive struct { arg int } + * + * func (e expensive) LogValue() slog.Value { + * return slog.AnyValue(computeExpensiveValue(e.arg)) + * } + * ``` + * + * Then use a value of that type in log calls: + * + * ``` + * slog.Debug("frobbing", "value", expensive{arg}) + * ``` + * + * Now computeExpensiveValue will only be called when the line is enabled. + * + * The built-in handlers acquire a lock before calling [io.Writer.Write] + * to ensure that exactly one [Record] is written at a time in its entirety. + * Although each log record has a timestamp, + * the built-in handlers do not use that time to sort the written records. + * User-defined handlers are responsible for their own locking and sorting. + * + * # Writing a handler + * + * For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. + */ +namespace slog { // @ts-ignore - import validation = ozzo_validation - /** - * ApiError defines the struct for a basic api error response. - */ - interface ApiError { - data: _TygojaDict - message: string - status: number - } - interface ApiError { - /** - * Error makes it compatible with the `error` interface. - */ - error(): string - } - interface ApiError { - /** - * RawData returns the unformatted error data (could be an internal error, text, etc.) - */ - rawData(): any - } - interface ApiError { - /** - * Is reports whether the current ApiError wraps the target. - */ - is(target: Error): boolean - } + import loginternal = internal /** - * Event specifies based Route handler event that is usually intended - * to be embedded as part of a custom event struct. + * A Logger records structured information about each call to its + * Log, Debug, Info, Warn, and Error methods. + * For each call, it creates a [Record] and passes it to a [Handler]. * - * NB! It is expected that the Response and Request fields are always set. + * To create a new Logger, call [New] or a Logger method + * that begins "With". */ - type _sdpOauu = hook.Event - interface Event extends _sdpOauu { - response: http.ResponseWriter - request?: http.Request + interface Logger { } - interface Event { + interface Logger { /** - * Written reports whether the current response has already been written. - * - * This method always returns false if e.ResponseWritter doesn't implement the WriteTracker interface - * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). + * Handler returns l's Handler. */ - written(): boolean + handler(): Handler } - interface Event { + interface Logger { /** - * Status reports the status code of the current response. - * - * This method always returns 0 if e.Response doesn't implement the StatusTracker interface - * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). + * With returns a Logger that includes the given attributes + * in each output operation. Arguments are converted to + * attributes as if by [Logger.Log]. */ - status(): number + with(...args: any[]): (Logger) } - interface Event { + interface Logger { /** - * Flush flushes buffered data to the current response. + * WithGroup returns a Logger that starts a group, if name is non-empty. + * The keys of all attributes added to the Logger will be qualified by the given + * name. (How that qualification happens depends on the [Handler.WithGroup] + * method of the Logger's Handler.) * - * Returns [http.ErrNotSupported] if e.Response doesn't implement the [http.Flusher] interface - * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). - */ - flush(): void - } - interface Event { - /** - * IsTLS reports whether the connection on which the request was received is TLS. + * If name is empty, WithGroup returns the receiver. */ - isTLS(): boolean + withGroup(name: string): (Logger) } - interface Event { + interface Logger { /** - * SetCookie is an alias for [http.SetCookie]. - * - * SetCookie adds a Set-Cookie header to the current response's headers. - * The provided cookie must have a valid Name. - * Invalid cookies may be silently dropped. + * Enabled reports whether l emits log records at the given context and level. */ - setCookie(cookie: http.Cookie): void + enabled(ctx: context.Context, level: Level): boolean } - interface Event { + interface Logger { /** - * RemoteIP returns the IP address of the client that sent the request. - * - * IPv6 addresses are returned expanded. - * For example, "2001:db8::1" becomes "2001:0db8:0000:0000:0000:0000:0000:0001". + * Log emits a log record with the current time and the given level and message. + * The Record's Attrs consist of the Logger's attributes followed by + * the Attrs specified by args. * - * Note that if you are behind reverse proxy(ies), this method returns - * the IP of the last connecting proxy. - */ - remoteIP(): string - } - interface Event { - /** - * FindUploadedFiles extracts all form files of "key" from a http request - * and returns a slice with filesystem.File instances (if any). - */ - findUploadedFiles(key: string): Array<(filesystem.File | undefined)> - } - interface Event { - /** - * Get retrieves single value from the current event data store. - */ - get(key: string): any - } - interface Event { - /** - * GetAll returns a copy of the current event data store. - */ - getAll(): _TygojaDict - } - interface Event { - /** - * Set saves single value into the current event data store. - */ - set(key: string, value: any): void - } - interface Event { - /** - * SetAll saves all items from m into the current event data store. - */ - setAll(m: _TygojaDict): void - } - interface Event { - /** - * String writes a plain string response. - */ - string(status: number, data: string): void - } - interface Event { - /** - * HTML writes an HTML response. + * The attribute arguments are processed as follows: + * ``` + * - If an argument is an Attr, it is used as is. + * - If an argument is a string and this is not the last argument, + * the following argument is treated as the value and the two are combined + * into an Attr. + * - Otherwise, the argument is treated as a value with key "!BADKEY". + * ``` */ - html(status: number, data: string): void + log(ctx: context.Context, level: Level, msg: string, ...args: any[]): void } - interface Event { + interface Logger { /** - * JSON writes a JSON response. - * - * It also provides a generic response data fields picker if the "fields" query parameter is set. - * For example, if you are requesting `?fields=a,b` for `e.JSON(200, map[string]int{ "a":1, "b":2, "c":3 })`, - * it should result in a JSON response like: `{"a":1, "b": 2}`. + * LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs. */ - json(status: number, data: any): void + logAttrs(ctx: context.Context, level: Level, msg: string, ...attrs: Attr[]): void } - interface Event { + interface Logger { /** - * XML writes an XML response. - * It automatically prepends the generic [xml.Header] string to the response. + * Debug logs at [LevelDebug]. */ - xml(status: number, data: any): void + debug(msg: string, ...args: any[]): void } - interface Event { + interface Logger { /** - * Stream streams the specified reader into the response. + * DebugContext logs at [LevelDebug] with the given context. */ - stream(status: number, contentType: string, reader: io.Reader): void + debugContext(ctx: context.Context, msg: string, ...args: any[]): void } - interface Event { + interface Logger { /** - * Blob writes a blob (bytes slice) response. + * Info logs at [LevelInfo]. */ - blob(status: number, contentType: string, b: string|Array): void + info(msg: string, ...args: any[]): void } - interface Event { + interface Logger { /** - * FileFS serves the specified filename from fsys. - * - * It is similar to [echo.FileFS] for consistency with earlier versions. + * InfoContext logs at [LevelInfo] with the given context. */ - fileFS(fsys: fs.FS, filename: string): void + infoContext(ctx: context.Context, msg: string, ...args: any[]): void } - interface Event { + interface Logger { /** - * NoContent writes a response with no body (ex. 204). + * Warn logs at [LevelWarn]. */ - noContent(status: number): void + warn(msg: string, ...args: any[]): void } - interface Event { + interface Logger { /** - * Redirect writes a redirect response to the specified url. - * The status code must be in between 300 – 399 range. + * WarnContext logs at [LevelWarn] with the given context. */ - redirect(status: number, url: string): void - } - interface Event { - error(status: number, message: string, errData: any): (ApiError) - } - interface Event { - badRequestError(message: string, errData: any): (ApiError) - } - interface Event { - notFoundError(message: string, errData: any): (ApiError) - } - interface Event { - forbiddenError(message: string, errData: any): (ApiError) - } - interface Event { - unauthorizedError(message: string, errData: any): (ApiError) - } - interface Event { - tooManyRequestsError(message: string, errData: any): (ApiError) - } - interface Event { - internalServerError(message: string, errData: any): (ApiError) + warnContext(ctx: context.Context, msg: string, ...args: any[]): void } - interface Event { + interface Logger { /** - * BindBody unmarshal the request body into the provided dst. - * - * dst must be either a struct pointer or map[string]any. - * - * The rules how the body will be scanned depends on the request Content-Type. - * - * Currently the following Content-Types are supported: - * ``` - * - application/json - * - text/xml, application/xml - * - multipart/form-data, application/x-www-form-urlencoded - * ``` - * - * Respectively the following struct tags are supported (again, which one will be used depends on the Content-Type): - * ``` - * - "json" (json body)- uses the builtin Go json package for unmarshaling. - * - "xml" (xml body) - uses the builtin Go xml package for unmarshaling. - * - "form" (form data) - utilizes the custom [router.UnmarshalRequestData] method. - * ``` - * - * NB! When dst is a struct make sure that it doesn't have public fields - * that shouldn't be bindable and it is advisible such fields to be unexported - * or have a separate struct just for the binding. For example: - * - * ``` - * data := struct{ - * somethingPrivate string - * - * Title string `json:"title" form:"title"` - * Total int `json:"total" form:"total"` - * }{} - * err := e.BindBody(&data) - * ``` + * Error logs at [LevelError]. */ - bindBody(dst: any): void - } - /** - * Router defines a thin wrapper around the standard Go [http.ServeMux] by - * adding support for routing sub-groups, middlewares and other common utils. - * - * Example: - * - * ``` - * r := NewRouter[*MyEvent](eventFactory) - * - * // middlewares - * r.BindFunc(m1, m2) - * - * // routes - * r.GET("/test", handler1) - * - * // sub-routers/groups - * api := r.Group("/api") - * api.GET("/admins", handler2) - * - * // generate a http.ServeMux instance based on the router configurations - * mux, _ := r.BuildMux() - * - * http.ListenAndServe("localhost:8090", mux) - * ``` - */ - type _sToAjYb = RouterGroup - interface Router extends _sToAjYb { + error(msg: string, ...args: any[]): void } - interface Router { + interface Logger { /** - * BuildMux constructs a new mux [http.Handler] instance from the current router configurations. + * ErrorContext logs at [LevelError] with the given context. */ - buildMux(): http.Handler + errorContext(ctx: context.Context, msg: string, ...args: any[]): void } } @@ -22074,7 +22069,149 @@ namespace cron { /** * HasStarted checks whether the current Cron ticker has been started. */ - hasStarted(): boolean + hasStarted(): boolean + } +} + +namespace subscriptions { + /** + * Broker defines a struct for managing subscriptions clients. + */ + interface Broker { + } + interface Broker { + /** + * Clients returns a shallow copy of all registered clients indexed + * with their connection id. + */ + clients(): _TygojaDict + } + interface Broker { + /** + * ChunkedClients splits the current clients into a chunked slice. + */ + chunkedClients(chunkSize: number): Array> + } + interface Broker { + /** + * TotalClients returns the total number of registered clients. + */ + totalClients(): number + } + interface Broker { + /** + * ClientById finds a registered client by its id. + * + * Returns non-nil error when client with clientId is not registered. + */ + clientById(clientId: string): Client + } + interface Broker { + /** + * Register adds a new client to the broker instance. + */ + register(client: Client): void + } + interface Broker { + /** + * Unregister removes a single client by its id and marks it as discarded. + * + * If client with clientId doesn't exist, this method does nothing. + */ + unregister(clientId: string): void + } + /** + * Client is an interface for a generic subscription client. + */ + interface Client { + [key:string]: any; + /** + * Id Returns the unique id of the client. + */ + id(): string + /** + * Channel returns the client's communication channel. + * + * NB! The channel shouldn't be used after calling Discard(). + */ + channel(): undefined + /** + * Subscriptions returns a shallow copy of the client subscriptions matching the prefixes. + * If no prefix is specified, returns all subscriptions. + */ + subscriptions(...prefixes: string[]): _TygojaDict + /** + * Subscribe subscribes the client to the provided subscriptions list. + * + * Each subscription can also have "options" (json serialized SubscriptionOptions) as query parameter. + * + * Example: + * + * ``` + * Subscribe( + * "subscriptionA", + * `subscriptionB?options={"query":{"a":1},"headers":{"x_token":"abc"}}`, + * ) + * ``` + */ + subscribe(...subs: string[]): void + /** + * Unsubscribe unsubscribes the client from the provided subscriptions list. + */ + unsubscribe(...subs: string[]): void + /** + * HasSubscription checks if the client is subscribed to `sub`. + */ + hasSubscription(sub: string): boolean + /** + * Set stores any value to the client's context. + */ + set(key: string, value: any): void + /** + * Unset removes a single value from the client's context. + */ + unset(key: string): void + /** + * Get retrieves the key value from the client's context. + */ + get(key: string): any + /** + * Discard marks the client as "discarded" (and closes its channel), + * meaning that it shouldn't be used anymore for sending new messages. + * + * It is safe to call Discard() multiple times. + */ + discard(): void + /** + * IsDiscarded indicates whether the client has been "discarded" + * and should no longer be used. + */ + isDiscarded(): boolean + /** + * Send sends the specified message to the client's channel (if not discarded). + */ + send(m: Message): void + } + /** + * Message defines a client's channel data. + */ + interface Message { + name: string + data: string|Array + } + interface Message { + /** + * WriteSSE writes the current message in a SSE format into the provided writer. + * + * For example, writing to a router.Event: + * + * ``` + * m := Message{Name: "users/create", Data: []byte{...}} + * m.WriteSSE(e.Response, "yourEventId") + * e.Flush() + * ``` + */ + writeSSE(w: io.Writer, eventId: string): void } } @@ -22091,15 +22228,6 @@ namespace sync { } } -namespace io { - /** - * WriteCloser is the interface that groups the basic Write and Close methods. - */ - interface WriteCloser { - [key:string]: any; - } -} - namespace syscall { // @ts-ignore import errpkg = errors @@ -22129,944 +22257,742 @@ namespace syscall { noSetGroups: boolean // If true, don't set supplementary groups } // @ts-ignore - import runtimesyscall = syscall - /** - * A Signal is a number describing a process signal. - * It implements the [os.Signal] interface. - */ - interface Signal extends Number{} - interface Signal { - signal(): void - } - interface Signal { - string(): string - } -} - -namespace time { - /** - * A Month specifies a month of the year (January = 1, ...). - */ - interface Month extends Number{} - interface Month { - /** - * String returns the English name of the month ("January", "February", ...). - */ - string(): string - } - /** - * A Weekday specifies a day of the week (Sunday = 0, ...). - */ - interface Weekday extends Number{} - interface Weekday { - /** - * String returns the English name of the day ("Sunday", "Monday", ...). - */ - string(): string - } - /** - * A Location maps time instants to the zone in use at that time. - * Typically, the Location represents the collection of time offsets - * in use in a geographical area. For many Locations the time offset varies - * depending on whether daylight savings time is in use at the time instant. - * - * Location is used to provide a time zone in a printed Time value and for - * calculations involving intervals that may cross daylight savings time - * boundaries. - */ - interface Location { - } - interface Location { - /** - * String returns a descriptive name for the time zone information, - * corresponding to the name argument to [LoadLocation] or [FixedZone]. - */ - string(): string - } -} - -namespace context { -} - -namespace fs { -} - -namespace slog { - /** - * An Attr is a key-value pair. - */ - interface Attr { - key: string - value: Value - } - interface Attr { - /** - * Equal reports whether a and b have equal keys and values. - */ - equal(b: Attr): boolean - } - interface Attr { - string(): string - } - /** - * A Handler handles log records produced by a Logger. - * - * A typical handler may print log records to standard error, - * or write them to a file or database, or perhaps augment them - * with additional attributes and pass them on to another handler. - * - * Any of the Handler's methods may be called concurrently with itself - * or with other methods. It is the responsibility of the Handler to - * manage this concurrency. - * - * Users of the slog package should not invoke Handler methods directly. - * They should use the methods of [Logger] instead. - * - * Before implementing your own handler, consult https://go.dev/s/slog-handler-guide. - */ - interface Handler { - [key:string]: any; - /** - * Enabled reports whether the handler handles records at the given level. - * The handler ignores records whose level is lower. - * It is called early, before any arguments are processed, - * to save effort if the log event should be discarded. - * If called from a Logger method, the first argument is the context - * passed to that method, or context.Background() if nil was passed - * or the method does not take a context. - * The context is passed so Enabled can use its values - * to make a decision. - */ - enabled(_arg0: context.Context, _arg1: Level): boolean - /** - * Handle handles the Record. - * It will only be called when Enabled returns true. - * The Context argument is as for Enabled. - * It is present solely to provide Handlers access to the context's values. - * Canceling the context should not affect record processing. - * (Among other things, log messages may be necessary to debug a - * cancellation-related problem.) - * - * Handle methods that produce output should observe the following rules: - * ``` - * - If r.Time is the zero time, ignore the time. - * - If r.PC is zero, ignore it. - * - Attr's values should be resolved. - * - If an Attr's key and value are both the zero value, ignore the Attr. - * This can be tested with attr.Equal(Attr{}). - * - If a group's key is empty, inline the group's Attrs. - * - If a group has no Attrs (even if it has a non-empty key), - * ignore it. - * ``` - * - * [Logger] discards any errors from Handle. Wrap the Handle method to - * process any errors from Handlers. - */ - handle(_arg0: context.Context, _arg1: Record): void - /** - * WithAttrs returns a new Handler whose attributes consist of - * both the receiver's attributes and the arguments. - * The Handler owns the slice: it may retain, modify or discard it. - */ - withAttrs(attrs: Array): Handler - /** - * WithGroup returns a new Handler with the given group appended to - * the receiver's existing groups. - * The keys of all subsequent attributes, whether added by With or in a - * Record, should be qualified by the sequence of group names. - * - * How this qualification happens is up to the Handler, so long as - * this Handler's attribute keys differ from those of another Handler - * with a different sequence of group names. - * - * A Handler should treat WithGroup as starting a Group of Attrs that ends - * at the end of the log event. That is, - * - * ``` - * logger.WithGroup("s").LogAttrs(ctx, level, msg, slog.Int("a", 1), slog.Int("b", 2)) - * ``` - * - * should behave like - * - * ``` - * logger.LogAttrs(ctx, level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2))) - * ``` - * - * If the name is empty, WithGroup returns the receiver. - */ - withGroup(name: string): Handler - } - /** - * A Level is the importance or severity of a log event. - * The higher the level, the more important or severe the event. - */ - interface Level extends Number{} - interface Level { - /** - * String returns a name for the level. - * If the level has a name, then that name - * in uppercase is returned. - * If the level is between named values, then - * an integer is appended to the uppercased name. - * Examples: - * - * ``` - * LevelWarn.String() => "WARN" - * (LevelInfo+2).String() => "INFO+2" - * ``` - */ - string(): string - } - interface Level { - /** - * MarshalJSON implements [encoding/json.Marshaler] - * by quoting the output of [Level.String]. - */ - marshalJSON(): string|Array - } - interface Level { - /** - * UnmarshalJSON implements [encoding/json.Unmarshaler] - * It accepts any string produced by [Level.MarshalJSON], - * ignoring case. - * It also accepts numeric offsets that would result in a different string on - * output. For example, "Error-8" would marshal as "INFO". - */ - unmarshalJSON(data: string|Array): void - } - interface Level { - /** - * AppendText implements [encoding.TextAppender] - * by calling [Level.String]. - */ - appendText(b: string|Array): string|Array - } - interface Level { - /** - * MarshalText implements [encoding.TextMarshaler] - * by calling [Level.AppendText]. - */ - marshalText(): string|Array - } - interface Level { - /** - * UnmarshalText implements [encoding.TextUnmarshaler]. - * It accepts any string produced by [Level.MarshalText], - * ignoring case. - * It also accepts numeric offsets that would result in a different string on - * output. For example, "Error-8" would marshal as "INFO". - */ - unmarshalText(data: string|Array): void - } - interface Level { - /** - * Level returns the receiver. - * It implements [Leveler]. - */ - level(): Level - } - // @ts-ignore - import loginternal = internal -} - -namespace bufio { + import runtimesyscall = syscall /** - * Reader implements buffering for an io.Reader object. - * A new Reader is created by calling [NewReader] or [NewReaderSize]; - * alternatively the zero value of a Reader may be used after calling [Reset] - * on it. + * A Signal is a number describing a process signal. + * It implements the [os.Signal] interface. */ - interface Reader { + interface Signal extends Number{} + interface Signal { + signal(): void } - interface Reader { - /** - * Size returns the size of the underlying buffer in bytes. - */ - size(): number + interface Signal { + string(): string } - interface Reader { +} + +namespace time { + /** + * A Month specifies a month of the year (January = 1, ...). + */ + interface Month extends Number{} + interface Month { /** - * Reset discards any buffered data, resets all state, and switches - * the buffered reader to read from r. - * Calling Reset on the zero value of [Reader] initializes the internal buffer - * to the default size. - * Calling b.Reset(b) (that is, resetting a [Reader] to itself) does nothing. + * String returns the English name of the month ("January", "February", ...). */ - reset(r: io.Reader): void + string(): string } - interface Reader { + /** + * A Weekday specifies a day of the week (Sunday = 0, ...). + */ + interface Weekday extends Number{} + interface Weekday { /** - * Peek returns the next n bytes without advancing the reader. The bytes stop - * being valid at the next read call. If necessary, Peek will read more bytes - * into the buffer in order to make n bytes available. If Peek returns fewer - * than n bytes, it also returns an error explaining why the read is short. - * The error is [ErrBufferFull] if n is larger than b's buffer size. - * - * Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding - * until the next read operation. + * String returns the English name of the day ("Sunday", "Monday", ...). */ - peek(n: number): string|Array + string(): string } - interface Reader { - /** - * Discard skips the next n bytes, returning the number of bytes discarded. - * - * If Discard skips fewer than n bytes, it also returns an error. - * If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without - * reading from the underlying io.Reader. - */ - discard(n: number): number + /** + * A Location maps time instants to the zone in use at that time. + * Typically, the Location represents the collection of time offsets + * in use in a geographical area. For many Locations the time offset varies + * depending on whether daylight savings time is in use at the time instant. + * + * Location is used to provide a time zone in a printed Time value and for + * calculations involving intervals that may cross daylight savings time + * boundaries. + */ + interface Location { } - interface Reader { + interface Location { /** - * Read reads data into p. - * It returns the number of bytes read into p. - * The bytes are taken from at most one Read on the underlying [Reader], - * hence n may be less than len(p). - * To read exactly len(p) bytes, use io.ReadFull(b, p). - * If the underlying [Reader] can return a non-zero count with io.EOF, - * then this Read method can do so as well; see the [io.Reader] docs. + * String returns a descriptive name for the time zone information, + * corresponding to the name argument to [LoadLocation] or [FixedZone]. */ - read(p: string|Array): number + string(): string } - interface Reader { - /** - * ReadByte reads and returns a single byte. - * If no byte is available, returns an error. - */ - readByte(): number +} + +namespace context { +} + +namespace io { + /** + * WriteCloser is the interface that groups the basic Write and Close methods. + */ + interface WriteCloser { + [key:string]: any; } - interface Reader { - /** - * UnreadByte unreads the last byte. Only the most recently read byte can be unread. - * - * UnreadByte returns an error if the most recent method called on the - * [Reader] was not a read operation. Notably, [Reader.Peek], [Reader.Discard], and [Reader.WriteTo] are not - * considered read operations. - */ - unreadByte(): void +} + +namespace fs { +} + +namespace net { + /** + * Addr represents a network end point address. + * + * The two methods [Addr.Network] and [Addr.String] conventionally return strings + * that can be passed as the arguments to [Dial], but the exact form + * and meaning of the strings is up to the implementation. + */ + interface Addr { + [key:string]: any; + network(): string // name of the network (for example, "tcp", "udp") + string(): string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80") } - interface Reader { - /** - * ReadRune reads a single UTF-8 encoded Unicode character and returns the - * rune and its size in bytes. If the encoded rune is invalid, it consumes one byte - * and returns unicode.ReplacementChar (U+FFFD) with a size of 1. - */ - readRune(): [number, number] + // @ts-ignore + import _cgopackage = cgo +} + +/** + * Package url parses URLs and implements query escaping. + * + * See RFC 3986. This package generally follows RFC 3986, except where + * it deviates for compatibility reasons. + * RFC 6874 followed for IPv6 zone literals. + */ +namespace url { + /** + * A URL represents a parsed URL (technically, a URI reference). + * + * The general form represented is: + * + * ``` + * [scheme:][//[userinfo@]host][/]path[?query][#fragment] + * ``` + * + * URLs that do not start with a slash after the scheme are interpreted as: + * + * ``` + * scheme:opaque[?query][#fragment] + * ``` + * + * The Host field contains the host and port subcomponents of the URL. + * When the port is present, it is separated from the host with a colon. + * When the host is an IPv6 address, it must be enclosed in square brackets: + * "[fe80::1]:80". The [net.JoinHostPort] function combines a host and port + * into a string suitable for the Host field, adding square brackets to + * the host when necessary. + * + * Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/. + * A consequence is that it is impossible to tell which slashes in the Path were + * slashes in the raw URL and which were %2f. This distinction is rarely important, + * but when it is, the code should use the [URL.EscapedPath] method, which preserves + * the original encoding of Path. + * + * The RawPath field is an optional field which is only set when the default + * encoding of Path is different from the escaped path. See the EscapedPath method + * for more details. + * + * URL's String method uses the EscapedPath method to obtain the path. + */ + interface URL { + scheme: string + opaque: string // encoded opaque data + user?: Userinfo // username and password information + host: string // host or host:port (see Hostname and Port methods) + path: string // path (relative paths may omit leading slash) + rawPath: string // encoded path hint (see EscapedPath method) + omitHost: boolean // do not emit empty host (authority) + forceQuery: boolean // append a query ('?') even if RawQuery is empty + rawQuery: string // encoded query values, without '?' + fragment: string // fragment for references, without '#' + rawFragment: string // encoded fragment hint (see EscapedFragment method) } - interface Reader { + interface URL { /** - * UnreadRune unreads the last rune. If the most recent method called on - * the [Reader] was not a [Reader.ReadRune], [Reader.UnreadRune] returns an error. (In this - * regard it is stricter than [Reader.UnreadByte], which will unread the last byte - * from any read operation.) + * EscapedPath returns the escaped form of u.Path. + * In general there are multiple possible escaped forms of any path. + * EscapedPath returns u.RawPath when it is a valid escaping of u.Path. + * Otherwise EscapedPath ignores u.RawPath and computes an escaped + * form on its own. + * The [URL.String] and [URL.RequestURI] methods use EscapedPath to construct + * their results. + * In general, code should call EscapedPath instead of + * reading u.RawPath directly. */ - unreadRune(): void + escapedPath(): string } - interface Reader { + interface URL { /** - * Buffered returns the number of bytes that can be read from the current buffer. + * EscapedFragment returns the escaped form of u.Fragment. + * In general there are multiple possible escaped forms of any fragment. + * EscapedFragment returns u.RawFragment when it is a valid escaping of u.Fragment. + * Otherwise EscapedFragment ignores u.RawFragment and computes an escaped + * form on its own. + * The [URL.String] method uses EscapedFragment to construct its result. + * In general, code should call EscapedFragment instead of + * reading u.RawFragment directly. */ - buffered(): number + escapedFragment(): string } - interface Reader { + interface URL { /** - * ReadSlice reads until the first occurrence of delim in the input, - * returning a slice pointing at the bytes in the buffer. - * The bytes stop being valid at the next read. - * If ReadSlice encounters an error before finding a delimiter, - * it returns all the data in the buffer and the error itself (often io.EOF). - * ReadSlice fails with error [ErrBufferFull] if the buffer fills without a delim. - * Because the data returned from ReadSlice will be overwritten - * by the next I/O operation, most clients should use - * [Reader.ReadBytes] or ReadString instead. - * ReadSlice returns err != nil if and only if line does not end in delim. + * String reassembles the [URL] into a valid URL string. + * The general form of the result is one of: + * + * ``` + * scheme:opaque?query#fragment + * scheme://userinfo@host/path?query#fragment + * ``` + * + * If u.Opaque is non-empty, String uses the first form; + * otherwise it uses the second form. + * Any non-ASCII characters in host are escaped. + * To obtain the path, String uses u.EscapedPath(). + * + * In the second form, the following rules apply: + * ``` + * - if u.Scheme is empty, scheme: is omitted. + * - if u.User is nil, userinfo@ is omitted. + * - if u.Host is empty, host/ is omitted. + * - if u.Scheme and u.Host are empty and u.User is nil, + * the entire scheme://userinfo@host/ is omitted. + * - if u.Host is non-empty and u.Path begins with a /, + * the form host/path does not add its own /. + * - if u.RawQuery is empty, ?query is omitted. + * - if u.Fragment is empty, #fragment is omitted. + * ``` */ - readSlice(delim: number): string|Array + string(): string } - interface Reader { + interface URL { /** - * ReadLine is a low-level line-reading primitive. Most callers should use - * [Reader.ReadBytes]('\n') or [Reader.ReadString]('\n') instead or use a [Scanner]. - * - * ReadLine tries to return a single line, not including the end-of-line bytes. - * If the line was too long for the buffer then isPrefix is set and the - * beginning of the line is returned. The rest of the line will be returned - * from future calls. isPrefix will be false when returning the last fragment - * of the line. The returned buffer is only valid until the next call to - * ReadLine. ReadLine either returns a non-nil line or it returns an error, - * never both. - * - * The text returned from ReadLine does not include the line end ("\r\n" or "\n"). - * No indication or error is given if the input ends without a final line end. - * Calling [Reader.UnreadByte] after ReadLine will always unread the last byte read - * (possibly a character belonging to the line end) even if that byte is not - * part of the line returned by ReadLine. + * Redacted is like [URL.String] but replaces any password with "xxxxx". + * Only the password in u.User is redacted. */ - readLine(): [string|Array, boolean] + redacted(): string } - interface Reader { + /** + * Values maps a string key to a list of values. + * It is typically used for query parameters and form values. + * Unlike in the http.Header map, the keys in a Values map + * are case-sensitive. + */ + interface Values extends _TygojaDict{} + interface Values { /** - * ReadBytes reads until the first occurrence of delim in the input, - * returning a slice containing the data up to and including the delimiter. - * If ReadBytes encounters an error before finding a delimiter, - * it returns the data read before the error and the error itself (often io.EOF). - * ReadBytes returns err != nil if and only if the returned data does not end in - * delim. - * For simple uses, a Scanner may be more convenient. + * Get gets the first value associated with the given key. + * If there are no values associated with the key, Get returns + * the empty string. To access multiple values, use the map + * directly. */ - readBytes(delim: number): string|Array + get(key: string): string } - interface Reader { + interface Values { /** - * ReadString reads until the first occurrence of delim in the input, - * returning a string containing the data up to and including the delimiter. - * If ReadString encounters an error before finding a delimiter, - * it returns the data read before the error and the error itself (often io.EOF). - * ReadString returns err != nil if and only if the returned data does not end in - * delim. - * For simple uses, a Scanner may be more convenient. + * Set sets the key to value. It replaces any existing + * values. */ - readString(delim: number): string + set(key: string, value: string): void } - interface Reader { + interface Values { /** - * WriteTo implements io.WriterTo. - * This may make multiple calls to the [Reader.Read] method of the underlying [Reader]. - * If the underlying reader supports the [Reader.WriteTo] method, - * this calls the underlying [Reader.WriteTo] without buffering. + * Add adds the value to key. It appends to any existing + * values associated with key. */ - writeTo(w: io.Writer): number - } - /** - * Writer implements buffering for an [io.Writer] object. - * If an error occurs writing to a [Writer], no more data will be - * accepted and all subsequent writes, and [Writer.Flush], will return the error. - * After all data has been written, the client should call the - * [Writer.Flush] method to guarantee all data has been forwarded to - * the underlying [io.Writer]. - */ - interface Writer { + add(key: string, value: string): void } - interface Writer { + interface Values { /** - * Size returns the size of the underlying buffer in bytes. + * Del deletes the values associated with key. */ - size(): number + del(key: string): void } - interface Writer { + interface Values { /** - * Reset discards any unflushed buffered data, clears any error, and - * resets b to write its output to w. - * Calling Reset on the zero value of [Writer] initializes the internal buffer - * to the default size. - * Calling w.Reset(w) (that is, resetting a [Writer] to itself) does nothing. + * Has checks whether a given key is set. */ - reset(w: io.Writer): void + has(key: string): boolean } - interface Writer { + interface Values { /** - * Flush writes any buffered data to the underlying [io.Writer]. + * Encode encodes the values into “URL encoded” form + * ("bar=baz&foo=quux") sorted by key. */ - flush(): void + encode(): string } - interface Writer { + interface URL { /** - * Available returns how many bytes are unused in the buffer. + * IsAbs reports whether the [URL] is absolute. + * Absolute means that it has a non-empty scheme. */ - available(): number + isAbs(): boolean } - interface Writer { + interface URL { /** - * AvailableBuffer returns an empty buffer with b.Available() capacity. - * This buffer is intended to be appended to and - * passed to an immediately succeeding [Writer.Write] call. - * The buffer is only valid until the next write operation on b. + * Parse parses a [URL] in the context of the receiver. The provided URL + * may be relative or absolute. Parse returns nil, err on parse + * failure, otherwise its return value is the same as [URL.ResolveReference]. */ - availableBuffer(): string|Array + parse(ref: string): (URL) } - interface Writer { + interface URL { /** - * Buffered returns the number of bytes that have been written into the current buffer. + * ResolveReference resolves a URI reference to an absolute URI from + * an absolute base URI u, per RFC 3986 Section 5.2. The URI reference + * may be relative or absolute. ResolveReference always returns a new + * [URL] instance, even if the returned URL is identical to either the + * base or reference. If ref is an absolute URL, then ResolveReference + * ignores base and returns a copy of ref. */ - buffered(): number + resolveReference(ref: URL): (URL) } - interface Writer { + interface URL { /** - * Write writes the contents of p into the buffer. - * It returns the number of bytes written. - * If nn < len(p), it also returns an error explaining - * why the write is short. + * Query parses RawQuery and returns the corresponding values. + * It silently discards malformed value pairs. + * To check errors use [ParseQuery]. */ - write(p: string|Array): number + query(): Values } - interface Writer { + interface URL { /** - * WriteByte writes a single byte. + * RequestURI returns the encoded path?query or opaque?query + * string that would be used in an HTTP request for u. */ - writeByte(c: number): void + requestURI(): string } - interface Writer { + interface URL { /** - * WriteRune writes a single Unicode code point, returning - * the number of bytes written and any error. + * Hostname returns u.Host, stripping any valid port number if present. + * + * If the result is enclosed in square brackets, as literal IPv6 addresses are, + * the square brackets are removed from the result. */ - writeRune(r: number): number + hostname(): string } - interface Writer { + interface URL { /** - * WriteString writes a string. - * It returns the number of bytes written. - * If the count is less than len(s), it also returns an error explaining - * why the write is short. + * Port returns the port part of u.Host, without the leading colon. + * + * If u.Host doesn't contain a valid numeric port, Port returns an empty string. */ - writeString(s: string): number + port(): string } - interface Writer { + interface URL { + marshalBinary(): string|Array + } + interface URL { + appendBinary(b: string|Array): string|Array + } + interface URL { + unmarshalBinary(text: string|Array): void + } + interface URL { /** - * ReadFrom implements [io.ReaderFrom]. If the underlying writer - * supports the ReadFrom method, this calls the underlying ReadFrom. - * If there is buffered data and an underlying ReadFrom, this fills - * the buffer and writes it before calling ReadFrom. + * JoinPath returns a new [URL] with the provided path elements joined to + * any existing path and the resulting path cleaned of any ./ or ../ elements. + * Any sequences of multiple / characters will be reduced to a single /. */ - readFrom(r: io.Reader): number - } -} - -namespace net { - /** - * Addr represents a network end point address. - * - * The two methods [Addr.Network] and [Addr.String] conventionally return strings - * that can be passed as the arguments to [Dial], but the exact form - * and meaning of the strings is up to the implementation. - */ - interface Addr { - [key:string]: any; - network(): string // name of the network (for example, "tcp", "udp") - string(): string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80") + joinPath(...elem: string[]): (URL) } - // @ts-ignore - import _cgopackage = cgo } -/** - * Package textproto implements generic support for text-based request/response - * protocols in the style of HTTP, NNTP, and SMTP. - * - * This package enforces the HTTP/1.1 character set defined by - * RFC 9112 for header keys and values. - * - * The package provides: - * - * [Error], which represents a numeric error response from - * a server. - * - * [Pipeline], to manage pipelined requests and responses - * in a client. - * - * [Reader], to read numeric response code lines, - * key: value headers, lines wrapped with leading spaces - * on continuation lines, and whole text blocks ending - * with a dot on a line by itself. - * - * [Writer], to write dot-encoded text blocks. - * - * [Conn], a convenient packaging of [Reader], [Writer], and [Pipeline] for use - * with a single network connection. - */ -namespace textproto { +namespace bufio { /** - * A MIMEHeader represents a MIME-style header mapping - * keys to sets of values. + * Reader implements buffering for an io.Reader object. + * A new Reader is created by calling [NewReader] or [NewReaderSize]; + * alternatively the zero value of a Reader may be used after calling [Reset] + * on it. */ - interface MIMEHeader extends _TygojaDict{} - interface MIMEHeader { - /** - * Add adds the key, value pair to the header. - * It appends to any existing values associated with key. - */ - add(key: string, value: string): void + interface Reader { } - interface MIMEHeader { + interface Reader { /** - * Set sets the header entries associated with key to - * the single element value. It replaces any existing - * values associated with key. + * Size returns the size of the underlying buffer in bytes. */ - set(key: string, value: string): void + size(): number } - interface MIMEHeader { + interface Reader { /** - * Get gets the first value associated with the given key. - * It is case insensitive; [CanonicalMIMEHeaderKey] is used - * to canonicalize the provided key. - * If there are no values associated with the key, Get returns "". - * To use non-canonical keys, access the map directly. + * Reset discards any buffered data, resets all state, and switches + * the buffered reader to read from r. + * Calling Reset on the zero value of [Reader] initializes the internal buffer + * to the default size. + * Calling b.Reset(b) (that is, resetting a [Reader] to itself) does nothing. */ - get(key: string): string + reset(r: io.Reader): void } - interface MIMEHeader { + interface Reader { /** - * Values returns all values associated with the given key. - * It is case insensitive; [CanonicalMIMEHeaderKey] is - * used to canonicalize the provided key. To use non-canonical - * keys, access the map directly. - * The returned slice is not a copy. + * Peek returns the next n bytes without advancing the reader. The bytes stop + * being valid at the next read call. If necessary, Peek will read more bytes + * into the buffer in order to make n bytes available. If Peek returns fewer + * than n bytes, it also returns an error explaining why the read is short. + * The error is [ErrBufferFull] if n is larger than b's buffer size. + * + * Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding + * until the next read operation. */ - values(key: string): Array + peek(n: number): string|Array } - interface MIMEHeader { + interface Reader { /** - * Del deletes the values associated with key. + * Discard skips the next n bytes, returning the number of bytes discarded. + * + * If Discard skips fewer than n bytes, it also returns an error. + * If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without + * reading from the underlying io.Reader. */ - del(key: string): void + discard(n: number): number } -} - -namespace multipart { interface Reader { /** - * ReadForm parses an entire multipart message whose parts have - * a Content-Disposition of "form-data". - * It stores up to maxMemory bytes + 10MB (reserved for non-file parts) - * in memory. File parts which can't be stored in memory will be stored on - * disk in temporary files. - * It returns [ErrMessageTooLarge] if all non-file parts can't be stored in - * memory. + * Read reads data into p. + * It returns the number of bytes read into p. + * The bytes are taken from at most one Read on the underlying [Reader], + * hence n may be less than len(p). + * To read exactly len(p) bytes, use io.ReadFull(b, p). + * If the underlying [Reader] can return a non-zero count with io.EOF, + * then this Read method can do so as well; see the [io.Reader] docs. */ - readForm(maxMemory: number): (Form) - } - /** - * Form is a parsed multipart form. - * Its File parts are stored either in memory or on disk, - * and are accessible via the [*FileHeader]'s Open method. - * Its Value parts are stored as strings. - * Both are keyed by field name. - */ - interface Form { - value: _TygojaDict - file: _TygojaDict + read(p: string|Array): number } - interface Form { + interface Reader { /** - * RemoveAll removes any temporary files associated with a [Form]. + * ReadByte reads and returns a single byte. + * If no byte is available, returns an error. */ - removeAll(): void + readByte(): number } - /** - * File is an interface to access the file part of a multipart message. - * Its contents may be either stored in memory or on disk. - * If stored on disk, the File's underlying concrete type will be an *os.File. - */ - interface File { - [key:string]: any; + interface Reader { + /** + * UnreadByte unreads the last byte. Only the most recently read byte can be unread. + * + * UnreadByte returns an error if the most recent method called on the + * [Reader] was not a read operation. Notably, [Reader.Peek], [Reader.Discard], and [Reader.WriteTo] are not + * considered read operations. + */ + unreadByte(): void } - /** - * Reader is an iterator over parts in a MIME multipart body. - * Reader's underlying parser consumes its input as needed. Seeking - * isn't supported. - */ interface Reader { + /** + * ReadRune reads a single UTF-8 encoded Unicode character and returns the + * rune and its size in bytes. If the encoded rune is invalid, it consumes one byte + * and returns unicode.ReplacementChar (U+FFFD) with a size of 1. + */ + readRune(): [number, number] } interface Reader { /** - * NextPart returns the next part in the multipart or an error. - * When there are no more parts, the error [io.EOF] is returned. - * - * As a special case, if the "Content-Transfer-Encoding" header - * has a value of "quoted-printable", that header is instead - * hidden and the body is transparently decoded during Read calls. + * UnreadRune unreads the last rune. If the most recent method called on + * the [Reader] was not a [Reader.ReadRune], [Reader.UnreadRune] returns an error. (In this + * regard it is stricter than [Reader.UnreadByte], which will unread the last byte + * from any read operation.) */ - nextPart(): (Part) + unreadRune(): void } interface Reader { /** - * NextRawPart returns the next part in the multipart or an error. - * When there are no more parts, the error [io.EOF] is returned. - * - * Unlike [Reader.NextPart], it does not have special handling for - * "Content-Transfer-Encoding: quoted-printable". + * Buffered returns the number of bytes that can be read from the current buffer. */ - nextRawPart(): (Part) + buffered(): number } -} - -namespace cron { - /** - * Job defines a single registered cron job. - */ - interface Job { + interface Reader { + /** + * ReadSlice reads until the first occurrence of delim in the input, + * returning a slice pointing at the bytes in the buffer. + * The bytes stop being valid at the next read. + * If ReadSlice encounters an error before finding a delimiter, + * it returns all the data in the buffer and the error itself (often io.EOF). + * ReadSlice fails with error [ErrBufferFull] if the buffer fills without a delim. + * Because the data returned from ReadSlice will be overwritten + * by the next I/O operation, most clients should use + * [Reader.ReadBytes] or ReadString instead. + * ReadSlice returns err != nil if and only if line does not end in delim. + */ + readSlice(delim: number): string|Array } - interface Job { + interface Reader { /** - * Id returns the cron job id. + * ReadLine is a low-level line-reading primitive. Most callers should use + * [Reader.ReadBytes]('\n') or [Reader.ReadString]('\n') instead or use a [Scanner]. + * + * ReadLine tries to return a single line, not including the end-of-line bytes. + * If the line was too long for the buffer then isPrefix is set and the + * beginning of the line is returned. The rest of the line will be returned + * from future calls. isPrefix will be false when returning the last fragment + * of the line. The returned buffer is only valid until the next call to + * ReadLine. ReadLine either returns a non-nil line or it returns an error, + * never both. + * + * The text returned from ReadLine does not include the line end ("\r\n" or "\n"). + * No indication or error is given if the input ends without a final line end. + * Calling [Reader.UnreadByte] after ReadLine will always unread the last byte read + * (possibly a character belonging to the line end) even if that byte is not + * part of the line returned by ReadLine. */ - id(): string + readLine(): [string|Array, boolean] } - interface Job { + interface Reader { /** - * Expression returns the plain cron job schedule expression. + * ReadBytes reads until the first occurrence of delim in the input, + * returning a slice containing the data up to and including the delimiter. + * If ReadBytes encounters an error before finding a delimiter, + * it returns the data read before the error and the error itself (often io.EOF). + * ReadBytes returns err != nil if and only if the returned data does not end in + * delim. + * For simple uses, a Scanner may be more convenient. */ - expression(): string + readBytes(delim: number): string|Array } - interface Job { + interface Reader { /** - * Run runs the cron job function. + * ReadString reads until the first occurrence of delim in the input, + * returning a string containing the data up to and including the delimiter. + * If ReadString encounters an error before finding a delimiter, + * it returns the data read before the error and the error itself (often io.EOF). + * ReadString returns err != nil if and only if the returned data does not end in + * delim. + * For simple uses, a Scanner may be more convenient. */ - run(): void + readString(delim: number): string } - interface Job { + interface Reader { /** - * MarshalJSON implements [json.Marshaler] and export the current - * jobs data into valid JSON. + * WriteTo implements io.WriterTo. + * This may make multiple calls to the [Reader.Read] method of the underlying [Reader]. + * If the underlying reader supports the [Reader.WriteTo] method, + * this calls the underlying [Reader.WriteTo] without buffering. */ - marshalJSON(): string|Array + writeTo(w: io.Writer): number } -} - -/** - * Package url parses URLs and implements query escaping. - * - * See RFC 3986. This package generally follows RFC 3986, except where - * it deviates for compatibility reasons. - * RFC 6874 followed for IPv6 zone literals. - */ -namespace url { /** - * A URL represents a parsed URL (technically, a URI reference). - * - * The general form represented is: - * - * ``` - * [scheme:][//[userinfo@]host][/]path[?query][#fragment] - * ``` - * - * URLs that do not start with a slash after the scheme are interpreted as: - * - * ``` - * scheme:opaque[?query][#fragment] - * ``` - * - * The Host field contains the host and port subcomponents of the URL. - * When the port is present, it is separated from the host with a colon. - * When the host is an IPv6 address, it must be enclosed in square brackets: - * "[fe80::1]:80". The [net.JoinHostPort] function combines a host and port - * into a string suitable for the Host field, adding square brackets to - * the host when necessary. - * - * Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/. - * A consequence is that it is impossible to tell which slashes in the Path were - * slashes in the raw URL and which were %2f. This distinction is rarely important, - * but when it is, the code should use the [URL.EscapedPath] method, which preserves - * the original encoding of Path. - * - * The RawPath field is an optional field which is only set when the default - * encoding of Path is different from the escaped path. See the EscapedPath method - * for more details. - * - * URL's String method uses the EscapedPath method to obtain the path. + * Writer implements buffering for an [io.Writer] object. + * If an error occurs writing to a [Writer], no more data will be + * accepted and all subsequent writes, and [Writer.Flush], will return the error. + * After all data has been written, the client should call the + * [Writer.Flush] method to guarantee all data has been forwarded to + * the underlying [io.Writer]. */ - interface URL { - scheme: string - opaque: string // encoded opaque data - user?: Userinfo // username and password information - host: string // host or host:port (see Hostname and Port methods) - path: string // path (relative paths may omit leading slash) - rawPath: string // encoded path hint (see EscapedPath method) - omitHost: boolean // do not emit empty host (authority) - forceQuery: boolean // append a query ('?') even if RawQuery is empty - rawQuery: string // encoded query values, without '?' - fragment: string // fragment for references, without '#' - rawFragment: string // encoded fragment hint (see EscapedFragment method) + interface Writer { } - interface URL { + interface Writer { /** - * EscapedPath returns the escaped form of u.Path. - * In general there are multiple possible escaped forms of any path. - * EscapedPath returns u.RawPath when it is a valid escaping of u.Path. - * Otherwise EscapedPath ignores u.RawPath and computes an escaped - * form on its own. - * The [URL.String] and [URL.RequestURI] methods use EscapedPath to construct - * their results. - * In general, code should call EscapedPath instead of - * reading u.RawPath directly. + * Size returns the size of the underlying buffer in bytes. */ - escapedPath(): string + size(): number } - interface URL { + interface Writer { /** - * EscapedFragment returns the escaped form of u.Fragment. - * In general there are multiple possible escaped forms of any fragment. - * EscapedFragment returns u.RawFragment when it is a valid escaping of u.Fragment. - * Otherwise EscapedFragment ignores u.RawFragment and computes an escaped - * form on its own. - * The [URL.String] method uses EscapedFragment to construct its result. - * In general, code should call EscapedFragment instead of - * reading u.RawFragment directly. + * Reset discards any unflushed buffered data, clears any error, and + * resets b to write its output to w. + * Calling Reset on the zero value of [Writer] initializes the internal buffer + * to the default size. + * Calling w.Reset(w) (that is, resetting a [Writer] to itself) does nothing. */ - escapedFragment(): string + reset(w: io.Writer): void } - interface URL { + interface Writer { /** - * String reassembles the [URL] into a valid URL string. - * The general form of the result is one of: - * - * ``` - * scheme:opaque?query#fragment - * scheme://userinfo@host/path?query#fragment - * ``` - * - * If u.Opaque is non-empty, String uses the first form; - * otherwise it uses the second form. - * Any non-ASCII characters in host are escaped. - * To obtain the path, String uses u.EscapedPath(). - * - * In the second form, the following rules apply: - * ``` - * - if u.Scheme is empty, scheme: is omitted. - * - if u.User is nil, userinfo@ is omitted. - * - if u.Host is empty, host/ is omitted. - * - if u.Scheme and u.Host are empty and u.User is nil, - * the entire scheme://userinfo@host/ is omitted. - * - if u.Host is non-empty and u.Path begins with a /, - * the form host/path does not add its own /. - * - if u.RawQuery is empty, ?query is omitted. - * - if u.Fragment is empty, #fragment is omitted. - * ``` + * Flush writes any buffered data to the underlying [io.Writer]. */ - string(): string + flush(): void } - interface URL { + interface Writer { /** - * Redacted is like [URL.String] but replaces any password with "xxxxx". - * Only the password in u.User is redacted. + * Available returns how many bytes are unused in the buffer. */ - redacted(): string + available(): number } - /** - * Values maps a string key to a list of values. - * It is typically used for query parameters and form values. - * Unlike in the http.Header map, the keys in a Values map - * are case-sensitive. - */ - interface Values extends _TygojaDict{} - interface Values { + interface Writer { /** - * Get gets the first value associated with the given key. - * If there are no values associated with the key, Get returns - * the empty string. To access multiple values, use the map - * directly. + * AvailableBuffer returns an empty buffer with b.Available() capacity. + * This buffer is intended to be appended to and + * passed to an immediately succeeding [Writer.Write] call. + * The buffer is only valid until the next write operation on b. */ - get(key: string): string + availableBuffer(): string|Array } - interface Values { + interface Writer { /** - * Set sets the key to value. It replaces any existing - * values. + * Buffered returns the number of bytes that have been written into the current buffer. */ - set(key: string, value: string): void + buffered(): number } - interface Values { + interface Writer { /** - * Add adds the value to key. It appends to any existing - * values associated with key. + * Write writes the contents of p into the buffer. + * It returns the number of bytes written. + * If nn < len(p), it also returns an error explaining + * why the write is short. */ - add(key: string, value: string): void + write(p: string|Array): number } - interface Values { + interface Writer { /** - * Del deletes the values associated with key. + * WriteByte writes a single byte. */ - del(key: string): void + writeByte(c: number): void } - interface Values { + interface Writer { /** - * Has checks whether a given key is set. + * WriteRune writes a single Unicode code point, returning + * the number of bytes written and any error. */ - has(key: string): boolean + writeRune(r: number): number } - interface Values { + interface Writer { /** - * Encode encodes the values into “URL encoded” form - * ("bar=baz&foo=quux") sorted by key. + * WriteString writes a string. + * It returns the number of bytes written. + * If the count is less than len(s), it also returns an error explaining + * why the write is short. */ - encode(): string + writeString(s: string): number } - interface URL { + interface Writer { /** - * IsAbs reports whether the [URL] is absolute. - * Absolute means that it has a non-empty scheme. + * ReadFrom implements [io.ReaderFrom]. If the underlying writer + * supports the ReadFrom method, this calls the underlying ReadFrom. + * If there is buffered data and an underlying ReadFrom, this fills + * the buffer and writes it before calling ReadFrom. */ - isAbs(): boolean + readFrom(r: io.Reader): number } - interface URL { +} + +/** + * Package textproto implements generic support for text-based request/response + * protocols in the style of HTTP, NNTP, and SMTP. + * + * This package enforces the HTTP/1.1 character set defined by + * RFC 9112 for header keys and values. + * + * The package provides: + * + * [Error], which represents a numeric error response from + * a server. + * + * [Pipeline], to manage pipelined requests and responses + * in a client. + * + * [Reader], to read numeric response code lines, + * key: value headers, lines wrapped with leading spaces + * on continuation lines, and whole text blocks ending + * with a dot on a line by itself. + * + * [Writer], to write dot-encoded text blocks. + * + * [Conn], a convenient packaging of [Reader], [Writer], and [Pipeline] for use + * with a single network connection. + */ +namespace textproto { + /** + * A MIMEHeader represents a MIME-style header mapping + * keys to sets of values. + */ + interface MIMEHeader extends _TygojaDict{} + interface MIMEHeader { /** - * Parse parses a [URL] in the context of the receiver. The provided URL - * may be relative or absolute. Parse returns nil, err on parse - * failure, otherwise its return value is the same as [URL.ResolveReference]. + * Add adds the key, value pair to the header. + * It appends to any existing values associated with key. */ - parse(ref: string): (URL) + add(key: string, value: string): void } - interface URL { + interface MIMEHeader { /** - * ResolveReference resolves a URI reference to an absolute URI from - * an absolute base URI u, per RFC 3986 Section 5.2. The URI reference - * may be relative or absolute. ResolveReference always returns a new - * [URL] instance, even if the returned URL is identical to either the - * base or reference. If ref is an absolute URL, then ResolveReference - * ignores base and returns a copy of ref. + * Set sets the header entries associated with key to + * the single element value. It replaces any existing + * values associated with key. */ - resolveReference(ref: URL): (URL) + set(key: string, value: string): void + } + interface MIMEHeader { + /** + * Get gets the first value associated with the given key. + * It is case insensitive; [CanonicalMIMEHeaderKey] is used + * to canonicalize the provided key. + * If there are no values associated with the key, Get returns "". + * To use non-canonical keys, access the map directly. + */ + get(key: string): string + } + interface MIMEHeader { + /** + * Values returns all values associated with the given key. + * It is case insensitive; [CanonicalMIMEHeaderKey] is + * used to canonicalize the provided key. To use non-canonical + * keys, access the map directly. + * The returned slice is not a copy. + */ + values(key: string): Array + } + interface MIMEHeader { + /** + * Del deletes the values associated with key. + */ + del(key: string): void + } +} + +namespace multipart { + interface Reader { + /** + * ReadForm parses an entire multipart message whose parts have + * a Content-Disposition of "form-data". + * It stores up to maxMemory bytes + 10MB (reserved for non-file parts) + * in memory. File parts which can't be stored in memory will be stored on + * disk in temporary files. + * It returns [ErrMessageTooLarge] if all non-file parts can't be stored in + * memory. + */ + readForm(maxMemory: number): (Form) + } + /** + * Form is a parsed multipart form. + * Its File parts are stored either in memory or on disk, + * and are accessible via the [*FileHeader]'s Open method. + * Its Value parts are stored as strings. + * Both are keyed by field name. + */ + interface Form { + value: _TygojaDict + file: _TygojaDict } - interface URL { + interface Form { /** - * Query parses RawQuery and returns the corresponding values. - * It silently discards malformed value pairs. - * To check errors use [ParseQuery]. + * RemoveAll removes any temporary files associated with a [Form]. */ - query(): Values + removeAll(): void } - interface URL { - /** - * RequestURI returns the encoded path?query or opaque?query - * string that would be used in an HTTP request for u. - */ - requestURI(): string + /** + * File is an interface to access the file part of a multipart message. + * Its contents may be either stored in memory or on disk. + * If stored on disk, the File's underlying concrete type will be an *os.File. + */ + interface File { + [key:string]: any; } - interface URL { - /** - * Hostname returns u.Host, stripping any valid port number if present. - * - * If the result is enclosed in square brackets, as literal IPv6 addresses are, - * the square brackets are removed from the result. - */ - hostname(): string + /** + * Reader is an iterator over parts in a MIME multipart body. + * Reader's underlying parser consumes its input as needed. Seeking + * isn't supported. + */ + interface Reader { } - interface URL { + interface Reader { /** - * Port returns the port part of u.Host, without the leading colon. + * NextPart returns the next part in the multipart or an error. + * When there are no more parts, the error [io.EOF] is returned. * - * If u.Host doesn't contain a valid numeric port, Port returns an empty string. + * As a special case, if the "Content-Transfer-Encoding" header + * has a value of "quoted-printable", that header is instead + * hidden and the body is transparently decoded during Read calls. */ - port(): string - } - interface URL { - marshalBinary(): string|Array - } - interface URL { - appendBinary(b: string|Array): string|Array - } - interface URL { - unmarshalBinary(text: string|Array): void + nextPart(): (Part) } - interface URL { + interface Reader { /** - * JoinPath returns a new [URL] with the provided path elements joined to - * any existing path and the resulting path cleaned of any ./ or ../ elements. - * Any sequences of multiple / characters will be reduced to a single /. + * NextRawPart returns the next part in the multipart or an error. + * When there are no more parts, the error [io.EOF] is returned. + * + * Unlike [Reader.NextPart], it does not have special handling for + * "Content-Transfer-Encoding: quoted-printable". */ - joinPath(...elem: string[]): (URL) + nextRawPart(): (Part) } } @@ -23581,13 +23507,19 @@ namespace oauth2 { } } +namespace types { +} + +namespace store { +} + namespace jwt { /** * NumericDate represents a JSON numeric date value, as referenced at * https://datatracker.ietf.org/doc/html/rfc7519#section-2. */ - type _sGiaGYO = time.Time - interface NumericDate extends _sGiaGYO { + type _sdvgjIR = time.Time + interface NumericDate extends _sdvgjIR { } interface NumericDate { /** @@ -23619,82 +23551,191 @@ namespace jwt { } } -namespace store { -} - namespace hook { /** * wrapped local Hook embedded struct to limit the public API surface. */ - type _sHoxvkd = Hook - interface mainHook extends _sHoxvkd { + type _sMiUliE = Hook + interface mainHook extends _sMiUliE { } } -namespace cobra { - interface PositionalArgs {(cmd: Command, args: Array): void } - // @ts-ignore - import flag = pflag +namespace slog { /** - * FParseErrWhitelist configures Flag parse errors to be ignored + * An Attr is a key-value pair. */ - interface FParseErrWhitelist extends _TygojaAny{} + interface Attr { + key: string + value: Value + } + interface Attr { + /** + * Equal reports whether a and b have equal keys and values. + */ + equal(b: Attr): boolean + } + interface Attr { + string(): string + } /** - * Group Structure to manage groups for commands + * A Handler handles log records produced by a Logger. + * + * A typical handler may print log records to standard error, + * or write them to a file or database, or perhaps augment them + * with additional attributes and pass them on to another handler. + * + * Any of the Handler's methods may be called concurrently with itself + * or with other methods. It is the responsibility of the Handler to + * manage this concurrency. + * + * Users of the slog package should not invoke Handler methods directly. + * They should use the methods of [Logger] instead. + * + * Before implementing your own handler, consult https://go.dev/s/slog-handler-guide. */ - interface Group { - id: string - title: string + interface Handler { + [key:string]: any; + /** + * Enabled reports whether the handler handles records at the given level. + * The handler ignores records whose level is lower. + * It is called early, before any arguments are processed, + * to save effort if the log event should be discarded. + * If called from a Logger method, the first argument is the context + * passed to that method, or context.Background() if nil was passed + * or the method does not take a context. + * The context is passed so Enabled can use its values + * to make a decision. + */ + enabled(_arg0: context.Context, _arg1: Level): boolean + /** + * Handle handles the Record. + * It will only be called when Enabled returns true. + * The Context argument is as for Enabled. + * It is present solely to provide Handlers access to the context's values. + * Canceling the context should not affect record processing. + * (Among other things, log messages may be necessary to debug a + * cancellation-related problem.) + * + * Handle methods that produce output should observe the following rules: + * ``` + * - If r.Time is the zero time, ignore the time. + * - If r.PC is zero, ignore it. + * - Attr's values should be resolved. + * - If an Attr's key and value are both the zero value, ignore the Attr. + * This can be tested with attr.Equal(Attr{}). + * - If a group's key is empty, inline the group's Attrs. + * - If a group has no Attrs (even if it has a non-empty key), + * ignore it. + * ``` + * + * [Logger] discards any errors from Handle. Wrap the Handle method to + * process any errors from Handlers. + */ + handle(_arg0: context.Context, _arg1: Record): void + /** + * WithAttrs returns a new Handler whose attributes consist of + * both the receiver's attributes and the arguments. + * The Handler owns the slice: it may retain, modify or discard it. + */ + withAttrs(attrs: Array): Handler + /** + * WithGroup returns a new Handler with the given group appended to + * the receiver's existing groups. + * The keys of all subsequent attributes, whether added by With or in a + * Record, should be qualified by the sequence of group names. + * + * How this qualification happens is up to the Handler, so long as + * this Handler's attribute keys differ from those of another Handler + * with a different sequence of group names. + * + * A Handler should treat WithGroup as starting a Group of Attrs that ends + * at the end of the log event. That is, + * + * ``` + * logger.WithGroup("s").LogAttrs(ctx, level, msg, slog.Int("a", 1), slog.Int("b", 2)) + * ``` + * + * should behave like + * + * ``` + * logger.LogAttrs(ctx, level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2))) + * ``` + * + * If the name is empty, WithGroup returns the receiver. + */ + withGroup(name: string): Handler } /** - * CompletionOptions are the options to control shell completion + * A Level is the importance or severity of a log event. + * The higher the level, the more important or severe the event. */ - interface CompletionOptions { + interface Level extends Number{} + interface Level { /** - * DisableDefaultCmd prevents Cobra from creating a default 'completion' command + * String returns a name for the level. + * If the level has a name, then that name + * in uppercase is returned. + * If the level is between named values, then + * an integer is appended to the uppercased name. + * Examples: + * + * ``` + * LevelWarn.String() => "WARN" + * (LevelInfo+2).String() => "INFO+2" + * ``` */ - disableDefaultCmd: boolean + string(): string + } + interface Level { /** - * DisableNoDescFlag prevents Cobra from creating the '--no-descriptions' flag - * for shells that support completion descriptions + * MarshalJSON implements [encoding/json.Marshaler] + * by quoting the output of [Level.String]. */ - disableNoDescFlag: boolean + marshalJSON(): string|Array + } + interface Level { /** - * DisableDescriptions turns off all completion descriptions for shells - * that support them + * UnmarshalJSON implements [encoding/json.Unmarshaler] + * It accepts any string produced by [Level.MarshalJSON], + * ignoring case. + * It also accepts numeric offsets that would result in a different string on + * output. For example, "Error-8" would marshal as "INFO". */ - disableDescriptions: boolean + unmarshalJSON(data: string|Array): void + } + interface Level { /** - * HiddenDefaultCmd makes the default 'completion' command hidden + * AppendText implements [encoding.TextAppender] + * by calling [Level.String]. */ - hiddenDefaultCmd: boolean + appendText(b: string|Array): string|Array + } + interface Level { /** - * DefaultShellCompDirective sets the ShellCompDirective that is returned - * if no special directive can be determined + * MarshalText implements [encoding.TextMarshaler] + * by calling [Level.AppendText]. */ - defaultShellCompDirective?: ShellCompDirective + marshalText(): string|Array } - interface CompletionOptions { - setDefaultShellCompDirective(directive: ShellCompDirective): void + interface Level { + /** + * UnmarshalText implements [encoding.TextUnmarshaler]. + * It accepts any string produced by [Level.MarshalText], + * ignoring case. + * It also accepts numeric offsets that would result in a different string on + * output. For example, "Error-8" would marshal as "INFO". + */ + unmarshalText(data: string|Array): void + } + interface Level { + /** + * Level returns the receiver. + * It implements [Leveler]. + */ + level(): Level } - /** - * Completion is a string that can be used for completions - * - * two formats are supported: - * ``` - * - the completion choice - * - the completion choice with a textual description (separated by a TAB). - * ``` - * - * [CompletionWithDesc] can be used to create a completion string with a textual description. - * - * Note: Go type alias is used to provide a more descriptive name in the documentation, but any string can be used. - */ - interface Completion extends String{} - /** - * CompletionFunc is a function that provides completion results. - */ - interface CompletionFunc {(cmd: Command, args: Array, toComplete: string): [Array, ShellCompDirective] } + // @ts-ignore + import loginternal = internal } namespace sql { @@ -23900,9 +23941,6 @@ namespace sql { } } -namespace types { -} - namespace search { /** * MultiMatchSubquery defines a multi-match record subquery expression. @@ -23926,9 +23964,6 @@ namespace search { interface NullFallbackPreference extends Number{} } -namespace subscriptions { -} - namespace router { // @ts-ignore import validation = ozzo_validation @@ -24063,6 +24098,108 @@ namespace router { } } +namespace cobra { + interface PositionalArgs {(cmd: Command, args: Array): void } + // @ts-ignore + import flag = pflag + /** + * FParseErrWhitelist configures Flag parse errors to be ignored + */ + interface FParseErrWhitelist extends _TygojaAny{} + /** + * Group Structure to manage groups for commands + */ + interface Group { + id: string + title: string + } + /** + * CompletionOptions are the options to control shell completion + */ + interface CompletionOptions { + /** + * DisableDefaultCmd prevents Cobra from creating a default 'completion' command + */ + disableDefaultCmd: boolean + /** + * DisableNoDescFlag prevents Cobra from creating the '--no-descriptions' flag + * for shells that support completion descriptions + */ + disableNoDescFlag: boolean + /** + * DisableDescriptions turns off all completion descriptions for shells + * that support them + */ + disableDescriptions: boolean + /** + * HiddenDefaultCmd makes the default 'completion' command hidden + */ + hiddenDefaultCmd: boolean + /** + * DefaultShellCompDirective sets the ShellCompDirective that is returned + * if no special directive can be determined + */ + defaultShellCompDirective?: ShellCompDirective + } + interface CompletionOptions { + setDefaultShellCompDirective(directive: ShellCompDirective): void + } + /** + * Completion is a string that can be used for completions + * + * two formats are supported: + * ``` + * - the completion choice + * - the completion choice with a textual description (separated by a TAB). + * ``` + * + * [CompletionWithDesc] can be used to create a completion string with a textual description. + * + * Note: Go type alias is used to provide a more descriptive name in the documentation, but any string can be used. + */ + interface Completion extends String{} + /** + * CompletionFunc is a function that provides completion results. + */ + interface CompletionFunc {(cmd: Command, args: Array, toComplete: string): [Array, ShellCompDirective] } +} + +namespace cron { + /** + * Job defines a single registered cron job. + */ + interface Job { + } + interface Job { + /** + * Id returns the cron job id. + */ + id(): string + } + interface Job { + /** + * Expression returns the plain cron job schedule expression. + */ + expression(): string + } + interface Job { + /** + * Run runs the cron job function. + */ + run(): void + } + interface Job { + /** + * MarshalJSON implements [json.Marshaler] and export the current + * jobs data into valid JSON. + */ + marshalJSON(): string|Array + } +} + +namespace subscriptions { +} + namespace url { /** * The Userinfo type is an immutable encapsulation of username and @@ -24093,6 +24230,17 @@ namespace url { } } +namespace search { + /** + * Join defines common fields required for a single SQL JOIN clause. + */ + interface Join { + tableName: string + tableAlias: string + on: dbx.Expression + } +} + namespace multipart { /** * A Part represents a single part in a multipart body. @@ -24148,6 +24296,57 @@ namespace http { import urlpkg = url } +namespace router { + // @ts-ignore + import validation = ozzo_validation + interface Route { + action: (e: T) => void + method: string + path: string + middlewares: Array<(hook.Handler | undefined)> + } + interface Route { + /** + * BindFunc registers one or multiple middleware functions to the current route. + * + * The registered middleware functions are "anonymous" and with default priority, + * aka. executes in the order they were registered. + * + * If you need to specify a named middleware (ex. so that it can be removed) + * or middleware with custom exec prirority, use the [Route.Bind] method. + */ + bindFunc(...middlewareFuncs: ((e: T) => void)[]): (Route) + } + interface Route { + /** + * Bind registers one or multiple middleware handlers to the current route. + */ + bind(...middlewares: (hook.Handler | undefined)[]): (Route) + } + interface Route { + /** + * Unbind removes one or more middlewares with the specified id(s) from the current route. + * + * It also adds the removed middleware ids to an exclude list so that they could be skipped from + * the execution chain in case the middleware is registered in a parent group. + * + * Anonymous middlewares are considered non-removable, aka. this method + * does nothing if the middleware id is an empty string. + */ + unbind(...middlewareIds: string[]): (Route) + } +} + +namespace cobra { + // @ts-ignore + import flag = pflag + /** + * ShellCompDirective is a bit map representing the different behaviors the shell + * can be instructed to have once completions have been provided. + */ + interface ShellCompDirective extends Number{} +} + namespace oauth2 { } @@ -24331,66 +24530,9 @@ namespace slog { } } -namespace cobra { - // @ts-ignore - import flag = pflag - /** - * ShellCompDirective is a bit map representing the different behaviors the shell - * can be instructed to have once completions have been provided. - */ - interface ShellCompDirective extends Number{} -} - -namespace search { - /** - * Join defines common fields required for a single SQL JOIN clause. - */ - interface Join { - tableName: string - tableAlias: string - on: dbx.Expression - } -} - namespace router { // @ts-ignore import validation = ozzo_validation - interface Route { - action: (e: T) => void - method: string - path: string - middlewares: Array<(hook.Handler | undefined)> - } - interface Route { - /** - * BindFunc registers one or multiple middleware functions to the current route. - * - * The registered middleware functions are "anonymous" and with default priority, - * aka. executes in the order they were registered. - * - * If you need to specify a named middleware (ex. so that it can be removed) - * or middleware with custom exec prirority, use the [Route.Bind] method. - */ - bindFunc(...middlewareFuncs: ((e: T) => void)[]): (Route) - } - interface Route { - /** - * Bind registers one or multiple middleware handlers to the current route. - */ - bind(...middlewares: (hook.Handler | undefined)[]): (Route) - } - interface Route { - /** - * Unbind removes one or more middlewares with the specified id(s) from the current route. - * - * It also adds the removed middleware ids to an exclude list so that they could be skipped from - * the execution chain in case the middleware is registered in a parent group. - * - * Anonymous middlewares are considered non-removable, aka. this method - * does nothing if the middleware id is an empty string. - */ - unbind(...middlewareIds: string[]): (Route) - } } namespace slog { @@ -24431,8 +24573,3 @@ namespace slog { logValue(): Value } } - -namespace router { - // @ts-ignore - import validation = ozzo_validation -} diff --git a/tools/filesystem/filesystem.go b/tools/filesystem/filesystem.go index 50b602f99e..e2db386baf 100644 --- a/tools/filesystem/filesystem.go +++ b/tools/filesystem/filesystem.go @@ -32,7 +32,7 @@ import ( // note: the same as blob.ErrNotFound for backward compatibility with earlier versions var ErrNotFound = blob.ErrNotFound -const metadataOriginalName = "original-filename" +const MetadataOriginalName = "original-filename" type System struct { ctx context.Context @@ -145,7 +145,7 @@ func (s *System) GetReuploadableFile(fileKey string, preserveName bool) (*File, } name := path.Base(fileKey) - originalName := attrs.Metadata[metadataOriginalName] + originalName := attrs.Metadata[MetadataOriginalName] if originalName == "" { originalName = name } @@ -240,7 +240,7 @@ func (s *System) UploadFile(file *File, fileKey string) error { opts := &blob.WriterOptions{ ContentType: mt.String(), Metadata: map[string]string{ - metadataOriginalName: originalName, + MetadataOriginalName: originalName, }, } @@ -282,7 +282,7 @@ func (s *System) UploadMultipart(fh *multipart.FileHeader, fileKey string) error opts := &blob.WriterOptions{ ContentType: mt.String(), Metadata: map[string]string{ - metadataOriginalName: originalName, + MetadataOriginalName: originalName, }, } @@ -300,6 +300,30 @@ func (s *System) UploadMultipart(fh *multipart.FileHeader, fileKey string) error return w.Close() } +// NewWriter returns a new blob.Writer instance allowing direct file +// create from an io.Reader value. +// +// If a file with the specified fileKey already exists, it will be replaced. +// +// NB! Make sure to call `Close()` on the resulting writer after you are done working with it. +// +// Note: If you have a bytes slice, [filesystem.File], or a multipart header value, +// you can check also the Upload* related methods as they are more user-friendly. +// +// Example: +// +// content := strings.NewReader("Lorem ipsum dolor sit amet...") +// +// fsys, _ := filesystem.NewLocal("dir") +// defer fsys.Close() +// +// w, _ := fsys.NewWriter("example/file/key", nil) +// w.ReadFrom(content) +// w.Close() +func (s *System) NewWriter(fileKey string, opts *blob.WriterOptions) (*blob.Writer, error) { + return s.bucket.NewWriter(s.ctx, fileKey, opts) +} + // Delete deletes stored file at fileKey location. // // If the file doesn't exist returns ErrNotFound. diff --git a/tools/filesystem/filesystem_test.go b/tools/filesystem/filesystem_test.go index f3e2063438..9fafdfb936 100644 --- a/tools/filesystem/filesystem_test.go +++ b/tools/filesystem/filesystem_test.go @@ -17,9 +17,10 @@ import ( "github.com/gabriel-vasile/mimetype" "github.com/pocketbase/pocketbase/tools/filesystem" + "github.com/pocketbase/pocketbase/tools/filesystem/blob" ) -func TestFileSystemExists(t *testing.T) { +func TestFilesystemExists(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -54,7 +55,7 @@ func TestFileSystemExists(t *testing.T) { } } -func TestFileSystemAttributes(t *testing.T) { +func TestFilesystemAttributes(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -96,7 +97,68 @@ func TestFileSystemAttributes(t *testing.T) { } } -func TestFileSystemDelete(t *testing.T) { +func TestFilesystemNewWriter(t *testing.T) { + dir := createTestDir(t) + defer os.RemoveAll(dir) + + fsys, err := filesystem.NewLocal(dir) + if err != nil { + t.Fatal(err) + } + defer fsys.Close() + + testKey := "test_writer" + + opts := &blob.WriterOptions{ + Metadata: map[string]string{"test": "abc"}, + } + + w, err := fsys.NewWriter("test_writer", opts) + if err != nil { + t.Fatal(err) + } + + expectedContent := "test_content" + + _, err = w.ReadFrom(strings.NewReader(expectedContent)) + if err != nil { + t.Fatal(err) + } + + err = w.Close() + if err != nil { + t.Fatal(err) + } + + // verify that the file attributes and content were properly saved + // --------------------------------------------------------------- + attrs, err := fsys.Attributes(testKey) + if err != nil { + t.Fatal(err) + } + if attrs.Metadata["test"] != "abc" { + t.Fatalf("Expected metadata test:abc, got %v", attrs.Metadata) + } + + r, err := fsys.GetReader(testKey) + if err != nil { + t.Fatal(err) + } + + var buf bytes.Buffer + + _, err = io.Copy(&buf, r) + if err != nil { + t.Fatal(err) + } + + result := buf.String() + if result != expectedContent { + t.Fatalf("Expected file content\n%s\ngot\n%s", expectedContent, result) + } +} + +func TestFilesystemDelete(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -115,7 +177,7 @@ func TestFileSystemDelete(t *testing.T) { } } -func TestFileSystemDeletePrefixWithoutTrailingSlash(t *testing.T) { +func TestFilesystemDeletePrefixWithoutTrailingSlash(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -151,7 +213,7 @@ func TestFileSystemDeletePrefixWithoutTrailingSlash(t *testing.T) { } } -func TestFileSystemDeletePrefixWithTrailingSlash(t *testing.T) { +func TestFilesystemDeletePrefixWithTrailingSlash(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -183,7 +245,7 @@ func TestFileSystemDeletePrefixWithTrailingSlash(t *testing.T) { } } -func TestFileSystemIsEmptyDir(t *testing.T) { +func TestFilesystemIsEmptyDir(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -218,7 +280,7 @@ func TestFileSystemIsEmptyDir(t *testing.T) { } } -func TestFileSystemUploadMultipart(t *testing.T) { +func TestFilesystemUploadMultipart(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -268,7 +330,7 @@ func TestFileSystemUploadMultipart(t *testing.T) { } } -func TestFileSystemUploadFile(t *testing.T) { +func TestFilesystemUploadFile(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -305,7 +367,7 @@ func TestFileSystemUploadFile(t *testing.T) { } } -func TestFileSystemUpload(t *testing.T) { +func TestFilesystemUpload(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -327,7 +389,7 @@ func TestFileSystemUpload(t *testing.T) { } } -func TestFileSystemServe(t *testing.T) { +func TestFilesystemServe(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -571,7 +633,7 @@ func TestFileSystemServe(t *testing.T) { } } -func TestFileSystemGetReader(t *testing.T) { +func TestFilesystemGetReader(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -623,7 +685,7 @@ func TestFileSystemGetReader(t *testing.T) { } } -func TestFileSystemGetReuploadableFile(t *testing.T) { +func TestFilesystemGetReuploadableFile(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -701,7 +763,7 @@ func TestFileSystemGetReuploadableFile(t *testing.T) { }) } -func TestFileSystemCopy(t *testing.T) { +func TestFilesystemCopy(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -735,7 +797,7 @@ func TestFileSystemCopy(t *testing.T) { } } -func TestFileSystemList(t *testing.T) { +func TestFilesystemList(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -809,7 +871,7 @@ func TestFileSystemList(t *testing.T) { } } -func TestFileSystemServeSingleRange(t *testing.T) { +func TestFilesystemServeSingleRange(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -843,7 +905,7 @@ func TestFileSystemServeSingleRange(t *testing.T) { } } -func TestFileSystemServeMultiRange(t *testing.T) { +func TestFilesystemServeMultiRange(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) @@ -872,7 +934,7 @@ func TestFileSystemServeMultiRange(t *testing.T) { } } -func TestFileSystemCreateThumb(t *testing.T) { +func TestFilesystemCreateThumb(t *testing.T) { dir := createTestDir(t) defer os.RemoveAll(dir) From 9f1a4bcfa5e3b182c22f17e0a29769a1c38d0b81 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Mon, 10 Aug 2026 08:15:14 +0300 Subject: [PATCH 07/37] minor ui base component fixes and shablon update --- .../{index-Kt84cKKj.js => index-atA5M29y.js} | 4 ++-- ...DVeUb.js => pageConfirmEmailChange-GJOKtnpT.js} | 2 +- ...Irh.js => pageConfirmPasswordReset-CpS0TV-W.js} | 2 +- ...9bV_.js => pageConfirmVerification-C7k_WAxC.js} | 2 +- ...aller-D0gTHS34.js => pageInstaller-BaO0hIrw.js} | 2 +- ui/dist/index.html | 2 +- ui/dist/libs/shablon/shablon.iife.js | 6 +++--- ui/public/libs/shablon/shablon.iife.js | 6 +++--- ui/src/base/codeEditor.js | 6 ++++++ ui/src/base/dropdownKeyboardNav.js | 6 ++++++ ui/src/base/sortable.js | 14 ++++++++++---- 11 files changed, 35 insertions(+), 17 deletions(-) rename ui/dist/assets/{index-Kt84cKKj.js => index-atA5M29y.js} (96%) rename ui/dist/assets/{pageConfirmEmailChange-BXaDVeUb.js => pageConfirmEmailChange-GJOKtnpT.js} (97%) rename ui/dist/assets/{pageConfirmPasswordReset-DY_-cIrh.js => pageConfirmPasswordReset-CpS0TV-W.js} (97%) rename ui/dist/assets/{pageConfirmVerification-Bo-r9bV_.js => pageConfirmVerification-C7k_WAxC.js} (96%) rename ui/dist/assets/{pageInstaller-D0gTHS34.js => pageInstaller-BaO0hIrw.js} (98%) diff --git a/ui/dist/assets/index-Kt84cKKj.js b/ui/dist/assets/index-atA5M29y.js similarity index 96% rename from ui/dist/assets/index-Kt84cKKj.js rename to ui/dist/assets/index-atA5M29y.js index 606aa924e2..78790cab88 100644 --- a/ui/dist/assets/index-Kt84cKKj.js +++ b/ui/dist/assets/index-atA5M29y.js @@ -4,7 +4,7 @@ var e=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i= `),n+=r.map(e=>{let n=``;return e.name.includes(`(`)||e.name.includes(` `)?n+=e.name:n+="`"+e.name+"`",e.collate&&(n+=` COLLATE `+e.collate),e.sort&&(n+=` `+e.sort.toUpperCase()),n}).join(`, `),r.length>1&&(n+=` `),n+=`)`,e.where&&(n+=` WHERE ${e.where}`),n},replaceIndexFields(e,n){let r=app.utils.parseIndex(e);return typeof n==`function`?Object.assign(r,n(r)||{}):Object.assign(r,n||{}),app.utils.buildIndex(r)},replaceIndexColumn(e,n,r){if(n===r)return e;let i=app.utils.parseIndex(e),a=!1;for(let e of i.columns)e.name===n&&(e.name=r,a=!0);return a?app.utils.buildIndex(i):e}};window.app=window.app||{},window.app.utils=f,window.app=window.app||{},window.app.utils=window.app.utils||{},window.app.utils.mimeTypes=[{ext:``,mimeType:`application/octet-stream`},{ext:`.xpm`,mimeType:`image/x-xpixmap`},{ext:`.7z`,mimeType:`application/x-7z-compressed`},{ext:`.zip`,mimeType:`application/zip`},{ext:`.xlsx`,mimeType:`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`},{ext:`.docx`,mimeType:`application/vnd.openxmlformats-officedocument.wordprocessingml.document`},{ext:`.pptx`,mimeType:`application/vnd.openxmlformats-officedocument.presentationml.presentation`},{ext:`.epub`,mimeType:`application/epub+zip`},{ext:`.apk`,mimeType:`application/vnd.android.package-archive`},{ext:`.jar`,mimeType:`application/jar`},{ext:`.odt`,mimeType:`application/vnd.oasis.opendocument.text`},{ext:`.ott`,mimeType:`application/vnd.oasis.opendocument.text-template`},{ext:`.ods`,mimeType:`application/vnd.oasis.opendocument.spreadsheet`},{ext:`.ots`,mimeType:`application/vnd.oasis.opendocument.spreadsheet-template`},{ext:`.odp`,mimeType:`application/vnd.oasis.opendocument.presentation`},{ext:`.otp`,mimeType:`application/vnd.oasis.opendocument.presentation-template`},{ext:`.odg`,mimeType:`application/vnd.oasis.opendocument.graphics`},{ext:`.otg`,mimeType:`application/vnd.oasis.opendocument.graphics-template`},{ext:`.odf`,mimeType:`application/vnd.oasis.opendocument.formula`},{ext:`.odc`,mimeType:`application/vnd.oasis.opendocument.chart`},{ext:`.sxc`,mimeType:`application/vnd.sun.xml.calc`},{ext:`.pdf`,mimeType:`application/pdf`},{ext:`.fdf`,mimeType:`application/vnd.fdf`},{ext:``,mimeType:`application/x-ole-storage`},{ext:`.msi`,mimeType:`application/x-ms-installer`},{ext:`.aaf`,mimeType:`application/octet-stream`},{ext:`.msg`,mimeType:`application/vnd.ms-outlook`},{ext:`.xls`,mimeType:`application/vnd.ms-excel`},{ext:`.pub`,mimeType:`application/vnd.ms-publisher`},{ext:`.ppt`,mimeType:`application/vnd.ms-powerpoint`},{ext:`.doc`,mimeType:`application/msword`},{ext:`.ps`,mimeType:`application/postscript`},{ext:`.psd`,mimeType:`image/vnd.adobe.photoshop`},{ext:`.p7s`,mimeType:`application/pkcs7-signature`},{ext:`.ogg`,mimeType:`application/ogg`},{ext:`.oga`,mimeType:`audio/ogg`},{ext:`.ogv`,mimeType:`video/ogg`},{ext:`.png`,mimeType:`image/png`},{ext:`.png`,mimeType:`image/vnd.mozilla.apng`},{ext:`.jpg`,mimeType:`image/jpeg`},{ext:`.jxl`,mimeType:`image/jxl`},{ext:`.jp2`,mimeType:`image/jp2`},{ext:`.jpf`,mimeType:`image/jpx`},{ext:`.jpm`,mimeType:`image/jpm`},{ext:`.jxs`,mimeType:`image/jxs`},{ext:`.gif`,mimeType:`image/gif`},{ext:`.webp`,mimeType:`image/webp`},{ext:`.exe`,mimeType:`application/vnd.microsoft.portable-executable`},{ext:``,mimeType:`application/x-elf`},{ext:``,mimeType:`application/x-object`},{ext:``,mimeType:`application/x-executable`},{ext:`.so`,mimeType:`application/x-sharedlib`},{ext:``,mimeType:`application/x-coredump`},{ext:`.a`,mimeType:`application/x-archive`},{ext:`.deb`,mimeType:`application/vnd.debian.binary-package`},{ext:`.tar`,mimeType:`application/x-tar`},{ext:`.xar`,mimeType:`application/x-xar`},{ext:`.bz2`,mimeType:`application/x-bzip2`},{ext:`.fits`,mimeType:`application/fits`},{ext:`.tiff`,mimeType:`image/tiff`},{ext:`.bmp`,mimeType:`image/bmp`},{ext:`.ico`,mimeType:`image/x-icon`},{ext:`.mp3`,mimeType:`audio/mpeg`},{ext:`.flac`,mimeType:`audio/flac`},{ext:`.midi`,mimeType:`audio/midi`},{ext:`.ape`,mimeType:`audio/ape`},{ext:`.mpc`,mimeType:`audio/musepack`},{ext:`.amr`,mimeType:`audio/amr`},{ext:`.wav`,mimeType:`audio/wav`},{ext:`.aiff`,mimeType:`audio/aiff`},{ext:`.au`,mimeType:`audio/basic`},{ext:`.mpeg`,mimeType:`video/mpeg`},{ext:`.mov`,mimeType:`video/quicktime`},{ext:`.mp4`,mimeType:`video/mp4`},{ext:`.avif`,mimeType:`image/avif`},{ext:`.3gp`,mimeType:`video/3gpp`},{ext:`.3g2`,mimeType:`video/3gpp2`},{ext:`.mp4`,mimeType:`audio/mp4`},{ext:`.mqv`,mimeType:`video/quicktime`},{ext:`.m4a`,mimeType:`audio/x-m4a`},{ext:`.m4v`,mimeType:`video/x-m4v`},{ext:`.heic`,mimeType:`image/heic`},{ext:`.heic`,mimeType:`image/heic-sequence`},{ext:`.heif`,mimeType:`image/heif`},{ext:`.heif`,mimeType:`image/heif-sequence`},{ext:`.mj2`,mimeType:`video/mj2`},{ext:`.dvb`,mimeType:`video/vnd.dvb.file`},{ext:`.webm`,mimeType:`video/webm`},{ext:`.avi`,mimeType:`video/x-msvideo`},{ext:`.flv`,mimeType:`video/x-flv`},{ext:`.mkv`,mimeType:`video/x-matroska`},{ext:`.asf`,mimeType:`video/x-ms-asf`},{ext:`.asf`,mimeType:`video/x-ms-wmv`},{ext:`.asf`,mimeType:`video/asf`},{ext:`.aac`,mimeType:`audio/aac`},{ext:`.voc`,mimeType:`audio/x-unknown`},{ext:`.m3u`,mimeType:`application/vnd.apple.mpegurl`},{ext:`.rmvb`,mimeType:`application/vnd.rn-realmedia-vbr`},{ext:`.gz`,mimeType:`application/gzip`},{ext:`.class`,mimeType:`application/x-java-applet`},{ext:`.swf`,mimeType:`application/x-shockwave-flash`},{ext:`.crx`,mimeType:`application/x-chrome-extension`},{ext:`.ttf`,mimeType:`font/ttf`},{ext:`.woff`,mimeType:`font/woff`},{ext:`.woff2`,mimeType:`font/woff2`},{ext:`.otf`,mimeType:`font/otf`},{ext:`.ttc`,mimeType:`font/collection`},{ext:`.eot`,mimeType:`application/vnd.ms-fontobject`},{ext:`.wasm`,mimeType:`application/wasm`},{ext:`.shx`,mimeType:`application/vnd.shx`},{ext:`.shp`,mimeType:`application/vnd.shp`},{ext:`.dbf`,mimeType:`application/x-dbf`},{ext:`.dcm`,mimeType:`application/dicom`},{ext:`.rar`,mimeType:`application/x-rar-compressed`},{ext:`.djvu`,mimeType:`image/vnd.djvu`},{ext:`.mobi`,mimeType:`application/x-mobipocket-ebook`},{ext:`.lit`,mimeType:`application/x-ms-reader`},{ext:`.bpg`,mimeType:`image/bpg`},{ext:`.cbor`,mimeType:`application/cbor`},{ext:`.sqlite`,mimeType:`application/vnd.sqlite3`},{ext:`.dwg`,mimeType:`image/vnd.dwg`},{ext:`.nes`,mimeType:`application/vnd.nintendo.snes.rom`},{ext:`.lnk`,mimeType:`application/x-ms-shortcut`},{ext:`.macho`,mimeType:`application/x-mach-binary`},{ext:`.qcp`,mimeType:`audio/qcelp`},{ext:`.icns`,mimeType:`image/x-icns`},{ext:`.hdr`,mimeType:`image/vnd.radiance`},{ext:`.mrc`,mimeType:`application/marc`},{ext:`.mdb`,mimeType:`application/x-msaccess`},{ext:`.accdb`,mimeType:`application/x-msaccess`},{ext:`.zst`,mimeType:`application/zstd`},{ext:`.cab`,mimeType:`application/vnd.ms-cab-compressed`},{ext:`.rpm`,mimeType:`application/x-rpm`},{ext:`.xz`,mimeType:`application/x-xz`},{ext:`.lz`,mimeType:`application/lzip`},{ext:`.torrent`,mimeType:`application/x-bittorrent`},{ext:`.cpio`,mimeType:`application/x-cpio`},{ext:``,mimeType:`application/tzif`},{ext:`.xcf`,mimeType:`image/x-xcf`},{ext:`.pat`,mimeType:`image/x-gimp-pat`},{ext:`.gbr`,mimeType:`image/x-gimp-gbr`},{ext:`.glb`,mimeType:`model/gltf-binary`},{ext:`.cab`,mimeType:`application/x-installshield`},{ext:`.jxr`,mimeType:`image/jxr`},{ext:`.parquet`,mimeType:`application/vnd.apache.parquet`},{ext:`.txt`,mimeType:`text/plain`},{ext:`.html`,mimeType:`text/html`},{ext:`.svg`,mimeType:`image/svg+xml`},{ext:`.xml`,mimeType:`text/xml`},{ext:`.rss`,mimeType:`application/rss+xml`},{ext:`.atom`,mimeType:`application/atom+xml`},{ext:`.x3d`,mimeType:`model/x3d+xml`},{ext:`.kml`,mimeType:`application/vnd.google-earth.kml+xml`},{ext:`.xlf`,mimeType:`application/x-xliff+xml`},{ext:`.dae`,mimeType:`model/vnd.collada+xml`},{ext:`.gml`,mimeType:`application/gml+xml`},{ext:`.gpx`,mimeType:`application/gpx+xml`},{ext:`.tcx`,mimeType:`application/vnd.garmin.tcx+xml`},{ext:`.amf`,mimeType:`application/x-amf`},{ext:`.3mf`,mimeType:`application/vnd.ms-package.3dmanufacturing-3dmodel+xml`},{ext:`.xfdf`,mimeType:`application/vnd.adobe.xfdf`},{ext:`.owl`,mimeType:`application/owl+xml`},{ext:`.php`,mimeType:`text/x-php`},{ext:`.js`,mimeType:`text/javascript`},{ext:`.lua`,mimeType:`text/x-lua`},{ext:`.pl`,mimeType:`text/x-perl`},{ext:`.py`,mimeType:`text/x-python`},{ext:`.json`,mimeType:`application/json`},{ext:`.geojson`,mimeType:`application/geo+json`},{ext:`.har`,mimeType:`application/json`},{ext:`.ndjson`,mimeType:`application/x-ndjson`},{ext:`.rtf`,mimeType:`text/rtf`},{ext:`.srt`,mimeType:`application/x-subrip`},{ext:`.tcl`,mimeType:`text/x-tcl`},{ext:`.csv`,mimeType:`text/csv`},{ext:`.tsv`,mimeType:`text/tab-separated-values`},{ext:`.vcf`,mimeType:`text/vcard`},{ext:`.ics`,mimeType:`text/calendar`},{ext:`.warc`,mimeType:`application/warc`},{ext:`.vtt`,mimeType:`text/vtt`},{ext:`.pbm`,mimeType:`image/x-portable-bitmap`},{ext:`.pgm`,mimeType:`image/x-portable-graymap`},{ext:`.ppm`,mimeType:`image/x-portable-pixmap`},{ext:`.eml`,mimeType:`message/rfc822`}];var p=new BroadcastChannel(`tabsSync`),m=`pbSettings`,h=`pbColorScheme`;window.app=window.app||{},window.app.store=store({_ready:!1,superuser:null,showHeader:!0,page:t.div({className:`page`},()=>{if(!app.store._ready)return t.span({className:`loader lg m-auto`,title:`Loading plugins...`})}),mainLogo:`./images/logo.svg`,headerLogo:`./images/logo_white.svg`,favicon:``,title:``,_mediaColorScheme:``,userColorScheme:window.localStorage.getItem(h)||``,get activeColorScheme(){return app.store.userColorScheme?app.store.userColorScheme:app.store._mediaColorScheme||`light`},errors:null,creditLinks:[{href:`https://pocketbase.io/docs`,icon:`ri-book-open-line`,label:`Docs`},{href:`https://github.com/pocketbase/pocketbase/releases`,icon:`ri-github-line`,label:`PocketBase v0.39.11-dev`}],headerLinks:[{href:`#/collections`,icon:`ri-database-2-line`,label:`Collections`},{href:`#/logs`,icon:`ri-bar-chart-box-line`,label:`Logs`},{href:`#/settings`,icon:`ri-settings-3-line`,label:`Settings`}],settingsNavGroups:{System:[{href:`#/settings`,icon:`ri-home-gear-line`,label:`Application`},{href:`#/settings/mail`,icon:`ri-send-plane-2-line`,label:`Mail settings`},{href:`#/settings/storage`,icon:`ri-archive-drawer-line`,label:`Files storage`},{href:`#/settings/backups`,icon:`ri-archive-line`,label:`Backups`},{href:`#/settings/crons`,icon:`ri-time-line`,label:`Crons`}],Sync:[{href:`#/settings/export-collections`,icon:`ri-uninstall-line`,label:`Export collections`},{href:`#/settings/import-collections`,icon:`ri-install-line`,label:`Import collections`}],Debug:[{href:`#/settings/sql`,icon:`ri-terminal-box-line`,label:`SQL console`}]},predefinedAccentColors:[`#1055c9`,`#a3142a`,`#096d5c`,`#e6620a`,`#007d9c`,`#3f3da9`],settings:app.utils.getLocalHistory(m,{}),isLoadingSettings:!1,async loadSettings(){app.store.isLoadingSettings=!0;try{let e=await app.pb.settings.getAll({requestKey:`appStore.loadSettings`});app.store.settings=e,app.store.isLoadingSettings=!1}catch(e){e.isAbort||(app.store.isLoadingSettings=!1,app.checkApiError(e))}},collections:[],collectionScaffolds:{},isLoadingCollections:!1,_activeCollectionIdOrName:``,get activeCollection(){let e=app.store._activeCollectionIdOrName;return app.store.collections.find(n=>n.id==e||n.name==e)||app.store.collections[0]},set activeCollection(e){typeof e==`string`?app.store._activeCollectionIdOrName=e:app.store._activeCollectionIdOrName=e?.id},async silentlyReloadCollections(){try{let e=await app.pb.collections.getFullList({requestKey:`appStore.silentlyReloadCollections`});e=app.utils.sortedCollectionsByType(e),JSON.stringify(e)!=JSON.stringify(app.store.collections)&&(app.store.collections=e)}catch(e){e.isAbort||console.warn(`failed to reload app store collections:`,e)}},async loadCollections(e=null){app.store.isLoadingCollections=!0;try{let[n,r]=await Promise.all([app.pb.collections.getScaffolds({requestKey:`appStore.loadCollections.getScaffolds`}),app.pb.collections.getFullList({requestKey:`appStore.loadCollections.getFullList`})]);r=app.utils.sortedCollectionsByType(r),JSON.stringify(app.store.collections)!=JSON.stringify(r)&&(app.store.collections=r),app.store.collectionScaffolds=n,app.store._activeCollectionIdOrName=e||app.store._activeCollectionIdOrName||app.store.collections[0]?.id||``,app.store.isLoadingCollections=!1}catch(e){e.isAbort||(app.store.isLoadingCollections=!1,app.checkApiError(e))}},addOrUpdateCollection(e){let n=app.store.collections.findIndex(n=>n.id==e.id);n>=0?(app.store.activeCollection?.id==e.id&&(app.store._activeCollectionIdOrName=e.id),app.store.collections[n]=e):app.store.collections.push(e),app.store.collections=app.utils.sortedCollectionsByType(app.store.collections)},oauth2Providers:[],isLoadingOAuth2Providers:!1,async loadOAuth2Providers(){app.store.isLoadingOAuth2Providers=!0;try{app.store.oauth2Providers=await app.pb.collections.getAllOAuth2Providers(),app.store.isLoadingOAuth2Providers=!1}catch(e){e.isAbort||(app.checkApiError(e),app.store.isLoadingOAuth2Providers=!1)}}}),window.addEventListener(`hashchange`,()=>{app.store.title=``,app.store.errors=null}),watch(()=>{let e=app.utils.toArray(app.store.title),n=app.store.settings?.meta?.appName||``;n&&e.push(n),document.title=e.join(` - `)});var g;watch(()=>app.store.settings?.meta?.accentColor,e=>{g||(g=t.meta({name:`theme-color`}),document.head.appendChild(g)),e?(g?.setAttribute(`content`,e),document.documentElement.style.setProperty(`--accentColor`,e)):(g?.removeAttribute(`content`),document.documentElement.style.removeProperty(`--accentColor`))});var _;watch(()=>app.store.favicon,e=>{_||(_=t.link({rel:`icon`}),document.head.appendChild(_)),e?_.href=e:_.href=window.location.href.startsWith(`https://`)?`./images/favicon_prod.png`:`./images/favicon.png`});var v=window.matchMedia(`(prefers-color-scheme: dark)`);app.store._mediaColorScheme=v.matches?`dark`:`light`,v.addEventListener(`change`,({matches:e})=>{app.store._mediaColorScheme=e?`dark`:`light`}),watch(()=>app.store.userColorScheme,e=>{e?window.localStorage.setItem(h,e):window.localStorage.removeItem(h),p?.postMessage({colorScheme:e})});var ee;watch(()=>app.store.activeColorScheme,e=>{clearTimeout(ee),document.documentElement.style.setProperty(`--animationSpeed`,`0`),document.documentElement.setAttribute(`data-color-scheme`,e),ee=setTimeout(()=>{document.documentElement.style.removeProperty(`--animationSpeed`)},100)});function te(e,n){e.__errListener&&=(e.removeEventListener(`input`,e.__errListener),e.removeEventListener(`change`,e.__errListener),null),e.setCustomValidity&&(e.setCustomValidity(``),e._oldTitle?e.setAttribute(`title`,e._oldTitle):e.removeAttribute(`title`)),e.removeAttribute(`data-error`);let r=n.nextSibling;r&&r.classList?.contains(`generated-error`)&&r.getAttribute(`data-input-name`)==e.getAttribute(`name`)&&r.remove(),n.querySelector(`[data-error]`)||n.classList.remove(`error`)}watch(()=>JSON.stringify(app.store.errors)&&app.store.errors,e=>{let n=document.querySelectorAll(`[name]`);for(let r of n){if(r.classList.contains(`no-error`))continue;let n=r.closest(`.field-list`)||r.closest(`.fields`)||r.closest(`.field`);if(!n)continue;let i=r.getAttribute(`name`);te(r,n);let a=app.utils.getByPath(e,i),o=a?.message||``;if(!o&&!app.utils.isEmpty(a)){let e=[];for(let n in a)a[n]?.message&&e.push(`${n}: ${a[n]?.message}`);o=e.join(` -`)}o&&(n.classList.add(`error`),r.__errListener=function(){te(r,n),app.utils.deleteByPath(app.store.errors,i)},r.addEventListener(`input`,r.__errListener),r.addEventListener(`change`,r.__errListener),r.setAttribute(`data-error`,!0),r.setCustomValidity&&r.reportValidity&&r.classList.contains(`inline-error`)?(r.setCustomValidity(o),r.reportValidity(),r._oldTitle=r.title,r.title=o):n.after(t.div({"html-data-input-name":i,className:`field-help error generated-error`,textContent:o})))}}),p.onmessage=e=>{e.data?.collections&&JSON.stringify(app.store.collections)!=JSON.stringify(e.data.collections)&&(app.store.collections=e.data.collections),e.data?.settings&&JSON.stringify(app.store.settings)!=JSON.stringify(e.data.settings)&&(app.store.settings=e.data.settings),e.data?.colorScheme&&(app.store.userColorScheme=e.data.colorScheme)},watch(()=>JSON.stringify(app.store.collections),(e,n)=>{e&&e!=`[]`&&n&&n!=`[]`&&e!=n&&p?.postMessage({collections:JSON.parse(e)})}),watch(()=>JSON.stringify(app.store.settings),(e,n)=>{e&&e!=`{}`&&n&&n!=`{}`&&e!=n&&p?.postMessage({settings:JSON.parse(e)}),window.localStorage.setItem(m,e)});var y=class e extends Error{constructor(n){super(`ClientResponseError`),this.url=``,this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,e.prototype),typeof n==`object`&&n&&(this.originalError=n.originalError,this.url=typeof n.url==`string`?n.url:``,this.status=typeof n.status==`number`?n.status:0,this.isAbort=!!n.isAbort||n.name===`AbortError`||n.message===`Aborted`,n.response!==null&&typeof n.response==`object`?this.response=n.response:n.data!==null&&typeof n.data==`object`?this.response=n.data:this.response={}),this.originalError||n instanceof e||(this.originalError=n),this.name=`ClientResponseError `+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message=`The request was aborted (most likely 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}}},ne=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function re(e,n){let r={};if(typeof e!=`string`)return r;let i=Object.assign({},n||{}).decode||ae,a=0;for(;a0&&(!r.exp||r.exp-n>Date.now()/1e3))}oe=typeof atob!=`function`||x?e=>{let n=String(e).replace(/=+$/,``);if(n.length%4==1)throw Error(`'atob' failed: The string to be decoded is not correctly encoded.`);for(var r,i,a=0,o=0,s=``;i=n.charAt(o++);~i&&(r=a%4?64*r+i:i,a++%4)&&(s+=String.fromCharCode(255&r>>(-2*a&6))))i=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=`.indexOf(i);return s}:atob;var C=`pb_auth`,ce=class{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!se(this.token)}get isSuperuser(){let e=S(this.token);return e.type==`auth`&&(this.record?.collectionName==`_superusers`||!this.record?.collectionName&&e.collectionId==`pbc_3142635823`)}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`),S(this.token).type==`auth`&&!this.isSuperuser}save(e,n){this.baseToken=e||``,this.baseModel=n||null,this.triggerChange()}clear(){this.baseToken=``,this.baseModel=null,this.triggerChange()}loadFromCookie(e,n=C){let r=re(e||``)[n]||``,i={};try{i=JSON.parse(r),(typeof i!=`object`||Array.isArray(i))&&(i={})}catch{}this.save(i.token||``,i.record||i.model||null)}exportToCookie(e,n=C){let r={secure:!0,sameSite:!0,httpOnly:!0,path:`/`},i=S(this.token);r.expires=i?.exp?new Date(1e3*i.exp):new Date(`1970-01-01`),e=Object.assign({},r,e);let a={token:this.token,record:this.record?JSON.parse(JSON.stringify(this.record)):null},o=ie(n,JSON.stringify(a),e),s=typeof Blob<`u`?new Blob([o]).size:o.length;if(a.record&&s>4096){a.record={id:a.record?.id,email:a.record?.email};let r=[`collectionId`,`collectionName`,`verified`];for(let e in this.record)r.includes(e)&&(a.record[e]=this.record[e]);o=ie(n,JSON.stringify(a),e)}return o}onChange(e,n=!1){return this._onChangeCallbacks.push(e),n&&e(this.token,this.record),()=>{for(let n=this._onChangeCallbacks.length-1;n>=0;n--)if(this._onChangeCallbacks[n]==e)return delete this._onChangeCallbacks[n],void this._onChangeCallbacks.splice(n,1)}}triggerChange(){for(let e of this._onChangeCallbacks)e&&e(this.token,this.record)}},w=class extends ce{constructor(e=`pocketbase_auth`){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||``}get record(){let e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,n){this._storageSet(this.storageKey,{token:e,record:n}),super.save(e,n)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if(typeof window<`u`&&window?.localStorage){let n=window.localStorage.getItem(e)||``;try{return JSON.parse(n)}catch{return n}}return this.storageFallback[e]}_storageSet(e,n){if(typeof window<`u`&&window?.localStorage){let r=n;typeof n!=`string`&&(r=JSON.stringify(n)),window.localStorage.setItem(e,r)}else this.storageFallback[e]=n}_storageRemove(e){typeof window<`u`&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){typeof window<`u`&&window?.localStorage&&window.addEventListener&&window.addEventListener(`storage`,(e=>{if(e.key!=this.storageKey)return;let n=this._storageGet(this.storageKey)||{};super.save(n.token||``,n.record||n.model||null)}))}},T=class{constructor(e){this.client=e}},E=class extends T{async getAll(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/settings`,e)}async update(e,n){return n=Object.assign({method:`PATCH`,body:e},n),this.client.send(`/api/settings`,n)}async testS3(e=`storage`,n){return n=Object.assign({method:`POST`,body:{filesystem:e}},n),this.client.send(`/api/settings/test/s3`,n).then((()=>!0))}async testEmail(e,n,r,i){return i=Object.assign({method:`POST`,body:{email:n,template:r,collection:e}},i),this.client.send(`/api/settings/test/email`,i).then((()=>!0))}async generateAppleClientSecret(e,n,r,i,a,o){return o=Object.assign({method:`POST`,body:{clientId:e,teamId:n,keyId:r,privateKey:i,duration:a}},o),this.client.send(`/api/settings/apple/generate-client-secret`,o)}},D=[`requestKey`,`$cancelKey`,`$autoCancel`,`fetch`,`headers`,`body`,`query`,`params`,`cache`,`credentials`,`headers`,`integrity`,`keepalive`,`method`,`mode`,`redirect`,`referrer`,`referrerPolicy`,`signal`,`window`];function O(e){if(e){e.query=e.query||{};for(let n in e)D.includes(n)||(e.query[n]=e[n],delete e[n])}}function k(e){let n=[];for(let r in e){let i=encodeURIComponent(r),a=Array.isArray(e[r])?e[r]:[e[r]];for(let e of a)e=A(e),e!==null&&n.push(i+`=`+e)}return n.join(`&`)}function A(e){return e==null?null:e instanceof Date?encodeURIComponent(e.toISOString().replace(`T`,` `)):encodeURIComponent(typeof e==`object`?JSON.stringify(e):e)}var j=class extends T{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=[],this.pendingSubmits=[],this.isProcessingPendingSubmits=!1}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,n,r){if(!e)throw Error(`topic must be set.`);let i=e;if(r){O(r=Object.assign({},r));let e=`options=`+encodeURIComponent(JSON.stringify({query:r.query,headers:r.headers}));i+=(i.includes(`?`)?`&`:`?`)+e}let a=function(e){let r=e,i;try{i=JSON.parse(r?.data)}catch{}n(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(a),this.isConnected?this.subscriptions[i].length===1?await this.submitSubscriptions():this.eventSource?.addEventListener(i,a):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,a)}async unsubscribe(e){if(e){let n=this.getSubscriptionsByTopic(e);for(let e in n)if(this.hasSubscriptionListeners(e)){for(let n of this.subscriptions[e])this.eventSource?.removeEventListener(e,n);delete this.subscriptions[e]}}else this.subscriptions={};await this.submitSubscriptions()}async unsubscribeByPrefix(e){let n=!1;for(let r in this.subscriptions)if((r+`?`).startsWith(e)){n=!0;for(let e of this.subscriptions[r])this.eventSource?.removeEventListener(r,e);delete this.subscriptions[r]}n&&await this.submitSubscriptions()}async unsubscribeByTopicAndListener(e,n){let r=this.getSubscriptionsByTopic(e);for(let e in r){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let r=!1;for(let i=this.subscriptions[e].length-1;i>=0;i--)this.subscriptions[e][i]===n&&(r=!0,delete this.subscriptions[e][i],this.subscriptions[e].splice(i,1),this.eventSource?.removeEventListener(e,n));r&&(this.subscriptions[e].length||delete this.subscriptions[e])}await this.submitSubscriptions()}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(){return new Promise(((e,n)=>{this.pendingSubmits.push({resolve:e,reject:n}),this.pendingSubmits.length==1&&queueMicrotask((()=>this.finalizePendingSubscriptions()))}))}async finalizePendingSubscriptions(){if(this.isProcessingPendingSubmits||!this.pendingSubmits.length)return;let e=this.pendingSubmits.slice();this.pendingSubmits=[],this.isProcessingPendingSubmits=!0;try{await this.sendSubscriptions();for(let n of e)n.resolve()}catch(n){for(let r of e)n?r.reject(n):r.resolve()}finally{this.isProcessingPendingSubmits=!1,this.pendingSubmits.length>0&&await this.finalizePendingSubscriptions()}}getSubscriptionsCancelKey(){return`realtime_`+this.clientId}getSubscriptionsByTopic(e){let n={};e=e.includes(`?`)?e:e+`?`;for(let r in this.subscriptions)(r+`?`).startsWith(e)&&(n[r]=this.subscriptions[r]);return n}getNonEmptySubscriptionKeys(){let e=[];for(let n in this.subscriptions)this.subscriptions[n].length&&e.push(n);return e}hasUnsentSubscriptions(){let e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(let n of e)if(!this.lastSentSubscriptions.includes(n))return!0;return!1}async sendSubscriptions(){if(this.clientId){if(!this.hasSubscriptionListeners())return this.disconnect();if(this.hasUnsentSubscriptions())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}))}}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let n of this.subscriptions[e])this.eventSource.addEventListener(e,n)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let n of this.subscriptions[e])this.eventSource.removeEventListener(e,n)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,n)=>{this.pendingConnects.push({resolve:e,reject:n}),this.pendingConnects.length==1&&queueMicrotask((()=>this.initConnect()))}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(Error(`EventSource connect took too long.`))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL(`/api/realtime`)),this.eventSource.onerror=e=>{this.connectErrorHandler(Error(`Failed to establish realtime connection.`))},this.eventSource.addEventListener(`PB_CONNECT`,(e=>{let n=e;this.clientId=n?.lastEventId,this.lastSentSubscriptions=[],this.submitSubscriptions().then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);let n=this.getSubscriptionsByTopic(`PB_CONNECT`);for(let r in n)for(let i of n[r])i(e)})).catch((e=>{this.clientId=``,this.lastSentSubscriptions=[],this.connectErrorHandler(e)}))}))}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let n of this.pendingConnects)n.reject(new y(e));this.pendingConnects=[],this.disconnect();return}this.disconnect(!0);let n=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),n)}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=``,this.lastSentSubscriptions=[],!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}},M=class extends T{decode(e){return e}async getFullList(e,n){if(typeof e==`number`)return this._getFullList(e,n);let r=1e3;return(n=Object.assign({},e,n)).batch&&(r=n.batch,delete n.batch),this._getFullList(r,n)}async getList(e=1,n=30,r){return(r=Object.assign({method:`GET`},r)).query=Object.assign({page:e,perPage:n},r.query),this.client.send(this.baseCrudPath,r).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,n){return(n=Object.assign({requestKey:`one_by_filter_`+this.baseCrudPath+`_`+e},n)).query=Object.assign({filter:e,skipTotal:1},n.query),this.getList(1,1,n).then((e=>{if(!e?.items?.length)throw new y({status:404,response:{code:404,message:`The requested resource wasn't found.`,data:{}}});return e.items[0]}))}async getOne(e,n){if(!e)throw new y({url:this.client.buildURL(this.baseCrudPath+`/`),status:404,response:{code:404,message:`Missing required record id.`,data:{}}});return n=Object.assign({method:`GET`},n),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e),n).then((e=>this.decode(e)))}async create(e,n){return n=Object.assign({method:`POST`,body:e},n),this.client.send(this.baseCrudPath,n).then((e=>this.decode(e)))}async update(e,n,r){return r=Object.assign({method:`PATCH`,body:n},r),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e),r).then((e=>this.decode(e)))}async delete(e,n){return n=Object.assign({method:`DELETE`},n),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e),n).then((()=>!0))}_getFullList(e=1e3,n){(n||={}).query=Object.assign({skipTotal:1},n.query);let r=[],i=async a=>this.getList(a,e||1e3,n).then((e=>{let n=e.items;return r=r.concat(n),n.length==e.perPage?i(a+1):r}));return i(1)}};function N(e,n,r,i){let a=i!==void 0;return a||r!==void 0?a?(console.warn(e),n.body=Object.assign({},n.body,r),n.query=Object.assign({},n.query,i),n):Object.assign(n,r):n}function le(e){e._resetAutoRefresh?.()}var ue=class extends M{constructor(e,n){super(e),this.collectionIdOrName=n}get baseCrudPath(){return this.baseCollectionPath+`/records`}get baseCollectionPath(){return`/api/collections/`+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return this.collectionIdOrName==`_superusers`||this.collectionIdOrName==`_pbc_2773867675`}async subscribe(e,n,r){if(!e)throw Error(`Missing topic.`);if(!n)throw Error(`Missing subscription callback.`);return this.client.realtime.subscribe(this.collectionIdOrName+`/`+e,n,r)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+`/`+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,n){if(typeof e==`number`)return super.getFullList(e,n);let r=Object.assign({},e,n);return super.getFullList(r)}async getList(e=1,n=30,r){return super.getList(e,n,r)}async getFirstListItem(e,n){return super.getFirstListItem(e,n)}async getOne(e,n){return super.getOne(e,n)}async create(e,n){return super.create(e,n)}async update(e,n,r){return super.update(e,n,r).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 n=Object.assign({},this.client.authStore.record.expand),r=Object.assign({},this.client.authStore.record,e);n&&(r.expand=Object.assign(n,e.expand)),this.client.authStore.save(this.client.authStore.token,r)}return e}))}async delete(e,n){return super.delete(e,n).then((n=>(!n||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),n)))}authResponse(e){let n=this.decode(e?.record||{});return this.client.authStore.save(e?.token,n),Object.assign({},e,{token:e?.token||``,record:n})}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,n,r){let i;r=Object.assign({method:`POST`,body:{identity:e,password:n}},r),this.isSuperusers&&(i=r.autoRefreshThreshold,delete r.autoRefreshThreshold,r.autoRefresh||le(this.client));let a=await this.client.send(this.baseCollectionPath+`/auth-with-password`,r);return a=this.authResponse(a),i&&this.isSuperusers&&function(e,n,r,i){le(e);let a=e.beforeSend,o=e.authStore.record,s=e.authStore.onChange(((n,r)=>{(!n||r?.id!=o?.id||(r?.collectionId||o?.collectionId)&&r?.collectionId!=o?.collectionId)&&le(e)}));e._resetAutoRefresh=function(){s(),e.beforeSend=a,delete e._resetAutoRefresh},e.beforeSend=async(o,s)=>{let c=e.authStore.token;if(s.query?.autoRefresh)return a?a(o,s):{url:o,sendOptions:s};let l=e.authStore.isValid;if(l&&se(e.authStore.token,n))try{await r()}catch{l=!1}l||await i();let u=s.headers||{};for(let n in u)if(n.toLowerCase()==`authorization`&&c==u[n]&&e.authStore.token){u[n]=e.authStore.token;break}return s.headers=u,a?a(o,s):{url:o,sendOptions:s}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,n,Object.assign({autoRefresh:!0},r)))),a}async authWithOAuth2Code(e,n,r,i,a,o,s){let c={method:`POST`,body:{provider:e,code:n,codeVerifier:r,redirectURL:i,createData:a}};return c=N(`This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).`,c,o,s),this.client.send(this.baseCollectionPath+`/auth-with-oauth2`,c).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||typeof e?.[0]==`string`)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]||{});let n=e?.[0]||{},r=null;n.urlCallback||(r=de(void 0));let i=new j(this.client);function a(){r?.close(),i.unsubscribe()}let o={},s=n.requestKey;return s&&(o.requestKey=s),this.listAuthMethods(o).then((e=>{let o=e.oauth2.providers.find((e=>e.name===n.provider));if(!o)throw new y(Error(`Missing or invalid provider "${n.provider}".`));let c=this.client.buildURL(`/api/oauth2-redirect`);return new Promise((async(e,l)=>{let u=s?this.client.cancelControllers?.[s]:void 0;u&&(u.signal.onabort=()=>{a(),l(new y({isAbort:!0,message:`manually cancelled`}))}),i.onDisconnect=e=>{e.length&&l&&(a(),l(new y(Error(`realtime connection interrupted`))))};try{await i.subscribe(`@oauth2`,(async r=>{let s=i.clientId;try{if(!r.state||s!==r.state)throw Error(`State parameters don't match.`);if(r.error||!r.code)throw Error(`OAuth2 redirect error or missing code: `+r.error);let i=Object.assign({},n);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,u?.signal?.onabort&&(u.signal.onabort=null),e(await this.authWithOAuth2Code(o.name,r.code,o.codeVerifier,c,n.createData,i))}catch(e){l(new y(e))}a()}));let s={state:i.clientId};n.scopes?.length&&(s.scope=n.scopes.join(` `));let d=this._replaceQueryParams(o.authURL+c,s);await(n.urlCallback||function(e){r?r.location.href=e:r=de(e)})(d)}catch(e){u?.signal?.onabort&&(u.signal.onabort=null),a(),l(new y(e))}}))})).catch((e=>{throw a(),e}))}async authRefresh(e,n){let r={method:`POST`};return r=N(`This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).`,r,e,n),this.client.send(this.baseCollectionPath+`/auth-refresh`,r).then((e=>this.authResponse(e)))}async requestPasswordReset(e,n,r){let i={method:`POST`,body:{email:e}};return i=N(`This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/request-password-reset`,i).then((()=>!0))}async confirmPasswordReset(e,n,r,i,a){let o={method:`POST`,body:{token:e,password:n,passwordConfirm:r}};return o=N(`This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).`,o,i,a),this.client.send(this.baseCollectionPath+`/confirm-password-reset`,o).then((()=>!0))}async requestVerification(e,n,r){let i={method:`POST`,body:{email:e}};return i=N(`This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/request-verification`,i).then((()=>!0))}async confirmVerification(e,n,r){let i={method:`POST`,body:{token:e}};return i=N(`This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/confirm-verification`,i).then((()=>{let n=S(e),r=this.client.authStore.record;return r&&!r.verified&&r.id===n.id&&r.collectionId===n.collectionId&&(r.verified=!0,this.client.authStore.save(this.client.authStore.token,r)),!0}))}async requestEmailChange(e,n,r){let i={method:`POST`,body:{newEmail:e}};return i=N(`This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/request-email-change`,i).then((()=>!0))}async confirmEmailChange(e,n,r,i){let a={method:`POST`,body:{token:e,password:n}};return a=N(`This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).`,a,r,i),this.client.send(this.baseCollectionPath+`/confirm-email-change`,a).then((()=>{let n=S(e),r=this.client.authStore.record;return r&&r.id===n.id&&r.collectionId===n.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,n){return this.client.collection(`_externalAuths`).getFullList(Object.assign({},n,{filter:this.client.filter(`recordRef = {:id}`,{id:e})}))}async unlinkExternalAuth(e,n,r){let i=await this.client.collection(`_externalAuths`).getFirstListItem(this.client.filter(`recordRef = {:recordId} && provider = {:provider}`,{recordId:e,provider:n}));return this.client.collection(`_externalAuths`).delete(i.id,r).then((()=>!0))}async requestOTP(e,n){return n=Object.assign({method:`POST`,body:{email:e}},n),this.client.send(this.baseCollectionPath+`/request-otp`,n)}async authWithOTP(e,n,r){return r=Object.assign({method:`POST`,body:{otpId:e,password:n}},r),this.client.send(this.baseCollectionPath+`/auth-with-otp`,r).then((e=>this.authResponse(e)))}async impersonate(e,n,r){(r=Object.assign({method:`POST`,body:{duration:n}},r)).headers=r.headers||{},r.headers.Authorization||(r.headers.Authorization=this.client.authStore.token);let i=new Ee(this.client.baseURL,new ce,this.client.lang),a=await i.send(this.baseCollectionPath+`/impersonate/`+encodeURIComponent(e),r);return i.authStore.save(a?.token,this.decode(a?.record||{})),i}_replaceQueryParams(e,n={}){let r=e,i=``;e.indexOf(`?`)>=0&&(r=e.substring(0,e.indexOf(`?`)),i=e.substring(e.indexOf(`?`)+1));let a={},o=i.split(`&`);for(let e of o){if(e==``)continue;let n=e.split(`=`);a[decodeURIComponent(n[0].replace(/\+/g,` `))]=decodeURIComponent((n[1]||``).replace(/\+/g,` `))}for(let e in n)n.hasOwnProperty(e)&&(n[e]==null?delete a[e]:a[e]=n[e]);i=``;for(let e in a)a.hasOwnProperty(e)&&(i!=``&&(i+=`&`),i+=encodeURIComponent(e.replace(/%20/g,`+`))+`=`+encodeURIComponent(a[e].replace(/%20/g,`+`)));return i==``?r:r+`?`+i}};function de(e){if(typeof window>`u`||!window?.open)throw new y(Error(`Not in a browser context - please pass a custom urlCallback function.`));let n=1024,r=768,i=window.innerWidth,a=window.innerHeight;n=n>i?i:n,r=r>a?a:r;let o=i/2-n/2,s=a/2-r/2;return window.open(e,`popup_window`,`width=`+n+`,height=`+r+`,top=`+s+`,left=`+o+`,resizable,menubar=no`)}var fe=class extends M{get baseCrudPath(){return`/api/collections`}async import(e,n=!1,r){return r=Object.assign({method:`PUT`,body:{collections:e,deleteMissing:n}},r),this.client.send(this.baseCrudPath+`/import`,r).then((()=>!0))}async truncate(e,n){return n=Object.assign({method:`DELETE`},n),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e)+`/truncate`,n).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:`GET`},e),this.client.send(this.baseCrudPath+`/meta/scaffolds`,e)}async getAllOAuth2Providers(e){return e=Object.assign({method:`GET`},e),this.client.send(this.baseCrudPath+`/meta/oauth2-providers`,e)}async dryRunViewQuery(e,n){return n=Object.assign({method:`POST`,body:{query:e}},n),this.client.send(this.baseCrudPath+`/meta/dry-run-view`,n)}},pe=class extends T{async getList(e=1,n=30,r){return(r=Object.assign({method:`GET`},r)).query=Object.assign({page:e,perPage:n},r.query),this.client.send(`/api/logs`,r)}async getOne(e,n){if(!e)throw new y({url:this.client.buildURL(`/api/logs/`),status:404,response:{code:404,message:`Missing required log id.`,data:{}}});return n=Object.assign({method:`GET`},n),this.client.send(`/api/logs/`+encodeURIComponent(e),n)}async getStats(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/logs/stats`,e)}},me=class extends T{async check(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/health`,e)}},he=class extends T{getUrl(e,n,r={}){return console.warn(`Please replace pb.files.getUrl() with pb.files.getURL()`),this.getURL(e,n,r)}getURL(e,n,r={}){if(!n||!e?.id||!e?.collectionId&&!e?.collectionName)return``;let i=[];i.push(`api`),i.push(`files`),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(n));let a=this.client.buildURL(i.join(`/`));!1===r.download&&delete r.download;let o=k(r);return o&&(a+=(a.includes(`?`)?`&`:`?`)+o),a}async getToken(e){return e=Object.assign({method:`POST`},e),this.client.send(`/api/files/token`,e).then((e=>e?.token||``))}},ge=class extends T{async getFullList(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/backups`,e)}async create(e,n){return n=Object.assign({method:`POST`,body:{name:e}},n),this.client.send(`/api/backups`,n).then((()=>!0))}async upload(e,n){return n=Object.assign({method:`POST`,body:e},n),this.client.send(`/api/backups/upload`,n).then((()=>!0))}async delete(e,n){return n=Object.assign({method:`DELETE`},n),this.client.send(`/api/backups/${encodeURIComponent(e)}`,n).then((()=>!0))}async restore(e,n){return n=Object.assign({method:`POST`},n),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,n).then((()=>!0))}getDownloadUrl(e,n){return console.warn(`Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()`),this.getDownloadURL(e,n)}getDownloadURL(e,n){return this.client.buildURL(`/api/backups/${encodeURIComponent(n)}?token=${encodeURIComponent(e)}`)}},_e=class extends T{async getFullList(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/crons`,e)}async run(e,n){return n=Object.assign({method:`POST`},n),this.client.send(`/api/crons/${encodeURIComponent(e)}`,n).then((()=>!0))}},ve=class extends T{async run(e,n){return n=Object.assign({method:`POST`,body:{query:e}},n),this.client.send(`/api/sql`,n)}};function ye(e){return typeof Blob<`u`&&e instanceof Blob||typeof File<`u`&&e instanceof File||typeof e==`object`&&!!e&&e.uri&&(typeof navigator<`u`&&navigator.product===`ReactNative`||typeof global<`u`&&global.HermesInternal)}function be(e){return e&&(e.constructor?.name===`FormData`||typeof FormData<`u`&&e instanceof FormData)}function xe(e){for(let n in e){let r=Array.isArray(e[n])?e[n]:[e[n]];for(let e of r)if(ye(e))return!0}return!1}var Se=/^[\-\.\d]+$/;function Ce(e){if(typeof e!=`string`)return e;if(e==`true`)return!0;if(e==`false`)return!1;if((e[0]===`-`||e[0]>=`0`&&e[0]<=`9`)&&Se.test(e)){let n=+e;if(``+n===e)return n}return e}var we=class extends T{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new Te(this.requests,e)),this.subs[e]}async send(e){let n=new FormData,r=[];for(let e=0;e{if(r===`@jsonPayload`&&typeof e==`string`)try{let r=JSON.parse(e);Object.assign(n,r)}catch(e){console.warn(`@jsonPayload error:`,e)}else n[r]===void 0?n[r]=Ce(e):(Array.isArray(n[r])||(n[r]=[n[r]]),n[r].push(Ce(e)))})),n}(r));for(let n in r){let i=r[n];if(ye(i))e.files[n]=e.files[n]||[],e.files[n].push(i);else if(Array.isArray(i)){let r=[],a=[];for(let e of i)ye(e)?r.push(e):a.push(e);if(r.length>0&&r.length==i.length){e.files[n]=e.files[n]||[];for(let i of r)e.files[n].push(i)}else if(e.json[n]=a,r.length>0){let i=n;n.startsWith(`+`)||n.endsWith(`+`)||(i+=`+`),e.files[i]=e.files[i]||[];for(let n of r)e.files[i].push(n)}}else e.json[n]=i}}},Ee=class{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e=`/`,n,r=`en-US`){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=r,n?this.authStore=n:typeof window<`u`&&window.Deno?this.authStore=new ce:this.authStore=new w,this.collections=new fe(this),this.files=new he(this),this.logs=new pe(this),this.settings=new E(this),this.realtime=new j(this),this.health=new me(this),this.backups=new ge(this),this.crons=new _e(this),this.sql=new ve(this)}get admins(){return this.collection(`_superusers`)}createBatch(){return new we(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new ue(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,n){if(!n)return e;for(let r in n){let i=n[r];switch(typeof i){case`boolean`:case`number`:i=``+i;break;case`string`:i=`'`+i.replace(/'/g,`\\'`)+`'`;break;default:i=i===null?`null`:i instanceof Date?`'`+i.toISOString().replace(`T`,` `)+`'`:`'`+JSON.stringify(i).replace(/'/g,`\\'`)+`'`}e=e.replaceAll(`{:`+r+`}`,i)}return e}getFileUrl(e,n,r={}){return console.warn(`Please replace pb.getFileUrl() with pb.files.getURL()`),this.files.getURL(e,n,r)}buildUrl(e){return console.warn(`Please replace pb.buildUrl() with pb.buildURL()`),this.buildURL(e)}buildURL(e){let n=this.baseURL;return typeof window>`u`||!window.location||n.startsWith(`https://`)||n.startsWith(`http://`)||(n=window.location.origin?.endsWith(`/`)?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||``,this.baseURL.startsWith(`/`)||(n+=window.location.pathname||`/`,n+=n.endsWith(`/`)?``:`/`),n+=this.baseURL),e&&(n+=n.endsWith(`/`)?``:`/`,n+=e.startsWith(`/`)?e.substring(1):e),n}async send(e,n){n=this.initSendOptions(e,n);let r=this.buildURL(e);if(this.beforeSend){let e=Object.assign({},await this.beforeSend(r,n));e.url!==void 0||e.options!==void 0?(r=e.url||r,n=e.options||n):Object.keys(e).length&&(n=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(n.query!==void 0){let e=k(n.query);e&&(r+=(r.includes(`?`)?`&`:`?`)+e),delete n.query}return this.getHeader(n.headers,`Content-Type`)==`application/json`&&n.body&&typeof n.body!=`string`&&(n.body=JSON.stringify(n.body)),(n.fetch||fetch)(r,n).then((async e=>{let r={};try{r=await e.json()}catch(e){if(n.signal?.aborted||e?.name==`AbortError`||e?.message==`Aborted`)throw e}if(this.afterSend&&(r=await this.afterSend(e,r,n)),e.status>=400)throw new y({url:e.url,status:e.status,data:r});return r})).catch((e=>{throw new y(e)}))}initSendOptions(e,n){if((n=Object.assign({method:`GET`},n)).body=function(e){if(typeof FormData>`u`||e===void 0||typeof e!=`object`||!e||be(e)||!xe(e))return e;let n=new FormData;for(let r in e){let i=e[r];if(i!==void 0)if(typeof i!=`object`||xe({data:i})){let e=Array.isArray(i)?i:[i];for(let i of e)n.append(r,i)}else{let e={};e[r]=i,n.append(`@jsonPayload`,JSON.stringify(e))}}return n}(n.body),O(n),n.query=Object.assign({},n.params,n.query),n.requestKey===void 0&&(!1===n.$autoCancel||!1===n.query.$autoCancel?n.requestKey=null:(n.$cancelKey||n.query.$cancelKey)&&(n.requestKey=n.$cancelKey||n.query.$cancelKey)),delete n.$autoCancel,delete n.query.$autoCancel,delete n.$cancelKey,delete n.query.$cancelKey,this.getHeader(n.headers,`Content-Type`)!==null||be(n.body)||(n.headers=Object.assign({},n.headers,{"Content-Type":`application/json`})),this.getHeader(n.headers,`Accept-Language`)===null&&(n.headers=Object.assign({},n.headers,{"Accept-Language":this.lang})),this.authStore.token&&this.getHeader(n.headers,`Authorization`)===null&&(n.headers=Object.assign({},n.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&n.requestKey!==null){let r=n.requestKey||(n.method||`GET`)+e;delete n.requestKey,this.cancelRequest(r);let i=new AbortController;this.cancelControllers[r]=i,n.signal=i.signal}return n}getHeader(e,n){e||={},n=n.toLowerCase();for(let r in e)if(r.toLowerCase()==n)return e[r];return null}},De=`#/login`,Oe=window.location.pathname.endsWith(`/`)?window.location.pathname.substring(0,window.location.pathname.length-1):window.location.pathname;window.app=window.app||{},window.app.pb=new Ee(`../`,new w(`__pb_superusers__`+Oe)),app.pb.beforeSend=function(e,n){return n.headers[`x-request-source`]=`pbui`,{url:e,options:n}},app.store.superuser=app.pb.authStore.record,app.pb.authStore.onChange((e,n)=>{!n&&window.location.hash!=De&&(app.modals.close(),window.location.hash=De),app.store.superuser=n}),app.pb.authStore.isValid&&app.pb.collection(app.pb.authStore.record?.collectionName||`_superusers`).authRefresh().catch(e=>{console.warn(`Failed to refresh the existing auth token:`,e);let n=e?.status<<0;(n==401||n==403)&&(app.pb.cancelAllRequests(),app.pb.authStore.clear())}),app.pb.authStore.onChange((e,n)=>{n?.id&&(app.store.loadCollections(),app.store.loadSettings(),app.store.loadOAuth2Providers())});var ke=app.pb.collection;app.pb.collection=function(e){let n=ke.call(this,e);return Ae(n),n};function Ae(e){if(e.__customUIEvents)return;e.__customUIEvents=!0;let n=e.create;e.create=function(){return n.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:create`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let r=e.update;e.update=function(){return r.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:update`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let i=e.delete;e.delete=function(){return i.apply(e,arguments).then(n=>{let r={id:arguments[0],collectionId:e.collectionIdOrName,collectionName:e.collectionIdOrName};return setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:delete`,{detail:r}))},0),n})}}var je=`pbLastFileToken`,Me=!1,Ne=[];app.pb.authStore.onChange((e,n)=>{n?.id||window.localStorage.removeItem(je)}),window.app.getFileToken=async function(e=``){let n=e&&app.store.collections?.find(n=>n.id==e||n.name==e);if(n&&!n.fields?.find(e=>e.type==`file`&&e.protected))return;let r=window.localStorage.getItem(je);return(!r||se(r,60))&&(r=await Pe()),r};async function Pe(){return new Promise(async(e,n)=>{if(Ne.push({resolve:e,reject:n}),!Me){Me=!0;try{let e=await app.pb.files.getToken();window.localStorage.setItem(je,e),Ne.forEach(n=>n.resolve(e))}catch(e){Ne.forEach(n=>n.reject(e))}Me=!1,Ne=[]}})}window.app.checkApiError=function(e,n=!0){if(!e||!(e instanceof Error)||e.isAbort){console.warn(`checkApiError - unexpected error type:`,e);return}let r=e?.status<<0,i=e?.response||{},a=n&&(i.message||e.message||`Something went wrong!`);if(a&&app.toasts.error(a),r==0&&console.log(e),app.utils.isEmpty(i.data)||(app.store.errors=i.data),r===401&&window.location.hash!=De)return app.pb.cancelAllRequests(),app.pb.authStore.clear()};function Fe(){return()=>{if(!(!app.store._ready||!app.store.showHeader||!app.store.superuser?.id))return t.header({pbEvent:`appHeader`,rid:`appHeader`,className:`app-header accent-surface`,onmount:async e=>{await new Promise(e=>setTimeout(e,0)),e._scrollToActiveMenuItem=function(){e?.querySelector(`.app-main-nav .header-link.active`)?.scrollIntoView()},e._scrollToActiveMenuItem(),window.addEventListener(`hashchange`,e._scrollToActiveMenuItem)},onunmount:e=>{window.removeEventListener(`hashchange`,e?._scrollToActiveMenuItem)}},t.a({href:`#/`,className:`logo`},t.img({src:()=>app.store.headerLogo,alt:`App logo`})),t.nav({pbEvent:`mainNav`,className:`app-main-nav`},()=>app.store.headerLinks.map(e=>{let n=e.href.startsWith(`#/`);return t.a({href:()=>e.href,target:()=>n?void 0:`_blank`,rel:()=>n?void 0:`noopener noreferrer`,className:n=>`header-link ${e.isActive?.(n)||app.utils.isActivePath(e.href)?`active`:``}`},()=>{if(e.icon)return t.i({className:e.icon,ariaHidden:!0})},t.span({className:`txt`},()=>e.label))})),t.div({className:`flex-fill app-header-separator`}),Ie(),t.button({type:`button`,className:`header-link logged-user txt-normal`,"html-popovertarget":`logged-user-dropdown`},t.span({className:`superuser-name txt-ellipsis`},()=>app.store.superuser?.email),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0})),t.div({pbEvent:`loggedUserDropdown`,id:`logged-user-dropdown`,className:`dropdown sm nowrap logged-user-dropdown`,popover:`auto`},t.a({className:`dropdown-item dropdown-item-manage`,href:`#/collections?collection=_superusers`,onclick:e=>{e.target.closest(`.dropdown`).hidePopover()}},t.i({className:`ri-group-line`,ariaHidden:!0}),t.span({className:`txt`},`Manage superusers`)),t.hr(),t.button({type:`button`,className:`dropdown-item txt-danger dropdown-item-logout`,onclick:()=>app.pb.authStore.clear()},t.i({className:`ri-logout-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Logout`))))}}function Ie(){let e=[{value:`light`,icon:`ri-sun-line`,label:`Light`},{value:`dark`,icon:`ri-moon-line`,label:`Dark`},{value:``,icon:`ri-subtract-line`,label:`Auto`}];return[t.button({type:`button`,className:`header-link color-scheme-picker`,"html-popovertarget":`color-scheme-dropdown`,title:`Color scheme`},t.i({className:()=>app.store.activeColorScheme==`dark`?`ri-moon-line`:`ri-sun-line`,ariaHidden:!0})),t.div({pbEvent:`colorSchemeDropdown`,id:`color-scheme-dropdown`,className:`dropdown sm nowrap color-scheme-dropdown`,popover:`auto`},()=>e.map(e=>t.button({type:`button`,className:()=>`dropdown-item dropdown-item-light ${app.store.userColorScheme==e.value?`active`:``}`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),app.store.userColorScheme=e.value}},t.i({className:e.icon,ariaHidden:!0}),t.span({className:`txt`},e.label))))]}document.addEventListener(`invalid`,e=>{let n=e.target.closest(`details`);n&&!n.open&&!e.target.closest(`summary`)&&(n.open=!0,e.target.reportValidity&&e.target.reportValidity())},!0);var Le=`dropdown-item`;document.addEventListener(`toggle`,e=>{if(e.newState!=`open`||!e.target||e.target.__keyboardNavRegistered||!e.target.matches(`.dropdown`))return;e.target.__keyboardNavRegistered=!0;let n=e.target;function r(e){if(!n.isConnected){document.removeEventListener(`keydown`,r);return}let i;if(i=document.activeElement&&document.activeElement.classList.contains(Le)?document.activeElement:n.querySelector(`.dropdown-item:not([hidden]):not(.disabled)`),i){if(e.key==`ArrowUp`){e.preventDefault();let n=ze(i,-1);i==document.activeElement&&n?.classList?.contains(Le)?n?.focus():i.focus()}else if(e.key==`ArrowDown`){e.preventDefault();let n=ze(i,1);i==document.activeElement&&n?.classList?.contains(Le)?n?.focus():i.focus()}else if(e.keyCode>=65&&e.keyCode<=90||e.keyCode>=48&&e.keyCode<=57){let e=n.querySelectorAll(`input,textare,select`);e.length==1&&e[0].focus()}}}n.addEventListener(`toggle`,e=>{e.newState==`open`?(Re(e.target.id,!0),document.addEventListener(`keydown`,r)):(Re(e.target.id,!1),document.removeEventListener(`keydown`,r))})},!0);function Re(e,n=!1){e&&document.querySelectorAll(`[popovertarget='`+e+`']`)?.forEach(e=>e.setAttribute(`data-popover-state`,n))}function ze(e,n=-1){let r=n<0?e.previousElementSibling:e.nextElementSibling;return r&&(r.hidden||r.classList.contains(`disabled`)||!r.classList.contains(Le))?ze(r,n):r}var Be=5,P=t.div({ariaHidden:!0,popover:`manual`,className:`pb-tooltip`});document.body.appendChild(P);function Ve(e,n,r){P._relatedNode=e;let i=e.getBoundingClientRect();P.setAttribute(`data-style`,r||``),P.setAttribute(`data-position`,n),P.style.top=`0px`,P.style.left=`0px`;let a=P.offsetHeight,o=P.offsetWidth,s=0,c=0;n==`left`?(s=i.top+i.height/2-a/2,c=i.left-o-Be):n==`right`?(s=i.top+i.height/2-a/2,c=i.right+Be):n==`top`?(s=i.top-a-Be,c=i.left+i.width/2-o/2):n==`top-left`?(s=i.top-a-Be,c=i.left):n==`top-right`?(s=i.top-a-Be,c=i.right-o):n==`bottom-left`?(s=i.top+i.height+Be,c=i.left):n==`bottom-right`?(s=i.top+i.height+Be,c=i.right-o):(s=i.top+i.height+Be,c=i.left+i.width/2-o/2),c+o>document.documentElement.clientWidth&&(c=document.documentElement.clientWidth-o),c=c>=0?c:0,s+a>document.documentElement.clientHeight&&(s=document.documentElement.clientHeight-a),s=s>=0?s:0,P.style.top=s+`px`,P.style.left=c+`px`}function He(){P._relatedNode=null,P.hidePopover()}function Ue(e,n,r,i){if(!e||!n){He();return}P.showPopover(),P.textContent=n,Ve(e,r,i)}document.body.addEventListener(`mouseleave`,()=>{He()});function We(e,n=`top`,r=``){return i=>{if(!i._tooltipText){i._tooltipText=store({value:``});let e;function a(){e?.unwatch(),e=watch(()=>i._tooltipText.value,async e=>{Ue(i,e,n,r)})}async function o(){e?.unwatch(),e=null,He()}i.addEventListener(`mouseenter`,a),i.addEventListener(`focusin`,a),i.addEventListener(`mouseleave`,o),i.addEventListener(`focusout`,o),i.addEventListener(`blur`,o);let s=i.onunmount;i.onunmount=n=>{P._relatedNode==n&&He(),e?.unwatch(),n._tooltipText=null,n?.removeEventListener(`mouseenter`,a),n?.removeEventListener(`focusin`,a),n?.removeEventListener(`mouseleave`,o),n?.removeEventListener(`focusout`,o),n?.removeEventListener(`blur`,o),s(n)}}return typeof e==`function`?i._tooltipText.value=e():i._tooltipText.value=e,i._tooltipText.value}}window.app=window.app||{},window.app.attrs=window.app.attrs||{},window.app.attrs.tooltip=We,window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.confirm=function(e,n,r,i={className:void 0,yesButton:``,noButton:``}){F.textOrElem=e,F.yesCallback=n,F.yesCallbackWaiting=!1,F.noCallback=r,F.noCallbackWaiting=!1,F.className=typeof i.className==`string`?i.className:`sm`,F.yesButton=i.yesButton||`Yes`,F.noButton=i.noButton||`No`,Ge.isConnected||document.body.appendChild(Ge),window.app.modals.open(Ge)};var F=store({className:``,textOrElem:null,yesButton:``,yesCallback:null,yesCallbackWaiting:!1,noButton:``,noCallback:null,noCallbackWaiting:!1,get isBusy(){return F.yesCallbackWaiting||F.noCallbackWaiting}}),Ge=t.div({className:()=>`modal popup manual ${F.className||``}`},t.div({className:`modal-content`},e=>typeof F.textOrElem==`string`?t.h6({className:`block txt-center`},F.textOrElem):typeof F.textOrElem==`function`?F.textOrElem(e):F.textOrElem),t.footer({className:`modal-footer p-sm`},t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block secondary ${F.noCallbackWaiting?`loading`:``}`,disabled:()=>F.isBusy,onclick:async()=>{if(F.noCallback){F.noCallbackWaiting=!0;try{if(await F.noCallback()===!1)return}catch(e){console.log(`confirm noCallback error:`,e)}finally{F.noCallbackWaiting=!1}}window.app.modals.close(Ge)}},()=>typeof F.noButton==`string`?t.span({className:`txt`},F.noButton):typeof F.noButton==`function`?F.noButton(el):F.noButton)),t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block warning ${F.yesCallbackWaiting?`loading`:``}`,disabled:()=>F.isBusy,onclick:async()=>{if(F.yesCallback){F.yesCallbackWaiting=!0;try{if(await F.yesCallback()===!1)return}catch(e){console.log(`confirm yesCallback error:`,e)}finally{F.yesCallbackWaiting=!1}}window.app.modals.close(Ge)}},()=>typeof F.yesButton==`string`?t.span({className:`txt`},F.yesButton):typeof F.yesButton==`function`?F.yesButton(el):F.yesButton)))));window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.dragline=function(e={}){let n,r=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,tolerance:0,ondragstart:function(e){},ondragstop:function(e){},ondragging:function(e,n,r){}}),i=app.utils.extendStore(r,e),a=store({dragStarted:!1}),o,s,c,l;function u(){document.addEventListener(`touchmove`,m),document.addEventListener(`mousemove`,m),document.addEventListener(`touchend`,p),document.addEventListener(`mouseup`,p)}function d(){document.removeEventListener(`touchmove`,m),document.removeEventListener(`mousemove`,m),document.removeEventListener(`touchend`,p),document.removeEventListener(`mouseup`,p)}function f(e){e.stopPropagation(),o=e.clientX,s=e.clientY,c=e.clientX-n.offsetLeft,l=e.clientY-n.offsetTop,u()}function p(e){a.dragStarted&&(e.preventDefault(),a.dragStarted=!1,r.ondragstop?.(e)),d()}function m(e){let i=e.clientX-o,u=e.clientY-s,d=e.clientX-c,f=e.clientY-l;!a.dragStarted&&Math.abs(d-n.offsetLeft)r.id,hidden:()=>r.hidden,inert:()=>r.inert,className:()=>`dragline ${a.dragStarted?`dragging`:``} ${r.className}`,onmousedown:e=>{e.button==0&&f(e)},ontouchstart:f,onunmount:()=>{d(),i.forEach(e=>e?.unwatch())}}),n},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.slide=function(e,...n){let r;return t.div({className:n=>`block slide-block ${e?.(n)?``:`hidden`}`,onmount:e=>{r=setTimeout(()=>{e?.setAttribute(`data-slide`,`1`)},200)},onunmount:()=>{clearTimeout(r)}},...n)},window.app=window.app||{},window.app.modals=window.app.modals||{};var Ke=`data-modal-state`,qe=`manual`,Je;window.app.modals.open=async function(e){if(!e?.isConnected){console.error(`modals.open requies an active DOM element`,e);return}let n;if(e.onbeforeopen&&(n=await e.onbeforeopen(e)),n===!1)return;if(e.onafteropen){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height>0&&e?.onafteropen&&(e.onafteropen(e),n.disconnect(),n=null)});n.observe(e)}Je=document.activeElement,Ye(e),e._forceClose=()=>app.modals.close(e,!0),window.addEventListener(`popstate`,e._forceClose);let r=Math.max(Xe(e)?.style.zIndex<<0,1e3);e.style.zIndex=r+1,e.setAttribute(Ke,`open`)},window.app.modals.close=async function(e=null,n=!1){if(e||=Xe(),e){if(window.removeEventListener(`popstate`,e._forceClose),n)e.onbeforeclose?.(e,!0),e.setAttribute(Ke,`close`),e.onafterclose?.(e,!0);else{if(e.onbeforeclose&&await e.onbeforeclose(e,!1)===!1)return;if(e.onafterclose){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height<=0&&e?.onafterclose&&(e.onafterclose(e,!1),n.disconnect(),n=null)});n.observe(e)}e.setAttribute(Ke,`close`)}Je&&(Je.focus?.(),setTimeout(()=>{Je?.blur?.(),Je=null},0))}};function Ye(e){if(e.getAttribute(`tabindex`)||e.setAttribute(`tabindex`,`-1`),setTimeout(()=>{let n=e?.querySelector(`[autofocus]`);n?n.focus():e?.focus()},0),e.getAttribute(Ke))return;e.setAttribute(Ke,``),e.addEventListener(`keydown`,n=>{n.key!=`Escape`||e.classList.contains(qe)||n.target!==e&&e.contains(n.target)||window.app.modals.close(e)});let n=!1,r=r=>{n=r.target!==e&&e.contains(r.target)};e.addEventListener(`mousedown`,r),e.addEventListener(`touchstart`,r);let i=!1,a=n=>{i=n.target!==e&&e.contains(n.target)};e.addEventListener(`mouseup`,a),e.addEventListener(`touchend`,a),e.addEventListener(`click`,r=>{n||i||e.classList.contains(qe)||r.target!==e&&e.contains(r.target)||window.app.modals.close(e)})}function Xe(e){let n=document.querySelectorAll(`[${Ke}="open"]`),r=0,i=0,a;for(let o of n)e&&o==e||(r=o.style.zIndex<<0,r>i&&(i=r,a=o));return a}window.app.modals.getTop=function(){return Xe()};var Ze=new Map,Qe=t.div({className:`toasts-container`});function I(e,n=!0){let r=Ze.get(e);!r||!r.isConnected||(Ze.delete(e),clearTimeout(r._removeTimeout),n?(r.classList.add(`removing`),setTimeout(()=>{r.remove()},300)):r.remove())}function R(e=!0){Ze.forEach((n,r)=>{window.app.toasts.remove(r,e)})}function $e(e,n={}){n.type=`info`,n.duration=n.duration||3e3,nt(e,n)}function et(e,n={}){n.type=`success`,n.duration=n.duration||3e3,nt(e,n)}function tt(e,n={}){n.type=`error`,n.duration=n.duration||3500,nt(e,n)}function nt(e,n={}){n=Object.assign({duration:3e3,key:void 0,type:`info`},n),Qe.isConnected||document.body.appendChild(Qe);let r=n.key||e;Ze.has(r)&&I(r,!1);function i(e){e?._removeTimeout&&clearTimeout(e?._removeTimeout),e._removeTimeout=setTimeout(()=>{I(r)},n.duration)}let a=t.div({className:`toast ${n.type||``}`,onmount:e=>{i(e)},onunmount:e=>{e?._removeTimeout&&(clearTimeout(e?._removeTimeout),a=null)},onmouseover:()=>{clearTimeout(a?._removeTimeout)},onmouseout:()=>{i(a)}},t.div({className:`toast-container`},t.div({className:`toast-icon`}),t.div({className:`toast-content`},e,t.button({type:`button`,className:`m-l-auto btn circle sm transparent secondary toast-remove`,title:`Clear`,onclick:()=>I(r)},t.i({className:`ri-close-line`,ariaHidden:!0})))));Ze.set(r,a),Qe.prepend(a)}window.app=window.app||{},window.app.toasts=window.app.toasts||{},window.app.toasts.info=$e,window.app.toasts.error=tt,window.app.toasts.success=et,window.app.toasts.remove=I,window.app.toasts.removeAll=R,window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.sortable=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,data:[],dataItem:function(e,n,r){return t.span(null,`Item `+n)},onchange:function(e,n,r){},handle:``,before:void 0,after:void 0}),r=app.utils.extendStore(n,e);function i(e){function r(){e.querySelectorAll(`:scope > [data-dragstart="true"]`)?.forEach(e=>{e.dataset.dragstart=!1}),e.querySelectorAll(`:scope > [data-dragover="true"]`)?.forEach(e=>{e.dataset.dragover=!1})}e.addEventListener(`dragstart`,r=>{if(n.handle&&!r.target.closest(n.handle)){r.preventDefault();return}let i=o(e,r.target);i&&(i.dataset.dragstart=!0)}),e.addEventListener(`dragenter`,n=>{for(let n of e.children)n.dataset.dragover&&(n.dataset.dragover=!1);let r=o(e,n.target);r&&(r.dataset.dragover=!0)}),e.addEventListener(`dragend`,e=>{r()}),e.addEventListener(`dragover`,e=>{e.preventDefault()}),e.addEventListener(`drop`,i=>{if(!n.onchange){r();return}let s=e.querySelector(`:scope > [data-dragstart="true"]`),c=o(e,i.target);if(r(),!s||!c||c==s)return;let l=e.querySelectorAll(`:scope > [data-sortable-child]`),u=a(l,s),d=a(l,c);if(u==-1||d==-1)return;let f=n.data.slice(),p=f.splice(u,1);f.splice(d,0,p[0]),n.onchange(f,u,d)})}function a(e,n){for(let r=0;rn.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>n.className,onmount:e=>{i(e)},onunmount:e=>{r.forEach(e=>e?.unwatch())}},e=>typeof n.before==`function`?n.before(e):n.before,e=>{let r=[];for(let i=0;itypeof n.after==`function`?n.after(e):n.after)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.copyButton=function(e,...n){let r=store({active:!1}),i;function a(){let n=e;typeof n==`function`&&(n=e()),app.utils.copyToClipboard(n),r.active=!0,clearTimeout(i),i=setTimeout(()=>{r.active=!1},500)}return t.button({tabIndex:-1,type:`button`,className:()=>`copy-to-clipboard ${r.active?`active`:``}`,title:`Copy`,ariaDescription:app.attrs.tooltip(()=>r.active?`Copied`:null),onclick:e=>{e.preventDefault(),e.stopPropagation(),a()}},t.i({hidden:n?.length,ariaHidden:!0,className:()=>`copy-icon ${r.active?`ri-check-double-line`:`ri-file-copy-line`}`}),...n)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlock=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,language:`js`,value:void 0,footnote:void 0}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`code-wrapper ${n.className}`,tabIndex:-1,onmount:e=>{e.addEventListener(`keydown`,n=>{(n.ctrlKey||n.metaKey)&&(n.key==`a`||n.key==`A`)&&(n.preventDefault(),window.getSelection().selectAllChildren(e))})},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.code({className:`block`,innerHTML:()=>rt(n.value,n.language)}),t.div({className:`footnote`},e=>typeof n.footnote==`function`?n.footnote(e):n.footnote))};function rt(e,n){return e=typeof e==`string`?e:``,e=Prism.plugins.NormalizeWhitespace.normalize(e,{"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.highlight(e,Prism.languages[n]||Prism.languages.js,n)}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeEditor=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,name:void 0,className:``,value:``,language:`js`,placeholder:``,disabled:!1,required:!1,singleLine:!1,autocomplete:void 0,oninput:function(e){},onfocus:function(e){},onblur:function(e){}}),r=app.utils.extendStore(n,e,`autocomplete`),i,a,o=!0;function s(e){c(),i=t.div({className:`dropdown autocomplete code-editor-dropdown`,onmount:e=>{e._updatePosition=()=>{o?dt(i):c()},e._closeOnEsc=e=>{e.key==`Escape`&&(e.preventDefault(),c())},window.addEventListener(`scroll`,e._updatePosition,!0),window.addEventListener(`resize`,e._updatePosition),window.addEventListener(`keydown`,e._closeOnEsc),e._updatePosition()},onunmount:e=>{e&&(window.removeEventListener(`scroll`,e._updatePosition,!0),window.removeEventListener(`resize`,e._updatePosition),window.removeEventListener(`keydown`,e._closeOnEsc))}},e),document.body.appendChild(i),f&&(a?.disconnect(),a=new IntersectionObserver(([e])=>{o=e.isIntersecting},{root:null,threshold:.1}),a.observe(f))}function c(){i&&=(i.remove(),null),a&&=(a.disconnect(),null),o=!0}function l(e){n.value=e,n.oninput?.(e),f.dispatchEvent(new CustomEvent(`change`,{detail:e}))}let u=!1,d,f=t.div({contentEditable:()=>!n.disabled&&`plaintext-only`,tabIndex:0,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,role:`textbox`,className:`editor-content`,"html-data-placeholder":()=>n.placeholder,onmount:e=>{d?.unwatch(),d=watch(()=>n.value,e=>{e!=f.textContent&&(f.textContent=e,c())})},onunmount:e=>{d?.unwatch(),c()},onfocus:()=>{n.onfocus?.(n.value)},onblur:e=>{i&&!i.contains(e.relatedTarget)&&c(),n.onblur?.(n.value)},oninput:e=>{if(c(),l(f.textContent),!n.value?.length){f.textContent=``;return}if(!f?.isConnected)return;let r=ut(f),i=st(n.value,r);if(!i.word.length||r==i.start)return;let a=[];if(typeof n.autocomplete==`function`)a=n.autocomplete(i.word)||[];else if(!app.utils.isEmpty(n.autocomplete)){let e=i.word.toLowerCase();a=n.autocomplete.filter(n=>(typeof n==`object`&&(n=n?.value),n=n?.toLowerCase(),n&&n!=e&&n.includes(e)))}a?.length&&s(()=>a.map((e,n)=>t.button({type:`button`,className:`dropdown-item ${n==0?`active`:``}`,textContent:e.label||e.value||e,onclick:n=>{n.preventDefault(),f.focus();let r=e.value||e;f.textContent=f.textContent.substring(0,i.start)+r+f.textContent.substring(i.end+1),l(f.textContent);try{window.getSelection().setPosition(f.childNodes[0],i.start+r.length)}catch(e){console.warn(`failed to set caret position`,e)}c()}})))},onkeydown:e=>{if(u=e.ctrlKey||e.metaKey,(e.key==`Enter`||e.key==`Tab`)&&i?.isConnected){e.preventDefault(),i.querySelector(`.dropdown-item.active`)?.click();return}if(e.key==`ArrowUp`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.previousElementSibling&&(n.classList.remove(`active`),n.previousElementSibling.classList.add(`active`),n.previousElementSibling.scrollIntoView(!1));return}if(e.key==`ArrowDown`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.nextElementSibling&&(n.classList.remove(`active`),n.nextElementSibling.classList.add(`active`),n.nextElementSibling.scrollIntoView(!1));return}if(u&&e.key.toLowerCase()==`l`){e.preventDefault(),ct(f);return}if(u&&e.key.toLowerCase()==`d`){e.preventDefault(),lt(f);return}if(!n.singleLine&&e.key==`Tab`){e.preventDefault();let n=window.getSelection();if(!n)return;if(e.shiftKey){n.modify(`extend`,`backward`,`character`),n.toString()[0]==` `?(n.deleteFromDocument(),l(f.textContent)):(n.modify(`extend`,`forward`,`character`),n.toString()[0]==` `&&(n.deleteFromDocument(),l(f.textContent)));return}let r=n.getRangeAt(0);r&&(r.deleteContents(),r.insertNode(document.createTextNode(` `)),r.collapse(),l(f.textContent));return}if(n.singleLine&&e.key==`Enter`){e.preventDefault(),m.click();return}},onscroll:()=>{c(),p&&(p.scrollLeft=f.scrollLeft,p.scrollTop=f.scrollTop)}}),p=t.div({className:`highlight-overlay`,innerHTML:()=>at(n.value,n.language),onscroll:()=>{f&&(f.scrollLeft=p.scrollLeft,f.scrollTop=p.scrollTop)}}),m=t.button({type:`submit`,className:`hidden`});return t.div({rid:n.rid,id:()=>n.id,inert:()=>n.inert,hidden:()=>n.hidden,"html-name":()=>n.name,"html-required":()=>n.required||void 0,className:()=>`input code-editor ${n.className} ${n.disabled?`disabled`:``} ${n.singleLine?`single-line`:``}`,onclick:()=>{f?.focus()},onunmount:()=>{r?.forEach(e=>e?.unwatch())}},t.div({className:`code-editor-container`},f,p,m))};var it=500;function at(e,n){return e=typeof e==`string`?e:``,e?((!Prism.languages[n]||e.length>it)&&(n=`plain`),Prism.highlight(e,Prism.languages[n],n)):``}var ot=new RegExp(/[\p{Alphabetic}\p{Number}_@:\."'{}]/,`u`);function st(e,n){let r=n;for(let i=n-1;i>=0&&ot.test(e[i]);i--)r=i;let i=r;for(let r=n-1;rdocument.documentElement.clientHeight&&(o=Math.max(n.top-r,0)),a+i>document.documentElement.clientWidth&&(a=Math.max(document.documentElement.clientWidth-i,0)),e.style.left=a+`px`,e.style.top=o+`px`}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlockTabs=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,activeTabIndex:0,historyKey:``,tabs:[],get activeTab(){return n.tabs[n.activeTabIndex]||n.tabs[0]}}),r=app.utils.extendStore(n,e);return r.push(watch(()=>n.activeTabIndex,(e,r)=>{r!=null&&n.historyKey&&localStorage.setItem(n.historyKey,e)})),t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden||!n.tabs.length,inert:()=>n.inert,className:()=>`code-block-tabs ${n.className}`,onmount:()=>{n.historyKey&&(n.activeTabIndex=localStorage.getItem(n.historyKey)<<0)},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.header({className:`tabs-header`},()=>n.tabs.map((e,r)=>t.button({type:`button`,className:()=>`tab-item ${n.activeTabIndex==r?`active`:``}`,onclick:()=>n.activeTabIndex=r},n=>typeof e.title==`function`?e.title(n):e.title))),t.div({className:`code-block-tabs-content`},()=>{if(n.activeTab)return app.components.codeBlock(n.activeTab)}))},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.select=function(e={}){let n=store({rid:void 0,id:void 0,name:void 0,hidden:void 0,inert:void 0,className:``,value:void 0,options:[],before:null,after:null,max:1,searchThreshold:6,required:!1,disabled:!1,placeholder:`- Select -`,noItemsFoundText:`No items found`,onchange:function(e){},ondropdowntoggle:function(e){}}),r=app.utils.extendStore(n,e);n.max<=0&&(n.max=1);let i=store({selected:[],search:``,get hasSearch(){return i.search?.length>0},get allowRemove(){return!n.disabled&&(!n.required||n.max>1)}});function a(){if(n.value===void 0)return;let e=app.utils.toArray(n.value,!0),r=e.slice(0,n.max||1);e.length!=r.length&&(console.warn(`[select] the provided select values (${e.length}) are more than the allowed max selected options (${r.length}):`,e),n.value=n.max>1?r:r[0]),i.selected=e.map(e=>n.options.find(n=>n.value===e)).filter(Boolean)}r.push(watch(()=>n.value,()=>a()));async function o(e){let r=i.selected.findIndex(n=>n.value===e.value);if(r>=0){if(!i.allowRemove){f?.hidePopover();return}i.selected.splice(r,1)}else{let r=i.selected.length-n.max;for(;r>=0;)i.selected.pop(),r--;i.selected.push(e)}n.max<=1&&f?.hidePopover(),n.onchange&&(await n.onchange(i.selected),a()),p?.isConnected&&p.dispatchEvent(new CustomEvent(`change`,{detail:i.selected,bubbles:!0}))}function s(e){return i.selected.findIndex(n=>n.value===e.value)>=0}let c=t.input({type:`text`,placeholder:`Search...`,value:()=>i.search,oninput:e=>i.search=e.target.value});function l(e=!1){i.search=``,e&&c?.focus()}let u=t.div({className:`txt-hint txt-center m-0 p-5`,hidden:!0},e=>typeof n.noItemsFoundText==`function`?n.noItemsFoundText(e):n.noItemsFoundText);async function d(){f&&(await new Promise(e=>setTimeout(e,0)),f.querySelector(`.select-option:not([hidden])`)?u.hidden=!0:u.hidden=!1)}let f=t.div({tabIndex:-1,popover:`auto`,className:`dropdown`,onbeforetoggle:e=>(e.newState==`closed`&&l(),n.ondropdowntoggle?.(e))},t.div({className:`fields dropdown-search`,hidden:()=>n.options.length!i.hasSearch},t.button({type:`button`,title:`Clear`,className:`btn sm secondary transparent circle`,onclick:()=>l(!0)},t.i({className:`ri-close-line`,ariaHidden:!0})))),()=>n.before?.__raw||n.before,()=>n.options.map(e=>t.button({type:`button`,className:()=>`dropdown-item select-option ${s(e)?`active`:``}`,onclick:()=>(o(e),!1)},e.label||e.value)),u,()=>n.after?.__raw||n.after),p=t.button({type:`button`,id:()=>n.id,name:()=>n.name,disabled:()=>n.disabled,className:()=>`selected-container ${n.className}`,popoverTargetElement:f,onclick:e=>{e.stopPropagation()}},()=>i.selected.length?i.selected.map(e=>t.div({className:`selected-item`},e.selected||e.label||e.value,()=>{if(i.allowRemove)return t.i({tabIndex:-1,role:`button`,className:`ri-close-line link-hint btn-option-unset`,ariaLabel:app.attrs.tooltip(`Unset`),onclick:()=>(o(e),!1)})})):t.span({rid:`selected-placeholder`,className:`placeholder`},e=>typeof n.placeholder==`function`?n.placeholder(e):n.placeholder));r.push(watch(()=>n.options,()=>{d()}));let m;return r.push(watch(()=>i.search,()=>{let e=i.search.toLowerCase().replaceAll(` `,``);clearTimeout(m),m=setTimeout(()=>{let n=f.querySelectorAll(`.select-option`);e.length?n.forEach(n=>{n.textContent.toLowerCase().replaceAll(` `,``).includes(e)?n.hidden=!1:n.hidden=!0}):n.forEach(e=>e.hidden=!1),d()},100)})),t.div({rid:n.rid,hidden:()=>n.hidden,inert:()=>n.inert,onmount:e=>{e.addEventListener(`focusout`,function(n){(!n.relatedTarget||!e.contains(n.relatedTarget))&&f?.hidePopover()})},onunmount:()=>{clearTimeout(m),r.forEach(e=>e.unwatch())},className:()=>[`input`,`select`,n.max>1?`multiple`:`single`,n.disabled?`disabled`:``,n.required?`required`:``].join(` `)},p,f)},window.app=window.app||{},window.app.components=window.app.components||{};var ft=Intl.DateTimeFormat().resolvedOptions().timeZone;window.app.components.formattedDate=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,value:``,short:!1}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,ariaDescription:app.attrs.tooltip(()=>n.short&&n.value?app.utils.toLocalDatetime(n.value)+` +`)}o&&(n.classList.add(`error`),r.__errListener=function(){te(r,n),app.utils.deleteByPath(app.store.errors,i)},r.addEventListener(`input`,r.__errListener),r.addEventListener(`change`,r.__errListener),r.setAttribute(`data-error`,!0),r.setCustomValidity&&r.reportValidity&&r.classList.contains(`inline-error`)?(r.setCustomValidity(o),r.reportValidity(),r._oldTitle=r.title,r.title=o):n.after(t.div({"html-data-input-name":i,className:`field-help error generated-error`,textContent:o})))}}),p.onmessage=e=>{e.data?.collections&&JSON.stringify(app.store.collections)!=JSON.stringify(e.data.collections)&&(app.store.collections=e.data.collections),e.data?.settings&&JSON.stringify(app.store.settings)!=JSON.stringify(e.data.settings)&&(app.store.settings=e.data.settings),e.data?.colorScheme&&(app.store.userColorScheme=e.data.colorScheme)},watch(()=>JSON.stringify(app.store.collections),(e,n)=>{e&&e!=`[]`&&n&&n!=`[]`&&e!=n&&p?.postMessage({collections:JSON.parse(e)})}),watch(()=>JSON.stringify(app.store.settings),(e,n)=>{e&&e!=`{}`&&n&&n!=`{}`&&e!=n&&p?.postMessage({settings:JSON.parse(e)}),window.localStorage.setItem(m,e)});var y=class e extends Error{constructor(n){super(`ClientResponseError`),this.url=``,this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,e.prototype),typeof n==`object`&&n&&(this.originalError=n.originalError,this.url=typeof n.url==`string`?n.url:``,this.status=typeof n.status==`number`?n.status:0,this.isAbort=!!n.isAbort||n.name===`AbortError`||n.message===`Aborted`,n.response!==null&&typeof n.response==`object`?this.response=n.response:n.data!==null&&typeof n.data==`object`?this.response=n.data:this.response={}),this.originalError||n instanceof e||(this.originalError=n),this.name=`ClientResponseError `+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message=`The request was aborted (most likely 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}}},ne=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function re(e,n){let r={};if(typeof e!=`string`)return r;let i=Object.assign({},n||{}).decode||ae,a=0;for(;a0&&(!r.exp||r.exp-n>Date.now()/1e3))}oe=typeof atob!=`function`||x?e=>{let n=String(e).replace(/=+$/,``);if(n.length%4==1)throw Error(`'atob' failed: The string to be decoded is not correctly encoded.`);for(var r,i,a=0,o=0,s=``;i=n.charAt(o++);~i&&(r=a%4?64*r+i:i,a++%4)&&(s+=String.fromCharCode(255&r>>(-2*a&6))))i=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=`.indexOf(i);return s}:atob;var C=`pb_auth`,ce=class{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!se(this.token)}get isSuperuser(){let e=S(this.token);return e.type==`auth`&&(this.record?.collectionName==`_superusers`||!this.record?.collectionName&&e.collectionId==`pbc_3142635823`)}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`),S(this.token).type==`auth`&&!this.isSuperuser}save(e,n){this.baseToken=e||``,this.baseModel=n||null,this.triggerChange()}clear(){this.baseToken=``,this.baseModel=null,this.triggerChange()}loadFromCookie(e,n=C){let r=re(e||``)[n]||``,i={};try{i=JSON.parse(r),(typeof i!=`object`||Array.isArray(i))&&(i={})}catch{}this.save(i.token||``,i.record||i.model||null)}exportToCookie(e,n=C){let r={secure:!0,sameSite:!0,httpOnly:!0,path:`/`},i=S(this.token);r.expires=i?.exp?new Date(1e3*i.exp):new Date(`1970-01-01`),e=Object.assign({},r,e);let a={token:this.token,record:this.record?JSON.parse(JSON.stringify(this.record)):null},o=ie(n,JSON.stringify(a),e),s=typeof Blob<`u`?new Blob([o]).size:o.length;if(a.record&&s>4096){a.record={id:a.record?.id,email:a.record?.email};let r=[`collectionId`,`collectionName`,`verified`];for(let e in this.record)r.includes(e)&&(a.record[e]=this.record[e]);o=ie(n,JSON.stringify(a),e)}return o}onChange(e,n=!1){return this._onChangeCallbacks.push(e),n&&e(this.token,this.record),()=>{for(let n=this._onChangeCallbacks.length-1;n>=0;n--)if(this._onChangeCallbacks[n]==e)return delete this._onChangeCallbacks[n],void this._onChangeCallbacks.splice(n,1)}}triggerChange(){for(let e of this._onChangeCallbacks)e&&e(this.token,this.record)}},w=class extends ce{constructor(e=`pocketbase_auth`){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||``}get record(){let e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,n){this._storageSet(this.storageKey,{token:e,record:n}),super.save(e,n)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if(typeof window<`u`&&window?.localStorage){let n=window.localStorage.getItem(e)||``;try{return JSON.parse(n)}catch{return n}}return this.storageFallback[e]}_storageSet(e,n){if(typeof window<`u`&&window?.localStorage){let r=n;typeof n!=`string`&&(r=JSON.stringify(n)),window.localStorage.setItem(e,r)}else this.storageFallback[e]=n}_storageRemove(e){typeof window<`u`&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){typeof window<`u`&&window?.localStorage&&window.addEventListener&&window.addEventListener(`storage`,(e=>{if(e.key!=this.storageKey)return;let n=this._storageGet(this.storageKey)||{};super.save(n.token||``,n.record||n.model||null)}))}},T=class{constructor(e){this.client=e}},E=class extends T{async getAll(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/settings`,e)}async update(e,n){return n=Object.assign({method:`PATCH`,body:e},n),this.client.send(`/api/settings`,n)}async testS3(e=`storage`,n){return n=Object.assign({method:`POST`,body:{filesystem:e}},n),this.client.send(`/api/settings/test/s3`,n).then((()=>!0))}async testEmail(e,n,r,i){return i=Object.assign({method:`POST`,body:{email:n,template:r,collection:e}},i),this.client.send(`/api/settings/test/email`,i).then((()=>!0))}async generateAppleClientSecret(e,n,r,i,a,o){return o=Object.assign({method:`POST`,body:{clientId:e,teamId:n,keyId:r,privateKey:i,duration:a}},o),this.client.send(`/api/settings/apple/generate-client-secret`,o)}},D=[`requestKey`,`$cancelKey`,`$autoCancel`,`fetch`,`headers`,`body`,`query`,`params`,`cache`,`credentials`,`headers`,`integrity`,`keepalive`,`method`,`mode`,`redirect`,`referrer`,`referrerPolicy`,`signal`,`window`];function O(e){if(e){e.query=e.query||{};for(let n in e)D.includes(n)||(e.query[n]=e[n],delete e[n])}}function k(e){let n=[];for(let r in e){let i=encodeURIComponent(r),a=Array.isArray(e[r])?e[r]:[e[r]];for(let e of a)e=A(e),e!==null&&n.push(i+`=`+e)}return n.join(`&`)}function A(e){return e==null?null:e instanceof Date?encodeURIComponent(e.toISOString().replace(`T`,` `)):encodeURIComponent(typeof e==`object`?JSON.stringify(e):e)}var j=class extends T{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=[],this.pendingSubmits=[],this.isProcessingPendingSubmits=!1}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,n,r){if(!e)throw Error(`topic must be set.`);let i=e;if(r){O(r=Object.assign({},r));let e=`options=`+encodeURIComponent(JSON.stringify({query:r.query,headers:r.headers}));i+=(i.includes(`?`)?`&`:`?`)+e}let a=function(e){let r=e,i;try{i=JSON.parse(r?.data)}catch{}n(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(a),this.isConnected?this.subscriptions[i].length===1?await this.submitSubscriptions():this.eventSource?.addEventListener(i,a):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,a)}async unsubscribe(e){if(e){let n=this.getSubscriptionsByTopic(e);for(let e in n)if(this.hasSubscriptionListeners(e)){for(let n of this.subscriptions[e])this.eventSource?.removeEventListener(e,n);delete this.subscriptions[e]}}else this.subscriptions={};await this.submitSubscriptions()}async unsubscribeByPrefix(e){let n=!1;for(let r in this.subscriptions)if((r+`?`).startsWith(e)){n=!0;for(let e of this.subscriptions[r])this.eventSource?.removeEventListener(r,e);delete this.subscriptions[r]}n&&await this.submitSubscriptions()}async unsubscribeByTopicAndListener(e,n){let r=this.getSubscriptionsByTopic(e);for(let e in r){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let r=!1;for(let i=this.subscriptions[e].length-1;i>=0;i--)this.subscriptions[e][i]===n&&(r=!0,delete this.subscriptions[e][i],this.subscriptions[e].splice(i,1),this.eventSource?.removeEventListener(e,n));r&&(this.subscriptions[e].length||delete this.subscriptions[e])}await this.submitSubscriptions()}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(){return new Promise(((e,n)=>{this.pendingSubmits.push({resolve:e,reject:n}),this.pendingSubmits.length==1&&queueMicrotask((()=>this.finalizePendingSubscriptions()))}))}async finalizePendingSubscriptions(){if(this.isProcessingPendingSubmits||!this.pendingSubmits.length)return;let e=this.pendingSubmits.slice();this.pendingSubmits=[],this.isProcessingPendingSubmits=!0;try{await this.sendSubscriptions();for(let n of e)n.resolve()}catch(n){for(let r of e)n?r.reject(n):r.resolve()}finally{this.isProcessingPendingSubmits=!1,this.pendingSubmits.length>0&&await this.finalizePendingSubscriptions()}}getSubscriptionsCancelKey(){return`realtime_`+this.clientId}getSubscriptionsByTopic(e){let n={};e=e.includes(`?`)?e:e+`?`;for(let r in this.subscriptions)(r+`?`).startsWith(e)&&(n[r]=this.subscriptions[r]);return n}getNonEmptySubscriptionKeys(){let e=[];for(let n in this.subscriptions)this.subscriptions[n].length&&e.push(n);return e}hasUnsentSubscriptions(){let e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(let n of e)if(!this.lastSentSubscriptions.includes(n))return!0;return!1}async sendSubscriptions(){if(this.clientId){if(!this.hasSubscriptionListeners())return this.disconnect();if(this.hasUnsentSubscriptions())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}))}}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let n of this.subscriptions[e])this.eventSource.addEventListener(e,n)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let n of this.subscriptions[e])this.eventSource.removeEventListener(e,n)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,n)=>{this.pendingConnects.push({resolve:e,reject:n}),this.pendingConnects.length==1&&queueMicrotask((()=>this.initConnect()))}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(Error(`EventSource connect took too long.`))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL(`/api/realtime`)),this.eventSource.onerror=e=>{this.connectErrorHandler(Error(`Failed to establish realtime connection.`))},this.eventSource.addEventListener(`PB_CONNECT`,(e=>{let n=e;this.clientId=n?.lastEventId,this.lastSentSubscriptions=[],this.submitSubscriptions().then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);let n=this.getSubscriptionsByTopic(`PB_CONNECT`);for(let r in n)for(let i of n[r])i(e)})).catch((e=>{this.clientId=``,this.lastSentSubscriptions=[],this.connectErrorHandler(e)}))}))}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let n of this.pendingConnects)n.reject(new y(e));this.pendingConnects=[],this.disconnect();return}this.disconnect(!0);let n=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),n)}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=``,this.lastSentSubscriptions=[],!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}},M=class extends T{decode(e){return e}async getFullList(e,n){if(typeof e==`number`)return this._getFullList(e,n);let r=1e3;return(n=Object.assign({},e,n)).batch&&(r=n.batch,delete n.batch),this._getFullList(r,n)}async getList(e=1,n=30,r){return(r=Object.assign({method:`GET`},r)).query=Object.assign({page:e,perPage:n},r.query),this.client.send(this.baseCrudPath,r).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,n){return(n=Object.assign({requestKey:`one_by_filter_`+this.baseCrudPath+`_`+e},n)).query=Object.assign({filter:e,skipTotal:1},n.query),this.getList(1,1,n).then((e=>{if(!e?.items?.length)throw new y({status:404,response:{code:404,message:`The requested resource wasn't found.`,data:{}}});return e.items[0]}))}async getOne(e,n){if(!e)throw new y({url:this.client.buildURL(this.baseCrudPath+`/`),status:404,response:{code:404,message:`Missing required record id.`,data:{}}});return n=Object.assign({method:`GET`},n),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e),n).then((e=>this.decode(e)))}async create(e,n){return n=Object.assign({method:`POST`,body:e},n),this.client.send(this.baseCrudPath,n).then((e=>this.decode(e)))}async update(e,n,r){return r=Object.assign({method:`PATCH`,body:n},r),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e),r).then((e=>this.decode(e)))}async delete(e,n){return n=Object.assign({method:`DELETE`},n),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e),n).then((()=>!0))}_getFullList(e=1e3,n){(n||={}).query=Object.assign({skipTotal:1},n.query);let r=[],i=async a=>this.getList(a,e||1e3,n).then((e=>{let n=e.items;return r=r.concat(n),n.length==e.perPage?i(a+1):r}));return i(1)}};function N(e,n,r,i){let a=i!==void 0;return a||r!==void 0?a?(console.warn(e),n.body=Object.assign({},n.body,r),n.query=Object.assign({},n.query,i),n):Object.assign(n,r):n}function le(e){e._resetAutoRefresh?.()}var ue=class extends M{constructor(e,n){super(e),this.collectionIdOrName=n}get baseCrudPath(){return this.baseCollectionPath+`/records`}get baseCollectionPath(){return`/api/collections/`+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return this.collectionIdOrName==`_superusers`||this.collectionIdOrName==`_pbc_2773867675`}async subscribe(e,n,r){if(!e)throw Error(`Missing topic.`);if(!n)throw Error(`Missing subscription callback.`);return this.client.realtime.subscribe(this.collectionIdOrName+`/`+e,n,r)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+`/`+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,n){if(typeof e==`number`)return super.getFullList(e,n);let r=Object.assign({},e,n);return super.getFullList(r)}async getList(e=1,n=30,r){return super.getList(e,n,r)}async getFirstListItem(e,n){return super.getFirstListItem(e,n)}async getOne(e,n){return super.getOne(e,n)}async create(e,n){return super.create(e,n)}async update(e,n,r){return super.update(e,n,r).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 n=Object.assign({},this.client.authStore.record.expand),r=Object.assign({},this.client.authStore.record,e);n&&(r.expand=Object.assign(n,e.expand)),this.client.authStore.save(this.client.authStore.token,r)}return e}))}async delete(e,n){return super.delete(e,n).then((n=>(!n||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),n)))}authResponse(e){let n=this.decode(e?.record||{});return this.client.authStore.save(e?.token,n),Object.assign({},e,{token:e?.token||``,record:n})}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,n,r){let i;r=Object.assign({method:`POST`,body:{identity:e,password:n}},r),this.isSuperusers&&(i=r.autoRefreshThreshold,delete r.autoRefreshThreshold,r.autoRefresh||le(this.client));let a=await this.client.send(this.baseCollectionPath+`/auth-with-password`,r);return a=this.authResponse(a),i&&this.isSuperusers&&function(e,n,r,i){le(e);let a=e.beforeSend,o=e.authStore.record,s=e.authStore.onChange(((n,r)=>{(!n||r?.id!=o?.id||(r?.collectionId||o?.collectionId)&&r?.collectionId!=o?.collectionId)&&le(e)}));e._resetAutoRefresh=function(){s(),e.beforeSend=a,delete e._resetAutoRefresh},e.beforeSend=async(o,s)=>{let c=e.authStore.token;if(s.query?.autoRefresh)return a?a(o,s):{url:o,sendOptions:s};let l=e.authStore.isValid;if(l&&se(e.authStore.token,n))try{await r()}catch{l=!1}l||await i();let u=s.headers||{};for(let n in u)if(n.toLowerCase()==`authorization`&&c==u[n]&&e.authStore.token){u[n]=e.authStore.token;break}return s.headers=u,a?a(o,s):{url:o,sendOptions:s}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,n,Object.assign({autoRefresh:!0},r)))),a}async authWithOAuth2Code(e,n,r,i,a,o,s){let c={method:`POST`,body:{provider:e,code:n,codeVerifier:r,redirectURL:i,createData:a}};return c=N(`This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).`,c,o,s),this.client.send(this.baseCollectionPath+`/auth-with-oauth2`,c).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||typeof e?.[0]==`string`)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]||{});let n=e?.[0]||{},r=null;n.urlCallback||(r=de(void 0));let i=new j(this.client);function a(){r?.close(),i.unsubscribe()}let o={},s=n.requestKey;return s&&(o.requestKey=s),this.listAuthMethods(o).then((e=>{let o=e.oauth2.providers.find((e=>e.name===n.provider));if(!o)throw new y(Error(`Missing or invalid provider "${n.provider}".`));let c=this.client.buildURL(`/api/oauth2-redirect`);return new Promise((async(e,l)=>{let u=s?this.client.cancelControllers?.[s]:void 0;u&&(u.signal.onabort=()=>{a(),l(new y({isAbort:!0,message:`manually cancelled`}))}),i.onDisconnect=e=>{e.length&&l&&(a(),l(new y(Error(`realtime connection interrupted`))))};try{await i.subscribe(`@oauth2`,(async r=>{let s=i.clientId;try{if(!r.state||s!==r.state)throw Error(`State parameters don't match.`);if(r.error||!r.code)throw Error(`OAuth2 redirect error or missing code: `+r.error);let i=Object.assign({},n);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,u?.signal?.onabort&&(u.signal.onabort=null),e(await this.authWithOAuth2Code(o.name,r.code,o.codeVerifier,c,n.createData,i))}catch(e){l(new y(e))}a()}));let s={state:i.clientId};n.scopes?.length&&(s.scope=n.scopes.join(` `));let d=this._replaceQueryParams(o.authURL+c,s);await(n.urlCallback||function(e){r?r.location.href=e:r=de(e)})(d)}catch(e){u?.signal?.onabort&&(u.signal.onabort=null),a(),l(new y(e))}}))})).catch((e=>{throw a(),e}))}async authRefresh(e,n){let r={method:`POST`};return r=N(`This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).`,r,e,n),this.client.send(this.baseCollectionPath+`/auth-refresh`,r).then((e=>this.authResponse(e)))}async requestPasswordReset(e,n,r){let i={method:`POST`,body:{email:e}};return i=N(`This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/request-password-reset`,i).then((()=>!0))}async confirmPasswordReset(e,n,r,i,a){let o={method:`POST`,body:{token:e,password:n,passwordConfirm:r}};return o=N(`This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).`,o,i,a),this.client.send(this.baseCollectionPath+`/confirm-password-reset`,o).then((()=>!0))}async requestVerification(e,n,r){let i={method:`POST`,body:{email:e}};return i=N(`This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/request-verification`,i).then((()=>!0))}async confirmVerification(e,n,r){let i={method:`POST`,body:{token:e}};return i=N(`This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/confirm-verification`,i).then((()=>{let n=S(e),r=this.client.authStore.record;return r&&!r.verified&&r.id===n.id&&r.collectionId===n.collectionId&&(r.verified=!0,this.client.authStore.save(this.client.authStore.token,r)),!0}))}async requestEmailChange(e,n,r){let i={method:`POST`,body:{newEmail:e}};return i=N(`This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).`,i,n,r),this.client.send(this.baseCollectionPath+`/request-email-change`,i).then((()=>!0))}async confirmEmailChange(e,n,r,i){let a={method:`POST`,body:{token:e,password:n}};return a=N(`This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).`,a,r,i),this.client.send(this.baseCollectionPath+`/confirm-email-change`,a).then((()=>{let n=S(e),r=this.client.authStore.record;return r&&r.id===n.id&&r.collectionId===n.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,n){return this.client.collection(`_externalAuths`).getFullList(Object.assign({},n,{filter:this.client.filter(`recordRef = {:id}`,{id:e})}))}async unlinkExternalAuth(e,n,r){let i=await this.client.collection(`_externalAuths`).getFirstListItem(this.client.filter(`recordRef = {:recordId} && provider = {:provider}`,{recordId:e,provider:n}));return this.client.collection(`_externalAuths`).delete(i.id,r).then((()=>!0))}async requestOTP(e,n){return n=Object.assign({method:`POST`,body:{email:e}},n),this.client.send(this.baseCollectionPath+`/request-otp`,n)}async authWithOTP(e,n,r){return r=Object.assign({method:`POST`,body:{otpId:e,password:n}},r),this.client.send(this.baseCollectionPath+`/auth-with-otp`,r).then((e=>this.authResponse(e)))}async impersonate(e,n,r){(r=Object.assign({method:`POST`,body:{duration:n}},r)).headers=r.headers||{},r.headers.Authorization||(r.headers.Authorization=this.client.authStore.token);let i=new Ee(this.client.baseURL,new ce,this.client.lang),a=await i.send(this.baseCollectionPath+`/impersonate/`+encodeURIComponent(e),r);return i.authStore.save(a?.token,this.decode(a?.record||{})),i}_replaceQueryParams(e,n={}){let r=e,i=``;e.indexOf(`?`)>=0&&(r=e.substring(0,e.indexOf(`?`)),i=e.substring(e.indexOf(`?`)+1));let a={},o=i.split(`&`);for(let e of o){if(e==``)continue;let n=e.split(`=`);a[decodeURIComponent(n[0].replace(/\+/g,` `))]=decodeURIComponent((n[1]||``).replace(/\+/g,` `))}for(let e in n)n.hasOwnProperty(e)&&(n[e]==null?delete a[e]:a[e]=n[e]);i=``;for(let e in a)a.hasOwnProperty(e)&&(i!=``&&(i+=`&`),i+=encodeURIComponent(e.replace(/%20/g,`+`))+`=`+encodeURIComponent(a[e].replace(/%20/g,`+`)));return i==``?r:r+`?`+i}};function de(e){if(typeof window>`u`||!window?.open)throw new y(Error(`Not in a browser context - please pass a custom urlCallback function.`));let n=1024,r=768,i=window.innerWidth,a=window.innerHeight;n=n>i?i:n,r=r>a?a:r;let o=i/2-n/2,s=a/2-r/2;return window.open(e,`popup_window`,`width=`+n+`,height=`+r+`,top=`+s+`,left=`+o+`,resizable,menubar=no`)}var fe=class extends M{get baseCrudPath(){return`/api/collections`}async import(e,n=!1,r){return r=Object.assign({method:`PUT`,body:{collections:e,deleteMissing:n}},r),this.client.send(this.baseCrudPath+`/import`,r).then((()=>!0))}async truncate(e,n){return n=Object.assign({method:`DELETE`},n),this.client.send(this.baseCrudPath+`/`+encodeURIComponent(e)+`/truncate`,n).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:`GET`},e),this.client.send(this.baseCrudPath+`/meta/scaffolds`,e)}async getAllOAuth2Providers(e){return e=Object.assign({method:`GET`},e),this.client.send(this.baseCrudPath+`/meta/oauth2-providers`,e)}async dryRunViewQuery(e,n){return n=Object.assign({method:`POST`,body:{query:e}},n),this.client.send(this.baseCrudPath+`/meta/dry-run-view`,n)}},pe=class extends T{async getList(e=1,n=30,r){return(r=Object.assign({method:`GET`},r)).query=Object.assign({page:e,perPage:n},r.query),this.client.send(`/api/logs`,r)}async getOne(e,n){if(!e)throw new y({url:this.client.buildURL(`/api/logs/`),status:404,response:{code:404,message:`Missing required log id.`,data:{}}});return n=Object.assign({method:`GET`},n),this.client.send(`/api/logs/`+encodeURIComponent(e),n)}async getStats(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/logs/stats`,e)}},me=class extends T{async check(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/health`,e)}},he=class extends T{getUrl(e,n,r={}){return console.warn(`Please replace pb.files.getUrl() with pb.files.getURL()`),this.getURL(e,n,r)}getURL(e,n,r={}){if(!n||!e?.id||!e?.collectionId&&!e?.collectionName)return``;let i=[];i.push(`api`),i.push(`files`),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(n));let a=this.client.buildURL(i.join(`/`));!1===r.download&&delete r.download;let o=k(r);return o&&(a+=(a.includes(`?`)?`&`:`?`)+o),a}async getToken(e){return e=Object.assign({method:`POST`},e),this.client.send(`/api/files/token`,e).then((e=>e?.token||``))}},ge=class extends T{async getFullList(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/backups`,e)}async create(e,n){return n=Object.assign({method:`POST`,body:{name:e}},n),this.client.send(`/api/backups`,n).then((()=>!0))}async upload(e,n){return n=Object.assign({method:`POST`,body:e},n),this.client.send(`/api/backups/upload`,n).then((()=>!0))}async delete(e,n){return n=Object.assign({method:`DELETE`},n),this.client.send(`/api/backups/${encodeURIComponent(e)}`,n).then((()=>!0))}async restore(e,n){return n=Object.assign({method:`POST`},n),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,n).then((()=>!0))}getDownloadUrl(e,n){return console.warn(`Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()`),this.getDownloadURL(e,n)}getDownloadURL(e,n){return this.client.buildURL(`/api/backups/${encodeURIComponent(n)}?token=${encodeURIComponent(e)}`)}},_e=class extends T{async getFullList(e){return e=Object.assign({method:`GET`},e),this.client.send(`/api/crons`,e)}async run(e,n){return n=Object.assign({method:`POST`},n),this.client.send(`/api/crons/${encodeURIComponent(e)}`,n).then((()=>!0))}},ve=class extends T{async run(e,n){return n=Object.assign({method:`POST`,body:{query:e}},n),this.client.send(`/api/sql`,n)}};function ye(e){return typeof Blob<`u`&&e instanceof Blob||typeof File<`u`&&e instanceof File||typeof e==`object`&&!!e&&e.uri&&(typeof navigator<`u`&&navigator.product===`ReactNative`||typeof global<`u`&&global.HermesInternal)}function be(e){return e&&(e.constructor?.name===`FormData`||typeof FormData<`u`&&e instanceof FormData)}function xe(e){for(let n in e){let r=Array.isArray(e[n])?e[n]:[e[n]];for(let e of r)if(ye(e))return!0}return!1}var Se=/^[\-\.\d]+$/;function Ce(e){if(typeof e!=`string`)return e;if(e==`true`)return!0;if(e==`false`)return!1;if((e[0]===`-`||e[0]>=`0`&&e[0]<=`9`)&&Se.test(e)){let n=+e;if(``+n===e)return n}return e}var we=class extends T{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new Te(this.requests,e)),this.subs[e]}async send(e){let n=new FormData,r=[];for(let e=0;e{if(r===`@jsonPayload`&&typeof e==`string`)try{let r=JSON.parse(e);Object.assign(n,r)}catch(e){console.warn(`@jsonPayload error:`,e)}else n[r]===void 0?n[r]=Ce(e):(Array.isArray(n[r])||(n[r]=[n[r]]),n[r].push(Ce(e)))})),n}(r));for(let n in r){let i=r[n];if(ye(i))e.files[n]=e.files[n]||[],e.files[n].push(i);else if(Array.isArray(i)){let r=[],a=[];for(let e of i)ye(e)?r.push(e):a.push(e);if(r.length>0&&r.length==i.length){e.files[n]=e.files[n]||[];for(let i of r)e.files[n].push(i)}else if(e.json[n]=a,r.length>0){let i=n;n.startsWith(`+`)||n.endsWith(`+`)||(i+=`+`),e.files[i]=e.files[i]||[];for(let n of r)e.files[i].push(n)}}else e.json[n]=i}}},Ee=class{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e=`/`,n,r=`en-US`){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=r,n?this.authStore=n:typeof window<`u`&&window.Deno?this.authStore=new ce:this.authStore=new w,this.collections=new fe(this),this.files=new he(this),this.logs=new pe(this),this.settings=new E(this),this.realtime=new j(this),this.health=new me(this),this.backups=new ge(this),this.crons=new _e(this),this.sql=new ve(this)}get admins(){return this.collection(`_superusers`)}createBatch(){return new we(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new ue(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,n){if(!n)return e;for(let r in n){let i=n[r];switch(typeof i){case`boolean`:case`number`:i=``+i;break;case`string`:i=`'`+i.replace(/'/g,`\\'`)+`'`;break;default:i=i===null?`null`:i instanceof Date?`'`+i.toISOString().replace(`T`,` `)+`'`:`'`+JSON.stringify(i).replace(/'/g,`\\'`)+`'`}e=e.replaceAll(`{:`+r+`}`,i)}return e}getFileUrl(e,n,r={}){return console.warn(`Please replace pb.getFileUrl() with pb.files.getURL()`),this.files.getURL(e,n,r)}buildUrl(e){return console.warn(`Please replace pb.buildUrl() with pb.buildURL()`),this.buildURL(e)}buildURL(e){let n=this.baseURL;return typeof window>`u`||!window.location||n.startsWith(`https://`)||n.startsWith(`http://`)||(n=window.location.origin?.endsWith(`/`)?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||``,this.baseURL.startsWith(`/`)||(n+=window.location.pathname||`/`,n+=n.endsWith(`/`)?``:`/`),n+=this.baseURL),e&&(n+=n.endsWith(`/`)?``:`/`,n+=e.startsWith(`/`)?e.substring(1):e),n}async send(e,n){n=this.initSendOptions(e,n);let r=this.buildURL(e);if(this.beforeSend){let e=Object.assign({},await this.beforeSend(r,n));e.url!==void 0||e.options!==void 0?(r=e.url||r,n=e.options||n):Object.keys(e).length&&(n=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(n.query!==void 0){let e=k(n.query);e&&(r+=(r.includes(`?`)?`&`:`?`)+e),delete n.query}return this.getHeader(n.headers,`Content-Type`)==`application/json`&&n.body&&typeof n.body!=`string`&&(n.body=JSON.stringify(n.body)),(n.fetch||fetch)(r,n).then((async e=>{let r={};try{r=await e.json()}catch(e){if(n.signal?.aborted||e?.name==`AbortError`||e?.message==`Aborted`)throw e}if(this.afterSend&&(r=await this.afterSend(e,r,n)),e.status>=400)throw new y({url:e.url,status:e.status,data:r});return r})).catch((e=>{throw new y(e)}))}initSendOptions(e,n){if((n=Object.assign({method:`GET`},n)).body=function(e){if(typeof FormData>`u`||e===void 0||typeof e!=`object`||!e||be(e)||!xe(e))return e;let n=new FormData;for(let r in e){let i=e[r];if(i!==void 0)if(typeof i!=`object`||xe({data:i})){let e=Array.isArray(i)?i:[i];for(let i of e)n.append(r,i)}else{let e={};e[r]=i,n.append(`@jsonPayload`,JSON.stringify(e))}}return n}(n.body),O(n),n.query=Object.assign({},n.params,n.query),n.requestKey===void 0&&(!1===n.$autoCancel||!1===n.query.$autoCancel?n.requestKey=null:(n.$cancelKey||n.query.$cancelKey)&&(n.requestKey=n.$cancelKey||n.query.$cancelKey)),delete n.$autoCancel,delete n.query.$autoCancel,delete n.$cancelKey,delete n.query.$cancelKey,this.getHeader(n.headers,`Content-Type`)!==null||be(n.body)||(n.headers=Object.assign({},n.headers,{"Content-Type":`application/json`})),this.getHeader(n.headers,`Accept-Language`)===null&&(n.headers=Object.assign({},n.headers,{"Accept-Language":this.lang})),this.authStore.token&&this.getHeader(n.headers,`Authorization`)===null&&(n.headers=Object.assign({},n.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&n.requestKey!==null){let r=n.requestKey||(n.method||`GET`)+e;delete n.requestKey,this.cancelRequest(r);let i=new AbortController;this.cancelControllers[r]=i,n.signal=i.signal}return n}getHeader(e,n){e||={},n=n.toLowerCase();for(let r in e)if(r.toLowerCase()==n)return e[r];return null}},De=`#/login`,Oe=window.location.pathname.endsWith(`/`)?window.location.pathname.substring(0,window.location.pathname.length-1):window.location.pathname;window.app=window.app||{},window.app.pb=new Ee(`../`,new w(`__pb_superusers__`+Oe)),app.pb.beforeSend=function(e,n){return n.headers[`x-request-source`]=`pbui`,{url:e,options:n}},app.store.superuser=app.pb.authStore.record,app.pb.authStore.onChange((e,n)=>{!n&&window.location.hash!=De&&(app.modals.close(),window.location.hash=De),app.store.superuser=n}),app.pb.authStore.isValid&&app.pb.collection(app.pb.authStore.record?.collectionName||`_superusers`).authRefresh().catch(e=>{console.warn(`Failed to refresh the existing auth token:`,e);let n=e?.status<<0;(n==401||n==403)&&(app.pb.cancelAllRequests(),app.pb.authStore.clear())}),app.pb.authStore.onChange((e,n)=>{n?.id&&(app.store.loadCollections(),app.store.loadSettings(),app.store.loadOAuth2Providers())});var ke=app.pb.collection;app.pb.collection=function(e){let n=ke.call(this,e);return Ae(n),n};function Ae(e){if(e.__customUIEvents)return;e.__customUIEvents=!0;let n=e.create;e.create=function(){return n.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:create`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let r=e.update;e.update=function(){return r.apply(e,arguments).then(e=>(setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:update`,{detail:e})),document.dispatchEvent(new CustomEvent(`record:save`,{detail:e}))},0),e))};let i=e.delete;e.delete=function(){return i.apply(e,arguments).then(n=>{let r={id:arguments[0],collectionId:e.collectionIdOrName,collectionName:e.collectionIdOrName};return setTimeout(()=>{document.dispatchEvent(new CustomEvent(`record:delete`,{detail:r}))},0),n})}}var je=`pbLastFileToken`,Me=!1,Ne=[];app.pb.authStore.onChange((e,n)=>{n?.id||window.localStorage.removeItem(je)}),window.app.getFileToken=async function(e=``){let n=e&&app.store.collections?.find(n=>n.id==e||n.name==e);if(n&&!n.fields?.find(e=>e.type==`file`&&e.protected))return;let r=window.localStorage.getItem(je);return(!r||se(r,60))&&(r=await Pe()),r};async function Pe(){return new Promise(async(e,n)=>{if(Ne.push({resolve:e,reject:n}),!Me){Me=!0;try{let e=await app.pb.files.getToken();window.localStorage.setItem(je,e),Ne.forEach(n=>n.resolve(e))}catch(e){Ne.forEach(n=>n.reject(e))}Me=!1,Ne=[]}})}window.app.checkApiError=function(e,n=!0){if(!e||!(e instanceof Error)||e.isAbort){console.warn(`checkApiError - unexpected error type:`,e);return}let r=e?.status<<0,i=e?.response||{},a=n&&(i.message||e.message||`Something went wrong!`);if(a&&app.toasts.error(a),r==0&&console.log(e),app.utils.isEmpty(i.data)||(app.store.errors=i.data),r===401&&window.location.hash!=De)return app.pb.cancelAllRequests(),app.pb.authStore.clear()};function Fe(){return()=>{if(!(!app.store._ready||!app.store.showHeader||!app.store.superuser?.id))return t.header({pbEvent:`appHeader`,rid:`appHeader`,className:`app-header accent-surface`,onmount:async e=>{await new Promise(e=>setTimeout(e,0)),e._scrollToActiveMenuItem=function(){e?.querySelector(`.app-main-nav .header-link.active`)?.scrollIntoView()},e._scrollToActiveMenuItem(),window.addEventListener(`hashchange`,e._scrollToActiveMenuItem)},onunmount:e=>{window.removeEventListener(`hashchange`,e?._scrollToActiveMenuItem)}},t.a({href:`#/`,className:`logo`},t.img({src:()=>app.store.headerLogo,alt:`App logo`})),t.nav({pbEvent:`mainNav`,className:`app-main-nav`},()=>app.store.headerLinks.map(e=>{let n=e.href.startsWith(`#/`);return t.a({href:()=>e.href,target:()=>n?void 0:`_blank`,rel:()=>n?void 0:`noopener noreferrer`,className:n=>`header-link ${e.isActive?.(n)||app.utils.isActivePath(e.href)?`active`:``}`},()=>{if(e.icon)return t.i({className:e.icon,ariaHidden:!0})},t.span({className:`txt`},()=>e.label))})),t.div({className:`flex-fill app-header-separator`}),Ie(),t.button({type:`button`,className:`header-link logged-user txt-normal`,"html-popovertarget":`logged-user-dropdown`},t.span({className:`superuser-name txt-ellipsis`},()=>app.store.superuser?.email),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0})),t.div({pbEvent:`loggedUserDropdown`,id:`logged-user-dropdown`,className:`dropdown sm nowrap logged-user-dropdown`,popover:`auto`},t.a({className:`dropdown-item dropdown-item-manage`,href:`#/collections?collection=_superusers`,onclick:e=>{e.target.closest(`.dropdown`).hidePopover()}},t.i({className:`ri-group-line`,ariaHidden:!0}),t.span({className:`txt`},`Manage superusers`)),t.hr(),t.button({type:`button`,className:`dropdown-item txt-danger dropdown-item-logout`,onclick:()=>app.pb.authStore.clear()},t.i({className:`ri-logout-circle-line`,ariaHidden:!0}),t.span({className:`txt`},`Logout`))))}}function Ie(){let e=[{value:`light`,icon:`ri-sun-line`,label:`Light`},{value:`dark`,icon:`ri-moon-line`,label:`Dark`},{value:``,icon:`ri-subtract-line`,label:`Auto`}];return[t.button({type:`button`,className:`header-link color-scheme-picker`,"html-popovertarget":`color-scheme-dropdown`,title:`Color scheme`},t.i({className:()=>app.store.activeColorScheme==`dark`?`ri-moon-line`:`ri-sun-line`,ariaHidden:!0})),t.div({pbEvent:`colorSchemeDropdown`,id:`color-scheme-dropdown`,className:`dropdown sm nowrap color-scheme-dropdown`,popover:`auto`},()=>e.map(e=>t.button({type:`button`,className:()=>`dropdown-item dropdown-item-light ${app.store.userColorScheme==e.value?`active`:``}`,onclick:n=>{n.target.closest(`.dropdown`).hidePopover(),app.store.userColorScheme=e.value}},t.i({className:e.icon,ariaHidden:!0}),t.span({className:`txt`},e.label))))]}document.addEventListener(`invalid`,e=>{let n=e.target.closest(`details`);n&&!n.open&&!e.target.closest(`summary`)&&(n.open=!0,e.target.reportValidity&&e.target.reportValidity())},!0);var Le=`dropdown-item`;document.addEventListener(`toggle`,e=>{if(e.newState!=`open`||!e.target||e.target.__keyboardNavRegistered||!e.target.matches(`.dropdown`))return;e.target.__keyboardNavRegistered=!0;let n=e.target;function r(e){if(!n.isConnected){document.removeEventListener(`keydown`,r);return}let i;if(i=document.activeElement&&document.activeElement.classList.contains(Le)?document.activeElement:n.querySelector(`.dropdown-item:not([hidden]):not(.disabled)`),i){if(e.key==`ArrowUp`){e.preventDefault();let n=ze(i,-1);i==document.activeElement&&n?.classList?.contains(Le)?n?.focus():i.focus()}else if(e.key==`ArrowDown`){e.preventDefault();let n=ze(i,1);i==document.activeElement&&n?.classList?.contains(Le)?n?.focus():i.focus()}else if(e.keyCode>=65&&e.keyCode<=90||e.keyCode>=48&&e.keyCode<=57){let e=n.querySelectorAll(`input,textare,select`);e.length==1&&e[0].focus()}}}n.addEventListener(`toggle`,e=>{e.newState==`open`?(n.__dropdownSource=e.source,n.__dropdownSource?.setAttribute(`data-popover-state`,!0),Re(e.target.id,!0),document.addEventListener(`keydown`,r)):(n.__dropdownSource?.setAttribute(`data-popover-state`,!1),Re(e.target.id,!1),document.removeEventListener(`keydown`,r))})},!0);function Re(e,n=!1){e&&document.querySelectorAll(`[popovertarget='`+e+`']`)?.forEach(e=>e.setAttribute(`data-popover-state`,n))}function ze(e,n=-1){let r=n<0?e.previousElementSibling:e.nextElementSibling;return r&&(r.hidden||r.classList.contains(`disabled`)||!r.classList.contains(Le))?ze(r,n):r}var Be=5,P=t.div({ariaHidden:!0,popover:`manual`,className:`pb-tooltip`});document.body.appendChild(P);function Ve(e,n,r){P._relatedNode=e;let i=e.getBoundingClientRect();P.setAttribute(`data-style`,r||``),P.setAttribute(`data-position`,n),P.style.top=`0px`,P.style.left=`0px`;let a=P.offsetHeight,o=P.offsetWidth,s=0,c=0;n==`left`?(s=i.top+i.height/2-a/2,c=i.left-o-Be):n==`right`?(s=i.top+i.height/2-a/2,c=i.right+Be):n==`top`?(s=i.top-a-Be,c=i.left+i.width/2-o/2):n==`top-left`?(s=i.top-a-Be,c=i.left):n==`top-right`?(s=i.top-a-Be,c=i.right-o):n==`bottom-left`?(s=i.top+i.height+Be,c=i.left):n==`bottom-right`?(s=i.top+i.height+Be,c=i.right-o):(s=i.top+i.height+Be,c=i.left+i.width/2-o/2),c+o>document.documentElement.clientWidth&&(c=document.documentElement.clientWidth-o),c=c>=0?c:0,s+a>document.documentElement.clientHeight&&(s=document.documentElement.clientHeight-a),s=s>=0?s:0,P.style.top=s+`px`,P.style.left=c+`px`}function He(){P._relatedNode=null,P.hidePopover()}function Ue(e,n,r,i){if(!e||!n){He();return}P.showPopover(),P.textContent=n,Ve(e,r,i)}document.body.addEventListener(`mouseleave`,()=>{He()});function We(e,n=`top`,r=``){return i=>{if(!i._tooltipText){i._tooltipText=store({value:``});let e;function a(){e?.unwatch(),e=watch(()=>i._tooltipText.value,async e=>{Ue(i,e,n,r)})}async function o(){e?.unwatch(),e=null,He()}i.addEventListener(`mouseenter`,a),i.addEventListener(`focusin`,a),i.addEventListener(`mouseleave`,o),i.addEventListener(`focusout`,o),i.addEventListener(`blur`,o);let s=i.onunmount;i.onunmount=n=>{P._relatedNode==n&&He(),e?.unwatch(),n._tooltipText=null,n?.removeEventListener(`mouseenter`,a),n?.removeEventListener(`focusin`,a),n?.removeEventListener(`mouseleave`,o),n?.removeEventListener(`focusout`,o),n?.removeEventListener(`blur`,o),s(n)}}return typeof e==`function`?i._tooltipText.value=e():i._tooltipText.value=e,i._tooltipText.value}}window.app=window.app||{},window.app.attrs=window.app.attrs||{},window.app.attrs.tooltip=We,window.app=window.app||{},window.app.modals=window.app.modals||{},window.app.modals.confirm=function(e,n,r,i={className:void 0,yesButton:``,noButton:``}){F.textOrElem=e,F.yesCallback=n,F.yesCallbackWaiting=!1,F.noCallback=r,F.noCallbackWaiting=!1,F.className=typeof i.className==`string`?i.className:`sm`,F.yesButton=i.yesButton||`Yes`,F.noButton=i.noButton||`No`,Ge.isConnected||document.body.appendChild(Ge),window.app.modals.open(Ge)};var F=store({className:``,textOrElem:null,yesButton:``,yesCallback:null,yesCallbackWaiting:!1,noButton:``,noCallback:null,noCallbackWaiting:!1,get isBusy(){return F.yesCallbackWaiting||F.noCallbackWaiting}}),Ge=t.div({className:()=>`modal popup manual ${F.className||``}`},t.div({className:`modal-content`},e=>typeof F.textOrElem==`string`?t.h6({className:`block txt-center`},F.textOrElem):typeof F.textOrElem==`function`?F.textOrElem(e):F.textOrElem),t.footer({className:`modal-footer p-sm`},t.div({className:`grid sm`},t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block secondary ${F.noCallbackWaiting?`loading`:``}`,disabled:()=>F.isBusy,onclick:async()=>{if(F.noCallback){F.noCallbackWaiting=!0;try{if(await F.noCallback()===!1)return}catch(e){console.log(`confirm noCallback error:`,e)}finally{F.noCallbackWaiting=!1}}window.app.modals.close(Ge)}},()=>typeof F.noButton==`string`?t.span({className:`txt`},F.noButton):typeof F.noButton==`function`?F.noButton(el):F.noButton)),t.div({className:`col-sm-6`},t.button({type:`button`,className:()=>`btn lg block warning ${F.yesCallbackWaiting?`loading`:``}`,disabled:()=>F.isBusy,onclick:async()=>{if(F.yesCallback){F.yesCallbackWaiting=!0;try{if(await F.yesCallback()===!1)return}catch(e){console.log(`confirm yesCallback error:`,e)}finally{F.yesCallbackWaiting=!1}}window.app.modals.close(Ge)}},()=>typeof F.yesButton==`string`?t.span({className:`txt`},F.yesButton):typeof F.yesButton==`function`?F.yesButton(el):F.yesButton)))));window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.dragline=function(e={}){let n,r=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,tolerance:0,ondragstart:function(e){},ondragstop:function(e){},ondragging:function(e,n,r){}}),i=app.utils.extendStore(r,e),a=store({dragStarted:!1}),o,s,c,l;function u(){document.addEventListener(`touchmove`,m),document.addEventListener(`mousemove`,m),document.addEventListener(`touchend`,p),document.addEventListener(`mouseup`,p)}function d(){document.removeEventListener(`touchmove`,m),document.removeEventListener(`mousemove`,m),document.removeEventListener(`touchend`,p),document.removeEventListener(`mouseup`,p)}function f(e){e.stopPropagation(),o=e.clientX,s=e.clientY,c=e.clientX-n.offsetLeft,l=e.clientY-n.offsetTop,u()}function p(e){a.dragStarted&&(e.preventDefault(),a.dragStarted=!1,r.ondragstop?.(e)),d()}function m(e){let i=e.clientX-o,u=e.clientY-s,d=e.clientX-c,f=e.clientY-l;!a.dragStarted&&Math.abs(d-n.offsetLeft)r.id,hidden:()=>r.hidden,inert:()=>r.inert,className:()=>`dragline ${a.dragStarted?`dragging`:``} ${r.className}`,onmousedown:e=>{e.button==0&&f(e)},ontouchstart:f,onunmount:()=>{d(),i.forEach(e=>e?.unwatch())}}),n},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.slide=function(e,...n){let r;return t.div({className:n=>`block slide-block ${e?.(n)?``:`hidden`}`,onmount:e=>{r=setTimeout(()=>{e?.setAttribute(`data-slide`,`1`)},200)},onunmount:()=>{clearTimeout(r)}},...n)},window.app=window.app||{},window.app.modals=window.app.modals||{};var Ke=`data-modal-state`,qe=`manual`,Je;window.app.modals.open=async function(e){if(!e?.isConnected){console.error(`modals.open requies an active DOM element`,e);return}let n;if(e.onbeforeopen&&(n=await e.onbeforeopen(e)),n===!1)return;if(e.onafteropen){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height>0&&e?.onafteropen&&(e.onafteropen(e),n.disconnect(),n=null)});n.observe(e)}Je=document.activeElement,Ye(e),e._forceClose=()=>app.modals.close(e,!0),window.addEventListener(`popstate`,e._forceClose);let r=Math.max(Xe(e)?.style.zIndex<<0,1e3);e.style.zIndex=r+1,e.setAttribute(Ke,`open`)},window.app.modals.close=async function(e=null,n=!1){if(e||=Xe(),e){if(window.removeEventListener(`popstate`,e._forceClose),n)e.onbeforeclose?.(e,!0),e.setAttribute(Ke,`close`),e.onafterclose?.(e,!0);else{if(e.onbeforeclose&&await e.onbeforeclose(e,!1)===!1)return;if(e.onafterclose){let n=new ResizeObserver(r=>{for(let i of r)i.contentRect.height<=0&&e?.onafterclose&&(e.onafterclose(e,!1),n.disconnect(),n=null)});n.observe(e)}e.setAttribute(Ke,`close`)}Je&&(Je.focus?.(),setTimeout(()=>{Je?.blur?.(),Je=null},0))}};function Ye(e){if(e.getAttribute(`tabindex`)||e.setAttribute(`tabindex`,`-1`),setTimeout(()=>{let n=e?.querySelector(`[autofocus]`);n?n.focus():e?.focus()},0),e.getAttribute(Ke))return;e.setAttribute(Ke,``),e.addEventListener(`keydown`,n=>{n.key!=`Escape`||e.classList.contains(qe)||n.target!==e&&e.contains(n.target)||window.app.modals.close(e)});let n=!1,r=r=>{n=r.target!==e&&e.contains(r.target)};e.addEventListener(`mousedown`,r),e.addEventListener(`touchstart`,r);let i=!1,a=n=>{i=n.target!==e&&e.contains(n.target)};e.addEventListener(`mouseup`,a),e.addEventListener(`touchend`,a),e.addEventListener(`click`,r=>{n||i||e.classList.contains(qe)||r.target!==e&&e.contains(r.target)||window.app.modals.close(e)})}function Xe(e){let n=document.querySelectorAll(`[${Ke}="open"]`),r=0,i=0,a;for(let o of n)e&&o==e||(r=o.style.zIndex<<0,r>i&&(i=r,a=o));return a}window.app.modals.getTop=function(){return Xe()};var Ze=new Map,Qe=t.div({className:`toasts-container`});function I(e,n=!0){let r=Ze.get(e);!r||!r.isConnected||(Ze.delete(e),clearTimeout(r._removeTimeout),n?(r.classList.add(`removing`),setTimeout(()=>{r.remove()},300)):r.remove())}function R(e=!0){Ze.forEach((n,r)=>{window.app.toasts.remove(r,e)})}function $e(e,n={}){n.type=`info`,n.duration=n.duration||3e3,nt(e,n)}function et(e,n={}){n.type=`success`,n.duration=n.duration||3e3,nt(e,n)}function tt(e,n={}){n.type=`error`,n.duration=n.duration||3500,nt(e,n)}function nt(e,n={}){n=Object.assign({duration:3e3,key:void 0,type:`info`},n),Qe.isConnected||document.body.appendChild(Qe);let r=n.key||e;Ze.has(r)&&I(r,!1);function i(e){e?._removeTimeout&&clearTimeout(e?._removeTimeout),e._removeTimeout=setTimeout(()=>{I(r)},n.duration)}let a=t.div({className:`toast ${n.type||``}`,onmount:e=>{i(e)},onunmount:e=>{e?._removeTimeout&&(clearTimeout(e?._removeTimeout),a=null)},onmouseover:()=>{clearTimeout(a?._removeTimeout)},onmouseout:()=>{i(a)}},t.div({className:`toast-container`},t.div({className:`toast-icon`}),t.div({className:`toast-content`},e,t.button({type:`button`,className:`m-l-auto btn circle sm transparent secondary toast-remove`,title:`Clear`,onclick:()=>I(r)},t.i({className:`ri-close-line`,ariaHidden:!0})))));Ze.set(r,a),Qe.prepend(a)}window.app=window.app||{},window.app.toasts=window.app.toasts||{},window.app.toasts.info=$e,window.app.toasts.error=tt,window.app.toasts.success=et,window.app.toasts.remove=I,window.app.toasts.removeAll=R,window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.sortable=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,data:[],dataItem:function(e,n,r){return t.span(null,`Item `+n)},onchange:function(e,n,r){},handle:``,before:void 0,after:void 0}),r=app.utils.extendStore(n,e);function i(e){function r(){e.querySelectorAll(`:scope > [data-dragstart="true"]`)?.forEach(e=>{e.dataset.dragstart=!1}),e.querySelectorAll(`:scope > [data-dragover="true"]`)?.forEach(e=>{e.dataset.dragover=!1})}e.addEventListener(`dragstart`,r=>{if(n.handle&&!r.target.closest(n.handle)){r.preventDefault();return}let i=o(e,r.target);i&&(i.dataset.dragstart=!0)}),e.addEventListener(`dragenter`,n=>{for(let n of e.children)n.dataset.dragover&&(n.dataset.dragover=!1);let r=o(e,n.target);r&&(r.dataset.dragover=!0)}),e.addEventListener(`dragover`,e=>{e.preventDefault()}),e.addEventListener(`drop`,i=>{if(!n.onchange){r();return}let s=e.querySelector(`:scope > [data-dragstart="true"]`),c=o(e,i.target);if(r(),!s||!c||c==s)return;let l=e.querySelectorAll(`:scope > [data-sortable-child]`),u=a(l,s),d=a(l,c);if(u==-1||d==-1)return;let f=n.data.slice(),p=f.splice(u,1);f.splice(d,0,p[0]),n.onchange(f,u,d)}),e._documentDragend=function(){r()},document.addEventListener(`dragend`,e._documentDragend)}function a(e,n){for(let r=0;rn.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>n.className,onmount:e=>{i(e)},onunmount:e=>{r.forEach(e=>e?.unwatch()),e._documentDragend&&document.removeEventListener(`dragend`,e._documentDragend)}},e=>typeof n.before==`function`?n.before(e):n.before,e=>{let r=[];for(let i=0;itypeof n.after==`function`?n.after(e):n.after)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.copyButton=function(e,...n){let r=store({active:!1}),i;function a(){let n=e;typeof n==`function`&&(n=e()),app.utils.copyToClipboard(n),r.active=!0,clearTimeout(i),i=setTimeout(()=>{r.active=!1},500)}return t.button({tabIndex:-1,type:`button`,className:()=>`copy-to-clipboard ${r.active?`active`:``}`,title:`Copy`,ariaDescription:app.attrs.tooltip(()=>r.active?`Copied`:null),onclick:e=>{e.preventDefault(),e.stopPropagation(),a()}},t.i({hidden:n?.length,ariaHidden:!0,className:()=>`copy-icon ${r.active?`ri-check-double-line`:`ri-file-copy-line`}`}),...n)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlock=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,language:`js`,value:void 0,footnote:void 0}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`code-wrapper ${n.className}`,tabIndex:-1,onmount:e=>{e.addEventListener(`keydown`,n=>{(n.ctrlKey||n.metaKey)&&(n.key==`a`||n.key==`A`)&&(n.preventDefault(),window.getSelection().selectAllChildren(e))})},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.code({className:`block`,innerHTML:()=>rt(n.value,n.language)}),t.div({className:`footnote`},e=>typeof n.footnote==`function`?n.footnote(e):n.footnote))};function rt(e,n){return e=typeof e==`string`?e:``,e=Prism.plugins.NormalizeWhitespace.normalize(e,{"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.highlight(e,Prism.languages[n]||Prism.languages.js,n)}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeEditor=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,name:void 0,className:``,value:``,language:`js`,placeholder:``,disabled:!1,required:!1,singleLine:!1,autocomplete:void 0,oninput:function(e){},onfocus:function(e){},onblur:function(e){}}),r=app.utils.extendStore(n,e,`autocomplete`),i,a,o=!0;function s(e){c(),i=t.div({className:`dropdown autocomplete code-editor-dropdown`,onmount:e=>{e._updatePosition=()=>{o?dt(i):c()},e._closeOnEsc=e=>{e.key==`Escape`&&(e.preventDefault(),c())},window.addEventListener(`scroll`,e._updatePosition,!0),window.addEventListener(`resize`,e._updatePosition),window.addEventListener(`keydown`,e._closeOnEsc),e._updatePosition()},onunmount:e=>{e&&(window.removeEventListener(`scroll`,e._updatePosition,!0),window.removeEventListener(`resize`,e._updatePosition),window.removeEventListener(`keydown`,e._closeOnEsc))}},e),document.body.appendChild(i),f&&(a?.disconnect(),a=new IntersectionObserver(([e])=>{o=e.isIntersecting},{root:null,threshold:.1}),a.observe(f))}function c(){i&&=(i.remove(),null),a&&=(a.disconnect(),null),o=!0}function l(e){n.value=e,n.oninput?.(e),f.dispatchEvent(new CustomEvent(`change`,{detail:e}))}let u=!1,d,f=t.div({contentEditable:()=>!n.disabled&&`plaintext-only`,tabIndex:0,spellcheck:!1,autocorrect:!1,autocomplete:`off`,autocapitalize:`off`,role:`textbox`,className:`editor-content`,"html-data-placeholder":()=>n.placeholder,onmount:e=>{d?.unwatch(),d=watch(()=>n.value,e=>{e!=f.textContent&&(f.textContent=e,c())})},onunmount:e=>{d?.unwatch(),c()},onfocus:()=>{n.onfocus?.(n.value)},onblur:e=>{i&&!i.contains(e.relatedTarget)&&c(),n.onblur?.(n.value)},oninput:e=>{if(c(),l(f.textContent),!n.value?.length){f.textContent=``;return}if(!f?.isConnected)return;let r=ut(f),i=st(n.value,r);if(!i.word.length||r==i.start)return;let a=[];if(typeof n.autocomplete==`function`)a=n.autocomplete(i.word)||[];else if(!app.utils.isEmpty(n.autocomplete)){let e=i.word.toLowerCase();a=n.autocomplete.filter(n=>(typeof n==`object`&&(n=n?.value),n=n?.toLowerCase(),n&&n!=e&&n.includes(e)))}a?.length&&s(()=>a.map((e,n)=>t.button({type:`button`,className:`dropdown-item ${n==0?`active`:``}`,textContent:e.label||e.value||e,onclick:n=>{n.preventDefault(),f.focus();let r=e.value||e;f.textContent=f.textContent.substring(0,i.start)+r+f.textContent.substring(i.end+1),l(f.textContent);try{window.getSelection().setPosition(f.childNodes[0],i.start+r.length)}catch(e){console.warn(`failed to set caret position`,e)}c()}})))},onkeydown:e=>{if(u=e.ctrlKey||e.metaKey,(e.key==`Enter`||e.key==`Tab`)&&i?.isConnected){e.preventDefault(),i.querySelector(`.dropdown-item.active`)?.click();return}if(e.key==`ArrowUp`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.previousElementSibling&&(n.classList.remove(`active`),n.previousElementSibling.classList.add(`active`),n.previousElementSibling.scrollIntoView(!1));return}if(e.key==`ArrowDown`&&i?.isConnected){e.preventDefault();let n=i.querySelector(`.dropdown-item.active`);n?.nextElementSibling&&(n.classList.remove(`active`),n.nextElementSibling.classList.add(`active`),n.nextElementSibling.scrollIntoView(!1));return}if(u&&e.key.toLowerCase()==`l`){e.preventDefault(),ct(f);return}if(u&&e.key.toLowerCase()==`d`){e.preventDefault(),lt(f);return}if(!n.singleLine&&e.key==`Escape`&&!i?.isConnected){f?.blur();return}if(!n.singleLine&&e.key==`Tab`){e.preventDefault();let n=window.getSelection();if(!n)return;if(e.shiftKey){n.modify(`extend`,`backward`,`character`),n.toString()[0]==` `?(n.deleteFromDocument(),l(f.textContent)):(n.modify(`extend`,`forward`,`character`),n.toString()[0]==` `&&(n.deleteFromDocument(),l(f.textContent)));return}let r=n.getRangeAt(0);r&&(r.deleteContents(),r.insertNode(document.createTextNode(` `)),r.collapse(),l(f.textContent));return}if(n.singleLine&&e.key==`Enter`){e.preventDefault(),m.click();return}},onscroll:()=>{c(),p&&(p.scrollLeft=f.scrollLeft,p.scrollTop=f.scrollTop)}}),p=t.div({className:`highlight-overlay`,innerHTML:()=>at(n.value,n.language),onscroll:()=>{f&&(f.scrollLeft=p.scrollLeft,f.scrollTop=p.scrollTop)}}),m=t.button({type:`submit`,className:`hidden`});return t.div({rid:n.rid,id:()=>n.id,inert:()=>n.inert,hidden:()=>n.hidden,"html-name":()=>n.name,"html-required":()=>n.required||void 0,className:()=>`input code-editor ${n.className} ${n.disabled?`disabled`:``} ${n.singleLine?`single-line`:``}`,onclick:()=>{f?.focus()},onunmount:()=>{r?.forEach(e=>e?.unwatch())}},t.div({className:`code-editor-container`},f,p,m))};var it=500;function at(e,n){return e=typeof e==`string`?e:``,e?((!Prism.languages[n]||e.length>it)&&(n=`plain`),Prism.highlight(e,Prism.languages[n],n)):``}var ot=new RegExp(/[\p{Alphabetic}\p{Number}_@:\."'{}]/,`u`);function st(e,n){let r=n;for(let i=n-1;i>=0&&ot.test(e[i]);i--)r=i;let i=r;for(let r=n-1;rdocument.documentElement.clientHeight&&(o=Math.max(n.top-r,0)),a+i>document.documentElement.clientWidth&&(a=Math.max(document.documentElement.clientWidth-i,0)),e.style.left=a+`px`,e.style.top=o+`px`}window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.codeBlockTabs=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,activeTabIndex:0,historyKey:``,tabs:[],get activeTab(){return n.tabs[n.activeTabIndex]||n.tabs[0]}}),r=app.utils.extendStore(n,e);return r.push(watch(()=>n.activeTabIndex,(e,r)=>{r!=null&&n.historyKey&&localStorage.setItem(n.historyKey,e)})),t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden||!n.tabs.length,inert:()=>n.inert,className:()=>`code-block-tabs ${n.className}`,onmount:()=>{n.historyKey&&(n.activeTabIndex=localStorage.getItem(n.historyKey)<<0)},onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.header({className:`tabs-header`},()=>n.tabs.map((e,r)=>t.button({type:`button`,className:()=>`tab-item ${n.activeTabIndex==r?`active`:``}`,onclick:()=>n.activeTabIndex=r},n=>typeof e.title==`function`?e.title(n):e.title))),t.div({className:`code-block-tabs-content`},()=>{if(n.activeTab)return app.components.codeBlock(n.activeTab)}))},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.select=function(e={}){let n=store({rid:void 0,id:void 0,name:void 0,hidden:void 0,inert:void 0,className:``,value:void 0,options:[],before:null,after:null,max:1,searchThreshold:6,required:!1,disabled:!1,placeholder:`- Select -`,noItemsFoundText:`No items found`,onchange:function(e){},ondropdowntoggle:function(e){}}),r=app.utils.extendStore(n,e);n.max<=0&&(n.max=1);let i=store({selected:[],search:``,get hasSearch(){return i.search?.length>0},get allowRemove(){return!n.disabled&&(!n.required||n.max>1)}});function a(){if(n.value===void 0)return;let e=app.utils.toArray(n.value,!0),r=e.slice(0,n.max||1);e.length!=r.length&&(console.warn(`[select] the provided select values (${e.length}) are more than the allowed max selected options (${r.length}):`,e),n.value=n.max>1?r:r[0]),i.selected=e.map(e=>n.options.find(n=>n.value===e)).filter(Boolean)}r.push(watch(()=>n.value,()=>a()));async function o(e){let r=i.selected.findIndex(n=>n.value===e.value);if(r>=0){if(!i.allowRemove){f?.hidePopover();return}i.selected.splice(r,1)}else{let r=i.selected.length-n.max;for(;r>=0;)i.selected.pop(),r--;i.selected.push(e)}n.max<=1&&f?.hidePopover(),n.onchange&&(await n.onchange(i.selected),a()),p?.isConnected&&p.dispatchEvent(new CustomEvent(`change`,{detail:i.selected,bubbles:!0}))}function s(e){return i.selected.findIndex(n=>n.value===e.value)>=0}let c=t.input({type:`text`,placeholder:`Search...`,value:()=>i.search,oninput:e=>i.search=e.target.value});function l(e=!1){i.search=``,e&&c?.focus()}let u=t.div({className:`txt-hint txt-center m-0 p-5`,hidden:!0},e=>typeof n.noItemsFoundText==`function`?n.noItemsFoundText(e):n.noItemsFoundText);async function d(){f&&(await new Promise(e=>setTimeout(e,0)),f.querySelector(`.select-option:not([hidden])`)?u.hidden=!0:u.hidden=!1)}let f=t.div({tabIndex:-1,popover:`auto`,className:`dropdown`,onbeforetoggle:e=>(e.newState==`closed`&&l(),n.ondropdowntoggle?.(e))},t.div({className:`fields dropdown-search`,hidden:()=>n.options.length!i.hasSearch},t.button({type:`button`,title:`Clear`,className:`btn sm secondary transparent circle`,onclick:()=>l(!0)},t.i({className:`ri-close-line`,ariaHidden:!0})))),()=>n.before?.__raw||n.before,()=>n.options.map(e=>t.button({type:`button`,className:()=>`dropdown-item select-option ${s(e)?`active`:``}`,onclick:()=>(o(e),!1)},e.label||e.value)),u,()=>n.after?.__raw||n.after),p=t.button({type:`button`,id:()=>n.id,name:()=>n.name,disabled:()=>n.disabled,className:()=>`selected-container ${n.className}`,popoverTargetElement:f,onclick:e=>{e.stopPropagation()}},()=>i.selected.length?i.selected.map(e=>t.div({className:`selected-item`},e.selected||e.label||e.value,()=>{if(i.allowRemove)return t.i({tabIndex:-1,role:`button`,className:`ri-close-line link-hint btn-option-unset`,ariaLabel:app.attrs.tooltip(`Unset`),onclick:()=>(o(e),!1)})})):t.span({rid:`selected-placeholder`,className:`placeholder`},e=>typeof n.placeholder==`function`?n.placeholder(e):n.placeholder));r.push(watch(()=>n.options,()=>{d()}));let m;return r.push(watch(()=>i.search,()=>{let e=i.search.toLowerCase().replaceAll(` `,``);clearTimeout(m),m=setTimeout(()=>{let n=f.querySelectorAll(`.select-option`);e.length?n.forEach(n=>{n.textContent.toLowerCase().replaceAll(` `,``).includes(e)?n.hidden=!1:n.hidden=!0}):n.forEach(e=>e.hidden=!1),d()},100)})),t.div({rid:n.rid,hidden:()=>n.hidden,inert:()=>n.inert,onmount:e=>{e.addEventListener(`focusout`,function(n){(!n.relatedTarget||!e.contains(n.relatedTarget))&&f?.hidePopover()})},onunmount:()=>{clearTimeout(m),r.forEach(e=>e.unwatch())},className:()=>[`input`,`select`,n.max>1?`multiple`:`single`,n.disabled?`disabled`:``,n.required?`required`:``].join(` `)},p,f)},window.app=window.app||{},window.app.components=window.app.components||{};var ft=Intl.DateTimeFormat().resolvedOptions().timeZone;window.app.components.formattedDate=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,value:``,short:!1}),r=app.utils.extendStore(n,e);return t.div({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,ariaDescription:app.attrs.tooltip(()=>n.short&&n.value?app.utils.toLocalDatetime(n.value)+` `+ft:null),"html-class":`formatted-date`,className:()=>`formatted-date ${n.short?`short`:`full`}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},()=>{if(!n.value)return t.span({className:`missing-value`});if(n.short){let e=n.value.split(` `);return[t.span({className:`primary-date`},e[0]),t.span({className:`secondary-date`},e[1])]}return[t.span({className:`primary-date`},app.utils.toLocalDatetime(n.value)),t.span({className:`secondary-date`},n.value)]})},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.refreshButton=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,tooltip:`Refresh`,className:`btn transparent secondary circle rotate-btn`,disabled:!1,onclick:function(e){}}),r=app.utils.extendStore(n,e),i,a=t.button({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,type:`button`,ariaLabel:app.attrs.tooltip(()=>n.tooltip),disabled:()=>n.disabled,className:()=>n.className,onunmount:()=>{clearTimeout(i),r.forEach(e=>e?.unwatch())},onclick:e=>{e.preventDefault(),n.onclick&&n.onclick(e),a.dataset.rotate=!0,a.addEventListener(`animationend`,()=>{a.dataset.rotate=!1}),clearTimeout(i),i=setTimeout(()=>{clearTimeout(i),a.dataset.rotate=!1},500)}},t.i({className:`ri-refresh-line`,ariaHidden:!0}));return a},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.searchHistoryButton=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,value:void 0,historyKey:`default`,max:15,openInNewTabParam:`filter`,btnClassName:`btn sm pill secondary transparent p-r-5`,onselect:function(e){}}),r=app.utils.extendStore(n,e),i=store({items:app.utils.getLocalHistory(n.historyKey,[])});function a(e){o(e),i.items.unshift(e)}function o(e){app.utils.removeByValue(i.items,e)}let s=`history_dropdown_`+app.utils.randomString();r.push(watch(()=>n.value,e=>{e&&a(e)})),r.push(watch(()=>{i.items.length>n.max&&(i.items=i.items.slice(0,n.max)),app.utils.saveLocalHistory(n.historyKey,i.items)}));let c=t.div({id:s,className:`dropdown sm left nowrap history-searchbar-dropdown`,popover:`hint`,onclick:e=>(e.stopPropagation(),!1)},t.div({className:`block p-5`},t.small({className:`txt-hint`},`Search history`)),()=>i.items?.length?i.items.slice(0,n.max).map(e=>t.button({type:`button`,className:`dropdown-item txt-code`,onclick:()=>{c.hidePopover(),n.onselect?.(e),a(e)},onauxclick:()=>{if(n.openInNewTabParam){a(e),c.hidePopover();let r=app.utils.replaceHashQueryParams({[n.openInNewTabParam]:e},!1);window.open(r,`_blank`)}}},t.span({className:`txt-ellipsis`,title:e,textContent:e}),t.small({role:`button`,className:`remove-btn link-hint m-l-auto p-l-5 p-r-5`,title:`Clear`,onauxclick:e=>(e.stopPropagation(),!1),onclick:n=>(n.stopPropagation(),o(e),!1)},t.i({className:`ri-close-line`,ariaHidden:!0})))):t.div({rid:`no-history`,className:`block p-5`},t.span(null,`Your recent searches will show up here.`)));return t.button({rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,type:`button`,title:`Search history`,className:()=>n.btnClassName,"html-popovertarget":s,onunmount:()=>{r?.forEach(e=>e?.unwatch())}},t.i({className:`ri-search-line`,ariaHidden:!0}),t.i({className:`ri-arrow-drop-down-line`,ariaHidden:!0}),c)},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.s3Test=function(e={}){let n=`s3_test_request`,r=store({rid:void 0,config:null,label:`Use S3 storage`,testFilesystem:`storage`}),i=app.utils.extendStore(r,e),a=store({isTesting:!1,testError:null,get hasError(){return!app.utils.isEmpty(a.testError)}}),o,s;function c(e=150){if(!r.config.enabled){clearTimeout(o);return}a.isTesting=!0,clearTimeout(o),o=setTimeout(()=>{l()},e)}async function l(){if(a.isTesting=!0,!r.config.enabled||!r.testFilesystem){a.testError=null,a.isTesting=!1;return}app.pb.cancelRequest(n),clearTimeout(s),s=setTimeout(()=>{app.pb.cancelRequest(n),a.testError=Error(`S3 test connection timeout.`),a.isTesting=!1},3e4);try{await app.pb.props.testS3(r.testFilesystem,{requestKey:n}),a.testError=null,a.isTesting=!1}catch(e){e?.isAbort||(a.testError=e,a.isTesting=!1,clearTimeout(s))}}return i.push(watch(()=>r.testFilesystem&&r.config,()=>c())),t.div({pbEvent:`s3Test`,rid:r.rid,hidden:()=>!r.testFilesystem,className:()=>`label s3-test-label txt-nowrap ${a.hasError?`warning`:`success`}`,ariaDescription:app.attrs.tooltip(()=>a.testError?.data?.message),onunmount:()=>{clearTimeout(s),clearTimeout(o),i.forEach(e=>e?.unwatch())}},()=>a.isTesting?t.span({className:`loader sm`}):a.hasError?[t.i({className:`ri-error-warning-line txt-warning`,ariaHidden:!0}),t.span({className:`txt`},`Failed to establish S3 connection`)]:[t.i({className:`ri-checkbox-circle-line txt-success`,ariaHidden:!0}),t.span({className:`txt`},`S3 connected successfully`)])},window.app=window.app||{},window.app.components=window.app.components||{},window.app.components.s3ConfigFields=function(e={}){let n=store({rid:void 0,id:void 0,hidden:void 0,inert:void 0,className:``,config:{},configKey:`s3`,toggleLabel:`Use S3 storage`,testFilesystem:`storage`,before:null,after:null}),r=app.utils.extendStore(n,e);n.configKey.endsWith(`.`)&&(n.configKey=n.configKey.substring(0,n.configKey.length-1));let i=store({originalHash:``,originalConfig:null});return r.push(watch(()=>n.config,e=>{i.originalHash=JSON.stringify(e),i.originalConfig=JSON.parse(i.originalHash)})),t.div({pbEvent:`s3ConfigFields`,rid:n.rid,id:()=>n.id,hidden:()=>n.hidden,inert:()=>n.inert,className:()=>`block s3-fields s3-config-${n.configKey} ${n.className}`,onunmount:()=>{r.forEach(e=>e?.unwatch())}},t.div({className:`field`},t.input({id:()=>`${n.configKey}.enabled`,name:()=>`${n.configKey}.enabled`,type:`checkbox`,className:`switch`,checked:()=>n.config.enabled,onchange:e=>n.config.enabled=e.target.checked}),t.label({htmlFor:()=>`${n.configKey}.enabled`},()=>n.toggleLabel)),e=>typeof n.before==`function`?n.before(e):n.before,app.components.slide(()=>n.config.enabled,t.div({className:`grid m-t-base`},t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.endpoint`},`Endpoint`),t.input({id:()=>`${n.configKey}.endpoint`,name:()=>`${n.configKey}.endpoint`,type:`text`,required:()=>n.config.enabled,value:()=>n.config.endpoint||``,oninput:e=>n.config.endpoint=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.bucket`},`Bucket`),t.input({id:()=>`${n.configKey}.bucket`,name:()=>`${n.configKey}.bucket`,type:`text`,required:()=>n.config.enabled,value:()=>n.config.bucket||``,oninput:e=>n.config.bucket=e.target.value}))),t.div({className:`col-lg-3`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.region`},`Region`),t.input({id:()=>`${n.configKey}.region`,name:()=>`${n.configKey}.region`,type:`text`,required:()=>n.config.enabled,value:()=>n.config.region||``,oninput:e=>n.config.region=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:`field`},t.label({htmlFor:()=>`${n.configKey}.accessKey`},`Access key`),t.input({id:()=>`${n.configKey}.accessKey`,name:()=>`${n.configKey}.accessKey`,type:`text`,autocomplete:`off`,required:()=>n.config.enabled,value:()=>n.config.accessKey||``,oninput:e=>n.config.accessKey=e.target.value}))),t.div({className:`col-lg-6`},t.div({className:()=>`field ${n.config.enabled?``:`required`}`},t.label({htmlFor:()=>`${n.configKey}.secret`},`Secret`),t.input({id:()=>`${n.configKey}.secret`,name:()=>`${n.configKey}.secret`,type:`password`,autocomplete:`new-password`,value:()=>n.config.secret||``,oninput:e=>n.config.secret=e.target.value,onkeyup:e=>{e.key==`Backspace`&&n.config.secret===void 0&&(n.config.secret=``)},placeholder:()=>n.config.secret===void 0?`* * * * * *`:``}))),t.div({className:`col-lg-6`,style:`min-height: 25px`},t.div({className:`field`},t.input({id:()=>`${n.configKey}.forcePathStyle`,name:()=>`${n.configKey}.forcePathStyle`,type:`checkbox`,checked:()=>n.config.forcePathStyle||!1,onchange:e=>n.config.forcePathStyle=e.target.checked}),t.label({htmlFor:()=>`${n.configKey}.forcePathStyle`},t.span({className:`txt`},`Force path-style addressing`),t.i({className:`ri-information-line link-hint`,ariaDescription:app.attrs.tooltip(`Forces the request to use path-style addressing, eg. "https://s3.amazonaws.com/BUCKET/KEY" instead of the default "https://BUCKET.s3.amazonaws.com/KEY".`)})))),t.div({className:`col-lg-6 txt-right`},()=>{if(!(!n.config?.enabled||i.originalHash!=JSON.stringify(n.config)))return app.components.s3Test({config:()=>n.config,testFilesystem:()=>n.testFilesystem})}))),e=>typeof n.after==`function`?n.after(e):n.after)};var pt=l(s(((e,n)=>{(function(r,i){typeof e==`object`&&n!==void 0?i(e):typeof define==`function`&&define.amd?define([`exports`],i):(r=typeof globalThis<`u`?globalThis:r||self,i(r.leaflet={}))})(e,(function(e){var n=`1.9.4`;function r(e){var n,r,i,a;for(r=1,i=arguments.length;r`u`||!L||!L.Mixin)){e=v(e)?e:[e];for(var n=0;n0?Math.floor(e):Math.ceil(e)};w.prototype={clone:function(){return new w(this.x,this.y)},add:function(e){return this.clone()._add(E(e))},_add:function(e){return this.x+=e.x,this.y+=e.y,this},subtract:function(e){return this.clone()._subtract(E(e))},_subtract:function(e){return this.x-=e.x,this.y-=e.y,this},divideBy:function(e){return this.clone()._divideBy(e)},_divideBy:function(e){return this.x/=e,this.y/=e,this},multiplyBy:function(e){return this.clone()._multiplyBy(e)},_multiplyBy:function(e){return this.x*=e,this.y*=e,this},scaleBy:function(e){return new w(this.x*e.x,this.y*e.y)},unscaleBy:function(e){return new w(this.x/e.x,this.y/e.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},trunc:function(){return this.clone()._trunc()},_trunc:function(){return this.x=T(this.x),this.y=T(this.y),this},distanceTo:function(e){e=E(e);var n=e.x-this.x,r=e.y-this.y;return Math.sqrt(n*n+r*r)},equals:function(e){return e=E(e),e.x===this.x&&e.y===this.y},contains:function(e){return e=E(e),Math.abs(e.x)<=Math.abs(this.x)&&Math.abs(e.y)<=Math.abs(this.y)},toString:function(){return`Point(`+d(this.x)+`, `+d(this.y)+`)`}};function E(e,n,r){return e instanceof w?e:v(e)?new w(e[0],e[1]):e==null?e:typeof e==`object`&&`x`in e&&`y`in e?new w(e.x,e.y):new w(e,n,r)}function D(e,n){if(e)for(var r=n?[e,n]:e,i=0,a=r.length;i=this.min.x&&r.x<=this.max.x&&n.y>=this.min.y&&r.y<=this.max.y},intersects:function(e){e=O(e);var n=this.min,r=this.max,i=e.min,a=e.max,o=a.x>=n.x&&i.x<=r.x,s=a.y>=n.y&&i.y<=r.y;return o&&s},overlaps:function(e){e=O(e);var n=this.min,r=this.max,i=e.min,a=e.max,o=a.x>n.x&&i.xn.y&&i.y=n.lat&&a.lat<=r.lat&&i.lng>=n.lng&&a.lng<=r.lng},intersects:function(e){e=A(e);var n=this._southWest,r=this._northEast,i=e.getSouthWest(),a=e.getNorthEast(),o=a.lat>=n.lat&&i.lat<=r.lat,s=a.lng>=n.lng&&i.lng<=r.lng;return o&&s},overlaps:function(e){e=A(e);var n=this._southWest,r=this._northEast,i=e.getSouthWest(),a=e.getNorthEast(),o=a.lat>n.lat&&i.latn.lng&&i.lng1,Ke=function(){var e=!1;try{var n=Object.defineProperty({},"passive",{get:function(){e=!0}});window.addEventListener(`testPassiveEventSupport`,u,n),window.removeEventListener(`testPassiveEventSupport`,u,n)}catch{}return e}(),qe=function(){return!!document.createElement(`canvas`).getContext}(),Je=!!(document.createElementNS&&ge(`svg`).createSVGRect),Ye=!!Je&&(function(){var e=document.createElement(`div`);return e.innerHTML=``,(e.firstChild&&e.firstChild.namespaceURI)===`http://www.w3.org/2000/svg`})(),Xe=!Je&&function(){try{var e=document.createElement(`div`);e.innerHTML=``;var n=e.firstChild;return n.style.behavior=`url(#default#VML)`,n&&typeof n.adj==`object`}catch{return!1}}(),Ze=navigator.platform.indexOf(`Mac`)===0,Qe=navigator.platform.indexOf(`Linux`)===0;function I(e){return navigator.userAgent.toLowerCase().indexOf(e)>=0}var R={ie:ye,ielt9:be,edge:xe,webkit:Se,android:Ce,android23:we,androidStock:Ee,opera:De,chrome:Oe,gecko:ke,safari:Ae,phantom:je,opera12:Me,win:Ne,ie3d:Pe,webkit3d:Fe,gecko3d:Ie,any3d:Le,mobile:Re,mobileWebkit:ze,mobileWebkit3d:Be,msPointer:P,pointer:Ve,touch:Ue,touchNative:He,mobileOpera:We,mobileGecko:F,retina:Ge,passiveEvents:Ke,canvas:qe,svg:Je,vml:Xe,inlineSvg:Ye,mac:Ze,linux:Qe},$e=R.msPointer?`MSPointerDown`:`pointerdown`,et=R.msPointer?`MSPointerMove`:`pointermove`,tt=R.msPointer?`MSPointerUp`:`pointerup`,nt=R.msPointer?`MSPointerCancel`:`pointercancel`,rt={touchstart:$e,touchmove:et,touchend:tt,touchcancel:nt},it={touchstart:mt,touchmove:pt,touchend:pt,touchcancel:pt},at={},ot=!1;function st(e,n,r){return n===`touchstart`&&ft(),it[n]?(r=it[n].bind(this,r),e.addEventListener(rt[n],r,!1),r):(console.warn(`wrong event specified:`,n),u)}function ct(e,n,r){if(!rt[n]){console.warn(`wrong event specified:`,n);return}e.removeEventListener(rt[n],r,!1)}function lt(e){at[e.pointerId]=e}function ut(e){at[e.pointerId]&&(at[e.pointerId]=e)}function dt(e){delete at[e.pointerId]}function ft(){ot||=(document.addEventListener($e,lt,!0),document.addEventListener(et,ut,!0),document.addEventListener(tt,dt,!0),document.addEventListener(nt,dt,!0),!0)}function pt(e,n){if(n.pointerType!==(n.MSPOINTER_TYPE_MOUSE||`mouse`)){for(var r in n.touches=[],at)n.touches.push(at[r]);n.changedTouches=[n],e(n)}}function mt(e,n){n.MSPOINTER_TYPE_TOUCH&&n.pointerType===n.MSPOINTER_TYPE_TOUCH&&X(n),pt(e,n)}function ht(e){var n={},r,i;for(i in e)r=e[i],n[i]=r&&r.bind?r.bind(e):r;return e=n,n.type=`dblclick`,n.detail=2,n.isTrusted=!1,n._simulated=!0,n}var gt=200;function _t(e,n){e.addEventListener(`dblclick`,n);var r=0,i;function a(e){if(e.detail!==1){i=e.detail;return}if(!(e.pointerType===`mouse`||e.sourceCapabilities&&!e.sourceCapabilities.firesTouchEvents)){var a=$t(e);if(!(a.some(function(e){return e instanceof HTMLLabelElement&&e.attributes.for})&&!a.some(function(e){return e instanceof HTMLInputElement||e instanceof HTMLSelectElement}))){var o=Date.now();o-r<=gt?(i++,i===2&&n(ht(e))):i=1,r=o}}}return e.addEventListener(`click`,a),{dblclick:n,simDblclick:a}}function vt(e,n){e.removeEventListener(`dblclick`,n.dblclick),e.removeEventListener(`click`,n.simDblclick)}var yt=jt([`transform`,`webkitTransform`,`OTransform`,`MozTransform`,`msTransform`]),bt=jt([`webkitTransition`,`transition`,`OTransition`,`MozTransition`,`msTransition`]),xt=bt===`webkitTransition`||bt===`OTransition`?bt+`End`:`transitionend`;function St(e){return typeof e==`string`?document.getElementById(e):e}function Ct(e,n){var r=e.style[n]||e.currentStyle&&e.currentStyle[n];if((!r||r===`auto`)&&document.defaultView){var i=document.defaultView.getComputedStyle(e,null);r=i?i[n]:null}return r===`auto`?null:r}function z(e,n,r){var i=document.createElement(e);return i.className=n||``,r&&r.appendChild(i),i}function B(e){var n=e.parentNode;n&&n.removeChild(e)}function wt(e){for(;e.firstChild;)e.removeChild(e.firstChild)}function Tt(e){var n=e.parentNode;n&&n.lastChild!==e&&n.appendChild(e)}function Et(e){var n=e.parentNode;n&&n.firstChild!==e&&n.insertBefore(e,n.firstChild)}function Dt(e,n){if(e.classList!==void 0)return e.classList.contains(n);var r=kt(e);return r.length>0&&RegExp(`(^|\\s)`+n+`(\\s|$)`).test(r)}function V(e,n){if(e.classList!==void 0)for(var r=p(n),i=0,a=r.length;i0?2*window.devicePixelRatio:1;function nn(e){return R.edge?e.wheelDeltaY/2:e.deltaY&&e.deltaMode===0?-e.deltaY/tn:e.deltaY&&e.deltaMode===1?-e.deltaY*20:e.deltaY&&e.deltaMode===2?-e.deltaY*60:e.deltaX||e.deltaZ?0:e.wheelDelta?(e.wheelDeltaY||e.wheelDelta)/2:e.detail&&Math.abs(e.detail)<32765?-e.detail*20:e.detail?e.detail/-32765*60:0}function rn(e,n){var r=n.relatedTarget;if(!r)return!0;try{for(;r&&r!==e;)r=r.parentNode}catch{return!1}return r!==e}var an={__proto__:null,on:q,off:Y,stopPropagation:Yt,disableScrollPropagation:Xt,disableClickPropagation:Zt,preventDefault:X,stop:Qt,getPropagationPath:$t,getMousePosition:en,getWheelDelta:nn,isExternalTarget:rn,addListener:q,removeListener:Y},on=ce.extend({run:function(e,n,r,i){this.stop(),this._el=e,this._inProgress=!0,this._duration=r||.25,this._easeOutPower=1/Math.max(i||.5,.2),this._startPos=Nt(e),this._offset=n.subtract(this._startPos),this._startTime=+new Date,this.fire(`start`),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=b(this._animate,this),this._step()},_step:function(e){var n=+new Date-this._startTime,r=this._duration*1e3;nthis.options.maxZoom)?this.setZoom(e):this},panInsideBounds:function(e,n){this._enforcingBounds=!0;var r=this.getCenter(),i=this._limitCenter(r,this._zoom,A(e));return r.equals(i)||this.panTo(i,n),this._enforcingBounds=!1,this},panInside:function(e,n){n||={};var r=E(n.paddingTopLeft||n.padding||[0,0]),i=E(n.paddingBottomRight||n.padding||[0,0]),a=this.project(this.getCenter()),o=this.project(e),s=this.getPixelBounds(),c=O([s.min.add(r),s.max.subtract(i)]),l=c.getSize();if(!c.contains(o)){this._enforcingBounds=!0;var u=o.subtract(c.getCenter()),d=c.extend(o).getSize().subtract(l);a.x+=u.x<0?-d.x:d.x,a.y+=u.y<0?-d.y:d.y,this.panTo(this.unproject(a),n),this._enforcingBounds=!1}return this},invalidateSize:function(e){if(!this._loaded)return this;e=r({animate:!1,pan:!0},e===!0?{animate:!0}:e);var n=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var i=this.getSize(),o=n.divideBy(2).round(),s=i.divideBy(2).round(),c=o.subtract(s);return!c.x&&!c.y?this:(e.animate&&e.pan?this.panBy(c):(e.pan&&this._rawPanBy(c),this.fire(`move`),e.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,`moveend`),200)):this.fire(`moveend`)),this.fire(`resize`,{oldSize:n,newSize:i}))},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire(`viewreset`),this._stop()},locate:function(e){if(e=this._locateOptions=r({timeout:1e4,watch:!1},e),!(`geolocation`in navigator))return this._handleGeolocationError({code:0,message:`Geolocation not supported.`}),this;var n=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this);return e.watch?this._locationWatchId=navigator.geolocation.watchPosition(n,i,e):navigator.geolocation.getCurrentPosition(n,i,e),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(e){if(this._container._leaflet_id){var n=e.code,r=e.message||(n===1?`permission denied`:n===2?`position unavailable`:`timeout`);this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire(`locationerror`,{code:n,message:`Geolocation error: `+r+`.`})}},_handleGeolocationResponse:function(e){if(this._container._leaflet_id){var n=e.coords.latitude,r=e.coords.longitude,i=new j(n,r),a=i.toBounds(e.coords.accuracy*2),o=this._locateOptions;if(o.setView){var s=this.getBoundsZoom(a);this.setView(i,o.maxZoom?Math.min(s,o.maxZoom):s)}var c={latlng:i,bounds:a,timestamp:e.timestamp};for(var l in e.coords)typeof e.coords[l]==`number`&&(c[l]=e.coords[l]);this.fire(`locationfound`,c)}},addHandler:function(e,n){if(!n)return this;var r=this[e]=new n(this);return this._handlers.push(r),this.options[e]&&r.enable(),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off(`moveend`,this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw Error(`Map container is being reused by another instance`);try{delete this._container._leaflet_id,delete this._containerId}catch{this._container._leaflet_id=void 0,this._containerId=void 0}for(var e in this._locationWatchId!==void 0&&this.stopLocate(),this._stop(),B(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&=(x(this._resizeRequest),null),this._clearHandlers(),this._loaded&&this.fire(`unload`),this._layers)this._layers[e].remove();for(e in this._panes)B(this._panes[e]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(e,n){var r=z(`div`,`leaflet-pane`+(e?` leaflet-`+e.replace(`Pane`,``)+`-pane`:``),n||this._mapPane);return e&&(this._panes[e]=r),r},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var e=this.getPixelBounds();return new k(this.unproject(e.getBottomLeft()),this.unproject(e.getTopRight()))},getMinZoom:function(){return this.options.minZoom===void 0?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return this.options.maxZoom===void 0?this._layersMaxZoom===void 0?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(e,n,r){e=A(e),r=E(r||[0,0]);var i=this.getZoom()||0,a=this.getMinZoom(),o=this.getMaxZoom(),s=e.getNorthWest(),c=e.getSouthEast(),l=this.getSize().subtract(r),u=O(this.project(c,i),this.project(s,i)).getSize(),d=R.any3d?this.options.zoomSnap:1,f=l.x/u.x,p=l.y/u.y,m=n?Math.max(f,p):Math.min(f,p);return i=this.getScaleZoom(m,i),d&&(i=Math.round(i/(d/100))*(d/100),i=n?Math.ceil(i/d)*d:Math.floor(i/d)*d),Math.max(a,Math.min(o,i))},getSize:function(){return(!this._size||this._sizeChanged)&&(this._size=new w(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(e,n){var r=this._getTopLeftPoint(e,n);return new D(r,r.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(e){return this.options.crs.getProjectedBounds(e===void 0?this.getZoom():e)},getPane:function(e){return typeof e==`string`?this._panes[e]:e},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(e,n){var r=this.options.crs;return n=n===void 0?this._zoom:n,r.scale(e)/r.scale(n)},getScaleZoom:function(e,n){var r=this.options.crs;n=n===void 0?this._zoom:n;var i=r.zoom(e*r.scale(n));return isNaN(i)?1/0:i},project:function(e,n){return n=n===void 0?this._zoom:n,this.options.crs.latLngToPoint(M(e),n)},unproject:function(e,n){return n=n===void 0?this._zoom:n,this.options.crs.pointToLatLng(E(e),n)},layerPointToLatLng:function(e){var n=E(e).add(this.getPixelOrigin());return this.unproject(n)},latLngToLayerPoint:function(e){return this.project(M(e))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(e){return this.options.crs.wrapLatLng(M(e))},wrapLatLngBounds:function(e){return this.options.crs.wrapLatLngBounds(A(e))},distance:function(e,n){return this.options.crs.distance(M(e),M(n))},containerPointToLayerPoint:function(e){return E(e).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(e){return E(e).add(this._getMapPanePos())},containerPointToLatLng:function(e){var n=this.containerPointToLayerPoint(E(e));return this.layerPointToLatLng(n)},latLngToContainerPoint:function(e){return this.layerPointToContainerPoint(this.latLngToLayerPoint(M(e)))},mouseEventToContainerPoint:function(e){return en(e,this._container)},mouseEventToLayerPoint:function(e){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e))},mouseEventToLatLng:function(e){return this.layerPointToLatLng(this.mouseEventToLayerPoint(e))},_initContainer:function(e){var n=this._container=St(e);if(!n)throw Error(`Map container not found.`);if(n._leaflet_id)throw Error(`Map container is already initialized.`);q(n,`scroll`,this._onScroll,this),this._containerId=s(n)},_initLayout:function(){var e=this._container;this._fadeAnimated=this.options.fadeAnimation&&R.any3d,V(e,`leaflet-container`+(R.touch?` leaflet-touch`:``)+(R.retina?` leaflet-retina`:``)+(R.ielt9?` leaflet-oldie`:``)+(R.safari?` leaflet-safari`:``)+(this._fadeAnimated?` leaflet-fade-anim`:``));var n=Ct(e,`position`);n!==`absolute`&&n!==`relative`&&n!==`fixed`&&n!==`sticky`&&(e.style.position=`relative`),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var e=this._panes={};this._paneRenderers={},this._mapPane=this.createPane(`mapPane`,this._container),W(this._mapPane,new w(0,0)),this.createPane(`tilePane`),this.createPane(`overlayPane`),this.createPane(`shadowPane`),this.createPane(`markerPane`),this.createPane(`tooltipPane`),this.createPane(`popupPane`),this.options.markerZoomAnimation||(V(e.markerPane,`leaflet-zoom-hide`),V(e.shadowPane,`leaflet-zoom-hide`))},_resetView:function(e,n,r){W(this._mapPane,new w(0,0));var i=!this._loaded;this._loaded=!0,n=this._limitZoom(n),this.fire(`viewprereset`);var a=this._zoom!==n;this._moveStart(a,r)._move(e,n)._moveEnd(a),this.fire(`viewreset`),i&&this.fire(`load`)},_moveStart:function(e,n){return e&&this.fire(`zoomstart`),n||this.fire(`movestart`),this},_move:function(e,n,r,i){n===void 0&&(n=this._zoom);var a=this._zoom!==n;return this._zoom=n,this._lastCenter=e,this._pixelOrigin=this._getNewPixelOrigin(e),i?r&&r.pinch&&this.fire(`zoom`,r):((a||r&&r.pinch)&&this.fire(`zoom`,r),this.fire(`move`,r)),this},_moveEnd:function(e){return e&&this.fire(`zoomend`),this.fire(`moveend`)},_stop:function(){return x(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(e){W(this._mapPane,this._getMapPanePos().subtract(e))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw Error(`Set map center and zoom first.`)},_initEvents:function(e){this._targets={},this._targets[s(this._container)]=this;var n=e?Y:q;n(this._container,`click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup`,this._handleDOMEvent,this),this.options.trackResize&&n(window,`resize`,this._onResize,this),R.any3d&&this.options.transform3DLimit&&(e?this.off:this.on).call(this,`moveend`,this._onMoveEnd)},_onResize:function(){x(this._resizeRequest),this._resizeRequest=b(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var e=this._getMapPanePos();Math.max(Math.abs(e.x),Math.abs(e.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(e,n){for(var r=[],i,a=n===`mouseout`||n===`mouseover`,o=e.target||e.srcElement,c=!1;o;){if(i=this._targets[s(o)],i&&(n===`click`||n===`preclick`)&&this._draggableMoved(i)){c=!0;break}if(i&&i.listens(n,!0)&&(a&&!rn(o,e)||(r.push(i),a))||o===this._container)break;o=o.parentNode}return!r.length&&!c&&!a&&this.listens(n,!0)&&(r=[this]),r},_isClickDisabled:function(e){for(;e&&e!==this._container;){if(e._leaflet_disable_click)return!0;e=e.parentNode}},_handleDOMEvent:function(e){var n=e.target||e.srcElement;if(!(!this._loaded||n._leaflet_disable_events||e.type===`click`&&this._isClickDisabled(n))){var r=e.type;r===`mousedown`&&K(n),this._fireDOMEvent(e,r)}},_mouseEvents:[`click`,`dblclick`,`mouseover`,`mouseout`,`contextmenu`],_fireDOMEvent:function(e,n,i){if(e.type===`click`){var a=r({},e);a.type=`preclick`,this._fireDOMEvent(a,a.type,i)}var o=this._findEventTargets(e,n);if(i){for(var s=[],c=0;c0?Math.round(e-n)/2:Math.max(0,Math.ceil(e))-Math.max(0,Math.floor(n))},_limitZoom:function(e){var n=this.getMinZoom(),r=this.getMaxZoom(),i=R.any3d?this.options.zoomSnap:1;return i&&(e=Math.round(e/i)*i),Math.max(n,Math.min(r,e))},_onPanTransitionStep:function(){this.fire(`move`)},_onPanTransitionEnd:function(){H(this._mapPane,`leaflet-pan-anim`),this.fire(`moveend`)},_tryAnimatedPan:function(e,n){var r=this._getCenterOffset(e)._trunc();return(n&&n.animate)!==!0&&!this.getSize().contains(r)?!1:(this.panBy(r,n),!0)},_createAnimProxy:function(){var e=this._proxy=z(`div`,`leaflet-proxy leaflet-zoom-animated`);this._panes.mapPane.appendChild(e),this.on(`zoomanim`,function(e){var n=yt,r=this._proxy.style[n];Mt(this._proxy,this.project(e.center,e.zoom),this.getZoomScale(e.zoom,1)),r===this._proxy.style[n]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on(`load moveend`,this._animMoveEnd,this),this._on(`unload`,this._destroyAnimProxy,this)},_destroyAnimProxy:function(){B(this._proxy),this.off(`load moveend`,this._animMoveEnd,this),delete this._proxy},_animMoveEnd:function(){var e=this.getCenter(),n=this.getZoom();Mt(this._proxy,this.project(e,n),this.getZoomScale(n,1))},_catchTransitionEnd:function(e){this._animatingZoom&&e.propertyName.indexOf(`transform`)>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName(`leaflet-zoom-animated`).length},_tryAnimatedZoom:function(e,n,r){if(this._animatingZoom)return!0;if(r||={},!this._zoomAnimated||r.animate===!1||this._nothingToAnimate()||Math.abs(n-this._zoom)>this.options.zoomAnimationThreshold)return!1;var i=this.getZoomScale(n),a=this._getCenterOffset(e)._divideBy(1-1/i);return r.animate!==!0&&!this.getSize().contains(a)?!1:(b(function(){this._moveStart(!0,r.noMoveStart||!1)._animateZoom(e,n,!0)},this),!0)},_animateZoom:function(e,n,r,i){this._mapPane&&(r&&(this._animatingZoom=!0,this._animateToCenter=e,this._animateToZoom=n,V(this._mapPane,`leaflet-zoom-anim`)),this.fire(`zoomanim`,{center:e,zoom:n,noUpdate:i}),this._tempFireZoomEvent||=this._zoom!==this._animateToZoom,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&H(this._mapPane,`leaflet-zoom-anim`),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire(`zoom`),delete this._tempFireZoomEvent,this.fire(`move`),this._moveEnd(!0))}});function sn(e,n){return new Z(e,n)}var Q=S.extend({options:{position:`topright`},initialize:function(e){m(this,e)},getPosition:function(){return this.options.position},setPosition:function(e){var n=this._map;return n&&n.removeControl(this),this.options.position=e,n&&n.addControl(this),this},getContainer:function(){return this._container},addTo:function(e){this.remove(),this._map=e;var n=this._container=this.onAdd(e),r=this.getPosition(),i=e._controlCorners[r];return V(n,`leaflet-control`),r.indexOf(`bottom`)===-1?i.appendChild(n):i.insertBefore(n,i.firstChild),this._map.on(`unload`,this.remove,this),this},remove:function(){return this._map?(B(this._container),this.onRemove&&this.onRemove(this._map),this._map.off(`unload`,this.remove,this),this._map=null,this):this},_refocusOnMap:function(e){this._map&&e&&e.screenX>0&&e.screenY>0&&this._map.getContainer().focus()}}),cn=function(e){return new Q(e)};Z.include({addControl:function(e){return e.addTo(this),this},removeControl:function(e){return e.remove(),this},_initControlPos:function(){var e=this._controlCorners={},n=`leaflet-`,r=this._controlContainer=z(`div`,n+`control-container`,this._container);function i(i,a){var o=n+i+` `+n+a;e[i+a]=z(`div`,o,r)}i(`top`,`left`),i(`top`,`right`),i(`bottom`,`left`),i(`bottom`,`right`)},_clearControlPos:function(){for(var e in this._controlCorners)B(this._controlCorners[e]);B(this._controlContainer),delete this._controlCorners,delete this._controlContainer}});var ln=Q.extend({options:{collapsed:!0,position:`topright`,autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(e,n,r,i){return r1,this._baseLayersList.style.display=e?``:`none`),this._separator.style.display=n&&e?``:`none`,this},_onLayerChange:function(e){this._handlingClick||this._update();var n=this._getLayer(s(e.target)),r=n.overlay?e.type===`add`?`overlayadd`:`overlayremove`:e.type===`add`?`baselayerchange`:null;r&&this._map.fire(r,n)},_createRadioElement:function(e,n){var r=``,i=document.createElement(`div`);return i.innerHTML=r,i.firstChild},_addItem:function(e){var n=document.createElement(`label`),r=this._map.hasLayer(e.layer),i;e.overlay?(i=document.createElement(`input`),i.type=`checkbox`,i.className=`leaflet-control-layers-selector`,i.defaultChecked=r):i=this._createRadioElement(`leaflet-base-layers_`+s(this),r),this._layerControlInputs.push(i),i.layerId=s(e.layer),q(i,`click`,this._onInputClick,this);var a=document.createElement(`span`);a.innerHTML=` `+e.name;var o=document.createElement(`span`);return n.appendChild(o),o.appendChild(i),o.appendChild(a),(e.overlay?this._overlaysList:this._baseLayersList).appendChild(n),this._checkDisabledLayers(),n},_onInputClick:function(){if(!this._preventClick){var e=this._layerControlInputs,n,r,i=[],a=[];this._handlingClick=!0;for(var o=e.length-1;o>=0;o--)n=e[o],r=this._getLayer(n.layerId).layer,n.checked?i.push(r):n.checked||a.push(r);for(o=0;o=0;a--)n=e[a],r=this._getLayer(n.layerId).layer,n.disabled=r.options.minZoom!==void 0&&ir.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var e=this._section;this._preventClick=!0,q(e,`click`,X),this.expand();var n=this;setTimeout(function(){Y(e,`click`,X),n._preventClick=!1})}}),un=function(e,n,r){return new ln(e,n,r)},dn=Q.extend({options:{position:`topleft`,zoomInText:``,zoomInTitle:`Zoom in`,zoomOutText:``,zoomOutTitle:`Zoom out`},onAdd:function(e){var n=`leaflet-control-zoom`,r=z(`div`,n+` leaflet-bar`),i=this.options;return this._zoomInButton=this._createButton(i.zoomInText,i.zoomInTitle,n+`-in`,r,this._zoomIn),this._zoomOutButton=this._createButton(i.zoomOutText,i.zoomOutTitle,n+`-out`,r,this._zoomOut),this._updateDisabled(),e.on(`zoomend zoomlevelschange`,this._updateDisabled,this),r},onRemove:function(e){e.off(`zoomend zoomlevelschange`,this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(e){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(e.shiftKey?3:1))},_createButton:function(e,n,r,i,a){var o=z(`a`,r,i);return o.innerHTML=e,o.href=`#`,o.title=n,o.setAttribute(`role`,`button`),o.setAttribute(`aria-label`,n),Zt(o),q(o,`click`,Qt),q(o,`click`,a,this),q(o,`click`,this._refocusOnMap,this),o},_updateDisabled:function(){var e=this._map,n=`leaflet-disabled`;H(this._zoomInButton,n),H(this._zoomOutButton,n),this._zoomInButton.setAttribute(`aria-disabled`,`false`),this._zoomOutButton.setAttribute(`aria-disabled`,`false`),(this._disabled||e._zoom===e.getMinZoom())&&(V(this._zoomOutButton,n),this._zoomOutButton.setAttribute(`aria-disabled`,`true`)),(this._disabled||e._zoom===e.getMaxZoom())&&(V(this._zoomInButton,n),this._zoomInButton.setAttribute(`aria-disabled`,`true`))}});Z.mergeOptions({zoomControl:!0}),Z.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new dn,this.addControl(this.zoomControl))});var fn=function(e){return new dn(e)},pn=Q.extend({options:{position:`bottomleft`,maxWidth:100,metric:!0,imperial:!0},onAdd:function(e){var n=`leaflet-control-scale`,r=z(`div`,n),i=this.options;return this._addScales(i,n+`-line`,r),e.on(i.updateWhenIdle?`moveend`:`move`,this._update,this),e.whenReady(this._update,this),r},onRemove:function(e){e.off(this.options.updateWhenIdle?`moveend`:`move`,this._update,this)},_addScales:function(e,n,r){e.metric&&(this._mScale=z(`div`,n,r)),e.imperial&&(this._iScale=z(`div`,n,r))},_update:function(){var e=this._map,n=e.getSize().y/2,r=e.distance(e.containerPointToLatLng([0,n]),e.containerPointToLatLng([this.options.maxWidth,n]));this._updateScales(r)},_updateScales:function(e){this.options.metric&&e&&this._updateMetric(e),this.options.imperial&&e&&this._updateImperial(e)},_updateMetric:function(e){var n=this._getRoundNum(e),r=n<1e3?n+` m`:n/1e3+` km`;this._updateScale(this._mScale,r,n/e)},_updateImperial:function(e){var n=e*3.2808399,r,i,a;n>5280?(r=n/5280,i=this._getRoundNum(r),this._updateScale(this._iScale,i+` mi`,i/r)):(a=this._getRoundNum(n),this._updateScale(this._iScale,a+` ft`,a/n))},_updateScale:function(e,n,r){e.style.width=Math.round(this.options.maxWidth*r)+`px`,e.innerHTML=n},_getRoundNum:function(e){var n=10**((Math.floor(e)+``).length-1),r=e/n;return r=r>=10?10:r>=5?5:r>=3?3:r>=2?2:1,n*r}}),mn=function(e){return new pn(e)},hn=Q.extend({options:{position:`bottomright`,prefix:``+(R.inlineSvg?` `:``)+`Leaflet`},initialize:function(e){m(this,e),this._attributions={}},onAdd:function(e){for(var n in e.attributionControl=this,this._container=z(`div`,`leaflet-control-attribution`),Zt(this._container),e._layers)e._layers[n].getAttribution&&this.addAttribution(e._layers[n].getAttribution());return this._update(),e.on(`layeradd`,this._addAttribution,this),this._container},onRemove:function(e){e.off(`layeradd`,this._addAttribution,this)},_addAttribution:function(e){e.layer.getAttribution&&(this.addAttribution(e.layer.getAttribution()),e.layer.once(`remove`,function(){this.removeAttribution(e.layer.getAttribution())},this))},setPrefix:function(e){return this.options.prefix=e,this._update(),this},addAttribution:function(e){return e?(this._attributions[e]||(this._attributions[e]=0),this._attributions[e]++,this._update(),this):this},removeAttribution:function(e){return e&&this._attributions[e]&&(this._attributions[e]--,this._update()),this},_update:function(){if(this._map){var e=[];for(var n in this._attributions)this._attributions[n]&&e.push(n);var r=[];this.options.prefix&&r.push(this.options.prefix),e.length&&r.push(e.join(`, `)),this._container.innerHTML=r.join(` `)}}});Z.mergeOptions({attributionControl:!0}),Z.addInitHook(function(){this.options.attributionControl&&new hn().addTo(this)}),Q.Layers=ln,Q.Zoom=dn,Q.Scale=pn,Q.Attribution=hn,cn.layers=un,cn.zoom=fn,cn.scale=mn,cn.attribution=function(e){return new hn(e)};var gn=S.extend({initialize:function(e){this._map=e},enable:function(){return this._enabled?this:(this._enabled=!0,this.addHooks(),this)},disable:function(){return this._enabled?(this._enabled=!1,this.removeHooks(),this):this},enabled:function(){return!!this._enabled}});gn.addTo=function(e,n){return e.addHandler(n,this),this};var _n={Events:C},vn=R.touch?`touchstart mousedown`:`mousedown`,yn=ce.extend({options:{clickTolerance:3},initialize:function(e,n,r,i){m(this,i),this._element=e,this._dragStartTarget=n||e,this._preventOutline=r},enable:function(){this._enabled||=(q(this._dragStartTarget,vn,this._onDown,this),!0)},disable:function(){this._enabled&&(yn._dragging===this&&this.finishDrag(!0),Y(this._dragStartTarget,vn,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(e){if(this._enabled&&(this._moved=!1,!Dt(this._element,`leaflet-zoom-anim`))){if(e.touches&&e.touches.length!==1){yn._dragging===this&&this.finishDrag();return}if(!(yn._dragging||e.shiftKey||e.which!==1&&e.button!==1&&!e.touches)&&(yn._dragging=this,this._preventOutline&&K(this._element),Lt(),G(),!this._moving)){this.fire(`down`);var n=e.touches?e.touches[0]:e,r=Ht(this._element);this._startPoint=new w(n.clientX,n.clientY),this._startPos=Nt(this._element),this._parentScale=Ut(r);var i=e.type===`mousedown`;q(document,i?`mousemove`:`touchmove`,this._onMove,this),q(document,i?`mouseup`:`touchend touchcancel`,this._onUp,this)}}},_onMove:function(e){if(this._enabled){if(e.touches&&e.touches.length>1){this._moved=!0;return}var n=e.touches&&e.touches.length===1?e.touches[0]:e,r=new w(n.clientX,n.clientY)._subtract(this._startPoint);!r.x&&!r.y||Math.abs(r.x)+Math.abs(r.y)o&&(s=c,o=l);o>r&&(n[s]=1,On(e,n,r,i,s),On(e,n,r,s,a))}function kn(e,n){for(var r=[e[0]],i=1,a=0,o=e.length;in&&(r.push(e[i]),a=i);return an.max.x&&(r|=2),e.yn.max.y&&(r|=8),r}function Pn(e,n){var r=n.x-e.x,i=n.y-e.y;return r*r+i*i}function Fn(e,n,r,i){var a=n.x,o=n.y,s=r.x-a,c=r.y-o,l=s*s+c*c,u;return l>0&&(u=((e.x-a)*s+(e.y-o)*c)/l,u>1?(a=r.x,o=r.y):u>0&&(a+=s*u,o+=c*u)),s=e.x-a,c=e.y-o,i?s*s+c*c:new w(a,o)}function $(e){return!v(e[0])||typeof e[0][0]!=`object`&&e[0][0]!==void 0}function In(e){return console.warn(`Deprecated use of _flat, please use L.LineUtil.isFlat instead.`),$(e)}function Ln(e,n){var r,i,a,o,s,c,l,u;if(!e||e.length===0)throw Error(`latlngs not passed`);$(e)||(console.warn(`latlngs are not flat! Only the first ring will be used`),e=e[0]);var d=M([0,0]),f=A(e);f.getNorthWest().distanceTo(f.getSouthWest())*f.getNorthEast().distanceTo(f.getNorthWest())<1700&&(d=Sn(e));var p=e.length,m=[];for(r=0;ri){l=(o-i)/a,u=[c.x-l*(c.x-s.x),c.y-l*(c.y-s.y)];break}var g=n.unproject(E(u));return M([g.lat+d.lat,g.lng+d.lng])}var Rn={__proto__:null,simplify:wn,pointToSegmentDistance:Tn,closestPointOnSegment:En,clipSegment:jn,_getEdgeIntersection:Mn,_getBitCode:Nn,_sqClosestPointOnSegment:Fn,isFlat:$,_flat:In,polylineCenter:Ln},zn={project:function(e){return new w(e.lng,e.lat)},unproject:function(e){return new j(e.y,e.x)},bounds:new D([-180,-90],[180,90])},Bn={R:6378137,R_MINOR:6356752.314245179,bounds:new D([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project:function(e){var n=Math.PI/180,r=this.R,i=e.lat*n,a=this.R_MINOR/r,o=Math.sqrt(1-a*a),s=o*Math.sin(i),c=Math.tan(Math.PI/4-i/2)/((1-s)/(1+s))**(o/2);return i=-r*Math.log(Math.max(c,1e-10)),new w(e.lng*n*r,i)},unproject:function(e){for(var n=180/Math.PI,r=this.R,i=this.R_MINOR/r,a=Math.sqrt(1-i*i),o=Math.exp(-e.y/r),s=Math.PI/2-2*Math.atan(o),c=0,l=.1,u;c<15&&Math.abs(l)>1e-7;c++)u=a*Math.sin(s),u=((1-u)/(1+u))**(a/2),l=Math.PI/2-2*Math.atan(o*u)-s,s+=l;return new j(s*n,e.x*n/r)}},Vn={__proto__:null,LonLat:zn,Mercator:Bn,SphericalMercator:de},Hn=r({},le,{code:`EPSG:3395`,projection:Bn,transformation:function(){var e=.5/(Math.PI*Bn.R);return pe(e,.5,-e,.5)}()}),Un=r({},le,{code:`EPSG:4326`,projection:zn,transformation:pe(1/180,1,-1/180,.5)}),Wn=r({},N,{projection:zn,transformation:pe(1,0,-1,0),scale:function(e){return 2**e},zoom:function(e){return Math.log(e)/Math.LN2},distance:function(e,n){var r=n.lng-e.lng,i=n.lat-e.lat;return Math.sqrt(r*r+i*i)},infinite:!0});N.Earth=le,N.EPSG3395=Hn,N.EPSG3857=me,N.EPSG900913=he,N.EPSG4326=Un,N.Simple=Wn;var Gn=ce.extend({options:{pane:`overlayPane`,attribution:null,bubblingMouseEvents:!0},addTo:function(e){return e.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(e){return e&&e.removeLayer(this),this},getPane:function(e){return this._map.getPane(e?this.options[e]||e:this.options.pane)},addInteractiveTarget:function(e){return this._map._targets[s(e)]=this,this},removeInteractiveTarget:function(e){return delete this._map._targets[s(e)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(e){var n=e.target;if(n.hasLayer(this)){if(this._map=n,this._zoomAnimated=n._zoomAnimated,this.getEvents){var r=this.getEvents();n.on(r,this),this.once(`remove`,function(){n.off(r,this)},this)}this.onAdd(n),this.fire(`add`),n.fire(`layeradd`,{layer:this})}}});Z.include({addLayer:function(e){if(!e._layerAdd)throw Error(`The provided object is not a Layer.`);var n=s(e);return this._layers[n]?this:(this._layers[n]=e,e._mapToAdd=this,e.beforeAdd&&e.beforeAdd(this),this.whenReady(e._layerAdd,e),this)},removeLayer:function(e){var n=s(e);return this._layers[n]?(this._loaded&&e.onRemove(this),delete this._layers[n],this._loaded&&(this.fire(`layerremove`,{layer:e}),e.fire(`remove`)),e._map=e._mapToAdd=null,this):this},hasLayer:function(e){return s(e)in this._layers},eachLayer:function(e,n){for(var r in this._layers)e.call(n,this._layers[r]);return this},_addLayers:function(e){e=e?v(e)?e:[e]:[];for(var n=0,r=e.length;nthis._layersMaxZoom&&this.setZoom(this._layersMaxZoom),this.options.minZoom===void 0&&this._layersMinZoom&&this.getZoom()=2&&n[0]instanceof j&&n[0].equals(n[r-1])&&n.pop(),n},_setLatLngs:function(e){sr.prototype._setLatLngs.call(this,e),$(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return $(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var e=this._renderer._bounds,n=this.options.weight,r=new w(n,n);if(e=new D(e.min.subtract(r),e.max.add(r)),this._parts=[],!(!this._pxBounds||!this._pxBounds.intersects(e))){if(this.options.noClip){this._parts=this._rings;return}for(var i=0,a=this._rings.length,o;ie.y!=a.y>e.y&&e.x<(a.x-i.x)*(e.y-i.y)/(a.y-i.y)+i.x&&(n=!n);return n||sr.prototype._containsPoint.call(this,e,!0)}});function ur(e,n){return new lr(e,n)}var dr=Jn.extend({initialize:function(e,n){m(this,n),this._layers={},e&&this.addData(e)},addData:function(e){var n=v(e)?e:e.features,r,i,a;if(n){for(r=0,i=n.length;r0&&a.push(a[0].slice()),a}function vr(e,n){return e.feature?r({},e.feature,{geometry:n}):yr(n)}function yr(e){return e.type===`Feature`||e.type===`FeatureCollection`?e:{type:`Feature`,properties:{},geometry:e}}var br={toGeoJSON:function(e){return vr(this,{type:`Point`,coordinates:gr(this.getLatLng(),e)})}};er.include(br),ar.include(br),rr.include(br),sr.include({toGeoJSON:function(e){var n=!$(this._latlngs),r=_r(this._latlngs,+!!n,!1,e);return vr(this,{type:(n?`Multi`:``)+`LineString`,coordinates:r})}}),lr.include({toGeoJSON:function(e){var n=!$(this._latlngs),r=n&&!$(this._latlngs[0]),i=_r(this._latlngs,r?2:+!!n,!0,e);return n||(i=[i]),vr(this,{type:(r?`Multi`:``)+`Polygon`,coordinates:i})}}),Kn.include({toMultiPoint:function(e){var n=[];return this.eachLayer(function(r){n.push(r.toGeoJSON(e).geometry.coordinates)}),vr(this,{type:`MultiPoint`,coordinates:n})},toGeoJSON:function(e){var n=this.feature&&this.feature.geometry&&this.feature.geometry.type;if(n===`MultiPoint`)return this.toMultiPoint(e);var r=n===`GeometryCollection`,i=[];return this.eachLayer(function(n){if(n.toGeoJSON){var a=n.toGeoJSON(e);if(r)i.push(a.geometry);else{var o=yr(a);o.type===`FeatureCollection`?i.push.apply(i,o.features):i.push(o)}}}),r?vr(this,{geometries:i,type:`GeometryCollection`}):{type:`FeatureCollection`,features:i}}});function xr(e,n){return new dr(e,n)}var Sr=xr,Cr=Gn.extend({options:{opacity:1,alt:``,interactive:!1,crossOrigin:!1,errorOverlayUrl:``,zIndex:1,className:``},initialize:function(e,n,r){this._url=e,this._bounds=A(n),m(this,r)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(V(this._image,`leaflet-interactive`),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){B(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(e){return this.options.opacity=e,this._image&&this._updateOpacity(),this},setStyle:function(e){return e.opacity&&this.setOpacity(e.opacity),this},bringToFront:function(){return this._map&&Tt(this._image),this},bringToBack:function(){return this._map&&Et(this._image),this},setUrl:function(e){return this._url=e,this._image&&(this._image.src=e),this},setBounds:function(e){return this._bounds=A(e),this._map&&this._reset(),this},getEvents:function(){var e={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(e.zoomanim=this._animateZoom),e},setZIndex:function(e){return this.options.zIndex=e,this._updateZIndex(),this},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var e=this._url.tagName===`IMG`,n=this._image=e?this._url:z(`img`);if(V(n,`leaflet-image-layer`),this._zoomAnimated&&V(n,`leaflet-zoom-animated`),this.options.className&&V(n,this.options.className),n.onselectstart=u,n.onmousemove=u,n.onload=a(this.fire,this,`load`),n.onerror=a(this._overlayOnError,this,`error`),(this.options.crossOrigin||this.options.crossOrigin===``)&&(n.crossOrigin=this.options.crossOrigin===!0?``:this.options.crossOrigin),this.options.zIndex&&this._updateZIndex(),e){this._url=n.src;return}n.src=this._url,n.alt=this.options.alt},_animateZoom:function(e){var n=this._map.getZoomScale(e.zoom),r=this._map._latLngBoundsToNewLayerBounds(this._bounds,e.zoom,e.center).min;Mt(this._image,r,n)},_reset:function(){var e=this._image,n=new D(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),r=n.getSize();W(e,n.min),e.style.width=r.x+`px`,e.style.height=r.y+`px`},_updateOpacity:function(){U(this._image,this.options.opacity)},_updateZIndex:function(){this._image&&this.options.zIndex!==void 0&&this.options.zIndex!==null&&(this._image.style.zIndex=this.options.zIndex)},_overlayOnError:function(){this.fire(`error`);var e=this.options.errorOverlayUrl;e&&this._url!==e&&(this._url=e,this._image.src=e)},getCenter:function(){return this._bounds.getCenter()}}),wr=function(e,n,r){return new Cr(e,n,r)},Tr=Cr.extend({options:{autoplay:!0,loop:!0,keepAspectRatio:!0,muted:!1,playsInline:!0},_initImage:function(){var e=this._url.tagName===`VIDEO`,n=this._image=e?this._url:z(`video`);if(V(n,`leaflet-image-layer`),this._zoomAnimated&&V(n,`leaflet-zoom-animated`),this.options.className&&V(n,this.options.className),n.onselectstart=u,n.onmousemove=u,n.onloadeddata=a(this.fire,this,`load`),e){for(var r=n.getElementsByTagName(`source`),i=[],o=0;o0?i:[n.src];return}v(this._url)||(this._url=[this._url]),!this.options.keepAspectRatio&&Object.prototype.hasOwnProperty.call(n.style,`objectFit`)&&(n.style.objectFit=`fill`),n.autoplay=!!this.options.autoplay,n.loop=!!this.options.loop,n.muted=!!this.options.muted,n.playsInline=!!this.options.playsInline;for(var s=0;s