{"version":3,"file":"pocketbase.es.mjs","sources":["../src/ClientResponseError.ts","../src/stores/utils/cookie.ts","../src/stores/utils/jwt.ts","../src/stores/BaseAuthStore.ts","../src/stores/LocalAuthStore.ts","../src/services/utils/BaseService.ts","../src/services/SettingsService.ts","../src/services/utils/CrudService.ts","../src/services/utils/legacy.ts","../src/services/utils/refresh.ts","../src/services/AdminService.ts","../src/services/utils/options.ts","../src/services/RealtimeService.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/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` to preserve the 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","let atobPolyfill: Function;\nif (typeof atob === \"function\") {\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 \"@/stores/utils/cookie\";\nimport { isTokenExpired, getTokenPayload } from \"@/stores/utils/jwt\";\n\nexport type AuthModel = { [key: string]: any } | null;\n\nexport type OnStoreChangeFunc = (token: string, model: AuthModel) => void;\n\nconst defaultCookieKey = \"pb_auth\";\n\n/**\n * Base AuthStore class that is intended to be extended by all other\n * PocketBase AuthStore implementations.\n */\nexport abstract class BaseAuthStore {\n protected baseToken: string = \"\";\n protected baseModel: AuthModel = 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 model(): AuthModel {\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 * Checks whether the current store state is for admin authentication.\n */\n get isAdmin(): boolean {\n return getTokenPayload(this.token).type === \"admin\";\n }\n\n /**\n * Checks whether the current store state is for auth record authentication.\n */\n get isAuthRecord(): boolean {\n return getTokenPayload(this.token).type === \"authRecord\";\n }\n\n /**\n * Saves the provided new token and model data in the auth store.\n */\n save(token: string, model?: AuthModel): void {\n this.baseToken = token || \"\";\n this.baseModel = model || 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.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 model: this.model ? JSON.parse(JSON.stringify(this.model)) : 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.model && resultLength > 4096) {\n rawData.model = { id: rawData?.model?.id, email: rawData?.model?.email };\n const extraProps = [\"collectionId\", \"username\", \"verified\"];\n for (const prop in this.model) {\n if (extraProps.includes(prop)) {\n rawData.model[prop] = this.model[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.model);\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.model);\n }\n }\n}\n","import { BaseAuthStore, AuthModel } from \"@/stores/BaseAuthStore\";\n\n/**\n * The default token store for browsers with auto fallback\n * to runtime/memory if local storage is undefined (eg. 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 model(): AuthModel {\n const data = this._storageGet(this.storageKey) || {};\n\n return data.model || null;\n }\n\n /**\n * @inheritdoc\n */\n save(token: string, model?: AuthModel) {\n this._storageSet(this.storageKey, {\n token: token,\n model: model,\n });\n\n super.save(token, model);\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.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/utils/BaseService\";\nimport { CommonOptions } from \"@/services/utils/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 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 },\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","import { BaseService } from \"@/services/utils/BaseService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult } from \"@/services/utils/dtos\";\nimport { CommonOptions, ListOptions, FullListOptions } from \"@/services/utils/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 \"@/services/utils/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 \"@/stores/utils/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.model;\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 // check the collection id in case an admin and auth record share the same 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 { CrudService } from \"@/services/utils/CrudService\";\nimport { AdminModel } from \"@/services/utils/dtos\";\nimport { AuthOptions, CommonOptions } from \"@/services/utils/options\";\nimport { normalizeLegacyOptionsArgs } from \"@/services/utils/legacy\";\nimport { registerAutoRefresh, resetAutoRefresh } from \"@/services/utils/refresh\";\n\nexport interface AdminAuthResponse {\n [key: string]: any;\n\n token: string;\n admin: AdminModel;\n}\n\nexport class AdminService extends CrudService {\n /**\n * @inheritdoc\n */\n get baseCrudPath(): string {\n return \"/api/admins\";\n }\n\n // ---------------------------------------------------------------\n // Post update/delete AuthStore sync\n // ---------------------------------------------------------------\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.model` matches with the updated id, then\n * on success the `client.authStore.model` will be updated with the result.\n */\n async update(\n id: string,\n bodyParams?: { [key: string]: any } | FormData,\n options?: CommonOptions,\n ): Promise {\n return super.update(id, bodyParams, options).then((item) => {\n // update the store state if the updated item id matches with the stored model\n if (\n this.client.authStore.model?.id === item.id &&\n typeof this.client.authStore.model?.collectionId === \"undefined\" // is not record auth\n ) {\n this.client.authStore.save(this.client.authStore.token, item);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.model` 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 // clear the store state if the deleted item id matches with the stored model\n if (\n success &&\n this.client.authStore.model?.id === id &&\n typeof this.client.authStore.model?.collectionId === \"undefined\" // is not record auth\n ) {\n this.client.authStore.clear();\n }\n\n return success;\n });\n }\n\n // ---------------------------------------------------------------\n // Auth handlers\n // ---------------------------------------------------------------\n\n /**\n * Prepare successful authorize response.\n */\n protected authResponse(responseData: any): AdminAuthResponse {\n const admin = this.decode(responseData?.admin || {});\n\n if (responseData?.token && responseData?.admin) {\n this.client.authStore.save(responseData.token, admin);\n }\n\n return Object.assign({}, responseData, {\n // normalize common fields\n token: responseData?.token || \"\",\n admin: admin,\n });\n }\n\n /**\n * Authenticate an admin account with its email and password\n * and returns a new admin token and data.\n *\n * On success this method automatically updates the client's AuthStore data.\n *\n * @throws {ClientResponseError}\n */\n async authWithPassword(\n email: string,\n password: string,\n options?: AuthOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using authWithPassword(email, password, options?).\n */\n async authWithPassword(\n email: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async authWithPassword(\n email: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise {\n let options: any = {\n method: \"POST\",\n body: {\n identity: email,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authWithPassword(email, pass, body?, query?) is deprecated. Consider replacing it with authWithPassword(email, pass, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n const autoRefreshThreshold = options.autoRefreshThreshold;\n delete options.autoRefreshThreshold;\n\n // not from auto refresh reauthentication\n if (!options.autoRefresh) {\n resetAutoRefresh(this.client);\n }\n\n let authData = await this.client.send(\n this.baseCrudPath + \"/auth-with-password\",\n options,\n );\n\n authData = this.authResponse(authData);\n\n if (autoRefreshThreshold) {\n registerAutoRefresh(\n this.client,\n autoRefreshThreshold,\n () => this.authRefresh({ autoRefresh: true }),\n () =>\n this.authWithPassword(\n email,\n password,\n Object.assign({ autoRefresh: true }, options),\n ),\n );\n }\n\n return authData;\n }\n\n /**\n * Refreshes the current admin authenticated instance and\n * returns a new token and admin data.\n *\n * On success this method automatically updates the client's AuthStore data.\n *\n * @throws {ClientResponseError}\n */\n async authRefresh(options?: CommonOptions): Promise;\n\n /**\n * @deprecated\n * Consider using authRefresh(options?).\n */\n async authRefresh(body?: any, query?: any): Promise;\n\n async authRefresh(bodyOrOptions?: any, query?: any): 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.baseCrudPath + \"/auth-refresh\", options)\n .then(this.authResponse.bind(this));\n }\n\n /**\n * Sends admin 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.baseCrudPath + \"/request-password-reset\", options)\n .then(() => true);\n }\n\n /**\n * Confirms admin password reset request.\n *\n * @throws {ClientResponseError}\n */\n async confirmPasswordReset(\n resetToken: string,\n password: string,\n passwordConfirm: string,\n options?: CommonOptions,\n ): Promise;\n\n /**\n * @deprecated\n * Consider using confirmPasswordReset(resetToken, password, passwordConfirm, options?).\n */\n async confirmPasswordReset(\n resetToken: string,\n password: string,\n passwordConfirm: string,\n body?: any,\n query?: any,\n ): Promise;\n\n async confirmPasswordReset(\n resetToken: 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: resetToken,\n password: password,\n passwordConfirm: passwordConfirm,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of confirmPasswordReset(resetToken, password, passwordConfirm, body?, query?) is deprecated. Consider replacing it with confirmPasswordReset(resetToken, password, passwordConfirm, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCrudPath + \"/confirm-password-reset\", options)\n .then(() => true);\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 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","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/utils/BaseService\";\nimport { SendOptions, normalizeUnknownQueryParams } from \"@/services/utils/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 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 Client from \"@/Client\";\nimport { getTokenPayload } from \"@/stores/utils/jwt\";\nimport { CrudService } from \"@/services/utils/CrudService\";\nimport { RealtimeService, UnsubscribeFunc } from \"@/services/RealtimeService\";\nimport { ClientResponseError } from \"@/ClientResponseError\";\nimport { ListResult, RecordModel, ExternalAuthModel } from \"@/services/utils/dtos\";\nimport {\n SendOptions,\n CommonOptions,\n RecordOptions,\n RecordListOptions,\n RecordFullListOptions,\n} from \"@/services/utils/options\";\nimport { normalizeLegacyOptionsArgs } from \"@/services/utils/legacy\";\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 usernamePassword: boolean;\n emailPassword: boolean;\n onlyVerified: boolean;\n authProviders: Array;\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 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 // 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?: SendOptions,\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.model` matches with the updated id, then\n * on success the `client.authStore.model` will be updated with the result.\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.model?.id === item?.id &&\n (this.client.authStore.model?.collectionId === this.collectionIdOrName ||\n this.client.authStore.model?.collectionName ===\n this.collectionIdOrName)\n ) {\n this.client.authStore.save(this.client.authStore.token, item);\n }\n\n return item as any as T;\n });\n }\n\n /**\n * @inheritdoc\n *\n * If the current `client.authStore.model` 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.model?.id === id &&\n (this.client.authStore.model?.collectionId === this.collectionIdOrName ||\n this.client.authStore.model?.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 },\n options,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-methods\", options)\n .then((responseData: any) => {\n return Object.assign({}, responseData, {\n // normalize common fields\n usernamePassword: !!responseData?.usernamePassword,\n emailPassword: !!responseData?.emailPassword,\n authProviders: Array.isArray(responseData?.authProviders)\n ? responseData?.authProviders\n : [],\n });\n });\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\n /**\n * @deprecated\n * Consider using authWithPassword(usernameOrEmail, password, options?).\n */\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n body?: any,\n query?: any,\n ): Promise>;\n\n async authWithPassword(\n usernameOrEmail: string,\n password: string,\n bodyOrOptions?: any,\n query?: any,\n ): Promise> {\n let options: any = {\n method: \"POST\",\n body: {\n identity: usernameOrEmail,\n password: password,\n },\n };\n\n options = normalizeLegacyOptionsArgs(\n \"This form of authWithPassword(usernameOrEmail, pass, body?, query?) is deprecated. Consider replacing it with authWithPassword(usernameOrEmail, pass, options?).\",\n options,\n bodyOrOptions,\n query,\n );\n\n return this.client\n .send(this.baseCollectionPath + \"/auth-with-password\", options)\n .then((data) => this.authResponse(data));\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 * _Site-note_: 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 * @throws {ClientResponseError}\n */\n async authWithOAuth2(\n options: OAuth2AuthConfig,\n ): Promise>;\n\n async 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 const authMethods = await this.listAuthMethods();\n\n const provider = authMethods.authProviders.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 // initialize a one-off realtime service\n const realtime = new RealtimeService(this.client);\n\n // open a new popup window in case config.urlCallback is not set\n //\n // note: it is opened before the async call 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 function cleanup() {\n eagerDefaultPopup?.close();\n realtime.unsubscribe();\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: \" + 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 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\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.model` matches with the auth record from the token,\n * then on success the `client.authStore.model.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.model;\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.model` 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.model;\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 * 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 options = Object.assign(\n {\n method: \"GET\",\n },\n options,\n );\n\n return this.client.send(\n this.baseCrudPath + \"/\" + encodeURIComponent(recordId) + \"/external-auths\",\n options,\n );\n }\n\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 options = Object.assign(\n {\n method: \"DELETE\",\n },\n options,\n );\n\n return this.client\n .send(\n this.baseCrudPath +\n \"/\" +\n encodeURIComponent(recordId) +\n \"/external-auths/\" +\n encodeURIComponent(provider),\n options,\n )\n .then(() => true);\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/utils/CrudService\";\nimport { CollectionModel } from \"@/services/utils/dtos\";\nimport { CommonOptions } from \"@/services/utils/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 schema 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","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseService } from \"@/services/utils/BaseService\";\nimport { ListResult, LogModel } from \"@/services/utils/dtos\";\nimport { CommonOptions, ListOptions, LogStatsOptions } from \"@/services/utils/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/utils/BaseService\";\nimport { CommonOptions } from \"@/services/utils/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/utils/BaseService\";\nimport { CommonOptions, FileOptions } from \"@/services/utils/options\";\n\nexport class FileService extends BaseService {\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 (admin or record).\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/utils/BaseService\";\nimport { CommonOptions } from \"@/services/utils/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 * Builds a download url for a single existing backup using an\n * admin 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","import { ClientResponseError } from \"@/ClientResponseError\";\nimport { BaseAuthStore } from \"@/stores/BaseAuthStore\";\nimport { LocalAuthStore } from \"@/stores/LocalAuthStore\";\nimport { SettingsService } from \"@/services/SettingsService\";\nimport { AdminService } from \"@/services/AdminService\";\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 { RecordModel } from \"@/services/utils/dtos\";\nimport {\n SendOptions,\n FileOptions,\n normalizeUnknownQueryParams,\n} from \"@/services/utils/options\";\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 * 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) {\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\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 **Admin APIs**.\n */\n readonly admins: AdminService;\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 this.authStore = authStore || new LocalAuthStore();\n\n // services\n this.admins = new AdminService(this);\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 * Returns the RecordService associated to the specified collection.\n *\n * @param {string} idOrName\n * @return {RecordService}\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 * Legacy alias of `pb.files.getUrl()`.\n */\n getFileUrl(\n record: { [key: string]: any },\n filename: string,\n queryParams: FileOptions = {},\n ): string {\n return this.files.getUrl(record, filename, queryParams);\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 = this.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);\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 = this.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 !this.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 * Converts analyzes the provided body and converts it to FormData\n * in case a plain object with File/Blob values is used.\n */\n private convertToFormDataIfNeeded(body: any): any {\n if (\n typeof FormData === \"undefined\" ||\n typeof body === \"undefined\" ||\n typeof body !== \"object\" ||\n body === null ||\n this.isFormData(body) ||\n !this.hasBlobField(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\" && !this.hasBlobField({ 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\n /**\n * Checks if the submitted body object has at least one Blob/File field.\n */\n private hasBlobField(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 (\n (typeof Blob !== \"undefined\" && v instanceof Blob) ||\n (typeof File !== \"undefined\" && v instanceof File)\n ) {\n return true;\n }\n }\n }\n\n return false;\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 /**\n * Loosely checks if the specified body is a FormData instance.\n */\n private 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 * Serializes the provided query parameters into a query string.\n */\n private serializeQueryParams(params: { [key: string]: any }): string {\n const result: Array = [];\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}\n","import { BaseAuthStore, AuthModel } 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, model?: AuthModel): void {\n super.save(token, model);\n\n let value = \"\";\n try {\n value = JSON.stringify({ token, model });\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.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","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","model","isValid","isAdmin","type","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","toEmail","emailTemplate","template","generateAppleClientSecret","clientId","teamId","keyId","privateKey","duration","CrudService","getFullList","batchOrqueryParams","_getFullList","batch","getList","page","perPage","query","baseCrudPath","responseData","items","item","getFirstListItem","filter","requestKey","skipTotal","code","getOne","buildUrl","create","batchSize","request","async","list","concat","normalizeLegacyOptionsArgs","legacyWarn","baseOptions","bodyOrOptions","hasQuery","console","warn","resetAutoRefresh","_resetAutoRefresh","AdminService","authStore","collectionId","delete","success","authResponse","admin","authWithPassword","password","identity","autoRefreshThreshold","autoRefresh","authData","registerAutoRefresh","threshold","refreshFunc","reauthenticateFunc","oldBeforeSend","beforeSend","oldModel","unsubStoreChange","newToken","sendOptions","oldToken","headers","authRefresh","bind","requestPasswordReset","confirmPasswordReset","resetToken","passwordConfirm","knownSendOptionsKeys","normalizeUnknownQueryParams","RealtimeService","eventSource","subscriptions","lastSentSubscriptions","maxConnectTimeout","reconnectAttempts","maxReconnectAttempts","Infinity","predefinedReconnectIntervals","pendingConnects","isConnected","subscribe","topic","serialized","listener","msgEvent","submitSubscriptions","connect","unsubscribeByTopicAndListener","unsubscribe","needToSubmit","subs","getSubscriptionsByTopic","hasSubscriptionListeners","removeEventListener","disconnect","unsubscribeByPrefix","keyPrefix","hasAtleastOneTopic","startsWith","exist","keyToCheck","addAllSubscriptionListeners","getNonEmptySubscriptionKeys","getSubscriptionsCancelKey","catch","err","removeAllSubscriptionListeners","Promise","resolve","reject","initConnect","clearTimeout","connectTimeoutId","setTimeout","connectErrorHandler","EventSource","onerror","lastEventId","retries","hasUnsentSubscriptions","p","reconnectTimeoutId","connectSubs","latestTopics","t","timeout","fromReconnect","cancelRequest","close","RecordService","collectionIdOrName","baseCollectionPath","realtime","batchOrOptions","params","collectionName","record","listAuthMethods","usernamePassword","emailPassword","authProviders","usernameOrEmail","authWithOAuth2Code","provider","codeVerifier","redirectUrl","createData","authWithOAuth2","args","config","find","eagerDefaultPopup","cleanup","urlCallback","openBrowserPopup","oldState","state","error","scopes","replacements","_replaceQueryParams","authUrl","location","href","passwordResetToken","requestVerification","confirmVerification","verificationToken","verified","requestEmailChange","newEmail","confirmEmailChange","emailChangeToken","listExternalAuths","recordId","unlinkExternalAuth","urlPath","substring","parsedParams","rawParams","param","pair","hasOwnProperty","open","width","height","windowWidth","innerWidth","windowHeight","innerHeight","left","top","CollectionService","import","collections","deleteMissing","LogService","getStats","HealthService","check","FileService","getUrl","filename","queryParams","parts","download","URLSearchParams","getToken","BackupService","basename","upload","restore","getDownloadUrl","Client","baseUrl","lang","cancelControllers","recordServices","enableAutoCancellation","admins","files","logs","settings","health","backups","collection","idOrName","autoCancellation","enable","abort","cancelAllRequests","k","raw","toISOString","replaceAll","getFileUrl","origin","endsWith","pathname","initSendOptions","serializeQueryParams","getHeader","fetch","json","afterSend","convertToFormDataIfNeeded","$autoCancel","$cancelKey","isFormData","Authorization","controller","AbortController","signal","FormData","hasBlobField","form","v","append","values","File","encodedKey","AsyncAuthStore","queue","saveFunc","clearFunc","_enqueue","_loadInitial","initial","parsed","asyncCallback","_dequeue","finally","shift"],"mappings":"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"}