From 53bf1f436b1fc642bb00a2b08079c562a3798e94 Mon Sep 17 00:00:00 2001 From: Gani Georgiev Date: Sun, 15 Dec 2024 17:34:08 +0200 Subject: [PATCH] added pb.realtime.onDisconnect hook --- CHANGELOG.md | 6 ++++++ README.md | 12 ++++++++++++ dist/pocketbase.cjs.d.ts | 13 +++++++++++++ dist/pocketbase.cjs.js | 2 +- dist/pocketbase.cjs.js.map | 2 +- dist/pocketbase.es.d.mts | 13 +++++++++++++ dist/pocketbase.es.d.ts | 13 +++++++++++++ dist/pocketbase.es.js | 2 +- dist/pocketbase.es.js.map | 2 +- dist/pocketbase.es.mjs | 2 +- dist/pocketbase.es.mjs.map | 2 +- dist/pocketbase.iife.d.ts | 13 +++++++++++++ dist/pocketbase.iife.js | 2 +- dist/pocketbase.iife.js.map | 2 +- dist/pocketbase.umd.d.ts | 13 +++++++++++++ dist/pocketbase.umd.js | 2 +- dist/pocketbase.umd.js.map | 2 +- package.json | 2 +- src/services/RealtimeService.ts | 18 ++++++++++++++++++ 19 files changed, 112 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16fa5df..428c76d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.23.0 + +- Added optional `pb.realtime.onDisconnect` hook function. + _Note that the realtime client autoreconnect on its own and this hook is useful only for the cases where you want to apply a special behavior on server error or after closing the realtime connection._ + + ## 0.22.1 - Fixed old `pb.authStore.isAdmin`/`pb.authStore.isAuthRecord` and marked them as deprecated in favour of `pb.authStore.isSuperuser` ([#323](https://github.com/pocketbase/js-sdk/issues/323)). diff --git a/README.md b/README.md index 1c74c62..40baba3 100644 --- a/README.md +++ b/README.md @@ -1015,6 +1015,18 @@ const result = await batch.send() // Unsubscribe from all subscriptions matching the specified topic and listener function. 🔓 pb.realtime.unsubscribeByTopicAndListener(topic, callback); + +// Getter that checks whether the realtime connection has been established. +pb.realtime.isConnected + +// An optional hook that is invoked when the realtime client disconnects +// either when unsubscribing from all subscriptions or when the connection +// was interrupted or closed by the server. +// +// Note that the realtime client autoreconnect on its own and this hook is +// useful only for the cases where you want to apply a special behavior on +// server error or after closing the realtime connection. +pb.realtime.onDisconnect = function(activeSubscriptions) ``` --- diff --git a/dist/pocketbase.cjs.d.ts b/dist/pocketbase.cjs.d.ts index 7fa0289..ad41c2d 100644 --- a/dist/pocketbase.cjs.d.ts +++ b/dist/pocketbase.cjs.d.ts @@ -382,6 +382,19 @@ declare class RealtimeService extends BaseService { * Returns whether the realtime connection has been established. */ get isConnected(): boolean; + /** + * An optional hook that is invoked when the realtime client disconnects + * either when unsubscribing from all subscriptions or when the + * connection was interrupted or closed by the server. + * + * The received argument could be used to determine whether the disconnect + * is a result from unsubscribing (`activeSubscriptions.length == 0`) + * or because of network/server error (`activeSubscriptions.length > 0`). + * + * If you want to listen for the opposite, aka. when the client connection is established, + * subscribe to the `PB_CONNECT` event. + */ + onDisconnect?: (activeSubscriptions: Array) => void; /** * Register the subscription listener. * diff --git a/dist/pocketbase.cjs.js b/dist/pocketbase.cjs.js index 257a415..542348d 100644 --- a/dist/pocketbase.cjs.js +++ b/dist/pocketbase.cjs.js @@ -1,2 +1,2 @@ -"use strict";class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),r=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const o=r(s);if(o&&!e.test(o))throw new TypeError("argument val is invalid");let a=t+"="+o;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},{}).decode||defaultDecode;let n=0;for(;n4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}module.exports=Client; +"use strict";class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),r=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const o=r(s);if(o&&!e.test(o))throw new TypeError("argument val is invalid");let a=t+"="+o;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},{}).decode||defaultDecode;let n=0;for(;n4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(this.clientId&&this.onDisconnect&&this.onDisconnect(Object.keys(this.subscriptions)),clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}module.exports=Client; //# sourceMappingURL=pocketbase.cjs.js.map diff --git a/dist/pocketbase.cjs.js.map b/dist/pocketbase.cjs.js.map index b47b995..a3a241d 100644 --- a/dist/pocketbase.cjs.js.map +++ b/dist/pocketbase.cjs.js.map @@ -1 +1 @@ -{"version":3,"file":"pocketbase.cjs.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieSerialize","val","options","opt","assign","encode","defaultEncode","test","TypeError","value","result","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","defaultDecode","indexOf","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","charCodeAt","slice","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","length","exp","now","atob","input","str","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","key","rawData","cookieParse","decode","index","eqIdx","endIdx","lastIndexOf","trim","undefined","_","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pocketbase.cjs.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * An optional hook that is invoked when the realtime client disconnects\n * either when unsubscribing from all subscriptions or when the\n * connection was interrupted or closed by the server.\n *\n * The received argument could be used to determine whether the disconnect\n * is a result from unsubscribing (`activeSubscriptions.length == 0`)\n * or because of network/server error (`activeSubscriptions.length > 0`).\n *\n * If you want to listen for the opposite, aka. when the client connection is established,\n * subscribe to the `PB_CONNECT` event.\n */\n onDisconnect?: (activeSubscriptions: Array) => void;\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n if (this.clientId && this.onDisconnect) {\n this.onDisconnect(Object.keys(this.subscriptions));\n }\n\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieSerialize","val","options","opt","assign","encode","defaultEncode","test","TypeError","value","result","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","defaultDecode","indexOf","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","charCodeAt","slice","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","length","exp","now","atob","input","str","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","key","rawData","cookieParse","decode","index","eqIdx","endIdx","lastIndexOf","trim","undefined","_","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","onDisconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController"],"mappings":"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"} \ No newline at end of file diff --git a/dist/pocketbase.es.d.mts b/dist/pocketbase.es.d.mts index e77aed4..0d73ea4 100644 --- a/dist/pocketbase.es.d.mts +++ b/dist/pocketbase.es.d.mts @@ -425,6 +425,19 @@ declare class RealtimeService extends BaseService { * Returns whether the realtime connection has been established. */ get isConnected(): boolean; + /** + * An optional hook that is invoked when the realtime client disconnects + * either when unsubscribing from all subscriptions or when the + * connection was interrupted or closed by the server. + * + * The received argument could be used to determine whether the disconnect + * is a result from unsubscribing (`activeSubscriptions.length == 0`) + * or because of network/server error (`activeSubscriptions.length > 0`). + * + * If you want to listen for the opposite, aka. when the client connection is established, + * subscribe to the `PB_CONNECT` event. + */ + onDisconnect?: (activeSubscriptions: Array) => void; /** * Register the subscription listener. * diff --git a/dist/pocketbase.es.d.ts b/dist/pocketbase.es.d.ts index e77aed4..0d73ea4 100644 --- a/dist/pocketbase.es.d.ts +++ b/dist/pocketbase.es.d.ts @@ -425,6 +425,19 @@ declare class RealtimeService extends BaseService { * Returns whether the realtime connection has been established. */ get isConnected(): boolean; + /** + * An optional hook that is invoked when the realtime client disconnects + * either when unsubscribing from all subscriptions or when the + * connection was interrupted or closed by the server. + * + * The received argument could be used to determine whether the disconnect + * is a result from unsubscribing (`activeSubscriptions.length == 0`) + * or because of network/server error (`activeSubscriptions.length > 0`). + * + * If you want to listen for the opposite, aka. when the client connection is established, + * subscribe to the `PB_CONNECT` event. + */ + onDisconnect?: (activeSubscriptions: Array) => void; /** * Register the subscription listener. * diff --git a/dist/pocketbase.es.js b/dist/pocketbase.es.js index ed6d465..36d74cf 100644 --- a/dist/pocketbase.es.js +++ b/dist/pocketbase.es.js @@ -1,2 +1,2 @@ -class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},t||{}).decode||defaultDecode;let n=0;for(;n0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=cookieParse(e||"")[t]||"";let n={};try{n=JSON.parse(s),(null===typeof n||"object"!=typeof n||Array.isArray(n))&&(n={})}catch(e){}this.save(n.token||"",n.record||n.model||null)}exportToCookie(e,t=i){const s={secure:!0,sameSite:!0,httpOnly:!0,path:"/"},n=getTokenPayload(this.token);s.expires=n?.exp?new Date(1e3*n.exp):new Date("1970-01-01"),e=Object.assign({},s,e);const r={token:this.token,record:this.record?JSON.parse(JSON.stringify(this.record)):null};let o=cookieSerialize(t,JSON.stringify(r),e);const a="undefined"!=typeof Blob?new Blob([o]).size:o.length;if(r.record&&a>4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}class AsyncAuthStore extends BaseAuthStore{constructor(e){super(),this.queue=[],this.saveFunc=e.save,this.clearFunc=e.clear,this._enqueue((()=>this._loadInitial(e.initial)))}save(e,t){super.save(e,t);let s="";try{s=JSON.stringify({token:e,record:t})}catch(e){console.warn("AsyncAuthStore: failed to stringify the new state")}this._enqueue((()=>this.saveFunc(s)))}clear(){super.clear(),this.clearFunc?this._enqueue((()=>this.clearFunc())):this._enqueue((()=>this.saveFunc("")))}async _loadInitial(e){try{if(e=await e){let t;"string"==typeof e?t=JSON.parse(e)||{}:"object"==typeof e&&(t=e),this.save(t.token||"",t.record||t.model||null)}}catch(e){}}_enqueue(e){this.queue.push(e),1==this.queue.length&&this._dequeue()}_dequeue(){this.queue.length&&this.queue[0]().finally((()=>{this.queue.shift(),this.queue.length&&this._dequeue()}))}}export{AsyncAuthStore,BaseAuthStore,BatchService,ClientResponseError,CollectionService,CrudService,HealthService,LocalAuthStore,LogService,RealtimeService,RecordService,SubBatchService,cookieParse,cookieSerialize,Client as default,getTokenPayload,isTokenExpired,normalizeUnknownQueryParams,serializeQueryParams}; +class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},t||{}).decode||defaultDecode;let n=0;for(;n0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=cookieParse(e||"")[t]||"";let n={};try{n=JSON.parse(s),(null===typeof n||"object"!=typeof n||Array.isArray(n))&&(n={})}catch(e){}this.save(n.token||"",n.record||n.model||null)}exportToCookie(e,t=i){const s={secure:!0,sameSite:!0,httpOnly:!0,path:"/"},n=getTokenPayload(this.token);s.expires=n?.exp?new Date(1e3*n.exp):new Date("1970-01-01"),e=Object.assign({},s,e);const r={token:this.token,record:this.record?JSON.parse(JSON.stringify(this.record)):null};let o=cookieSerialize(t,JSON.stringify(r),e);const a="undefined"!=typeof Blob?new Blob([o]).size:o.length;if(r.record&&a>4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(this.clientId&&this.onDisconnect&&this.onDisconnect(Object.keys(this.subscriptions)),clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}class AsyncAuthStore extends BaseAuthStore{constructor(e){super(),this.queue=[],this.saveFunc=e.save,this.clearFunc=e.clear,this._enqueue((()=>this._loadInitial(e.initial)))}save(e,t){super.save(e,t);let s="";try{s=JSON.stringify({token:e,record:t})}catch(e){console.warn("AsyncAuthStore: failed to stringify the new state")}this._enqueue((()=>this.saveFunc(s)))}clear(){super.clear(),this.clearFunc?this._enqueue((()=>this.clearFunc())):this._enqueue((()=>this.saveFunc("")))}async _loadInitial(e){try{if(e=await e){let t;"string"==typeof e?t=JSON.parse(e)||{}:"object"==typeof e&&(t=e),this.save(t.token||"",t.record||t.model||null)}}catch(e){}}_enqueue(e){this.queue.push(e),1==this.queue.length&&this._dequeue()}_dequeue(){this.queue.length&&this.queue[0]().finally((()=>{this.queue.shift(),this.queue.length&&this._dequeue()}))}}export{AsyncAuthStore,BaseAuthStore,BatchService,ClientResponseError,CollectionService,CrudService,HealthService,LocalAuthStore,LogService,RealtimeService,RecordService,SubBatchService,cookieParse,cookieSerialize,Client as default,getTokenPayload,isTokenExpired,normalizeUnknownQueryParams,serializeQueryParams}; //# sourceMappingURL=pocketbase.es.js.map diff --git a/dist/pocketbase.es.js.map b/dist/pocketbase.es.js.map index 520d5e4..b5a8033 100644 --- a/dist/pocketbase.es.js.map +++ b/dist/pocketbase.es.js.map @@ -1 +1 @@ -{"version":3,"file":"pocketbase.es.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts","../src/stores/AsyncAuthStore.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\nexport type AsyncSaveFunc = (serializedPayload: string) => Promise;\n\nexport type AsyncClearFunc = () => Promise;\n\ntype queueFunc = () => Promise;\n\n/**\n * AsyncAuthStore is a helper auth store implementation\n * that could be used with any external async persistent layer\n * (key-value db, local file, etc.).\n *\n * Here is an example with the React Native AsyncStorage package:\n *\n * ```\n * import AsyncStorage from \"@react-native-async-storage/async-storage\";\n * import PocketBase, { AsyncAuthStore } from \"pocketbase\";\n *\n * const store = new AsyncAuthStore({\n * save: async (serialized) => AsyncStorage.setItem(\"pb_auth\", serialized),\n * initial: AsyncStorage.getItem(\"pb_auth\"),\n * });\n *\n * const pb = new PocketBase(\"https://example.com\", store)\n * ```\n */\nexport class AsyncAuthStore extends BaseAuthStore {\n private saveFunc: AsyncSaveFunc;\n private clearFunc?: AsyncClearFunc;\n private queue: Array = [];\n\n constructor(config: {\n // The async function that is called every time\n // when the auth store state needs to be persisted.\n save: AsyncSaveFunc;\n\n /// An *optional* async function that is called every time\n /// when the auth store needs to be cleared.\n ///\n /// If not explicitly set, `saveFunc` with empty data will be used.\n clear?: AsyncClearFunc;\n\n // An *optional* initial data to load into the store.\n initial?: string | Promise;\n }) {\n super();\n\n this.saveFunc = config.save;\n this.clearFunc = config.clear;\n\n this._enqueue(() => this._loadInitial(config.initial));\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord): void {\n super.save(token, record);\n\n let value = \"\";\n try {\n value = JSON.stringify({ token, record });\n } catch (err) {\n console.warn(\"AsyncAuthStore: failed to stringify the new state\");\n }\n\n this._enqueue(() => this.saveFunc(value));\n }\n\n /**\n * @inheritdoc\n */\n clear(): void {\n super.clear();\n\n if (this.clearFunc) {\n this._enqueue(() => this.clearFunc!());\n } else {\n this._enqueue(() => this.saveFunc(\"\"));\n }\n }\n\n /**\n * Initializes the auth store state.\n */\n private async _loadInitial(payload?: string | Promise) {\n try {\n payload = await payload;\n\n if (payload) {\n let parsed;\n if (typeof payload === \"string\") {\n parsed = JSON.parse(payload) || {};\n } else if (typeof payload === \"object\") {\n parsed = payload;\n }\n\n this.save(parsed.token || \"\", parsed.record || parsed.model || null);\n }\n } catch (_) {}\n }\n\n /**\n * Appends an async function to the queue.\n */\n private _enqueue(asyncCallback: () => Promise) {\n this.queue.push(asyncCallback);\n\n if (this.queue.length == 1) {\n this._dequeue();\n }\n }\n\n /**\n * Starts the queue processing.\n */\n private _dequeue() {\n if (!this.queue.length) {\n return;\n }\n\n this.queue[0]().finally(() => {\n this.queue.shift();\n\n if (!this.queue.length) {\n return;\n }\n\n this._dequeue();\n });\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieParse","str","options","result","decode","assign","defaultDecode","index","length","eqIdx","indexOf","endIdx","lastIndexOf","key","slice","trim","undefined","val","charCodeAt","_","cookieSerialize","opt","encode","defaultEncode","test","TypeError","value","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","exp","now","atob","input","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","rawData","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController","AsyncAuthStore","queue","saveFunc","clearFunc","_enqueue","_loadInitial","initial","parsed","asyncCallback","_dequeue","finally","shift"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pocketbase.es.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts","../src/stores/AsyncAuthStore.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * An optional hook that is invoked when the realtime client disconnects\n * either when unsubscribing from all subscriptions or when the\n * connection was interrupted or closed by the server.\n *\n * The received argument could be used to determine whether the disconnect\n * is a result from unsubscribing (`activeSubscriptions.length == 0`)\n * or because of network/server error (`activeSubscriptions.length > 0`).\n *\n * If you want to listen for the opposite, aka. when the client connection is established,\n * subscribe to the `PB_CONNECT` event.\n */\n onDisconnect?: (activeSubscriptions: Array) => void;\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n if (this.clientId && this.onDisconnect) {\n this.onDisconnect(Object.keys(this.subscriptions));\n }\n\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\nexport type AsyncSaveFunc = (serializedPayload: string) => Promise;\n\nexport type AsyncClearFunc = () => Promise;\n\ntype queueFunc = () => Promise;\n\n/**\n * AsyncAuthStore is a helper auth store implementation\n * that could be used with any external async persistent layer\n * (key-value db, local file, etc.).\n *\n * Here is an example with the React Native AsyncStorage package:\n *\n * ```\n * import AsyncStorage from \"@react-native-async-storage/async-storage\";\n * import PocketBase, { AsyncAuthStore } from \"pocketbase\";\n *\n * const store = new AsyncAuthStore({\n * save: async (serialized) => AsyncStorage.setItem(\"pb_auth\", serialized),\n * initial: AsyncStorage.getItem(\"pb_auth\"),\n * });\n *\n * const pb = new PocketBase(\"https://example.com\", store)\n * ```\n */\nexport class AsyncAuthStore extends BaseAuthStore {\n private saveFunc: AsyncSaveFunc;\n private clearFunc?: AsyncClearFunc;\n private queue: Array = [];\n\n constructor(config: {\n // The async function that is called every time\n // when the auth store state needs to be persisted.\n save: AsyncSaveFunc;\n\n /// An *optional* async function that is called every time\n /// when the auth store needs to be cleared.\n ///\n /// If not explicitly set, `saveFunc` with empty data will be used.\n clear?: AsyncClearFunc;\n\n // An *optional* initial data to load into the store.\n initial?: string | Promise;\n }) {\n super();\n\n this.saveFunc = config.save;\n this.clearFunc = config.clear;\n\n this._enqueue(() => this._loadInitial(config.initial));\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord): void {\n super.save(token, record);\n\n let value = \"\";\n try {\n value = JSON.stringify({ token, record });\n } catch (err) {\n console.warn(\"AsyncAuthStore: failed to stringify the new state\");\n }\n\n this._enqueue(() => this.saveFunc(value));\n }\n\n /**\n * @inheritdoc\n */\n clear(): void {\n super.clear();\n\n if (this.clearFunc) {\n this._enqueue(() => this.clearFunc!());\n } else {\n this._enqueue(() => this.saveFunc(\"\"));\n }\n }\n\n /**\n * Initializes the auth store state.\n */\n private async _loadInitial(payload?: string | Promise) {\n try {\n payload = await payload;\n\n if (payload) {\n let parsed;\n if (typeof payload === \"string\") {\n parsed = JSON.parse(payload) || {};\n } else if (typeof payload === \"object\") {\n parsed = payload;\n }\n\n this.save(parsed.token || \"\", parsed.record || parsed.model || null);\n }\n } catch (_) {}\n }\n\n /**\n * Appends an async function to the queue.\n */\n private _enqueue(asyncCallback: () => Promise) {\n this.queue.push(asyncCallback);\n\n if (this.queue.length == 1) {\n this._dequeue();\n }\n }\n\n /**\n * Starts the queue processing.\n */\n private _dequeue() {\n if (!this.queue.length) {\n return;\n }\n\n this.queue[0]().finally(() => {\n this.queue.shift();\n\n if (!this.queue.length) {\n return;\n }\n\n this._dequeue();\n });\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieParse","str","options","result","decode","assign","defaultDecode","index","length","eqIdx","indexOf","endIdx","lastIndexOf","key","slice","trim","undefined","val","charCodeAt","_","cookieSerialize","opt","encode","defaultEncode","test","TypeError","value","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","exp","now","atob","input","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","rawData","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","onDisconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController","AsyncAuthStore","queue","saveFunc","clearFunc","_enqueue","_loadInitial","initial","parsed","asyncCallback","_dequeue","finally","shift"],"mappings":"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"} \ No newline at end of file diff --git a/dist/pocketbase.es.mjs b/dist/pocketbase.es.mjs index 96827b2..a756111 100644 --- a/dist/pocketbase.es.mjs +++ b/dist/pocketbase.es.mjs @@ -1,2 +1,2 @@ -class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},t||{}).decode||defaultDecode;let n=0;for(;n0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=cookieParse(e||"")[t]||"";let n={};try{n=JSON.parse(s),(null===typeof n||"object"!=typeof n||Array.isArray(n))&&(n={})}catch(e){}this.save(n.token||"",n.record||n.model||null)}exportToCookie(e,t=i){const s={secure:!0,sameSite:!0,httpOnly:!0,path:"/"},n=getTokenPayload(this.token);s.expires=n?.exp?new Date(1e3*n.exp):new Date("1970-01-01"),e=Object.assign({},s,e);const r={token:this.token,record:this.record?JSON.parse(JSON.stringify(this.record)):null};let o=cookieSerialize(t,JSON.stringify(r),e);const a="undefined"!=typeof Blob?new Blob([o]).size:o.length;if(r.record&&a>4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}class AsyncAuthStore extends BaseAuthStore{constructor(e){super(),this.queue=[],this.saveFunc=e.save,this.clearFunc=e.clear,this._enqueue((()=>this._loadInitial(e.initial)))}save(e,t){super.save(e,t);let s="";try{s=JSON.stringify({token:e,record:t})}catch(e){console.warn("AsyncAuthStore: failed to stringify the new state")}this._enqueue((()=>this.saveFunc(s)))}clear(){super.clear(),this.clearFunc?this._enqueue((()=>this.clearFunc())):this._enqueue((()=>this.saveFunc("")))}async _loadInitial(e){try{if(e=await e){let t;"string"==typeof e?t=JSON.parse(e)||{}:"object"==typeof e&&(t=e),this.save(t.token||"",t.record||t.model||null)}}catch(e){}}_enqueue(e){this.queue.push(e),1==this.queue.length&&this._dequeue()}_dequeue(){this.queue.length&&this.queue[0]().finally((()=>{this.queue.shift(),this.queue.length&&this._dequeue()}))}}export{AsyncAuthStore,BaseAuthStore,BatchService,ClientResponseError,CollectionService,CrudService,HealthService,LocalAuthStore,LogService,RealtimeService,RecordService,SubBatchService,cookieParse,cookieSerialize,Client as default,getTokenPayload,isTokenExpired,normalizeUnknownQueryParams,serializeQueryParams}; +class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},t||{}).decode||defaultDecode;let n=0;for(;n0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=cookieParse(e||"")[t]||"";let n={};try{n=JSON.parse(s),(null===typeof n||"object"!=typeof n||Array.isArray(n))&&(n={})}catch(e){}this.save(n.token||"",n.record||n.model||null)}exportToCookie(e,t=i){const s={secure:!0,sameSite:!0,httpOnly:!0,path:"/"},n=getTokenPayload(this.token);s.expires=n?.exp?new Date(1e3*n.exp):new Date("1970-01-01"),e=Object.assign({},s,e);const r={token:this.token,record:this.record?JSON.parse(JSON.stringify(this.record)):null};let o=cookieSerialize(t,JSON.stringify(r),e);const a="undefined"!=typeof Blob?new Blob([o]).size:o.length;if(r.record&&a>4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(this.clientId&&this.onDisconnect&&this.onDisconnect(Object.keys(this.subscriptions)),clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}class AsyncAuthStore extends BaseAuthStore{constructor(e){super(),this.queue=[],this.saveFunc=e.save,this.clearFunc=e.clear,this._enqueue((()=>this._loadInitial(e.initial)))}save(e,t){super.save(e,t);let s="";try{s=JSON.stringify({token:e,record:t})}catch(e){console.warn("AsyncAuthStore: failed to stringify the new state")}this._enqueue((()=>this.saveFunc(s)))}clear(){super.clear(),this.clearFunc?this._enqueue((()=>this.clearFunc())):this._enqueue((()=>this.saveFunc("")))}async _loadInitial(e){try{if(e=await e){let t;"string"==typeof e?t=JSON.parse(e)||{}:"object"==typeof e&&(t=e),this.save(t.token||"",t.record||t.model||null)}}catch(e){}}_enqueue(e){this.queue.push(e),1==this.queue.length&&this._dequeue()}_dequeue(){this.queue.length&&this.queue[0]().finally((()=>{this.queue.shift(),this.queue.length&&this._dequeue()}))}}export{AsyncAuthStore,BaseAuthStore,BatchService,ClientResponseError,CollectionService,CrudService,HealthService,LocalAuthStore,LogService,RealtimeService,RecordService,SubBatchService,cookieParse,cookieSerialize,Client as default,getTokenPayload,isTokenExpired,normalizeUnknownQueryParams,serializeQueryParams}; //# sourceMappingURL=pocketbase.es.mjs.map diff --git a/dist/pocketbase.es.mjs.map b/dist/pocketbase.es.mjs.map index 2566d6d..adce3f4 100644 --- a/dist/pocketbase.es.mjs.map +++ b/dist/pocketbase.es.mjs.map @@ -1 +1 @@ -{"version":3,"file":"pocketbase.es.mjs","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts","../src/stores/AsyncAuthStore.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\nexport type AsyncSaveFunc = (serializedPayload: string) => Promise;\n\nexport type AsyncClearFunc = () => Promise;\n\ntype queueFunc = () => Promise;\n\n/**\n * AsyncAuthStore is a helper auth store implementation\n * that could be used with any external async persistent layer\n * (key-value db, local file, etc.).\n *\n * Here is an example with the React Native AsyncStorage package:\n *\n * ```\n * import AsyncStorage from \"@react-native-async-storage/async-storage\";\n * import PocketBase, { AsyncAuthStore } from \"pocketbase\";\n *\n * const store = new AsyncAuthStore({\n * save: async (serialized) => AsyncStorage.setItem(\"pb_auth\", serialized),\n * initial: AsyncStorage.getItem(\"pb_auth\"),\n * });\n *\n * const pb = new PocketBase(\"https://example.com\", store)\n * ```\n */\nexport class AsyncAuthStore extends BaseAuthStore {\n private saveFunc: AsyncSaveFunc;\n private clearFunc?: AsyncClearFunc;\n private queue: Array = [];\n\n constructor(config: {\n // The async function that is called every time\n // when the auth store state needs to be persisted.\n save: AsyncSaveFunc;\n\n /// An *optional* async function that is called every time\n /// when the auth store needs to be cleared.\n ///\n /// If not explicitly set, `saveFunc` with empty data will be used.\n clear?: AsyncClearFunc;\n\n // An *optional* initial data to load into the store.\n initial?: string | Promise;\n }) {\n super();\n\n this.saveFunc = config.save;\n this.clearFunc = config.clear;\n\n this._enqueue(() => this._loadInitial(config.initial));\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord): void {\n super.save(token, record);\n\n let value = \"\";\n try {\n value = JSON.stringify({ token, record });\n } catch (err) {\n console.warn(\"AsyncAuthStore: failed to stringify the new state\");\n }\n\n this._enqueue(() => this.saveFunc(value));\n }\n\n /**\n * @inheritdoc\n */\n clear(): void {\n super.clear();\n\n if (this.clearFunc) {\n this._enqueue(() => this.clearFunc!());\n } else {\n this._enqueue(() => this.saveFunc(\"\"));\n }\n }\n\n /**\n * Initializes the auth store state.\n */\n private async _loadInitial(payload?: string | Promise) {\n try {\n payload = await payload;\n\n if (payload) {\n let parsed;\n if (typeof payload === \"string\") {\n parsed = JSON.parse(payload) || {};\n } else if (typeof payload === \"object\") {\n parsed = payload;\n }\n\n this.save(parsed.token || \"\", parsed.record || parsed.model || null);\n }\n } catch (_) {}\n }\n\n /**\n * Appends an async function to the queue.\n */\n private _enqueue(asyncCallback: () => Promise) {\n this.queue.push(asyncCallback);\n\n if (this.queue.length == 1) {\n this._dequeue();\n }\n }\n\n /**\n * Starts the queue processing.\n */\n private _dequeue() {\n if (!this.queue.length) {\n return;\n }\n\n this.queue[0]().finally(() => {\n this.queue.shift();\n\n if (!this.queue.length) {\n return;\n }\n\n this._dequeue();\n });\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieParse","str","options","result","decode","assign","defaultDecode","index","length","eqIdx","indexOf","endIdx","lastIndexOf","key","slice","trim","undefined","val","charCodeAt","_","cookieSerialize","opt","encode","defaultEncode","test","TypeError","value","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","exp","now","atob","input","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","rawData","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController","AsyncAuthStore","queue","saveFunc","clearFunc","_enqueue","_loadInitial","initial","parsed","asyncCallback","_dequeue","finally","shift"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pocketbase.es.mjs","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts","../src/stores/AsyncAuthStore.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * An optional hook that is invoked when the realtime client disconnects\n * either when unsubscribing from all subscriptions or when the\n * connection was interrupted or closed by the server.\n *\n * The received argument could be used to determine whether the disconnect\n * is a result from unsubscribing (`activeSubscriptions.length == 0`)\n * or because of network/server error (`activeSubscriptions.length > 0`).\n *\n * If you want to listen for the opposite, aka. when the client connection is established,\n * subscribe to the `PB_CONNECT` event.\n */\n onDisconnect?: (activeSubscriptions: Array) => void;\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n if (this.clientId && this.onDisconnect) {\n this.onDisconnect(Object.keys(this.subscriptions));\n }\n\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\nexport type AsyncSaveFunc = (serializedPayload: string) => Promise;\n\nexport type AsyncClearFunc = () => Promise;\n\ntype queueFunc = () => Promise;\n\n/**\n * AsyncAuthStore is a helper auth store implementation\n * that could be used with any external async persistent layer\n * (key-value db, local file, etc.).\n *\n * Here is an example with the React Native AsyncStorage package:\n *\n * ```\n * import AsyncStorage from \"@react-native-async-storage/async-storage\";\n * import PocketBase, { AsyncAuthStore } from \"pocketbase\";\n *\n * const store = new AsyncAuthStore({\n * save: async (serialized) => AsyncStorage.setItem(\"pb_auth\", serialized),\n * initial: AsyncStorage.getItem(\"pb_auth\"),\n * });\n *\n * const pb = new PocketBase(\"https://example.com\", store)\n * ```\n */\nexport class AsyncAuthStore extends BaseAuthStore {\n private saveFunc: AsyncSaveFunc;\n private clearFunc?: AsyncClearFunc;\n private queue: Array = [];\n\n constructor(config: {\n // The async function that is called every time\n // when the auth store state needs to be persisted.\n save: AsyncSaveFunc;\n\n /// An *optional* async function that is called every time\n /// when the auth store needs to be cleared.\n ///\n /// If not explicitly set, `saveFunc` with empty data will be used.\n clear?: AsyncClearFunc;\n\n // An *optional* initial data to load into the store.\n initial?: string | Promise;\n }) {\n super();\n\n this.saveFunc = config.save;\n this.clearFunc = config.clear;\n\n this._enqueue(() => this._loadInitial(config.initial));\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord): void {\n super.save(token, record);\n\n let value = \"\";\n try {\n value = JSON.stringify({ token, record });\n } catch (err) {\n console.warn(\"AsyncAuthStore: failed to stringify the new state\");\n }\n\n this._enqueue(() => this.saveFunc(value));\n }\n\n /**\n * @inheritdoc\n */\n clear(): void {\n super.clear();\n\n if (this.clearFunc) {\n this._enqueue(() => this.clearFunc!());\n } else {\n this._enqueue(() => this.saveFunc(\"\"));\n }\n }\n\n /**\n * Initializes the auth store state.\n */\n private async _loadInitial(payload?: string | Promise) {\n try {\n payload = await payload;\n\n if (payload) {\n let parsed;\n if (typeof payload === \"string\") {\n parsed = JSON.parse(payload) || {};\n } else if (typeof payload === \"object\") {\n parsed = payload;\n }\n\n this.save(parsed.token || \"\", parsed.record || parsed.model || null);\n }\n } catch (_) {}\n }\n\n /**\n * Appends an async function to the queue.\n */\n private _enqueue(asyncCallback: () => Promise) {\n this.queue.push(asyncCallback);\n\n if (this.queue.length == 1) {\n this._dequeue();\n }\n }\n\n /**\n * Starts the queue processing.\n */\n private _dequeue() {\n if (!this.queue.length) {\n return;\n }\n\n this.queue[0]().finally(() => {\n this.queue.shift();\n\n if (!this.queue.length) {\n return;\n }\n\n this._dequeue();\n });\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieParse","str","options","result","decode","assign","defaultDecode","index","length","eqIdx","indexOf","endIdx","lastIndexOf","key","slice","trim","undefined","val","charCodeAt","_","cookieSerialize","opt","encode","defaultEncode","test","TypeError","value","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","exp","now","atob","input","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","rawData","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","onDisconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController","AsyncAuthStore","queue","saveFunc","clearFunc","_enqueue","_loadInitial","initial","parsed","asyncCallback","_dequeue","finally","shift"],"mappings":"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"} \ No newline at end of file diff --git a/dist/pocketbase.iife.d.ts b/dist/pocketbase.iife.d.ts index 7fa0289..ad41c2d 100644 --- a/dist/pocketbase.iife.d.ts +++ b/dist/pocketbase.iife.d.ts @@ -382,6 +382,19 @@ declare class RealtimeService extends BaseService { * Returns whether the realtime connection has been established. */ get isConnected(): boolean; + /** + * An optional hook that is invoked when the realtime client disconnects + * either when unsubscribing from all subscriptions or when the + * connection was interrupted or closed by the server. + * + * The received argument could be used to determine whether the disconnect + * is a result from unsubscribing (`activeSubscriptions.length == 0`) + * or because of network/server error (`activeSubscriptions.length > 0`). + * + * If you want to listen for the opposite, aka. when the client connection is established, + * subscribe to the `PB_CONNECT` event. + */ + onDisconnect?: (activeSubscriptions: Array) => void; /** * Register the subscription listener. * diff --git a/dist/pocketbase.iife.js b/dist/pocketbase.iife.js index e64ec79..3b55de0 100644 --- a/dist/pocketbase.iife.js +++ b/dist/pocketbase.iife.js @@ -1,2 +1,2 @@ -var PocketBase=function(){"use strict";class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),r=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const o=r(s);if(o&&!e.test(o))throw new TypeError("argument val is invalid");let a=t+"="+o;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},{}).decode||defaultDecode;let n=0;for(;n4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}return Client}(); +var PocketBase=function(){"use strict";class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),r=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const o=r(s);if(o&&!e.test(o))throw new TypeError("argument val is invalid");let a=t+"="+o;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},{}).decode||defaultDecode;let n=0;for(;n4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(this.clientId&&this.onDisconnect&&this.onDisconnect(Object.keys(this.subscriptions)),clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}return Client}(); //# sourceMappingURL=pocketbase.iife.js.map diff --git a/dist/pocketbase.iife.js.map b/dist/pocketbase.iife.js.map index facf0fb..0284837 100644 --- a/dist/pocketbase.iife.js.map +++ b/dist/pocketbase.iife.js.map @@ -1 +1 @@ -{"version":3,"file":"pocketbase.iife.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieSerialize","val","options","opt","assign","encode","defaultEncode","test","TypeError","value","result","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","defaultDecode","indexOf","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","charCodeAt","slice","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","length","exp","now","atob","input","str","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","key","rawData","cookieParse","decode","index","eqIdx","endIdx","lastIndexOf","trim","undefined","_","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pocketbase.iife.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * An optional hook that is invoked when the realtime client disconnects\n * either when unsubscribing from all subscriptions or when the\n * connection was interrupted or closed by the server.\n *\n * The received argument could be used to determine whether the disconnect\n * is a result from unsubscribing (`activeSubscriptions.length == 0`)\n * or because of network/server error (`activeSubscriptions.length > 0`).\n *\n * If you want to listen for the opposite, aka. when the client connection is established,\n * subscribe to the `PB_CONNECT` event.\n */\n onDisconnect?: (activeSubscriptions: Array) => void;\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n if (this.clientId && this.onDisconnect) {\n this.onDisconnect(Object.keys(this.subscriptions));\n }\n\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieSerialize","val","options","opt","assign","encode","defaultEncode","test","TypeError","value","result","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","defaultDecode","indexOf","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","charCodeAt","slice","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","length","exp","now","atob","input","str","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","key","rawData","cookieParse","decode","index","eqIdx","endIdx","lastIndexOf","trim","undefined","_","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","onDisconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController"],"mappings":"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"} \ No newline at end of file diff --git a/dist/pocketbase.umd.d.ts b/dist/pocketbase.umd.d.ts index 7fa0289..ad41c2d 100644 --- a/dist/pocketbase.umd.d.ts +++ b/dist/pocketbase.umd.d.ts @@ -382,6 +382,19 @@ declare class RealtimeService extends BaseService { * Returns whether the realtime connection has been established. */ get isConnected(): boolean; + /** + * An optional hook that is invoked when the realtime client disconnects + * either when unsubscribing from all subscriptions or when the + * connection was interrupted or closed by the server. + * + * The received argument could be used to determine whether the disconnect + * is a result from unsubscribing (`activeSubscriptions.length == 0`) + * or because of network/server error (`activeSubscriptions.length > 0`). + * + * If you want to listen for the opposite, aka. when the client connection is established, + * subscribe to the `PB_CONNECT` event. + */ + onDisconnect?: (activeSubscriptions: Array) => void; /** * Register the subscription listener. * diff --git a/dist/pocketbase.umd.js b/dist/pocketbase.umd.js index ea3d5e7..55bb1f7 100644 --- a/dist/pocketbase.umd.js +++ b/dist/pocketbase.umd.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PocketBase=t()}(this,(function(){"use strict";class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),r=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const o=r(s);if(o&&!e.test(o))throw new TypeError("argument val is invalid");let a=t+"="+o;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},{}).decode||defaultDecode;let n=0;for(;n4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}return Client})); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PocketBase=t()}(this,(function(){"use strict";class ClientResponseError extends Error{constructor(e){super("ClientResponseError"),this.url="",this.status=0,this.response={},this.isAbort=!1,this.originalError=null,Object.setPrototypeOf(this,ClientResponseError.prototype),null!==e&&"object"==typeof e&&(this.url="string"==typeof e.url?e.url:"",this.status="number"==typeof e.status?e.status:0,this.isAbort=!!e.isAbort,this.originalError=e.originalError,null!==e.response&&"object"==typeof e.response?this.response=e.response:null!==e.data&&"object"==typeof e.data?this.response=e.data:this.response={}),this.originalError||e instanceof ClientResponseError||(this.originalError=e),"undefined"!=typeof DOMException&&e instanceof DOMException&&(this.isAbort=!0),this.name="ClientResponseError "+this.status,this.message=this.response?.message,this.message||(this.isAbort?this.message="The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.":this.originalError?.cause?.message?.includes("ECONNREFUSED ::1")?this.message="Failed to connect to the PocketBase server. Try changing the SDK URL from localhost to 127.0.0.1 (https://github.com/pocketbase/js-sdk/issues/21).":this.message="Something went wrong while processing your request.")}get data(){return this.response}toJSON(){return{...this}}}const e=/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/;function cookieSerialize(t,s,i){const n=Object.assign({},i||{}),r=n.encode||defaultEncode;if(!e.test(t))throw new TypeError("argument name is invalid");const o=r(s);if(o&&!e.test(o))throw new TypeError("argument val is invalid");let a=t+"="+o;if(null!=n.maxAge){const e=n.maxAge-0;if(isNaN(e)||!isFinite(e))throw new TypeError("option maxAge is invalid");a+="; Max-Age="+Math.floor(e)}if(n.domain){if(!e.test(n.domain))throw new TypeError("option domain is invalid");a+="; Domain="+n.domain}if(n.path){if(!e.test(n.path))throw new TypeError("option path is invalid");a+="; Path="+n.path}if(n.expires){if(!function isDate(e){return"[object Date]"===Object.prototype.toString.call(e)||e instanceof Date}(n.expires)||isNaN(n.expires.valueOf()))throw new TypeError("option expires is invalid");a+="; Expires="+n.expires.toUTCString()}if(n.httpOnly&&(a+="; HttpOnly"),n.secure&&(a+="; Secure"),n.priority){switch("string"==typeof n.priority?n.priority.toLowerCase():n.priority){case"low":a+="; Priority=Low";break;case"medium":a+="; Priority=Medium";break;case"high":a+="; Priority=High";break;default:throw new TypeError("option priority is invalid")}}if(n.sameSite){switch("string"==typeof n.sameSite?n.sameSite.toLowerCase():n.sameSite){case!0:a+="; SameSite=Strict";break;case"lax":a+="; SameSite=Lax";break;case"strict":a+="; SameSite=Strict";break;case"none":a+="; SameSite=None";break;default:throw new TypeError("option sameSite is invalid")}}return a}function defaultDecode(e){return-1!==e.indexOf("%")?decodeURIComponent(e):e}function defaultEncode(e){return encodeURIComponent(e)}const t="undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal;let s;function getTokenPayload(e){if(e)try{const t=decodeURIComponent(s(e.split(".")[1]).split("").map((function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)})).join(""));return JSON.parse(t)||{}}catch(e){}return{}}function isTokenExpired(e,t=0){let s=getTokenPayload(e);return!(Object.keys(s).length>0&&(!s.exp||s.exp-t>Date.now()/1e3))}s="function"!=typeof atob||t?e=>{let t=String(e).replace(/=+$/,"");if(t.length%4==1)throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");for(var s,i,n=0,r=0,o="";i=t.charAt(r++);~i&&(s=n%4?64*s+i:i,n++%4)?o+=String.fromCharCode(255&s>>(-2*n&6)):0)i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(i);return o}:atob;const i="pb_auth";class BaseAuthStore{constructor(){this.baseToken="",this.baseModel=null,this._onChangeCallbacks=[]}get token(){return this.baseToken}get record(){return this.baseModel}get model(){return this.baseModel}get isValid(){return!isTokenExpired(this.token)}get isSuperuser(){let e=getTokenPayload(this.token);return"auth"==e.type&&("_superusers"==this.record?.collectionName||!this.record?.collectionName&&"pbc_3142635823"==e.collectionId)}get isAdmin(){return console.warn("Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),this.isSuperuser}get isAuthRecord(){return console.warn("Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName"),"auth"==getTokenPayload(this.token).type&&!this.isSuperuser}save(e,t){this.baseToken=e||"",this.baseModel=t||null,this.triggerChange()}clear(){this.baseToken="",this.baseModel=null,this.triggerChange()}loadFromCookie(e,t=i){const s=function cookieParse(e,t){const s={};if("string"!=typeof e)return s;const i=Object.assign({},{}).decode||defaultDecode;let n=0;for(;n4096){r.record={id:r.record?.id,email:r.record?.email};const s=["collectionId","collectionName","verified"];for(const e in this.record)s.includes(e)&&(r.record[e]=this.record[e]);o=cookieSerialize(t,JSON.stringify(r),e)}return o}onChange(e,t=!1){return this._onChangeCallbacks.push(e),t&&e(this.token,this.record),()=>{for(let t=this._onChangeCallbacks.length-1;t>=0;t--)if(this._onChangeCallbacks[t]==e)return delete this._onChangeCallbacks[t],void this._onChangeCallbacks.splice(t,1)}}triggerChange(){for(const e of this._onChangeCallbacks)e&&e(this.token,this.record)}}class LocalAuthStore extends BaseAuthStore{constructor(e="pocketbase_auth"){super(),this.storageFallback={},this.storageKey=e,this._bindStorageEvent()}get token(){return(this._storageGet(this.storageKey)||{}).token||""}get record(){const e=this._storageGet(this.storageKey)||{};return e.record||e.model||null}get model(){return this.record}save(e,t){this._storageSet(this.storageKey,{token:e,record:t}),super.save(e,t)}clear(){this._storageRemove(this.storageKey),super.clear()}_storageGet(e){if("undefined"!=typeof window&&window?.localStorage){const t=window.localStorage.getItem(e)||"";try{return JSON.parse(t)}catch(e){return t}}return this.storageFallback[e]}_storageSet(e,t){if("undefined"!=typeof window&&window?.localStorage){let s=t;"string"!=typeof t&&(s=JSON.stringify(t)),window.localStorage.setItem(e,s)}else this.storageFallback[e]=t}_storageRemove(e){"undefined"!=typeof window&&window?.localStorage&&window.localStorage?.removeItem(e),delete this.storageFallback[e]}_bindStorageEvent(){"undefined"!=typeof window&&window?.localStorage&&window.addEventListener&&window.addEventListener("storage",(e=>{if(e.key!=this.storageKey)return;const t=this._storageGet(this.storageKey)||{};super.save(t.token||"",t.record||t.model||null)}))}}class BaseService{constructor(e){this.client=e}}class SettingsService extends BaseService{async getAll(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/settings",e)}async update(e,t){return t=Object.assign({method:"PATCH",body:e},t),this.client.send("/api/settings",t)}async testS3(e="storage",t){return t=Object.assign({method:"POST",body:{filesystem:e}},t),this.client.send("/api/settings/test/s3",t).then((()=>!0))}async testEmail(e,t,s,i){return i=Object.assign({method:"POST",body:{email:t,template:s,collection:e}},i),this.client.send("/api/settings/test/email",i).then((()=>!0))}async generateAppleClientSecret(e,t,s,i,n,r){return r=Object.assign({method:"POST",body:{clientId:e,teamId:t,keyId:s,privateKey:i,duration:n}},r),this.client.send("/api/settings/apple/generate-client-secret",r)}}const n=["requestKey","$cancelKey","$autoCancel","fetch","headers","body","query","params","cache","credentials","headers","integrity","keepalive","method","mode","redirect","referrer","referrerPolicy","signal","window"];function normalizeUnknownQueryParams(e){if(e){e.query=e.query||{};for(let t in e)n.includes(t)||(e.query[t]=e[t],delete e[t])}}function serializeQueryParams(e){const t=[];for(const s in e){if(null===e[s])continue;const i=e[s],n=encodeURIComponent(s);if(Array.isArray(i))for(const e of i)t.push(n+"="+encodeURIComponent(e));else i instanceof Date?t.push(n+"="+encodeURIComponent(i.toISOString())):null!==typeof i&&"object"==typeof i?t.push(n+"="+encodeURIComponent(JSON.stringify(i))):t.push(n+"="+encodeURIComponent(i))}return t.join("&")}class RealtimeService extends BaseService{constructor(){super(...arguments),this.clientId="",this.eventSource=null,this.subscriptions={},this.lastSentSubscriptions=[],this.maxConnectTimeout=15e3,this.reconnectAttempts=0,this.maxReconnectAttempts=1/0,this.predefinedReconnectIntervals=[200,300,500,1e3,1200,1500,2e3],this.pendingConnects=[]}get isConnected(){return!!this.eventSource&&!!this.clientId&&!this.pendingConnects.length}async subscribe(e,t,s){if(!e)throw new Error("topic must be set.");let i=e;if(s){normalizeUnknownQueryParams(s=Object.assign({},s));const e="options="+encodeURIComponent(JSON.stringify({query:s.query,headers:s.headers}));i+=(i.includes("?")?"&":"?")+e}const listener=function(e){const s=e;let i;try{i=JSON.parse(s?.data)}catch{}t(i||{})};return this.subscriptions[i]||(this.subscriptions[i]=[]),this.subscriptions[i].push(listener),this.isConnected?1===this.subscriptions[i].length?await this.submitSubscriptions():this.eventSource?.addEventListener(i,listener):await this.connect(),async()=>this.unsubscribeByTopicAndListener(e,listener)}async unsubscribe(e){let t=!1;if(e){const s=this.getSubscriptionsByTopic(e);for(let e in s)if(this.hasSubscriptionListeners(e)){for(let t of this.subscriptions[e])this.eventSource?.removeEventListener(e,t);delete this.subscriptions[e],t||(t=!0)}}else this.subscriptions={};this.hasSubscriptionListeners()?t&&await this.submitSubscriptions():this.disconnect()}async unsubscribeByPrefix(e){let t=!1;for(let s in this.subscriptions)if((s+"?").startsWith(e)){t=!0;for(let e of this.subscriptions[s])this.eventSource?.removeEventListener(s,e);delete this.subscriptions[s]}t&&(this.hasSubscriptionListeners()?await this.submitSubscriptions():this.disconnect())}async unsubscribeByTopicAndListener(e,t){let s=!1;const i=this.getSubscriptionsByTopic(e);for(let e in i){if(!Array.isArray(this.subscriptions[e])||!this.subscriptions[e].length)continue;let i=!1;for(let s=this.subscriptions[e].length-1;s>=0;s--)this.subscriptions[e][s]===t&&(i=!0,delete this.subscriptions[e][s],this.subscriptions[e].splice(s,1),this.eventSource?.removeEventListener(e,t));i&&(this.subscriptions[e].length||delete this.subscriptions[e],s||this.hasSubscriptionListeners(e)||(s=!0))}this.hasSubscriptionListeners()?s&&await this.submitSubscriptions():this.disconnect()}hasSubscriptionListeners(e){if(this.subscriptions=this.subscriptions||{},e)return!!this.subscriptions[e]?.length;for(let e in this.subscriptions)if(this.subscriptions[e]?.length)return!0;return!1}async submitSubscriptions(){if(this.clientId)return this.addAllSubscriptionListeners(),this.lastSentSubscriptions=this.getNonEmptySubscriptionKeys(),this.client.send("/api/realtime",{method:"POST",body:{clientId:this.clientId,subscriptions:this.lastSentSubscriptions},requestKey:this.getSubscriptionsCancelKey()}).catch((e=>{if(!e?.isAbort)throw e}))}getSubscriptionsCancelKey(){return"realtime_"+this.clientId}getSubscriptionsByTopic(e){const t={};e=e.includes("?")?e:e+"?";for(let s in this.subscriptions)(s+"?").startsWith(e)&&(t[s]=this.subscriptions[s]);return t}getNonEmptySubscriptionKeys(){const e=[];for(let t in this.subscriptions)this.subscriptions[t].length&&e.push(t);return e}addAllSubscriptionListeners(){if(this.eventSource){this.removeAllSubscriptionListeners();for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.addEventListener(e,t)}}removeAllSubscriptionListeners(){if(this.eventSource)for(let e in this.subscriptions)for(let t of this.subscriptions[e])this.eventSource.removeEventListener(e,t)}async connect(){if(!(this.reconnectAttempts>0))return new Promise(((e,t)=>{this.pendingConnects.push({resolve:e,reject:t}),this.pendingConnects.length>1||this.initConnect()}))}initConnect(){this.disconnect(!0),clearTimeout(this.connectTimeoutId),this.connectTimeoutId=setTimeout((()=>{this.connectErrorHandler(new Error("EventSource connect took too long."))}),this.maxConnectTimeout),this.eventSource=new EventSource(this.client.buildURL("/api/realtime")),this.eventSource.onerror=e=>{this.connectErrorHandler(new Error("Failed to establish realtime connection."))},this.eventSource.addEventListener("PB_CONNECT",(e=>{const t=e;this.clientId=t?.lastEventId,this.submitSubscriptions().then((async()=>{let e=3;for(;this.hasUnsentSubscriptions()&&e>0;)e--,await this.submitSubscriptions()})).then((()=>{for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[],this.reconnectAttempts=0,clearTimeout(this.reconnectTimeoutId),clearTimeout(this.connectTimeoutId);const t=this.getSubscriptionsByTopic("PB_CONNECT");for(let s in t)for(let i of t[s])i(e)})).catch((e=>{this.clientId="",this.connectErrorHandler(e)}))}))}hasUnsentSubscriptions(){const e=this.getNonEmptySubscriptionKeys();if(e.length!=this.lastSentSubscriptions.length)return!0;for(const t of e)if(!this.lastSentSubscriptions.includes(t))return!0;return!1}connectErrorHandler(e){if(clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),!this.clientId&&!this.reconnectAttempts||this.reconnectAttempts>this.maxReconnectAttempts){for(let t of this.pendingConnects)t.reject(new ClientResponseError(e));return this.pendingConnects=[],void this.disconnect()}this.disconnect(!0);const t=this.predefinedReconnectIntervals[this.reconnectAttempts]||this.predefinedReconnectIntervals[this.predefinedReconnectIntervals.length-1];this.reconnectAttempts++,this.reconnectTimeoutId=setTimeout((()=>{this.initConnect()}),t)}disconnect(e=!1){if(this.clientId&&this.onDisconnect&&this.onDisconnect(Object.keys(this.subscriptions)),clearTimeout(this.connectTimeoutId),clearTimeout(this.reconnectTimeoutId),this.removeAllSubscriptionListeners(),this.client.cancelRequest(this.getSubscriptionsCancelKey()),this.eventSource?.close(),this.eventSource=null,this.clientId="",!e){this.reconnectAttempts=0;for(let e of this.pendingConnects)e.resolve();this.pendingConnects=[]}}}class CrudService extends BaseService{decode(e){return e}async getFullList(e,t){if("number"==typeof e)return this._getFullList(e,t);let s=500;return(t=Object.assign({},e,t)).batch&&(s=t.batch,delete t.batch),this._getFullList(s,t)}async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send(this.baseCrudPath,s).then((e=>(e.items=e.items?.map((e=>this.decode(e)))||[],e)))}async getFirstListItem(e,t){return(t=Object.assign({requestKey:"one_by_filter_"+this.baseCrudPath+"_"+e},t)).query=Object.assign({filter:e,skipTotal:1},t.query),this.getList(1,1,t).then((e=>{if(!e?.items?.length)throw new ClientResponseError({status:404,response:{code:404,message:"The requested resource wasn't found.",data:{}}});return e.items[0]}))}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL(this.baseCrudPath+"/"),status:404,response:{code:404,message:"Missing required record id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((e=>this.decode(e)))}async create(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send(this.baseCrudPath,t).then((e=>this.decode(e)))}async update(e,t,s){return s=Object.assign({method:"PATCH",body:t},s),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),s).then((e=>this.decode(e)))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e),t).then((()=>!0))}_getFullList(e=500,t){(t=t||{}).query=Object.assign({skipTotal:1},t.query);let s=[],request=async i=>this.getList(i,e||500,t).then((e=>{const t=e.items;return s=s.concat(t),t.length==e.perPage?request(i+1):s}));return request(1)}}function normalizeLegacyOptionsArgs(e,t,s,i){const n=void 0!==i;return n||void 0!==s?n?(console.warn(e),t.body=Object.assign({},t.body,s),t.query=Object.assign({},t.query,i),t):Object.assign(t,s):t}function resetAutoRefresh(e){e._resetAutoRefresh?.()}class RecordService extends CrudService{constructor(e,t){super(e),this.collectionIdOrName=t}get baseCrudPath(){return this.baseCollectionPath+"/records"}get baseCollectionPath(){return"/api/collections/"+encodeURIComponent(this.collectionIdOrName)}get isSuperusers(){return"_superusers"==this.collectionIdOrName||"_pbc_2773867675"==this.collectionIdOrName}async subscribe(e,t,s){if(!e)throw new Error("Missing topic.");if(!t)throw new Error("Missing subscription callback.");return this.client.realtime.subscribe(this.collectionIdOrName+"/"+e,t,s)}async unsubscribe(e){return e?this.client.realtime.unsubscribe(this.collectionIdOrName+"/"+e):this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName)}async getFullList(e,t){if("number"==typeof e)return super.getFullList(e,t);const s=Object.assign({},e,t);return super.getFullList(s)}async getList(e=1,t=30,s){return super.getList(e,t,s)}async getFirstListItem(e,t){return super.getFirstListItem(e,t)}async getOne(e,t){return super.getOne(e,t)}async create(e,t){return super.create(e,t)}async update(e,t,s){return super.update(e,t,s).then((e=>{if(this.client.authStore.record?.id===e?.id&&(this.client.authStore.record?.collectionId===this.collectionIdOrName||this.client.authStore.record?.collectionName===this.collectionIdOrName)){let t=Object.assign({},this.client.authStore.record.expand),s=Object.assign({},this.client.authStore.record,e);t&&(s.expand=Object.assign(t,e.expand)),this.client.authStore.save(this.client.authStore.token,s)}return e}))}async delete(e,t){return super.delete(e,t).then((t=>(!t||this.client.authStore.record?.id!==e||this.client.authStore.record?.collectionId!==this.collectionIdOrName&&this.client.authStore.record?.collectionName!==this.collectionIdOrName||this.client.authStore.clear(),t)))}authResponse(e){const t=this.decode(e?.record||{});return this.client.authStore.save(e?.token,t),Object.assign({},e,{token:e?.token||"",record:t})}async listAuthMethods(e){return e=Object.assign({method:"GET",fields:"mfa,otp,password,oauth2"},e),this.client.send(this.baseCollectionPath+"/auth-methods",e)}async authWithPassword(e,t,s){let i;s=Object.assign({method:"POST",body:{identity:e,password:t}},s),this.isSuperusers&&(i=s.autoRefreshThreshold,delete s.autoRefreshThreshold,s.autoRefresh||resetAutoRefresh(this.client));let n=await this.client.send(this.baseCollectionPath+"/auth-with-password",s);return n=this.authResponse(n),i&&this.isSuperusers&&function registerAutoRefresh(e,t,s,i){resetAutoRefresh(e);const n=e.beforeSend,r=e.authStore.record,o=e.authStore.onChange(((t,s)=>{(!t||s?.id!=r?.id||(s?.collectionId||r?.collectionId)&&s?.collectionId!=r?.collectionId)&&resetAutoRefresh(e)}));e._resetAutoRefresh=function(){o(),e.beforeSend=n,delete e._resetAutoRefresh},e.beforeSend=async(r,o)=>{const a=e.authStore.token;if(o.query?.autoRefresh)return n?n(r,o):{url:r,sendOptions:o};let c=e.authStore.isValid;if(c&&isTokenExpired(e.authStore.token,t))try{await s()}catch(e){c=!1}c||await i();const l=o.headers||{};for(let t in l)if("authorization"==t.toLowerCase()&&a==l[t]&&e.authStore.token){l[t]=e.authStore.token;break}return o.headers=l,n?n(r,o):{url:r,sendOptions:o}}}(this.client,i,(()=>this.authRefresh({autoRefresh:!0})),(()=>this.authWithPassword(e,t,Object.assign({autoRefresh:!0},s)))),n}async authWithOAuth2Code(e,t,s,i,n,r,o){let a={method:"POST",body:{provider:e,code:t,codeVerifier:s,redirectURL:i,createData:n}};return a=normalizeLegacyOptionsArgs("This form of authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, body?, query?) is deprecated. Consider replacing it with authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createData?, options?).",a,r,o),this.client.send(this.baseCollectionPath+"/auth-with-oauth2",a).then((e=>this.authResponse(e)))}authWithOAuth2(...e){if(e.length>1||"string"==typeof e?.[0])return console.warn("PocketBase: This form of authWithOAuth2() is deprecated and may get removed in the future. Please replace with authWithOAuth2Code() OR use the authWithOAuth2() realtime form as shown in https://pocketbase.io/docs/authentication/#oauth2-integration."),this.authWithOAuth2Code(e?.[0]||"",e?.[1]||"",e?.[2]||"",e?.[3]||"",e?.[4]||{},e?.[5]||{},e?.[6]||{});const t=e?.[0]||{};let s=null;t.urlCallback||(s=openBrowserPopup(void 0));const i=new RealtimeService(this.client);function cleanup(){s?.close(),i.unsubscribe()}const n={},r=t.requestKey;return r&&(n.requestKey=r),this.listAuthMethods(n).then((e=>{const n=e.oauth2.providers.find((e=>e.name===t.provider));if(!n)throw new ClientResponseError(new Error(`Missing or invalid provider "${t.provider}".`));const o=this.client.buildURL("/api/oauth2-redirect"),a=r?this.client.cancelControllers?.[r]:void 0;return a&&(a.signal.onabort=()=>{cleanup()}),new Promise((async(e,r)=>{try{await i.subscribe("@oauth2",(async s=>{const c=i.clientId;try{if(!s.state||c!==s.state)throw new Error("State parameters don't match.");if(s.error||!s.code)throw new Error("OAuth2 redirect error or missing code: "+s.error);const i=Object.assign({},t);delete i.provider,delete i.scopes,delete i.createData,delete i.urlCallback,a?.signal?.onabort&&(a.signal.onabort=null);const r=await this.authWithOAuth2Code(n.name,s.code,n.codeVerifier,o,t.createData,i);e(r)}catch(e){r(new ClientResponseError(e))}cleanup()}));const c={state:i.clientId};t.scopes?.length&&(c.scope=t.scopes.join(" "));const l=this._replaceQueryParams(n.authURL+o,c);let h=t.urlCallback||function(e){s?s.location.href=e:s=openBrowserPopup(e)};await h(l)}catch(e){cleanup(),r(new ClientResponseError(e))}}))})).catch((e=>{throw cleanup(),e}))}async authRefresh(e,t){let s={method:"POST"};return s=normalizeLegacyOptionsArgs("This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).",s,e,t),this.client.send(this.baseCollectionPath+"/auth-refresh",s).then((e=>this.authResponse(e)))}async requestPasswordReset(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-password-reset",i).then((()=>!0))}async confirmPasswordReset(e,t,s,i,n){let r={method:"POST",body:{token:e,password:t,passwordConfirm:s}};return r=normalizeLegacyOptionsArgs("This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).",r,i,n),this.client.send(this.baseCollectionPath+"/confirm-password-reset",r).then((()=>!0))}async requestVerification(e,t,s){let i={method:"POST",body:{email:e}};return i=normalizeLegacyOptionsArgs("This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-verification",i).then((()=>!0))}async confirmVerification(e,t,s){let i={method:"POST",body:{token:e}};return i=normalizeLegacyOptionsArgs("This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/confirm-verification",i).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&!s.verified&&s.id===t.id&&s.collectionId===t.collectionId&&(s.verified=!0,this.client.authStore.save(this.client.authStore.token,s)),!0}))}async requestEmailChange(e,t,s){let i={method:"POST",body:{newEmail:e}};return i=normalizeLegacyOptionsArgs("This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).",i,t,s),this.client.send(this.baseCollectionPath+"/request-email-change",i).then((()=>!0))}async confirmEmailChange(e,t,s,i){let n={method:"POST",body:{token:e,password:t}};return n=normalizeLegacyOptionsArgs("This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).",n,s,i),this.client.send(this.baseCollectionPath+"/confirm-email-change",n).then((()=>{const t=getTokenPayload(e),s=this.client.authStore.record;return s&&s.id===t.id&&s.collectionId===t.collectionId&&this.client.authStore.clear(),!0}))}async listExternalAuths(e,t){return this.client.collection("_externalAuths").getFullList(Object.assign({},t,{filter:this.client.filter("recordRef = {:id}",{id:e})}))}async unlinkExternalAuth(e,t,s){const i=await this.client.collection("_externalAuths").getFirstListItem(this.client.filter("recordRef = {:recordId} && provider = {:provider}",{recordId:e,provider:t}));return this.client.collection("_externalAuths").delete(i.id,s).then((()=>!0))}async requestOTP(e,t){return t=Object.assign({method:"POST",body:{email:e}},t),this.client.send(this.baseCollectionPath+"/request-otp",t)}async authWithOTP(e,t,s){return s=Object.assign({method:"POST",body:{otpId:e,password:t}},s),this.client.send(this.baseCollectionPath+"/auth-with-otp",s).then((e=>this.authResponse(e)))}async impersonate(e,t,s){(s=Object.assign({method:"POST",body:{duration:t}},s)).headers=s.headers||{},s.headers.Authorization||(s.headers.Authorization=this.client.authStore.token);const i=new Client(this.client.baseURL,new BaseAuthStore,this.client.lang),n=await i.send(this.baseCollectionPath+"/impersonate/"+encodeURIComponent(e),s);return i.authStore.save(n?.token,this.decode(n?.record||{})),i}_replaceQueryParams(e,t={}){let s=e,i="";e.indexOf("?")>=0&&(s=e.substring(0,e.indexOf("?")),i=e.substring(e.indexOf("?")+1));const n={},r=i.split("&");for(const e of r){if(""==e)continue;const t=e.split("=");n[decodeURIComponent(t[0].replace(/\+/g," "))]=decodeURIComponent((t[1]||"").replace(/\+/g," "))}for(let e in t)t.hasOwnProperty(e)&&(null==t[e]?delete n[e]:n[e]=t[e]);i="";for(let e in n)n.hasOwnProperty(e)&&(""!=i&&(i+="&"),i+=encodeURIComponent(e.replace(/%20/g,"+"))+"="+encodeURIComponent(n[e].replace(/%20/g,"+")));return""!=i?s+"?"+i:s}}function openBrowserPopup(e){if("undefined"==typeof window||!window?.open)throw new ClientResponseError(new Error("Not in a browser context - please pass a custom urlCallback function."));let t=1024,s=768,i=window.innerWidth,n=window.innerHeight;t=t>i?i:t,s=s>n?n:s;let r=i/2-t/2,o=n/2-s/2;return window.open(e,"popup_window","width="+t+",height="+s+",top="+o+",left="+r+",resizable,menubar=no")}class CollectionService extends CrudService{get baseCrudPath(){return"/api/collections"}async import(e,t=!1,s){return s=Object.assign({method:"PUT",body:{collections:e,deleteMissing:t}},s),this.client.send(this.baseCrudPath+"/import",s).then((()=>!0))}async getScaffolds(e){return e=Object.assign({method:"GET"},e),this.client.send(this.baseCrudPath+"/meta/scaffolds",e)}async truncate(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(this.baseCrudPath+"/"+encodeURIComponent(e)+"/truncate",t).then((()=>!0))}}class LogService extends BaseService{async getList(e=1,t=30,s){return(s=Object.assign({method:"GET"},s)).query=Object.assign({page:e,perPage:t},s.query),this.client.send("/api/logs",s)}async getOne(e,t){if(!e)throw new ClientResponseError({url:this.client.buildURL("/api/logs/"),status:404,response:{code:404,message:"Missing required log id.",data:{}}});return t=Object.assign({method:"GET"},t),this.client.send("/api/logs/"+encodeURIComponent(e),t)}async getStats(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/logs/stats",e)}}class HealthService extends BaseService{async check(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/health",e)}}class FileService extends BaseService{getUrl(e,t,s={}){return console.warn("Please replace pb.files.getUrl() with pb.files.getURL()"),this.getURL(e,t,s)}getURL(e,t,s={}){if(!t||!e?.id||!e?.collectionId&&!e?.collectionName)return"";const i=[];i.push("api"),i.push("files"),i.push(encodeURIComponent(e.collectionId||e.collectionName)),i.push(encodeURIComponent(e.id)),i.push(encodeURIComponent(t));let n=this.client.buildURL(i.join("/"));if(Object.keys(s).length){!1===s.download&&delete s.download;const e=new URLSearchParams(s);n+=(n.includes("?")?"&":"?")+e}return n}async getToken(e){return e=Object.assign({method:"POST"},e),this.client.send("/api/files/token",e).then((e=>e?.token||""))}}class BackupService extends BaseService{async getFullList(e){return e=Object.assign({method:"GET"},e),this.client.send("/api/backups",e)}async create(e,t){return t=Object.assign({method:"POST",body:{name:e}},t),this.client.send("/api/backups",t).then((()=>!0))}async upload(e,t){return t=Object.assign({method:"POST",body:e},t),this.client.send("/api/backups/upload",t).then((()=>!0))}async delete(e,t){return t=Object.assign({method:"DELETE"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}`,t).then((()=>!0))}async restore(e,t){return t=Object.assign({method:"POST"},t),this.client.send(`/api/backups/${encodeURIComponent(e)}/restore`,t).then((()=>!0))}getDownloadUrl(e,t){return console.warn("Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()"),this.getDownloadURL(e,t)}getDownloadURL(e,t){return this.client.buildURL(`/api/backups/${encodeURIComponent(t)}?token=${encodeURIComponent(e)}`)}}function isFile(e){return"undefined"!=typeof Blob&&e instanceof Blob||"undefined"!=typeof File&&e instanceof File||null!==e&&"object"==typeof e&&e.uri&&("undefined"!=typeof navigator&&"ReactNative"===navigator.product||"undefined"!=typeof global&&global.HermesInternal)}function isFormData(e){return e&&("FormData"===e.constructor.name||"undefined"!=typeof FormData&&e instanceof FormData)}function hasFileField(e){for(const t in e){const s=Array.isArray(e[t])?e[t]:[e[t]];for(const e of s)if(isFile(e))return!0}return!1}class BatchService extends BaseService{constructor(){super(...arguments),this.requests=[],this.subs={}}collection(e){return this.subs[e]||(this.subs[e]=new SubBatchService(this.requests,e)),this.subs[e]}async send(e){const t=new FormData,s=[];for(let e=0;e0&&t.length==i.length){e.files[s]=e.files[s]||[];for(let i of t)e.files[s].push(i)}else if(e.json[s]=n,t.length>0){let i=s;s.startsWith("+")||s.endsWith("+")||(i+="+"),e.files[i]=e.files[i]||[];for(let s of t)e.files[i].push(s)}}else e.json[s]=i}}}class Client{get baseUrl(){return this.baseURL}set baseUrl(e){this.baseURL=e}constructor(e="/",t,s="en-US"){this.cancelControllers={},this.recordServices={},this.enableAutoCancellation=!0,this.baseURL=e,this.lang=s,t?this.authStore=t:"undefined"!=typeof window&&window.Deno?this.authStore=new BaseAuthStore:this.authStore=new LocalAuthStore,this.collections=new CollectionService(this),this.files=new FileService(this),this.logs=new LogService(this),this.settings=new SettingsService(this),this.realtime=new RealtimeService(this),this.health=new HealthService(this),this.backups=new BackupService(this)}get admins(){return this.collection("_superusers")}createBatch(){return new BatchService(this)}collection(e){return this.recordServices[e]||(this.recordServices[e]=new RecordService(this,e)),this.recordServices[e]}autoCancellation(e){return this.enableAutoCancellation=!!e,this}cancelRequest(e){return this.cancelControllers[e]&&(this.cancelControllers[e].abort(),delete this.cancelControllers[e]),this}cancelAllRequests(){for(let e in this.cancelControllers)this.cancelControllers[e].abort();return this.cancelControllers={},this}filter(e,t){if(!t)return e;for(let s in t){let i=t[s];switch(typeof i){case"boolean":case"number":i=""+i;break;case"string":i="'"+i.replace(/'/g,"\\'")+"'";break;default:i=null===i?"null":i instanceof Date?"'"+i.toISOString().replace("T"," ")+"'":"'"+JSON.stringify(i).replace(/'/g,"\\'")+"'"}e=e.replaceAll("{:"+s+"}",i)}return e}getFileUrl(e,t,s={}){return console.warn("Please replace pb.getFileUrl() with pb.files.getURL()"),this.files.getURL(e,t,s)}buildUrl(e){return console.warn("Please replace pb.buildUrl() with pb.buildURL()"),this.buildURL(e)}buildURL(e){let t=this.baseURL;return"undefined"==typeof window||!window.location||t.startsWith("https://")||t.startsWith("http://")||(t=window.location.origin?.endsWith("/")?window.location.origin.substring(0,window.location.origin.length-1):window.location.origin||"",this.baseURL.startsWith("/")||(t+=window.location.pathname||"/",t+=t.endsWith("/")?"":"/"),t+=this.baseURL),e&&(t+=t.endsWith("/")?"":"/",t+=e.startsWith("/")?e.substring(1):e),t}async send(e,t){t=this.initSendOptions(e,t);let s=this.buildURL(e);if(this.beforeSend){const e=Object.assign({},await this.beforeSend(s,t));void 0!==e.url||void 0!==e.options?(s=e.url||s,t=e.options||t):Object.keys(e).length&&(t=e,console?.warn&&console.warn("Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`."))}if(void 0!==t.query){const e=serializeQueryParams(t.query);e&&(s+=(s.includes("?")?"&":"?")+e),delete t.query}"application/json"==this.getHeader(t.headers,"Content-Type")&&t.body&&"string"!=typeof t.body&&(t.body=JSON.stringify(t.body));return(t.fetch||fetch)(s,t).then((async e=>{let s={};try{s=await e.json()}catch(e){}if(this.afterSend&&(s=await this.afterSend(e,s,t)),e.status>=400)throw new ClientResponseError({url:e.url,status:e.status,data:s});return s})).catch((e=>{throw new ClientResponseError(e)}))}initSendOptions(e,t){if((t=Object.assign({method:"GET"},t)).body=function convertToFormDataIfNeeded(e){if("undefined"==typeof FormData||void 0===e||"object"!=typeof e||null===e||isFormData(e)||!hasFileField(e))return e;const t=new FormData;for(const s in e){const i=e[s];if("object"!=typeof i||hasFileField({data:i})){const e=Array.isArray(i)?i:[i];for(let i of e)t.append(s,i)}else{let e={};e[s]=i,t.append("@jsonPayload",JSON.stringify(e))}}return t}(t.body),normalizeUnknownQueryParams(t),t.query=Object.assign({},t.params,t.query),void 0===t.requestKey&&(!1===t.$autoCancel||!1===t.query.$autoCancel?t.requestKey=null:(t.$cancelKey||t.query.$cancelKey)&&(t.requestKey=t.$cancelKey||t.query.$cancelKey)),delete t.$autoCancel,delete t.query.$autoCancel,delete t.$cancelKey,delete t.query.$cancelKey,null!==this.getHeader(t.headers,"Content-Type")||isFormData(t.body)||(t.headers=Object.assign({},t.headers,{"Content-Type":"application/json"})),null===this.getHeader(t.headers,"Accept-Language")&&(t.headers=Object.assign({},t.headers,{"Accept-Language":this.lang})),this.authStore.token&&null===this.getHeader(t.headers,"Authorization")&&(t.headers=Object.assign({},t.headers,{Authorization:this.authStore.token})),this.enableAutoCancellation&&null!==t.requestKey){const s=t.requestKey||(t.method||"GET")+e;delete t.requestKey,this.cancelRequest(s);const i=new AbortController;this.cancelControllers[s]=i,t.signal=i.signal}return t}getHeader(e,t){e=e||{},t=t.toLowerCase();for(let s in e)if(s.toLowerCase()==t)return e[s];return null}}return Client})); //# sourceMappingURL=pocketbase.umd.js.map diff --git a/dist/pocketbase.umd.js.map b/dist/pocketbase.umd.js.map index 33cf026..0170ac2 100644 --- a/dist/pocketbase.umd.js.map +++ b/dist/pocketbase.umd.js.map @@ -1 +1 @@ -{"version":3,"file":"pocketbase.umd.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieSerialize","val","options","opt","assign","encode","defaultEncode","test","TypeError","value","result","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","defaultDecode","indexOf","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","charCodeAt","slice","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","length","exp","now","atob","input","str","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","key","rawData","cookieParse","decode","index","eqIdx","endIdx","lastIndexOf","trim","undefined","_","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"pocketbase.umd.js","sources":["../src/ClientResponseError.ts","../src/tools/cookie.ts","../src/tools/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/BaseService.ts","../src/services/SettingsService.ts","../src/tools/options.ts","../src/services/RealtimeService.ts","../src/services/CrudService.ts","../src/tools/legacy.ts","../src/tools/refresh.ts","../src/services/RecordService.ts","../src/services/CollectionService.ts","../src/services/LogService.ts","../src/services/HealthService.ts","../src/services/FileService.ts","../src/services/BackupService.ts","../src/tools/formdata.ts","../src/services/BatchService.ts","../src/Client.ts"],"sourcesContent":["/**\n * ClientResponseError is a custom Error class that is intended to wrap\n * and normalize any error thrown by `Client.send()`.\n */\nexport class ClientResponseError extends Error {\n url: string = \"\";\n status: number = 0;\n response: { [key: string]: any } = {};\n isAbort: boolean = false;\n originalError: any = null;\n\n constructor(errData?: any) {\n super(\"ClientResponseError\");\n\n // Set the prototype explicitly.\n // https://github.com/Microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work\n Object.setPrototypeOf(this, ClientResponseError.prototype);\n\n if (errData !== null && typeof errData === \"object\") {\n this.url = typeof errData.url === \"string\" ? errData.url : \"\";\n this.status = typeof errData.status === \"number\" ? errData.status : 0;\n this.isAbort = !!errData.isAbort;\n this.originalError = errData.originalError;\n\n if (errData.response !== null && typeof errData.response === \"object\") {\n this.response = errData.response;\n } else if (errData.data !== null && typeof errData.data === \"object\") {\n this.response = errData.data;\n } else {\n this.response = {};\n }\n }\n\n if (!this.originalError && !(errData instanceof ClientResponseError)) {\n this.originalError = errData;\n }\n\n if (typeof DOMException !== \"undefined\" && errData instanceof DOMException) {\n this.isAbort = true;\n }\n\n this.name = \"ClientResponseError \" + this.status;\n this.message = this.response?.message;\n if (!this.message) {\n if (this.isAbort) {\n this.message =\n \"The request was autocancelled. You can find more info in https://github.com/pocketbase/js-sdk#auto-cancellation.\";\n } else if (this.originalError?.cause?.message?.includes(\"ECONNREFUSED ::1\")) {\n this.message =\n \"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).\";\n } else {\n this.message = \"Something went wrong while processing your request.\";\n }\n }\n }\n\n /**\n * Alias for `this.response` for backward compatibility.\n */\n get data() {\n return this.response;\n }\n\n /**\n * Make a POJO's copy of the current error class instance.\n * @see https://github.com/vuex-orm/vuex-orm/issues/255\n */\n toJSON() {\n return { ...this };\n }\n}\n","/**\n * -------------------------------------------------------------------\n * Simple cookie parse and serialize utilities mostly based on the\n * node module https://github.com/jshttp/cookie.\n * -------------------------------------------------------------------\n */\n\n/**\n * RegExp to match field-content in RFC 7230 sec 3.2\n *\n * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]\n * field-vchar = VCHAR / obs-text\n * obs-text = %x80-FF\n */\nconst fieldContentRegExp = /^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;\n\nexport interface ParseOptions {\n decode?: (val: string) => string;\n}\n\n/**\n * Parses the given cookie header string into an object\n * The object has the various cookies as keys(names) => values\n */\nexport function cookieParse(str: string, options?: ParseOptions): { [key: string]: any } {\n const result: { [key: string]: any } = {};\n\n if (typeof str !== \"string\") {\n return result;\n }\n\n const opt = Object.assign({}, options || {});\n const decode = opt.decode || defaultDecode;\n\n let index = 0;\n while (index < str.length) {\n const eqIdx = str.indexOf(\"=\", index);\n\n // no more cookie pairs\n if (eqIdx === -1) {\n break;\n }\n\n let endIdx = str.indexOf(\";\", index);\n\n if (endIdx === -1) {\n endIdx = str.length;\n } else if (endIdx < eqIdx) {\n // backtrack on prior semicolon\n index = str.lastIndexOf(\";\", eqIdx - 1) + 1;\n continue;\n }\n\n const key = str.slice(index, eqIdx).trim();\n\n // only assign once\n if (undefined === result[key]) {\n let val = str.slice(eqIdx + 1, endIdx).trim();\n\n // quoted values\n if (val.charCodeAt(0) === 0x22) {\n val = val.slice(1, -1);\n }\n\n try {\n result[key] = decode(val);\n } catch (_) {\n result[key] = val; // no decoding\n }\n }\n\n index = endIdx + 1;\n }\n\n return result;\n}\n\nexport interface SerializeOptions {\n encode?: (val: string | number | boolean) => string;\n maxAge?: number;\n domain?: string;\n path?: string;\n expires?: Date;\n httpOnly?: boolean;\n secure?: boolean;\n priority?: string;\n sameSite?: boolean | string;\n}\n\n/**\n * Serialize data into a cookie header.\n *\n * Serialize the a name value pair into a cookie string suitable for\n * http headers. An optional options object specified cookie parameters.\n *\n * ```js\n * cookieSerialize('foo', 'bar', { httpOnly: true }) // \"foo=bar; httpOnly\"\n * ```\n */\nexport function cookieSerialize(\n name: string,\n val: string,\n options?: SerializeOptions,\n): string {\n const opt = Object.assign({}, options || {});\n const encode = opt.encode || defaultEncode;\n\n if (!fieldContentRegExp.test(name)) {\n throw new TypeError(\"argument name is invalid\");\n }\n\n const value = encode(val);\n\n if (value && !fieldContentRegExp.test(value)) {\n throw new TypeError(\"argument val is invalid\");\n }\n\n let result = name + \"=\" + value;\n\n if (opt.maxAge != null) {\n const maxAge = opt.maxAge - 0;\n\n if (isNaN(maxAge) || !isFinite(maxAge)) {\n throw new TypeError(\"option maxAge is invalid\");\n }\n\n result += \"; Max-Age=\" + Math.floor(maxAge);\n }\n\n if (opt.domain) {\n if (!fieldContentRegExp.test(opt.domain)) {\n throw new TypeError(\"option domain is invalid\");\n }\n\n result += \"; Domain=\" + opt.domain;\n }\n\n if (opt.path) {\n if (!fieldContentRegExp.test(opt.path)) {\n throw new TypeError(\"option path is invalid\");\n }\n\n result += \"; Path=\" + opt.path;\n }\n\n if (opt.expires) {\n if (!isDate(opt.expires) || isNaN(opt.expires.valueOf())) {\n throw new TypeError(\"option expires is invalid\");\n }\n\n result += \"; Expires=\" + opt.expires.toUTCString();\n }\n\n if (opt.httpOnly) {\n result += \"; HttpOnly\";\n }\n\n if (opt.secure) {\n result += \"; Secure\";\n }\n\n if (opt.priority) {\n const priority =\n typeof opt.priority === \"string\" ? opt.priority.toLowerCase() : opt.priority;\n\n switch (priority) {\n case \"low\":\n result += \"; Priority=Low\";\n break;\n case \"medium\":\n result += \"; Priority=Medium\";\n break;\n case \"high\":\n result += \"; Priority=High\";\n break;\n default:\n throw new TypeError(\"option priority is invalid\");\n }\n }\n\n if (opt.sameSite) {\n const sameSite =\n typeof opt.sameSite === \"string\" ? opt.sameSite.toLowerCase() : opt.sameSite;\n\n switch (sameSite) {\n case true:\n result += \"; SameSite=Strict\";\n break;\n case \"lax\":\n result += \"; SameSite=Lax\";\n break;\n case \"strict\":\n result += \"; SameSite=Strict\";\n break;\n case \"none\":\n result += \"; SameSite=None\";\n break;\n default:\n throw new TypeError(\"option sameSite is invalid\");\n }\n }\n\n return result;\n}\n\n/**\n * Default URL-decode string value function.\n * Optimized to skip native call when no `%`.\n */\nfunction defaultDecode(val: string): string {\n return val.indexOf(\"%\") !== -1 ? decodeURIComponent(val) : val;\n}\n\n/**\n * Default URL-encode value function.\n */\nfunction defaultEncode(val: string | number | boolean): string {\n return encodeURIComponent(val);\n}\n\n/**\n * Determines if value is a Date.\n */\nfunction isDate(val: any): boolean {\n return Object.prototype.toString.call(val) === \"[object Date]\" || val instanceof Date;\n}\n","// @todo remove after https://github.com/reactwg/react-native-releases/issues/287\nconst isReactNative =\n (typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal);\n\nlet atobPolyfill: Function;\nif (typeof atob === \"function\" && !isReactNative) {\n atobPolyfill = atob;\n} else {\n /**\n * The code was extracted from:\n * https://github.com/davidchambers/Base64.js\n */\n atobPolyfill = (input: any) => {\n const chars = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\";\n\n let str = String(input).replace(/=+$/, \"\");\n if (str.length % 4 == 1) {\n throw new Error(\n \"'atob' failed: The string to be decoded is not correctly encoded.\",\n );\n }\n\n for (\n // initialize result and counters\n var bc = 0, bs, buffer, idx = 0, output = \"\";\n // get next character\n (buffer = str.charAt(idx++));\n // character found in table? initialize bit storage and add its ascii value;\n ~buffer &&\n ((bs = bc % 4 ? (bs as any) * 64 + buffer : buffer),\n // and if not first of each 4 characters,\n // convert the first 8 bits to one ascii character\n bc++ % 4)\n ? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))\n : 0\n ) {\n // try to find character in table (0-63, not found => -1)\n buffer = chars.indexOf(buffer);\n }\n\n return output;\n };\n}\n\n/**\n * Returns JWT token's payload data.\n */\nexport function getTokenPayload(token: string): { [key: string]: any } {\n if (token) {\n try {\n const encodedPayload = decodeURIComponent(\n atobPolyfill(token.split(\".\")[1])\n .split(\"\")\n .map(function (c: string) {\n return \"%\" + (\"00\" + c.charCodeAt(0).toString(16)).slice(-2);\n })\n .join(\"\"),\n );\n\n return JSON.parse(encodedPayload) || {};\n } catch (e) {}\n }\n\n return {};\n}\n\n/**\n * Checks whether a JWT token is expired or not.\n * Tokens without `exp` payload key are considered valid.\n * Tokens with empty payload (eg. invalid token strings) are considered expired.\n *\n * @param token The token to check.\n * @param [expirationThreshold] Time in seconds that will be subtracted from the token `exp` property.\n */\nexport function isTokenExpired(token: string, expirationThreshold = 0): boolean {\n let payload = getTokenPayload(token);\n\n if (\n Object.keys(payload).length > 0 &&\n (!payload.exp || payload.exp - expirationThreshold > Date.now() / 1000)\n ) {\n return false;\n }\n\n return true;\n}\n","import { cookieParse, cookieSerialize, SerializeOptions } from \"@/tools/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/tools/jwt\";\nimport { RecordModel } from \"@/tools/dtos\";\n\nexport type AuthRecord = RecordModel | null;\n\nexport type AuthModel = AuthRecord; // for backward compatibility\n\nexport type OnStoreChangeFunc = (token: string, record: AuthRecord) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that stores the auth state in runtime memory (aka. only for the duration of the store instane).\n *\n * Usually you wouldn't use it directly and instead use the builtin LocalAuthStore, AsyncAuthStore\n * or extend it with your own custom implementation.\n */\nexport class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthRecord = null;\n\n private _onChangeCallbacks: Array = [];\n\n /**\n * Retrieves the stored token (if any).\n */\n get token(): string {\n return this.baseToken;\n }\n\n /**\n * Retrieves the stored model data (if any).\n */\n get record(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.baseModel;\n }\n\n /**\n * Loosely checks if the store has valid token (aka. existing and unexpired exp claim).\n */\n get isValid(): boolean {\n return !isTokenExpired(this.token);\n }\n\n /**\n * Loosely checks whether the currently loaded store state is for superuser.\n *\n * Alternatively you can also compare directly `pb.authStore.record?.collectionName`.\n */\n get isSuperuser(): boolean {\n let payload = getTokenPayload(this.token)\n\n return payload.type == \"auth\" && (\n this.record?.collectionName == \"_superusers\" ||\n // fallback in case the record field is not populated and assuming\n // that the collection crc32 checksum id wasn't manually changed\n (!this.record?.collectionName && payload.collectionId == \"pbc_3142635823\")\n );\n }\n\n /**\n * @deprecated use `isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAdmin(): boolean {\n console.warn(\"Please replace pb.authStore.isAdmin with pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return this.isSuperuser;\n }\n\n /**\n * @deprecated use `!isSuperuser` instead or simply check the record.collectionName property.\n */\n get isAuthRecord(): boolean {\n console.warn(\"Please replace pb.authStore.isAuthRecord with !pb.authStore.isSuperuser OR simply check the value of pb.authStore.record?.collectionName\");\n return getTokenPayload(this.token).type == \"auth\" && !this.isSuperuser;\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, record?: AuthRecord): void {\n this.baseToken = token || \"\";\n this.baseModel = record || null;\n\n this.triggerChange();\n }\n\n /**\n * Removes the stored token and model data form the auth store.\n */\n clear(): void {\n this.baseToken = \"\";\n this.baseModel = null;\n this.triggerChange();\n }\n\n /**\n * Parses the provided cookie string and updates the store state\n * with the cookie's token and model data.\n *\n * NB! This function doesn't validate the token or its data.\n * Usually this isn't a concern if you are interacting only with the\n * PocketBase API because it has the proper server-side security checks in place,\n * but if you are using the store `isValid` state for permission controls\n * in a node server (eg. SSR), then it is recommended to call `authRefresh()`\n * after loading the cookie to ensure an up-to-date token and model state.\n * For example:\n *\n * ```js\n * pb.authStore.loadFromCookie(\"cookie string...\");\n *\n * try {\n * // get an up-to-date auth store state by veryfing and refreshing the loaded auth model (if any)\n * pb.authStore.isValid && await pb.collection('users').authRefresh();\n * } catch (_) {\n * // clear the auth store on failed refresh\n * pb.authStore.clear();\n * }\n * ```\n */\n loadFromCookie(cookie: string, key = defaultCookieKey): void {\n const rawData = cookieParse(cookie || \"\")[key] || \"\";\n\n let data: { [key: string]: any } = {};\n try {\n data = JSON.parse(rawData);\n // normalize\n if (typeof data === null || typeof data !== \"object\" || Array.isArray(data)) {\n data = {};\n }\n } catch (_) {}\n\n this.save(data.token || \"\", data.record || data.model || null);\n }\n\n /**\n * Exports the current store state as cookie string.\n *\n * By default the following optional attributes are added:\n * - Secure\n * - HttpOnly\n * - SameSite=Strict\n * - Path=/\n * - Expires={the token expiration date}\n *\n * NB! If the generated cookie exceeds 4096 bytes, this method will\n * strip the model data to the bare minimum to try to fit within the\n * recommended size in https://www.rfc-editor.org/rfc/rfc6265#section-6.1.\n */\n exportToCookie(options?: SerializeOptions, key = defaultCookieKey): string {\n const defaultOptions: SerializeOptions = {\n secure: true,\n sameSite: true,\n httpOnly: true,\n path: \"/\",\n };\n\n // extract the token expiration date\n const payload = getTokenPayload(this.token);\n if (payload?.exp) {\n defaultOptions.expires = new Date(payload.exp * 1000);\n } else {\n defaultOptions.expires = new Date(\"1970-01-01\");\n }\n\n // merge with the user defined options\n options = Object.assign({}, defaultOptions, options);\n\n const rawData = {\n token: this.token,\n record: this.record ? JSON.parse(JSON.stringify(this.record)) : null,\n };\n\n let result = cookieSerialize(key, JSON.stringify(rawData), options);\n\n const resultLength =\n typeof Blob !== \"undefined\" ? new Blob([result]).size : result.length;\n\n // strip down the model data to the bare minimum\n if (rawData.record && resultLength > 4096) {\n rawData.record = { id: rawData.record?.id, email: rawData.record?.email };\n const extraProps = [\"collectionId\", \"collectionName\", \"verified\"];\n for (const prop in this.record) {\n if (extraProps.includes(prop)) {\n rawData.record[prop] = this.record[prop];\n }\n }\n result = cookieSerialize(key, JSON.stringify(rawData), options);\n }\n\n return result;\n }\n\n /**\n * Register a callback function that will be called on store change.\n *\n * You can set the `fireImmediately` argument to true in order to invoke\n * the provided callback right after registration.\n *\n * Returns a removal function that you could call to \"unsubscribe\" from the changes.\n */\n onChange(callback: OnStoreChangeFunc, fireImmediately = false): () => void {\n this._onChangeCallbacks.push(callback);\n\n if (fireImmediately) {\n callback(this.token, this.record);\n }\n\n return () => {\n for (let i = this._onChangeCallbacks.length - 1; i >= 0; i--) {\n if (this._onChangeCallbacks[i] == callback) {\n delete this._onChangeCallbacks[i]; // removes the function reference\n this._onChangeCallbacks.splice(i, 1); // reindex the array\n return;\n }\n }\n };\n }\n\n protected triggerChange(): void {\n for (const callback of this._onChangeCallbacks) {\n callback && callback(this.token, this.record);\n }\n }\n}\n","import { BaseAuthStore, AuthRecord } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (e.g. in node env).\n */\nexport class LocalAuthStore extends BaseAuthStore {\n private storageFallback: { [key: string]: any } = {};\n private storageKey: string;\n\n constructor(storageKey = \"pocketbase_auth\") {\n super();\n\n this.storageKey = storageKey;\n\n this._bindStorageEvent();\n }\n\n /**\n * @inheritdoc\n */\n get token(): string {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.token || \"\";\n }\n\n /**\n * @inheritdoc\n */\n get record(): AuthRecord {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.record || data.model || null;\n }\n\n /**\n * @deprecated use `record` instead.\n */\n get model(): AuthRecord {\n return this.record;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, record?: AuthRecord) {\n this._storageSet(this.storageKey, {\n token: token,\n record: record,\n });\n\n super.save(token, record);\n }\n\n /**\n * @inheritdoc\n */\n clear() {\n this._storageRemove(this.storageKey);\n\n super.clear();\n }\n\n // ---------------------------------------------------------------\n // Internal helpers:\n // ---------------------------------------------------------------\n\n /**\n * Retrieves `key` from the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageGet(key: string): any {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n const rawValue = window.localStorage.getItem(key) || \"\";\n try {\n return JSON.parse(rawValue);\n } catch (e) {\n // not a json\n return rawValue;\n }\n }\n\n // fallback\n return this.storageFallback[key];\n }\n\n /**\n * Stores a new data in the browser's local storage\n * (or runtime/memory if local storage is undefined).\n */\n private _storageSet(key: string, value: any) {\n if (typeof window !== \"undefined\" && window?.localStorage) {\n // store in local storage\n let normalizedVal = value;\n if (typeof value !== \"string\") {\n normalizedVal = JSON.stringify(value);\n }\n window.localStorage.setItem(key, normalizedVal);\n } else {\n // store in fallback\n this.storageFallback[key] = value;\n }\n }\n\n /**\n * Removes `key` from the browser's local storage and the runtime/memory.\n */\n private _storageRemove(key: string) {\n // delete from local storage\n if (typeof window !== \"undefined\" && window?.localStorage) {\n window.localStorage?.removeItem(key);\n }\n\n // delete from fallback\n delete this.storageFallback[key];\n }\n\n /**\n * Updates the current store state on localStorage change.\n */\n private _bindStorageEvent() {\n if (\n typeof window === \"undefined\" ||\n !window?.localStorage ||\n !window.addEventListener\n ) {\n return;\n }\n\n window.addEventListener(\"storage\", (e) => {\n if (e.key != this.storageKey) {\n return;\n }\n\n const data = this._storageGet(this.storageKey) || {};\n\n super.save(data.token || \"\", data.record || data.model || null);\n });\n }\n}\n","import Client from \"@/Client\";\n\n/**\n * BaseService class that should be inherited from all API services.\n */\nexport abstract class BaseService {\n readonly client: Client;\n\n constructor(client: Client) {\n this.client = client;\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\ninterface appleClientSecret {\n secret: string;\n}\n\nexport class SettingsService extends BaseService {\n /**\n * Fetch all available app settings.\n *\n * @throws {ClientResponseError}\n */\n async getAll(options?: CommonOptions): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Bulk updates app settings.\n *\n * @throws {ClientResponseError}\n */\n async update(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise<{ [key: string]: any }> {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/settings\", options);\n }\n\n /**\n * Performs a S3 filesystem connection test.\n *\n * The currently supported `filesystem` are \"storage\" and \"backups\".\n *\n * @throws {ClientResponseError}\n */\n async testS3(\n filesystem: string = \"storage\",\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n filesystem: filesystem,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/s3\", options).then(() => true);\n }\n\n /**\n * Sends a test email.\n *\n * The possible `emailTemplate` values are:\n * - verification\n * - password-reset\n * - email-change\n *\n * @throws {ClientResponseError}\n */\n async testEmail(\n collectionIdOrName: string,\n toEmail: string,\n emailTemplate: string,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n email: toEmail,\n template: emailTemplate,\n collection: collectionIdOrName,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/test/email\", options).then(() => true);\n }\n\n /**\n * Generates a new Apple OAuth2 client secret.\n *\n * @throws {ClientResponseError}\n */\n async generateAppleClientSecret(\n clientId: string,\n teamId: string,\n keyId: string,\n privateKey: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n clientId,\n teamId,\n keyId,\n privateKey,\n duration,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/settings/apple/generate-client-secret\", options);\n }\n}\n","export interface SendOptions extends RequestInit {\n // for backward compatibility and to minimize the verbosity,\n // any top-level field that doesn't exist in RequestInit or the\n // fields below will be treated as query parameter.\n [key: string]: any;\n\n /**\n * Optional custom fetch function to use for sending the request.\n */\n fetch?: (url: RequestInfo | URL, config?: RequestInit) => Promise;\n\n /**\n * Custom headers to send with the requests.\n */\n headers?: { [key: string]: string };\n\n /**\n * The body of the request (serialized automatically for json requests).\n */\n body?: any;\n\n /**\n * Query parameters that will be appended to the request url.\n */\n query?: { [key: string]: any };\n\n /**\n * @deprecated use `query` instead\n *\n * for backward-compatibility `params` values are merged with `query`,\n * but this option may get removed in the final v1 release\n */\n params?: { [key: string]: any };\n\n /**\n * The request identifier that can be used to cancel pending requests.\n */\n requestKey?: string | null;\n\n /**\n * @deprecated use `requestKey:string` instead\n */\n $cancelKey?: string;\n\n /**\n * @deprecated use `requestKey:null` instead\n */\n $autoCancel?: boolean;\n}\n\nexport interface CommonOptions extends SendOptions {\n fields?: string;\n}\n\nexport interface ListOptions extends CommonOptions {\n page?: number;\n perPage?: number;\n sort?: string;\n filter?: string;\n skipTotal?: boolean;\n}\n\nexport interface FullListOptions extends ListOptions {\n batch?: number;\n}\n\nexport interface RecordOptions extends CommonOptions {\n expand?: string;\n}\n\nexport interface RecordListOptions extends ListOptions, RecordOptions {}\n\nexport interface RecordFullListOptions extends FullListOptions, RecordOptions {}\n\nexport interface RecordSubscribeOptions extends SendOptions {\n fields?: string;\n filter?: string;\n expand?: string;\n}\n\nexport interface LogStatsOptions extends CommonOptions {\n filter?: string;\n}\n\nexport interface FileOptions extends CommonOptions {\n thumb?: string;\n download?: boolean;\n}\n\nexport interface AuthOptions extends CommonOptions {\n /**\n * If autoRefreshThreshold is set it will take care to auto refresh\n * when necessary the auth data before each request to ensure that\n * the auth state is always valid.\n *\n * The value must be in seconds, aka. the amount of seconds\n * that will be subtracted from the current token `exp` claim in order\n * to determine whether it is going to expire within the specified time threshold.\n *\n * For example, if you want to auto refresh the token if it is\n * going to expire in the next 30mins (or already has expired),\n * it can be set to `1800`\n */\n autoRefreshThreshold?: number;\n}\n\n// -------------------------------------------------------------------\n\n// list of known SendOptions keys (everything else is treated as query param)\nconst knownSendOptionsKeys = [\n \"requestKey\",\n \"$cancelKey\",\n \"$autoCancel\",\n \"fetch\",\n \"headers\",\n \"body\",\n \"query\",\n \"params\",\n // ---,\n \"cache\",\n \"credentials\",\n \"headers\",\n \"integrity\",\n \"keepalive\",\n \"method\",\n \"mode\",\n \"redirect\",\n \"referrer\",\n \"referrerPolicy\",\n \"signal\",\n \"window\",\n];\n\n// modifies in place the provided options by moving unknown send options as query parameters.\nexport function normalizeUnknownQueryParams(options?: SendOptions): void {\n if (!options) {\n return;\n }\n\n options.query = options.query || {};\n for (let key in options) {\n if (knownSendOptionsKeys.includes(key)) {\n continue;\n }\n\n options.query[key] = options[key];\n delete options[key];\n }\n}\n\nexport function serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\n\n for (const key in params) {\n if (params[key] === null) {\n // skip null query params\n continue;\n }\n\n const value = params[key];\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n // repeat array params\n for (const v of value) {\n result.push(encodedKey + \"=\" + encodeURIComponent(v));\n }\n } else if (value instanceof Date) {\n result.push(encodedKey + \"=\" + encodeURIComponent(value.toISOString()));\n } else if (typeof value !== null && typeof value === \"object\") {\n result.push(encodedKey + \"=\" + encodeURIComponent(JSON.stringify(value)));\n } else {\n result.push(encodedKey + \"=\" + encodeURIComponent(value));\n }\n }\n\n return result.join(\"&\");\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/tools/options\";\n\ninterface promiseCallbacks {\n resolve: Function;\n reject: Function;\n}\n\ntype Subscriptions = { [key: string]: Array };\n\nexport type UnsubscribeFunc = () => Promise;\n\nexport class RealtimeService extends BaseService {\n clientId: string = \"\";\n\n private eventSource: EventSource | null = null;\n private subscriptions: Subscriptions = {};\n private lastSentSubscriptions: Array = [];\n private connectTimeoutId: any;\n private maxConnectTimeout: number = 15000;\n private reconnectTimeoutId: any;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = Infinity;\n private predefinedReconnectIntervals: Array = [\n 200, 300, 500, 1000, 1200, 1500, 2000,\n ];\n private pendingConnects: Array = [];\n\n /**\n * Returns whether the realtime connection has been established.\n */\n get isConnected(): boolean {\n return !!this.eventSource && !!this.clientId && !this.pendingConnects.length;\n }\n\n /**\n * An optional hook that is invoked when the realtime client disconnects\n * either when unsubscribing from all subscriptions or when the\n * connection was interrupted or closed by the server.\n *\n * The received argument could be used to determine whether the disconnect\n * is a result from unsubscribing (`activeSubscriptions.length == 0`)\n * or because of network/server error (`activeSubscriptions.length > 0`).\n *\n * If you want to listen for the opposite, aka. when the client connection is established,\n * subscribe to the `PB_CONNECT` event.\n */\n onDisconnect?: (activeSubscriptions: Array) => void;\n\n /**\n * Register the subscription listener.\n *\n * You can subscribe multiple times to the same topic.\n *\n * If the SSE connection is not started yet,\n * this method will also initialize it.\n */\n async subscribe(\n topic: string,\n callback: (data: any) => void,\n options?: SendOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"topic must be set.\");\n }\n\n let key = topic;\n\n // serialize and append the topic options (if any)\n if (options) {\n options = Object.assign({}, options); // shallow copy\n normalizeUnknownQueryParams(options);\n const serialized =\n \"options=\" +\n encodeURIComponent(\n JSON.stringify({ query: options.query, headers: options.headers }),\n );\n key += (key.includes(\"?\") ? \"&\" : \"?\") + serialized;\n }\n\n const listener = function (e: Event) {\n const msgEvent = e as MessageEvent;\n\n let data;\n try {\n data = JSON.parse(msgEvent?.data);\n } catch {}\n\n callback(data || {});\n };\n\n // store the listener\n if (!this.subscriptions[key]) {\n this.subscriptions[key] = [];\n }\n this.subscriptions[key].push(listener);\n\n if (!this.isConnected) {\n // initialize sse connection\n await this.connect();\n } else if (this.subscriptions[key].length === 1) {\n // send the updated subscriptions (if it is the first for the key)\n await this.submitSubscriptions();\n } else {\n // only register the listener\n this.eventSource?.addEventListener(key, listener);\n }\n\n return async (): Promise => {\n return this.unsubscribeByTopicAndListener(topic, listener);\n };\n }\n\n /**\n * Unsubscribe from all subscription listeners with the specified topic.\n *\n * If `topic` is not provided, then this method will unsubscribe\n * from all active subscriptions.\n *\n * This method is no-op if there are no active subscriptions.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribe(topic?: string): Promise {\n let needToSubmit = false;\n\n if (!topic) {\n // remove all subscriptions\n this.subscriptions = {};\n } else {\n // remove all listeners related to the topic\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (!this.hasSubscriptionListeners(key)) {\n continue; // already unsubscribed\n }\n\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit) {\n needToSubmit = true;\n }\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n /**\n * Unsubscribe from all subscription listeners starting with the specified topic prefix.\n *\n * This method is no-op if there are no active subscriptions with the specified topic prefix.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByPrefix(keyPrefix: string): Promise {\n let hasAtleastOneTopic = false;\n for (let key in this.subscriptions) {\n // \"?\" so that it can be used as end delimiter for the prefix\n if (!(key + \"?\").startsWith(keyPrefix)) {\n continue;\n }\n\n hasAtleastOneTopic = true;\n for (let listener of this.subscriptions[key]) {\n this.eventSource?.removeEventListener(key, listener);\n }\n delete this.subscriptions[key];\n }\n\n if (!hasAtleastOneTopic) {\n return; // nothing to unsubscribe from\n }\n\n if (this.hasSubscriptionListeners()) {\n // submit the deleted subscriptions\n await this.submitSubscriptions();\n } else {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n }\n }\n\n /**\n * Unsubscribe from all subscriptions matching the specified topic and listener function.\n *\n * This method is no-op if there are no active subscription with\n * the specified topic and listener.\n *\n * The related sse connection will be autoclosed if after the\n * unsubscribe operation there are no active subscriptions left.\n */\n async unsubscribeByTopicAndListener(\n topic: string,\n listener: EventListener,\n ): Promise {\n let needToSubmit = false;\n\n const subs = this.getSubscriptionsByTopic(topic);\n for (let key in subs) {\n if (\n !Array.isArray(this.subscriptions[key]) ||\n !this.subscriptions[key].length\n ) {\n continue; // already unsubscribed\n }\n\n let exist = false;\n for (let i = this.subscriptions[key].length - 1; i >= 0; i--) {\n if (this.subscriptions[key][i] !== listener) {\n continue;\n }\n\n exist = true; // has at least one matching listener\n delete this.subscriptions[key][i]; // removes the function reference\n this.subscriptions[key].splice(i, 1); // reindex the array\n this.eventSource?.removeEventListener(key, listener);\n }\n if (!exist) {\n continue;\n }\n\n // remove the key from the subscriptions list if there are no other listeners\n if (!this.subscriptions[key].length) {\n delete this.subscriptions[key];\n }\n\n // mark for subscriptions change submit if there are no other listeners\n if (!needToSubmit && !this.hasSubscriptionListeners(key)) {\n needToSubmit = true;\n }\n }\n\n if (!this.hasSubscriptionListeners()) {\n // no other active subscriptions -> close the sse connection\n this.disconnect();\n } else if (needToSubmit) {\n await this.submitSubscriptions();\n }\n }\n\n private hasSubscriptionListeners(keyToCheck?: string): boolean {\n this.subscriptions = this.subscriptions || {};\n\n // check the specified key\n if (keyToCheck) {\n return !!this.subscriptions[keyToCheck]?.length;\n }\n\n // check for at least one non-empty subscription\n for (let key in this.subscriptions) {\n if (!!this.subscriptions[key]?.length) {\n return true;\n }\n }\n\n return false;\n }\n\n private async submitSubscriptions(): Promise {\n if (!this.clientId) {\n return; // no client/subscriber\n }\n\n // optimistic update\n this.addAllSubscriptionListeners();\n\n this.lastSentSubscriptions = this.getNonEmptySubscriptionKeys();\n\n return this.client\n .send(\"/api/realtime\", {\n method: \"POST\",\n body: {\n clientId: this.clientId,\n subscriptions: this.lastSentSubscriptions,\n },\n requestKey: this.getSubscriptionsCancelKey(),\n })\n .catch((err) => {\n if (err?.isAbort) {\n return; // silently ignore aborted pending requests\n }\n throw err;\n });\n }\n\n private getSubscriptionsCancelKey(): string {\n return \"realtime_\" + this.clientId;\n }\n\n private getSubscriptionsByTopic(topic: string): Subscriptions {\n const result: Subscriptions = {};\n\n // \"?\" so that it can be used as end delimiter for the topic\n topic = topic.includes(\"?\") ? topic : topic + \"?\";\n\n for (let key in this.subscriptions) {\n if ((key + \"?\").startsWith(topic)) {\n result[key] = this.subscriptions[key];\n }\n }\n\n return result;\n }\n\n private getNonEmptySubscriptionKeys(): Array {\n const result: Array = [];\n\n for (let key in this.subscriptions) {\n if (this.subscriptions[key].length) {\n result.push(key);\n }\n }\n\n return result;\n }\n\n private addAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n this.removeAllSubscriptionListeners();\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.addEventListener(key, listener);\n }\n }\n }\n\n private removeAllSubscriptionListeners(): void {\n if (!this.eventSource) {\n return;\n }\n\n for (let key in this.subscriptions) {\n for (let listener of this.subscriptions[key]) {\n this.eventSource.removeEventListener(key, listener);\n }\n }\n }\n\n private async connect(): Promise {\n if (this.reconnectAttempts > 0) {\n // immediately resolve the promise to avoid indefinitely\n // blocking the client during reconnection\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.pendingConnects.push({ resolve, reject });\n\n if (this.pendingConnects.length > 1) {\n // all promises will be resolved once the connection is established\n return;\n }\n\n this.initConnect();\n });\n }\n\n private initConnect() {\n this.disconnect(true);\n\n // wait up to 15s for connect\n clearTimeout(this.connectTimeoutId);\n this.connectTimeoutId = setTimeout(() => {\n this.connectErrorHandler(new Error(\"EventSource connect took too long.\"));\n }, this.maxConnectTimeout);\n\n this.eventSource = new EventSource(this.client.buildURL(\"/api/realtime\"));\n\n this.eventSource.onerror = (_) => {\n this.connectErrorHandler(\n new Error(\"Failed to establish realtime connection.\"),\n );\n };\n\n this.eventSource.addEventListener(\"PB_CONNECT\", (e) => {\n const msgEvent = e as MessageEvent;\n this.clientId = msgEvent?.lastEventId;\n\n this.submitSubscriptions()\n .then(async () => {\n let retries = 3;\n while (this.hasUnsentSubscriptions() && retries > 0) {\n retries--;\n // resubscribe to ensure that the latest topics are submitted\n //\n // This is needed because missed topics could happen on reconnect\n // if after the pending sent `submitSubscriptions()` call another `subscribe()`\n // was made before the submit was able to complete.\n await this.submitSubscriptions();\n }\n })\n .then(() => {\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n\n // reset connect meta\n this.pendingConnects = [];\n this.reconnectAttempts = 0;\n clearTimeout(this.reconnectTimeoutId);\n clearTimeout(this.connectTimeoutId);\n\n // propagate the PB_CONNECT event\n const connectSubs = this.getSubscriptionsByTopic(\"PB_CONNECT\");\n for (let key in connectSubs) {\n for (let listener of connectSubs[key]) {\n listener(e);\n }\n }\n })\n .catch((err) => {\n this.clientId = \"\";\n this.connectErrorHandler(err);\n });\n });\n }\n\n private hasUnsentSubscriptions(): boolean {\n const latestTopics = this.getNonEmptySubscriptionKeys();\n if (latestTopics.length != this.lastSentSubscriptions.length) {\n return true;\n }\n\n for (const t of latestTopics) {\n if (!this.lastSentSubscriptions.includes(t)) {\n return true;\n }\n }\n\n return false;\n }\n\n private connectErrorHandler(err: any) {\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n\n if (\n // wasn't previously connected -> direct reject\n (!this.clientId && !this.reconnectAttempts) ||\n // was previously connected but the max reconnection limit has been reached\n this.reconnectAttempts > this.maxReconnectAttempts\n ) {\n for (let p of this.pendingConnects) {\n p.reject(new ClientResponseError(err));\n }\n this.pendingConnects = [];\n this.disconnect();\n return;\n }\n\n // otherwise -> reconnect in the background\n this.disconnect(true);\n const timeout =\n this.predefinedReconnectIntervals[this.reconnectAttempts] ||\n this.predefinedReconnectIntervals[\n this.predefinedReconnectIntervals.length - 1\n ];\n this.reconnectAttempts++;\n this.reconnectTimeoutId = setTimeout(() => {\n this.initConnect();\n }, timeout);\n }\n\n private disconnect(fromReconnect = false): void {\n if (this.clientId && this.onDisconnect) {\n this.onDisconnect(Object.keys(this.subscriptions));\n }\n\n clearTimeout(this.connectTimeoutId);\n clearTimeout(this.reconnectTimeoutId);\n this.removeAllSubscriptionListeners();\n this.client.cancelRequest(this.getSubscriptionsCancelKey());\n this.eventSource?.close();\n this.eventSource = null;\n this.clientId = \"\";\n\n if (!fromReconnect) {\n this.reconnectAttempts = 0;\n\n // resolve any remaining connect promises\n //\n // this is done to avoid unnecessary throwing errors in case\n // unsubscribe is called before the pending connect promises complete\n // (see https://github.com/pocketbase/pocketbase/discussions/2897#discussioncomment-6423818)\n for (let p of this.pendingConnects) {\n p.resolve();\n }\n this.pendingConnects = [];\n }\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/tools/options\";\n\nexport abstract class CrudService extends BaseService {\n /**\n * Base path for the crud actions (without trailing slash, eg. '/admins').\n */\n abstract get baseCrudPath(): string;\n\n /**\n * Response data decoder.\n */\n decode(data: { [key: string]: any }): T {\n return data as T;\n }\n\n /**\n * Returns a promise with all list items batch fetched at once\n * (by default 500 items per request; to change it set the `batch` query param).\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: FullListOptions): Promise>;\n\n /**\n * Legacy version of getFullList with explicitly specified batch size.\n */\n async getFullList(batch?: number, options?: ListOptions): Promise>;\n\n async getFullList(\n batchOrqueryParams?: number | FullListOptions,\n options?: ListOptions,\n ): Promise> {\n if (typeof batchOrqueryParams == \"number\") {\n return this._getFullList(batchOrqueryParams, options);\n }\n\n options = Object.assign({}, batchOrqueryParams, options);\n\n let batch = 500;\n if (options.batch) {\n batch = options.batch;\n delete options.batch;\n }\n\n return this._getFullList(batch, options);\n }\n\n /**\n * Returns paginated items list.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(this.baseCrudPath, options).then((responseData: any) => {\n responseData.items =\n responseData.items?.map((item: any) => {\n return this.decode(item);\n }) || [];\n\n return responseData;\n });\n }\n\n /**\n * Returns the first found item by the specified filter.\n *\n * Internally it calls `getList(1, 1, { filter, skipTotal })` and\n * returns the first found item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * For consistency with `getOne`, this method will throw a 404\n * ClientResponseError if no item was found.\n *\n * @throws {ClientResponseError}\n */\n async getFirstListItem(filter: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n requestKey: \"one_by_filter_\" + this.baseCrudPath + \"_\" + filter,\n },\n options,\n );\n\n options.query = Object.assign(\n {\n filter: filter,\n skipTotal: 1,\n },\n options.query,\n );\n\n return this.getList(1, 1, options).then((result) => {\n if (!result?.items?.length) {\n throw new ClientResponseError({\n status: 404,\n response: {\n code: 404,\n message: \"The requested resource wasn't found.\",\n data: {},\n },\n });\n }\n\n return result.items[0];\n });\n }\n\n /**\n * Returns single item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(this.baseCrudPath + \"/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required record id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Creates a new item.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath, options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Updates an existing item by its id.\n *\n * You can use the generic T to supply a wrapper type of the crud model.\n *\n * @throws {ClientResponseError}\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PATCH\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then((responseData: any) => this.decode(responseData));\n }\n\n /**\n * Deletes an existing item by its id.\n *\n * @throws {ClientResponseError}\n */\n async delete(id: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/\" + encodeURIComponent(id), options)\n .then(() => true);\n }\n\n /**\n * Returns a promise with all list items batch fetched at once.\n */\n protected _getFullList(\n batchSize = 500,\n options?: ListOptions,\n ): Promise> {\n options = options || {};\n options.query = Object.assign(\n {\n skipTotal: 1,\n },\n options.query,\n );\n\n let result: Array = [];\n\n let request = async (page: number): Promise> => {\n return this.getList(page, batchSize || 500, options).then((list) => {\n const castedList = list as any as ListResult;\n const items = castedList.items;\n\n result = result.concat(items);\n\n if (items.length == list.perPage) {\n return request(page + 1);\n }\n\n return result;\n });\n };\n\n return request(1);\n }\n}\n","import { SendOptions } from \"@/tools/options\";\n\nexport function normalizeLegacyOptionsArgs(\n legacyWarn: string,\n baseOptions: SendOptions,\n bodyOrOptions?: any,\n query?: any,\n): SendOptions {\n const hasBodyOrOptions = typeof bodyOrOptions !== \"undefined\";\n const hasQuery = typeof query !== \"undefined\";\n\n if (!hasQuery && !hasBodyOrOptions) {\n return baseOptions;\n }\n\n if (hasQuery) {\n console.warn(legacyWarn);\n baseOptions.body = Object.assign({}, baseOptions.body, bodyOrOptions);\n baseOptions.query = Object.assign({}, baseOptions.query, query);\n\n return baseOptions;\n }\n\n return Object.assign(baseOptions, bodyOrOptions);\n}\n","import Client from \"@/Client\";\nimport { isTokenExpired } from \"@/tools/jwt\";\n\n// reset previous auto refresh registrations\nexport function resetAutoRefresh(client: Client) {\n (client as any)._resetAutoRefresh?.();\n}\n\nexport function registerAutoRefresh(\n client: Client,\n threshold: number,\n refreshFunc: () => Promise,\n reauthenticateFunc: () => Promise,\n) {\n resetAutoRefresh(client);\n\n const oldBeforeSend = client.beforeSend;\n const oldModel = client.authStore.record;\n\n // unset the auto refresh in case the auth store was cleared\n // OR a new model was authenticated\n const unsubStoreChange = client.authStore.onChange((newToken, model) => {\n if (\n !newToken ||\n model?.id != oldModel?.id ||\n ((model?.collectionId || oldModel?.collectionId) &&\n model?.collectionId != oldModel?.collectionId)\n ) {\n resetAutoRefresh(client);\n }\n });\n\n // initialize a reset function and attach it dynamically to the client\n (client as any)._resetAutoRefresh = function () {\n unsubStoreChange();\n client.beforeSend = oldBeforeSend;\n delete (client as any)._resetAutoRefresh;\n };\n\n client.beforeSend = async (url, sendOptions) => {\n const oldToken = client.authStore.token;\n\n if (sendOptions.query?.autoRefresh) {\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n }\n\n let isValid = client.authStore.isValid;\n if (\n // is loosely valid\n isValid &&\n // but it is going to expire in the next \"threshold\" seconds\n isTokenExpired(client.authStore.token, threshold)\n ) {\n try {\n await refreshFunc();\n } catch (_) {\n isValid = false;\n }\n }\n\n // still invalid -> reauthenticate\n if (!isValid) {\n await reauthenticateFunc();\n }\n\n // the request wasn't sent with a custom token\n const headers = sendOptions.headers || {};\n for (let key in headers) {\n if (\n key.toLowerCase() == \"authorization\" &&\n // the request wasn't sent with a custom token\n oldToken == headers[key] &&\n client.authStore.token\n ) {\n // set the latest store token\n headers[key] = client.authStore.token;\n break;\n }\n }\n sendOptions.headers = headers;\n\n return oldBeforeSend ? oldBeforeSend(url, sendOptions) : { url, sendOptions };\n };\n}\n","import Client from \"@/Client\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { CrudService } from \"@/services/CrudService\";\nimport { ListResult, RecordModel } from \"@/tools/dtos\";\nimport { normalizeLegacyOptionsArgs } from \"@/tools/legacy\";\nimport {\n CommonOptions,\n RecordFullListOptions,\n RecordListOptions,\n RecordOptions,\n SendOptions,\n RecordSubscribeOptions,\n} from \"@/tools/options\";\nimport { getTokenPayload } from \"@/tools/jwt\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/tools/refresh\";\n\nexport interface RecordAuthResponse {\n /**\n * The signed PocketBase auth record.\n */\n record: T;\n\n /**\n * The PocketBase record auth token.\n *\n * If you are looking for the OAuth2 access and refresh tokens\n * they are available under the `meta.accessToken` and `meta.refreshToken` props.\n */\n token: string;\n\n /**\n * Auth meta data usually filled when OAuth2 is used.\n */\n meta?: { [key: string]: any };\n}\n\nexport interface AuthProviderInfo {\n name: string;\n displayName: string;\n state: string;\n authURL: string;\n codeVerifier: string;\n codeChallenge: string;\n codeChallengeMethod: string;\n}\n\nexport interface AuthMethodsList {\n mfa: {\n enabled: boolean;\n duration: number;\n };\n otp: {\n enabled: boolean;\n duration: number;\n };\n password: {\n enabled: boolean;\n identityFields: Array;\n };\n oauth2: {\n enabled: boolean;\n providers: Array;\n };\n}\n\nexport interface RecordSubscription {\n action: string; // eg. create, update, delete\n record: T;\n}\n\nexport type OAuth2UrlCallback = (url: string) => void | Promise;\n\nexport interface OAuth2AuthConfig extends SendOptions {\n // the name of the OAuth2 provider (eg. \"google\")\n provider: string;\n\n // custom scopes to overwrite the default ones\n scopes?: Array;\n\n // optional record create data\n createData?: { [key: string]: any };\n\n // optional callback that is triggered after the OAuth2 sign-in/sign-up url generation\n urlCallback?: OAuth2UrlCallback;\n\n // optional query params to send with the PocketBase auth request (eg. fields, expand, etc.)\n query?: RecordOptions;\n}\n\nexport interface OTPResponse {\n otpId: string;\n}\n\nexport class RecordService extends CrudService {\n readonly collectionIdOrName: string;\n\n constructor(client: Client, collectionIdOrName: string) {\n super(client);\n\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return this.baseCollectionPath + \"/records\";\n }\n\n /**\n * Returns the current collection service base path.\n */\n get baseCollectionPath(): string {\n return \"/api/collections/\" + encodeURIComponent(this.collectionIdOrName);\n }\n\n /**\n * Returns whether the current service collection is superusers.\n */\n get isSuperusers(): boolean {\n return (\n this.collectionIdOrName == \"_superusers\" ||\n this.collectionIdOrName == \"_pbc_2773867675\"\n );\n }\n\n // ---------------------------------------------------------------\n // Realtime handlers\n // ---------------------------------------------------------------\n\n /**\n * Subscribe to realtime changes to the specified topic (\"*\" or record id).\n *\n * If `topic` is the wildcard \"*\", then this method will subscribe to\n * any record changes in the collection.\n *\n * If `topic` is a record id, then this method will subscribe only\n * to changes of the specified record id.\n *\n * It's OK to subscribe multiple times to the same topic.\n * You can use the returned `UnsubscribeFunc` to remove only a single subscription.\n * Or use `unsubscribe(topic)` if you want to remove all subscriptions attached to the topic.\n */\n async subscribe(\n topic: string,\n callback: (data: RecordSubscription) => void,\n options?: RecordSubscribeOptions,\n ): Promise {\n if (!topic) {\n throw new Error(\"Missing topic.\");\n }\n\n if (!callback) {\n throw new Error(\"Missing subscription callback.\");\n }\n\n return this.client.realtime.subscribe(\n this.collectionIdOrName + \"/\" + topic,\n callback,\n options,\n );\n }\n\n /**\n * Unsubscribe from all subscriptions of the specified topic\n * (\"*\" or record id).\n *\n * If `topic` is not set, then this method will unsubscribe from\n * all subscriptions associated to the current collection.\n */\n async unsubscribe(topic?: string): Promise {\n // unsubscribe from the specified topic\n if (topic) {\n return this.client.realtime.unsubscribe(\n this.collectionIdOrName + \"/\" + topic,\n );\n }\n\n // unsubscribe from everything related to the collection\n return this.client.realtime.unsubscribeByPrefix(this.collectionIdOrName);\n }\n\n // ---------------------------------------------------------------\n // Crud handers\n // ---------------------------------------------------------------\n /**\n * @inheritdoc\n */\n async getFullList(options?: RecordFullListOptions): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batch?: number,\n options?: RecordListOptions,\n ): Promise>;\n\n /**\n * @inheritdoc\n */\n async getFullList(\n batchOrOptions?: number | RecordFullListOptions,\n options?: RecordListOptions,\n ): Promise> {\n if (typeof batchOrOptions == \"number\") {\n return super.getFullList(batchOrOptions, options);\n }\n\n const params = Object.assign({}, batchOrOptions, options);\n\n return super.getFullList(params);\n }\n\n /**\n * @inheritdoc\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: RecordListOptions,\n ): Promise> {\n return super.getList(page, perPage, options);\n }\n\n /**\n * @inheritdoc\n */\n async getFirstListItem(\n filter: string,\n options?: RecordListOptions,\n ): Promise {\n return super.getFirstListItem(filter, options);\n }\n\n /**\n * @inheritdoc\n */\n async getOne(id: string, options?: RecordOptions): Promise {\n return super.getOne(id, options);\n }\n\n /**\n * @inheritdoc\n */\n async create(\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.create(bodyParams, options);\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the updated id, then\n * on success the `client.authStore.record` will be updated with the new response record fields.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: RecordOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n if (\n // is record auth\n this.client.authStore.record?.id === item?.id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n let authExpand = Object.assign({}, this.client.authStore.record.expand);\n let authRecord = Object.assign({}, this.client.authStore.record, item);\n if (authExpand) {\n // for now \"merge\" only top-level expand\n authRecord.expand = Object.assign(authExpand, item.expand)\n }\n\n this.client.authStore.save(this.client.authStore.token, authRecord);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.record` matches with the deleted id,\n * then on success the `client.authStore` will be cleared.\n */\n async delete(id: string, options?: CommonOptions): Promise {\n return super.delete(id, options).then((success) => {\n if (\n success &&\n // is record auth\n this.client.authStore.record?.id === id &&\n (this.client.authStore.record?.collectionId === this.collectionIdOrName ||\n this.client.authStore.record?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful collection authorization response.\n */\n protected authResponse(responseData: any): RecordAuthResponse {\n const record = this.decode(responseData?.record || {});\n\n this.client.authStore.save(responseData?.token, record as any);\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n record: record as any as T,\n });\n }\n\n /**\n * Returns all available collection auth methods.\n *\n * @throws {ClientResponseError}\n */\n async listAuthMethods(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n // @todo remove after deleting the pre v0.23 API response fields\n fields: \"mfa,otp,password,oauth2\",\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/auth-methods\", options);\n }\n\n /**\n * Authenticate a single auth collection record via its username/email and password.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n options?: RecordOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n },\n options,\n );\n\n // note: consider to deprecate\n let autoRefreshThreshold;\n if (this.isSuperusers) {\n autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n }\n\n let authData = await this.client.send(\n this.baseCollectionPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold && this.isSuperusers) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n usernameOrEmail,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Authenticate a single auth collection record with OAuth2 code.\n *\n * If you don't have an OAuth2 code you may also want to check `authWithOAuth2` method.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n options?: RecordOptions,\n ): Promise>;\n\n /**\n * @deprecated\n * Consider using authWithOAuth2Code(provider, code, codeVerifier, redirectURL, createdData, options?).\n */\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithOAuth2Code(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n provider: provider,\n code: code,\n codeVerifier: codeVerifier,\n redirectURL: redirectURL,\n createData: createData,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\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?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-oauth2\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * @deprecated This form of authWithOAuth2 is deprecated.\n *\n * Please use `authWithOAuth2Code()` OR its simplified realtime version\n * as shown in https://pocketbase.io/docs/authentication/#oauth2-integration.\n */\n async authWithOAuth2(\n provider: string,\n code: string,\n codeVerifier: string,\n redirectURL: string,\n createData?: { [key: string]: any },\n bodyParams?: { [key: string]: any },\n queryParams?: RecordOptions,\n ): Promise>;\n\n /**\n * Authenticate a single auth collection record with OAuth2\n * **without custom redirects, deeplinks or even page reload**.\n *\n * This method initializes a one-off realtime subscription and will\n * open a popup window with the OAuth2 vendor page to authenticate.\n * Once the external OAuth2 sign-in/sign-up flow is completed, the popup\n * window will be automatically closed and the OAuth2 data sent back\n * to the user through the previously established realtime connection.\n *\n * You can specify an optional `urlCallback` prop to customize\n * the default url `window.open` behavior.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n * - the OAuth2 account data (eg. name, email, avatar, etc.)\n *\n * Example:\n *\n * ```js\n * const authData = await pb.collection(\"users\").authWithOAuth2({\n * provider: \"google\",\n * })\n * ```\n *\n * Note1: When creating the OAuth2 app in the provider dashboard\n * you have to configure `https://yourdomain.com/api/oauth2-redirect`\n * as redirect URL.\n *\n * Note2: Safari may block the default `urlCallback` popup because\n * it doesn't allow `window.open` calls as part of an `async` click functions.\n * To workaround this you can either change your click handler to not be marked as `async`\n * OR manually call `window.open` before your `async` function and use the\n * window reference in your own custom `urlCallback` (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061).\n * For example:\n * ```js\n * \n * ...\n * document.getElementById(\"btn\").addEventListener(\"click\", () => {\n * pb.collection(\"users\").authWithOAuth2({\n * provider: \"gitlab\",\n * }).then((authData) => {\n * console.log(authData)\n * }).catch((err) => {\n * console.log(err, err.originalError);\n * });\n * })\n * ```\n *\n * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n authWithOAuth2(...args: any): Promise> {\n // fallback to legacy format\n if (args.length > 1 || typeof args?.[0] === \"string\") {\n console.warn(\n \"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.\",\n );\n return this.authWithOAuth2Code(\n args?.[0] || \"\",\n args?.[1] || \"\",\n args?.[2] || \"\",\n args?.[3] || \"\",\n args?.[4] || {},\n args?.[5] || {},\n args?.[6] || {},\n );\n }\n\n const config = args?.[0] || {};\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before any async calls due to Safari restrictions\n // (see https://github.com/pocketbase/pocketbase/discussions/2429#discussioncomment-5943061)\n let eagerDefaultPopup: Window | null = null;\n if (!config.urlCallback) {\n eagerDefaultPopup = openBrowserPopup(undefined);\n }\n\n // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\n }\n\n const requestKeyOptions: SendOptions = {};\n const requestKey = config.requestKey;\n if (requestKey) {\n requestKeyOptions.requestKey = requestKey;\n }\n\n return this.listAuthMethods(requestKeyOptions)\n .then((authMethods) => {\n const provider = authMethods.oauth2.providers.find(\n (p) => p.name === config.provider,\n );\n if (!provider) {\n throw new ClientResponseError(\n new Error(`Missing or invalid provider \"${config.provider}\".`),\n );\n }\n\n const redirectURL = this.client.buildURL(\"/api/oauth2-redirect\");\n\n // find the AbortController associated with the current request key (if any)\n const cancelController = requestKey\n ? this.client[\"cancelControllers\"]?.[requestKey]\n : undefined;\n if (cancelController) {\n cancelController.signal.onabort = () => {\n cleanup();\n };\n }\n\n return new Promise(async (resolve, reject) => {\n try {\n await realtime.subscribe(\"@oauth2\", async (e) => {\n const oldState = realtime.clientId;\n\n try {\n if (!e.state || oldState !== e.state) {\n throw new Error(\"State parameters don't match.\");\n }\n\n if (e.error || !e.code) {\n throw new Error(\n \"OAuth2 redirect error or missing code: \" +\n e.error,\n );\n }\n\n // clear the non SendOptions props\n const options = Object.assign({}, config);\n delete options.provider;\n delete options.scopes;\n delete options.createData;\n delete options.urlCallback;\n\n // reset the cancelController listener as it will be triggered by the next api call\n if (cancelController?.signal?.onabort) {\n cancelController.signal.onabort = null;\n }\n\n const authData = await this.authWithOAuth2Code(\n provider.name,\n e.code,\n provider.codeVerifier,\n redirectURL,\n config.createData,\n options,\n );\n\n resolve(authData);\n } catch (err) {\n reject(new ClientResponseError(err));\n }\n\n cleanup();\n });\n\n const replacements: { [key: string]: any } = {\n state: realtime.clientId,\n };\n if (config.scopes?.length) {\n replacements[\"scope\"] = config.scopes.join(\" \");\n }\n\n const url = this._replaceQueryParams(\n provider.authURL + redirectURL,\n replacements,\n );\n\n let urlCallback =\n config.urlCallback ||\n function (url: string) {\n if (eagerDefaultPopup) {\n eagerDefaultPopup.location.href = url;\n } else {\n // it could have been blocked due to its empty initial url,\n // try again...\n eagerDefaultPopup = openBrowserPopup(url);\n }\n };\n\n await urlCallback(url);\n } catch (err) {\n cleanup();\n reject(new ClientResponseError(err));\n }\n });\n })\n .catch((err) => {\n cleanup();\n throw err; // rethrow\n }) as Promise>;\n }\n\n /**\n * Refreshes the current authenticated record instance and\n * returns a new token and record data.\n *\n * On success this method also automatically updates the client's AuthStore.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: RecordOptions): Promise>;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise>;\n\n async authRefresh(\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authRefresh(body?, query?) is deprecated. Consider replacing it with authRefresh(options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-refresh\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Sends auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async requestPasswordReset(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestPasswordReset(email, options?).\n */\n async requestPasswordReset(email: string, body?: any, query?: any): Promise;\n\n async requestPasswordReset(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestPasswordReset(email, body?, query?) is deprecated. Consider replacing it with requestPasswordReset(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(passwordResetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n passwordResetToken: string,\n password: string,\n passwordConfirm: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: passwordResetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(token, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(token, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Sends auth record verification email request.\n *\n * @throws {ClientResponseError}\n */\n async requestVerification(email: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestVerification(email, options?).\n */\n async requestVerification(email: string, body?: any, query?: any): Promise;\n\n async requestVerification(\n email: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n email: email,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestVerification(email, body?, query?) is deprecated. Consider replacing it with requestVerification(email, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-verification\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record email verification request.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore.record.verified` will be updated to `true`.\n *\n * @throws {ClientResponseError}\n */\n async confirmVerification(\n verificationToken: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmVerification(verificationToken, options?).\n */\n async confirmVerification(\n verificationToken: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmVerification(\n verificationToken: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: verificationToken,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmVerification(token, body?, query?) is deprecated. Consider replacing it with confirmVerification(token, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-verification\", options)\n .then(() => {\n // on success manually update the current auth record verified state\n const payload = getTokenPayload(verificationToken);\n const model = this.client.authStore.record;\n if (\n model &&\n !model.verified &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n model.verified = true;\n this.client.authStore.save(this.client.authStore.token, model);\n }\n\n return true;\n });\n }\n\n /**\n * Sends an email change request to the authenticated record model.\n *\n * @throws {ClientResponseError}\n */\n async requestEmailChange(newEmail: string, options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using requestEmailChange(newEmail, options?).\n */\n async requestEmailChange(newEmail: string, body?: any, query?: any): Promise;\n\n async requestEmailChange(\n newEmail: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n newEmail: newEmail,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of requestEmailChange(newEmail, body?, query?) is deprecated. Consider replacing it with requestEmailChange(newEmail, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/request-email-change\", options)\n .then(() => true);\n }\n\n /**\n * Confirms auth record's new email address.\n *\n * If the current `client.authStore.record` matches with the auth record from the token,\n * then on success the `client.authStore` will be cleared.\n *\n * @throws {ClientResponseError}\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmEmailChange(emailChangeToken, password, options?).\n */\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmEmailChange(\n emailChangeToken: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n token: emailChangeToken,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmEmailChange(token, password, body?, query?) is deprecated. Consider replacing it with confirmEmailChange(token, password, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/confirm-email-change\", options)\n .then(() => {\n const payload = getTokenPayload(emailChangeToken);\n const model = this.client.authStore.record;\n if (\n model &&\n model.id === payload.id &&\n model.collectionId === payload.collectionId\n ) {\n this.client.authStore.clear();\n }\n\n return true;\n });\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Lists all linked external auth providers for the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async listExternalAuths(\n recordId: string,\n options?: CommonOptions,\n ): Promise> {\n return this.client.collection(\"_externalAuths\").getFullList(\n Object.assign({}, options, {\n filter: this.client.filter(\"recordRef = {:id}\", { id: recordId }),\n }),\n );\n }\n\n /**\n * @deprecated use collection(\"_externalAuths\").*\n *\n * Unlink a single external auth provider from the specified auth record.\n *\n * @throws {ClientResponseError}\n */\n async unlinkExternalAuth(\n recordId: string,\n provider: string,\n options?: CommonOptions,\n ): Promise {\n const ea = await this.client.collection(\"_externalAuths\").getFirstListItem(\n this.client.filter(\"recordRef = {:recordId} && provider = {:provider}\", {\n recordId,\n provider,\n }),\n );\n\n return this.client\n .collection(\"_externalAuths\")\n .delete(ea.id, options)\n .then(() => true);\n }\n\n /**\n * Sends auth record OTP to the provided email.\n *\n * @throws {ClientResponseError}\n */\n async requestOTP(email: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { email: email },\n },\n options,\n );\n\n return this.client.send(this.baseCollectionPath + \"/request-otp\", options);\n }\n\n /**\n * Authenticate a single auth collection record via OTP.\n *\n * On success, this method also automatically updates\n * the client's AuthStore data and returns:\n * - the authentication token\n * - the authenticated record model\n *\n * @throws {ClientResponseError}\n */\n async authWithOTP(\n otpId: string,\n password: string,\n options?: CommonOptions,\n ): Promise> {\n options = Object.assign(\n {\n method: \"POST\",\n body: { otpId, password },\n },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-otp\", options)\n .then((data) => this.authResponse(data));\n }\n\n /**\n * Impersonate authenticates with the specified recordId and\n * returns a new client with the received auth token in a memory store.\n *\n * If `duration` is 0 the generated auth token will fallback\n * to the default collection auth token duration.\n *\n * This action currently requires superusers privileges.\n *\n * @throws {ClientResponseError}\n */\n async impersonate(\n recordId: string,\n duration: number,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: { duration: duration },\n },\n options,\n );\n options.headers = options.headers || {};\n if (!options.headers.Authorization) {\n options.headers.Authorization = this.client.authStore.token;\n }\n\n // create a new client loaded with the impersonated auth state\n // ---\n const client = new Client(\n this.client.baseURL,\n new BaseAuthStore(),\n this.client.lang,\n );\n\n const authData = await client.send(\n this.baseCollectionPath + \"/impersonate/\" + encodeURIComponent(recordId),\n options,\n );\n\n client.authStore.save(authData?.token, this.decode(authData?.record || {}));\n // ---\n\n return client;\n }\n\n // ---------------------------------------------------------------\n\n // very rudimentary url query params replacement because at the moment\n // URL (and URLSearchParams) doesn't seem to be fully supported in React Native\n //\n // note: for details behind some of the decode/encode parsing check https://unixpapa.com/js/querystring.html\n private _replaceQueryParams(\n url: string,\n replacements: { [key: string]: any } = {},\n ): string {\n let urlPath = url;\n let query = \"\";\n\n const queryIndex = url.indexOf(\"?\");\n if (queryIndex >= 0) {\n urlPath = url.substring(0, url.indexOf(\"?\"));\n query = url.substring(url.indexOf(\"?\") + 1);\n }\n\n const parsedParams: { [key: string]: string } = {};\n\n // parse the query parameters\n const rawParams = query.split(\"&\");\n for (const param of rawParams) {\n if (param == \"\") {\n continue;\n }\n\n const pair = param.split(\"=\");\n parsedParams[decodeURIComponent(pair[0].replace(/\\+/g, \" \"))] =\n decodeURIComponent((pair[1] || \"\").replace(/\\+/g, \" \"));\n }\n\n // apply the replacements\n for (let key in replacements) {\n if (!replacements.hasOwnProperty(key)) {\n continue;\n }\n\n if (replacements[key] == null) {\n delete parsedParams[key];\n } else {\n parsedParams[key] = replacements[key];\n }\n }\n\n // construct back the full query string\n query = \"\";\n for (let key in parsedParams) {\n if (!parsedParams.hasOwnProperty(key)) {\n continue;\n }\n\n if (query != \"\") {\n query += \"&\";\n }\n\n query +=\n encodeURIComponent(key.replace(/%20/g, \"+\")) +\n \"=\" +\n encodeURIComponent(parsedParams[key].replace(/%20/g, \"+\"));\n }\n\n return query != \"\" ? urlPath + \"?\" + query : urlPath;\n }\n}\n\nfunction openBrowserPopup(url?: string): Window | null {\n if (typeof window === \"undefined\" || !window?.open) {\n throw new ClientResponseError(\n new Error(\n `Not in a browser context - please pass a custom urlCallback function.`,\n ),\n );\n }\n\n let width = 1024;\n let height = 768;\n\n let windowWidth = window.innerWidth;\n let windowHeight = window.innerHeight;\n\n // normalize window size\n width = width > windowWidth ? windowWidth : width;\n height = height > windowHeight ? windowHeight : height;\n\n let left = windowWidth / 2 - width / 2;\n let top = windowHeight / 2 - height / 2;\n\n // note: we don't use the noopener and noreferrer attributes since\n // for some reason browser blocks such windows then url is undefined/blank\n return window.open(\n url,\n \"popup_window\",\n \"width=\" +\n width +\n \",height=\" +\n height +\n \",top=\" +\n top +\n \",left=\" +\n left +\n \",resizable,menubar=no\",\n );\n}\n","import { CrudService } from \"@/services/CrudService\";\nimport { CollectionModel } from \"@/tools/dtos\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport class CollectionService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/collections\";\n }\n\n /**\n * Imports the provided collections.\n *\n * If `deleteMissing` is `true`, all local collections and their fields,\n * that are not present in the imported configuration, WILL BE DELETED\n * (including their related records data)!\n *\n * @throws {ClientResponseError}\n */\n async import(\n collections: Array,\n deleteMissing: boolean = false,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"PUT\",\n body: {\n collections: collections,\n deleteMissing: deleteMissing,\n },\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/import\", options).then(() => true);\n }\n\n /**\n * Returns type indexed map with scaffolded collection models\n * populated with their default field values.\n *\n * @throws {ClientResponseError}\n */\n async getScaffolds(\n options?: CommonOptions,\n ): Promise<{ [key: string]: CollectionModel }> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/meta/scaffolds\", options);\n }\n\n /**\n * Deletes all records associated with the specified collection.\n *\n * @throws {ClientResponseError}\n */\n async truncate(collectionIdOrName: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client.send(this.baseCrudPath + \"/\" + encodeURIComponent(collectionIdOrName) +\"/truncate\", options).then(() => true);\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/BaseService\";\nimport { ListResult, LogModel } from \"@/tools/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/tools/options\";\n\nexport interface HourlyStats {\n total: number;\n date: string;\n}\n\nexport class LogService extends BaseService {\n /**\n * Returns paginated logs list.\n *\n * @throws {ClientResponseError}\n */\n async getList(\n page = 1,\n perPage = 30,\n options?: ListOptions,\n ): Promise> {\n options = Object.assign({ method: \"GET\" }, options);\n\n options.query = Object.assign(\n {\n page: page,\n perPage: perPage,\n },\n options.query,\n );\n\n return this.client.send(\"/api/logs\", options);\n }\n\n /**\n * Returns a single log by its id.\n *\n * If `id` is empty it will throw a 404 error.\n *\n * @throws {ClientResponseError}\n */\n async getOne(id: string, options?: CommonOptions): Promise {\n if (!id) {\n throw new ClientResponseError({\n url: this.client.buildURL(\"/api/logs/\"),\n status: 404,\n response: {\n code: 404,\n message: \"Missing required log id.\",\n data: {},\n },\n });\n }\n\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/\" + encodeURIComponent(id), options);\n }\n\n /**\n * Returns logs statistics.\n *\n * @throws {ClientResponseError}\n */\n async getStats(options?: LogStatsOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/logs/stats\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface HealthCheckResponse {\n code: number;\n message: string;\n data: { [key: string]: any };\n}\n\nexport class HealthService extends BaseService {\n /**\n * Checks the health status of the api.\n *\n * @throws {ClientResponseError}\n */\n async check(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/health\", options);\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/tools/options\";\n\nexport class FileService extends BaseService {\n /**\n * @deprecated Please replace with `pb.files.getURL()`.\n */\n getUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.files.getUrl() with pb.files.getURL()\");\n return this.getURL(record, filename, queryParams);\n }\n\n /**\n * Builds and returns an absolute record file url for the provided filename.\n */\n getURL(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n if (\n !filename ||\n !record?.id ||\n !(record?.collectionId || record?.collectionName)\n ) {\n return \"\";\n }\n\n const parts = [];\n parts.push(\"api\");\n parts.push(\"files\");\n parts.push(encodeURIComponent(record.collectionId || record.collectionName));\n parts.push(encodeURIComponent(record.id));\n parts.push(encodeURIComponent(filename));\n\n let result = this.client.buildURL(parts.join(\"/\"));\n\n if (Object.keys(queryParams).length) {\n // normalize the download query param for consistency with the Dart sdk\n if (queryParams.download === false) {\n delete queryParams.download;\n }\n\n const params = new URLSearchParams(queryParams);\n\n result += (result.includes(\"?\") ? \"&\" : \"?\") + params;\n }\n\n return result;\n }\n\n /**\n * Requests a new private file access token for the current auth model.\n *\n * @throws {ClientResponseError}\n */\n async getToken(options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(\"/api/files/token\", options)\n .then((data) => data?.token || \"\");\n }\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { CommonOptions } from \"@/tools/options\";\n\nexport interface BackupFileInfo {\n key: string;\n size: number;\n modified: string;\n}\n\nexport class BackupService extends BaseService {\n /**\n * Returns list with all available backup files.\n *\n * @throws {ClientResponseError}\n */\n async getFullList(options?: CommonOptions): Promise> {\n options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options);\n }\n\n /**\n * Initializes a new backup.\n *\n * @throws {ClientResponseError}\n */\n async create(basename: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: {\n name: basename,\n },\n },\n options,\n );\n\n return this.client.send(\"/api/backups\", options).then(() => true);\n }\n\n /**\n * Uploads an existing backup file.\n *\n * Example:\n *\n * ```js\n * await pb.backups.upload({\n * file: new Blob([...]),\n * });\n * ```\n *\n * @throws {ClientResponseError}\n */\n async upload(\n bodyParams: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n body: bodyParams,\n },\n options,\n );\n\n return this.client.send(\"/api/backups/upload\", options).then(() => true);\n }\n\n /**\n * Deletes a single backup file.\n *\n * @throws {ClientResponseError}\n */\n async delete(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}`, options)\n .then(() => true);\n }\n\n /**\n * Initializes an app data restore from an existing backup.\n *\n * @throws {ClientResponseError}\n */\n async restore(key: string, options?: CommonOptions): Promise {\n options = Object.assign(\n {\n method: \"POST\",\n },\n options,\n );\n\n return this.client\n .send(`/api/backups/${encodeURIComponent(key)}/restore`, options)\n .then(() => true);\n }\n\n /**\n * @deprecated Please use `getDownloadURL()`.\n */\n getDownloadUrl(token: string, key: string): string {\n console.warn(\n \"Please replace pb.backups.getDownloadUrl() with pb.backups.getDownloadURL()\",\n );\n return this.getDownloadURL(token, key);\n }\n\n /**\n * Builds a download url for a single existing backup using a\n * superuser file token and the backup file key.\n *\n * The file token can be generated via `pb.files.getToken()`.\n */\n getDownloadURL(token: string, key: string): string {\n return this.client.buildURL(\n `/api/backups/${encodeURIComponent(key)}?token=${encodeURIComponent(token)}`,\n );\n }\n}\n","/**\n * Checks if the specified value is a file (aka. File, Blob, RN file object).\n */\nexport function isFile(val: any): boolean {\n return (\n (typeof Blob !== \"undefined\" && val instanceof Blob) ||\n (typeof File !== \"undefined\" && val instanceof File) ||\n // check for React Native file object format\n // (see https://github.com/pocketbase/pocketbase/discussions/2002#discussioncomment-5254168)\n (val !== null &&\n typeof val === \"object\" &&\n val.uri &&\n ((typeof navigator !== \"undefined\" && navigator.product === \"ReactNative\") ||\n (typeof global !== \"undefined\" && (global as any).HermesInternal)))\n );\n}\n\n/**\n * Loosely checks if the specified body is a FormData instance.\n */\nexport function isFormData(body: any): boolean {\n return (\n body &&\n // we are checking the constructor name because FormData\n // is not available natively in some environments and the\n // polyfill(s) may not be globally accessible\n (body.constructor.name === \"FormData\" ||\n // fallback to global FormData instance check\n // note: this is needed because the constructor.name could be different in case of\n // custom global FormData implementation, eg. React Native on Android/iOS\n (typeof FormData !== \"undefined\" && body instanceof FormData))\n );\n}\n\n/**\n * Checks if the submitted body object has at least one Blob/File field value.\n */\nexport function hasFileField(body: { [key: string]: any }): boolean {\n for (const key in body) {\n const values = Array.isArray(body[key]) ? body[key] : [body[key]];\n for (const v of values) {\n if (isFile(v)) {\n return true;\n }\n }\n }\n\n return false;\n}\n\n/**\n * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\nexport function convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n isFormData(body) ||\n !hasFileField(body)\n ) {\n return body;\n }\n\n const form = new FormData();\n\n for (const key in body) {\n const val = body[key];\n\n if (typeof val === \"object\" && !hasFileField({ data: val })) {\n // send json-like values as jsonPayload to avoid the implicit string value normalization\n let payload: { [key: string]: any } = {};\n payload[key] = val;\n form.append(\"@jsonPayload\", JSON.stringify(payload));\n } else {\n // in case of mixed string and file/blob\n const normalizedVal = Array.isArray(val) ? val : [val];\n for (let v of normalizedVal) {\n form.append(key, v);\n }\n }\n }\n\n return form;\n}\n","import { BaseService } from \"@/services/BaseService\";\nimport { isFile } from \"@/tools/formdata\";\nimport {\n SendOptions,\n RecordOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\n\nexport interface BatchRequest {\n method: string;\n url: string;\n json?: { [key: string]: any };\n files?: { [key: string]: Array };\n headers?: { [key: string]: string };\n}\n\nexport interface BatchRequestResult {\n status: number;\n body: any;\n}\n\nexport class BatchService extends BaseService {\n private requests: Array = [];\n private subs: { [key: string]: SubBatchService } = {};\n\n /**\n * Starts constructing a batch request entry for the specified collection.\n */\n collection(collectionIdOrName: string): SubBatchService {\n if (!this.subs[collectionIdOrName]) {\n this.subs[collectionIdOrName] = new SubBatchService(\n this.requests,\n collectionIdOrName,\n );\n }\n\n return this.subs[collectionIdOrName];\n }\n\n /**\n * Sends the batch requests.\n *\n * Note: FormData as individual request body is not supported at the moment.\n *\n * @throws {ClientResponseError}\n */\n async send(options?: SendOptions): Promise> {\n const formData = new FormData();\n\n const jsonData = [];\n\n for (let i = 0; i < this.requests.length; i++) {\n const req = this.requests[i];\n\n jsonData.push({\n method: req.method,\n url: req.url,\n headers: req.headers,\n body: req.json,\n });\n\n if (req.files) {\n for (let key in req.files) {\n const files = req.files[key] || [];\n for (let file of files) {\n formData.append(\"requests.\" + i + \".\" + key, file);\n }\n }\n }\n }\n\n formData.append(\"@jsonPayload\", JSON.stringify({ requests: jsonData }));\n\n options = Object.assign(\n {\n method: \"POST\",\n body: formData,\n },\n options,\n );\n\n return this.client.send(\"/api/batch\", options);\n }\n}\n\nexport class SubBatchService {\n private requests: Array = [];\n private readonly collectionIdOrName: string;\n\n constructor(requests: Array, collectionIdOrName: string) {\n this.requests = requests;\n this.collectionIdOrName = collectionIdOrName;\n }\n\n /**\n * Registers a record upsert request into the current batch queue.\n *\n * The request will be executed as update if `bodyParams` have a valid existing record `id` value, otherwise - create.\n */\n upsert(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PUT\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record create request into the current batch queue.\n */\n create(bodyParams?: { [key: string]: any }, options?: RecordOptions): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"POST\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records\",\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record update request into the current batch queue.\n */\n update(\n id: string,\n bodyParams?: { [key: string]: any },\n options?: RecordOptions,\n ): void {\n options = Object.assign(\n {\n body: bodyParams || {},\n },\n options,\n );\n\n const request: BatchRequest = {\n method: \"PATCH\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n /**\n * Registers a record delete request into the current batch queue.\n */\n delete(id: string, options?: SendOptions): void {\n options = Object.assign({}, options);\n\n const request: BatchRequest = {\n method: \"DELETE\",\n url:\n \"/api/collections/\" +\n encodeURIComponent(this.collectionIdOrName) +\n \"/records/\" +\n encodeURIComponent(id),\n };\n\n this.prepareRequest(request, options);\n\n this.requests.push(request);\n }\n\n private prepareRequest(request: BatchRequest, options: SendOptions) {\n normalizeUnknownQueryParams(options);\n\n request.headers = options.headers;\n request.json = {};\n request.files = {};\n\n // serialize query parameters\n // -----------------------------------------------------------\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n request.url += (request.url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n }\n\n // extract json and files body data\n // -----------------------------------------------------------\n for (const key in options.body) {\n const val = options.body[key];\n\n if (isFile(val)) {\n request.files[key] = request.files[key] || [];\n request.files[key].push(val);\n } else if (Array.isArray(val)) {\n const foundFiles = [];\n const foundRegular = [];\n for (const v of val) {\n if (isFile(v)) {\n foundFiles.push(v);\n } else {\n foundRegular.push(v);\n }\n }\n\n if (foundFiles.length > 0 && foundFiles.length == val.length) {\n // only files\n // ---\n request.files[key] = request.files[key] || [];\n for (let file of foundFiles) {\n request.files[key].push(file);\n }\n } else {\n // empty or mixed array (both regular and File/Blob values)\n // ---\n request.json[key] = foundRegular;\n\n if (foundFiles.length > 0) {\n // add \"+\" to append if not already since otherwise\n // the existing regular files will be deleted\n // (the mixed values order is preserved only within their corresponding groups)\n let fileKey = key;\n if (!key.startsWith(\"+\") && !key.endsWith(\"+\")) {\n fileKey += \"+\";\n }\n\n request.files[fileKey] = request.files[fileKey] || [];\n for (let file of foundFiles) {\n request.files[fileKey].push(file);\n }\n }\n }\n } else {\n request.json[key] = val;\n }\n }\n }\n}\n","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { RecordService } from \"@/services/RecordService\";\nimport { CollectionService } from \"@/services/CollectionService\";\nimport { LogService } from \"@/services/LogService\";\nimport { RealtimeService } from \"@/services/RealtimeService\";\nimport { HealthService } from \"@/services/HealthService\";\nimport { FileService } from \"@/services/FileService\";\nimport { BackupService } from \"@/services/BackupService\";\nimport { BatchService } from \"@/services/BatchService\";\nimport { RecordModel } from \"@/tools/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n serializeQueryParams,\n} from \"@/tools/options\";\nimport { isFormData, convertToFormDataIfNeeded } from \"@/tools/formdata\";\n\nexport interface BeforeSendResult {\n [key: string]: any; // for backward compatibility\n url?: string;\n options?: { [key: string]: any };\n}\n\n/**\n * PocketBase JS Client.\n */\nexport default class Client {\n /**\n * The base PocketBase backend url address (eg. 'http://127.0.0.1.8090').\n */\n baseURL: string;\n\n /**\n * Legacy getter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n get baseUrl(): string {\n return this.baseURL;\n }\n\n /**\n * Legacy setter alias for baseURL.\n * @deprecated Please replace with baseURL.\n */\n set baseUrl(v: string) {\n this.baseURL = v;\n }\n\n /**\n * Hook that get triggered right before sending the fetch request,\n * allowing you to inspect and modify the url and request options.\n *\n * For list of the possible options check https://developer.mozilla.org/en-US/docs/Web/API/fetch#options\n *\n * You can return a non-empty result object `{ url, options }` to replace the url and request options entirely.\n *\n * Example:\n * ```js\n * client.beforeSend = function (url, options) {\n * options.headers = Object.assign({}, options.headers, {\n * 'X-Custom-Header': 'example',\n * });\n *\n * return { url, options }\n * };\n * ```\n */\n beforeSend?: (\n url: string,\n options: SendOptions,\n ) => BeforeSendResult | Promise;\n\n /**\n * Hook that get triggered after successfully sending the fetch request,\n * allowing you to inspect/modify the response object and its parsed data.\n *\n * Returns the new Promise resolved `data` that will be returned to the client.\n *\n * Example:\n * ```js\n * client.afterSend = function (response, data, options) {\n * if (response.status != 200) {\n * throw new ClientResponseError({\n * url: response.url,\n * status: response.status,\n * response: { ... },\n * });\n * }\n *\n * return data;\n * };\n * ```\n */\n afterSend?: ((response: Response, data: any) => any) &\n ((response: Response, data: any, options: SendOptions) => any);\n\n /**\n * Optional language code (default to `en-US`) that will be sent\n * with the requests to the server as `Accept-Language` header.\n */\n lang: string;\n\n /**\n * A replaceable instance of the local auth store service.\n */\n authStore: BaseAuthStore;\n\n /**\n * An instance of the service that handles the **Settings APIs**.\n */\n readonly settings: SettingsService;\n\n /**\n * An instance of the service that handles the **Collection APIs**.\n */\n readonly collections: CollectionService;\n\n /**\n * An instance of the service that handles the **File APIs**.\n */\n readonly files: FileService;\n\n /**\n * An instance of the service that handles the **Log APIs**.\n */\n readonly logs: LogService;\n\n /**\n * An instance of the service that handles the **Realtime APIs**.\n */\n readonly realtime: RealtimeService;\n\n /**\n * An instance of the service that handles the **Health APIs**.\n */\n readonly health: HealthService;\n\n /**\n * An instance of the service that handles the **Backup APIs**.\n */\n readonly backups: BackupService;\n\n private cancelControllers: { [key: string]: AbortController } = {};\n private recordServices: { [key: string]: RecordService } = {};\n private enableAutoCancellation: boolean = true;\n\n constructor(baseURL = \"/\", authStore?: BaseAuthStore | null, lang = \"en-US\") {\n this.baseURL = baseURL;\n this.lang = lang;\n\n if (authStore) {\n this.authStore = authStore;\n } else if (typeof window != \"undefined\" && !!(window as any).Deno) {\n // note: to avoid common security issues we fallback to runtime/memory store in case the code is running in Deno env\n this.authStore = new BaseAuthStore();\n } else {\n this.authStore = new LocalAuthStore();\n }\n\n // common services\n this.collections = new CollectionService(this);\n this.files = new FileService(this);\n this.logs = new LogService(this);\n this.settings = new SettingsService(this);\n this.realtime = new RealtimeService(this);\n this.health = new HealthService(this);\n this.backups = new BackupService(this);\n }\n\n /**\n * @deprecated\n * With PocketBase v0.23.0 admins are converted to a regular auth\n * collection named \"_superusers\", aka. you can use directly collection(\"_superusers\").\n */\n get admins(): RecordService {\n return this.collection(\"_superusers\");\n }\n\n /**\n * Creates a new batch handler for sending multiple transactional\n * create/update/upsert/delete collection requests in one network call.\n *\n * Example:\n * ```js\n * const batch = pb.createBatch();\n *\n * batch.collection(\"example1\").create({ ... })\n * batch.collection(\"example2\").update(\"RECORD_ID\", { ... })\n * batch.collection(\"example3\").delete(\"RECORD_ID\")\n * batch.collection(\"example4\").upsert({ ... })\n *\n * await batch.send()\n * ```\n */\n createBatch(): BatchService {\n return new BatchService(this);\n }\n\n /**\n * Returns the RecordService associated to the specified collection.\n */\n collection(idOrName: string): RecordService {\n if (!this.recordServices[idOrName]) {\n this.recordServices[idOrName] = new RecordService(this, idOrName);\n }\n\n return this.recordServices[idOrName];\n }\n\n /**\n * Globally enable or disable auto cancellation for pending duplicated requests.\n */\n autoCancellation(enable: boolean): Client {\n this.enableAutoCancellation = !!enable;\n\n return this;\n }\n\n /**\n * Cancels single request by its cancellation key.\n */\n cancelRequest(requestKey: string): Client {\n if (this.cancelControllers[requestKey]) {\n this.cancelControllers[requestKey].abort();\n delete this.cancelControllers[requestKey];\n }\n\n return this;\n }\n\n /**\n * Cancels all pending requests.\n */\n cancelAllRequests(): Client {\n for (let k in this.cancelControllers) {\n this.cancelControllers[k].abort();\n }\n\n this.cancelControllers = {};\n\n return this;\n }\n\n /**\n * Constructs a filter expression with placeholders populated from a parameters object.\n *\n * Placeholder parameters are defined with the `{:paramName}` notation.\n *\n * The following parameter values are supported:\n *\n * - `string` (_single quotes are autoescaped_)\n * - `number`\n * - `boolean`\n * - `Date` object (_stringified into the PocketBase datetime format_)\n * - `null`\n * - everything else is converted to a string using `JSON.stringify()`\n *\n * Example:\n *\n * ```js\n * pb.collection(\"example\").getFirstListItem(pb.filter(\n * 'title ~ {:title} && created >= {:created}',\n * { title: \"example\", created: new Date()}\n * ))\n * ```\n */\n filter(raw: string, params?: { [key: string]: any }): string {\n if (!params) {\n return raw;\n }\n\n for (let key in params) {\n let val = params[key];\n switch (typeof val) {\n case \"boolean\":\n case \"number\":\n val = \"\" + val;\n break;\n case \"string\":\n val = \"'\" + val.replace(/'/g, \"\\\\'\") + \"'\";\n break;\n default:\n if (val === null) {\n val = \"null\";\n } else if (val instanceof Date) {\n val = \"'\" + val.toISOString().replace(\"T\", \" \") + \"'\";\n } else {\n val = \"'\" + JSON.stringify(val).replace(/'/g, \"\\\\'\") + \"'\";\n }\n }\n raw = raw.replaceAll(\"{:\" + key + \"}\", val);\n }\n\n return raw;\n }\n\n /**\n * @deprecated Please use `pb.files.getURL()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n console.warn(\"Please replace pb.getFileUrl() with pb.files.getURL()\");\n return this.files.getURL(record, filename, queryParams);\n }\n\n /**\n * @deprecated Please use `pb.buildURL()`.\n */\n buildUrl(path: string): string {\n console.warn(\"Please replace pb.buildUrl() with pb.buildURL()\");\n return this.buildURL(path);\n }\n\n /**\n * Builds a full client url by safely concatenating the provided path.\n */\n buildURL(path: string): string {\n let url = this.baseURL;\n\n // construct an absolute base url if in a browser environment\n if (\n typeof window !== \"undefined\" &&\n !!window.location &&\n !url.startsWith(\"https://\") &&\n !url.startsWith(\"http://\")\n ) {\n url = window.location.origin?.endsWith(\"/\")\n ? window.location.origin.substring(0, window.location.origin.length - 1)\n : window.location.origin || \"\";\n\n if (!this.baseURL.startsWith(\"/\")) {\n url += window.location.pathname || \"/\";\n url += url.endsWith(\"/\") ? \"\" : \"/\";\n }\n\n url += this.baseURL;\n }\n\n // concatenate the path\n if (path) {\n url += url.endsWith(\"/\") ? \"\" : \"/\"; // append trailing slash if missing\n url += path.startsWith(\"/\") ? path.substring(1) : path;\n }\n\n return url;\n }\n\n /**\n * Sends an api http request.\n *\n * @throws {ClientResponseError}\n */\n async send(path: string, options: SendOptions): Promise {\n options = this.initSendOptions(path, options);\n\n // build url + path\n let url = this.buildURL(path);\n\n if (this.beforeSend) {\n const result = Object.assign({}, await this.beforeSend(url, options));\n if (\n typeof result.url !== \"undefined\" ||\n typeof result.options !== \"undefined\"\n ) {\n url = result.url || url;\n options = result.options || options;\n } else if (Object.keys(result).length) {\n // legacy behavior\n options = result as SendOptions;\n console?.warn &&\n console.warn(\n \"Deprecated format of beforeSend return: please use `return { url, options }`, instead of `return options`.\",\n );\n }\n }\n\n // serialize the query parameters\n if (typeof options.query !== \"undefined\") {\n const query = serializeQueryParams(options.query);\n if (query) {\n url += (url.includes(\"?\") ? \"&\" : \"?\") + query;\n }\n delete options.query;\n }\n\n // ensures that the json body is serialized\n if (\n this.getHeader(options.headers, \"Content-Type\") == \"application/json\" &&\n options.body &&\n typeof options.body !== \"string\"\n ) {\n options.body = JSON.stringify(options.body);\n }\n\n const fetchFunc = options.fetch || fetch;\n\n // send the request\n return fetchFunc(url, options)\n .then(async (response) => {\n let data: any = {};\n\n try {\n data = await response.json();\n } catch (_) {\n // all api responses are expected to return json\n // with the exception of the realtime event and 204\n }\n\n if (this.afterSend) {\n data = await this.afterSend(response, data, options);\n }\n\n if (response.status >= 400) {\n throw new ClientResponseError({\n url: response.url,\n status: response.status,\n data: data,\n });\n }\n\n return data as T;\n })\n .catch((err) => {\n // wrap to normalize all errors\n throw new ClientResponseError(err);\n });\n }\n\n /**\n * Shallow copy the provided object and takes care to initialize\n * any options required to preserve the backward compatability.\n *\n * @param {SendOptions} options\n * @return {SendOptions}\n */\n private initSendOptions(path: string, options: SendOptions): SendOptions {\n options = Object.assign({ method: \"GET\" } as SendOptions, options);\n\n // auto convert the body to FormData, if needed\n options.body = convertToFormDataIfNeeded(options.body);\n\n // move unknown send options as query parameters\n normalizeUnknownQueryParams(options);\n\n // requestKey normalizations for backward-compatibility\n // ---\n options.query = Object.assign({}, options.params, options.query);\n if (typeof options.requestKey === \"undefined\") {\n if (options.$autoCancel === false || options.query.$autoCancel === false) {\n options.requestKey = null;\n } else if (options.$cancelKey || options.query.$cancelKey) {\n options.requestKey = options.$cancelKey || options.query.$cancelKey;\n }\n }\n // remove the deprecated special cancellation params from the other query params\n delete options.$autoCancel;\n delete options.query.$autoCancel;\n delete options.$cancelKey;\n delete options.query.$cancelKey;\n // ---\n\n // add the json header, if not explicitly set\n // (for FormData body the Content-Type header should be skipped since the boundary is autogenerated)\n if (\n this.getHeader(options.headers, \"Content-Type\") === null &&\n !isFormData(options.body)\n ) {\n options.headers = Object.assign({}, options.headers, {\n \"Content-Type\": \"application/json\",\n });\n }\n\n // add Accept-Language header, if not explicitly set\n if (this.getHeader(options.headers, \"Accept-Language\") === null) {\n options.headers = Object.assign({}, options.headers, {\n \"Accept-Language\": this.lang,\n });\n }\n\n // check if Authorization header can be added\n if (\n // has valid token\n this.authStore.token &&\n // auth header is not explicitly set\n this.getHeader(options.headers, \"Authorization\") === null\n ) {\n options.headers = Object.assign({}, options.headers, {\n Authorization: this.authStore.token,\n });\n }\n\n // handle auto cancelation for duplicated pending request\n if (this.enableAutoCancellation && options.requestKey !== null) {\n const requestKey = options.requestKey || (options.method || \"GET\") + path;\n\n delete options.requestKey;\n\n // cancel previous pending requests\n this.cancelRequest(requestKey);\n\n const controller = new AbortController();\n this.cancelControllers[requestKey] = controller;\n options.signal = controller.signal;\n }\n\n return options;\n }\n\n /**\n * Extracts the header with the provided name in case-insensitive manner.\n * Returns `null` if no header matching the name is found.\n */\n private getHeader(\n headers: { [key: string]: string } | undefined,\n name: string,\n ): string | null {\n headers = headers || {};\n name = name.toLowerCase();\n\n for (let key in headers) {\n if (key.toLowerCase() == name) {\n return headers[key];\n }\n }\n\n return null;\n }\n}\n"],"names":["ClientResponseError","Error","constructor","errData","super","this","url","status","response","isAbort","originalError","Object","setPrototypeOf","prototype","data","DOMException","name","message","cause","includes","toJSON","fieldContentRegExp","cookieSerialize","val","options","opt","assign","encode","defaultEncode","test","TypeError","value","result","maxAge","isNaN","isFinite","Math","floor","domain","path","expires","isDate","toString","call","Date","valueOf","toUTCString","httpOnly","secure","priority","toLowerCase","sameSite","defaultDecode","indexOf","decodeURIComponent","encodeURIComponent","isReactNative","navigator","product","global","HermesInternal","atobPolyfill","getTokenPayload","token","encodedPayload","split","map","c","charCodeAt","slice","join","JSON","parse","e","isTokenExpired","expirationThreshold","payload","keys","length","exp","now","atob","input","str","String","replace","bs","buffer","bc","idx","output","charAt","fromCharCode","defaultCookieKey","BaseAuthStore","baseToken","baseModel","_onChangeCallbacks","record","model","isValid","isSuperuser","type","collectionName","collectionId","isAdmin","console","warn","isAuthRecord","save","triggerChange","clear","loadFromCookie","cookie","key","rawData","cookieParse","decode","index","eqIdx","endIdx","lastIndexOf","trim","undefined","_","Array","isArray","exportToCookie","defaultOptions","stringify","resultLength","Blob","size","id","email","extraProps","prop","onChange","callback","fireImmediately","push","i","splice","LocalAuthStore","storageKey","storageFallback","_bindStorageEvent","_storageGet","_storageSet","_storageRemove","window","localStorage","rawValue","getItem","normalizedVal","setItem","removeItem","addEventListener","BaseService","client","SettingsService","getAll","method","send","update","bodyParams","body","testS3","filesystem","then","testEmail","collectionIdOrName","toEmail","emailTemplate","template","collection","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","knownSendOptionsKeys","normalizeUnknownQueryParams","query","serializeQueryParams","params","encodedKey","v","toISOString","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","headers","listener","msgEvent","submitSubscriptions","connect","async","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","requestKey","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","buildURL","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","onDisconnect","cancelRequest","close","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","baseCrudPath","responseData","items","item","getFirstListItem","filter","skipTotal","code","getOne","create","batchSize","request","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","resetAutoRefresh","_resetAutoRefresh","RecordService","baseCollectionPath","isSuperusers","realtime","batchOrOptions","authStore","authExpand","expand","authRecord","delete","success","authResponse","listAuthMethods","fields","authWithPassword","usernameOrEmail","password","autoRefreshThreshold","identity","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","authRefresh","authWithOAuth2Code","provider","codeVerifier","redirectURL","createData","authWithOAuth2","args","config","eagerDefaultPopup","urlCallback","openBrowserPopup","cleanup","requestKeyOptions","authMethods","oauth2","providers","find","cancelController","signal","onabort","oldState","state","error","scopes","replacements","_replaceQueryParams","authURL","location","href","requestPasswordReset","confirmPasswordReset","passwordResetToken","passwordConfirm","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","ea","requestOTP","authWithOTP","otpId","impersonate","Authorization","Client","baseURL","lang","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","getScaffolds","truncate","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","getURL","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","getDownloadURL","isFile","File","uri","isFormData","FormData","hasFileField","values","BatchService","requests","SubBatchService","formData","jsonData","req","json","files","file","append","upsert","prepareRequest","foundFiles","foundRegular","fileKey","endsWith","baseUrl","cancelControllers","recordServices","enableAutoCancellation","Deno","logs","settings","health","backups","admins","createBatch","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","replaceAll","getFileUrl","buildUrl","origin","pathname","initSendOptions","getHeader","fetch","afterSend","convertToFormDataIfNeeded","form","$autoCancel","$cancelKey","controller","AbortController"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json index 6d3bb92..23a61e3 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "0.22.1", + "version": "0.23.0", "name": "pocketbase", "description": "PocketBase JavaScript SDK", "author": "Gani Georgiev", diff --git a/src/services/RealtimeService.ts b/src/services/RealtimeService.ts index 31f386a..d87dccc 100644 --- a/src/services/RealtimeService.ts +++ b/src/services/RealtimeService.ts @@ -34,6 +34,20 @@ export class RealtimeService extends BaseService { return !!this.eventSource && !!this.clientId && !this.pendingConnects.length; } + /** + * An optional hook that is invoked when the realtime client disconnects + * either when unsubscribing from all subscriptions or when the + * connection was interrupted or closed by the server. + * + * The received argument could be used to determine whether the disconnect + * is a result from unsubscribing (`activeSubscriptions.length == 0`) + * or because of network/server error (`activeSubscriptions.length > 0`). + * + * If you want to listen for the opposite, aka. when the client connection is established, + * subscribe to the `PB_CONNECT` event. + */ + onDisconnect?: (activeSubscriptions: Array) => void; + /** * Register the subscription listener. * @@ -465,6 +479,10 @@ export class RealtimeService extends BaseService { } private disconnect(fromReconnect = false): void { + if (this.clientId && this.onDisconnect) { + this.onDisconnect(Object.keys(this.subscriptions)); + } + clearTimeout(this.connectTimeoutId); clearTimeout(this.reconnectTimeoutId); this.removeAllSubscriptionListeners();