@tencent-ai/workbuddy-cloud-sdk 0.1.0-dev.dee063d.202608201621
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +58 -0
- package/lib/index.cjs +9271 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +6499 -0
- package/lib/index.d.ts +6499 -0
- package/lib/index.global.js +7 -0
- package/lib/index.global.js.map +1 -0
- package/lib/index.js +9228 -0
- package/lib/index.js.map +1 -0
- package/package.json +102 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/config.ts","../src/http/fetch.ts","../src/paths.ts","../src/modules/auth/protocol.ts","../src/modules/auth/session-manager.ts","../src/modules/auth/session-store.ts","../src/modules/auth/index.ts","../src/vendor/postgrest/types/common/common.ts","../src/vendor/postgrest/PostgrestError.ts","../src/vendor/postgrest/PostgrestBuilder.ts","../src/vendor/postgrest/PostgrestTransformBuilder.ts","../src/vendor/postgrest/PostgrestFilterBuilder.ts","../src/vendor/postgrest/PostgrestQueryBuilder.ts","../src/vendor/postgrest/PostgrestClient.ts","../src/modules/database.ts","../src/modules/llm/errors.ts","../src/modules/llm/models.ts","../src/modules/llm/sse.ts","../src/modules/llm/chat.ts","../src/modules/llm.ts","../src/vendor/storage/lib/common/errors.ts","../src/vendor/storage/lib/common/headers.ts","../src/vendor/storage/lib/common/helpers.ts","../src/vendor/storage/lib/common/fetch.ts","../src/vendor/storage/lib/common/BaseApiClient.ts","../src/vendor/storage/packages/StreamDownloadBuilder.ts","../src/vendor/storage/packages/BlobDownloadBuilder.ts","../src/vendor/storage/packages/StorageFileApi.ts","../src/vendor/storage/lib/version.ts","../src/vendor/storage/lib/constants.ts","../src/vendor/storage/packages/StorageBucketApi.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/errors/IcebergError.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/utils/url.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/http/createFetchClient.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/utils/idempotency-key.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/catalog/namespaces.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/catalog/tables.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/catalog/IcebergRestCatalog.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/catalog/types.ts","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/spec-pin.json","../../../node_modules/.pnpm/iceberg-js@1.0.0/node_modules/iceberg-js/src/spec-version.ts","../src/vendor/storage/packages/StorageAnalyticsClient.ts","../src/vendor/storage/packages/VectorIndexApi.ts","../src/vendor/storage/packages/VectorDataApi.ts","../src/vendor/storage/packages/VectorBucketApi.ts","../src/vendor/storage/packages/StorageVectorsClient.ts","../src/vendor/storage/StorageClient.ts","../src/modules/storage.ts","../src/client.ts","../src/http/errors.ts"],"sourcesContent":["/**\n * WorkBuddy Cloud SDK 公开入口(#89098)\n *\n * 生成应用只从这里导入。\n *\n * ⚠️ **不要从这里导出 vendor 的类型名**(`PostgrestClient` / `StorageClient` 等)。\n * vendor 是内部实现细节,泄漏到公开 d.ts 会让消费方写出依赖第三方命名的代码,\n * 之后就换不掉了。\n */\n\nexport { createWorkBuddyCloud, WorkBuddyCloudClient } from './client.js';\nexport { CLOUD_MODULE_PATHS, CLOUD_PATH_PREFIX } from './paths.js';\nexport { WorkBuddyDatabaseModule } from './modules/database.js';\nexport { AuthModule, type AuthModuleOptions } from './modules/auth/index.js';\nexport { createMemoryStorage } from './modules/auth/session-store.js';\nexport { LlmModule } from './modules/llm.js';\nexport {\n CloudStoragePathError,\n DEFAULT_SIGNED_URL_TTL_SECONDS,\n MAX_SIGNED_URL_TTL_SECONDS,\n RUNTIME_STORAGE_BUCKET,\n WorkBuddyStorageBucket,\n WorkBuddyStorageDownload,\n WorkBuddyStorageModule,\n type CloudStorageCursorFolder,\n type CloudStorageCursorObject,\n type CloudStorageCursorListOptions,\n type CloudStorageError,\n type CloudStorageFile,\n type CloudStorageFileBody,\n type CloudStorageFileOptions,\n type CloudStorageListOptions,\n type CloudStorageListResult,\n type CloudStorageMetadata,\n type CloudStorageObjectInfo,\n type CloudStorageResult,\n} from './modules/storage.js';\nexport { CloudOpenAIError } from './modules/llm/errors.js';\nexport type { OpenAIErrorObject, CloudOpenAIErrorInit } from './modules/llm/errors.js';\nexport type {\n PublicLLMModel,\n PublicModelCapabilities,\n PublicModelModalities,\n PublicModelPricing,\n ChatCompletion,\n ChatCompletionChunk,\n ChatCompletionChoice,\n ChatCompletionChunkChoice,\n ChatCompletionCreateParams,\n ChatCompletionCreateParamsStreaming,\n ChatCompletionCreateParamsNonStreaming,\n CompletionUsage,\n ChatCompletionMessage,\n ChatCompletionRequestMessage,\n ChatCompletionAssistantMessage,\n ChatCompletionTool,\n ChatCompletionToolChoice,\n ChatCompletionResponseFormat,\n ChatCompletionContentPart,\n ChatCompletionRole,\n} from './modules/llm/types.js';\nexport {\n type AuthStateChangeCallback,\n type AuthStateChangeEvent,\n type CloudAuthEvent,\n type CloudAuthStateCallback,\n type CloudAuthStorage,\n type CloudOAuthProvider,\n type CloudSession,\n type CloudUser,\n type OAuthCredentials,\n type OAuthRedirect,\n type OAuthSignInOptions,\n type OAuthStartResult,\n type OtpChallenge,\n type OtpCredentials,\n type OtpSignInChallenge,\n type OtpVerifyCredentials,\n type PasswordResetChallenge,\n type PasswordResetUpdate,\n type PasswordCredentials,\n type ResetPasswordWithOldCredentials,\n type VerifyOtpParams,\n} from './modules/auth/types.js';\nexport {\n type CloudError,\n type CloudErrorKind,\n type CloudResult,\n shouldClearCredentials,\n} from './http/errors.js';\nexport {\n anonymousTokenProvider,\n PUBLISHABLE_KEY_HEADER,\n type SessionTokenProvider,\n} from './http/fetch.js';\nexport {\n type CloudModuleName,\n type CloudRuntimeConfig,\n WorkBuddyCloudConfigError,\n type WorkBuddyCloudOptions,\n} from './types.js';\n","/**\n * WorkBuddy Cloud SDK 公共类型(#89098)\n *\n * 契约权威来源(不要在此另行发明字段):\n * - `services/cmd/agentserver/docs/genie-baas/genie-baas-phase1-design.md` §5 / §6\n * - `packages/workbuddy-server/src/cloud-service/types.ts`(`CloudServicePublicConfig`)\n *\n * 本文件只有类型与常量,不含任何 I/O。\n */\n\nimport type { CloudAuthStorage } from './modules/auth/types.js';\n\n/**\n * 四个云服务模块。数据面路径按 `/.cloud/{module}/**` 组织,\n * 前缀 `/.cloud/` 是刻意选的,避免与生成应用自有路由冲突(设计文档 §5.0)。\n */\nexport type CloudModuleName = 'auth' | 'database' | 'storage' | 'llm';\n\n/**\n * 创建客户端的入参,字段与 `CloudServicePublicConfig` 下发给应用的部分一一对应。\n *\n * ⚠️ 这里只接受公开配置。envId、CloudBase publish_key / api_key 只存服务端,\n * 任何响应都不下发(设计文档 §5.2),因此不要为它们加配置项。\n */\nexport interface WorkBuddyCloudOptions {\n /** 数据面基址,例如 `https://app.workbuddy.link`。末尾斜杠会被归一化掉。 */\n endpoint: string;\n /**\n * Google OAuth Relay 的环境中心基址,例如\n * `https://test4-api.workbuddy.cn/v2/as/genie-baas/oauth`。\n *\n * 它与 endpoint 是两条入口:endpoint 是每应用发布域名,承载 `/.cloud/**`;\n * OAuth Relay 走中心 APISIX,不能根据 endpoint 拼接。\n */\n oauthRelayBaseUrl: string;\n /**\n * 我方签发的半公开 key,格式 `wbpk_{appId}_{随机}`。\n *\n * 它只标识「哪个应用」、不携带权限,可以打进前端产物;安全性由服务端 Origin\n * 精确匹配提供(设计文档 §5.2 / §7.3)。仍不应打进日志。\n */\n publishableKey: string;\n /**\n * 自定义 fetch,便于测试与非标准运行时注入。缺省用全局 `fetch`。\n */\n fetch?: typeof globalThis.fetch;\n /**\n * 凭据存储。缺省用 localStorage(不可用时退回内存)。\n *\n * 什么时候需要显式传:\n * - 测试里要一个**干净的、与当前登录态无关**的客户端(例如验证「未登录\n * 时写数据会被拒」——若沿用 localStorage 就会带上现有身份,测不到)\n * - 非浏览器运行时(Node、小程序)里没有 localStorage\n *\n * ⚠️ **不要传 cookie 实现。** 兄弟子域可读写共享后缀 cookie,那是已识别\n * 的越权面(设计文档 §7.1)。这个选项存在是为了可注入,不是为了给 cookie\n * 留口子。\n */\n storage?: CloudAuthStorage;\n}\n\n/** 归一化后的运行期配置,四个模块共享同一份。 */\nexport interface CloudRuntimeConfig {\n /** 归一化后的 endpoint(无尾斜杠)。 */\n readonly endpoint: string;\n /** 归一化后的中心 OAuth Relay 基址(无尾斜杠)。 */\n readonly oauthRelayBaseUrl: string;\n readonly publishableKey: string;\n readonly fetch: typeof globalThis.fetch;\n}\n\n/**\n * 配置非法。**在初始化阶段就抛**,而不是等到第一次业务调用才失败 ——\n * 生成应用里这类错误几乎都是 publicConfig 没接上,早失败才好定位。\n */\nexport class WorkBuddyCloudConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WorkBuddyCloudConfigError';\n }\n}\n","/**\n * 配置校验与归一化(骨架,#89098)\n */\n\nimport {\n type CloudRuntimeConfig,\n WorkBuddyCloudConfigError,\n type WorkBuddyCloudOptions,\n} from './types.js';\n\n/** publishableKey 形态:`wbpk_{appId}_{随机}`(设计文档 §5.2)。 */\nconst PUBLISHABLE_KEY_PATTERN = /^wbpk_/;\n\nfunction normalizeHttpUrl(value: unknown, field: string): string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new WorkBuddyCloudConfigError(\n `${field} is required and must be a non-empty string.`,\n );\n }\n\n const trimmed = value.trim();\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new WorkBuddyCloudConfigError(\n `${field} must be an absolute URL, received: ${trimmed}`,\n );\n }\n\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new WorkBuddyCloudConfigError(\n `${field} must use http(s), received protocol: ${parsed.protocol}`,\n );\n }\n\n // 去掉尾斜杠,后续模块统一用 `${endpoint}${modulePath}` 拼接,避免出现 `//`。\n return trimmed.replace(/\\/+$/, '');\n}\n\nfunction normalizePublishableKey(publishableKey: unknown): string {\n if (typeof publishableKey !== 'string' || publishableKey.trim() === '') {\n throw new WorkBuddyCloudConfigError(\n 'publishableKey is required and must be a non-empty string.',\n );\n }\n\n const trimmed = publishableKey.trim();\n if (!PUBLISHABLE_KEY_PATTERN.test(trimmed)) {\n // 只校验前缀,不校验长度/字符集 —— 随机段格式由服务端签发决定,SDK 不该跟死。\n throw new WorkBuddyCloudConfigError('publishableKey must start with \"wbpk_\".');\n }\n\n return trimmed;\n}\n\nfunction resolveFetch(candidate: WorkBuddyCloudOptions['fetch']): typeof globalThis.fetch {\n if (candidate) {\n return candidate;\n }\n\n if (typeof globalThis.fetch !== 'function') {\n throw new WorkBuddyCloudConfigError(\n 'Global fetch is unavailable in this runtime; pass options.fetch explicitly.',\n );\n }\n\n // 绑定回 globalThis:某些运行时下裸取 fetch 再调用会丢 this(Illegal invocation)。\n return globalThis.fetch.bind(globalThis);\n}\n\n/** 校验并归一化用户传入的配置。任何一项不合法都会抛 {@link WorkBuddyCloudConfigError}。 */\nexport function resolveRuntimeConfig(options: WorkBuddyCloudOptions): CloudRuntimeConfig {\n if (!options || typeof options !== 'object') {\n throw new WorkBuddyCloudConfigError(\n 'createWorkBuddyCloud requires endpoint, oauthRelayBaseUrl and publishableKey.',\n );\n }\n\n return Object.freeze({\n endpoint: normalizeHttpUrl(options.endpoint, 'endpoint'),\n oauthRelayBaseUrl: normalizeHttpUrl(options.oauthRelayBaseUrl, 'oauthRelayBaseUrl'),\n publishableKey: normalizePublishableKey(options.publishableKey),\n fetch: resolveFetch(options.fetch),\n });\n}\n","/**\n * 单一 I/O 出口(骨架,#89098)\n *\n * 四个模块**共用这一个 fetch**。publishableKey 注入、自签 session 注入、超时策略\n * 都只在这里实现一次 —— 任何模块自己拼 fetch 都是架构错误:\n * 会长出多套鉴权发送方式,而 §5.2 对此有唯一规定。\n *\n * 契约来源:`services/cmd/agentserver/docs/genie-baas/genie-baas-phase1-design.md` §5.2 / §6.0\n */\n\nimport type { CloudRuntimeConfig } from '../types.js';\n\n/**\n * publishableKey 的请求头形态。\n *\n * §5.2 规定服务端同时接受两种发送方式:`clientId` 位置(TCB 语义,body/query)\n * 与本头部。SDK 统一走头部 —— 它对 GET/POST 一致,不需要按方法改写 body。\n *\n * 头名用 genie-baas 自己的品牌(`x-wb-webapp-access-key`)而非 TCB 的\n * `x-cloudbase-access-key`:genie-baas 在服务端做了凭据换签,浏览器端根本\n * 不直接对话 CloudBase,暴露 cloudbase 品牌名没有意义、也泄漏底层实现。\n * 服务端 gateway 认这个新头(见 dataplane_proxy.go 的 accessKeyHeader)。\n */\nexport const PUBLISHABLE_KEY_HEADER = 'x-wb-webapp-access-key';\n\n/**\n * 已登录终端用户的自签 session token 提供者。\n *\n * 返回 undefined 表示未登录 —— 此时按匿名身份转发(§6.1),**不是错误**。\n * 用函数而非固定值:登录/登出/刷新后无需重建 client,database、storage\n * 自动带上最新身份。\n *\n * ---------------------------------------------------------------------------\n * 为什么是异步(这一点不是可选的)\n *\n * 因为「取 token」这个动作**可能要先发一次网络请求** —— token 已过期或临近\n * 过期时必须先续期再发业务请求。同步签名下做不到这件事:\n *\n * - 同步 XHR 发续期请求:浏览器已废弃,且阻塞主线程。\n * - 只靠后台定时器续期、provider 同步读缓存:**会漏**。后台标签页的\n * setInterval 被节流到分钟级,笔记本休眠唤醒后 token 早已过期。\n * 定时器只能算优化,请求前检查才是正确性底线。\n * - 返回过期 token、靠 401 重试:见 AuthModule 里关于句柄轮换的说明 ——\n * 我方句柄一旦轮换旧的立即失效,N 个并发 401 各自去刷会把会话弄坏。\n *\n * 改异步对 vendor 完全无感:它只知道自己拿到一个返回 Promise 的 fetch\n * (`src/vendor/postgrest/PostgrestBuilder.ts` 里是 `await _fetch(...)`)。\n * ---------------------------------------------------------------------------\n */\nexport type SessionTokenProvider = () => Promise<string | undefined>;\n\n/**\n * 包装出四模块共用的 fetch。\n *\n * ⚠️ 注入的是**我方自签 session token**,不是 CloudBase 的 token ——\n * 真实 provider 凭据只存服务端,浏览器永远拿不到(§5.3)。\n *\n * ⚠️ auth 模块**自己的**请求不能用带 provider 的 fetch:`/auth/v1/token`\n * 本身就是续期端点,让它去调「取 token(必要时续期)」会死锁。装配见 client.ts。\n */\nexport function createCloudFetch(\n config: CloudRuntimeConfig,\n getSessionToken: SessionTokenProvider,\n): typeof globalThis.fetch {\n return async (input, init) => {\n const headers = new Headers(init?.headers);\n\n // 应用身份:标识「哪个应用」,不携带权限(§5.2)。\n headers.set(PUBLISHABLE_KEY_HEADER, config.publishableKey);\n\n // 终端用户身份:有则带,无则匿名。\n //\n // 已有 Authorization 时不覆盖:调用方显式指定身份的场景(例如刻意用\n // 别的 token 做越权验证)必须能压过默认注入。\n if (!headers.has('Authorization')) {\n const token = await getSessionToken();\n if (token) {\n headers.set('Authorization', `Bearer ${token}`);\n }\n }\n\n return config.fetch(input, { ...init, headers });\n };\n}\n\n/** 恒定匿名的 provider,供 auth 模块自身使用(见 createCloudFetch 的死锁说明)。 */\nexport const anonymousTokenProvider: SessionTokenProvider = () => Promise.resolve(undefined);\n","/**\n * 数据面路径前缀(骨架,#89098)\n *\n * 取值来自设计文档 §5.0 / §6.0 的路径白名单,与 skill 的 “How an App Talks to It”\n * 表格一致。**写死为常量表,不做通用拼接** —— 网关侧同样是常量映射,两边必须对齐。\n */\n\nimport type { CloudModuleName } from './types.js';\n\n/** 所有数据面路径的公共前缀。 */\nexport const CLOUD_PATH_PREFIX = '/.cloud';\n\n/**\n * 模块 → 数据面路径前缀。\n *\n * 网关剥掉 `/.cloud/{模块}` 后还原为 TCB 原路径(auth→`/auth/**`、\n * database→`/v1/rdb/rest/**`、storage→`/v1/storages/**`),该映射是服务端职责,\n * SDK 不感知,也不要在这里镜像。\n */\nexport const CLOUD_MODULE_PATHS: Readonly<Record<CloudModuleName, string>> = Object.freeze({\n auth: `${CLOUD_PATH_PREFIX}/auth`,\n database: `${CLOUD_PATH_PREFIX}/database/rest`,\n storage: `${CLOUD_PATH_PREFIX}/storage`,\n llm: `${CLOUD_PATH_PREFIX}/llm`,\n});\n","/**\n * auth 端点的请求/响应适配(#89098)\n *\n * 这一层只做三件事:拼路径、把上游响应解析成 CloudSession、把上游错误归一成\n * CloudError。业务流程在 index.ts,并发与生命周期在 session-manager.ts。\n *\n * 端点路径全部取自 `@cloudbase/js-sdk` 的 ApiUrls 常量表(v3.8.0 的\n * `consts.ts`),与服务端的放行表逐条对齐。**不要凭印象改这些字符串** ——\n * 服务端按路径精确匹配来决定「换签 / 本地处理 / 透传 / 拒绝」,改错一个字符\n * 就会掉到另一条分支上(例如带了尾斜杠会从「本地续期」掉成「透传给上游」)。\n */\n\nimport type { CloudError, CloudErrorKind } from '../../http/errors.js';\nimport type { CloudSession, CloudUser } from './types.js';\n\n/**\n * auth 端点表。\n *\n * ⚠️ 续期**只能**用 v1 的 `/v1/token`。v2 的 `/v2/token` 在服务端落在「换签」\n * 分支、会被转发给上游,而我们手里的 refresh_token 是我方句柄,上游不认识它,\n * 结果必然是 invalid_grant。\n */\nexport const AUTH_PATHS = {\n signUp: '/v1/signup',\n signIn: '/v1/signin',\n signInWithProvider: '/v1/signin/with/provider',\n /** 本地续期端点(服务端不转发上游)。 */\n token: '/v1/token',\n signOut: '/v1/user/signout',\n userMe: '/v1/user/me',\n /** 发码。 */\n verification: '/v1/verification',\n /** 验码,返回一次性的 verification_token(**不是**会话)。 */\n verificationVerify: '/v1/verification/verify',\n /** 忘记密码最终更新。 */\n resetPassword: '/v1/reset',\n /** 登录后改密的二次校验。 */\n sudo: '/v1/user/sudo',\n /** 登录后更新密码。 */\n userPassword: '/v1/user/password',\n} as const;\n\n/** 上游返回的会话形状(换签后的我方字段)。 */\ninterface RawSession {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n sub?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * 把换签后的响应解析成 CloudSession。\n *\n * ⚠️ 上游字段是**保留的**:服务端在原始 JSON 上覆盖那五个字段,其余(如\n * `is_anonymous`)原样留着。所以这里按「至少含这几个键」解析,不能假设\n * 响应里只有这五个键。\n */\nexport function parseSession(payload: unknown, receivedAt: number): CloudSession {\n const raw = (payload ?? {}) as RawSession;\n const accessToken = typeof raw.access_token === 'string' ? raw.access_token : '';\n if (!accessToken) {\n throw sessionShapeError('response has no access_token');\n }\n const refreshToken = typeof raw.refresh_token === 'string' ? raw.refresh_token : '';\n // expires_in 是**秒**(服务端 int,向零截断)。缺失时给 0,交给\n // SessionManager 的 fail-safe 当作已过期处理,而不是在这里编一个默认值。\n const expiresInSec = typeof raw.expires_in === 'number' ? raw.expires_in : 0;\n\n return {\n accessToken,\n refreshToken,\n expiresAt: receivedAt + expiresInSec * 1000,\n user: userFromSessionPayload(raw),\n };\n}\n\n/**\n * 从换签响应里取用户信息。\n *\n * 换签响应只保证有 `sub`,其它字段取决于上游返了什么 —— 需要完整用户信息时\n * 应当另调 `/v1/user/me`。这里刻意不去发那次请求:登录路径上多一个往返会让\n * 首屏变慢,而多数应用只需要一个 id。\n */\nfunction userFromSessionPayload(raw: RawSession): CloudUser {\n const isAnonymous = raw.is_anonymous === true;\n return {\n id: typeof raw.sub === 'string' ? raw.sub : '',\n isAnonymous,\n raw: raw as Record<string, unknown>,\n };\n}\n\n/**\n * 解析 `/v1/user/me` 的响应。\n *\n * 该端点服务端**纯透传**,所以拿到的是上游原始 user 对象。字段名两种都见过\n * (`sub` 与旧的 `uid`),都认。\n */\nexport function parseUser(payload: unknown): CloudUser {\n const raw = (payload ?? {}) as Record<string, unknown>;\n const id =\n typeof raw.sub === 'string' ? raw.sub : typeof raw.uid === 'string' ? raw.uid : '';\n const metadata = (raw.user_metadata ?? {}) as Record<string, unknown>;\n return {\n id,\n email: pickString(raw.email) ?? pickString(metadata.email),\n phone: pickString(raw.phone_number) ?? pickString(raw.phone),\n // 两处都判:上游在不同端点上用过不同字段表达匿名。\n isAnonymous: raw.is_anonymous === true || raw.scope === 'anonymous',\n raw,\n };\n}\n\nfunction pickString(v: unknown): string | undefined {\n return typeof v === 'string' && v !== '' ? v : undefined;\n}\n\n/** 上游错误体(OAuth2 形状,服务端归一后固定这两个字段)。 */\ninterface RawError {\n error?: unknown;\n error_description?: unknown;\n message?: unknown;\n msg?: unknown;\n code?: unknown;\n}\n\n/**\n * 把一次失败的响应归一成 CloudError。\n *\n * 映射依据是服务端的 errorMapping:它把内部错误码收敛成 OAuth2 的枚举值 +\n * 固定 HTTP 状态。这里按 (status, error) 双因素判定,不只看状态码 ——\n * 401 既可能是「key 无效」(invalid_client) 也可能是「会话失效」(invalid_grant),\n * 二者的处置完全不同:前者是配置错,后者要清凭据重登。\n */\nexport function normalizeHttpError(status: number, payload: unknown): CloudError {\n const raw = (payload ?? {}) as RawError;\n const code = typeof raw.error === 'string' ? raw.error : undefined;\n const message =\n pickString(raw.error_description) ??\n pickString(raw.message) ??\n pickString(raw.msg) ??\n `HTTP ${status}`;\n\n return { kind: errorKind(status, code), message, status, code, cause: payload };\n}\n\nfunction errorKind(status: number, code?: string): CloudErrorKind {\n if (code === 'invalid_grant') {\n return 'unauthenticated';\n }\n switch (status) {\n case 400:\n return 'invalid-request';\n case 401:\n // 走到这里说明不是 invalid_grant —— 多半是 invalid_client(key 无效\n // 或已吊销)。归到 invalid-request 会让调用方以为改参数就能好。\n return 'unauthenticated';\n case 403:\n return 'permission-denied';\n case 404:\n return 'not-found';\n case 429:\n return 'rate-limited';\n case 501:\n return 'unimplemented';\n case 503:\n return 'backend-unavailable';\n default:\n return status >= 500 ? 'backend-unavailable' : 'unknown';\n }\n}\n\n/**\n * fetch 本身失败(离线、DNS、CORS)时的归一。\n *\n * 这条路径**必须**存在:服务端对 403 与 404 刻意不回 CORS 头,所以浏览器里\n * 这两类错误表现为 fetch 抛 TypeError、**读不到响应体**。只处理 HTTP 状态码\n * 的实现会在这里静默漏掉两类真实失败。\n */\nexport function normalizeNetworkError(err: unknown): CloudError {\n const message = err instanceof Error ? err.message : String(err);\n return {\n kind: 'network',\n message: `request failed before a response was received: ${message}`,\n status: 0,\n cause: err,\n };\n}\n\nfunction sessionShapeError(reason: string): CloudError & Error {\n const e = new Error(`workbuddy-cloud auth: ${reason}`) as CloudError & Error;\n e.kind = 'unknown';\n e.status = 0;\n return e;\n}\n","/**\n * 会话生命周期:过期判定、续期、单飞、并发保护(#89098)\n *\n * ============================================================================\n * 为什么这个文件比「调一下 /auth/v1/token」复杂得多\n *\n * 我方刷新句柄的语义是:**每次成功续期都轮换,旧句柄立即失效,没有宽限期。**\n * 这一条把几个平时属于「优化」的东西变成了正确性必需项。\n *\n * 具体的失效场景(不是假想,是这套语义的必然推论):\n *\n * 3 个并发请求(database ×2 + storage ×1)同时发现 token 过期,各自拿着\n * 句柄 A 去续期。服务端侧有单飞锁,所以只有一个真的轮换成 B,另外两个抢不到\n * 锁、沿用旧记录返回(句柄仍是 A)。三个响应回到浏览器后**都会写 localStorage,\n * 且顺序不确定**:如果 B 先落盘、A 后落盘覆盖,客户端最终持有 A,而服务端\n * 已经轮换到 B、A 已失效 —— 下次续期必然 401,会话锁死。\n *\n * 注意这是**永久损坏**:本地只有失效的 A,没有任何自愈路径,用户被强制登出\n * 且重新登录前做不了任何事。\n *\n * 结论:**服务端单飞不能替代客户端单飞**。两者防的是不同的东西 ——\n * 服务端防「重复轮换」,客户端防「响应乱序覆盖 localStorage」。必须两边都有。\n *\n * 因此本文件实现四层保护,每层针对一个具体的竞态:\n *\n * 1. 单飞(inflight) —— 同一实例内的并发续期合并成一次\n * 2. commit guard —— 写入前复核 storage,句柄被别人换过就丢弃自己的结果\n * (这是唯一能挡住**跨标签页**覆盖的机制)\n * 3. 登出 epoch —— 防「登出 + 在途续期」把用户重新登入\n * 4. 失败冷却 —— 服务端故障时不让每个请求都去打 /token\n * ============================================================================\n */\n\nimport type { SessionStore } from './session-store.js';\nimport type { CloudAuthEvent, CloudSession } from './types.js';\n\n/**\n * 提前多久就认为「该续期了」。\n *\n * 余量放在**比较时**而不是写入时:写入时减会把余量固化进 localStorage,\n * 之后想调都调不了(CloudBase 就是写入时减 30s,改不动)。\n *\n * 90 秒的取值理由:token 要经网络到服务端才被校验,「本地还差 3 秒过期」的\n * token 到服务端时很可能已经过期了。留足一个网络往返加时钟偏差的余量。\n */\nconst EXPIRY_MARGIN_MS = 90_000;\n\n/**\n * 同一个句柄续期失败后的冷却时间。\n *\n * 没有冷却时的表现:服务端故障期间,进入过期窗口后**每一个**业务请求都会去打\n * 一次 /token,把故障放大成请求风暴。\n *\n * 按句柄索引而非按时间点索引:句柄一旦换新就绕过冷却立即重试 —— 换新说明\n * 上一次其实成功了,没理由继续冷却。\n */\nconst REFRESH_FAILURE_COOLDOWN_MS = 60_000;\n\n/** 续期请求的执行体,由 AuthModule 注入(它才知道怎么发 HTTP)。 */\nexport type RefreshExecutor = (refreshToken: string) => Promise<CloudSession>;\n\n/** 续期彻底失败(凭据已不可用)时通知 AuthModule 广播 SIGNED_OUT。 */\nexport type SessionEventEmitter = (event: CloudAuthEvent, session: CloudSession | null) => void;\n\n/** 判定一个错误是否意味着「凭据已废,清掉重登」。 */\nexport type CredentialsRejected = (error: unknown) => boolean;\n\nexport interface SessionManagerOptions {\n store: SessionStore;\n refresh: RefreshExecutor;\n emit: SessionEventEmitter;\n isCredentialsRejected: CredentialsRejected;\n /** 可注入时钟,仅供测试。 */\n now?: () => number;\n}\n\nexport class SessionManager {\n private readonly store: SessionStore;\n private readonly refresh: RefreshExecutor;\n private readonly emit: SessionEventEmitter;\n private readonly isCredentialsRejected: CredentialsRejected;\n private readonly now: () => number;\n\n /** 在途的续期。并发调用共享同一个 Promise(第 1 层保护)。 */\n private inflight: Promise<CloudSession | null> | null = null;\n\n /**\n * 登出计数(第 3 层保护)。\n *\n * 在任何 await **之前**同步自增,续期流程在写入前后各读一次;若期间发生过\n * 登出,就把刚拿到的新会话丢弃。否则「用户点了登出 + 一个在途续期」会让\n * 用户在登出之后被重新登入。\n */\n private signOutEpoch = 0;\n\n /** 上次续期失败的句柄与时刻(第 4 层保护)。 */\n private lastFailure: { token: string; at: number } | null = null;\n\n constructor(opts: SessionManagerOptions) {\n this.store = opts.store;\n this.refresh = opts.refresh;\n this.emit = opts.emit;\n this.isCredentialsRejected = opts.isCredentialsRejected;\n this.now = opts.now ?? Date.now;\n }\n\n /** 读当前会话(不触发续期)。总是从 storage 重读,见 session-store.ts。 */\n peek(): CloudSession | null {\n return this.store.read();\n }\n\n /**\n * 取一个**当前可用**的会话,必要时先续期。\n *\n * 这是 database / storage 请求路径上的入口,所以它必须「要么给一个能用的\n * token,要么给 null」,不能给一个即将过期的 token 让调用方去撞 401。\n */\n async ensure(): Promise<CloudSession | null> {\n const current = this.store.read();\n if (!current) {\n return null;\n }\n if (!this.isExpiring(current)) {\n return current;\n }\n if (!current.refreshToken) {\n // 没句柄就续不了。清掉:留着一个永远刷不动的会话,表现是每个请求\n // 都先白跑一次续期再失败。\n return this.abandon();\n }\n return this.refreshOnce(current);\n }\n\n /**\n * 强制续期一次,无论是否临近过期。\n *\n * 对外暴露给 `auth.refreshSession()` —— 应用有时需要在拿到「权限刚变更」\n * 的信号后立刻换一份新 token。\n */\n async forceRefresh(): Promise<CloudSession | null> {\n const current = this.store.read();\n if (!current?.refreshToken) {\n return null;\n }\n return this.refreshOnce(current, { ignoreCooldown: true });\n }\n\n /** 登录成功后落盘并广播。 */\n commitSignIn(session: CloudSession): CloudSession {\n this.lastFailure = null;\n this.store.write(session);\n this.emit('SIGNED_IN', session);\n return session;\n }\n\n /** 用户信息变更(如匿名升级重签了 token)后落盘并广播。 */\n commitUserUpdate(session: CloudSession): CloudSession {\n this.store.write(session);\n this.emit('USER_UPDATED', session);\n return session;\n }\n\n /**\n * 清掉本地会话并广播登出。\n *\n * 同步自增 epoch 是关键(见 signOutEpoch 注释)——必须在任何 await 之前。\n */\n clear(): void {\n this.signOutEpoch += 1;\n this.lastFailure = null;\n this.inflight = null;\n this.store.clear();\n this.emit('SIGNED_OUT', null);\n }\n\n /** 是否已进入「该续期」的窗口。 */\n private isExpiring(session: CloudSession): boolean {\n // 缺 expiresAt 一律当作已过期(fail-safe):宁可多刷一次,也不要拿着\n // 一个不知道什么时候过期的 token 一直用下去。\n if (typeof session.expiresAt !== 'number') {\n return true;\n }\n return session.expiresAt - this.now() < EXPIRY_MARGIN_MS;\n }\n\n /** 单飞入口:在途则复用,否则起一次。 */\n private refreshOnce(\n current: CloudSession,\n opts: { ignoreCooldown?: boolean } = {},\n ): Promise<CloudSession | null> {\n if (this.inflight) {\n return this.inflight;\n }\n if (!opts.ignoreCooldown && this.inCooldown(current.refreshToken)) {\n // 冷却期内直接给出「没有可用会话」,不去打服务端。\n return Promise.resolve(null);\n }\n const task = this.doRefresh(current).finally(() => {\n this.inflight = null;\n });\n this.inflight = task;\n return task;\n }\n\n private inCooldown(refreshToken: string): boolean {\n const f = this.lastFailure;\n return (\n f !== null &&\n f.token === refreshToken &&\n this.now() - f.at < REFRESH_FAILURE_COOLDOWN_MS\n );\n }\n\n /** 实际续期,含 commit guard 与 epoch 复核。 */\n private async doRefresh(current: CloudSession): Promise<CloudSession | null> {\n const epochBefore = this.signOutEpoch;\n const handleBefore = current.refreshToken;\n\n let next: CloudSession;\n try {\n next = await this.refresh(handleBefore);\n } catch (err) {\n return this.onRefreshFailed(handleBefore, err);\n }\n\n // --- 第 3 层:期间是否发生过登出 -----------------------------------\n if (this.signOutEpoch !== epochBefore) {\n // 用户在续期途中登出了。把刚拿到的会话丢掉 —— 落盘就等于把用户\n // 重新登入,那是明确违背用户意图的。\n this.store.clear();\n return null;\n }\n\n // --- 第 2 层:commit guard ----------------------------------------\n // 复核 storage:若期间**别人**(另一个标签页)已经用同一个句柄换过一份\n // 新会话,那份才是服务端认的。此时写入自己的结果会把对方的覆盖掉,\n // 而被覆盖的那个句柄很可能已失效 —— 正是会话锁死的成因。\n const latest = this.store.read();\n if (latest && latest.refreshToken !== handleBefore) {\n return latest;\n }\n\n this.lastFailure = null;\n this.store.write(next);\n this.emit('TOKEN_REFRESHED', next);\n return next;\n }\n\n /**\n * 续期失败的分流。\n *\n * 「凭据被拒」与「网络/服务端故障」必须区别对待:\n * - 凭据被拒(invalid_grant)→ 会话已不可能恢复,清掉并广播登出。留着它\n * 只会让每个后续请求都先白跑一次续期。\n * - 其它(网络、5xx)→ **保留**会话,只记冷却。这类失败会自愈,清掉等于\n * 把一次网络抖动升级成用户被强制登出。\n */\n private onRefreshFailed(handle: string, err: unknown): CloudSession | null {\n if (this.isCredentialsRejected(err)) {\n return this.abandon();\n }\n this.lastFailure = { token: handle, at: this.now() };\n return null;\n }\n\n /** 会话已不可恢复:清本地并广播登出。 */\n private abandon(): null {\n this.store.clear();\n this.lastFailure = null;\n this.emit('SIGNED_OUT', null);\n return null;\n }\n}\n","/**\n * 会话持久化(#89098)\n *\n * ---------------------------------------------------------------------------\n * localStorage 是**唯一真源**,内存里不留副本\n * ---------------------------------------------------------------------------\n *\n * 每次取 session 都重读 localStorage,承担一次同步读的开销,换「绝不读到脏值」。\n *\n * 为什么不能缓存在内存里:凭据存 localStorage,那么「另一个标签页登出了」\n * 或「另一个标签页刚把刷新句柄轮换了」这类事件,只有重读才能发现。任何长期\n * 驻留的内存副本都会变脏,而变脏的后果不是「多一次 401」——我方句柄一旦轮换\n * 旧的立即失效,拿着脏句柄去续期会把会话彻底弄坏(见 session-manager.ts)。\n *\n * 两家 BaaS SDK 都是这个结论:CloudBase 的 LocalCredentials 注释直接写了\n * 「storage 为凭证的唯一可信来源」;supabase 的 GoTrueClient 每次\n * `__loadSession` 都重读 storage。\n */\n\nimport type { CloudAuthStorage, CloudSession } from './types.js';\n\n/**\n * 存储 key 前缀。\n *\n * 带上 publishableKey:同一浏览器可能开着同平台的多个应用,共用一个 key 会让\n * 它们互相顶掉登录态。\n */\nconst STORAGE_KEY_PREFIX = 'workbuddy-cloud.session.';\n\n/** 内存实现,供测试与无 localStorage 的运行时使用。 */\nexport function createMemoryStorage(): CloudAuthStorage {\n const map = new Map<string, string>();\n return {\n getItem: (k) => map.get(k) ?? null,\n setItem: (k, v) => void map.set(k, v),\n removeItem: (k) => void map.delete(k),\n };\n}\n\n/**\n * 解析出可用的 storage。\n *\n * localStorage 在隐私模式、禁用第三方存储、部分 WebView 里访问即抛,所以要\n * 探测而不是假设存在。探测不到就退回内存版 —— 此时刷新页面会掉登录态,\n * 但**功能可用**,比整个 SDK 初始化就抛异常要好。\n */\nexport function resolveStorage(candidate?: CloudAuthStorage): CloudAuthStorage {\n if (candidate) {\n return candidate;\n }\n try {\n const probe = '__workbuddy_probe__';\n globalThis.localStorage.setItem(probe, '1');\n globalThis.localStorage.removeItem(probe);\n return globalThis.localStorage;\n } catch {\n return createMemoryStorage();\n }\n}\n\n/**\n * 会话读写。\n *\n * 只做「读 / 写 / 删」三件事,不含任何过期判定与刷新逻辑 —— 那些在\n * session-manager.ts。分开是因为持久化的正确性(脏数据、序列化)与并发的\n * 正确性(单飞、commit guard)是两类问题,混在一起两边都难看清。\n */\nexport class SessionStore {\n private readonly key: string;\n\n constructor(\n private readonly storage: CloudAuthStorage,\n publishableKey: string,\n ) {\n this.key = STORAGE_KEY_PREFIX + publishableKey;\n }\n\n /**\n * 读当前会话。\n *\n * 任何解析失败都当作「没有会话」并**顺手清掉**那条脏记录:残留的坏 JSON\n * 会让每次读都失败一次,而用户永远不知道该去清哪个 key。\n * 触发场景真实存在 —— 用户手改 localStorage、SDK 升级换了存储格式。\n */\n read(): CloudSession | null {\n let raw: string | null;\n try {\n raw = this.storage.getItem(this.key);\n } catch {\n return null;\n }\n if (!raw) {\n return null;\n }\n try {\n const parsed = JSON.parse(raw) as unknown;\n return isStoredSession(parsed) ? parsed : this.discard();\n } catch {\n return this.discard();\n }\n }\n\n write(session: CloudSession): void {\n try {\n this.storage.setItem(this.key, JSON.stringify(session));\n } catch {\n // 写失败(配额满 / 隐私模式)不能让登录整体失败:内存里这次调用\n // 返回的 session 仍然可用,只是刷新页面会掉。\n }\n }\n\n clear(): void {\n try {\n this.storage.removeItem(this.key);\n } catch {\n // 同上:清理失败不该抛给调用方,登出的语义是「尽力清干净」。\n }\n }\n\n private discard(): null {\n this.clear();\n return null;\n }\n}\n\n/**\n * 校验存储内容的形状。\n *\n * 逐字段检查而不是只判 `typeof === 'object'`:格式升级后旧记录会缺字段,\n * 那时候「读到一个缺 refreshToken 的 session」比「读不到」更难查 ——\n * 它会一路走到续期时才炸。\n */\nfunction isStoredSession(value: unknown): value is CloudSession {\n if (!value || typeof value !== 'object') {\n return false;\n }\n const s = value as Record<string, unknown>;\n return (\n typeof s.accessToken === 'string' &&\n s.accessToken !== '' &&\n typeof s.refreshToken === 'string' &&\n typeof s.expiresAt === 'number' &&\n !!s.user &&\n typeof s.user === 'object'\n );\n}\n","/**\n * Auth 模块(#89098)\n *\n * 数据面 `/.cloud/auth/v1/**`。\n *\n * **四个模块里唯一自研的**。Auth 也是唯一不能纯透传的能力:登录响应里 provider\n * 的 token 必须被换成我方自签 session,续期在服务端完成(§5.3 / §6.0)。\n *\n * ============================================================================\n * 本模块是整个客户端的**身份唯一来源**\n *\n * database / storage 的请求身份不由它们自己管 —— client.ts 把\n * `() => auth.getAccessToken()` 交给共享 fetch,于是登录一次其它模块自动带上\n * 身份,登出一次其它模块自动变匿名。调用方不需要(也不应该)手动搬 token。\n *\n * 这也意味着 `getAccessToken()` 在**每个** database/storage 请求前都会被调用、\n * 且可能被高并发调用 —— 它必须便宜且幂等。过期续期的并发保护在\n * session-manager.ts。\n * ============================================================================\n */\n\nimport type { CloudError, CloudResult } from '../../http/errors.js';\nimport { CLOUD_MODULE_PATHS } from '../../paths.js';\nimport type { CloudRuntimeConfig } from '../../types.js';\nimport {\n AUTH_PATHS,\n normalizeHttpError,\n normalizeNetworkError,\n parseSession,\n parseUser,\n} from './protocol.js';\nimport { SessionManager } from './session-manager.js';\nimport { resolveStorage, SessionStore } from './session-store.js';\nimport type {\n CloudAuthEvent,\n CloudAuthStateCallback,\n CloudAuthStorage,\n CloudSession,\n CloudUser,\n OAuthRedirect,\n OAuthSignInOptions,\n OtpChallenge,\n OtpCredentials,\n OtpSignInChallenge,\n PasswordResetChallenge,\n PasswordCredentials,\n ResetPasswordWithOldCredentials,\n VerifyOtpParams,\n} from './types.js';\n\nexport interface AuthModuleOptions {\n /** 凭据存储。缺省用 localStorage(探测失败退回内存)。 */\n storage?: CloudAuthStorage;\n}\n\nexport class AuthModule {\n /** 该模块的数据面基址。 */\n readonly baseUrl: string;\n\n private readonly sessions: SessionManager;\n private readonly storage: CloudAuthStorage;\n private readonly oauthRelayBaseUrl: string;\n private readonly listeners = new Map<number, CloudAuthStateCallback>();\n private nextListenerId = 1;\n\n /**\n * @param fetch 必须是**不带 session provider** 的 fetch。\n *\n * 原因:本模块的 `/v1/token` 就是续期端点;若它走「取 token(必要时先续期)」\n * 那条出口,续期就会调用自己 —— 死锁。CloudBase 的 OAuth2Client 为同一个\n * 问题留了逃生口,注释里直接写了 \"may cause deadlock during initialization\"。\n * 装配见 client.ts。\n */\n constructor(\n config: CloudRuntimeConfig,\n private readonly fetch: typeof globalThis.fetch,\n opts: AuthModuleOptions = {},\n ) {\n this.baseUrl = `${config.endpoint}${CLOUD_MODULE_PATHS.auth}`;\n this.oauthRelayBaseUrl = config.oauthRelayBaseUrl;\n this.storage = resolveStorage(opts.storage);\n this.sessions = new SessionManager({\n store: new SessionStore(this.storage, config.publishableKey),\n refresh: (handle) => this.exchangeRefreshHandle(handle),\n emit: (event, session) => this.notify(event, session),\n isCredentialsRejected: (err) => isCloudError(err) && rejectedCredentials(err),\n });\n }\n\n // ------------------------------------------------------------------\n // 供 client.ts 装配共享 fetch 用\n // ------------------------------------------------------------------\n\n /**\n * 取一个当前可用的 access token,必要时先续期。无会话返回 undefined。\n *\n * database / storage 的每个请求都会调它 —— 返回 undefined 表示匿名,\n * 那是合法状态不是错误(服务端按 anon 角色处理)。\n */\n async getAccessToken(): Promise<string | undefined> {\n const session = await this.sessions.ensure();\n return session?.accessToken;\n }\n\n // ------------------------------------------------------------------\n // 登录\n // ------------------------------------------------------------------\n\n /** 邮箱 + 密码登录。当前环境未启用手机号或匿名登录。 */\n async signInWithPassword(credentials: PasswordCredentials): Promise<CloudResult<CloudSession>> {\n if (!credentials.email || !credentials.password) {\n return fail(badRequest('signInWithPassword requires email and password'));\n }\n return this.postForSession(AUTH_PATHS.signIn, {\n username: credentials.email,\n password: credentials.password,\n });\n }\n\n /**\n * 注册。\n *\n * 上游要求先完成验证码验证,所以必须带一个 `verificationToken`(来自\n * `verifyOtp`)。只有用户名+密码的注册会被上游明确拒绝。\n */\n async signUp(\n credentials: PasswordCredentials & { verificationToken: string },\n ): Promise<CloudResult<CloudSession>> {\n if (!credentials.email) {\n return fail(badRequest('signUp requires email'));\n }\n if (!credentials.verificationToken) {\n return fail(\n badRequest(\n 'signUp requires a verificationToken; run sendOtp + verifyOtp first ' +\n '(the provider rejects username+password-only signup)',\n ),\n );\n }\n const body: Record<string, unknown> = {\n verification_token: credentials.verificationToken,\n };\n body.email = credentials.email;\n if (credentials.password) body.password = credentials.password;\n return this.postForSession(AUTH_PATHS.signUp, body);\n }\n\n /**\n * 发邮箱验证码。\n *\n * 这一步**不产生会话**,只返回一个 `verificationId`。发码由上游完成,\n * 我方不实现发码逻辑。\n *\n * 返回的 `isExistingUser` 决定验码之后走登录还是注册 —— 该判断由上游给出,\n * SDK 不猜。\n */\n async sendOtp(credentials: OtpCredentials): Promise<CloudResult<OtpChallenge>> {\n if (!credentials.email) {\n return fail(badRequest('sendOtp requires email'));\n }\n const body: Record<string, unknown> = {\n email: credentials.email,\n usage: 'EMAIL',\n };\n if (credentials.emailRedirectTo) body.email_redirect_to = credentials.emailRedirectTo;\n\n const res = await this.request(AUTH_PATHS.verification, { method: 'POST', body });\n if (res.error) {\n return fail(res.error);\n }\n const payload = (res.data ?? {}) as Record<string, unknown>;\n const verificationId =\n typeof payload.verification_id === 'string' ? payload.verification_id : '';\n if (!verificationId) {\n return fail(badRequest('provider returned no verification_id'));\n }\n return ok({ verificationId, isExistingUser: payload.is_user === true });\n }\n\n /** gotrue 风格的 OTP 入口:发码后由 challenge.verify 完成登录。 */\n async signInWithOtp(\n credentials: OtpCredentials,\n ): Promise<CloudResult<OtpSignInChallenge>> {\n const sent = await this.sendOtp(credentials);\n if (sent.error) {\n return fail(sent.error);\n }\n const { verificationId, isExistingUser } = sent.data;\n return ok({\n verificationId,\n isExistingUser,\n isUser: isExistingUser,\n verify: ({ token }) =>\n this.verifyOtp({\n verificationId,\n token,\n email: credentials.email,\n isExistingUser,\n }),\n });\n }\n\n /**\n * 验码并登录(或注册后登录)。\n *\n * 两步:先用验证码换一个**一次性** `verification_token`,再用它换会话。\n * 中间那个 token 不是会话 —— 拿它当 Bearer 会被拒。\n *\n * 走登录还是注册由 `isExistingUser` 决定(`sendOtp` 的返回值)。刻意不做\n * 「先试登录失败再试注册」的兜底:那会把「密码错」这类真实错误掩盖成一次\n * 莫名的注册尝试。\n */\n async verifyOtp(\n params: VerifyOtpParams & { isExistingUser: boolean },\n ): Promise<CloudResult<CloudSession>> {\n if (!params.verificationId || !params.token || !params.email) {\n return fail(badRequest('verifyOtp requires verificationId, token and email'));\n }\n const verified = await this.request(AUTH_PATHS.verificationVerify, {\n method: 'POST',\n body: {\n verification_id: params.verificationId,\n verification_code: params.token,\n },\n });\n if (verified.error) {\n return fail(verified.error);\n }\n const vt = (verified.data ?? {}) as Record<string, unknown>;\n const verificationToken =\n typeof vt.verification_token === 'string' ? vt.verification_token : '';\n if (!verificationToken) {\n return fail(badRequest('provider returned no verification_token'));\n }\n\n if (params.isExistingUser) {\n return this.postForSession(AUTH_PATHS.signIn, {\n username: params.email,\n verification_token: verificationToken,\n });\n }\n return this.signUp({\n email: params.email,\n password: params.password ?? '',\n verificationToken,\n });\n }\n\n // ------------------------------------------------------------------\n // OAuth\n // ------------------------------------------------------------------\n\n /**\n * 发起第三方登录,返回该把用户送去的地址。\n *\n * 一期固定走 Cloud Backend Service OAuth Relay。IdP 回调白名单只登记平台\n * 统一域名,由 Relay 把结果转回具体应用;应用不需要理解 Provider 配置、\n * state 校验或回调白名单。\n *\n * SDK 不自己跳转(不写 `location.href`):跳转时机应由应用决定 —— 有的要\n * 先存草稿,有的在 iframe 里要开弹窗。返回 url 交调用方处置。\n */\n async signInWithOAuth(options: OAuthSignInOptions): Promise<CloudResult<OAuthRedirect>> {\n if (options.provider !== 'google') {\n return fail(badRequest('signInWithOAuth currently supports only google'));\n }\n const redirectTo = options.redirectTo ?? currentPageUrl();\n if (!redirectTo) {\n return fail(\n badRequest('signInWithOAuth requires redirectTo outside a browser environment'),\n );\n }\n return this.startRelayOAuth(options, redirectTo);\n }\n\n /**\n * 完成第三方登录:读回调 URL 上的参数换会话。\n *\n * 在回调落地页调一次即可。`code` 缺失时返回 `null` 数据而**不是**错误 ——\n * 落地页可能被直接访问(用户收藏了它),那不是失败。\n */\n async handleOAuthCallback(search?: string): Promise<CloudResult<CloudSession | null>> {\n const callbackInput = search ?? currentPageSearch();\n let query = callbackInput;\n try {\n if (/^https?:\\/\\//i.test(callbackInput)) {\n query = new URL(callbackInput).search;\n }\n } catch {\n return fail(badRequest('oauth callback URL is invalid'));\n }\n const params = new URLSearchParams(query);\n // 上游的失败也从 query 回来(用户点了「拒绝授权」)。\n const oauthError = params.get('error') ?? params.get('error_description');\n if (oauthError) {\n return fail({\n kind: 'unauthenticated',\n message: `oauth provider rejected the request: ${oauthError}`,\n status: 0,\n });\n }\n const code = params.get('code');\n if (!code) {\n return ok(null);\n }\n\n const state = params.get('state') ?? '';\n const providerId = params.get('provider_id');\n if (providerId !== 'custom-oauth') {\n return fail(badRequest('oauth callback requires provider_id=custom-oauth'));\n }\n if (!state) {\n return fail(badRequest('oauth callback requires state'));\n }\n\n const body: Record<string, unknown> = {\n provider_id: providerId,\n provider_code: code,\n state,\n provider_params: { state },\n };\n return this.postForSession(AUTH_PATHS.signInWithProvider, body);\n }\n\n /** 忘记密码:发码,验证码通过后更新密码并自动登录。 */\n async resetPasswordForEmail(\n email: string,\n ): Promise<CloudResult<PasswordResetChallenge>> {\n if (!email) {\n return fail(badRequest('resetPasswordForEmail requires email'));\n }\n const sent = await this.request(AUTH_PATHS.verification, {\n method: 'POST',\n body: { email, usage: 'PASSWORD_RESET', target: 'USER' },\n });\n if (sent.error) {\n return fail(sent.error);\n }\n const payload = (sent.data ?? {}) as Record<string, unknown>;\n const verificationId =\n typeof payload.verification_id === 'string' ? payload.verification_id : '';\n if (!verificationId) {\n return fail(badRequest('provider returned no verification_id'));\n }\n return ok({\n updateUser: async ({ nonce, password }) => {\n const verified = await this.request(AUTH_PATHS.verificationVerify, {\n method: 'POST',\n body: {\n verification_id: verificationId,\n verification_code: nonce,\n },\n });\n if (verified.error) {\n return fail(verified.error);\n }\n const verifiedPayload = (verified.data ?? {}) as Record<string, unknown>;\n const verificationToken =\n typeof verifiedPayload.verification_token === 'string'\n ? verifiedPayload.verification_token\n : '';\n if (!verificationToken) {\n return fail(badRequest('provider returned no verification_token'));\n }\n const reset = await this.request(AUTH_PATHS.resetPassword, {\n method: 'POST',\n body: {\n email,\n new_password: password,\n verification_token: verificationToken,\n },\n });\n if (reset.error) {\n return fail(reset.error);\n }\n const signedIn = await this.signInWithPassword({ email, password });\n if (!signedIn.error) {\n this.notify('PASSWORD_RECOVERY', signedIn.data);\n }\n return signedIn;\n },\n });\n }\n\n /** 登录后使用旧密码进行 sudo 校验并更新密码。 */\n async resetPasswordForOld(\n credentials: ResetPasswordWithOldCredentials,\n ): Promise<CloudResult<CloudSession>> {\n const token = await this.getAccessToken();\n if (!token) {\n return fail({ kind: 'unauthenticated', message: 'no active session', status: 0 });\n }\n const sudo = await this.request(AUTH_PATHS.sudo, {\n method: 'POST',\n token,\n body: { password: credentials.oldPassword },\n });\n if (sudo.error) {\n return fail(sudo.error);\n }\n const payload = (sudo.data ?? {}) as Record<string, unknown>;\n const sudoToken = typeof payload.sudo_token === 'string' ? payload.sudo_token : '';\n if (!sudoToken) {\n return fail(badRequest('provider returned no sudo_token'));\n }\n const updated = await this.request(AUTH_PATHS.userPassword, {\n method: 'PATCH',\n token,\n body: { sudo_token: sudoToken, new_password: credentials.newPassword },\n });\n if (updated.error) {\n return fail(updated.error);\n }\n const session = await this.getSession();\n if (session.data) {\n this.notify('USER_UPDATED', session.data);\n return ok(session.data);\n }\n return fail(session.error ?? {\n kind: 'unauthenticated',\n message: 'no active session',\n status: 0,\n });\n }\n\n // ------------------------------------------------------------------\n // 会话\n // ------------------------------------------------------------------\n\n /**\n * 读当前会话。\n *\n * 会在临近过期时**顺手续期** —— 只读本地不续期的话,调用方拿到一个还剩\n * 3 秒有效期的 token 去发请求,到服务端就已经过期了。\n */\n async getSession(): Promise<CloudResult<CloudSession | null>> {\n try {\n return ok(await this.sessions.ensure());\n } catch (err) {\n return fail(isCloudError(err) ? err : normalizeNetworkError(err));\n }\n }\n\n /** 强制续期一次,不管是否临近过期。 */\n async refreshSession(): Promise<CloudResult<CloudSession | null>> {\n try {\n return ok(await this.sessions.forceRefresh());\n } catch (err) {\n return fail(isCloudError(err) ? err : normalizeNetworkError(err));\n }\n }\n\n /**\n * 读当前用户。\n *\n * 会发请求(`/v1/user/me`)而不是读本地 session —— 后者的 user 字段来自\n * 登录那一刻,可能已过时(别处改了昵称、或匿名已升级为实名)。\n */\n async getUser(): Promise<CloudResult<CloudUser>> {\n const token = await this.getAccessToken();\n if (!token) {\n return fail({ kind: 'unauthenticated', message: 'no active session', status: 0 });\n }\n const res = await this.request(AUTH_PATHS.userMe, { method: 'GET', token });\n if (res.error) {\n // 会话在服务端已失效(例如别处登出了):本地也要清,否则界面会一直\n // 显示登录态却什么都做不了。\n if (rejectedCredentials(res.error)) {\n this.sessions.clear();\n }\n return fail(res.error);\n }\n return ok(parseUser(res.data));\n }\n\n /**\n * 登出。\n *\n * 无论服务端返回什么都清本地:服务端侧是**无条件销毁**的(转发上游之后就\n * 销毁,不看上游成败),本地留着只会让界面显示一个已经不能用的登录态。\n * 断网时也必须能登出。\n */\n async signOut(): Promise<CloudResult<null>> {\n const session = this.sessions.peek();\n if (session?.accessToken) {\n // 必须带 Authorization:不带的话服务端不知道要销毁哪个会话,\n // 会静默什么都不做。\n await this.request(AUTH_PATHS.signOut, {\n method: 'POST',\n body: {},\n token: session.accessToken,\n });\n }\n this.sessions.clear();\n return ok(null);\n }\n\n /**\n * 订阅登录态变化。返回取消订阅函数。\n *\n * 订阅时会**立即**回放一次 `INITIAL_SESSION`:没有它,调用方无法区分\n * 「还没初始化完」与「初始化完了但未登录」,首屏会闪一下登录页。\n */\n onAuthStateChange(callback: CloudAuthStateCallback): () => void {\n const id = this.nextListenerId++;\n this.listeners.set(id, callback);\n // 同步回放,不推到微任务:调用方常在首次 render 前订阅,延迟一拍就会\n // 多渲染一帧未登录状态。\n safeInvoke(callback, 'INITIAL_SESSION', this.sessions.peek());\n return () => void this.listeners.delete(id);\n }\n\n // ------------------------------------------------------------------\n // 内部\n // ------------------------------------------------------------------\n\n /** 拼出平台 Relay 授权地址;state 由 Relay 自己签发、校验并一次性消费。 */\n private async startRelayOAuth(\n options: OAuthSignInOptions,\n redirectTo: string,\n ): Promise<CloudResult<OAuthRedirect>> {\n // Cloud Backend Relay 自己签发、校验并一次性消费 state;应用只提供最终\n // callback URL,不能自行生成或覆盖 state。\n const callback = new URL(redirectTo);\n const relay = new URL(`${this.oauthRelayBaseUrl}/authorize`);\n relay.searchParams.set('provider', options.provider);\n relay.searchParams.set('callback_url', callback.toString());\n\n return ok({ url: relay.toString() });\n }\n\n /** 用我方句柄换新会话。这是 SessionManager 注入的续期执行体。 */\n private async exchangeRefreshHandle(handle: string): Promise<CloudSession> {\n // 刻意**不带** Authorization:句柄本身就是凭据;带上一个已过期的\n // access token 反而会在服务端的鉴权阶段先被 401 挡掉。\n const res = await this.request(AUTH_PATHS.token, {\n method: 'POST',\n body: { grant_type: 'refresh_token', refresh_token: handle },\n });\n if (res.error) {\n throw res.error;\n }\n return parseSession(res.data, Date.now());\n }\n\n /** POST 一个换签端点并把响应解析成会话。 */\n private async postForSession(\n path: string,\n body: unknown,\n opts: { headers?: Record<string, string> } = {},\n ): Promise<CloudResult<CloudSession>> {\n const res = await this.request(path, { method: 'POST', body, headers: opts.headers });\n if (res.error) {\n return fail(res.error);\n }\n try {\n return ok(this.sessions.commitSignIn(parseSession(res.data, Date.now())));\n } catch (err) {\n return fail(isCloudError(err) ? err : normalizeNetworkError(err));\n }\n }\n\n /** 发一次 auth 请求并归一错误。 */\n private async request(\n path: string,\n init: {\n method: string;\n body?: unknown;\n token?: string;\n headers?: Record<string, string>;\n },\n ): Promise<CloudResult<unknown>> {\n const headers: Record<string, string> = { ...init.headers };\n if (init.body !== undefined) {\n // Content-Type 必须是 JSON:服务端只在这个前提下才解析 body\n // (它要从里面找 refresh_token / redirect_uri 等字段)。\n headers['Content-Type'] = 'application/json';\n }\n if (init.token) {\n headers.Authorization = `Bearer ${init.token}`;\n }\n\n let response: Response;\n try {\n response = await this.fetch(this.baseUrl + path, {\n method: init.method,\n headers,\n body: init.body === undefined ? undefined : JSON.stringify(init.body),\n });\n } catch (err) {\n // fetch 层失败。403/404 在浏览器里也会走到这里(服务端对这两类刻意\n // 不回 CORS 头),所以这条分支不是「只有断网才进」。\n return fail(normalizeNetworkError(err));\n }\n\n const payload = await readBody(response);\n if (!response.ok) {\n return fail(normalizeHttpError(response.status, payload));\n }\n return ok(payload);\n }\n\n /** 广播事件。单个监听器抛错不能影响其它监听器与主流程。 */\n private notify(event: CloudAuthEvent, session: CloudSession | null): void {\n for (const cb of this.listeners.values()) {\n safeInvoke(cb, event, session);\n }\n }\n}\n\n// ----------------------------------------------------------------------\n// 小工具\n// ----------------------------------------------------------------------\n\nfunction ok<T>(data: T): CloudResult<T> {\n return { data, error: null };\n}\n\nfunction fail<T>(error: CloudError): CloudResult<T> {\n return { data: null, error };\n}\n\nfunction badRequest(message: string): CloudError {\n return { kind: 'invalid-request', message, status: 0 };\n}\n\nfunction isCloudError(v: unknown): v is CloudError {\n return !!v && typeof v === 'object' && typeof (v as CloudError).kind === 'string';\n}\n\n/** 该错误是否意味着本地凭据已废。 */\nfunction rejectedCredentials(error: CloudError): boolean {\n return error.kind === 'unauthenticated' || error.code === 'invalid_grant';\n}\n\nasync function readBody(response: Response): Promise<unknown> {\n const text = await response.text();\n if (!text) {\n return null;\n }\n try {\n return JSON.parse(text);\n } catch {\n // 非 JSON 响应(网关错误页等):包一层,让上层仍能拿到原文。\n return { message: text };\n }\n}\n\nfunction safeInvoke(\n cb: CloudAuthStateCallback,\n event: CloudAuthEvent,\n session: CloudSession | null,\n): void {\n try {\n cb(event, session);\n } catch {\n // 监听器里的异常是调用方的问题,不能让它中断登录/登出流程。\n }\n}\n\n/** 当前页地址(去掉 query 与 hash)—— OAuth 回调的缺省落地点。 */\nfunction currentPageUrl(): string {\n const loc = globalThis.location;\n return loc ? loc.origin + loc.pathname : '';\n}\n\nfunction currentPageSearch(): string {\n return globalThis.location?.search ?? '';\n}\n","// Types that are shared between supabase-js and postgrest-js\n\nexport type Fetch = typeof fetch\n\n/**\n * Default number of retry attempts.\n */\nexport const DEFAULT_MAX_RETRIES = 3\n\n/**\n * Default exponential backoff delay function.\n * Delays: 1s, 2s, 4s, 8s, ... (max 30s)\n *\n * @param attemptIndex - Zero-based index of the retry attempt\n * @returns Delay in milliseconds before the next retry\n */\nexport const getRetryDelay = (attemptIndex: number): number =>\n Math.min(1000 * 2 ** attemptIndex, 30000)\n\n/**\n * Status codes that are safe to retry.\n * 520 = Cloudflare timeout/connection errors (transient)\n * 503 = PostgREST schema cache not yet loaded (transient, signals retry via Retry-After header)\n */\nexport const RETRYABLE_STATUS_CODES = [520, 503] as const\n\n/**\n * HTTP methods that are safe to retry (idempotent operations).\n */\nexport const RETRYABLE_METHODS = ['GET', 'HEAD', 'OPTIONS'] as const\n\nexport type GenericRelationship = {\n foreignKeyName: string\n columns: string[]\n isOneToOne?: boolean\n referencedRelation: string\n referencedColumns: string[]\n}\n\nexport type GenericTable = {\n Row: Record<string, unknown>\n Insert: Record<string, unknown>\n Update: Record<string, unknown>\n Relationships: GenericRelationship[]\n}\n\nexport type GenericUpdatableView = {\n Row: Record<string, unknown>\n Insert: Record<string, unknown>\n Update: Record<string, unknown>\n Relationships: GenericRelationship[]\n}\n\nexport type GenericNonUpdatableView = {\n Row: Record<string, unknown>\n Relationships: GenericRelationship[]\n}\n\nexport type GenericView = GenericUpdatableView | GenericNonUpdatableView\n\nexport type GenericSetofOption = {\n isSetofReturn?: boolean | undefined\n isOneToOne?: boolean | undefined\n isNotNullable?: boolean | undefined\n to: string\n from: string\n}\n\nexport type GenericFunction = {\n Args: Record<string, unknown> | never\n Returns: unknown\n SetofOptions?: GenericSetofOption\n}\n\nexport type GenericSchema = {\n Tables: Record<string, GenericTable>\n Views: Record<string, GenericView>\n Functions: Record<string, GenericFunction>\n}\n\nexport type ClientServerOptions = {\n PostgrestVersion?: string\n}\n","/**\n * Error format\n *\n * Returned by every PostgREST request that fails. When something fails, the\n * single most useful field is usually `hint` — Postgres often returns the\n * actionable fix there, not in `message`. Always log the full object (e.g.\n * `console.error(error)`); logging only `error.message` hides the hint.\n *\n * Read the fields in roughly this order of usefulness:\n *\n * - `hint` — actionable guidance from the database when available. For\n * permission-denied errors (`42501`), this is the literal SQL to fix the\n * problem, e.g.\n * `\"Grant the required privileges to the current role with: GRANT SELECT ON public.users TO anon;\"`.\n * Missing column? `hint` suggests the column you probably meant. Whenever\n * Postgres knows the fix, it puts it in `hint`.\n * - `code` — stable error code from PostgREST (e.g. `PGRST301`) or Postgres\n * (e.g. `42501`). Branch on this rather than on `message` text.\n * - `details` — extra context, often the offending value, key, or row.\n * - `message` — human-readable summary. Useful in UI strings; less useful\n * for debugging.\n *\n * {@link https://postgrest.org/en/stable/api.html?highlight=options#errors-and-http-status-codes}\n */\nexport default class PostgrestError extends Error {\n details: string\n hint: string\n code: string\n\n /**\n * @example\n * ```ts\n * import PostgrestError from '@supabase/postgrest-js'\n *\n * throw new PostgrestError({\n * message: 'Row level security prevented the request',\n * details: 'RLS denied the insert',\n * hint: 'Check your policies',\n * code: 'PGRST301',\n * })\n * ```\n */\n constructor(context: { message: string; details: string; hint: string; code: string }) {\n super(context.message)\n this.name = 'PostgrestError'\n this.details = context.details\n this.hint = context.hint\n this.code = context.code\n }\n\n toJSON(): { name: string; message: string; details: string; hint: string; code: string } {\n return {\n name: this.name,\n message: this.message,\n details: this.details,\n hint: this.hint,\n code: this.code,\n }\n }\n}\n","import type {\n PostgrestSingleResponse,\n PostgrestResponseSuccess,\n CheckMatchingArrayTypes,\n MergePartialResult,\n IsValidResultOverride,\n} from './types/types'\nimport {\n ClientServerOptions,\n Fetch,\n DEFAULT_MAX_RETRIES,\n getRetryDelay,\n RETRYABLE_STATUS_CODES,\n RETRYABLE_METHODS,\n} from './types/common/common'\nimport PostgrestError from './PostgrestError'\nimport { ContainsNull } from './select-query-parser/types'\n\n/**\n * Sleep for a given number of milliseconds.\n * If an AbortSignal is provided, the sleep resolves early when the signal is aborted.\n */\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal?.aborted) {\n resolve()\n return\n }\n const id = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n function onAbort() {\n clearTimeout(id)\n resolve()\n }\n signal?.addEventListener('abort', onAbort)\n })\n}\n\n/**\n * Check if a request should be retried based on method and status code.\n */\nfunction shouldRetry(\n method: string,\n status: number,\n attemptCount: number,\n retryEnabled: boolean\n): boolean {\n // Don't retry if retries are disabled or we've exhausted attempts\n if (!retryEnabled || attemptCount >= DEFAULT_MAX_RETRIES) {\n return false\n }\n\n // Only retry idempotent methods (GET, HEAD, OPTIONS)\n if (!RETRYABLE_METHODS.includes(method as (typeof RETRYABLE_METHODS)[number])) {\n return false\n }\n\n // Only retry on specific status codes (520 - Cloudflare errors)\n if (!RETRYABLE_STATUS_CODES.includes(status as (typeof RETRYABLE_STATUS_CODES)[number])) {\n return false\n }\n\n return true\n}\n\nexport default abstract class PostgrestBuilder<\n ClientOptions extends ClientServerOptions,\n Result,\n ThrowOnError extends boolean = false,\n> implements PromiseLike<\n ThrowOnError extends true ? PostgrestResponseSuccess<Result> : PostgrestSingleResponse<Result>\n> {\n protected method: 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'DELETE'\n protected url: URL\n protected headers: Headers\n protected schema?: string\n protected body?: unknown\n protected shouldThrowOnError = false\n protected signal?: AbortSignal\n protected fetch: Fetch\n protected isMaybeSingle: boolean\n protected shouldStripNulls: boolean\n protected urlLengthLimit: number\n\n // Retry configuration - enabled by default\n protected retryEnabled: boolean = true\n\n /**\n * Creates a builder configured for a specific PostgREST request.\n *\n * @example Using supabase-js (recommended)\n * ```ts\n * import { createClient } from '@supabase/supabase-js'\n *\n * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')\n * const { data, error } = await supabase.from('users').select('*')\n * ```\n *\n * @category Database\n *\n * @example Standalone import for bundle-sensitive environments\n * ```ts\n * import { PostgrestQueryBuilder } from '@supabase/postgrest-js'\n *\n * const builder = new PostgrestQueryBuilder(\n * new URL('https://xyzcompany.supabase.co/rest/v1/users'),\n * { headers: new Headers({ apikey: 'your-publishable-key' }) }\n * )\n * ```\n */\n constructor(builder: {\n method: 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'DELETE'\n url: URL\n headers: HeadersInit\n schema?: string\n body?: unknown\n shouldThrowOnError?: boolean\n signal?: AbortSignal\n fetch?: Fetch\n isMaybeSingle?: boolean\n shouldStripNulls?: boolean\n urlLengthLimit?: number\n // Retry option\n retry?: boolean\n }) {\n this.method = builder.method\n this.url = builder.url\n this.headers = new Headers(builder.headers)\n this.schema = builder.schema\n this.body = builder.body\n this.shouldThrowOnError = builder.shouldThrowOnError ?? false\n this.signal = builder.signal\n this.isMaybeSingle = builder.isMaybeSingle ?? false\n this.shouldStripNulls = builder.shouldStripNulls ?? false\n this.urlLengthLimit = builder.urlLengthLimit ?? 8000\n this.retryEnabled = builder.retry ?? true\n\n if (builder.fetch) {\n this.fetch = builder.fetch\n } else {\n this.fetch = fetch\n }\n }\n\n /**\n * If there's an error with the query, throwOnError will reject the promise by\n * throwing the error instead of returning it as part of a successful response.\n *\n * {@link https://github.com/supabase/supabase-js/issues/92}\n *\n * @category Database\n * @subcategory Using modifiers\n */\n throwOnError(): PostgrestBuilder<ClientOptions, Result, true> {\n this.shouldThrowOnError = true\n return this as PostgrestBuilder<ClientOptions, Result, true>\n }\n\n /**\n * Strip null values from the response data. Properties with `null` values\n * will be omitted from the returned JSON objects.\n *\n * Requires PostgREST 11.2.0+.\n *\n * {@link https://docs.postgrest.org/en/stable/references/api/resource_representation.html#stripped-nulls}\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .stripNulls()\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text, bio text);\n *\n * insert into\n * characters (id, name, bio)\n * values\n * (1, 'Luke', null),\n * (2, 'Leia', 'Princess of Alderaan');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Luke\"\n * },\n * {\n * \"id\": 2,\n * \"name\": \"Leia\",\n * \"bio\": \"Princess of Alderaan\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n stripNulls(): this {\n if (this.headers.get('Accept') === 'text/csv') {\n throw new Error('stripNulls() cannot be used with csv()')\n }\n this.shouldStripNulls = true\n return this\n }\n\n /**\n * Set an HTTP header on this single PostgREST request, overriding any header\n * with the same name set on the client.\n *\n * This is an advanced escape hatch for one-off needs (passing a custom\n * `Authorization` for a single query, attaching a tracing header, etc.).\n * Most callers do not need it: configure client-wide headers via the\n * `headers` option when constructing the client, and authentication via\n * Supabase Auth.\n *\n * @param name - HTTP header name\n * @param value - HTTP header value\n *\n * @category Database\n * @subcategory Using modifiers\n */\n setHeader(name: string, value: string): this {\n this.headers = new Headers(this.headers)\n this.headers.set(name, value)\n return this\n }\n\n /**\n * @category Database\n * @subcategory Using modifiers\n *\n * Configure retry behavior for this request.\n *\n * By default, retries are enabled for idempotent requests (GET, HEAD, OPTIONS)\n * that fail with network errors or specific HTTP status codes (503, 520).\n * Retries use exponential backoff (1s, 2s, 4s) with a maximum of 3 attempts.\n *\n * @param enabled - Whether to enable retries for this request\n *\n * @example\n * ```ts\n * // Disable retries for a specific query\n * const { data, error } = await supabase\n * .from('users')\n * .select()\n * .retry(false)\n * ```\n */\n retry(enabled: boolean): this {\n this.retryEnabled = enabled\n return this\n }\n\n then<\n TResult1 = ThrowOnError extends true\n ? PostgrestResponseSuccess<Result>\n : PostgrestSingleResponse<Result>,\n TResult2 = never,\n >(\n onfulfilled?:\n | ((\n value: ThrowOnError extends true\n ? PostgrestResponseSuccess<Result>\n : PostgrestSingleResponse<Result>\n ) => TResult1 | PromiseLike<TResult1>)\n | undefined\n | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null\n ): PromiseLike<TResult1 | TResult2> {\n // https://postgrest.org/en/stable/api.html#switching-schemas\n if (this.schema === undefined) {\n // skip\n } else if (['GET', 'HEAD'].includes(this.method)) {\n this.headers.set('Accept-Profile', this.schema)\n } else {\n this.headers.set('Content-Profile', this.schema)\n }\n if (this.method !== 'GET' && this.method !== 'HEAD') {\n this.headers.set('Content-Type', 'application/json')\n }\n\n // https://docs.postgrest.org/en/stable/references/api/resource_representation.html#stripped-nulls\n if (this.shouldStripNulls) {\n const currentAccept = this.headers.get('Accept')\n if (currentAccept === 'application/vnd.pgrst.object+json') {\n this.headers.set('Accept', 'application/vnd.pgrst.object+json;nulls=stripped')\n } else if (!currentAccept || currentAccept === 'application/json') {\n this.headers.set('Accept', 'application/vnd.pgrst.array+json;nulls=stripped')\n }\n }\n\n // NOTE: Invoke w/o `this` to avoid illegal invocation error.\n // https://github.com/supabase/postgrest-js/pull/247\n const _fetch = this.fetch\n\n // Execute fetch with retry logic\n const executeWithRetry = async (): Promise<{\n error: any\n data: any\n count: number | null\n status: number\n statusText: string\n }> => {\n let attemptCount = 0\n\n while (true) {\n // Serialize headers as a plain object rather than a Headers instance.\n // React Native's XHR-based fetch silently drops headers (notably Content-Type)\n // when given a Headers instance, causing PGRST202 on parameter-less RPC calls.\n // See supabase/supabase-js#1562 and facebook/react-native#33933.\n // All sibling packages (auth-js, storage-js, functions-js) already pass plain objects.\n const headers: Record<string, string> = {}\n this.headers.forEach((value, key) => {\n headers[key] = value\n })\n if (attemptCount > 0) {\n headers['X-Retry-Count'] = String(attemptCount)\n }\n\n // Only wrap the fetch call itself — processResponse errors must never trigger retries\n let res: Response\n try {\n res = await _fetch(this.url.toString(), {\n method: this.method,\n headers,\n body: JSON.stringify(this.body, (_, value) =>\n typeof value === 'bigint' ? value.toString() : value\n ),\n signal: this.signal,\n })\n // JS allows throwing any value, and serverless or realm-crossing fetch\n // implementations can reject with non-Error objects. `instanceof Error`\n // is too narrow here; narrow at the use site with optional chaining.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (fetchError: any) {\n // Never retry aborted requests\n if (fetchError?.name === 'AbortError' || fetchError?.code === 'ABORT_ERR') {\n throw fetchError\n }\n\n // Don't retry network errors for non-idempotent methods\n if (!RETRYABLE_METHODS.includes(this.method as (typeof RETRYABLE_METHODS)[number])) {\n throw fetchError\n }\n\n // Check if we should retry network errors\n if (this.retryEnabled && attemptCount < DEFAULT_MAX_RETRIES) {\n const delay = getRetryDelay(attemptCount)\n attemptCount++\n await sleep(delay, this.signal)\n continue\n }\n\n // Exhausted retries or retries disabled, throw the last error\n throw fetchError\n }\n\n // Check if we should retry this HTTP response\n if (shouldRetry(this.method, res.status, attemptCount, this.retryEnabled)) {\n const retryAfterHeader = res.headers?.get('Retry-After') ?? null\n const delay =\n retryAfterHeader !== null\n ? Math.max(0, parseInt(retryAfterHeader, 10) || 0) * 1000\n : getRetryDelay(attemptCount)\n await res.text()\n attemptCount++\n await sleep(delay, this.signal)\n continue\n }\n\n return await this.processResponse(res)\n }\n }\n\n let res = executeWithRetry()\n\n if (!this.shouldThrowOnError) {\n res = res.catch((fetchError) => {\n // Build detailed error information including cause if available\n // Note: We don't populate code/hint for client-side network errors since those\n // fields are meant for upstream service errors (PostgREST/PostgreSQL)\n let errorDetails = ''\n let hint = ''\n let code = ''\n\n // Add cause information if available (e.g., DNS errors, network failures)\n const cause = fetchError?.cause\n if (cause) {\n const causeMessage = cause?.message ?? ''\n const causeCode = cause?.code ?? ''\n\n errorDetails = `${fetchError?.name ?? 'FetchError'}: ${fetchError?.message}`\n errorDetails += `\\n\\nCaused by: ${cause?.name ?? 'Error'}: ${causeMessage}`\n if (causeCode) {\n errorDetails += ` (${causeCode})`\n }\n if (cause?.stack) {\n errorDetails += `\\n${cause.stack}`\n }\n } else {\n // No cause available, just include the error stack\n errorDetails = fetchError?.stack ?? ''\n }\n\n // Get URL length for potential hints\n const urlLength = this.url.toString().length\n\n // Handle AbortError specially with helpful hints\n if (fetchError?.name === 'AbortError' || fetchError?.code === 'ABORT_ERR') {\n code = ''\n hint = 'Request was aborted (timeout or manual cancellation)'\n\n if (urlLength > this.urlLengthLimit) {\n hint += `. Note: Your request URL is ${urlLength} characters, which may exceed server limits. If selecting many fields, consider using views. If filtering with large arrays (e.g., .in('id', [many IDs])), consider using an RPC function to pass values server-side.`\n }\n }\n // Handle HeadersOverflowError from undici (Node.js fetch implementation)\n else if (\n cause?.name === 'HeadersOverflowError' ||\n cause?.code === 'UND_ERR_HEADERS_OVERFLOW'\n ) {\n code = ''\n hint = 'HTTP headers exceeded server limits (typically 16KB)'\n\n if (urlLength > this.urlLengthLimit) {\n hint += `. Your request URL is ${urlLength} characters. If selecting many fields, consider using views. If filtering with large arrays (e.g., .in('id', [200+ IDs])), consider using an RPC function instead.`\n }\n }\n\n return {\n success: false as const,\n error: {\n message: `${fetchError?.name ?? 'FetchError'}: ${fetchError?.message}`,\n details: errorDetails,\n hint: hint,\n code: code,\n },\n data: null,\n count: null,\n status: 0,\n statusText: '',\n }\n })\n }\n\n return (\n res as Promise<\n ThrowOnError extends true\n ? PostgrestResponseSuccess<Result>\n : PostgrestSingleResponse<Result>\n >\n ).then(onfulfilled, onrejected)\n }\n\n /**\n * Process a fetch response and return the standardized postgrest response.\n */\n private async processResponse(res: Response): Promise<{\n success: boolean\n error: any\n data: any\n count: number | null\n status: number\n statusText: string\n }> {\n let error = null\n let data = null\n let count: number | null = null\n let status = res.status\n let statusText = res.statusText\n\n if (res.ok) {\n if (this.method !== 'HEAD') {\n const body = await res.text()\n if (body === '') {\n // Prefer: return=minimal\n } else if (this.headers.get('Accept') === 'text/csv') {\n data = body\n } else if (\n this.headers.get('Accept') &&\n this.headers.get('Accept')?.includes('application/vnd.pgrst.plan+text')\n ) {\n data = body\n } else {\n try {\n data = JSON.parse(body)\n } catch {\n // A 2xx status doesn't guarantee a JSON body; mirror the non-2xx fallback below.\n error = { message: body }\n data = null\n\n if (this.shouldThrowOnError) {\n throw new PostgrestError({ message: body, details: '', hint: '', code: '' })\n }\n }\n }\n }\n\n const countHeader = this.headers.get('Prefer')?.match(/count=(exact|planned|estimated)/)\n const contentRange = res.headers.get('content-range')?.split('/')\n if (countHeader && contentRange && contentRange.length > 1) {\n count = parseInt(contentRange[1])\n }\n\n // Fix for https://github.com/supabase/postgrest-js/issues/361 — applies to all methods.\n if (this.isMaybeSingle && Array.isArray(data)) {\n if (data.length > 1) {\n error = {\n // https://github.com/PostgREST/postgrest/blob/a867d79c42419af16c18c3fb019eba8df992626f/src/PostgREST/Error.hs#L553\n code: 'PGRST116',\n details: `Results contain ${data.length} rows, application/vnd.pgrst.object+json requires 1 row`,\n hint: null,\n message: 'JSON object requested, multiple (or no) rows returned',\n }\n data = null\n count = null\n status = 406\n statusText = 'Not Acceptable'\n\n if (this.shouldThrowOnError) {\n // `hint` is null in the returned error to match PostgREST, but\n // PostgrestError types it as a string, like the other throws here.\n throw new PostgrestError({ ...error, hint: error.hint ?? '' })\n }\n } else if (data.length === 1) {\n data = data[0]\n } else {\n data = null\n }\n }\n } else {\n const body = await res.text()\n\n try {\n error = JSON.parse(body)\n\n // Workaround for https://github.com/supabase/postgrest-js/issues/295\n if (Array.isArray(error) && res.status === 404) {\n data = []\n error = null\n status = 200\n statusText = 'OK'\n }\n } catch {\n // Workaround for https://github.com/supabase/postgrest-js/issues/295\n if (res.status === 404 && body === '') {\n status = 204\n statusText = 'No Content'\n } else {\n error = {\n message: body,\n }\n }\n }\n\n if (error && this.shouldThrowOnError) {\n throw new PostgrestError(error)\n }\n }\n\n return {\n success: error === null,\n error,\n data,\n count,\n status,\n statusText,\n }\n }\n\n /**\n * Override the type of the returned `data`.\n *\n * @typeParam NewResult - The new result type to override with\n * @deprecated Use overrideTypes<yourType, { merge: false }>() method at the end of your call chain instead\n *\n * @category Database\n * @subcategory Using modifiers\n */\n returns<NewResult>(): PostgrestBuilder<\n ClientOptions,\n CheckMatchingArrayTypes<Result, NewResult>,\n ThrowOnError\n > {\n /* istanbul ignore next */\n return this as unknown as PostgrestBuilder<\n ClientOptions,\n CheckMatchingArrayTypes<Result, NewResult>,\n ThrowOnError\n >\n }\n\n /**\n * Override the type of the returned `data` field in the response.\n *\n * @typeParam NewResult - The new type to cast the response data to\n * @typeParam Options - Optional type configuration (defaults to { merge: true })\n * @typeParam Options.merge - When true, merges the new type with existing return type. When false, replaces the existing types entirely (defaults to true)\n * @example\n * ```typescript\n * // Merge with existing types (default behavior)\n * const query = supabase\n * .from('users')\n * .select()\n * .overrideTypes<{ custom_field: string }>()\n *\n * // Replace existing types completely\n * const replaceQuery = supabase\n * .from('users')\n * .select()\n * .overrideTypes<{ id: number; name: string }, { merge: false }>()\n * ```\n * @returns A PostgrestBuilder instance with the new type\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example Complete Override type of successful response\n * ```ts\n * const { data } = await supabase\n * .from('countries')\n * .select()\n * .overrideTypes<Array<MyType>, { merge: false }>()\n * ```\n *\n * @exampleResponse Complete Override type of successful response\n * ```ts\n * let x: typeof data // MyType[]\n * ```\n *\n * @example Complete Override type of object response\n * ```ts\n * const { data } = await supabase\n * .from('countries')\n * .select()\n * .maybeSingle()\n * .overrideTypes<MyType, { merge: false }>()\n * ```\n *\n * @exampleResponse Complete Override type of object response\n * ```ts\n * let x: typeof data // MyType | null\n * ```\n *\n * @example Partial Override type of successful response\n * ```ts\n * const { data } = await supabase\n * .from('countries')\n * .select()\n * .overrideTypes<Array<{ status: \"A\" | \"B\" }>>()\n * ```\n *\n * @exampleResponse Partial Override type of successful response\n * ```ts\n * let x: typeof data // Array<CountryRowProperties & { status: \"A\" | \"B\" }>\n * ```\n *\n * @example Partial Override type of object response\n * ```ts\n * const { data } = await supabase\n * .from('countries')\n * .select()\n * .maybeSingle()\n * .overrideTypes<{ status: \"A\" | \"B\" }>()\n * ```\n *\n * @exampleResponse Partial Override type of object response\n * ```ts\n * let x: typeof data // CountryRowProperties & { status: \"A\" | \"B\" } | null\n * ```\n *\n * @example Merge vs replace existing types\n * ```typescript\n * // Merge with existing types (default behavior)\n * const query = supabase\n * .from('users')\n * .select()\n * .overrideTypes<{ custom_field: string }>()\n *\n * // Replace existing types completely\n * const replaceQuery = supabase\n * .from('users')\n * .select()\n * .overrideTypes<{ id: number; name: string }, { merge: false }>()\n * ```\n */\n overrideTypes<\n NewResult,\n Options extends { merge?: boolean } = { merge: true },\n >(): PostgrestBuilder<\n ClientOptions,\n IsValidResultOverride<Result, NewResult, false, false> extends true\n ? // Preserve the optionality of the result if the overriden type is an object (case of chaining with `maybeSingle`)\n ContainsNull<Result> extends true\n ? MergePartialResult<NewResult, NonNullable<Result>, Options> | null\n : MergePartialResult<NewResult, Result, Options>\n : CheckMatchingArrayTypes<Result, NewResult>,\n ThrowOnError\n > {\n return this as unknown as PostgrestBuilder<\n ClientOptions,\n IsValidResultOverride<Result, NewResult, false, false> extends true\n ? // Preserve the optionality of the result if the overriden type is an object (case of chaining with `maybeSingle`)\n ContainsNull<Result> extends true\n ? MergePartialResult<NewResult, NonNullable<Result>, Options> | null\n : MergePartialResult<NewResult, Result, Options>\n : CheckMatchingArrayTypes<Result, NewResult>,\n ThrowOnError\n >\n }\n}\n","import PostgrestBuilder from './PostgrestBuilder'\nimport PostgrestFilterBuilder, { InvalidMethodError } from './PostgrestFilterBuilder'\nimport { GetResult } from './select-query-parser/result'\nimport { CheckMatchingArrayTypes } from './types/types'\nimport { ClientServerOptions, GenericSchema } from './types/common/common'\nimport type { MaxAffectedEnabled } from './types/feature-flags'\n\nexport default class PostgrestTransformBuilder<\n ClientOptions extends ClientServerOptions,\n Schema extends GenericSchema,\n Row extends Record<string, unknown>,\n Result,\n RelationName = unknown,\n Relationships = unknown,\n Method = unknown,\n ThrowOnError extends boolean = false,\n> extends PostgrestBuilder<ClientOptions, Result, ThrowOnError> {\n throwOnError(): PostgrestTransformBuilder<\n ClientOptions,\n Schema,\n Row,\n Result,\n RelationName,\n Relationships,\n Method,\n true\n > {\n return super.throwOnError() as PostgrestTransformBuilder<\n ClientOptions,\n Schema,\n Row,\n Result,\n RelationName,\n Relationships,\n Method,\n true\n >\n }\n\n /**\n * Perform a SELECT on the query result.\n *\n * By default, `.insert()`, `.update()`, `.upsert()`, and `.delete()` do not\n * return modified rows. By calling this method, modified rows are returned in\n * `data`.\n *\n * @param columns - The columns to retrieve, separated by commas\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example With `upsert()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .upsert({ id: 1, name: 'Han Solo' })\n * .select()\n * ```\n *\n * @exampleSql With `upsert()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Han');\n * ```\n *\n * @exampleResponse With `upsert()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Han Solo\"\n * }\n * ],\n * \"status\": 201,\n * \"statusText\": \"\"\n * }\n * ```\n */\n select<\n Query extends string = '*',\n NewResultOne = GetResult<Schema, Row, RelationName, Relationships, Query, ClientOptions>,\n >(\n columns?: Query\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Row,\n Method extends 'RPC'\n ? Result extends unknown[]\n ? NewResultOne[]\n : NewResultOne\n : NewResultOne[],\n RelationName,\n Relationships,\n Method,\n ThrowOnError\n > {\n // Remove whitespaces except when quoted\n let quoted = false\n const cleanedColumns = (columns ?? '*')\n .split('')\n .map((c) => {\n if (/\\s/.test(c) && !quoted) {\n return ''\n }\n if (c === '\"') {\n quoted = !quoted\n }\n return c\n })\n .join('')\n this.url.searchParams.set('select', cleanedColumns)\n this.headers.append('Prefer', 'return=representation')\n return this as unknown as PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Row,\n Method extends 'RPC'\n ? Result extends unknown[]\n ? NewResultOne[]\n : NewResultOne\n : NewResultOne[],\n RelationName,\n Relationships,\n Method,\n ThrowOnError\n >\n }\n\n /**\n * Order the query result by `column`.\n *\n * You can call this method multiple times to order by multiple columns.\n *\n * You can order referenced tables, but it only affects the ordering of the\n * parent table if you use `!inner` in the query.\n *\n * @param column - The column to order by\n * @param options - Named parameters\n * @param options.ascending - If `true`, the result will be in ascending order\n * @param options.nullsFirst - If `true`, `null`s appear first. If `false`,\n * `null`s appear last.\n * @param options.referencedTable - Set this to order a referenced table by\n * its columns\n *\n * @category Database\n * @subcategory Using modifiers\n */\n order<ColumnName extends string & keyof Row>(\n column: ColumnName,\n options?: { ascending?: boolean; nullsFirst?: boolean; referencedTable?: undefined }\n ): this\n order(\n column: string,\n options?: { ascending?: boolean; nullsFirst?: boolean; referencedTable?: string }\n ): this\n /**\n * @deprecated Use `options.referencedTable` instead of `options.foreignTable`\n */\n order<ColumnName extends string & keyof Row>(\n column: ColumnName,\n options?: { ascending?: boolean; nullsFirst?: boolean; foreignTable?: undefined }\n ): this\n /**\n * @deprecated Use `options.referencedTable` instead of `options.foreignTable`\n */\n order(\n column: string,\n options?: { ascending?: boolean; nullsFirst?: boolean; foreignTable?: string }\n ): this\n /**\n * Order the query result by `column`.\n *\n * You can call this method multiple times to order by multiple columns.\n *\n * You can order referenced tables, but it only affects the ordering of the\n * parent table if you use `!inner` in the query.\n *\n * @param column - The column to order by\n * @param options - Named parameters\n * @param options.ascending - If `true`, the result will be in ascending order\n * @param options.nullsFirst - If `true`, `null`s appear first. If `false`,\n * `null`s appear last.\n * @param options.referencedTable - Set this to order a referenced table by\n * its columns\n * @param options.foreignTable - Deprecated, use `options.referencedTable`\n * instead\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select('id, name')\n * .order('id', { ascending: false })\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 3,\n * \"name\": \"Han\"\n * },\n * {\n * \"id\": 2,\n * \"name\": \"Leia\"\n * },\n * {\n * \"id\": 1,\n * \"name\": \"Luke\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription On a referenced table\n * Ordering with `referencedTable` doesn't affect the ordering of the\n * parent table.\n *\n * @example On a referenced table\n * ```ts\n * const { data, error } = await supabase\n * .from('orchestral_sections')\n * .select(`\n * name,\n * instruments (\n * name\n * )\n * `)\n * .order('name', { referencedTable: 'instruments', ascending: false })\n *\n * ```\n *\n * @exampleSql On a referenced table\n * ```sql\n * create table\n * orchestral_sections (id int8 primary key, name text);\n * create table\n * instruments (\n * id int8 primary key,\n * section_id int8 not null references orchestral_sections,\n * name text\n * );\n *\n * insert into\n * orchestral_sections (id, name)\n * values\n * (1, 'strings'),\n * (2, 'woodwinds');\n * insert into\n * instruments (id, section_id, name)\n * values\n * (1, 1, 'harp'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse On a referenced table\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"strings\",\n * \"instruments\": [\n * {\n * \"name\": \"violin\"\n * },\n * {\n * \"name\": \"harp\"\n * }\n * ]\n * },\n * {\n * \"name\": \"woodwinds\",\n * \"instruments\": []\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Order parent table by a referenced table\n * Ordering with `referenced_table(col)` affects the ordering of the\n * parent table.\n *\n * @example Order parent table by a referenced table\n * ```ts\n * const { data, error } = await supabase\n * .from('instruments')\n * .select(`\n * name,\n * section:orchestral_sections (\n * name\n * )\n * `)\n * .order('section(name)', { ascending: true })\n *\n * ```\n *\n * @exampleSql Order parent table by a referenced table\n * ```sql\n * create table\n * orchestral_sections (id int8 primary key, name text);\n * create table\n * instruments (\n * id int8 primary key,\n * section_id int8 not null references orchestral_sections,\n * name text\n * );\n *\n * insert into\n * orchestral_sections (id, name)\n * values\n * (1, 'strings'),\n * (2, 'woodwinds');\n * insert into\n * instruments (id, section_id, name)\n * values\n * (1, 2, 'flute'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse Order parent table by a referenced table\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"violin\",\n * \"orchestral_sections\": {\"name\": \"strings\"}\n * },\n * {\n * \"name\": \"flute\",\n * \"orchestral_sections\": {\"name\": \"woodwinds\"}\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n order(\n column: string,\n {\n ascending = true,\n nullsFirst,\n foreignTable,\n referencedTable = foreignTable,\n }: {\n ascending?: boolean\n nullsFirst?: boolean\n foreignTable?: string\n referencedTable?: string\n } = {}\n ): this {\n const key = referencedTable ? `${referencedTable}.order` : 'order'\n const existingOrder = this.url.searchParams.get(key)\n\n this.url.searchParams.set(\n key,\n `${existingOrder ? `${existingOrder},` : ''}${column}.${ascending ? 'asc' : 'desc'}${\n nullsFirst === undefined ? '' : nullsFirst ? '.nullsfirst' : '.nullslast'\n }`\n )\n return this\n }\n\n /**\n * Limit the query result by `rows`.\n *\n * @param rows - The maximum number of rows to return\n * @param options - Named parameters\n * @param options.referencedTable - Set this to limit rows of referenced\n * tables instead of the parent table\n * @param options.foreignTable - Deprecated, use `options.referencedTable`\n * instead\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select('name')\n * .limit(1)\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Luke\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example On a referenced table\n * ```ts\n * const { data, error } = await supabase\n * .from('orchestral_sections')\n * .select(`\n * name,\n * instruments (\n * name\n * )\n * `)\n * .limit(1, { referencedTable: 'instruments' })\n * ```\n *\n * @exampleSql On a referenced table\n * ```sql\n * create table\n * orchestral_sections (id int8 primary key, name text);\n * create table\n * instruments (\n * id int8 primary key,\n * section_id int8 not null references orchestral_sections,\n * name text\n * );\n *\n * insert into\n * orchestral_sections (id, name)\n * values\n * (1, 'strings');\n * insert into\n * instruments (id, section_id, name)\n * values\n * (1, 1, 'harp'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse On a referenced table\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"strings\",\n * \"instruments\": [\n * {\n * \"name\": \"violin\"\n * }\n * ]\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n limit(\n rows: number,\n {\n foreignTable,\n referencedTable = foreignTable,\n }: { foreignTable?: string; referencedTable?: string } = {}\n ): this {\n const key = typeof referencedTable === 'undefined' ? 'limit' : `${referencedTable}.limit`\n this.url.searchParams.set(key, `${rows}`)\n return this\n }\n\n /**\n * Limit the query result by starting at an offset `from` and ending at the offset `to`.\n * Only records within this range are returned.\n * This respects the query order and if there is no order clause the range could behave unexpectedly.\n * The `from` and `to` values are 0-based and inclusive: `range(1, 3)` will include the second, third\n * and fourth rows of the query.\n *\n * @param from - The starting index from which to limit the result\n * @param to - The last index to which to limit the result\n * @param options - Named parameters\n * @param options.referencedTable - Set this to limit rows of referenced\n * tables instead of the parent table\n * @param options.foreignTable - Deprecated, use `options.referencedTable`\n * instead\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select('name')\n * .range(0, 1)\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Luke\"\n * },\n * {\n * \"name\": \"Leia\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n range(\n from: number,\n to: number,\n {\n foreignTable,\n referencedTable = foreignTable,\n }: { foreignTable?: string; referencedTable?: string } = {}\n ): this {\n const keyOffset =\n typeof referencedTable === 'undefined' ? 'offset' : `${referencedTable}.offset`\n const keyLimit = typeof referencedTable === 'undefined' ? 'limit' : `${referencedTable}.limit`\n this.url.searchParams.set(keyOffset, `${from}`)\n // Range is inclusive, so add 1\n this.url.searchParams.set(keyLimit, `${to - from + 1}`)\n return this\n }\n\n /**\n * Set the AbortSignal for the fetch request.\n *\n * @param signal - The AbortSignal to use for the fetch request\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @remarks\n * You can use this to set a timeout for the request.\n *\n * @exampleDescription Aborting requests in-flight\n * You can use an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to abort requests.\n * Note that `status` and `statusText` don't mean anything for aborted requests as the request wasn't fulfilled.\n *\n * @example Aborting requests in-flight\n * ```ts\n * const ac = new AbortController()\n *\n * const { data, error } = await supabase\n * .from('very_big_table')\n * .select()\n * .abortSignal(ac.signal)\n *\n * // Abort the request after 100 ms\n * setTimeout(() => ac.abort(), 100)\n * ```\n *\n * @exampleResponse Aborting requests in-flight\n * ```json\n * {\n * \"error\": {\n * \"message\": \"AbortError: The user aborted a request.\",\n * \"details\": \"\",\n * \"hint\": \"The request was aborted locally via the provided AbortSignal.\",\n * \"code\": \"\"\n * },\n * \"status\": 0,\n * \"statusText\": \"\"\n * }\n *\n * ```\n *\n * @example Set a timeout\n * ```ts\n * const { data, error } = await supabase\n * .from('very_big_table')\n * .select()\n * .abortSignal(AbortSignal.timeout(1000 /* ms *\\/))\n * ```\n *\n * @exampleResponse Set a timeout\n * ```json\n * {\n * \"error\": {\n * \"message\": \"FetchError: The user aborted a request.\",\n * \"details\": \"\",\n * \"hint\": \"\",\n * \"code\": \"\"\n * },\n * \"status\": 0,\n * \"statusText\": \"\"\n * }\n *\n * ```\n */\n abortSignal(signal: AbortSignal): this {\n this.signal = signal\n return this\n }\n\n /**\n * Return `data` as a single object instead of an array of objects.\n *\n * Query result must be one row (e.g. using `.limit(1)`), otherwise this\n * returns an error.\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select('name')\n * .limit(1)\n * .single()\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": {\n * \"name\": \"Luke\"\n * },\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n single<ResultOne = Result extends (infer ResultOne)[] ? ResultOne : never>(): PostgrestBuilder<\n ClientOptions,\n ResultOne,\n ThrowOnError\n > {\n this.headers.set('Accept', 'application/vnd.pgrst.object+json')\n return this as unknown as PostgrestBuilder<ClientOptions, ResultOne, ThrowOnError>\n }\n\n /**\n * Return `data` as a single object instead of an array of objects.\n *\n * Query result must be zero or one row (e.g. using `.limit(1)`), otherwise\n * this returns an error.\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .eq('name', 'Katniss')\n * .maybeSingle()\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n maybeSingle<\n ResultOne = Result extends (infer ResultOne)[] ? ResultOne : never,\n >(): PostgrestBuilder<ClientOptions, ResultOne | null, ThrowOnError> {\n // No Accept header override — we fetch as a list and enforce cardinality client-side.\n // Fixes https://github.com/supabase/postgrest-js/issues/361 for all request methods.\n this.isMaybeSingle = true\n return this as unknown as PostgrestBuilder<ClientOptions, ResultOne | null, ThrowOnError>\n }\n\n /**\n * Return `data` as a string in CSV format.\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @exampleDescription Return data as CSV\n * By default, the data is returned in JSON format, but can also be returned as Comma Separated Values.\n *\n * @example Return data as CSV\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .csv()\n * ```\n *\n * @exampleSql Return data as CSV\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse Return data as CSV\n * ```json\n * {\n * \"data\": \"id,name\\n1,Luke\\n2,Leia\\n3,Han\",\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n csv(): PostgrestBuilder<ClientOptions, string, ThrowOnError> {\n this.headers.set('Accept', 'text/csv')\n return this as unknown as PostgrestBuilder<ClientOptions, string, ThrowOnError>\n }\n\n /**\n * Return `data` as an object in [GeoJSON](https://geojson.org) format.\n *\n * @category Database\n * @subcategory Using modifiers\n */\n geojson(): PostgrestBuilder<ClientOptions, Record<string, unknown>, ThrowOnError> {\n this.headers.set('Accept', 'application/geo+json')\n return this as unknown as PostgrestBuilder<ClientOptions, Record<string, unknown>, ThrowOnError>\n }\n\n /**\n * Return `data` as the EXPLAIN plan for the query.\n *\n * You need to enable the\n * [db_plan_enabled](https://supabase.com/docs/guides/database/debugging-performance#enabling-explain)\n * setting before using this method.\n *\n * @param options - Named parameters\n *\n * @param options.analyze - If `true`, the query will be executed and the\n * actual run time will be returned\n *\n * @param options.verbose - If `true`, the query identifier will be returned\n * and `data` will include the output columns of the query\n *\n * @param options.settings - If `true`, include information on configuration\n * parameters that affect query planning\n *\n * @param options.buffers - If `true`, include information on buffer usage\n *\n * @param options.wal - If `true`, include information on WAL record generation\n *\n * @param options.format - The format of the output, can be `\"text\"` (default)\n * or `\"json\"`\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @exampleDescription Get the execution plan\n * By default, the data is returned in TEXT format, but can also be returned as JSON by using the `format` parameter.\n *\n * @example Get the execution plan\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .explain()\n * ```\n *\n * @exampleSql Get the execution plan\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse Get the execution plan\n * ```js\n * Aggregate (cost=33.34..33.36 rows=1 width=112)\n * -> Limit (cost=0.00..18.33 rows=1000 width=40)\n * -> Seq Scan on characters (cost=0.00..22.00 rows=1200 width=40)\n * ```\n *\n * @exampleDescription Get the execution plan with analyze and verbose\n * By default, the data is returned in TEXT format, but can also be returned as JSON by using the `format` parameter.\n *\n * @example Get the execution plan with analyze and verbose\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .explain({analyze:true,verbose:true})\n * ```\n *\n * @exampleSql Get the execution plan with analyze and verbose\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse Get the execution plan with analyze and verbose\n * ```js\n * Aggregate (cost=33.34..33.36 rows=1 width=112) (actual time=0.041..0.041 rows=1 loops=1)\n * Output: NULL::bigint, count(ROW(characters.id, characters.name)), COALESCE(json_agg(ROW(characters.id, characters.name)), '[]'::json), NULLIF(current_setting('response.headers'::text, true), ''::text), NULLIF(current_setting('response.status'::text, true), ''::text)\n * -> Limit (cost=0.00..18.33 rows=1000 width=40) (actual time=0.005..0.006 rows=3 loops=1)\n * Output: characters.id, characters.name\n * -> Seq Scan on public.characters (cost=0.00..22.00 rows=1200 width=40) (actual time=0.004..0.005 rows=3 loops=1)\n * Output: characters.id, characters.name\n * Query Identifier: -4730654291623321173\n * Planning Time: 0.407 ms\n * Execution Time: 0.119 ms\n * ```\n */\n explain({\n analyze = false,\n verbose = false,\n settings = false,\n buffers = false,\n wal = false,\n format = 'text',\n }: {\n analyze?: boolean\n verbose?: boolean\n settings?: boolean\n buffers?: boolean\n wal?: boolean\n format?: 'json' | 'text'\n } = {}) {\n const options = [\n analyze ? 'analyze' : null,\n verbose ? 'verbose' : null,\n settings ? 'settings' : null,\n buffers ? 'buffers' : null,\n wal ? 'wal' : null,\n ]\n .filter(Boolean)\n .join('|')\n // An Accept header can carry multiple media types but postgrest-js always sends one\n const forMediatype = this.headers.get('Accept') ?? 'application/json'\n this.headers.set(\n 'Accept',\n `application/vnd.pgrst.plan+${format}; for=\"${forMediatype}\"; options=${options};`\n )\n if (format === 'json') {\n return this as unknown as PostgrestBuilder<\n ClientOptions,\n Record<string, unknown>[],\n ThrowOnError\n >\n } else {\n return this as unknown as PostgrestBuilder<ClientOptions, string, ThrowOnError>\n }\n }\n\n /**\n * Dry-run this request: execute the query but discard the changes.\n *\n * Server-side, PostgREST runs the query inside a transaction and rolls it back\n * instead of committing. The response still contains the data that *would* have\n * been returned — `RETURNING` clauses execute and RLS, triggers, and constraints\n * are all evaluated — but no row is actually inserted, updated, or deleted.\n *\n * This affects only the single request it is chained to. The JS caller has no\n * handle on the transaction: supabase-js does not group multiple queries into\n * one transaction. For multi-statement transactional logic, use a database\n * function (`supabase.rpc(...)`).\n *\n * Sets the `Prefer: tx=rollback` header. See PostgREST's docs on transaction\n * preferences for the underlying mechanism.\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @example Validate an insert without persisting\n * ```ts\n * const { data, error } = await supabase\n * .from('countries')\n * .insert({ name: 'France' })\n * .select()\n * .rollback()\n * // `data` shows what would have been inserted; nothing is saved.\n * ```\n */\n rollback(): this {\n this.headers.append('Prefer', 'tx=rollback')\n return this\n }\n\n /**\n * Override the type of the returned `data`.\n *\n * @typeParam NewResult - The new result type to override with\n * @deprecated Use overrideTypes<yourType, { merge: false }>() method at the end of your call chain instead\n *\n * @category Database\n * @subcategory Using modifiers\n *\n * @remarks\n * - Deprecated: use overrideTypes method instead\n *\n * @example Override type of successful response\n * ```ts\n * const { data } = await supabase\n * .from('countries')\n * .select()\n * .returns<Array<MyType>>()\n * ```\n *\n * @exampleResponse Override type of successful response\n * ```js\n * let x: typeof data // MyType[]\n * ```\n *\n * @example Override type of object response\n * ```ts\n * const { data } = await supabase\n * .from('countries')\n * .select()\n * .maybeSingle()\n * .returns<MyType>()\n * ```\n *\n * @exampleResponse Override type of object response\n * ```js\n * let x: typeof data // MyType | null\n * ```\n */\n returns<NewResult>(): PostgrestTransformBuilder<\n ClientOptions,\n Schema,\n Row,\n CheckMatchingArrayTypes<Result, NewResult>,\n RelationName,\n Relationships,\n Method,\n ThrowOnError\n > {\n return this as unknown as PostgrestTransformBuilder<\n ClientOptions,\n Schema,\n Row,\n CheckMatchingArrayTypes<Result, NewResult>,\n RelationName,\n Relationships,\n Method,\n ThrowOnError\n >\n }\n\n /**\n * Set the maximum number of rows that can be affected by the query.\n * Only available in PostgREST v13+ and only works with PATCH and DELETE methods.\n *\n * @param rows - The maximum number of rows that can be affected\n *\n * @category Database\n * @subcategory Using modifiers\n */\n maxAffected(rows: number): MaxAffectedEnabled<ClientOptions['PostgrestVersion']> extends true\n ? // TODO: update the RPC case to only work on RPC that returns SETOF rows\n Method extends 'PATCH' | 'DELETE' | 'RPC'\n ? this\n : InvalidMethodError<'maxAffected method only available on update or delete'>\n : InvalidMethodError<'maxAffected method only available on postgrest 13+'> {\n this.headers.append('Prefer', 'handling=strict')\n this.headers.append('Prefer', `max-affected=${rows}`)\n return this as unknown as MaxAffectedEnabled<ClientOptions['PostgrestVersion']> extends true\n ? Method extends 'PATCH' | 'DELETE' | 'RPC'\n ? this\n : InvalidMethodError<'maxAffected method only available on update or delete'>\n : InvalidMethodError<'maxAffected method only available on postgrest 13+'>\n }\n}\n","import PostgrestTransformBuilder from './PostgrestTransformBuilder'\nimport { JsonPathToAccessor, JsonPathToType } from './select-query-parser/utils'\nimport { ClientServerOptions, GenericSchema } from './types/common/common'\n\ntype FilterOperator =\n | 'eq'\n | 'neq'\n | 'gt'\n | 'gte'\n | 'lt'\n | 'lte'\n | 'like'\n | 'ilike'\n | 'is'\n | 'isdistinct'\n | 'in'\n | 'cs'\n | 'cd'\n | 'sl'\n | 'sr'\n | 'nxl'\n | 'nxr'\n | 'adj'\n | 'ov'\n | 'fts'\n | 'plfts'\n | 'phfts'\n | 'wfts'\n | 'match'\n | 'imatch'\n\nexport type IsStringOperator<Path extends string> = Path extends `${string}->>${string}`\n ? true\n : false\n\nconst PostgrestReservedCharsRegexp = new RegExp('[,()]')\n\n// Match relationship filters with `table.column` syntax and resolve underlying\n// column value. If not matched, fallback to generic type.\n// TODO: Validate the relationship itself ala select-query-parser. Currently we\n// assume that all tables have valid relationships to each other, despite\n// nonexistent foreign keys.\ntype ResolveFilterValue<\n Schema extends GenericSchema,\n Row extends Record<string, unknown>,\n ColumnName extends string,\n> = ColumnName extends `${infer RelationshipTable}.${infer Remainder}`\n ? Remainder extends `${infer _}.${infer _}`\n ? ResolveFilterValue<Schema, Row, Remainder>\n : ResolveFilterRelationshipValue<Schema, RelationshipTable, Remainder>\n : ColumnName extends keyof Row\n ? Row[ColumnName]\n : // If the column selection is a jsonpath like `data->value` or `data->>value` we attempt to match\n // the expected type with the parsed custom json type\n IsStringOperator<ColumnName> extends true\n ? string\n : JsonPathToType<Row, JsonPathToAccessor<ColumnName>> extends infer JsonPathValue\n ? JsonPathValue extends never\n ? never\n : JsonPathValue\n : never\n\ntype ResolveFilterRelationshipValue<\n Schema extends GenericSchema,\n RelationshipTable extends string,\n RelationshipColumn extends string,\n> = Schema['Tables'] & Schema['Views'] extends infer TablesAndViews\n ? RelationshipTable extends keyof TablesAndViews\n ? 'Row' extends keyof TablesAndViews[RelationshipTable]\n ? RelationshipColumn extends keyof TablesAndViews[RelationshipTable]['Row']\n ? TablesAndViews[RelationshipTable]['Row'][RelationshipColumn]\n : unknown\n : unknown\n : unknown\n : never\n\nexport type InvalidMethodError<S extends string> = { Error: S }\n\ntype NonNullableColumn<T extends Record<string, unknown>, Col extends string> = Col extends keyof T\n ? { [K in keyof T]: K extends Col ? NonNullable<T[K]> : T[K] }\n : T\n\ntype NarrowResultColumn<T, Col extends string> = T extends (infer Item)[]\n ? Item extends Record<string, unknown>\n ? Col extends keyof Item\n ? { [K in keyof Item]: K extends Col ? NonNullable<Item[K]> : Item[K] }[]\n : T\n : T\n : T extends Record<string, unknown>\n ? Col extends keyof T\n ? { [K in keyof T]: K extends Col ? NonNullable<T[K]> : T[K] }\n : T\n : T\n\nexport default class PostgrestFilterBuilder<\n ClientOptions extends ClientServerOptions,\n Schema extends GenericSchema,\n Row extends Record<string, unknown>,\n Result,\n RelationName = unknown,\n Relationships = unknown,\n Method = unknown,\n ThrowOnError extends boolean = false,\n> extends PostgrestTransformBuilder<\n ClientOptions,\n Schema,\n Row,\n Result,\n RelationName,\n Relationships,\n Method,\n ThrowOnError\n> {\n throwOnError(): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Row,\n Result,\n RelationName,\n Relationships,\n Method,\n true\n > {\n return super.throwOnError() as PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Row,\n Result,\n RelationName,\n Relationships,\n Method,\n true\n >\n }\n\n /**\n * Match only rows where `column` is equal to `value`.\n *\n * To check if the value of `column` is NULL, you should use `.is()` instead.\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .eq('name', 'Leia')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 2,\n * \"name\": \"Leia\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n eq<ColumnName extends string>(\n column: ColumnName extends keyof Row\n ? ColumnName\n : ColumnName extends `${string}.${string}` | `${string}->${string}`\n ? ColumnName\n : string extends ColumnName\n ? string\n : keyof Row,\n value: ResolveFilterValue<Schema, Row, ColumnName> extends never\n ? NonNullable<unknown>\n : ResolveFilterValue<Schema, Row, ColumnName> extends infer ResolvedFilterValue\n ? NonNullable<ResolvedFilterValue>\n : never\n ): this {\n this.url.searchParams.append(column as string, `eq.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` is not equal to `value`.\n *\n * This filter does not include rows where `column` is `NULL`. To match null\n * values, use `.is(column, null)` instead.\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .neq('name', 'Leia')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Luke\"\n * },\n * {\n * \"id\": 3,\n * \"name\": \"Han\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n neq<ColumnName extends string>(\n column: ColumnName extends keyof Row\n ? ColumnName\n : ColumnName extends `${string}.${string}` | `${string}->${string}`\n ? ColumnName\n : string extends ColumnName\n ? string\n : keyof Row,\n value: ResolveFilterValue<Schema, Row, ColumnName> extends never\n ? unknown\n : ResolveFilterValue<Schema, Row, ColumnName> extends infer Resolved\n ? Resolved\n : never\n ): this {\n this.url.searchParams.append(column as string, `neq.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` is greater than `value`.\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @exampleDescription With `select()`\n * When using [reserved words](https://www.postgresql.org/docs/current/sql-keywords-appendix.html) for column names you need\n * to add double quotes e.g. `.gt('\"order\"', 2)`\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .gt('id', 2)\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 3,\n * \"name\": \"Han\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n gt<ColumnName extends string & keyof Row>(column: ColumnName, value: Row[ColumnName]): this\n gt(column: string, value: unknown): this\n gt(column: string, value: unknown): this {\n this.url.searchParams.append(column, `gt.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` is greater than or equal to `value`.\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .gte('id', 2)\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 2,\n * \"name\": \"Leia\"\n * },\n * {\n * \"id\": 3,\n * \"name\": \"Han\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n gte<ColumnName extends string & keyof Row>(column: ColumnName, value: Row[ColumnName]): this\n gte(column: string, value: unknown): this\n gte(column: string, value: unknown): this {\n this.url.searchParams.append(column, `gte.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` is less than `value`.\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .lt('id', 2)\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Luke\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n lt<ColumnName extends string & keyof Row>(column: ColumnName, value: Row[ColumnName]): this\n lt(column: string, value: unknown): this\n lt(column: string, value: unknown): this {\n this.url.searchParams.append(column, `lt.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` is less than or equal to `value`.\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .lte('id', 2)\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Luke\"\n * },\n * {\n * \"id\": 2,\n * \"name\": \"Leia\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n lte<ColumnName extends string & keyof Row>(column: ColumnName, value: Row[ColumnName]): this\n lte(column: string, value: unknown): this\n lte(column: string, value: unknown): this {\n this.url.searchParams.append(column, `lte.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches `pattern` case-sensitively.\n *\n * @param column - The column to filter on\n * @param pattern - The pattern to match with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .like('name', '%Lu%')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Luke\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n like<ColumnName extends string & keyof Row>(column: ColumnName, pattern: string): this\n like(column: string, pattern: string): this\n like(column: string, pattern: string): this {\n this.url.searchParams.append(column, `like.${pattern}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches all of `patterns` case-sensitively.\n *\n * @param column - The column to filter on\n * @param patterns - The patterns to match with\n *\n * @category Database\n * @subcategory Using filters\n */\n likeAllOf<ColumnName extends string & keyof Row>(\n column: ColumnName,\n patterns: readonly string[]\n ): this\n likeAllOf(column: string, patterns: readonly string[]): this\n likeAllOf(column: string, patterns: readonly string[]): this {\n this.url.searchParams.append(column, `like(all).{${patterns.join(',')}}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches any of `patterns` case-sensitively.\n *\n * @param column - The column to filter on\n * @param patterns - The patterns to match with\n *\n * @category Database\n * @subcategory Using filters\n */\n likeAnyOf<ColumnName extends string & keyof Row>(\n column: ColumnName,\n patterns: readonly string[]\n ): this\n likeAnyOf(column: string, patterns: readonly string[]): this\n likeAnyOf(column: string, patterns: readonly string[]): this {\n this.url.searchParams.append(column, `like(any).{${patterns.join(',')}}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches `pattern` case-insensitively.\n *\n * @param column - The column to filter on\n * @param pattern - The pattern to match with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .ilike('name', '%lu%')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Luke\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n ilike<ColumnName extends string & keyof Row>(column: ColumnName, pattern: string): this\n ilike(column: string, pattern: string): this\n ilike(column: string, pattern: string): this {\n this.url.searchParams.append(column, `ilike.${pattern}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches all of `patterns` case-insensitively.\n *\n * @param column - The column to filter on\n * @param patterns - The patterns to match with\n *\n * @category Database\n * @subcategory Using filters\n */\n ilikeAllOf<ColumnName extends string & keyof Row>(\n column: ColumnName,\n patterns: readonly string[]\n ): this\n ilikeAllOf(column: string, patterns: readonly string[]): this\n ilikeAllOf(column: string, patterns: readonly string[]): this {\n this.url.searchParams.append(column, `ilike(all).{${patterns.join(',')}}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches any of `patterns` case-insensitively.\n *\n * @param column - The column to filter on\n * @param patterns - The patterns to match with\n *\n * @category Database\n * @subcategory Using filters\n */\n ilikeAnyOf<ColumnName extends string & keyof Row>(\n column: ColumnName,\n patterns: readonly string[]\n ): this\n ilikeAnyOf(column: string, patterns: readonly string[]): this\n ilikeAnyOf(column: string, patterns: readonly string[]): this {\n this.url.searchParams.append(column, `ilike(any).{${patterns.join(',')}}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches the PostgreSQL regex `pattern`\n * case-sensitively (using the `~` operator).\n *\n * @param column - The column to filter on\n * @param pattern - The PostgreSQL regular expression pattern to match with\n */\n regexMatch<ColumnName extends string & keyof Row>(column: ColumnName, pattern: string): this\n regexMatch(column: string, pattern: string): this\n regexMatch(column: string, pattern: string): this {\n this.url.searchParams.append(column, `match.${pattern}`)\n return this\n }\n\n /**\n * Match only rows where `column` matches the PostgreSQL regex `pattern`\n * case-insensitively (using the `~*` operator).\n *\n * @param column - The column to filter on\n * @param pattern - The PostgreSQL regular expression pattern to match with\n */\n regexIMatch<ColumnName extends string & keyof Row>(column: ColumnName, pattern: string): this\n regexIMatch(column: string, pattern: string): this\n regexIMatch(column: string, pattern: string): this {\n this.url.searchParams.append(column, `imatch.${pattern}`)\n return this\n }\n\n /**\n * Match only rows where `column` IS `value`.\n *\n * For non-boolean columns, this is only relevant for checking if the value of\n * `column` is NULL by setting `value` to `null`.\n *\n * For boolean columns, you can also set `value` to `true` or `false` and it\n * will behave the same way as `.eq()`.\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @exampleDescription Checking for nullness, true or false\n * Using the `eq()` filter doesn't work when filtering for `null`.\n *\n * Instead, you need to use `is()`.\n *\n * @example Checking for nullness, true or false\n * ```ts\n * const { data, error } = await supabase\n * .from('countries')\n * .select()\n * .is('name', null)\n * ```\n *\n * @exampleSql Checking for nullness, true or false\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n *\n * insert into\n * countries (id, name)\n * values\n * (1, 'null'),\n * (2, null);\n * ```\n *\n * @exampleResponse Checking for nullness, true or false\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 2,\n * \"name\": \"null\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n is<ColumnName extends string & keyof Row>(\n column: ColumnName,\n value: Row[ColumnName] & (boolean | null)\n ): this\n is(column: string, value: boolean | null): this\n is(column: string, value: boolean | null): this {\n this.url.searchParams.append(column, `is.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` IS DISTINCT FROM `value`.\n *\n * Unlike `.neq()`, this treats `NULL` as a comparable value. Two `NULL` values\n * are considered equal (not distinct), and comparing `NULL` with any non-NULL\n * value returns true (distinct).\n *\n * @param column - The column to filter on\n * @param value - The value to filter with\n */\n isDistinct<ColumnName extends string>(\n column: ColumnName,\n value: ResolveFilterValue<Schema, Row, ColumnName> extends never\n ? unknown\n : ResolveFilterValue<Schema, Row, ColumnName> extends infer ResolvedFilterValue\n ? ResolvedFilterValue\n : never\n ): this {\n this.url.searchParams.append(column, `isdistinct.${value}`)\n return this\n }\n\n /**\n * Match only rows where `column` is included in the `values` array.\n *\n * @param column - The column to filter on\n * @param values - The values array to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .in('name', ['Leia', 'Han'])\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 2,\n * \"name\": \"Leia\"\n * },\n * {\n * \"id\": 3,\n * \"name\": \"Han\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n in<ColumnName extends string>(\n column: ColumnName,\n values: ReadonlyArray<\n ResolveFilterValue<Schema, Row, ColumnName> extends never\n ? unknown\n : // We want to infer the type before wrapping it into a `NonNullable` to avoid too deep\n // type resolution error\n ResolveFilterValue<Schema, Row, ColumnName> extends infer ResolvedFilterValue\n ? ResolvedFilterValue\n : // We should never enter this case as all the branches are covered above\n never\n >\n ): this {\n const cleanedValues = Array.from(new Set(values))\n .map((s) => {\n // handle postgrest reserved characters\n // https://postgrest.org/en/v7.0.0/api.html#reserved-characters\n if (typeof s === 'string' && PostgrestReservedCharsRegexp.test(s)) return `\"${s}\"`\n else return `${s}`\n })\n .join(',')\n this.url.searchParams.append(column, `in.(${cleanedValues})`)\n return this\n }\n\n /**\n * Match only rows where `column` is NOT included in the `values` array.\n *\n * @param column - The column to filter on\n * @param values - The values array to filter with\n */\n notIn<ColumnName extends string>(\n column: ColumnName,\n values: ReadonlyArray<\n ResolveFilterValue<Schema, Row, ColumnName> extends never\n ? unknown\n : ResolveFilterValue<Schema, Row, ColumnName> extends infer ResolvedFilterValue\n ? ResolvedFilterValue\n : never\n >\n ): this {\n const cleanedValues = Array.from(new Set(values))\n .map((s) => {\n // handle postgrest reserved characters\n // https://postgrest.org/en/v7.0.0/api.html#reserved-characters\n if (typeof s === 'string' && PostgrestReservedCharsRegexp.test(s)) return `\"${s}\"`\n else return `${s}`\n })\n .join(',')\n this.url.searchParams.append(column, `not.in.(${cleanedValues})`)\n return this\n }\n\n /**\n * Only relevant for jsonb, array, and range columns. Match only rows where\n * `column` contains every element appearing in `value`.\n *\n * @param column - The jsonb, array, or range column to filter on\n * @param value - The jsonb, array, or range value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example On array columns\n * ```ts\n * const { data, error } = await supabase\n * .from('issues')\n * .select()\n * .contains('tags', ['is:open', 'priority:low'])\n * ```\n *\n * @exampleSql On array columns\n * ```sql\n * create table\n * issues (\n * id int8 primary key,\n * title text,\n * tags text[]\n * );\n *\n * insert into\n * issues (id, title, tags)\n * values\n * (1, 'Cache invalidation is not working', array['is:open', 'severity:high', 'priority:low']),\n * (2, 'Use better names', array['is:open', 'severity:low', 'priority:medium']);\n * ```\n *\n * @exampleResponse On array columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"title\": \"Cache invalidation is not working\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription On range columns\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example On range columns\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .contains('during', '[2000-01-01 13:00, 2000-01-01 13:30)')\n * ```\n *\n * @exampleSql On range columns\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse On range columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"room_name\": \"Emerald\",\n * \"during\": \"[\\\"2000-01-01 13:00:00\\\",\\\"2000-01-01 15:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example On `jsonb` columns\n * ```ts\n * const { data, error } = await supabase\n * .from('users')\n * .select('name')\n * .contains('address', { postcode: 90210 })\n * ```\n *\n * @exampleSql On `jsonb` columns\n * ```sql\n * create table\n * users (\n * id int8 primary key,\n * name text,\n * address jsonb\n * );\n *\n * insert into\n * users (id, name, address)\n * values\n * (1, 'Michael', '{ \"postcode\": 90210, \"street\": \"Melrose Place\" }'),\n * (2, 'Jane', '{}');\n * ```\n *\n * @exampleResponse On `jsonb` columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Michael\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n contains<ColumnName extends string & keyof Row>(\n column: ColumnName,\n value: string | ReadonlyArray<Row[ColumnName]> | Record<string, unknown>\n ): this\n contains(column: string, value: string | readonly unknown[] | Record<string, unknown>): this\n contains(column: string, value: string | readonly unknown[] | Record<string, unknown>): this {\n if (typeof value === 'string') {\n // range types can be inclusive '[', ']' or exclusive '(', ')' so just\n // keep it simple and accept a string\n this.url.searchParams.append(column, `cs.${value}`)\n } else if (Array.isArray(value)) {\n // array\n this.url.searchParams.append(column, `cs.{${value.join(',')}}`)\n } else {\n // json\n this.url.searchParams.append(column, `cs.${JSON.stringify(value)}`)\n }\n return this\n }\n\n /**\n * Only relevant for jsonb, array, and range columns. Match only rows where\n * every element appearing in `column` is contained by `value`.\n *\n * @param column - The jsonb, array, or range column to filter on\n * @param value - The jsonb, array, or range value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example On array columns\n * ```ts\n * const { data, error } = await supabase\n * .from('classes')\n * .select('name')\n * .containedBy('days', ['monday', 'tuesday', 'wednesday', 'friday'])\n * ```\n *\n * @exampleSql On array columns\n * ```sql\n * create table\n * classes (\n * id int8 primary key,\n * name text,\n * days text[]\n * );\n *\n * insert into\n * classes (id, name, days)\n * values\n * (1, 'Chemistry', array['monday', 'friday']),\n * (2, 'History', array['monday', 'wednesday', 'thursday']);\n * ```\n *\n * @exampleResponse On array columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Chemistry\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription On range columns\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example On range columns\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .containedBy('during', '[2000-01-01 00:00, 2000-01-01 23:59)')\n * ```\n *\n * @exampleSql On range columns\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse On range columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"room_name\": \"Emerald\",\n * \"during\": \"[\\\"2000-01-01 13:00:00\\\",\\\"2000-01-01 15:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example On `jsonb` columns\n * ```ts\n * const { data, error } = await supabase\n * .from('users')\n * .select('name')\n * .containedBy('address', {})\n * ```\n *\n * @exampleSql On `jsonb` columns\n * ```sql\n * create table\n * users (\n * id int8 primary key,\n * name text,\n * address jsonb\n * );\n *\n * insert into\n * users (id, name, address)\n * values\n * (1, 'Michael', '{ \"postcode\": 90210, \"street\": \"Melrose Place\" }'),\n * (2, 'Jane', '{}');\n * ```\n *\n * @exampleResponse On `jsonb` columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Jane\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n */\n containedBy<ColumnName extends string & keyof Row>(\n column: ColumnName,\n value: string | ReadonlyArray<Row[ColumnName]> | Record<string, unknown>\n ): this\n containedBy(column: string, value: string | readonly unknown[] | Record<string, unknown>): this\n containedBy(column: string, value: string | readonly unknown[] | Record<string, unknown>): this {\n if (typeof value === 'string') {\n // range\n this.url.searchParams.append(column, `cd.${value}`)\n } else if (Array.isArray(value)) {\n // array\n this.url.searchParams.append(column, `cd.{${value.join(',')}}`)\n } else {\n // json\n this.url.searchParams.append(column, `cd.${JSON.stringify(value)}`)\n }\n return this\n }\n\n /**\n * Only relevant for range columns. Match only rows where every element in\n * `column` is greater than any element in `range`.\n *\n * @param column - The range column to filter on\n * @param range - The range to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @exampleDescription With `select()`\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .rangeGt('during', '[2000-01-02 08:00, 2000-01-02 09:00)')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 2,\n * \"room_name\": \"Topaz\",\n * \"during\": \"[\\\"2000-01-02 09:00:00\\\",\\\"2000-01-02 10:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n */\n rangeGt<ColumnName extends string & keyof Row>(column: ColumnName, range: string): this\n rangeGt(column: string, range: string): this\n rangeGt(column: string, range: string): this {\n this.url.searchParams.append(column, `sr.${range}`)\n return this\n }\n\n /**\n * Only relevant for range columns. Match only rows where every element in\n * `column` is either contained in `range` or greater than any element in\n * `range`.\n *\n * @param column - The range column to filter on\n * @param range - The range to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @exampleDescription With `select()`\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .rangeGte('during', '[2000-01-02 08:30, 2000-01-02 09:30)')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 2,\n * \"room_name\": \"Topaz\",\n * \"during\": \"[\\\"2000-01-02 09:00:00\\\",\\\"2000-01-02 10:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n */\n rangeGte<ColumnName extends string & keyof Row>(column: ColumnName, range: string): this\n rangeGte(column: string, range: string): this\n rangeGte(column: string, range: string): this {\n this.url.searchParams.append(column, `nxl.${range}`)\n return this\n }\n\n /**\n * Only relevant for range columns. Match only rows where every element in\n * `column` is less than any element in `range`.\n *\n * @param column - The range column to filter on\n * @param range - The range to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @exampleDescription With `select()`\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .rangeLt('during', '[2000-01-01 15:00, 2000-01-01 16:00)')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"room_name\": \"Emerald\",\n * \"during\": \"[\\\"2000-01-01 13:00:00\\\",\\\"2000-01-01 15:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n rangeLt<ColumnName extends string & keyof Row>(column: ColumnName, range: string): this\n rangeLt(column: string, range: string): this\n rangeLt(column: string, range: string): this {\n this.url.searchParams.append(column, `sl.${range}`)\n return this\n }\n\n /**\n * Only relevant for range columns. Match only rows where every element in\n * `column` is either contained in `range` or less than any element in\n * `range`.\n *\n * @param column - The range column to filter on\n * @param range - The range to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @exampleDescription With `select()`\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .rangeLte('during', '[2000-01-01 14:00, 2000-01-01 16:00)')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"room_name\": \"Emerald\",\n * \"during\": \"[\\\"2000-01-01 13:00:00\\\",\\\"2000-01-01 15:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n */\n rangeLte<ColumnName extends string & keyof Row>(column: ColumnName, range: string): this\n rangeLte(column: string, range: string): this\n rangeLte(column: string, range: string): this {\n this.url.searchParams.append(column, `nxr.${range}`)\n return this\n }\n\n /**\n * Only relevant for range columns. Match only rows where `column` is\n * mutually exclusive to `range` and there can be no element between the two\n * ranges.\n *\n * @param column - The range column to filter on\n * @param range - The range to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @exampleDescription With `select()`\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .rangeAdjacent('during', '[2000-01-01 12:00, 2000-01-01 13:00)')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"room_name\": \"Emerald\",\n * \"during\": \"[\\\"2000-01-01 13:00:00\\\",\\\"2000-01-01 15:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n rangeAdjacent<ColumnName extends string & keyof Row>(column: ColumnName, range: string): this\n rangeAdjacent(column: string, range: string): this\n rangeAdjacent(column: string, range: string): this {\n this.url.searchParams.append(column, `adj.${range}`)\n return this\n }\n\n /**\n * Only relevant for array and range columns. Match only rows where\n * `column` and `value` have an element in common.\n *\n * @param column - The array or range column to filter on\n * @param value - The array or range value to filter with\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example On array columns\n * ```ts\n * const { data, error } = await supabase\n * .from('issues')\n * .select('title')\n * .overlaps('tags', ['is:closed', 'severity:high'])\n * ```\n *\n * @exampleSql On array columns\n * ```sql\n * create table\n * issues (\n * id int8 primary key,\n * title text,\n * tags text[]\n * );\n *\n * insert into\n * issues (id, title, tags)\n * values\n * (1, 'Cache invalidation is not working', array['is:open', 'severity:high', 'priority:low']),\n * (2, 'Use better names', array['is:open', 'severity:low', 'priority:medium']);\n * ```\n *\n * @exampleResponse On array columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"title\": \"Cache invalidation is not working\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription On range columns\n * Postgres supports a number of [range\n * types](https://www.postgresql.org/docs/current/rangetypes.html). You\n * can filter on range columns using the string representation of range\n * values.\n *\n * @example On range columns\n * ```ts\n * const { data, error } = await supabase\n * .from('reservations')\n * .select()\n * .overlaps('during', '[2000-01-01 12:45, 2000-01-01 13:15)')\n * ```\n *\n * @exampleSql On range columns\n * ```sql\n * create table\n * reservations (\n * id int8 primary key,\n * room_name text,\n * during tsrange\n * );\n *\n * insert into\n * reservations (id, room_name, during)\n * values\n * (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'),\n * (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)');\n * ```\n *\n * @exampleResponse On range columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"room_name\": \"Emerald\",\n * \"during\": \"[\\\"2000-01-01 13:00:00\\\",\\\"2000-01-01 15:00:00\\\")\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n overlaps<ColumnName extends string & keyof Row>(\n column: ColumnName,\n value: string | ReadonlyArray<Row[ColumnName]>\n ): this\n overlaps(column: string, value: string | readonly unknown[]): this\n overlaps(column: string, value: string | readonly unknown[]): this {\n if (typeof value === 'string') {\n // range\n this.url.searchParams.append(column, `ov.${value}`)\n } else {\n // array\n this.url.searchParams.append(column, `ov.{${value.join(',')}}`)\n }\n return this\n }\n\n /**\n * Only relevant for text and tsvector columns. Match only rows where\n * `column` matches the query string in `query`.\n *\n * @param column - The text or tsvector column to filter on\n * @param query - The query text to match with\n * @param options - Named parameters\n * @param options.config - The text search configuration to use\n * @param options.type - Change how the `query` text is interpreted\n *\n * @category Database\n * @subcategory Using filters\n *\n * @remarks\n * - For more information, see [Postgres full text search](/docs/guides/database/full-text-search).\n *\n * @example Text search\n * ```ts\n * const result = await supabase\n * .from(\"texts\")\n * .select(\"content\")\n * .textSearch(\"content\", `'eggs' & 'ham'`, {\n * config: \"english\",\n * });\n * ```\n *\n * @exampleSql Text search\n * ```sql\n * create table texts (\n * id bigint\n * primary key\n * generated always as identity,\n * content text\n * );\n *\n * insert into texts (content) values\n * ('Four score and seven years ago'),\n * ('The road goes ever on and on'),\n * ('Green eggs and ham')\n * ;\n * ```\n *\n * @exampleResponse Text search\n * ```json\n * {\n * \"data\": [\n * {\n * \"content\": \"Green eggs and ham\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Basic normalization\n * Uses PostgreSQL's `plainto_tsquery` function.\n *\n * @example Basic normalization\n * ```ts\n * const { data, error } = await supabase\n * .from('quotes')\n * .select('catchphrase')\n * .textSearch('catchphrase', `'fat' & 'cat'`, {\n * type: 'plain',\n * config: 'english'\n * })\n * ```\n *\n * @exampleDescription Full normalization\n * Uses PostgreSQL's `phraseto_tsquery` function.\n *\n * @example Full normalization\n * ```ts\n * const { data, error } = await supabase\n * .from('quotes')\n * .select('catchphrase')\n * .textSearch('catchphrase', `'fat' & 'cat'`, {\n * type: 'phrase',\n * config: 'english'\n * })\n * ```\n *\n * @exampleDescription Websearch\n * Uses PostgreSQL's `websearch_to_tsquery` function.\n * This function will never raise syntax errors, which makes it possible to use raw user-supplied input for search, and can be used\n * with advanced operators.\n *\n * - `unquoted text`: text not inside quote marks will be converted to terms separated by & operators, as if processed by plainto_tsquery.\n * - `\"quoted text\"`: text inside quote marks will be converted to terms separated by `<->` operators, as if processed by phraseto_tsquery.\n * - `OR`: the word “or” will be converted to the | operator.\n * - `-`: a dash will be converted to the ! operator.\n *\n * @example Websearch\n * ```ts\n * const { data, error } = await supabase\n * .from('quotes')\n * .select('catchphrase')\n * .textSearch('catchphrase', `'fat or cat'`, {\n * type: 'websearch',\n * config: 'english'\n * })\n * ```\n */\n textSearch<ColumnName extends string & keyof Row>(\n column: ColumnName,\n query: string,\n options?: { config?: string; type?: 'plain' | 'phrase' | 'websearch' }\n ): this\n textSearch(\n column: string,\n query: string,\n options?: { config?: string; type?: 'plain' | 'phrase' | 'websearch' }\n ): this\n textSearch(\n column: string,\n query: string,\n { config, type }: { config?: string; type?: 'plain' | 'phrase' | 'websearch' } = {}\n ): this {\n let typePart = ''\n if (type === 'plain') {\n typePart = 'pl'\n } else if (type === 'phrase') {\n typePart = 'ph'\n } else if (type === 'websearch') {\n typePart = 'w'\n }\n const configPart = config === undefined ? '' : `(${config})`\n this.url.searchParams.append(column, `${typePart}fts${configPart}.${query}`)\n return this\n }\n\n /**\n * Match only rows where each column in `query` keys is equal to its\n * associated value. Shorthand for multiple `.eq()`s.\n *\n * @param query - The object to filter with, with column names as keys mapped\n * to their filter values\n *\n * @category Database\n * @subcategory Using filters\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select('name')\n * .match({ id: 2, name: 'Leia' })\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Leia\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n match<ColumnName extends string & keyof Row>(query: Record<ColumnName, Row[ColumnName]>): this\n match(query: Record<string, unknown>): this\n match(query: Record<string, unknown>): this {\n Object.entries(query)\n // columns with `undefined` value needs to be filtered out, otherwise it'll\n // show up as `?column=eq.undefined`\n .filter(([_, value]) => value !== undefined)\n .forEach(([column, value]) => {\n this.url.searchParams.append(column, `eq.${value}`)\n })\n return this\n }\n\n /**\n * Match only rows which doesn't satisfy the filter.\n *\n * Unlike most filters, `opearator` and `value` are used as-is and need to\n * follow [PostgREST\n * syntax](https://postgrest.org/en/stable/api.html#operators). You also need\n * to make sure they are properly sanitized.\n *\n * @param column - The column to filter on\n * @param operator - The operator to be negated to filter with, following\n * PostgREST syntax\n * @param value - The value to filter with, following PostgREST syntax\n *\n * @category Database\n * @subcategory Using filters\n */\n not<ColumnName extends string & keyof Row>(\n column: ColumnName,\n operator: 'is',\n value: null\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n NonNullableColumn<Row, ColumnName>,\n NarrowResultColumn<Result, ColumnName>,\n RelationName,\n Relationships,\n Method,\n ThrowOnError\n > &\n this\n not<ColumnName extends string & keyof Row>(\n column: ColumnName,\n operator: FilterOperator,\n value: Row[ColumnName]\n ): this\n not(column: string, operator: string, value: unknown): this\n /**\n * Match only rows which doesn't satisfy the filter.\n *\n * Unlike most filters, `opearator` and `value` are used as-is and need to\n * follow [PostgREST\n * syntax](https://postgrest.org/en/stable/api.html#operators). You also need\n * to make sure they are properly sanitized.\n *\n * @param column - The column to filter on\n * @param operator - The operator to be negated to filter with, following\n * PostgREST syntax\n * @param value - The value to filter with, following PostgREST syntax\n *\n * @category Database\n * @subcategory Using filters\n *\n * @remarks\n * not() expects you to use the raw PostgREST syntax for the filter values.\n *\n * ```ts\n * .not('id', 'in', '(5,6,7)') // Use `()` for `in` filter\n * .not('arraycol', 'cs', '{\"a\",\"b\"}') // Use `cs` for `contains()`, `{}` for array values\n * ```\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('countries')\n * .select()\n * .not('name', 'is', null)\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n *\n * insert into\n * countries (id, name)\n * values\n * (1, 'null'),\n * (2, null);\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"null\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n */\n not(\n column: string,\n operator: string,\n value: unknown\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n any,\n any,\n RelationName,\n Relationships,\n Method,\n ThrowOnError\n > &\n this {\n this.url.searchParams.append(column, `not.${operator}.${value}`)\n return this as any\n }\n\n /**\n * Match only rows which satisfy at least one of the filters.\n *\n * Unlike most filters, `filters` is used as-is and needs to follow [PostgREST\n * syntax](https://postgrest.org/en/stable/api.html#operators). You also need\n * to make sure it's properly sanitized.\n *\n * It's currently not possible to do an `.or()` filter across multiple tables.\n *\n * @param filters - The filters to use, following PostgREST syntax\n * @param options - Named parameters\n * @param options.referencedTable - Set this to filter on referenced tables\n * instead of the parent table\n * @param options.foreignTable - Deprecated, use `referencedTable` instead\n *\n * @category Database\n * @subcategory Using filters\n *\n * @remarks\n * or() expects you to use the raw PostgREST syntax for the filter names and values.\n *\n * ```ts\n * .or('id.in.(5,6,7), arraycol.cs.{\"a\",\"b\"}') // Use `()` for `in` filter, `{}` for array values and `cs` for `contains()`.\n * .or('id.in.(5,6,7), arraycol.cd.{\"a\",\"b\"}') // Use `cd` for `containedBy()`\n * ```\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select('name')\n * .or('id.eq.2,name.eq.Han')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Leia\"\n * },\n * {\n * \"name\": \"Han\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example Use `or` with `and`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select('name')\n * .or('id.gt.3,and(id.eq.1,name.eq.Luke)')\n * ```\n *\n * @exampleSql Use `or` with `and`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse Use `or` with `and`\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Luke\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example Use `or` on referenced tables\n * ```ts\n * const { data, error } = await supabase\n * .from('orchestral_sections')\n * .select(`\n * name,\n * instruments!inner (\n * name\n * )\n * `)\n * .or('section_id.eq.1,name.eq.guzheng', { referencedTable: 'instruments' })\n * ```\n *\n * @exampleSql Use `or` on referenced tables\n * ```sql\n * create table\n * orchestral_sections (id int8 primary key, name text);\n * create table\n * instruments (\n * id int8 primary key,\n * section_id int8 not null references orchestral_sections,\n * name text\n * );\n *\n * insert into\n * orchestral_sections (id, name)\n * values\n * (1, 'strings'),\n * (2, 'woodwinds');\n * insert into\n * instruments (id, section_id, name)\n * values\n * (1, 2, 'flute'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse Use `or` on referenced tables\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"strings\",\n * \"instruments\": [\n * {\n * \"name\": \"violin\"\n * }\n * ]\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n or(\n filters: string,\n {\n foreignTable,\n referencedTable = foreignTable,\n }: { foreignTable?: string; referencedTable?: string } = {}\n ): this {\n const key = referencedTable ? `${referencedTable}.or` : 'or'\n this.url.searchParams.append(key, `(${filters})`)\n return this\n }\n\n /**\n * Match only rows which satisfy the filter. This is an escape hatch - you\n * should use the specific filter methods wherever possible.\n *\n * Unlike most filters, `opearator` and `value` are used as-is and need to\n * follow [PostgREST\n * syntax](https://postgrest.org/en/stable/api.html#operators). You also need\n * to make sure they are properly sanitized.\n *\n * @param column - The column to filter on\n * @param operator - The operator to filter with, following PostgREST syntax\n * @param value - The value to filter with, following PostgREST syntax\n *\n * @category Database\n * @subcategory Using filters\n *\n * @remarks\n * filter() expects you to use the raw PostgREST syntax for the filter values.\n *\n * ```ts\n * .filter('id', 'in', '(5,6,7)') // Use `()` for `in` filter\n * .filter('arraycol', 'cs', '{\"a\",\"b\"}') // Use `cs` for `contains()`, `{}` for array values\n * ```\n *\n * @example With `select()`\n * ```ts\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * .filter('name', 'in', '(\"Han\",\"Yoda\")')\n * ```\n *\n * @exampleSql With `select()`\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse With `select()`\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 3,\n * \"name\": \"Han\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example On a referenced table\n * ```ts\n * const { data, error } = await supabase\n * .from('orchestral_sections')\n * .select(`\n * name,\n * instruments!inner (\n * name\n * )\n * `)\n * .filter('instruments.name', 'eq', 'flute')\n * ```\n *\n * @exampleSql On a referenced table\n * ```sql\n * create table\n * orchestral_sections (id int8 primary key, name text);\n * create table\n * instruments (\n * id int8 primary key,\n * section_id int8 not null references orchestral_sections,\n * name text\n * );\n *\n * insert into\n * orchestral_sections (id, name)\n * values\n * (1, 'strings'),\n * (2, 'woodwinds');\n * insert into\n * instruments (id, section_id, name)\n * values\n * (1, 2, 'flute'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse On a referenced table\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"woodwinds\",\n * \"instruments\": [\n * {\n * \"name\": \"flute\"\n * }\n * ]\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n filter<ColumnName extends string & keyof Row>(\n column: ColumnName,\n operator: `${'' | 'not.'}${FilterOperator}`,\n value: unknown\n ): this\n filter(column: string, operator: string, value: unknown): this\n filter(column: string, operator: string, value: unknown): this {\n this.url.searchParams.append(column, `${operator}.${value}`)\n return this\n }\n}\n","import PostgrestFilterBuilder from './PostgrestFilterBuilder'\nimport { GetResult } from './select-query-parser/result'\nimport {\n ClientServerOptions,\n Fetch,\n GenericSchema,\n GenericTable,\n GenericView,\n} from './types/common/common'\nimport { RejectExcessProperties } from './types/types'\n\nexport default class PostgrestQueryBuilder<\n ClientOptions extends ClientServerOptions,\n Schema extends GenericSchema,\n Relation extends GenericTable | GenericView,\n RelationName = unknown,\n Relationships = Relation extends { Relationships: infer R } ? R : unknown,\n> {\n url: URL\n headers: Headers\n schema?: string\n signal?: AbortSignal\n fetch?: Fetch\n urlLengthLimit: number\n\n /**\n * Enable or disable automatic retries for transient errors.\n * When enabled, idempotent requests (GET/HEAD/OPTIONS) that fail with network\n * errors or HTTP 503/520 responses are automatically retried with exponential\n * backoff (1s, 2s, 4s, up to 3 attempts). Defaults to `true` when not specified.\n */\n retry?: boolean\n\n /**\n * Creates a query builder scoped to a Postgres table or view.\n *\n * @category Database\n *\n * @param url - The URL for the query\n * @param options - Named parameters\n * @param options.headers - Custom headers\n * @param options.schema - Postgres schema to use\n * @param options.fetch - Custom fetch implementation\n * @param options.urlLengthLimit - Maximum URL length before warning\n * @param options.retry - Enable automatic retries for transient errors (default: true)\n *\n * @example Using supabase-js (recommended)\n * ```ts\n * import { createClient } from '@supabase/supabase-js'\n *\n * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')\n * const { data, error } = await supabase.from('users').select('*')\n * ```\n *\n * @example Standalone import for bundle-sensitive environments\n * ```ts\n * import { PostgrestQueryBuilder } from '@supabase/postgrest-js'\n *\n * const query = new PostgrestQueryBuilder(\n * new URL('https://xyzcompany.supabase.co/rest/v1/users'),\n * { headers: { apikey: 'your-publishable-key' }, retry: true }\n * )\n * ```\n */\n constructor(\n url: URL,\n {\n headers = {},\n schema,\n fetch,\n urlLengthLimit = 8000,\n retry,\n }: {\n headers?: HeadersInit\n schema?: string\n fetch?: Fetch\n urlLengthLimit?: number\n retry?: boolean\n }\n ) {\n this.url = url\n this.headers = new Headers(headers)\n this.schema = schema\n this.fetch = fetch\n this.urlLengthLimit = urlLengthLimit\n this.retry = retry\n }\n\n /**\n * Clone URL and headers to prevent shared state between operations.\n */\n private cloneRequestState(): { url: URL; headers: Headers } {\n return {\n url: new URL(this.url.toString()),\n headers: new Headers(this.headers),\n }\n }\n\n /**\n * Perform a SELECT query on the table or view.\n *\n * @param columns - The columns to retrieve, separated by commas. Columns can be renamed when returned with `customName:columnName`\n *\n * @param options - Named parameters\n *\n * @param options.head - When set to `true`, `data` will not be returned.\n * Useful if you only need the count.\n *\n * @param options.count - Count algorithm to use to count rows in the table or view.\n *\n * `\"exact\"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the\n * hood.\n *\n * `\"planned\"`: Approximated but fast count algorithm. Uses the Postgres\n * statistics under the hood.\n *\n * `\"estimated\"`: Uses exact count for low numbers and planned count for high\n * numbers.\n *\n * @remarks\n * When using `count` with `.range()` or `.limit()`, the returned `count` is the total number of rows\n * that match your filters, not the number of rows in the current page. Use this to build pagination UI.\n *\n * - By default, Supabase projects return a maximum of 1,000 rows. This setting can be changed in your project's [API settings](/dashboard/project/_/settings/api). It's recommended that you keep it low to limit the payload size of accidental or malicious requests. You can use `range()` queries to paginate through your data.\n * - `select()` can be combined with [Filters](/docs/reference/javascript/using-filters)\n * - `select()` can be combined with [Modifiers](/docs/reference/javascript/using-modifiers)\n * - `apikey` is a reserved keyword if you're using the [Supabase Platform](/docs/guides/platform) and [should be avoided as a column name](https://github.com/supabase/supabase/issues/5465). *\n * @category Database\n *\n * @example Getting your data\n * ```js\n * const { data, error } = await supabase\n * .from('characters')\n * .select()\n * ```\n *\n * @exampleSql Getting your data\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Harry'),\n * (2, 'Frodo'),\n * (3, 'Katniss');\n * ```\n *\n * @exampleResponse Getting your data\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Harry\"\n * },\n * {\n * \"id\": 2,\n * \"name\": \"Frodo\"\n * },\n * {\n * \"id\": 3,\n * \"name\": \"Katniss\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Handling errors\n * The most useful field on a Postgres error is usually `hint` — when the database knows the fix, it puts the literal SQL there. For example, a permission-denied error (`code: '42501'`) arrives with a `hint` like `\"Grant the required privileges to the current role with: GRANT SELECT ON public.characters TO anon;\"`. Log the full `error` object so the hint isn't hidden behind `error.message`.\n *\n * @example Handling errors\n * ```js\n * const { data, error } = await supabase.from('characters').select()\n * if (error) {\n * // Logs the full error: message, code, details, and hint.\n * console.error(error)\n * return\n * }\n * ```\n *\n * @exampleResponse Handling errors\n * ```json\n * {\n * \"error\": {\n * \"code\": \"42501\",\n * \"details\": null,\n * \"hint\": \"Grant the required privileges to the current role with: GRANT SELECT ON public.characters TO anon;\",\n * \"message\": \"permission denied for table characters\"\n * },\n * \"status\": 401,\n * \"statusText\": \"\"\n * }\n * ```\n *\n * @example Selecting specific columns\n * ```js\n * const { data, error } = await supabase\n * .from('characters')\n * .select('name')\n * ```\n *\n * @exampleSql Selecting specific columns\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Frodo'),\n * (2, 'Harry'),\n * (3, 'Katniss');\n * ```\n *\n * @exampleResponse Selecting specific columns\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Frodo\"\n * },\n * {\n * \"name\": \"Harry\"\n * },\n * {\n * \"name\": \"Katniss\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Query referenced tables\n * If your database has foreign key relationships, you can query related tables too.\n *\n * @example Query referenced tables\n * ```js\n * const { data, error } = await supabase\n * .from('orchestral_sections')\n * .select(`\n * name,\n * instruments (\n * name\n * )\n * `)\n * ```\n *\n * @exampleSql Query referenced tables\n * ```sql\n * create table\n * orchestral_sections (id int8 primary key, name text);\n * create table\n * instruments (\n * id int8 primary key,\n * section_id int8 not null references orchestral_sections,\n * name text\n * );\n *\n * insert into\n * orchestral_sections (id, name)\n * values\n * (1, 'strings'),\n * (2, 'woodwinds');\n * insert into\n * instruments (id, section_id, name)\n * values\n * (1, 2, 'flute'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse Query referenced tables\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"strings\",\n * \"instruments\": [\n * {\n * \"name\": \"violin\"\n * }\n * ]\n * },\n * {\n * \"name\": \"woodwinds\",\n * \"instruments\": [\n * {\n * \"name\": \"flute\"\n * }\n * ]\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Query referenced tables with spaces in their names\n * If your table name contains spaces, you must use double quotes in the `select` statement to reference the table.\n *\n * @example Query referenced tables with spaces in their names\n * ```js\n * const { data, error } = await supabase\n * .from('orchestral sections')\n * .select(`\n * name,\n * \"musical instruments\" (\n * name\n * )\n * `)\n * ```\n *\n * @exampleSql Query referenced tables with spaces in their names\n * ```sql\n * create table\n * \"orchestral sections\" (id int8 primary key, name text);\n * create table\n * \"musical instruments\" (\n * id int8 primary key,\n * section_id int8 not null references \"orchestral sections\",\n * name text\n * );\n *\n * insert into\n * \"orchestral sections\" (id, name)\n * values\n * (1, 'strings'),\n * (2, 'woodwinds');\n * insert into\n * \"musical instruments\" (id, section_id, name)\n * values\n * (1, 2, 'flute'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse Query referenced tables with spaces in their names\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"strings\",\n * \"musical instruments\": [\n * {\n * \"name\": \"violin\"\n * }\n * ]\n * },\n * {\n * \"name\": \"woodwinds\",\n * \"musical instruments\": [\n * {\n * \"name\": \"flute\"\n * }\n * ]\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Query referenced tables through a join table\n * If you're in a situation where your tables are **NOT** directly\n * related, but instead are joined by a _join table_, you can still use\n * the `select()` method to query the related data. The join table needs\n * to have the foreign keys as part of its composite primary key.\n *\n * @example Query referenced tables through a join table\n * ```ts\n * const { data, error } = await supabase\n * .from('users')\n * .select(`\n * name,\n * teams (\n * name\n * )\n * `)\n *\n * ``` * @exampleSql Query referenced tables through a join table\n * ```sql\n * create table\n * users (\n * id int8 primary key,\n * name text\n * );\n * create table\n * teams (\n * id int8 primary key,\n * name text\n * );\n * -- join table\n * create table\n * users_teams (\n * user_id int8 not null references users,\n * team_id int8 not null references teams,\n * -- both foreign keys must be part of a composite primary key\n * primary key (user_id, team_id)\n * );\n *\n * insert into\n * users (id, name)\n * values\n * (1, 'Kiran'),\n * (2, 'Evan');\n * insert into\n * teams (id, name)\n * values\n * (1, 'Green'),\n * (2, 'Blue');\n * insert into\n * users_teams (user_id, team_id)\n * values\n * (1, 1),\n * (1, 2),\n * (2, 2);\n * ```\n *\n * @exampleResponse Query referenced tables through a join table\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"Kiran\",\n * \"teams\": [\n * {\n * \"name\": \"Green\"\n * },\n * {\n * \"name\": \"Blue\"\n * }\n * ]\n * },\n * {\n * \"name\": \"Evan\",\n * \"teams\": [\n * {\n * \"name\": \"Blue\"\n * }\n * ]\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n *\n * @exampleDescription Query the same referenced table multiple times\n * If you need to query the same referenced table twice, use the name of the\n * joined column to identify which join to use. You can also give each\n * column an alias.\n *\n * @example Query the same referenced table multiple times\n * ```ts\n * const { data, error } = await supabase\n * .from('messages')\n * .select(`\n * content,\n * from:sender_id(name),\n * to:receiver_id(name)\n * `)\n *\n * // To infer types, use the name of the table (in this case `users`) and\n * // the name of the foreign key constraint.\n * const { data, error } = await supabase\n * .from('messages')\n * .select(`\n * content,\n * from:users!messages_sender_id_fkey(name),\n * to:users!messages_receiver_id_fkey(name)\n * `)\n * ```\n *\n * @exampleSql Query the same referenced table multiple times\n * ```sql\n * create table\n * users (id int8 primary key, name text);\n *\n * create table\n * messages (\n * sender_id int8 not null references users,\n * receiver_id int8 not null references users,\n * content text\n * );\n *\n * insert into\n * users (id, name)\n * values\n * (1, 'Kiran'),\n * (2, 'Evan');\n *\n * insert into\n * messages (sender_id, receiver_id, content)\n * values\n * (1, 2, '👋');\n * ```\n * ```\n *\n * @exampleResponse Query the same referenced table multiple times\n * ```json\n * {\n * \"data\": [\n * {\n * \"content\": \"👋\",\n * \"from\": {\n * \"name\": \"Kiran\"\n * },\n * \"to\": {\n * \"name\": \"Evan\"\n * }\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Query nested foreign tables through a join table\n * You can use the result of a joined table to gather data in\n * another foreign table. With multiple references to the same foreign\n * table you must specify the column on which to conduct the join.\n *\n * @example Query nested foreign tables through a join table\n * ```ts\n * const { data, error } = await supabase\n * .from('games')\n * .select(`\n * game_id:id,\n * away_team:teams!games_away_team_fkey (\n * users (\n * id,\n * name\n * )\n * )\n * `)\n *\n * ```\n *\n * @exampleSql Query nested foreign tables through a join table\n * ```sql\n * ```sql\n * create table\n * users (\n * id int8 primary key,\n * name text\n * );\n * create table\n * teams (\n * id int8 primary key,\n * name text\n * );\n * -- join table\n * create table\n * users_teams (\n * user_id int8 not null references users,\n * team_id int8 not null references teams,\n *\n * primary key (user_id, team_id)\n * );\n * create table\n * games (\n * id int8 primary key,\n * home_team int8 not null references teams,\n * away_team int8 not null references teams,\n * name text\n * );\n *\n * insert into users (id, name)\n * values\n * (1, 'Kiran'),\n * (2, 'Evan');\n * insert into\n * teams (id, name)\n * values\n * (1, 'Green'),\n * (2, 'Blue');\n * insert into\n * users_teams (user_id, team_id)\n * values\n * (1, 1),\n * (1, 2),\n * (2, 2);\n * insert into\n * games (id, home_team, away_team, name)\n * values\n * (1, 1, 2, 'Green vs Blue'),\n * (2, 2, 1, 'Blue vs Green');\n * ```\n *\n * @exampleResponse Query nested foreign tables through a join table\n * ```json\n * {\n * \"data\": [\n * {\n * \"game_id\": 1,\n * \"away_team\": {\n * \"users\": [\n * {\n * \"id\": 1,\n * \"name\": \"Kiran\"\n * },\n * {\n * \"id\": 2,\n * \"name\": \"Evan\"\n * }\n * ]\n * }\n * },\n * {\n * \"game_id\": 2,\n * \"away_team\": {\n * \"users\": [\n * {\n * \"id\": 1,\n * \"name\": \"Kiran\"\n * }\n * ]\n * }\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n *\n * @exampleDescription Filtering through referenced tables\n * If the filter on a referenced table's column is not satisfied, the referenced\n * table returns `[]` or `null` but the parent table is not filtered out.\n * If you want to filter out the parent table rows, use the `!inner` hint\n *\n * @example Filtering through referenced tables\n * ```ts\n * const { data, error } = await supabase\n * .from('instruments')\n * .select('name, orchestral_sections(*)')\n * .eq('orchestral_sections.name', 'percussion')\n * ```\n *\n * @exampleSql Filtering through referenced tables\n * ```sql\n * create table\n * orchestral_sections (id int8 primary key, name text);\n * create table\n * instruments (\n * id int8 primary key,\n * section_id int8 not null references orchestral_sections,\n * name text\n * );\n *\n * insert into\n * orchestral_sections (id, name)\n * values\n * (1, 'strings'),\n * (2, 'woodwinds');\n * insert into\n * instruments (id, section_id, name)\n * values\n * (1, 2, 'flute'),\n * (2, 1, 'violin');\n * ```\n *\n * @exampleResponse Filtering through referenced tables\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"flute\",\n * \"orchestral_sections\": null\n * },\n * {\n * \"name\": \"violin\",\n * \"orchestral_sections\": null\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Querying referenced table with count\n * You can get the number of rows in a related table by using the\n * **count** property.\n *\n * @example Querying referenced table with count\n * ```ts\n * const { data, error } = await supabase\n * .from('orchestral_sections')\n * .select(`*, instruments(count)`)\n * ```\n *\n * @exampleSql Querying referenced table with count\n * ```sql\n * create table orchestral_sections (\n * \"id\" \"uuid\" primary key default \"extensions\".\"uuid_generate_v4\"() not null,\n * \"name\" text\n * );\n *\n * create table characters (\n * \"id\" \"uuid\" primary key default \"extensions\".\"uuid_generate_v4\"() not null,\n * \"name\" text,\n * \"section_id\" \"uuid\" references public.orchestral_sections on delete cascade\n * );\n *\n * with section as (\n * insert into orchestral_sections (name)\n * values ('strings') returning id\n * )\n * insert into instruments (name, section_id) values\n * ('violin', (select id from section)),\n * ('viola', (select id from section)),\n * ('cello', (select id from section)),\n * ('double bass', (select id from section));\n * ```\n *\n * @exampleResponse Querying referenced table with count\n * ```json\n * [\n * {\n * \"id\": \"693694e7-d993-4360-a6d7-6294e325d9b6\",\n * \"name\": \"strings\",\n * \"instruments\": [\n * {\n * \"count\": 4\n * }\n * ]\n * }\n * ]\n * ```\n *\n * @exampleDescription Querying with count option\n * You can get the number of rows by using the\n * [count](/docs/reference/javascript/select#parameters) option.\n *\n * @example Querying with count option\n * ```ts\n * const { count, error } = await supabase\n * .from('characters')\n * .select('*', { count: 'exact', head: true })\n * ```\n *\n * @exampleSql Querying with count option\n * ```sql\n * create table\n * characters (id int8 primary key, name text);\n *\n * insert into\n * characters (id, name)\n * values\n * (1, 'Luke'),\n * (2, 'Leia'),\n * (3, 'Han');\n * ```\n *\n * @exampleResponse Querying with count option\n * ```json\n * {\n * \"count\": 3,\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Querying JSON data\n * You can select and filter data inside of\n * [JSON](/docs/guides/database/json) columns. Postgres offers some\n * [operators](/docs/guides/database/json#query-the-jsonb-data) for\n * querying JSON data.\n *\n * @example Querying JSON data\n * ```ts\n * const { data, error } = await supabase\n * .from('users')\n * .select(`\n * id, name,\n * address->city\n * `)\n * ```\n *\n * @exampleSql Querying JSON data\n * ```sql\n * create table\n * users (\n * id int8 primary key,\n * name text,\n * address jsonb\n * );\n *\n * insert into\n * users (id, name, address)\n * values\n * (1, 'Frodo', '{\"city\":\"Hobbiton\"}');\n * ```\n *\n * @exampleResponse Querying JSON data\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Frodo\",\n * \"city\": \"Hobbiton\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Querying referenced table with inner join\n * If you don't want to return the referenced table contents, you can leave the parenthesis empty.\n * Like `.select('name, orchestral_sections!inner()')`.\n *\n * @example Querying referenced table with inner join\n * ```ts\n * const { data, error } = await supabase\n * .from('instruments')\n * .select('name, orchestral_sections!inner(name)')\n * .eq('orchestral_sections.name', 'woodwinds')\n * .limit(1)\n * ```\n *\n * @exampleSql Querying referenced table with inner join\n * ```sql\n * create table orchestral_sections (\n * \"id\" \"uuid\" primary key default \"extensions\".\"uuid_generate_v4\"() not null,\n * \"name\" text\n * );\n *\n * create table instruments (\n * \"id\" \"uuid\" primary key default \"extensions\".\"uuid_generate_v4\"() not null,\n * \"name\" text,\n * \"section_id\" \"uuid\" references public.orchestral_sections on delete cascade\n * );\n *\n * with section as (\n * insert into orchestral_sections (name)\n * values ('woodwinds') returning id\n * )\n * insert into instruments (name, section_id) values\n * ('flute', (select id from section)),\n * ('clarinet', (select id from section)),\n * ('bassoon', (select id from section)),\n * ('piccolo', (select id from section));\n * ```\n *\n * @exampleResponse Querying referenced table with inner join\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"flute\",\n * \"orchestral_sections\": {\"name\": \"woodwinds\"}\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Switching schemas per query\n * In addition to setting the schema during initialization, you can also switch schemas on a per-query basis.\n * Make sure you've set up your [database privileges and API settings](/docs/guides/api/using-custom-schemas).\n *\n * @example Switching schemas per query\n * ```ts\n * const { data, error } = await supabase\n * .schema('myschema')\n * .from('mytable')\n * .select()\n * ```\n *\n * @exampleSql Switching schemas per query\n * ```sql\n * create schema myschema;\n *\n * create table myschema.mytable (\n * id uuid primary key default gen_random_uuid(),\n * data text\n * );\n *\n * insert into myschema.mytable (data) values ('mydata');\n * ```\n *\n * @exampleResponse Switching schemas per query\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": \"4162e008-27b0-4c0f-82dc-ccaeee9a624d\",\n * \"data\": \"mydata\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n select<\n Query extends string = '*',\n ResultOne = GetResult<\n Schema,\n Relation['Row'],\n RelationName,\n Relationships,\n Query,\n ClientOptions\n >,\n >(\n columns?: Query,\n options?: {\n head?: boolean\n count?: 'exact' | 'planned' | 'estimated' | (string & {})\n }\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Relation['Row'],\n ResultOne[],\n RelationName,\n Relationships,\n 'GET'\n > {\n const { head = false, count } = options ?? {}\n\n const method = head ? 'HEAD' : 'GET'\n // Remove whitespaces except when quoted\n let quoted = false\n const cleanedColumns = (columns ?? '*')\n .split('')\n .map((c) => {\n if (/\\s/.test(c) && !quoted) {\n return ''\n }\n if (c === '\"') {\n quoted = !quoted\n }\n return c\n })\n .join('')\n\n const { url, headers } = this.cloneRequestState()\n url.searchParams.set('select', cleanedColumns)\n\n if (count) {\n headers.append('Prefer', `count=${count}`)\n }\n\n return new PostgrestFilterBuilder({\n method,\n url,\n headers,\n schema: this.schema,\n fetch: this.fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n\n /**\n * Perform an INSERT into the table or view.\n *\n * By default, inserted rows are not returned. To return it, chain the call\n * with `.select()`.\n *\n * @param values - The values to insert. Pass an object to insert a single row\n * or an array to insert multiple rows.\n *\n * @param options - Named parameters\n *\n * @param options.count - Count algorithm to use to count inserted rows.\n *\n * `\"exact\"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the\n * hood.\n *\n * `\"planned\"`: Approximated but fast count algorithm. Uses the Postgres\n * statistics under the hood.\n *\n * `\"estimated\"`: Uses exact count for low numbers and planned count for high\n * numbers.\n *\n * @param options.defaultToNull - Make missing fields default to `null`.\n * Otherwise, use the default value for the column. Only applies for bulk\n * inserts.\n *\n * @category Database\n *\n * @example Create a record\n * ```ts\n * const { error } = await supabase\n * .from('countries')\n * .insert({ id: 1, name: 'Mordor' })\n * ```\n *\n * @exampleSql Create a record\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n * ```\n *\n * @exampleResponse Create a record\n * ```json\n * {\n * \"status\": 201,\n * \"statusText\": \"\"\n * }\n * ```\n *\n * @exampleDescription Handling errors\n * `error.hint` from Postgres often contains the actionable fix (e.g. `\"Grant the required privileges to the current role with: GRANT INSERT ON public.countries TO anon;\"` for a `42501` permission-denied error). Log the full `error` object so it isn't hidden behind `error.message`.\n *\n * @example Handling errors\n * ```js\n * const { error } = await supabase.from('countries').insert({ id: 1, name: 'Mordor' })\n * if (error) console.error(error)\n * ```\n *\n * @example Create a record and return it\n * ```ts\n * const { data, error } = await supabase\n * .from('countries')\n * .insert({ id: 1, name: 'Mordor' })\n * .select()\n * ```\n *\n * @exampleSql Create a record and return it\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n * ```\n *\n * @exampleResponse Create a record and return it\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Mordor\"\n * }\n * ],\n * \"status\": 201,\n * \"statusText\": \"\"\n * }\n * ```\n *\n * @exampleDescription Bulk create\n * A bulk create operation is handled in a single transaction.\n * If any of the inserts fail, none of the rows are inserted.\n *\n * @example Bulk create\n * ```ts\n * const { error } = await supabase\n * .from('countries')\n * .insert([\n * { id: 1, name: 'Mordor' },\n * { id: 1, name: 'The Shire' },\n * ])\n * ```\n *\n * @exampleSql Bulk create\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n * ```\n *\n * @exampleResponse Bulk create\n * ```json\n * {\n * \"error\": {\n * \"code\": \"23505\",\n * \"details\": \"Key (id)=(1) already exists.\",\n * \"hint\": null,\n * \"message\": \"duplicate key value violates unique constraint \\\"countries_pkey\\\"\"\n * },\n * \"status\": 409,\n * \"statusText\": \"\"\n * }\n * ```\n */\n insert<Row extends Relation extends { Insert: unknown } ? Relation['Insert'] : never>(\n values:\n | RejectExcessProperties<\n Relation extends { Insert: unknown } ? Relation['Insert'] : never,\n Row\n >\n | RejectExcessProperties<\n Relation extends { Insert: unknown } ? Relation['Insert'] : never,\n Row\n >[],\n {\n count,\n defaultToNull = true,\n }: {\n count?: 'exact' | 'planned' | 'estimated' | (string & {})\n defaultToNull?: boolean\n } = {}\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Relation['Row'],\n null,\n RelationName,\n Relationships,\n 'POST'\n > {\n const method = 'POST'\n const { url, headers } = this.cloneRequestState()\n\n if (count) {\n headers.append('Prefer', `count=${count}`)\n }\n if (!defaultToNull) {\n headers.append('Prefer', `missing=default`)\n }\n\n if (Array.isArray(values)) {\n const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), [] as string[])\n if (columns.length > 0) {\n const uniqueColumns = [...new Set(columns)].map((column) => `\"${column}\"`)\n url.searchParams.set('columns', uniqueColumns.join(','))\n }\n }\n\n return new PostgrestFilterBuilder({\n method,\n url,\n headers,\n schema: this.schema,\n body: values,\n fetch: this.fetch ?? fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n\n /**\n * Perform an UPSERT on the table or view. Depending on the column(s) passed\n * to `onConflict`, `.upsert()` allows you to perform the equivalent of\n * `.insert()` if a row with the corresponding `onConflict` columns doesn't\n * exist, or if it does exist, perform an alternative action depending on\n * `ignoreDuplicates`.\n *\n * By default, upserted rows are not returned. To return it, chain the call\n * with `.select()`.\n *\n * @param values - The values to upsert with. Pass an object to upsert a\n * single row or an array to upsert multiple rows.\n *\n * @param options - Named parameters\n *\n * @param options.onConflict - Comma-separated UNIQUE column(s) to specify how\n * duplicate rows are determined. Two rows are duplicates if all the\n * `onConflict` columns are equal.\n *\n * @param options.ignoreDuplicates - If `true`, duplicate rows are ignored. If\n * `false`, duplicate rows are merged with existing rows.\n *\n * @param options.count - Count algorithm to use to count upserted rows.\n *\n * `\"exact\"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the\n * hood.\n *\n * `\"planned\"`: Approximated but fast count algorithm. Uses the Postgres\n * statistics under the hood.\n *\n * `\"estimated\"`: Uses exact count for low numbers and planned count for high\n * numbers.\n *\n * @param options.defaultToNull - Make missing fields default to `null`.\n * Otherwise, use the default value for the column. This only applies when\n * inserting new rows, not when merging with existing rows under\n * `ignoreDuplicates: false`. This also only applies when doing bulk upserts.\n *\n * @example Upsert a single row using a unique key\n * ```ts\n * // Upserting a single row, overwriting based on the 'username' unique column\n * const { data, error } = await supabase\n * .from('users')\n * .upsert({ username: 'supabot' }, { onConflict: 'username' })\n *\n * // Example response:\n * // {\n * // data: [\n * // { id: 4, message: 'bar', username: 'supabot' }\n * // ],\n * // error: null\n * // }\n * ```\n *\n * @example Upsert with conflict resolution and exact row counting\n * ```ts\n * // Upserting and returning exact count\n * const { data, error, count } = await supabase\n * .from('users')\n * .upsert(\n * {\n * id: 3,\n * message: 'foo',\n * username: 'supabot'\n * },\n * {\n * onConflict: 'username',\n * count: 'exact'\n * }\n * )\n *\n * // Example response:\n * // {\n * // data: [\n * // {\n * // id: 42,\n * // handle: \"saoirse\",\n * // display_name: \"Saoirse\"\n * // }\n * // ],\n * // count: 1,\n * // error: null\n * // }\n * ```\n *\n * @category Database\n *\n * @remarks\n * - Primary keys must be included in `values` to use upsert.\n *\n * @example Upsert your data\n * ```ts\n * const { data, error } = await supabase\n * .from('instruments')\n * .upsert({ id: 1, name: 'piano' })\n * .select()\n * ```\n *\n * @exampleSql Upsert your data\n * ```sql\n * create table\n * instruments (id int8 primary key, name text);\n *\n * insert into\n * instruments (id, name)\n * values\n * (1, 'harpsichord');\n * ```\n *\n * @exampleResponse Upsert your data\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"piano\"\n * }\n * ],\n * \"status\": 201,\n * \"statusText\": \"\"\n * }\n * ```\n *\n * @exampleDescription Handling errors\n * `error.hint` from Postgres often contains the actionable fix (e.g. `\"Grant the required privileges to the current role with: GRANT INSERT, UPDATE ON public.instruments TO anon;\"` for a `42501` permission-denied error). Log the full `error` object so it isn't hidden behind `error.message`.\n *\n * @example Handling errors\n * ```js\n * const { data, error } = await supabase.from('instruments').upsert({ id: 1, name: 'piano' }).select()\n * if (error) console.error(error)\n * ```\n *\n * @example Bulk Upsert your data\n * ```ts\n * const { data, error } = await supabase\n * .from('instruments')\n * .upsert([\n * { id: 1, name: 'piano' },\n * { id: 2, name: 'harp' },\n * ])\n * .select()\n * ```\n *\n * @exampleSql Bulk Upsert your data\n * ```sql\n * create table\n * instruments (id int8 primary key, name text);\n *\n * insert into\n * instruments (id, name)\n * values\n * (1, 'harpsichord');\n * ```\n *\n * @exampleResponse Bulk Upsert your data\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"piano\"\n * },\n * {\n * \"id\": 2,\n * \"name\": \"harp\"\n * }\n * ],\n * \"status\": 201,\n * \"statusText\": \"\"\n * }\n * ```\n *\n * @exampleDescription Upserting into tables with constraints\n * In the following query, `upsert()` implicitly uses the `id`\n * (primary key) column to determine conflicts. If there is no existing\n * row with the same `id`, `upsert()` inserts a new row, which\n * will fail in this case as there is already a row with `handle` `\"saoirse\"`.\n * Using the `onConflict` option, you can instruct `upsert()` to use\n * another column with a unique constraint to determine conflicts.\n *\n * @example Upserting into tables with constraints\n * ```ts\n * const { data, error } = await supabase\n * .from('users')\n * .upsert({ id: 42, handle: 'saoirse', display_name: 'Saoirse' })\n * .select()\n * ```\n *\n * @exampleSql Upserting into tables with constraints\n * ```sql\n * create table\n * users (\n * id int8 generated by default as identity primary key,\n * handle text not null unique,\n * display_name text\n * );\n *\n * insert into\n * users (id, handle, display_name)\n * values\n * (1, 'saoirse', null);\n * ```\n *\n * @exampleResponse Upserting into tables with constraints\n * ```json\n * {\n * \"error\": {\n * \"code\": \"23505\",\n * \"details\": \"Key (handle)=(saoirse) already exists.\",\n * \"hint\": null,\n * \"message\": \"duplicate key value violates unique constraint \\\"users_handle_key\\\"\"\n * },\n * \"status\": 409,\n * \"statusText\": \"\"\n * }\n * ```\n */\n\n upsert<Row extends Relation extends { Insert: unknown } ? Relation['Insert'] : never>(\n values:\n | RejectExcessProperties<\n Relation extends { Insert: unknown } ? Relation['Insert'] : never,\n Row\n >\n | RejectExcessProperties<\n Relation extends { Insert: unknown } ? Relation['Insert'] : never,\n Row\n >[],\n {\n onConflict,\n ignoreDuplicates = false,\n count,\n defaultToNull = true,\n }: {\n onConflict?: string\n ignoreDuplicates?: boolean\n count?: 'exact' | 'planned' | 'estimated' | (string & {})\n defaultToNull?: boolean\n } = {}\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Relation['Row'],\n null,\n RelationName,\n Relationships,\n 'POST'\n > {\n const method = 'POST'\n const { url, headers } = this.cloneRequestState()\n\n headers.append('Prefer', `resolution=${ignoreDuplicates ? 'ignore' : 'merge'}-duplicates`)\n\n if (onConflict !== undefined) url.searchParams.set('on_conflict', onConflict)\n if (count) {\n headers.append('Prefer', `count=${count}`)\n }\n if (!defaultToNull) {\n headers.append('Prefer', 'missing=default')\n }\n\n if (Array.isArray(values)) {\n const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), [] as string[])\n if (columns.length > 0) {\n const uniqueColumns = [...new Set(columns)].map((column) => `\"${column}\"`)\n url.searchParams.set('columns', uniqueColumns.join(','))\n }\n }\n\n return new PostgrestFilterBuilder({\n method,\n url,\n headers,\n schema: this.schema,\n body: values,\n fetch: this.fetch ?? fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n\n /**\n * Perform an UPDATE on the table or view.\n *\n * By default, updated rows are not returned. To return it, chain the call\n * with `.select()` after filters.\n *\n * @param values - The values to update with\n *\n * @param options - Named parameters\n *\n * @param options.count - Count algorithm to use to count updated rows.\n *\n * `\"exact\"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the\n * hood.\n *\n * `\"planned\"`: Approximated but fast count algorithm. Uses the Postgres\n * statistics under the hood.\n *\n * `\"estimated\"`: Uses exact count for low numbers and planned count for high\n * numbers.\n *\n * @category Database\n *\n * @remarks\n * - `update()` should always be combined with [Filters](/docs/reference/javascript/using-filters) to target the item(s) you wish to update.\n *\n * @example Updating your data\n * ```ts\n * const { error } = await supabase\n * .from('instruments')\n * .update({ name: 'piano' })\n * .eq('id', 1)\n * ```\n *\n * @exampleSql Updating your data\n * ```sql\n * create table\n * instruments (id int8 primary key, name text);\n *\n * insert into\n * instruments (id, name)\n * values\n * (1, 'harpsichord');\n * ```\n *\n * @exampleResponse Updating your data\n * ```json\n * {\n * \"status\": 204,\n * \"statusText\": \"\"\n * }\n * ```\n *\n * @exampleDescription Handling errors\n * `error.hint` from Postgres often contains the actionable fix (e.g. `\"Grant the required privileges to the current role with: GRANT UPDATE ON public.instruments TO anon;\"` for a `42501` permission-denied error). Log the full `error` object so it isn't hidden behind `error.message`.\n *\n * @example Handling errors\n * ```js\n * const { error } = await supabase.from('instruments').update({ name: 'piano' }).eq('id', 1)\n * if (error) console.error(error)\n * ```\n *\n * @example Update a record and return it\n * ```ts\n * const { data, error } = await supabase\n * .from('instruments')\n * .update({ name: 'piano' })\n * .eq('id', 1)\n * .select()\n * ```\n *\n * @exampleSql Update a record and return it\n * ```sql\n * create table\n * instruments (id int8 primary key, name text);\n *\n * insert into\n * instruments (id, name)\n * values\n * (1, 'harpsichord');\n * ```\n *\n * @exampleResponse Update a record and return it\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"piano\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Updating JSON data\n * Postgres offers some\n * [operators](/docs/guides/database/json#query-the-jsonb-data) for\n * working with JSON data. Currently, it is only possible to update the entire JSON document.\n *\n * @example Updating JSON data\n * ```ts\n * const { data, error } = await supabase\n * .from('users')\n * .update({\n * address: {\n * street: 'Melrose Place',\n * postcode: 90210\n * }\n * })\n * .eq('address->postcode', 90210)\n * .select()\n * ```\n *\n * @exampleSql Updating JSON data\n * ```sql\n * create table\n * users (\n * id int8 primary key,\n * name text,\n * address jsonb\n * );\n *\n * insert into\n * users (id, name, address)\n * values\n * (1, 'Michael', '{ \"postcode\": 90210 }');\n * ```\n *\n * @exampleResponse Updating JSON data\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Michael\",\n * \"address\": {\n * \"street\": \"Melrose Place\",\n * \"postcode\": 90210\n * }\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n update<Row extends Relation extends { Update: unknown } ? Relation['Update'] : never>(\n values: RejectExcessProperties<\n Relation extends { Update: unknown } ? Relation['Update'] : never,\n Row\n >,\n {\n count,\n }: {\n count?: 'exact' | 'planned' | 'estimated' | (string & {})\n } = {}\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Relation['Row'],\n null,\n RelationName,\n Relationships,\n 'PATCH'\n > {\n const method = 'PATCH'\n const { url, headers } = this.cloneRequestState()\n\n if (count) {\n headers.append('Prefer', `count=${count}`)\n }\n\n return new PostgrestFilterBuilder({\n method,\n url,\n headers,\n schema: this.schema,\n body: values,\n fetch: this.fetch ?? fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n\n /**\n * Perform a DELETE on the table or view.\n *\n * By default, deleted rows are not returned. To return it, chain the call\n * with `.select()` after filters.\n *\n * @param options - Named parameters\n *\n * @param options.count - Count algorithm to use to count deleted rows.\n *\n * `\"exact\"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the\n * hood.\n *\n * `\"planned\"`: Approximated but fast count algorithm. Uses the Postgres\n * statistics under the hood.\n *\n * `\"estimated\"`: Uses exact count for low numbers and planned count for high\n * numbers.\n *\n * @category Database\n *\n * @remarks\n * - `delete()` should always be combined with [filters](/docs/reference/javascript/using-filters) to target the item(s) you wish to delete.\n * - If you use `delete()` with filters and you have\n * [RLS](/docs/learn/auth-deep-dive/auth-row-level-security) enabled, only\n * rows visible through `SELECT` policies are deleted. Note that by default\n * no rows are visible, so you need at least one `SELECT`/`ALL` policy that\n * makes the rows visible.\n * - When using `delete().in()`, specify an array of values to target multiple rows with a single query. This is particularly useful for batch deleting entries that share common criteria, such as deleting users by their IDs. Ensure that the array you provide accurately represents all records you intend to delete to avoid unintended data removal.\n *\n * @example Delete a single record\n * ```ts\n * const response = await supabase\n * .from('countries')\n * .delete()\n * .eq('id', 1)\n * ```\n *\n * @exampleSql Delete a single record\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n *\n * insert into\n * countries (id, name)\n * values\n * (1, 'Mordor');\n * ```\n *\n * @exampleResponse Delete a single record\n * ```json\n * {\n * \"status\": 204,\n * \"statusText\": \"\"\n * }\n * ```\n *\n * @exampleDescription Handling errors\n * `error.hint` from Postgres often contains the actionable fix (e.g. `\"Grant the required privileges to the current role with: GRANT DELETE ON public.countries TO anon;\"` for a `42501` permission-denied error). Log the full `error` object so it isn't hidden behind `error.message`.\n *\n * @example Handling errors\n * ```js\n * const { error } = await supabase.from('countries').delete().eq('id', 1)\n * if (error) console.error(error)\n * ```\n *\n * @example Delete a record and return it\n * ```ts\n * const { data, error } = await supabase\n * .from('countries')\n * .delete()\n * .eq('id', 1)\n * .select()\n * ```\n *\n * @exampleSql Delete a record and return it\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n *\n * insert into\n * countries (id, name)\n * values\n * (1, 'Mordor');\n * ```\n *\n * @exampleResponse Delete a record and return it\n * ```json\n * {\n * \"data\": [\n * {\n * \"id\": 1,\n * \"name\": \"Mordor\"\n * }\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example Delete multiple records\n * ```ts\n * const response = await supabase\n * .from('countries')\n * .delete()\n * .in('id', [1, 2, 3])\n * ```\n *\n * @exampleSql Delete multiple records\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n *\n * insert into\n * countries (id, name)\n * values\n * (1, 'Rohan'), (2, 'The Shire'), (3, 'Mordor');\n * ```\n *\n * @exampleResponse Delete multiple records\n * ```json\n * {\n * \"status\": 204,\n * \"statusText\": \"\"\n * }\n * ```\n */\n delete({\n count,\n }: {\n count?: 'exact' | 'planned' | 'estimated' | (string & {})\n } = {}): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n Relation['Row'],\n null,\n RelationName,\n Relationships,\n 'DELETE'\n > {\n const method = 'DELETE'\n const { url, headers } = this.cloneRequestState()\n\n if (count) {\n headers.append('Prefer', `count=${count}`)\n }\n\n return new PostgrestFilterBuilder({\n method,\n url,\n headers,\n schema: this.schema,\n fetch: this.fetch ?? fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n}\n","import PostgrestQueryBuilder from './PostgrestQueryBuilder'\nimport PostgrestFilterBuilder from './PostgrestFilterBuilder'\nimport { Fetch, GenericSchema, ClientServerOptions } from './types/common/common'\nimport { GetRpcFunctionFilterBuilderByArgs } from './types/common/rpc'\n\n/**\n * PostgREST client.\n *\n * @typeParam Database - Types for the schema from the [type\n * generator](https://supabase.com/docs/reference/javascript/next/typescript-support)\n *\n * @typeParam SchemaName - Postgres schema to switch to. Must be a string\n * literal, the same one passed to the constructor. If the schema is not\n * `\"public\"`, this must be supplied manually.\n */\nexport default class PostgrestClient<\n Database = any,\n ClientOptions extends ClientServerOptions = Database extends {\n __InternalSupabase: infer I extends ClientServerOptions\n }\n ? I\n : {},\n SchemaName extends string & keyof Omit<Database, '__InternalSupabase'> =\n 'public' extends keyof Omit<Database, '__InternalSupabase'>\n ? 'public'\n : string & keyof Omit<Database, '__InternalSupabase'>,\n Schema extends GenericSchema = Omit<\n Database,\n '__InternalSupabase'\n >[SchemaName] extends GenericSchema\n ? Omit<Database, '__InternalSupabase'>[SchemaName]\n : any,\n> {\n url: string\n headers: Headers\n schemaName?: SchemaName\n fetch?: Fetch\n urlLengthLimit: number\n\n // Retry configuration - enabled by default\n retry?: boolean\n\n // TODO: Add back shouldThrowOnError once we figure out the typings\n /**\n * Creates a PostgREST client.\n *\n * @param url - URL of the PostgREST endpoint\n * @param options - Named parameters\n * @param options.headers - Custom headers\n * @param options.schema - Postgres schema to switch to\n * @param options.fetch - Custom fetch\n * @param options.timeout - Optional timeout in milliseconds for all requests. When set, requests will automatically abort after this duration to prevent indefinite hangs.\n * @param options.urlLengthLimit - Maximum URL length in characters before warnings/errors are triggered. Defaults to 8000.\n * @param options.retry - Enable or disable automatic retries for transient errors.\n * When enabled, idempotent requests (GET, HEAD, OPTIONS) that fail with network\n * errors or HTTP 503/520 responses will be automatically retried up to 3 times\n * with exponential backoff (1s, 2s, 4s). Defaults to `true`.\n * @example Using supabase-js (recommended)\n * ```ts\n * import { createClient } from '@supabase/supabase-js'\n *\n * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')\n * const { data, error } = await supabase.from('profiles').select('*')\n * ```\n *\n * @category Database\n *\n * @remarks\n * - A `timeout` option (in milliseconds) can be set to automatically abort requests that take too long.\n * - A `urlLengthLimit` option (default: 8000) can be set to control when URL length warnings are included in error messages for aborted requests.\n *\n * @example Standalone import for bundle-sensitive environments\n * ```ts\n * import { PostgrestClient } from '@supabase/postgrest-js'\n *\n * const postgrest = new PostgrestClient('https://xyzcompany.supabase.co/rest/v1', {\n * headers: { apikey: 'your-publishable-key' },\n * schema: 'public',\n * timeout: 30000, // 30 second timeout\n * })\n * ```\n */\n constructor(\n url: string,\n {\n headers = {},\n schema,\n fetch,\n timeout,\n urlLengthLimit = 8000,\n retry,\n }: {\n headers?: HeadersInit\n schema?: SchemaName\n fetch?: Fetch\n timeout?: number\n urlLengthLimit?: number\n retry?: boolean\n } = {}\n ) {\n this.url = url\n this.headers = new Headers(headers)\n this.schemaName = schema\n this.urlLengthLimit = urlLengthLimit\n\n const originalFetch = fetch ?? globalThis.fetch\n\n // Wrap fetch with timeout if specified\n if (timeout !== undefined && timeout > 0) {\n this.fetch = (input, init) => {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n // Merge abort signals if one already exists\n const existingSignal = init?.signal\n if (existingSignal) {\n // If the existing signal is already aborted, use it directly\n if (existingSignal.aborted) {\n clearTimeout(timeoutId)\n return originalFetch(input, init)\n }\n\n // Listen to existing signal and abort our controller too\n const abortHandler = () => {\n clearTimeout(timeoutId)\n controller.abort()\n }\n existingSignal.addEventListener('abort', abortHandler, { once: true })\n\n return originalFetch(input, {\n ...init,\n signal: controller.signal,\n }).finally(() => {\n clearTimeout(timeoutId)\n existingSignal.removeEventListener('abort', abortHandler)\n })\n }\n\n return originalFetch(input, {\n ...init,\n signal: controller.signal,\n }).finally(() => clearTimeout(timeoutId))\n }\n } else {\n this.fetch = originalFetch\n }\n this.retry = retry\n }\n /**\n * Perform a query on a table or a view.\n *\n * @param relation - The table or view name to query\n *\n * @category Database\n */\n from<\n TableName extends string & keyof Schema['Tables'],\n Table extends Schema['Tables'][TableName],\n >(relation: TableName): PostgrestQueryBuilder<ClientOptions, Schema, Table, TableName>\n from<ViewName extends string & keyof Schema['Views'], View extends Schema['Views'][ViewName]>(\n relation: ViewName\n ): PostgrestQueryBuilder<ClientOptions, Schema, View, ViewName>\n from(\n relation: (string & keyof Schema['Tables']) | (string & keyof Schema['Views'])\n ): PostgrestQueryBuilder<ClientOptions, Schema, any, any> {\n if (!relation || typeof relation !== 'string' || relation.trim() === '') {\n throw new Error('Invalid relation name: relation must be a non-empty string.')\n }\n\n const url = new URL(`${this.url}/${relation}`)\n return new PostgrestQueryBuilder(url, {\n headers: new Headers(this.headers),\n schema: this.schemaName,\n fetch: this.fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n\n /**\n * Select a schema to query or perform an function (rpc) call.\n *\n * The schema needs to be on the list of exposed schemas inside Supabase.\n *\n * @param schema - The schema to query\n *\n * @category Database\n */\n schema<DynamicSchema extends string & keyof Omit<Database, '__InternalSupabase'>>(\n schema: DynamicSchema\n ): PostgrestClient<\n Database,\n ClientOptions,\n DynamicSchema,\n Database[DynamicSchema] extends GenericSchema ? Database[DynamicSchema] : any\n > {\n return new PostgrestClient(this.url, {\n headers: this.headers,\n schema,\n fetch: this.fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n\n /**\n * Perform a function call.\n *\n * @param fn - The function name to call\n * @param args - The arguments to pass to the function call\n * @param options - Named parameters\n * @param options.head - When set to `true`, `data` will not be returned.\n * Useful if you only need the count.\n * @param options.get - When set to `true`, the function will be called with\n * read-only access mode.\n * @param options.count - Count algorithm to use to count rows returned by the\n * function. Only applicable for [set-returning\n * functions](https://www.postgresql.org/docs/current/functions-srf.html).\n *\n * `\"exact\"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the\n * hood.\n *\n * `\"planned\"`: Approximated but fast count algorithm. Uses the Postgres\n * statistics under the hood.\n *\n * `\"estimated\"`: Uses exact count for low numbers and planned count for high\n * numbers.\n *\n * @example\n * ```ts\n * // For cross-schema functions where type inference fails, use overrideTypes:\n * const { data } = await supabase\n * .schema('schema_b')\n * .rpc('function_a', {})\n * .overrideTypes<{ id: string; user_id: string }[]>()\n * ```\n *\n * @category Database\n *\n * @example Call a Postgres function without arguments\n * ```ts\n * const { data, error } = await supabase.rpc('hello_world')\n * ```\n *\n * @exampleSql Call a Postgres function without arguments\n * ```sql\n * create function hello_world() returns text as $$\n * select 'Hello world';\n * $$ language sql;\n * ```\n *\n * @exampleResponse Call a Postgres function without arguments\n * ```json\n * {\n * \"data\": \"Hello world\",\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example Call a Postgres function with arguments\n * ```ts\n * const { data, error } = await supabase.rpc('echo', { say: '👋' })\n * ```\n *\n * @exampleSql Call a Postgres function with arguments\n * ```sql\n * create function echo(say text) returns text as $$\n * select say;\n * $$ language sql;\n * ```\n *\n * @exampleResponse Call a Postgres function with arguments\n * ```json\n * {\n * \"data\": \"👋\",\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n *\n * ```\n *\n * @exampleDescription Bulk processing\n * You can process large payloads by passing in an array as an argument.\n *\n * @example Bulk processing\n * ```ts\n * const { data, error } = await supabase.rpc('add_one_each', { arr: [1, 2, 3] })\n * ```\n *\n * @exampleSql Bulk processing\n * ```sql\n * create function add_one_each(arr int[]) returns int[] as $$\n * select array_agg(n + 1) from unnest(arr) as n;\n * $$ language sql;\n * ```\n *\n * @exampleResponse Bulk processing\n * ```json\n * {\n * \"data\": [\n * 2,\n * 3,\n * 4\n * ],\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @exampleDescription Call a Postgres function with filters\n * Postgres functions that return tables can also be combined with [Filters](/docs/reference/javascript/using-filters) and [Modifiers](/docs/reference/javascript/using-modifiers).\n *\n * @example Call a Postgres function with filters\n * ```ts\n * const { data, error } = await supabase\n * .rpc('list_stored_countries')\n * .eq('id', 1)\n * .single()\n * ```\n *\n * @exampleSql Call a Postgres function with filters\n * ```sql\n * create table\n * countries (id int8 primary key, name text);\n *\n * insert into\n * countries (id, name)\n * values\n * (1, 'Rohan'),\n * (2, 'The Shire');\n *\n * create function list_stored_countries() returns setof countries as $$\n * select * from countries;\n * $$ language sql;\n * ```\n *\n * @exampleResponse Call a Postgres function with filters\n * ```json\n * {\n * \"data\": {\n * \"id\": 1,\n * \"name\": \"Rohan\"\n * },\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n *\n * @example Call a read-only Postgres function\n * ```ts\n * const { data, error } = await supabase.rpc('hello_world', undefined, { get: true })\n * ```\n *\n * @exampleSql Call a read-only Postgres function\n * ```sql\n * create function hello_world() returns text as $$\n * select 'Hello world';\n * $$ language sql;\n * ```\n *\n * @exampleResponse Call a read-only Postgres function\n * ```json\n * {\n * \"data\": \"Hello world\",\n * \"status\": 200,\n * \"statusText\": \"OK\"\n * }\n * ```\n */\n rpc<\n FnName extends string & keyof Schema['Functions'],\n Args extends Schema['Functions'][FnName]['Args'] = never,\n FilterBuilder extends GetRpcFunctionFilterBuilderByArgs<Schema, FnName, Args> =\n GetRpcFunctionFilterBuilderByArgs<Schema, FnName, Args>,\n >(\n fn: FnName,\n args: Args = {} as Args,\n {\n head = false,\n get = false,\n count,\n }: {\n head?: boolean\n get?: boolean\n count?: 'exact' | 'planned' | 'estimated' | (string & {})\n } = {}\n ): PostgrestFilterBuilder<\n ClientOptions,\n Schema,\n FilterBuilder['Row'],\n FilterBuilder['Result'],\n FilterBuilder['RelationName'],\n FilterBuilder['Relationships'],\n 'RPC'\n > {\n let method: 'HEAD' | 'GET' | 'POST'\n const url = new URL(`${this.url}/rpc/${fn}`)\n let body: unknown | undefined\n // objects/arrays-of-objects can't be serialized to URL params, use POST + return=minimal instead\n const _isObject = (v: unknown): boolean =>\n v !== null && typeof v === 'object' && (!Array.isArray(v) || v.some(_isObject))\n const _hasObjectArg = head && Object.values(args as object).some(_isObject)\n if (_hasObjectArg) {\n method = 'POST'\n body = args\n } else if (head || get) {\n method = head ? 'HEAD' : 'GET'\n Object.entries(args)\n // params with undefined value needs to be filtered out, otherwise it'll\n // show up as `?param=undefined`\n .filter(([_, value]) => value !== undefined)\n // array values need special syntax\n .map(([name, value]) => [name, Array.isArray(value) ? `{${value.join(',')}}` : `${value}`])\n .forEach(([name, value]) => {\n url.searchParams.append(name, value)\n })\n } else {\n method = 'POST'\n body = args\n }\n\n const headers = new Headers(this.headers)\n if (_hasObjectArg) {\n headers.set('Prefer', count ? `count=${count},return=minimal` : 'return=minimal')\n } else if (count) {\n headers.set('Prefer', `count=${count}`)\n }\n\n return new PostgrestFilterBuilder({\n method,\n url,\n headers,\n schema: this.schemaName,\n body,\n fetch: this.fetch ?? fetch,\n urlLengthLimit: this.urlLengthLimit,\n retry: this.retry,\n })\n }\n}\n","/**\n * Database 模块封装(#89098)\n *\n * 数据面 `/.cloud/database/rest/**`,PostgREST 语义(设计文档 §6.1)。\n *\n * ============================================================================\n * 为什么有这层 facade,而不是把 vendor 的 PostgrestClient 裸抛给应用\n *\n * 其余三个模块(auth/storage/llm)都在 SDK 侧收一层 facade,公开自命名类型、\n * 藏住 vendor —— database 若独独裸透传,会有两个后果:\n *\n * 1. vendor 类型泄漏。`index.ts` 明确规定不导出 `PostgrestClient` 之类的名字\n * (泄漏后消费方会写出依赖第三方命名的代码,之后换不掉)。裸抛就等于把\n * 整个 vendor 类型面暴露到公开 d.ts。\n * 2. 入口失控。vendor 的 `.schema()` 能切到任意 schema,但数据面只放行 public\n * (网关 `provider/tcb/data.go` 的 deniedSchemas 会拒 auth、pg_ 前缀、information_schema)。\n * 裸抛会让应用写出「类型上成立、运行期必被网关拒」的代码。\n *\n * 因此这里收一层**薄** facade:只转发 `from` / `rpc`(保留 vendor builder 的\n * 全部链式与 `{data,error}` 语义,体验对齐 supabase-js),去掉 `.schema()`,\n * 并以自己的泛型入口 `Database` 承接强类型(对齐 supabase 的 createClient<DB>)。\n *\n * 这里**没有自研请求层**,底座仍是 `src/vendor/postgrest`。原因:\n * - 官方 `@cloudbase/js-sdk` 用不了 —— `getBaseEndPoint` 会把配置值截取到 host,\n * 我们的 `/.cloud/database/rest` 前缀被丢弃(`runtime-auth-design.md` §4.1)。\n * - vendor 的客户端只把 base URL 当字符串保存,路径原样保留,正是所需行为。\n * ============================================================================\n */\n\nimport { CLOUD_MODULE_PATHS } from '../paths.js';\nimport type { CloudRuntimeConfig } from '../types.js';\nimport { PostgrestClient } from '../vendor/postgrest/index.js';\n\n/**\n * WorkBuddy 数据库模块。PostgREST 语义、`{ data, error }` 信封,\n * 查询构造器与 supabase-js 的 `.from()` 完全一致。\n *\n * 泛型 `Database` 承接 [类型生成器](https://supabase.com/docs/guides/api/rest/generating-types)\n * 产出的 schema 类型,用法与 supabase 的 `createClient<Database>()` 一致;\n * 不传时退化为无类型(`any` Row),运行期行为不变。\n */\nexport class WorkBuddyDatabaseModule<Database = unknown> {\n /**\n * 底层 PostgREST 客户端。刻意保持 private —— 对外只暴露 `from` / `rpc`,\n * 不让 vendor 客户端(及其 `.schema()` 等入口)泄漏到应用。\n */\n private readonly client: PostgrestClient<Database>;\n\n constructor(config: CloudRuntimeConfig, fetch: typeof globalThis.fetch) {\n // 身份由 `fetch` 携带(publishableKey + 自签 session),所以这里不传 headers ——\n // 避免出现第二处鉴权注入点。\n this.client = new PostgrestClient<Database>(\n `${config.endpoint}${CLOUD_MODULE_PATHS.database}`,\n { fetch },\n );\n\n // 直接把 vendor 的方法引用绑定过来,保留其全部重载与泛型签名\n // (用 Parameters/ReturnType 包一层会塌掉重载、弱化类型)。\n // 这是「薄 facade」:只搬 from / rpc 两个入口,不搬 .schema() 等。\n this.from = this.client.from.bind(this.client);\n this.rpc = this.client.rpc.bind(this.client);\n }\n\n /**\n * 在一张表或视图上发起查询。返回值即 supabase-js 的查询构造器,\n * 支持 `select/insert/upsert/update/delete` 及全部 filter/transform 链,\n * `await` 得到 `{ data, error }`。语义与 supabase-js `.from()` 一致。\n *\n * 只放行 public schema —— 不提供 `.schema()` 切换(数据面会拒系统 schema)。\n */\n readonly from: PostgrestClient<Database>['from'];\n\n /**\n * 调用一个 PostgreSQL 函数(RPC)。语义同 supabase-js `.rpc()`:\n * 返回可继续 `.select()/.order()/.limit()` 的构造器(集合返回型函数)。\n */\n readonly rpc: PostgrestClient<Database>['rpc'];\n\n /**\n * 归一化后的数据面基址(`/.cloud/database/rest`,无尾斜杠)。\n * 仅用于诊断/契约测试;应用不应据此手拼请求。\n */\n get url(): string {\n return this.client.url;\n }\n}\n\n/**\n * 创建 Database 模块。\n */\nexport function createDatabaseModule<Database = unknown>(\n config: CloudRuntimeConfig,\n fetch: typeof globalThis.fetch,\n): WorkBuddyDatabaseModule<Database> {\n return new WorkBuddyDatabaseModule<Database>(config, fetch);\n}\n","/**\n * CloudOpenAIError — OpenAI-style error for the LLM module (#89098).\n *\n * Shape follows the OpenAI error object:\n * { error: { message, type, param?, code? } }\n * Plus Genie BaaS extensions: status?, requestId?, retryAfterMs?.\n *\n * Uses the formal package's existing error philosophy: a single typed error\n * class for LLM operations (consistent with how `CloudError` serves the other\n * three modules), while remaining OpenAI-compatible for ergonomic consumption.\n */\n\nexport interface OpenAIErrorObject {\n message: string;\n type: string;\n param: string | null;\n code: string | null;\n}\n\nexport interface CloudOpenAIErrorInit {\n /** HTTP response status code (undefined for in-stream errors). */\n status?: number;\n /** Server X-Request-Id header. */\n requestId?: string;\n /** Parsed Retry-After header in milliseconds. */\n retryAfterMs?: number;\n /** Underlying cause (e.g. original TypeError from fetch). */\n cause?: unknown;\n}\n\n/**\n * Error thrown by all LLM module operations.\n *\n * Both non-2xx HTTP responses and in-stream `event: error` events produce\n * this error. The `error` field always follows the OpenAI error object shape.\n */\nexport class CloudOpenAIError extends Error {\n readonly error: OpenAIErrorObject;\n readonly status?: number;\n readonly requestId?: string;\n readonly retryAfterMs?: number;\n\n constructor(\n error: OpenAIErrorObject | string,\n init: CloudOpenAIErrorInit = {},\n ) {\n const errorObj: OpenAIErrorObject =\n typeof error === 'string'\n ? { message: error, type: 'server_error', param: null, code: null }\n : error;\n super(errorObj.message);\n this.name = 'CloudOpenAIError';\n this.error = errorObj;\n this.status = init.status;\n this.requestId = init.requestId;\n this.retryAfterMs = init.retryAfterMs;\n if (init.cause !== undefined) {\n if (!('cause' in this)) {\n Object.defineProperty(this, 'cause', {\n value: init.cause,\n writable: false,\n enumerable: false,\n configurable: false,\n });\n }\n }\n }\n}\n\n/**\n * Parse Retry-After header value into milliseconds.\n *\n * Supports:\n * - Integer seconds: \"120\"\n * - HTTP-date: \"Wed, 21 Oct 2026 07:28:00 GMT\"\n * Returns undefined if the header is absent or unparseable.\n */\nexport function parseRetryAfter(headerValue: string | null): number | undefined {\n if (!headerValue) return undefined;\n\n const trimmed = headerValue.trim();\n\n // Try integer seconds (most common)\n const asNum = Number(trimmed);\n if (!isNaN(asNum) && asNum >= 0 && Number.isInteger(asNum)) {\n return asNum * 1000;\n }\n\n // Try HTTP-date\n const asDate = Date.parse(trimmed);\n if (!isNaN(asDate)) {\n const diff = asDate - Date.now();\n return diff > 0 ? diff : 0;\n }\n\n return undefined;\n}\n","/**\n * LLM Models — GET /.cloud/llm/models (#89098)\n *\n * Fetches GenieBaas's browser-safe public model directory. The service has\n * already applied the application owner's model policy; this module preserves\n * its explicit public fields without exposing provider routing or credentials.\n *\n * Uses the shared fetch injected by `WorkBuddyCloudClient` — never constructs\n * its own fetch or adds Authorization/ModelHub headers.\n */\n\nimport { CloudOpenAIError, parseRetryAfter } from './errors.js';\nimport type {\n PublicLLMModel,\n PublicModelCapabilities,\n PublicModelModalities,\n PublicModelPricing,\n} from './types.js';\n\n/**\n * Raw public model object returned by GenieBaas.\n *\n * camelCase is the current data-plane contract. PascalCase aliases remain only\n * for a rolling upgrade where an older AgentServer may still return Go default\n * JSON field names. Unknown fields are deliberately not surfaced by the SDK.\n */\nexport interface RawLLMModel {\n ID?: string;\n id?: string;\n Name?: string;\n name?: string;\n Provider?: string;\n provider?: string;\n Vendor?: string;\n vendor?: string;\n Family?: string;\n family?: string;\n Version?: string;\n version?: string;\n Description?: string;\n description?: string;\n DescriptionZh?: string;\n descriptionZh?: string;\n DescriptionEn?: string;\n descriptionEn?: string;\n IconURL?: string;\n iconUrl?: string;\n ContextWindow?: number;\n contextWindow?: number;\n MaxInputTokens?: number;\n maxInputTokens?: number;\n MaxOutputTokens?: number;\n maxOutputTokens?: number;\n Modalities?: PublicModelModalities;\n modalities?: PublicModelModalities;\n Capabilities?: PublicModelCapabilities;\n capabilities?: PublicModelCapabilities;\n Enabled?: boolean;\n enabled?: boolean;\n IsDefault?: boolean;\n isDefault?: boolean;\n SortOrder?: number;\n sortOrder?: number;\n Pricing?: PublicModelPricing;\n pricing?: PublicModelPricing;\n}\n\nfunction stringField(...values: unknown[]): string | undefined {\n return values.find((value): value is string => typeof value === 'string' && value.length > 0);\n}\n\nfunction numberField(...values: unknown[]): number | undefined {\n return values.find((value): value is number => typeof value === 'number' && Number.isFinite(value));\n}\n\nfunction booleanField(...values: unknown[]): boolean | undefined {\n return values.find((value): value is boolean => typeof value === 'boolean');\n}\n\nfunction modalitiesField(value: unknown): PublicModelModalities | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const raw = value as PublicModelModalities;\n const input = Array.isArray(raw.input) ? raw.input.filter((item): item is string => typeof item === 'string') : undefined;\n const output = Array.isArray(raw.output) ? raw.output.filter((item): item is string => typeof item === 'string') : undefined;\n return input?.length || output?.length ? { ...(input?.length ? { input } : {}), ...(output?.length ? { output } : {}) } : undefined;\n}\n\nfunction capabilitiesField(value: unknown): PublicModelCapabilities | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const raw = value as PublicModelCapabilities;\n const entries = Object.entries(raw).filter(([, enabled]) => typeof enabled === 'boolean');\n return entries.length ? Object.fromEntries(entries) as PublicModelCapabilities : undefined;\n}\n\nfunction pricingField(value: unknown): PublicModelPricing | undefined {\n if (!value || typeof value !== 'object') return undefined;\n const raw = value as PublicModelPricing;\n const pricing: PublicModelPricing = {\n ...(stringField(raw.currency) ? { currency: raw.currency } : {}),\n ...(numberField(raw.inputPerMillionTokens) !== undefined ? { inputPerMillionTokens: raw.inputPerMillionTokens } : {}),\n ...(numberField(raw.outputPerMillionTokens) !== undefined ? { outputPerMillionTokens: raw.outputPerMillionTokens } : {}),\n ...(stringField(raw.displayText) ? { displayText: raw.displayText } : {}),\n };\n return Object.keys(pricing).length ? pricing : undefined;\n}\n\n/**\n * Normalize a raw public server model to the SDK's public directory type.\n *\n * Missing optional fields remain absent. The SDK deliberately keeps\n * `enabled: false` entries so a UI can render a disabled state without\n * inventing policy; callers must never treat omitted capabilities as false.\n */\nexport function normalizeModel(raw: RawLLMModel): PublicLLMModel | null {\n const id = stringField(raw.id, raw.ID);\n if (!id) return null;\n\n return {\n id,\n name: stringField(raw.name, raw.Name) ?? id,\n ...(stringField(raw.provider, raw.Provider) ? { provider: stringField(raw.provider, raw.Provider) } : {}),\n ...(stringField(raw.vendor, raw.Vendor) ? { vendor: stringField(raw.vendor, raw.Vendor) } : {}),\n ...(stringField(raw.family, raw.Family) ? { family: stringField(raw.family, raw.Family) } : {}),\n ...(stringField(raw.version, raw.Version) ? { version: stringField(raw.version, raw.Version) } : {}),\n ...(stringField(raw.description, raw.Description) ? { description: stringField(raw.description, raw.Description) } : {}),\n ...(stringField(raw.descriptionZh, raw.DescriptionZh) ? { descriptionZh: stringField(raw.descriptionZh, raw.DescriptionZh) } : {}),\n ...(stringField(raw.descriptionEn, raw.DescriptionEn) ? { descriptionEn: stringField(raw.descriptionEn, raw.DescriptionEn) } : {}),\n ...(stringField(raw.iconUrl, raw.IconURL) ? { iconUrl: stringField(raw.iconUrl, raw.IconURL) } : {}),\n ...(numberField(raw.contextWindow, raw.ContextWindow) !== undefined ? { contextWindow: numberField(raw.contextWindow, raw.ContextWindow) } : {}),\n ...(numberField(raw.maxInputTokens, raw.MaxInputTokens) !== undefined ? { maxInputTokens: numberField(raw.maxInputTokens, raw.MaxInputTokens) } : {}),\n ...(numberField(raw.maxOutputTokens, raw.MaxOutputTokens) !== undefined ? { maxOutputTokens: numberField(raw.maxOutputTokens, raw.MaxOutputTokens) } : {}),\n ...(modalitiesField(raw.modalities ?? raw.Modalities) ? { modalities: modalitiesField(raw.modalities ?? raw.Modalities) } : {}),\n ...(capabilitiesField(raw.capabilities ?? raw.Capabilities) ? { capabilities: capabilitiesField(raw.capabilities ?? raw.Capabilities) } : {}),\n enabled: booleanField(raw.enabled, raw.Enabled) ?? true,\n ...(booleanField(raw.isDefault, raw.IsDefault) !== undefined ? { isDefault: booleanField(raw.isDefault, raw.IsDefault) } : {}),\n ...(numberField(raw.sortOrder, raw.SortOrder) !== undefined ? { sortOrder: numberField(raw.sortOrder, raw.SortOrder) } : {}),\n ...(pricingField(raw.pricing ?? raw.Pricing) ? { pricing: pricingField(raw.pricing ?? raw.Pricing) } : {}),\n };\n}\n\n/** LLM models namespace. */\nexport class ModelsAPI {\n constructor(\n private readonly baseUrl: string,\n private readonly fetch: typeof globalThis.fetch,\n ) {}\n\n /**\n * List the browser-safe public model directory for this application.\n *\n * `id` is the value to pass as `model` to `chat.completions.create()`.\n * Optional metadata is included only when the server explicitly provides\n * it; absence means unknown, not unsupported. The server remains the\n * final allowlist authority for chat requests.\n */\n async list(signal?: AbortSignal): Promise<PublicLLMModel[]> {\n let response: Response;\n try {\n response = await this.fetch(`${this.baseUrl}/models`, {\n method: 'GET',\n headers: { Accept: 'application/json' },\n signal,\n });\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw err;\n }\n throw new CloudOpenAIError(\n {\n message: `Network error: ${(err as Error)?.message ?? 'unknown'}`,\n type: 'server_error',\n param: null,\n code: 'gateway_network_error',\n },\n { cause: err },\n );\n }\n\n if (!response.ok) {\n throw await httpError(response);\n }\n\n const text = await response.text();\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n throw new CloudOpenAIError({\n message: 'Failed to parse models response: invalid JSON',\n type: 'server_error',\n param: null,\n code: 'gateway_invalid_response',\n });\n }\n\n // Current data-plane contract is a bare array. Accepting { data: [] }\n // preserves compatibility with older deployments without changing the\n // public SDK result type.\n const rawModels: RawLLMModel[] = Array.isArray(parsed)\n ? (parsed as RawLLMModel[])\n : Array.isArray((parsed as { data?: unknown[] })?.data)\n ? ((parsed as { data: RawLLMModel[] }).data)\n : [];\n\n const models: PublicLLMModel[] = [];\n for (const raw of rawModels) {\n const normalized = normalizeModel(raw);\n if (normalized) models.push(normalized);\n }\n return models;\n }\n}\n\n/**\n * Build a CloudOpenAIError from a non-2xx HTTP response.\n *\n * Extracts the OpenAI error object from the response body if present,\n * otherwise synthesizes a fallback from the HTTP status.\n */\nexport async function httpError(response: Response): Promise<CloudOpenAIError> {\n const text = await response.text().catch(() => '');\n let errorObj: import('./errors.js').OpenAIErrorObject;\n\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === 'object' && parsed.error) {\n const e = parsed.error;\n errorObj = {\n message: typeof e.message === 'string' ? e.message : `HTTP ${response.status}`,\n type: typeof e.type === 'string' ? e.type : 'server_error',\n param: e.param === undefined ? null : e.param,\n code: e.code === undefined ? null : e.code,\n };\n } else {\n errorObj = {\n message: typeof parsed === 'string' ? parsed : `HTTP ${response.status}`,\n type: 'server_error',\n param: null,\n code: null,\n };\n }\n } catch {\n errorObj = {\n message: text || `HTTP ${response.status}`,\n type: 'server_error',\n param: null,\n code: null,\n };\n }\n\n const requestId = response.headers.get('x-request-id') ?? undefined;\n const retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));\n\n return new CloudOpenAIError(errorObj, {\n status: response.status,\n requestId,\n retryAfterMs,\n });\n}\n","/**\n * Minimal SSE (Server-Sent Events) parser for LLM Chat Completions streaming (#89098).\n *\n * Self-implemented to avoid pulling in the `openai` runtime package or any\n * Node-specific API. Uses only Web-standard `ReadableStream` + `TextDecoder`.\n *\n * Handles:\n * - Standard SSE `data:` / `event:` fields\n * - Multi-line `data:` fields (joined with \\n per SSE spec)\n * - UTF-8 cross-chunk boundary (via TextDecoder with stream=true)\n * - `[DONE]` sentinel\n * - `event: error` dispatch\n * - CRLF and LF line endings\n * - AbortSignal — cancels the stream reader cleanly\n */\n\nexport interface SSEEvent {\n /** The event type (null for default/unspecified events). */\n event: string | null;\n /** The data payload (multiple `data:` lines joined with \\n). */\n data: string;\n}\n\n/**\n * SSEDecoder processes complete SSE lines and assembles them into events.\n *\n * An SSE event is terminated by an empty line (double newline).\n * Lines starting with `:` are comments and are ignored.\n */\nclass SSEDecoder {\n private event: string | null = null;\n private dataParts: string[] = [];\n\n /**\n * Feed a single line. Returns an SSEEvent when the current event is\n * terminated (i.e. when an empty line is received), or null otherwise.\n */\n decode(line: string): SSEEvent | null {\n // Strip trailing \\r for CRLF compatibility\n let l = line;\n if (l.endsWith('\\r')) {\n l = l.slice(0, -1);\n }\n\n // Empty line = event terminator\n if (l === '') {\n if (this.event === null && this.dataParts.length === 0) {\n return null;\n }\n const ev: SSEEvent = {\n event: this.event,\n data: this.dataParts.join('\\n'),\n };\n this.event = null;\n this.dataParts = [];\n return ev;\n }\n\n // Comment line (starts with ':')\n if (l.startsWith(':')) {\n return null;\n }\n\n // Parse field: value\n const colonIdx = l.indexOf(':');\n let field: string;\n let value: string;\n if (colonIdx === -1) {\n field = l;\n value = '';\n } else {\n field = l.slice(0, colonIdx);\n // Per SSE spec, a single leading space after the colon is removed\n let rest = l.slice(colonIdx + 1);\n if (rest.startsWith(' ')) {\n rest = rest.slice(1);\n }\n value = rest;\n }\n\n if (field === 'event') {\n this.event = value;\n } else if (field === 'data') {\n this.dataParts.push(value);\n }\n // Ignore id/retry fields — not needed for this SDK\n\n return null;\n }\n\n /** Flush any remaining buffered data as a final event. */\n flush(): SSEEvent | null {\n if (this.event === null && this.dataParts.length === 0) {\n return null;\n }\n const ev: SSEEvent = {\n event: this.event,\n data: this.dataParts.join('\\n'),\n };\n this.event = null;\n this.dataParts = [];\n return ev;\n }\n}\n\n/**\n * LineDecoder splits a byte stream into individual lines (by \\n or \\r\\n).\n *\n * Operates on Uint8Array to correctly handle UTF-8 multi-byte characters\n * that may be split across chunks. Uses TextDecoder with stream=true\n * for incremental decoding.\n */\nclass LineDecoder {\n private buffer: Uint8Array = new Uint8Array();\n private decoder: TextDecoder;\n\n constructor() {\n // stream=true keeps incomplete multi-byte sequences buffered internally\n this.decoder = new TextDecoder('utf-8');\n }\n\n /**\n * Decode a chunk and yield complete lines.\n *\n * Lines are terminated by \\n, \\r, or \\r\\n. The line terminators are\n * NOT included in the returned strings.\n */\n decode(chunk: Uint8Array): string[] {\n // Append to buffer\n const newData = new Uint8Array(this.buffer.length + chunk.length);\n newData.set(this.buffer);\n newData.set(chunk, this.buffer.length);\n this.buffer = newData;\n\n const lines: string[] = [];\n let start = 0;\n\n for (let i = 0; i < this.buffer.length; i++) {\n if (this.buffer[i] === 0x0a /* \\n */ || this.buffer[i] === 0x0d /* \\r */) {\n // Decode the line (excluding the terminator)\n const lineBytes = this.buffer.subarray(start, i);\n const line = this.decoder.decode(lineBytes, { stream: true });\n lines.push(line);\n\n // Handle \\r\\n: skip the \\n\n if (this.buffer[i] === 0x0d && i + 1 < this.buffer.length && this.buffer[i + 1] === 0x0a) {\n i++;\n }\n start = i + 1;\n }\n }\n\n // Keep the remainder in buffer\n if (start > 0) {\n this.buffer = this.buffer.slice(start);\n }\n\n return lines;\n }\n\n /**\n * Flush remaining buffered data. Returns a final line if any data remains\n * (without a trailing newline). The TextDecoder is also flushed.\n */\n flush(): string[] {\n if (this.buffer.length === 0) {\n // Flush any remaining bytes in the TextDecoder\n const remaining = this.decoder.decode();\n return remaining ? [remaining] : [];\n }\n const line = this.decoder.decode(this.buffer, { stream: false });\n this.buffer = new Uint8Array();\n return line ? [line] : [];\n }\n}\n\n/** Sentinel value indicating end of stream. */\nexport const SSE_DONE = '[DONE]';\n\n/**\n * Async generator that yields SSE events from a ReadableStream<Uint8Array>.\n *\n * This is the core streaming primitive: it takes a raw response body\n * and yields parsed SSEEvent objects one at a time.\n *\n * When an AbortSignal is provided and fires, the stream is cancelled\n * (which causes the pending reader.read() to reject), allowing the\n * generator to exit cleanly.\n */\nexport async function* iterSSEEvents(\n body: ReadableStream<Uint8Array>,\n signal?: AbortSignal,\n): AsyncGenerator<SSEEvent, void, unknown> {\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const reader = body.getReader();\n\n // When the abort signal fires, cancel the stream to unblock reader.read()\n let aborted = false;\n const onAbort = () => {\n aborted = true;\n reader.cancel().catch(() => {});\n };\n\n if (signal) {\n if (signal.aborted) {\n return;\n }\n signal.addEventListener('abort', onAbort, { once: true });\n }\n\n try {\n while (true) {\n if (aborted) {\n return;\n }\n\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await reader.read();\n } catch (err) {\n // reader.read() rejects when the stream is cancelled (abort)\n if (aborted || (err instanceof Error && err.name === 'AbortError')) {\n return;\n }\n throw err;\n }\n\n const { done, value } = result;\n if (done) break;\n\n for (const line of lineDecoder.decode(value)) {\n const ev = sseDecoder.decode(line);\n if (ev) yield ev;\n }\n }\n\n // Flush remaining data\n for (const line of lineDecoder.flush()) {\n const ev = sseDecoder.decode(line);\n if (ev) yield ev;\n }\n const finalEv = sseDecoder.flush();\n if (finalEv) yield finalEv;\n } finally {\n if (signal) {\n signal.removeEventListener('abort', onAbort);\n }\n try {\n reader.releaseLock();\n } catch {\n // already released or stream errored\n }\n }\n}\n","/**\n * LLM Chat Completions — POST /.cloud/llm/chat/completions (#89098)\n *\n * Supports both streaming (SSE) and non-streaming (JSON) modes.\n *\n * Uses the shared fetch injected by `WorkBuddyCloudClient` — never\n * constructs its own fetch or adds Authorization/ModelHub headers.\n */\n\nimport { CloudOpenAIError } from './errors.js';\nimport { httpError } from './models.js';\nimport { iterSSEEvents, SSE_DONE } from './sse.js';\nimport type {\n ChatCompletion,\n ChatCompletionChunk,\n ChatCompletionCreateParamsNonStreaming,\n ChatCompletionCreateParamsStreaming,\n} from './types.js';\n\n/**\n * Extract error from an SSE `event: error` data payload.\n *\n * The server sends:\n * event: error\n * data: { \"error\": { \"message\": \"...\", \"type\": \"...\", \"param\": null, \"code\": \"...\" } }\n */\nfunction extractSSEError(data: string): CloudOpenAIError {\n try {\n const parsed = JSON.parse(data);\n if (parsed && typeof parsed === 'object') {\n const errorObj = parsed.error ?? parsed;\n if (errorObj && typeof errorObj === 'object') {\n return new CloudOpenAIError({\n message: typeof errorObj.message === 'string' ? errorObj.message : 'Stream error',\n type: typeof errorObj.type === 'string' ? errorObj.type : 'server_error',\n param: errorObj.param === undefined ? null : errorObj.param,\n code: errorObj.code === undefined ? null : errorObj.code,\n });\n }\n }\n } catch {\n // Not JSON\n }\n return new CloudOpenAIError({\n message: data || 'Stream error',\n type: 'server_error',\n param: null,\n code: null,\n });\n}\n\n/** LLM chat completions namespace. */\nexport class ChatCompletionsAPI {\n constructor(\n private readonly baseUrl: string,\n private readonly fetch: typeof globalThis.fetch,\n ) {}\n\n /**\n * Create a chat completion.\n *\n * When `input.stream === true`, returns an async iterable of\n * ChatCompletionChunk objects. When `input.stream` is false or\n * omitted, returns a ChatCompletion.\n */\n create(input: ChatCompletionCreateParamsStreaming): AsyncIterable<ChatCompletionChunk>;\n create(input: ChatCompletionCreateParamsNonStreaming): Promise<ChatCompletion>;\n create(\n input: ChatCompletionCreateParamsStreaming | ChatCompletionCreateParamsNonStreaming,\n ): AsyncIterable<ChatCompletionChunk> | Promise<ChatCompletion> {\n if (input.stream === true) {\n return this.createStreaming(input);\n }\n return this.createNonStreaming(input);\n }\n\n /**\n * Non-streaming chat completion.\n */\n private async createNonStreaming(\n input: ChatCompletionCreateParamsNonStreaming,\n ): Promise<ChatCompletion> {\n // Reject stream_options with stream=false per API spec\n if (input.stream_options) {\n throw new CloudOpenAIError({\n message: 'stream_options can only be used with stream=true',\n type: 'invalid_request_error',\n param: 'stream_options',\n code: 'request_invalid_parameter',\n });\n }\n\n // Separate SDK-internal fields from the request body\n const { signal, ...body } = input;\n // stream defaults to false; don't send it if undefined\n if (body.stream === undefined) {\n delete body.stream;\n } else {\n body.stream = false;\n }\n\n let response: Response;\n try {\n response = await this.fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n });\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw err;\n }\n throw new CloudOpenAIError(\n {\n message: `Network error: ${(err as Error)?.message ?? 'unknown'}`,\n type: 'server_error',\n param: null,\n code: 'gateway_network_error',\n },\n { cause: err },\n );\n }\n\n if (!response.ok) {\n throw await httpError(response);\n }\n\n const text = await response.text();\n try {\n return JSON.parse(text) as ChatCompletion;\n } catch {\n throw new CloudOpenAIError({\n message: 'Failed to parse chat completion response: invalid JSON',\n type: 'server_error',\n param: null,\n code: 'gateway_invalid_response',\n });\n }\n }\n\n /**\n * Streaming chat completion — returns an async generator of chunks.\n *\n * Reads the SSE stream incrementally, yielding ChatCompletionChunk objects.\n * Throws CloudOpenAIError on:\n * - `event: error` in the stream\n * - Stream ends without `[DONE]` (gateway_stream_interrupted)\n * - JSON parse errors in data frames\n * - Caller abort (AbortSignal) — exits silently, no throw\n */\n private async *createStreaming(\n input: ChatCompletionCreateParamsStreaming,\n ): AsyncGenerator<ChatCompletionChunk, void, unknown> {\n const { signal, ...body } = input;\n body.stream = true;\n\n let response: Response;\n try {\n response = await this.fetch(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: {\n Accept: 'text/event-stream',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n });\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n return;\n }\n throw new CloudOpenAIError(\n {\n message: `Network error: ${(err as Error)?.message ?? 'unknown'}`,\n type: 'server_error',\n param: null,\n code: 'gateway_network_error',\n },\n { cause: err },\n );\n }\n\n // Non-2xx on a streaming request still returns a body — convert to error.\n if (!response.ok) {\n throw await httpError(response);\n }\n\n if (!response.body) {\n throw new CloudOpenAIError({\n message: 'Response body is empty — streaming not supported',\n type: 'server_error',\n param: null,\n code: 'gateway_invalid_response',\n });\n }\n\n let receivedDone = false;\n let threw = false;\n\n try {\n for await (const sseEvent of iterSSEEvents(response.body, signal)) {\n // Check for named error event\n if (sseEvent.event === 'error') {\n threw = true;\n throw extractSSEError(sseEvent.data);\n }\n\n // Default event: data frame\n if (sseEvent.event === null || sseEvent.event === '') {\n if (sseEvent.data === SSE_DONE) {\n receivedDone = true;\n return;\n }\n\n if (!sseEvent.data) {\n // Empty data frame, skip\n continue;\n }\n\n let chunk: ChatCompletionChunk;\n try {\n chunk = JSON.parse(sseEvent.data) as ChatCompletionChunk;\n } catch {\n threw = true;\n throw new CloudOpenAIError({\n message: `Failed to parse SSE data: ${sseEvent.data}`,\n type: 'server_error',\n param: null,\n code: 'gateway_invalid_response',\n });\n }\n\n // Check for error embedded in the chunk (some servers do this)\n if (chunk && typeof chunk === 'object' && 'error' in chunk) {\n threw = true;\n const errObj = (chunk as unknown as { error: Record<string, unknown> }).error;\n throw new CloudOpenAIError({\n message: typeof errObj?.message === 'string' ? errObj.message : 'Stream error',\n type: typeof errObj?.type === 'string' ? errObj.type : 'server_error',\n param: errObj?.param === undefined ? null : (errObj.param as string | null),\n code: errObj?.code === undefined ? null : (errObj.code as string | null),\n });\n }\n\n yield chunk;\n }\n }\n } catch (err) {\n // AbortError: caller cancelled, exit silently\n if (err instanceof Error && err.name === 'AbortError') {\n return;\n }\n threw = true;\n throw err;\n }\n\n // Stream ended normally (reader returned done) but without [DONE].\n if (!receivedDone && !threw && !signal?.aborted) {\n throw new CloudOpenAIError({\n message: '流式响应中断。',\n type: 'server_error',\n param: null,\n code: 'gateway_stream_interrupted',\n });\n }\n }\n}\n","/**\n * LLM 模块入口(#89098)\n *\n * 数据面 `/.cloud/llm`:\n * GET /.cloud/llm/models\n * POST /.cloud/llm/chat/completions\n *\n * 凭据换手在服务端完成 —— 终端用户 session 绝不透传给 ModelHub,SDK 侧不感知。\n * LLM 模块**不得**自行配置 ModelHub/token,只使用 client 传入的 shared fetch。\n *\n * 公开 API:\n * cloud.llm.models.list()\n * cloud.llm.chat.completions.create()\n *\n * 流式响应走 SSE(`text/event-stream`),分块解析由 `./llm/sse.ts` 处理。\n */\n\nimport { CLOUD_MODULE_PATHS } from '../paths.js';\nimport type { CloudRuntimeConfig } from '../types.js';\nimport { ChatCompletionsAPI } from './llm/chat.js';\nimport { ModelsAPI } from './llm/models.js';\n\nexport class LlmModule {\n /** 该模块的数据面基址。 */\n readonly baseUrl: string;\n\n /** Models namespace。 */\n readonly models: ModelsAPI;\n\n /** Chat namespace。 */\n readonly chat: {\n completions: ChatCompletionsAPI;\n };\n\n constructor(\n config: CloudRuntimeConfig,\n private readonly fetch: typeof globalThis.fetch,\n ) {\n this.baseUrl = `${config.endpoint}${CLOUD_MODULE_PATHS.llm}`;\n this.models = new ModelsAPI(this.baseUrl, this.fetch);\n this.chat = {\n completions: new ChatCompletionsAPI(this.baseUrl, this.fetch),\n };\n }\n}\n\n// Re-export public types for ergonomic consumption from the module entry.\nexport type {\n ChatCompletion,\n ChatCompletionChunk,\n ChatCompletionChoice,\n ChatCompletionChunkChoice,\n ChatCompletionCreateParams,\n ChatCompletionCreateParamsStreaming,\n ChatCompletionCreateParamsNonStreaming,\n CompletionUsage,\n ChatCompletionMessage,\n ChatCompletionRequestMessage,\n ChatCompletionAssistantMessage,\n ChatCompletionTool,\n ChatCompletionToolChoice,\n ChatCompletionResponseFormat,\n ChatCompletionContentPart,\n ChatCompletionRole,\n PublicLLMModel,\n PublicModelCapabilities,\n PublicModelModalities,\n PublicModelPricing,\n} from './llm/types.js';\nexport { CloudOpenAIError } from './llm/errors.js';\nexport type { OpenAIErrorObject, CloudOpenAIErrorInit } from './llm/errors.js';\n","/**\n * Namespace type for error classes\n * Determines the error class names and type guards\n */\nexport type ErrorNamespace = 'storage' | 'vectors'\n\n/**\n * Base error class for all Storage errors\n * Supports both 'storage' and 'vectors' namespaces\n */\nexport class StorageError extends Error {\n protected __isStorageError = true\n protected namespace: ErrorNamespace\n status: number | undefined\n statusCode: string | undefined\n\n constructor(\n message: string,\n namespace: ErrorNamespace = 'storage',\n status?: number,\n statusCode?: string\n ) {\n super(message)\n this.namespace = namespace\n this.name = namespace === 'vectors' ? 'StorageVectorsError' : 'StorageError'\n this.status = status\n this.statusCode = statusCode\n }\n\n toJSON(): {\n name: string\n message: string\n status: number | undefined\n statusCode: string | undefined\n } {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n statusCode: this.statusCode,\n }\n }\n}\n\n/**\n * Type guard to check if an error is a StorageError\n * @param error - The error to check\n * @returns True if the error is a StorageError\n */\nexport function isStorageError(error: unknown): error is StorageError {\n return typeof error === 'object' && error !== null && '__isStorageError' in error\n}\n\n/**\n * API error returned from Storage service\n * Includes HTTP status code and service-specific error code\n */\nexport class StorageApiError extends StorageError {\n override status: number\n override statusCode: string\n /**\n * Service-specific error code from the Storage API response body, such as\n * `NoSuchKey`, `AccessDenied` or `ResourceAlreadyExists`. Use this to branch\n * on the specific error rather than parsing the message.\n * @see https://supabase.com/docs/guides/storage/debugging/error-codes\n */\n code: string | undefined\n\n constructor(\n message: string,\n status: number,\n statusCode: string,\n namespace: ErrorNamespace = 'storage',\n code?: string\n ) {\n super(message, namespace, status, statusCode)\n this.name = namespace === 'vectors' ? 'StorageVectorsApiError' : 'StorageApiError'\n this.status = status\n this.statusCode = statusCode\n this.code = code\n }\n\n toJSON(): {\n name: string\n message: string\n status: number | undefined\n statusCode: string | undefined\n code: string | undefined\n } {\n return {\n ...super.toJSON(),\n code: this.code,\n }\n }\n}\n\n/**\n * Unknown error that doesn't match expected error patterns\n * Wraps the original error for debugging\n */\nexport class StorageUnknownError extends StorageError {\n originalError: unknown\n\n constructor(message: string, originalError: unknown, namespace: ErrorNamespace = 'storage') {\n super(message, namespace)\n this.name = namespace === 'vectors' ? 'StorageVectorsUnknownError' : 'StorageUnknownError'\n this.originalError = originalError\n }\n}\n\n// ============================================================================\n// Backward Compatibility Exports for Vectors\n// ============================================================================\n\n/**\n * @deprecated Use StorageError with namespace='vectors' instead\n * Alias for backward compatibility with existing vector storage code\n */\nexport class StorageVectorsError extends StorageError {\n constructor(message: string) {\n super(message, 'vectors')\n }\n}\n\n/**\n * Type guard to check if an error is a StorageVectorsError\n * @param error - The error to check\n * @returns True if the error is a StorageVectorsError\n */\nexport function isStorageVectorsError(error: unknown): error is StorageVectorsError {\n return isStorageError(error) && (error as StorageError)['namespace'] === 'vectors'\n}\n\n/**\n * @deprecated Use StorageApiError with namespace='vectors' instead\n * Alias for backward compatibility with existing vector storage code\n */\nexport class StorageVectorsApiError extends StorageApiError {\n constructor(message: string, status: number, statusCode: string) {\n super(message, status, statusCode, 'vectors')\n }\n}\n\n/**\n * @deprecated Use StorageUnknownError with namespace='vectors' instead\n * Alias for backward compatibility with existing vector storage code\n */\nexport class StorageVectorsUnknownError extends StorageUnknownError {\n constructor(message: string, originalError: unknown) {\n super(message, originalError, 'vectors')\n }\n}\n\n/**\n * Error codes specific to S3 Vectors API\n * Maps AWS service errors to application-friendly error codes\n */\nexport enum StorageVectorsErrorCode {\n /** Internal server fault (HTTP 500) */\n InternalError = 'InternalError',\n /** Resource already exists / conflict (HTTP 409) */\n S3VectorConflictException = 'S3VectorConflictException',\n /** Resource not found (HTTP 404) */\n S3VectorNotFoundException = 'S3VectorNotFoundException',\n /** Delete bucket while not empty (HTTP 400) */\n S3VectorBucketNotEmpty = 'S3VectorBucketNotEmpty',\n /** Exceeds bucket quota/limit (HTTP 400) */\n S3VectorMaxBucketsExceeded = 'S3VectorMaxBucketsExceeded',\n /** Exceeds index quota/limit (HTTP 400) */\n S3VectorMaxIndexesExceeded = 'S3VectorMaxIndexesExceeded',\n}\n","/**\n * Sets a header with case-insensitive deduplication.\n * Removes any existing headers whose name matches (case-insensitive),\n * then sets the value under the lowercase key. Does not mutate the input object.\n *\n * @param headers - Existing headers object\n * @param name - Header name to set (stored as lowercase)\n * @param value - Header value\n * @returns New headers object with the header set\n */\nexport function setHeader(\n headers: Record<string, string>,\n name: string,\n value: string\n): Record<string, string> {\n const result = { ...headers }\n const nameLower = name.toLowerCase()\n\n for (const key of Object.keys(result)) {\n if (key.toLowerCase() === nameLower) {\n delete result[key]\n }\n }\n\n result[nameLower] = value\n return result\n}\n\n/**\n * Normalizes all header keys to lowercase with case-insensitive deduplication.\n * When duplicate keys exist (differing only in case), the last value wins.\n * Does not mutate the input object.\n *\n * @param headers - Headers object to normalize\n * @returns New headers object with all keys lowercased\n */\nexport function normalizeHeaders(headers: Record<string, string>): Record<string, string> {\n const result: Record<string, string> = {}\n for (const [key, value] of Object.entries(headers)) {\n result[key.toLowerCase()] = value\n }\n return result\n}\n","type Fetch = typeof fetch\n\n/**\n * Resolves the fetch implementation to use\n * Uses custom fetch if provided, otherwise uses native fetch\n *\n * @param customFetch - Optional custom fetch implementation\n * @returns Resolved fetch function\n */\nexport const resolveFetch = (customFetch?: Fetch): Fetch => {\n if (customFetch) {\n return (...args) => customFetch(...args)\n }\n return (...args) => fetch(...args)\n}\n\n/**\n * Resolves the Response constructor to use\n * Returns native Response constructor\n *\n * @returns Response constructor\n */\nexport const resolveResponse = (): typeof Response => {\n return Response\n}\n\n/**\n * Determine if input is a plain object\n * An object is plain if it's created by either {}, new Object(), or Object.create(null)\n *\n * @param value - Value to check\n * @returns True if value is a plain object\n * @source https://github.com/sindresorhus/is-plain-obj\n */\nexport const isPlainObject = (value: object): boolean => {\n if (typeof value !== 'object' || value === null) {\n return false\n }\n\n const prototype = Object.getPrototypeOf(value)\n return (\n (prototype === null ||\n prototype === Object.prototype ||\n Object.getPrototypeOf(prototype) === null) &&\n !(Symbol.toStringTag in value) &&\n !(Symbol.iterator in value)\n )\n}\n\n/**\n * Recursively converts object keys from snake_case to camelCase\n * Used for normalizing API responses\n *\n * @param item - Object to convert\n * @returns Converted object with camelCase keys\n */\nexport const recursiveToCamel = (item: Record<string, any>): unknown => {\n if (Array.isArray(item)) {\n return item.map((el) => recursiveToCamel(el))\n } else if (typeof item === 'function' || item !== Object(item)) {\n return item\n }\n\n const result: Record<string, any> = {}\n Object.entries(item).forEach(([key, value]) => {\n const newKey = key.replace(/([-_][a-z])/gi, (c) => c.toUpperCase().replace(/[-_]/g, ''))\n result[newKey] = recursiveToCamel(value)\n })\n\n return result\n}\n\n/**\n * Validates if a given bucket name is valid according to Supabase Storage API rules\n * Mirrors backend validation from: storage/src/storage/limits.ts:isValidBucketName()\n *\n * Rules:\n * - Length: 1-100 characters\n * - Allowed characters: alphanumeric (a-z, A-Z, 0-9), underscore (_), and safe special characters\n * - Safe special characters: ! - . * ' ( ) space & $ @ = ; : + , ?\n * - Forbidden: path separators (/, \\), path traversal (..), leading/trailing whitespace\n *\n * AWS S3 Reference: https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html\n *\n * @param bucketName - The bucket name to validate\n * @returns true if valid, false otherwise\n */\nexport const isValidBucketName = (bucketName: string): boolean => {\n if (!bucketName || typeof bucketName !== 'string') {\n return false\n }\n\n // Check length constraints (1-100 characters)\n if (bucketName.length === 0 || bucketName.length > 100) {\n return false\n }\n\n // Check for leading/trailing whitespace\n if (bucketName.trim() !== bucketName) {\n return false\n }\n\n // Explicitly reject path separators (security)\n // Note: Consecutive periods (..) are allowed by backend - the AWS restriction\n // on relative paths applies to object keys, not bucket names\n if (bucketName.includes('/') || bucketName.includes('\\\\')) {\n return false\n }\n\n // Validate against allowed character set\n // Pattern matches backend regex: /^(\\w|!|-|\\.|\\*|'|\\(|\\)| |&|\\$|@|=|;|:|\\+|,|\\?)*$/\n // This explicitly excludes path separators (/, \\) and other problematic characters\n const bucketNameRegex = /^[\\w!.\\*'() &$@=;:+,?-]+$/\n return bucketNameRegex.test(bucketName)\n}\n\n/**\n * Normalizes a number array to float32 format\n * Ensures all vector values are valid 32-bit floats\n *\n * @param values - Array of numbers to normalize\n * @returns Normalized float32 array\n */\nexport const normalizeToFloat32 = (values: number[]): number[] => {\n // Use Float32Array to ensure proper precision\n return Array.from(new Float32Array(values))\n}\n\n/**\n * Validates vector dimensions match expected dimension\n * Throws error if dimensions don't match\n *\n * @param vector - Vector data to validate\n * @param expectedDimension - Expected vector dimension\n * @throws Error if dimensions don't match\n */\nexport const validateVectorDimension = (\n vector: { float32: number[] },\n expectedDimension?: number\n): void => {\n if (expectedDimension !== undefined && vector.float32.length !== expectedDimension) {\n throw new Error(\n `Vector dimension mismatch: expected ${expectedDimension}, got ${vector.float32.length}`\n )\n }\n}\n\n/**\n * Percent-encodes each segment of a storage path so URL delimiters within a\n * key (e.g. `?`, `#`) can't be interpreted as a querystring/fragment start.\n *\n * Splits on `/` so real path separators stay literal — the storage server\n * routes on them and decodes each segment back to the original key.\n *\n * @param path - A bucket id or `bucketId/objectKey` path\n * @returns The path with each `/`-delimited segment percent-encoded\n */\nexport const encodeStoragePath = (path: string): string =>\n path.split('/').map(encodeURIComponent).join('/')\n","import { StorageApiError, StorageError, StorageUnknownError, ErrorNamespace } from './errors'\nimport { setHeader } from './headers'\nimport { isPlainObject, resolveResponse } from './helpers'\nimport { FetchParameters } from '../types'\n\nexport type Fetch = typeof fetch\n\n/**\n * Options for fetch requests\n */\nexport interface FetchOptions {\n headers?: {\n [key: string]: string\n }\n duplex?: string\n noResolveJson?: boolean\n}\n\n/**\n * HTTP methods supported by the API\n */\nexport type RequestMethodType = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD'\n\n/**\n * Extracts error message from various error response formats\n * @param err - Error object from API\n * @returns Human-readable error message\n */\nconst _getErrorMessage = (err: unknown): string => {\n if (typeof err === 'object' && err !== null) {\n const e = err as Record<string, unknown>\n if (typeof e.msg === 'string') return e.msg\n if (typeof e.message === 'string') return e.message\n if (typeof e.error_description === 'string') return e.error_description\n if (typeof e.error === 'string') return e.error\n if (typeof e.error === 'object' && e.error !== null) {\n const nested = e.error as Record<string, unknown>\n if (typeof nested.message === 'string') return nested.message\n }\n }\n return JSON.stringify(err)\n}\n\n/**\n * Handles fetch errors and converts them to Storage error types\n * @param error - The error caught from fetch\n * @param reject - Promise rejection function\n * @param options - Fetch options that may affect error handling\n * @param namespace - Error namespace ('storage' or 'vectors')\n */\nconst handleError = async (\n error: unknown,\n reject: (reason: StorageError) => void,\n options: FetchOptions | undefined,\n namespace: ErrorNamespace\n) => {\n // Structural detection of json() method, present in all Response implementations\n // (native, node-fetch, cross-fetch, undici) and absent from standard Error objects.\n // Checking 'ok' or 'status' via `in` is unreliable across fetch polyfills/realms.\n const isResponseLike =\n error !== null &&\n typeof error === 'object' &&\n 'json' in error &&\n typeof (error as Record<string, unknown>).json === 'function'\n\n if (isResponseLike) {\n const responseError = error as Response\n // Defensive coercion: some fetch polyfills have historically returned status as a string.\n let status = parseInt(String(responseError.status), 10)\n if (!Number.isFinite(status)) {\n status = 500\n }\n\n responseError\n .json()\n .then(\n (err: { statusCode?: string; code?: string; error?: string; message?: string } | null) => {\n const statusCode = err?.statusCode || err?.code || status + ''\n reject(\n new StorageApiError(_getErrorMessage(err), status, statusCode, namespace, err?.code)\n )\n }\n )\n .catch(() => {\n const statusCode = status + ''\n const message = responseError.statusText || `HTTP ${status} error`\n reject(new StorageApiError(message, status, statusCode, namespace))\n })\n } else {\n reject(new StorageUnknownError(_getErrorMessage(error), error, namespace))\n }\n}\n\n/**\n * Builds request parameters for fetch calls\n * @param method - HTTP method\n * @param options - Custom fetch options\n * @param parameters - Additional fetch parameters like AbortSignal\n * @param body - Request body (will be JSON stringified if plain object)\n * @returns Complete fetch request parameters\n */\nconst _getRequestParams = (\n method: RequestMethodType,\n options?: FetchOptions,\n parameters?: FetchParameters,\n body?: object\n) => {\n const params: { [k: string]: any } = { method, headers: options?.headers || {} }\n\n if (method === 'GET' || method === 'HEAD' || !body) {\n return { ...params, ...parameters }\n }\n\n if (isPlainObject(body)) {\n const headers = options?.headers || {}\n let contentType: string | undefined\n\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === 'content-type') {\n contentType = value\n }\n }\n\n params.headers = setHeader(headers, 'Content-Type', contentType ?? 'application/json')\n params.body = JSON.stringify(body)\n } else {\n params.body = body\n }\n\n if (options?.duplex) {\n params.duplex = options.duplex\n }\n\n return { ...params, ...parameters }\n}\n\n/**\n * Internal request handler that wraps fetch with error handling\n * @param fetcher - Fetch function to use\n * @param method - HTTP method\n * @param url - Request URL\n * @param options - Custom fetch options\n * @param parameters - Additional fetch parameters\n * @param body - Request body\n * @param namespace - Error namespace ('storage' or 'vectors')\n * @returns Promise with parsed response or error\n */\nasync function _handleRequest(\n fetcher: Fetch,\n method: RequestMethodType,\n url: string,\n options: FetchOptions | undefined,\n parameters: FetchParameters | undefined,\n body: object | undefined,\n namespace: ErrorNamespace\n): Promise<any> {\n return new Promise((resolve, reject) => {\n fetcher(url, _getRequestParams(method, options, parameters, body))\n .then((result) => {\n if (!result.ok) throw result\n if (options?.noResolveJson) return result\n\n // AWS S3 Vectors API returns 200 OK with content-length: 0 for successful mutations\n // (putVectors, deleteVectors) instead of 204 or JSON response. This is AWS's design choice\n // for performance optimization of bulk operations (up to 500 vectors per request).\n // We handle this to prevent \"Unexpected end of JSON input\" errors when calling result.json()\n if (namespace === 'vectors') {\n const contentType = result.headers.get('content-type')\n const contentLength = result.headers.get('content-length')\n\n // Return empty object for explicitly empty responses\n if (contentLength === '0' || result.status === 204) {\n return {}\n }\n\n // Return empty object if no JSON content type\n if (!contentType || !contentType.includes('application/json')) {\n return {}\n }\n }\n\n return result.json()\n })\n .then((data) => resolve(data))\n .catch((error) => handleError(error, reject, options, namespace))\n })\n}\n\n/**\n * Creates a fetch API with the specified namespace\n * @param namespace - Error namespace ('storage' or 'vectors')\n * @returns Object with HTTP method functions\n */\nexport function createFetchApi(namespace: ErrorNamespace = 'storage') {\n return {\n /**\n * Performs a GET request\n * @param fetcher - Fetch function to use\n * @param url - Request URL\n * @param options - Custom fetch options\n * @param parameters - Additional fetch parameters\n * @returns Promise with parsed response\n */\n get: async (\n fetcher: Fetch,\n url: string,\n options?: FetchOptions,\n parameters?: FetchParameters\n ): Promise<any> => {\n return _handleRequest(fetcher, 'GET', url, options, parameters, undefined, namespace)\n },\n\n /**\n * Performs a POST request\n * @param fetcher - Fetch function to use\n * @param url - Request URL\n * @param body - Request body to be JSON stringified\n * @param options - Custom fetch options\n * @param parameters - Additional fetch parameters\n * @returns Promise with parsed response\n */\n post: async (\n fetcher: Fetch,\n url: string,\n body: object,\n options?: FetchOptions,\n parameters?: FetchParameters\n ): Promise<any> => {\n return _handleRequest(fetcher, 'POST', url, options, parameters, body, namespace)\n },\n\n /**\n * Performs a PUT request\n * @param fetcher - Fetch function to use\n * @param url - Request URL\n * @param body - Request body to be JSON stringified\n * @param options - Custom fetch options\n * @param parameters - Additional fetch parameters\n * @returns Promise with parsed response\n */\n put: async (\n fetcher: Fetch,\n url: string,\n body: object,\n options?: FetchOptions,\n parameters?: FetchParameters\n ): Promise<any> => {\n return _handleRequest(fetcher, 'PUT', url, options, parameters, body, namespace)\n },\n\n /**\n * Performs a HEAD request\n * @param fetcher - Fetch function to use\n * @param url - Request URL\n * @param options - Custom fetch options\n * @param parameters - Additional fetch parameters\n * @returns Promise with Response object (not JSON parsed)\n */\n head: async (\n fetcher: Fetch,\n url: string,\n options?: FetchOptions,\n parameters?: FetchParameters\n ): Promise<any> => {\n return _handleRequest(\n fetcher,\n 'HEAD',\n url,\n {\n ...options,\n noResolveJson: true,\n },\n parameters,\n undefined,\n namespace\n )\n },\n\n /**\n * Performs a DELETE request\n * @param fetcher - Fetch function to use\n * @param url - Request URL\n * @param body - Request body to be JSON stringified\n * @param options - Custom fetch options\n * @param parameters - Additional fetch parameters\n * @returns Promise with parsed response\n */\n remove: async (\n fetcher: Fetch,\n url: string,\n body: object,\n options?: FetchOptions,\n parameters?: FetchParameters\n ): Promise<any> => {\n return _handleRequest(fetcher, 'DELETE', url, options, parameters, body, namespace)\n },\n }\n}\n\n// Default exports for backward compatibility with 'storage' namespace\nconst defaultApi = createFetchApi('storage')\nexport const { get, post, put, head, remove } = defaultApi\n\n// Vectors API with 'vectors' namespace for proper error handling\nexport const vectorsApi = createFetchApi('vectors')\n","import { ErrorNamespace, isStorageError, StorageError } from './errors'\nimport { Fetch } from './fetch'\nimport { normalizeHeaders, setHeader as setHeaderUtil } from './headers'\nimport { resolveFetch } from './helpers'\n\n/**\n * @ignore\n * Base API client class for all Storage API classes\n * Provides common infrastructure for error handling and configuration\n *\n * @typeParam TError - The error type (StorageError or subclass)\n */\nexport default abstract class BaseApiClient<TError extends StorageError = StorageError> {\n protected url: string\n protected headers: { [key: string]: string }\n protected fetch: Fetch\n protected shouldThrowOnError = false\n protected namespace: ErrorNamespace\n\n /**\n * Creates a new BaseApiClient instance\n * @param url - Base URL for API requests\n * @param headers - Default headers for API requests\n * @param fetch - Optional custom fetch implementation\n * @param namespace - Error namespace ('storage' or 'vectors')\n */\n constructor(\n url: string,\n headers: { [key: string]: string } = {},\n fetch?: Fetch,\n namespace: ErrorNamespace = 'storage'\n ) {\n this.url = url\n this.headers = normalizeHeaders(headers)\n this.fetch = resolveFetch(fetch)\n this.namespace = namespace\n }\n\n /**\n * Enable throwing errors instead of returning them.\n * When enabled, errors are thrown instead of returned in { data, error } format.\n *\n * @returns this - For method chaining\n */\n public throwOnError(): this {\n this.shouldThrowOnError = true\n return this\n }\n\n /**\n * Set an HTTP header for the request.\n * Creates a shallow copy of headers to avoid mutating shared state.\n *\n * @param name - Header name\n * @param value - Header value\n * @returns this - For method chaining\n */\n public setHeader(name: string, value: string): this {\n this.headers = setHeaderUtil(this.headers, name, value)\n return this\n }\n\n /**\n * Handles API operation with standardized error handling\n * Eliminates repetitive try-catch blocks across all API methods\n *\n * This wrapper:\n * 1. Executes the operation\n * 2. Returns { data, error: null } on success\n * 3. Returns { data: null, error } on failure (if shouldThrowOnError is false)\n * 4. Throws error on failure (if shouldThrowOnError is true)\n *\n * @typeParam T - The expected data type from the operation\n * @param operation - Async function that performs the API call\n * @returns Promise with { data, error } tuple\n *\n * @example Handling an operation\n * ```typescript\n * async listBuckets() {\n * return this.handleOperation(async () => {\n * return await get(this.fetch, `${this.url}/bucket`, {\n * headers: this.headers,\n * })\n * })\n * }\n * ```\n */\n protected async handleOperation<T>(\n operation: () => Promise<T>\n ): Promise<{ data: T; error: null } | { data: null; error: TError }> {\n try {\n const data = await operation()\n return { data, error: null }\n } catch (error) {\n if (this.shouldThrowOnError) {\n throw error\n }\n if (isStorageError(error)) {\n return { data: null, error: error as TError }\n }\n throw error\n }\n }\n}\n","import { isStorageError } from '../lib/common/errors'\nimport { DownloadResult } from '../lib/types'\n\nexport default class StreamDownloadBuilder implements Promise<DownloadResult<ReadableStream>> {\n readonly [Symbol.toStringTag]: string = 'StreamDownloadBuilder'\n private promise: Promise<DownloadResult<ReadableStream>> | null = null\n\n constructor(\n private downloadFn: () => Promise<Response>,\n private shouldThrowOnError: boolean\n ) {}\n\n then<TResult1 = DownloadResult<ReadableStream>, TResult2 = never>(\n onfulfilled?:\n | ((value: DownloadResult<ReadableStream>) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n return this.getPromise().then(onfulfilled, onrejected)\n }\n\n catch<TResult = never>(\n onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null\n ): Promise<DownloadResult<ReadableStream> | TResult> {\n return this.getPromise().catch(onrejected)\n }\n\n finally(onfinally?: (() => void) | null): Promise<DownloadResult<ReadableStream>> {\n return this.getPromise().finally(onfinally)\n }\n\n private getPromise(): Promise<DownloadResult<ReadableStream>> {\n if (!this.promise) {\n this.promise = this.execute()\n }\n return this.promise\n }\n\n private async execute(): Promise<DownloadResult<ReadableStream>> {\n try {\n const result = await this.downloadFn()\n\n return {\n data: result.body as ReadableStream,\n error: null,\n }\n } catch (error) {\n if (this.shouldThrowOnError) {\n throw error\n }\n\n if (isStorageError(error)) {\n return { data: null, error }\n }\n\n throw error\n }\n }\n}\n","import { isStorageError } from '../lib/common/errors'\nimport { DownloadResult } from '../lib/types'\nimport StreamDownloadBuilder from './StreamDownloadBuilder'\n\nexport default class BlobDownloadBuilder implements Promise<DownloadResult<Blob>> {\n readonly [Symbol.toStringTag]: string = 'BlobDownloadBuilder'\n private promise: Promise<DownloadResult<Blob>> | null = null\n\n constructor(\n private downloadFn: () => Promise<Response>,\n private shouldThrowOnError: boolean\n ) {}\n\n asStream(): StreamDownloadBuilder {\n return new StreamDownloadBuilder(this.downloadFn, this.shouldThrowOnError)\n }\n\n then<TResult1 = DownloadResult<Blob>, TResult2 = never>(\n onfulfilled?: ((value: DownloadResult<Blob>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n return this.getPromise().then(onfulfilled, onrejected)\n }\n\n catch<TResult = never>(\n onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null\n ): Promise<DownloadResult<Blob> | TResult> {\n return this.getPromise().catch(onrejected)\n }\n\n finally(onfinally?: (() => void) | null): Promise<DownloadResult<Blob>> {\n return this.getPromise().finally(onfinally)\n }\n\n private getPromise(): Promise<DownloadResult<Blob>> {\n if (!this.promise) {\n this.promise = this.execute()\n }\n return this.promise\n }\n\n private async execute(): Promise<DownloadResult<Blob>> {\n try {\n const result = await this.downloadFn()\n\n return {\n data: await result.blob(),\n error: null,\n }\n } catch (error) {\n if (this.shouldThrowOnError) {\n throw error\n }\n\n if (isStorageError(error)) {\n return { data: null, error }\n }\n\n throw error\n }\n }\n}\n","import {\n StorageApiError,\n StorageError,\n StorageUnknownError,\n isStorageError,\n} from '../lib/common/errors'\nimport { get, head, post, put, remove, Fetch } from '../lib/common/fetch'\nimport { setHeader } from '../lib/common/headers'\nimport { encodeStoragePath, recursiveToCamel } from '../lib/common/helpers'\nimport BaseApiClient from '../lib/common/BaseApiClient'\nimport {\n FileObject,\n FileOptions,\n SearchOptions,\n FetchParameters,\n TransformOptions,\n DestinationOptions,\n FileObjectV2,\n Camelize,\n SearchV2Options,\n SearchV2Result,\n PurgeCacheOptions,\n} from '../lib/types'\nimport BlobDownloadBuilder from './BlobDownloadBuilder'\n\nconst DEFAULT_SEARCH_OPTIONS = {\n limit: 100,\n offset: 0,\n sortBy: {\n column: 'name',\n order: 'asc',\n },\n}\n\nconst DEFAULT_FILE_OPTIONS: FileOptions = {\n cacheControl: '3600',\n contentType: 'text/plain;charset=UTF-8',\n upsert: false,\n}\n\ntype FileBody =\n | ArrayBuffer\n | ArrayBufferView\n | Blob\n | Buffer\n | File\n | FormData\n | NodeJS.ReadableStream\n | ReadableStream<Uint8Array>\n | URLSearchParams\n | string\n\nexport default class StorageFileApi extends BaseApiClient<StorageError> {\n protected bucketId: string | undefined\n\n constructor(\n url: string,\n headers: { [key: string]: string } = {},\n bucketId?: string,\n fetch?: Fetch\n ) {\n super(url, headers, fetch, 'storage')\n this.bucketId = bucketId\n }\n\n /**\n * Uploads a file to an existing bucket or replaces an existing file at the specified path with a new one.\n *\n * @param method HTTP method.\n * @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.\n * @param fileBody The body of the file to be stored in the bucket.\n */\n private async uploadOrUpdate(\n method: 'POST' | 'PUT',\n path: string,\n fileBody: FileBody,\n fileOptions?: FileOptions\n ): Promise<\n | {\n data: { id: string; path: string; fullPath: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n let body\n const options = { ...DEFAULT_FILE_OPTIONS, ...fileOptions }\n let headers: Record<string, string> = {\n ...this.headers,\n ...(method === 'POST' && { 'x-upsert': String(options.upsert as boolean) }),\n }\n\n const metadata = options.metadata\n\n if (typeof Blob !== 'undefined' && fileBody instanceof Blob) {\n body = new FormData()\n body.append('cacheControl', options.cacheControl as string)\n if (metadata) {\n body.append('metadata', this.encodeMetadata(metadata))\n }\n body.append('', fileBody)\n } else if (typeof FormData !== 'undefined' && fileBody instanceof FormData) {\n body = fileBody\n // Only append if not already present\n if (!body.has('cacheControl')) {\n body.append('cacheControl', options.cacheControl as string)\n }\n if (metadata && !body.has('metadata')) {\n body.append('metadata', this.encodeMetadata(metadata))\n }\n } else {\n body = fileBody\n headers['cache-control'] = `max-age=${options.cacheControl}`\n headers['content-type'] = options.contentType as string\n\n if (metadata) {\n headers['x-metadata'] = this.toBase64(this.encodeMetadata(metadata))\n }\n\n // Node.js streams require duplex option for fetch in Node 20+\n // Check for both web ReadableStream and Node.js streams\n const isStream =\n (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) ||\n (body && typeof body === 'object' && 'pipe' in body && typeof body.pipe === 'function')\n\n if (isStream && !options.duplex) {\n options.duplex = 'half'\n }\n }\n\n if (fileOptions?.headers) {\n for (const [key, value] of Object.entries(fileOptions.headers)) {\n headers = setHeader(headers, key, value)\n }\n }\n\n const cleanPath = this._removeEmptyFolders(path)\n const _path = this._getFinalPath(cleanPath)\n const data = await (method == 'PUT' ? put : post)(\n this.fetch,\n `${this.url}/object/${_path}`,\n body as object,\n { headers, ...(options?.duplex ? { duplex: options.duplex } : {}) }\n )\n\n return { path: cleanPath, id: data.Id, fullPath: data.Key }\n })\n }\n\n /**\n * Uploads a file to an existing bucket.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The file path, including the file name. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.\n * @param fileBody The body of the file to be stored in the bucket.\n * @param fileOptions Optional file upload options including cacheControl, contentType, upsert, and metadata.\n * @returns Promise with response containing file path, id, and fullPath or error\n *\n * @example Upload file\n * ```js\n * const avatarFile = event.target.files[0]\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .upload('public/avatar1.png', avatarFile, {\n * cacheControl: '3600',\n * upsert: false\n * })\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"path\": \"public/avatar1.png\",\n * \"fullPath\": \"avatars/public/avatar1.png\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @example Upload file using `ArrayBuffer` from base64 file data\n * ```js\n * import { decode } from 'base64-arraybuffer'\n *\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .upload('public/avatar1.png', decode('base64FileData'), {\n * contentType: 'image/png'\n * })\n * ```\n *\n * @example Handling errors\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .upload('public/avatar1.png', avatarFile)\n *\n * if (error) {\n * // Log the full error so fields like `statusCode` and `error` (the\n * // Storage error name, e.g. \"Duplicate\") aren't hidden behind `error.message`.\n * console.error(error)\n * return\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: only `insert` when you are uploading new files and `select`, `insert` and `update` when you are upserting files\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n * - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Upload file using `ArrayBuffer` from base64 file data instead, see example below.\n */\n async upload(\n path: string,\n fileBody: FileBody,\n fileOptions?: FileOptions\n ): Promise<\n | {\n data: { id: string; path: string; fullPath: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.uploadOrUpdate('POST', path, fileBody, fileOptions)\n }\n\n /**\n * Upload a file with a token generated from `createSignedUploadUrl`.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The file path, including the file name. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to upload.\n * @param token The token generated from `createSignedUploadUrl`\n * @param fileBody The body of the file to be stored in the bucket.\n * @param fileOptions HTTP headers (cacheControl, contentType, etc.).\n * **Note:** The `upsert` option has no effect here. To enable upsert behavior,\n * pass `{ upsert: true }` when calling `createSignedUploadUrl()` instead.\n * @returns Promise with response containing file path and fullPath or error\n *\n * @example Upload to a signed URL\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .uploadToSignedUrl('folder/cat.jpg', 'token-from-createSignedUploadUrl', file)\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"path\": \"folder/cat.jpg\",\n * \"fullPath\": \"avatars/folder/cat.jpg\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: none\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async uploadToSignedUrl(\n path: string,\n token: string,\n fileBody: FileBody,\n fileOptions?: FileOptions\n ) {\n const cleanPath = this._removeEmptyFolders(path)\n const _path = this._getFinalPath(cleanPath)\n\n const url = new URL(this.url + `/object/upload/sign/${_path}`)\n url.searchParams.set('token', token)\n\n return this.handleOperation(async () => {\n let body\n const options = { ...DEFAULT_FILE_OPTIONS, ...fileOptions }\n let headers: Record<string, string> = {\n ...this.headers,\n ...{ 'x-upsert': String(options.upsert as boolean) },\n }\n\n const metadata = options.metadata\n\n if (typeof Blob !== 'undefined' && fileBody instanceof Blob) {\n body = new FormData()\n body.append('cacheControl', options.cacheControl as string)\n if (metadata) {\n body.append('metadata', this.encodeMetadata(metadata))\n }\n body.append('', fileBody)\n } else if (typeof FormData !== 'undefined' && fileBody instanceof FormData) {\n body = fileBody\n if (!body.has('cacheControl')) {\n body.append('cacheControl', options.cacheControl as string)\n }\n if (metadata && !body.has('metadata')) {\n body.append('metadata', this.encodeMetadata(metadata))\n }\n } else {\n body = fileBody\n headers['cache-control'] = `max-age=${options.cacheControl}`\n headers['content-type'] = options.contentType as string\n if (metadata) {\n headers['x-metadata'] = this.toBase64(this.encodeMetadata(metadata))\n }\n\n const isStream =\n (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) ||\n (body && typeof body === 'object' && 'pipe' in body && typeof body.pipe === 'function')\n\n if (isStream && !options.duplex) {\n options.duplex = 'half'\n }\n }\n\n if (fileOptions?.headers) {\n for (const [key, value] of Object.entries(fileOptions.headers)) {\n headers = setHeader(headers, key, value)\n }\n }\n\n const data = await put(this.fetch, url.toString(), body as object, {\n headers,\n ...(options?.duplex ? { duplex: options.duplex } : {}),\n })\n\n return { path: cleanPath, fullPath: data.Key }\n })\n }\n\n /**\n * Creates a signed upload URL.\n * Signed upload URLs can be used to upload files to the bucket without further authentication.\n * They are valid for 2 hours.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The file path, including the current file name. For example `folder/image.png`.\n * @param options.upsert If set to true, allows the file to be overwritten if it already exists.\n * @returns Promise with response containing signed upload URL, token, and path or error\n *\n * @example Create Signed Upload URL\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .createSignedUploadUrl('folder/cat.jpg')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"signedUrl\": \"https://example.supabase.co/storage/v1/object/upload/sign/avatars/folder/cat.jpg?token=<TOKEN>\",\n * \"path\": \"folder/cat.jpg\",\n * \"token\": \"<TOKEN>\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `insert`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async createSignedUploadUrl(\n path: string,\n options?: { upsert: boolean }\n ): Promise<\n | {\n data: { signedUrl: string; token: string; path: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n let _path = this._getFinalPath(path)\n\n const headers = { ...this.headers }\n\n if (options?.upsert) {\n headers['x-upsert'] = 'true'\n }\n\n const data = await post(\n this.fetch,\n `${this.url}/object/upload/sign/${_path}`,\n {},\n { headers }\n )\n\n const url = new URL(this.url + data.url)\n\n const token = url.searchParams.get('token')\n\n if (!token) {\n throw new StorageError('No token returned by API')\n }\n\n return { signedUrl: url.toString(), path, token }\n })\n }\n\n /**\n * Replaces an existing file at the specified path with a new one.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The relative file path. Should be of the format `folder/subfolder/filename.png`. The bucket must already exist before attempting to update.\n * @param fileBody The body of the file to be stored in the bucket.\n * @param fileOptions Optional file upload options including cacheControl, contentType, and metadata.\n * **Note:** The `upsert` option has no effect here. `update()` always replaces the\n * file at the given path, so the `x-upsert` header is not sent. To control upsert\n * behavior, use `upload()` instead.\n * @returns Promise with response containing file path, id, and fullPath or error\n *\n * @example Update file\n * ```js\n * const avatarFile = event.target.files[0]\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .update('public/avatar1.png', avatarFile, {\n * cacheControl: '3600'\n * })\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"path\": \"public/avatar1.png\",\n * \"fullPath\": \"avatars/public/avatar1.png\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @example Update file using `ArrayBuffer` from base64 file data\n * ```js\n * import {decode} from 'base64-arraybuffer'\n *\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .update('public/avatar1.png', decode('base64FileData'), {\n * contentType: 'image/png'\n * })\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `update` and `select`\n * - `update()` always replaces the file at the given path regardless of the `upsert` option.\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n * - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Update file using `ArrayBuffer` from base64 file data instead, see example below.\n */\n async update(\n path: string,\n fileBody:\n | ArrayBuffer\n | ArrayBufferView\n | Blob\n | Buffer\n | File\n | FormData\n | NodeJS.ReadableStream\n | ReadableStream<Uint8Array>\n | URLSearchParams\n | string,\n fileOptions?: FileOptions\n ): Promise<\n | {\n data: { id: string; path: string; fullPath: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.uploadOrUpdate('PUT', path, fileBody, fileOptions)\n }\n\n /**\n * Moves an existing file to a new path in the same bucket.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param fromPath The original file path, including the current file name. For example `folder/image.png`.\n * @param toPath The new file path, including the new file name. For example `folder/image-new.png`.\n * @param options The destination options.\n * @returns Promise with response containing success message or error\n *\n * @example Move file\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .move('public/avatar1.png', 'private/avatar2.png')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"message\": \"Successfully moved\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `update` and `select`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async move(\n fromPath: string,\n toPath: string,\n options?: DestinationOptions\n ): Promise<\n | {\n data: { message: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await post(\n this.fetch,\n `${this.url}/object/move`,\n {\n bucketId: this.bucketId,\n sourceKey: fromPath,\n destinationKey: toPath,\n destinationBucket: options?.destinationBucket,\n },\n { headers: this.headers }\n )\n })\n }\n\n /**\n * Copies an existing file to a new path in the same bucket.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param fromPath The original file path, including the current file name. For example `folder/image.png`.\n * @param toPath The new file path, including the new file name. For example `folder/image-copy.png`.\n * @param options The destination options.\n * @returns Promise with response containing copied file path or error\n *\n * @example Copy file\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .copy('public/avatar1.png', 'private/avatar2.png')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"path\": \"avatars/private/avatar2.png\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `insert` and `select`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async copy(\n fromPath: string,\n toPath: string,\n options?: DestinationOptions\n ): Promise<\n | {\n data: { path: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n const data = await post(\n this.fetch,\n `${this.url}/object/copy`,\n {\n bucketId: this.bucketId,\n sourceKey: fromPath,\n destinationKey: toPath,\n destinationBucket: options?.destinationBucket,\n },\n { headers: this.headers }\n )\n return { path: data.Key }\n })\n }\n\n /**\n * Creates a signed URL. Use a signed URL to share a file for a fixed amount of time.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The file path, including the current file name. For example `folder/image.png`.\n * @param expiresIn The number of seconds until the signed URL expires. For example, `60` for a URL which is valid for one minute.\n * @param options.download triggers the file as a download if set to true. Set this parameter as the name of the file if you want to trigger the download with a different filename.\n * @param options.transform Transform the asset before serving it to the client.\n * @param options.cacheNonce Append a cache nonce parameter to the URL to invalidate the cache.\n * @returns Promise with response containing signed URL or error\n *\n * @example Create Signed URL\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .createSignedUrl('folder/avatar1.png', 60)\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"signedUrl\": \"https://example.supabase.co/storage/v1/object/sign/avatars/folder/avatar1.png?token=<TOKEN>\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @example Create a signed URL for an asset with transformations\n * ```js\n * const { data } = await supabase\n * .storage\n * .from('avatars')\n * .createSignedUrl('folder/avatar1.png', 60, {\n * transform: {\n * width: 100,\n * height: 100,\n * }\n * })\n * ```\n *\n * @example Create a signed URL which triggers the download of the asset\n * ```js\n * const { data } = await supabase\n * .storage\n * .from('avatars')\n * .createSignedUrl('folder/avatar1.png', 60, {\n * download: true,\n * })\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `select`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async createSignedUrl(\n path: string,\n expiresIn: number,\n options?: {\n download?: string | boolean\n transform?: TransformOptions\n cacheNonce?: string\n }\n ): Promise<\n | {\n data: { signedUrl: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n let _path = this._getFinalPath(path)\n\n const hasTransform =\n typeof options?.transform === 'object' &&\n options.transform !== null &&\n Object.keys(options.transform).length > 0\n\n let data = await post(\n this.fetch,\n `${this.url}/object/sign/${_path}`,\n { expiresIn, ...(hasTransform ? { transform: options!.transform } : {}) },\n { headers: this.headers }\n )\n\n const query = new URLSearchParams()\n if (options?.download)\n query.set('download', options.download === true ? '' : options.download)\n if (options?.cacheNonce != null) query.set('cacheNonce', String(options.cacheNonce))\n const queryString = query.toString()\n\n // `data.signedURL` contains a `token` query parameter, so append extra params with `&`\n // only when we actually have something to add.\n const signedUrl = encodeURI(\n `${this.url}${data.signedURL}${queryString ? `&${queryString}` : ''}`\n )\n\n return { signedUrl }\n })\n }\n\n /**\n * Creates multiple signed URLs. Use a signed URL to share a file for a fixed amount of time.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param paths The file paths to be downloaded, including the current file names. For example `['folder/image.png', 'folder2/image2.png']`.\n * @param expiresIn The number of seconds until the signed URLs expire. For example, `60` for URLs which are valid for one minute.\n * @param options.download triggers the file as a download if set to true. Set this parameter as the name of the file if you want to trigger the download with a different filename.\n * @param options.cacheNonce Append a cache nonce parameter to the URL to invalidate the cache.\n * @returns Promise with response containing array of objects with signedUrl, path, and error or error\n *\n * @example Create Signed URLs\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .createSignedUrls(['folder/avatar1.png', 'folder/avatar2.png'], 60)\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": [\n * {\n * \"error\": null,\n * \"path\": \"folder/avatar1.png\",\n * \"signedURL\": \"/object/sign/avatars/folder/avatar1.png?token=<TOKEN>\",\n * \"signedUrl\": \"https://example.supabase.co/storage/v1/object/sign/avatars/folder/avatar1.png?token=<TOKEN>\"\n * },\n * {\n * \"error\": null,\n * \"path\": \"folder/avatar2.png\",\n * \"signedURL\": \"/object/sign/avatars/folder/avatar2.png?token=<TOKEN>\",\n * \"signedUrl\": \"https://example.supabase.co/storage/v1/object/sign/avatars/folder/avatar2.png?token=<TOKEN>\"\n * }\n * ],\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `select`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async createSignedUrls(\n paths: string[],\n expiresIn: number,\n options?: { download?: string | boolean; cacheNonce?: string }\n ): Promise<\n | {\n data: {\n error: string | null\n path: string | null\n signedURL: string | null\n signedUrl: string | null\n }[]\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n const data = await post(\n this.fetch,\n `${this.url}/object/sign/${this.bucketId}`,\n { expiresIn, paths },\n { headers: this.headers }\n )\n\n const query = new URLSearchParams()\n\n if (options?.download)\n query.set('download', options.download === true ? '' : options.download)\n if (options?.cacheNonce != null) query.set('cacheNonce', String(options.cacheNonce))\n\n const queryString = query.toString()\n\n return data.map(\n (datum: { error: string | null; path: string | null; signedURL: string | null }) => ({\n ...datum,\n signedUrl: datum.signedURL\n ? encodeURI(`${this.url}${datum.signedURL}${queryString ? `&${queryString}` : ''}`)\n : null,\n })\n )\n })\n }\n\n /**\n * Downloads a file from a private bucket. For public buckets, make a request to the URL returned from `getPublicUrl` instead.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The full path and file name of the file to be downloaded. For example `folder/image.png`.\n * @param options Optional settings: `transform` to transform the asset before serving it to the client, and `cacheNonce` to append a cache nonce parameter to the URL to invalidate the cache.\n * @param parameters Additional fetch parameters like signal for cancellation. Supports standard fetch options including cache control.\n * @returns BlobDownloadBuilder instance for downloading the file\n *\n * @example Download file\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .download('folder/avatar1.png')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": <BLOB>,\n * \"error\": null\n * }\n * ```\n *\n * @example Download file with transformations\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .download('folder/avatar1.png', {\n * transform: {\n * width: 100,\n * height: 100,\n * quality: 80\n * }\n * })\n * ```\n *\n * @example Download with cache control (useful in Edge Functions)\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .download('folder/avatar1.png', {}, { cache: 'no-store' })\n * ```\n *\n * @example Download with abort signal\n * ```js\n * const controller = new AbortController()\n * setTimeout(() => controller.abort(), 5000)\n *\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .download('folder/avatar1.png', {}, { signal: controller.signal })\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `select`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n download<Options extends { transform?: TransformOptions; cacheNonce?: string }>(\n path: string,\n options?: Options,\n parameters?: FetchParameters\n ): BlobDownloadBuilder {\n const wantsTransformation =\n typeof options?.transform === 'object' &&\n options.transform !== null &&\n Object.keys(options.transform).length > 0\n const renderPath = wantsTransformation ? 'render/image/authenticated' : 'object'\n\n const query = new URLSearchParams()\n if (options?.transform) this.applyTransformOptsToQuery(query, options.transform)\n if (options?.cacheNonce != null) query.set('cacheNonce', String(options.cacheNonce))\n const queryString = query.toString()\n\n const _path = this._getFinalPath(path)\n const downloadFn = () =>\n get(\n this.fetch,\n `${this.url}/${renderPath}/${_path}${queryString ? `?${queryString}` : ''}`,\n {\n headers: this.headers,\n noResolveJson: true,\n },\n parameters\n )\n return new BlobDownloadBuilder(downloadFn, this.shouldThrowOnError)\n }\n\n /**\n * Retrieves the details of an existing file.\n *\n * Returns detailed file metadata including size, content type, and timestamps.\n * Note: The API returns `last_modified` field, not `updated_at`.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The file path, including the file name. For example `folder/image.png`.\n * @returns Promise with response containing file metadata or error\n *\n * @example Get file info\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .info('folder/avatar1.png')\n *\n * if (data) {\n * console.log('Last modified:', data.lastModified)\n * console.log('Size:', data.size)\n * }\n * ```\n */\n async info(path: string): Promise<\n | {\n data: Camelize<FileObjectV2>\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n const _path = this._getFinalPath(path)\n\n return this.handleOperation(async () => {\n const data = await get(this.fetch, `${this.url}/object/info/${_path}`, {\n headers: this.headers,\n })\n\n return recursiveToCamel(data) as Camelize<FileObjectV2>\n })\n }\n\n /**\n * Checks the existence of a file.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The file path, including the file name. For example `folder/image.png`.\n * @returns Promise with response containing boolean indicating file existence or error\n *\n * @example Check file existence\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .exists('folder/avatar1.png')\n * ```\n */\n async exists(path: string): Promise<\n | {\n data: boolean\n error: null\n }\n | {\n data: boolean\n error: StorageError\n }\n > {\n const _path = this._getFinalPath(path)\n\n try {\n await head(this.fetch, `${this.url}/object/${_path}`, {\n headers: this.headers,\n })\n\n return { data: true, error: null }\n } catch (error) {\n if (this.shouldThrowOnError) {\n throw error\n }\n if (isStorageError(error)) {\n // HEAD requests produce StorageApiError (via handleError) or StorageUnknownError (legacy)\n const status =\n error instanceof StorageApiError\n ? error.status\n : error instanceof StorageUnknownError\n ? (error.originalError as { status: number })?.status\n : undefined\n\n if (status !== undefined && [400, 404].includes(status)) {\n return { data: false, error }\n }\n }\n\n throw error\n }\n }\n\n /**\n * A simple convenience function to get the URL for an asset in a public bucket. If you do not want to use this function, you can construct the public URL by concatenating the bucket URL with the path to the asset.\n * This function does not verify if the bucket is public. If a public URL is created for a bucket which is not public, you will not be able to download the asset.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The path and name of the file to generate the public URL for. For example `folder/image.png`.\n * @param options.download Triggers the file as a download if set to true. Set this parameter as the name of the file if you want to trigger the download with a different filename.\n * @param options.transform Transform the asset before serving it to the client.\n * @param options.cacheNonce Append a cache nonce parameter to the URL to invalidate the cache.\n * @returns Object with public URL\n *\n * @example Returns the URL for an asset in a public bucket\n * ```js\n * const { data } = supabase\n * .storage\n * .from('public-bucket')\n * .getPublicUrl('folder/avatar1.png')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"publicUrl\": \"https://example.supabase.co/storage/v1/object/public/public-bucket/folder/avatar1.png\"\n * }\n * }\n * ```\n *\n * @example Returns the URL for an asset in a public bucket with transformations\n * ```js\n * const { data } = supabase\n * .storage\n * .from('public-bucket')\n * .getPublicUrl('folder/avatar1.png', {\n * transform: {\n * width: 100,\n * height: 100,\n * }\n * })\n * ```\n *\n * @example Returns the URL which triggers the download of an asset in a public bucket\n * ```js\n * const { data } = supabase\n * .storage\n * .from('public-bucket')\n * .getPublicUrl('folder/avatar1.png', {\n * download: true,\n * })\n * ```\n *\n * @remarks\n * - The bucket needs to be set to public, either via [updateBucket()](/docs/reference/javascript/storage-updatebucket) or by going to Storage on [supabase.com/dashboard](https://supabase.com/dashboard), clicking the overflow menu on a bucket and choosing \"Make public\"\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: none\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n getPublicUrl(\n path: string,\n options?: {\n download?: string | boolean\n transform?: TransformOptions\n cacheNonce?: string\n }\n ): { data: { publicUrl: string } } {\n const _path = this._getFinalPath(path)\n\n const query = new URLSearchParams()\n if (options?.download) query.set('download', options.download === true ? '' : options.download)\n if (options?.transform) this.applyTransformOptsToQuery(query, options.transform)\n if (options?.cacheNonce != null) query.set('cacheNonce', String(options.cacheNonce))\n const queryString = query.toString()\n\n const wantsTransformation =\n typeof options?.transform === 'object' &&\n options.transform !== null &&\n Object.keys(options.transform).length > 0\n const renderPath = wantsTransformation ? 'render/image' : 'object'\n\n return {\n data: {\n publicUrl:\n encodeURI(`${this.url}/${renderPath}/public/${_path}`) +\n (queryString ? `?${queryString}` : ''),\n },\n }\n }\n\n /**\n * Deletes files within the same bucket\n *\n * Returns an array of FileObject entries for the deleted files. Note that deprecated\n * fields like `bucket_id` may or may not be present in the response - do not rely on them.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param paths An array of files to delete, including the path and file name. For example [`'folder/image.png'`].\n * @returns Promise with response containing array of deleted file objects or error\n *\n * @example Delete file\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .remove(['folder/avatar1.png'])\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": [],\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `delete` and `select`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async remove(paths: string[]): Promise<\n | {\n data: FileObject[]\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await remove(\n this.fetch,\n `${this.url}/object/${this.bucketId}`,\n { prefixes: paths },\n { headers: this.headers }\n )\n })\n }\n\n /**\n * Purges the CDN cache for a single object in this bucket.\n *\n * Maps to `DELETE /cdn/{bucket}/{path}` on the Storage API. The server\n * issues a CDN invalidation for the object and returns `{ message: 'success' }`.\n *\n * **Requires the `service_role` key.** The underlying endpoint enforces\n * `service_role` JWT — calls made with the anon key or a user JWT will be\n * rejected by the server.\n *\n * **Hosted CDN feature.** On self-hosted Supabase, the Storage service must\n * have `CDN_PURGE_ENDPOINT_URL` configured and the `purgeCache` tenant\n * feature enabled, otherwise the server returns an error.\n *\n * Operates on a single object path. There is no wildcard or recursion: pass\n * the exact path of the object you want invalidated.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The path (relative to the bucket) of the object to purge, e.g. `folder/avatar.png`.\n * @param options Optional purge cache options.\n * @param options.transformations If true, purges only transformations (resized/formatted variants), leaving the original cached file intact.\n * @param parameters Optional fetch parameters such as an `AbortController` signal.\n * @returns Promise with `{ data: { message }, error: null }` on success or `{ data: null, error }` on failure.\n *\n * @example Purge a single cached object\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .purgeCache('folder/avatar1.png')\n * ```\n *\n * @example Purge only transformations for a single object\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .purgeCache('folder/avatar1.png', { transformations: true })\n * ```\n */\n async purgeCache(\n path: string,\n options?: PurgeCacheOptions,\n parameters?: FetchParameters\n ): Promise<\n | {\n data: { message: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n const _path = encodeStoragePath(this._getFinalPath(path))\n const query = new URLSearchParams()\n if (options?.transformations) {\n query.set('transformations', 'true')\n }\n const queryString = query.toString()\n\n return await remove(\n this.fetch,\n `${this.url}/cdn/${_path}${queryString ? `?${queryString}` : ''}`,\n {},\n { headers: this.headers },\n parameters\n )\n })\n }\n\n /**\n * Get file metadata\n * @param id the file id to retrieve metadata\n */\n // async getMetadata(\n // id: string\n // ): Promise<\n // | {\n // data: Metadata\n // error: null\n // }\n // | {\n // data: null\n // error: StorageError\n // }\n // > {\n // try {\n // const data = await get(this.fetch, `${this.url}/metadata/${id}`, { headers: this.headers })\n // return { data, error: null }\n // } catch (error) {\n // if (isStorageError(error)) {\n // return { data: null, error }\n // }\n\n // throw error\n // }\n // }\n\n /**\n * Update file metadata\n * @param id the file id to update metadata\n * @param meta the new file metadata\n */\n // async updateMetadata(\n // id: string,\n // meta: Metadata\n // ): Promise<\n // | {\n // data: Metadata\n // error: null\n // }\n // | {\n // data: null\n // error: StorageError\n // }\n // > {\n // try {\n // const data = await post(\n // this.fetch,\n // `${this.url}/metadata/${id}`,\n // { ...meta },\n // { headers: this.headers }\n // )\n // return { data, error: null }\n // } catch (error) {\n // if (isStorageError(error)) {\n // return { data: null, error }\n // }\n\n // throw error\n // }\n // }\n\n /**\n * Lists all the files and folders within a path of the bucket.\n *\n * **Important:** For folder entries, fields like `id`, `updated_at`, `created_at`,\n * `last_accessed_at`, and `metadata` will be `null`. Only files have these fields populated.\n * Additionally, deprecated fields like `bucket_id`, `owner`, and `buckets` are NOT returned\n * by this method.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param path The folder path.\n * @param options Search options including limit (defaults to 100), offset, sortBy, and search\n * @param parameters Optional fetch parameters including signal for cancellation\n * @returns Promise with response containing array of files/folders or error\n *\n * @example List files in a bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .list('folder', {\n * limit: 100,\n * offset: 0,\n * sortBy: { column: 'name', order: 'asc' },\n * })\n *\n * // Handle files vs folders\n * data?.forEach(item => {\n * if (item.id !== null) {\n * // It's a file\n * console.log('File:', item.name, 'Size:', item.metadata?.size)\n * } else {\n * // It's a folder\n * console.log('Folder:', item.name)\n * }\n * })\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"avatar1.png\",\n * \"id\": \"e668cf7f-821b-4a2f-9dce-7dfa5dd1cfd2\",\n * \"updated_at\": \"2024-05-22T23:06:05.580Z\",\n * \"created_at\": \"2024-05-22T23:04:34.443Z\",\n * \"last_accessed_at\": \"2024-05-22T23:04:34.443Z\",\n * \"metadata\": {\n * \"eTag\": \"\\\"c5e8c553235d9af30ef4f6e280790b92\\\"\",\n * \"size\": 32175,\n * \"mimetype\": \"image/png\",\n * \"cacheControl\": \"max-age=3600\",\n * \"lastModified\": \"2024-05-22T23:06:05.574Z\",\n * \"contentLength\": 32175,\n * \"httpStatusCode\": 200\n * }\n * }\n * ],\n * \"error\": null\n * }\n * ```\n *\n * @example Search files in a bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .list('folder', {\n * limit: 100,\n * offset: 0,\n * sortBy: { column: 'name', order: 'asc' },\n * search: 'jon'\n * })\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: none\n * - `objects` table permissions: `select`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async list(\n path?: string,\n options?: SearchOptions,\n parameters?: FetchParameters\n ): Promise<\n | {\n data: FileObject[]\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n // Deep-merge `sortBy` so overriding only one of its keys (e.g. `column`) keeps the\n // default for the other (e.g. `order`), matching how the top-level defaults behave.\n const sortBy = options?.sortBy\n ? { ...DEFAULT_SEARCH_OPTIONS.sortBy, ...options.sortBy }\n : DEFAULT_SEARCH_OPTIONS.sortBy\n const body = { ...DEFAULT_SEARCH_OPTIONS, ...options, sortBy, prefix: path || '' }\n return await post(\n this.fetch,\n `${this.url}/object/list/${this.bucketId}`,\n body,\n { headers: this.headers },\n parameters\n )\n })\n }\n\n /**\n * Lists all the files and folders within a bucket using the V2 API with pagination support.\n *\n * **Important:** Folder entries in the `folders` array only contain `name` and optionally `key` —\n * they have no `id`, timestamps, or `metadata` fields. Full file metadata is only available\n * on entries in the `objects` array.\n *\n * @experimental this method signature might change in the future\n *\n * @category Storage\n * @subcategory File Buckets\n * @param options Search options including prefix, cursor for pagination, limit, with_delimiter\n * @param parameters Optional fetch parameters including signal for cancellation\n * @returns Promise with response containing folders/objects arrays with pagination info or error\n *\n * @example List files with pagination\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .from('avatars')\n * .listV2({\n * prefix: 'folder/',\n * limit: 100,\n * })\n *\n * // Handle pagination\n * if (data?.hasNext) {\n * const nextPage = await supabase\n * .storage\n * .from('avatars')\n * .listV2({\n * prefix: 'folder/',\n * cursor: data.nextCursor,\n * })\n * }\n *\n * // Handle files vs folders\n * data?.objects.forEach(file => {\n * if (file.id !== null) {\n * console.log('File:', file.name, 'Size:', file.metadata?.size)\n * }\n * })\n * data?.folders.forEach(folder => {\n * console.log('Folder:', folder.name)\n * })\n * ```\n */\n async listV2(\n options?: SearchV2Options,\n parameters?: FetchParameters\n ): Promise<\n | {\n data: SearchV2Result\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n const body = { ...options }\n return await post(\n this.fetch,\n `${this.url}/object/list-v2/${this.bucketId}`,\n body,\n { headers: this.headers },\n parameters\n )\n })\n }\n\n protected encodeMetadata(metadata: Record<string, any>) {\n return JSON.stringify(metadata)\n }\n\n toBase64(data: string) {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(data).toString('base64')\n }\n return btoa(data)\n }\n\n private _getFinalPath(path: string) {\n return `${this.bucketId}/${path.replace(/^\\/+/, '')}`\n }\n\n private _removeEmptyFolders(path: string) {\n return path.replace(/^\\/|\\/$/g, '').replace(/\\/+/g, '/')\n }\n\n /** Modifies the `query`, appending values the from `transform` */\n private applyTransformOptsToQuery(\n query: URLSearchParams,\n transform: TransformOptions\n ): URLSearchParams {\n if (transform.width) query.set('width', transform.width.toString())\n if (transform.height) query.set('height', transform.height.toString())\n if (transform.resize) query.set('resize', transform.resize)\n if (transform.format) query.set('format', transform.format)\n if (transform.quality) query.set('quality', transform.quality.toString())\n\n return query\n }\n}\n","// Generated automatically during releases by scripts/update-version-files.ts\n// This file provides runtime access to the package version for:\n// - HTTP request headers (e.g., X-Client-Info header for API requests)\n// - Debugging and support (identifying which version is running)\n// - Telemetry and logging (version reporting in errors/analytics)\n// - Ensuring build artifacts match the published package version\nexport const version = '2.112.3'\n","import { version } from './version'\nexport const DEFAULT_HEADERS = {\n 'X-Client-Info': `storage-js/${version}`,\n}\n","import { DEFAULT_HEADERS } from '../lib/constants'\nimport { StorageError } from '../lib/common/errors'\nimport { Fetch, get, post, put, remove } from '../lib/common/fetch'\nimport { encodeStoragePath } from '../lib/common/helpers'\nimport BaseApiClient from '../lib/common/BaseApiClient'\nimport {\n Bucket,\n BucketType,\n FetchParameters,\n ListBucketOptions,\n PurgeCacheOptions,\n} from '../lib/types'\nimport { StorageClientOptions } from '../StorageClient'\n\nexport default class StorageBucketApi extends BaseApiClient<StorageError> {\n constructor(\n url: string,\n headers: { [key: string]: string } = {},\n fetch?: Fetch,\n opts?: StorageClientOptions\n ) {\n const baseUrl = new URL(url)\n\n // if legacy uri is used, replace with new storage host (disables request buffering to allow > 50GB uploads)\n // \"project-ref.supabase.co\" becomes \"project-ref.storage.supabase.co\"\n if (opts?.useNewHostname) {\n const isSupabaseHost = /supabase\\.(co|in|red)$/.test(baseUrl.hostname)\n if (isSupabaseHost && !baseUrl.hostname.includes('storage.supabase.')) {\n baseUrl.hostname = baseUrl.hostname.replace('supabase.', 'storage.supabase.')\n }\n }\n\n const finalUrl = baseUrl.href.replace(/\\/$/, '')\n const finalHeaders = { ...DEFAULT_HEADERS, ...headers }\n\n super(finalUrl, finalHeaders, fetch, 'storage')\n }\n\n /**\n * Retrieves the details of all Storage buckets within an existing project.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param options Query parameters for listing buckets\n * @param options.limit Maximum number of buckets to return\n * @param options.offset Number of buckets to skip\n * @param options.sortColumn Column to sort by ('id', 'name', 'created_at', 'updated_at')\n * @param options.sortOrder Sort order ('asc' or 'desc')\n * @param options.search Search term to filter bucket names\n * @returns Promise with response containing array of buckets or error\n *\n * @example List buckets\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .listBuckets()\n * ```\n *\n * @example List buckets with options\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .listBuckets({\n * limit: 10,\n * offset: 0,\n * sortColumn: 'created_at',\n * sortOrder: 'desc',\n * search: 'prod'\n * })\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: `select`\n * - `objects` table permissions: none\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async listBuckets(options?: ListBucketOptions): Promise<\n | {\n data: Bucket[]\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n const queryString = this.listBucketOptionsToQueryString(options)\n return await get(this.fetch, `${this.url}/bucket${queryString}`, {\n headers: this.headers,\n })\n })\n }\n\n /**\n * Retrieves the details of an existing Storage bucket.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param id The unique identifier of the bucket you would like to retrieve.\n * @returns Promise with response containing bucket details or error\n *\n * @example Get bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .getBucket('avatars')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"id\": \"avatars\",\n * \"name\": \"avatars\",\n * \"owner\": \"\",\n * \"public\": false,\n * \"file_size_limit\": 1024,\n * \"allowed_mime_types\": [\n * \"image/png\"\n * ],\n * \"created_at\": \"2024-05-22T22:26:05.100Z\",\n * \"updated_at\": \"2024-05-22T22:26:05.100Z\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: `select`\n * - `objects` table permissions: none\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async getBucket(id: string): Promise<\n | {\n data: Bucket\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await get(this.fetch, `${this.url}/bucket/${id}`, { headers: this.headers })\n })\n }\n\n /**\n * Creates a new Storage bucket\n *\n * @category Storage\n * @subcategory File Buckets\n * @param id A unique identifier for the bucket you are creating.\n * @param options.public The visibility of the bucket. Public buckets don't require an authorization token to download objects, but still require a valid token for all other operations. By default, buckets are private.\n * @param options.fileSizeLimit specifies the max file size in bytes that can be uploaded to this bucket.\n * The global file size limit takes precedence over this value.\n * The default value is null, which doesn't set a per bucket file size limit.\n * @param options.allowedMimeTypes specifies the allowed mime types that this bucket can accept during upload.\n * The default value is null, which allows files with all mime types to be uploaded.\n * Each mime type specified can be a wildcard, e.g. image/*, or a specific mime type, e.g. image/png.\n * @param options.type (private-beta) specifies the bucket type. see `BucketType` for more details.\n * - default bucket type is `STANDARD`\n * @returns Promise with response containing newly created bucket name or error\n *\n * @example Create bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .createBucket('avatars', {\n * public: false,\n * allowedMimeTypes: ['image/png'],\n * fileSizeLimit: 1024\n * })\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"name\": \"avatars\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: `insert`\n * - `objects` table permissions: none\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async createBucket(\n id: string,\n options: {\n public: boolean\n fileSizeLimit?: number | string | null\n allowedMimeTypes?: string[] | null\n type?: BucketType\n } = {\n public: false,\n }\n ): Promise<\n | {\n data: Pick<Bucket, 'name'>\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await post(\n this.fetch,\n `${this.url}/bucket`,\n {\n id,\n name: id,\n type: options.type,\n public: options.public,\n file_size_limit: options.fileSizeLimit,\n allowed_mime_types: options.allowedMimeTypes,\n },\n { headers: this.headers }\n )\n })\n }\n\n /**\n * Updates a Storage bucket\n *\n * @category Storage\n * @subcategory File Buckets\n * @param id A unique identifier for the bucket you are updating.\n * @param options.public The visibility of the bucket. Public buckets don't require an authorization token to download objects, but still require a valid token for all other operations.\n * @param options.fileSizeLimit specifies the max file size in bytes that can be uploaded to this bucket.\n * The global file size limit takes precedence over this value.\n * The default value is null, which doesn't set a per bucket file size limit.\n * @param options.allowedMimeTypes specifies the allowed mime types that this bucket can accept during upload.\n * The default value is null, which allows files with all mime types to be uploaded.\n * Each mime type specified can be a wildcard, e.g. image/*, or a specific mime type, e.g. image/png.\n * @returns Promise with response containing success message or error\n *\n * @example Update bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .updateBucket('avatars', {\n * public: false,\n * allowedMimeTypes: ['image/png'],\n * fileSizeLimit: 1024\n * })\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"message\": \"Successfully updated\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: `select` and `update`\n * - `objects` table permissions: none\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async updateBucket(\n id: string,\n options: {\n public: boolean\n fileSizeLimit?: number | string | null\n allowedMimeTypes?: string[] | null\n }\n ): Promise<\n | {\n data: { message: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await put(\n this.fetch,\n `${this.url}/bucket/${id}`,\n {\n id,\n name: id,\n public: options.public,\n file_size_limit: options.fileSizeLimit,\n allowed_mime_types: options.allowedMimeTypes,\n },\n { headers: this.headers }\n )\n })\n }\n\n /**\n * Removes all objects inside a single bucket.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param id The unique identifier of the bucket you would like to empty.\n * @returns Promise with success message or error\n *\n * @example Empty bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .emptyBucket('avatars')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"message\": \"Successfully emptied\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: `select`\n * - `objects` table permissions: `select` and `delete`\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async emptyBucket(id: string): Promise<\n | {\n data: { message: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await post(this.fetch, `${this.url}/bucket/${id}/empty`, {}, { headers: this.headers })\n })\n }\n\n /**\n * Deletes an existing bucket. A bucket can't be deleted with existing objects inside it.\n * You must first `empty()` the bucket.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param id The unique identifier of the bucket you would like to delete.\n * @returns Promise with success message or error\n *\n * @example Delete bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .deleteBucket('avatars')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"message\": \"Successfully deleted\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - RLS policy permissions required:\n * - `buckets` table permissions: `select` and `delete`\n * - `objects` table permissions: none\n * - Refer to the [Storage guide](/docs/guides/storage/security/access-control) on how access control works\n */\n async deleteBucket(id: string): Promise<\n | {\n data: { message: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await remove(this.fetch, `${this.url}/bucket/${id}`, {}, { headers: this.headers })\n })\n }\n\n /**\n * Purges the CDN cache for an entire bucket.\n *\n * Maps to `DELETE /cdn/{bucket}` on the Storage API. The server\n * issues a CDN invalidation for the bucket and returns `{ message: 'success' }`.\n *\n * **Requires the `service_role` key.** The underlying endpoint enforces\n * `service_role` JWT — calls made with the anon key or a user JWT will be\n * rejected by the server.\n *\n * **Hosted CDN feature.** On self-hosted Supabase, the Storage service must\n * have `CDN_PURGE_ENDPOINT_URL` configured and the `purgeCache` tenant\n * feature enabled, otherwise the server returns an error.\n *\n * @category Storage\n * @subcategory File Buckets\n * @param id The unique identifier of the bucket you would like to purge from cache.\n * @param options Optional purge cache options.\n * @param options.transformations If true, purges only transformations (resized/formatted variants), leaving original cached files intact.\n * @param parameters Optional fetch parameters such as an `AbortController` signal.\n * @returns Promise with `{ data: { message }, error: null }` on success or `{ data: null, error }` on failure.\n *\n * @example Purge cache for an entire bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .purgeBucketCache('avatars')\n * ```\n *\n * @example Purge only transformations for an entire bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .purgeBucketCache('avatars', { transformations: true })\n * ```\n */\n async purgeBucketCache(\n id: string,\n options?: PurgeCacheOptions,\n parameters?: FetchParameters\n ): Promise<\n | {\n data: { message: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n const query = new URLSearchParams()\n if (options?.transformations) {\n query.set('transformations', 'true')\n }\n const queryString = query.toString()\n\n return await remove(\n this.fetch,\n `${this.url}/cdn/${encodeStoragePath(id)}${queryString ? `?${queryString}` : ''}`,\n {},\n { headers: this.headers },\n parameters\n )\n })\n }\n\n private listBucketOptionsToQueryString(options?: ListBucketOptions): string {\n const params: Record<string, string> = {}\n if (options) {\n if ('limit' in options) {\n params.limit = String(options.limit)\n }\n if ('offset' in options) {\n params.offset = String(options.offset)\n }\n if (options.search) {\n params.search = options.search\n }\n if (options.sortColumn) {\n params.sortColumn = options.sortColumn\n }\n if (options.sortOrder) {\n params.sortOrder = options.sortOrder\n }\n }\n return Object.keys(params).length > 0 ? '?' + new URLSearchParams(params).toString() : ''\n }\n}\n","export interface IcebergErrorResponse {\n error: {\n message: string\n type: string\n code: number\n stack?: string[]\n }\n}\n\nexport class IcebergError extends Error {\n readonly status: number\n readonly icebergType?: string\n readonly icebergCode?: number\n readonly details?: unknown\n readonly isCommitStateUnknown: boolean\n\n constructor(\n message: string,\n opts: {\n status: number\n icebergType?: string\n icebergCode?: number\n details?: unknown\n }\n ) {\n super(message)\n this.name = 'IcebergError'\n this.status = opts.status\n this.icebergType = opts.icebergType\n this.icebergCode = opts.icebergCode\n this.details = opts.details\n\n // Detect CommitStateUnknownException by exact type match. The previous\n // `includes('CommitState')` substring check would false-positive on\n // unrelated exception types and is not a thing the spec defines.\n this.isCommitStateUnknown = opts.icebergType === 'CommitStateUnknownException'\n }\n\n /**\n * Returns true if the error is a 404 Not Found error.\n */\n isNotFound(): boolean {\n return this.status === 404\n }\n\n /**\n * Returns true if the error is a 409 Conflict error.\n */\n isConflict(): boolean {\n return this.status === 409\n }\n\n /**\n * Returns true if the error is a 419 Authentication Timeout error.\n */\n isAuthenticationTimeout(): boolean {\n return this.status === 419\n }\n}\n","export function buildUrl(\n baseUrl: string,\n path: string,\n query?: Record<string, string | undefined>\n): string {\n const url = new URL(path, baseUrl)\n\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value !== undefined) {\n url.searchParams.set(key, value)\n }\n }\n }\n\n return url.toString()\n}\n","import { IcebergError, type IcebergErrorResponse } from '../errors/IcebergError'\nimport { buildUrl } from '../utils/url'\nimport type { AuthConfig, HttpClient, HttpRequest, HttpResponse } from './types'\n\nasync function buildAuthHeaders(auth?: AuthConfig): Promise<Record<string, string>> {\n if (!auth || auth.type === 'none') {\n return {}\n }\n\n if (auth.type === 'bearer') {\n return { Authorization: `Bearer ${auth.token}` }\n }\n\n if (auth.type === 'header') {\n return { [auth.name]: auth.value }\n }\n\n if (auth.type === 'custom') {\n return await auth.getHeaders()\n }\n\n return {}\n}\n\nexport function createFetchClient(options: {\n baseUrl: string\n auth?: AuthConfig\n fetchImpl?: typeof fetch\n}): HttpClient {\n const fetchFn = options.fetchImpl ?? globalThis.fetch\n\n return {\n async request<T>({\n method,\n path,\n query,\n body,\n headers,\n }: HttpRequest): Promise<HttpResponse<T>> {\n const url = buildUrl(options.baseUrl, path, query)\n const authHeaders = await buildAuthHeaders(options.auth)\n\n let res: Response\n try {\n res = await fetchFn(url, {\n method,\n headers: {\n ...(body ? { 'Content-Type': 'application/json' } : {}),\n ...authHeaders,\n ...headers,\n },\n body: body ? JSON.stringify(body) : undefined,\n })\n } catch (err) {\n // Network-level failure (DNS, TLS, offline, AbortError, …). Surface\n // it as IcebergError with status: 0 so consumers can rely on a single\n // error class for everything from the client.\n if (err instanceof IcebergError) throw err\n const message = err instanceof Error ? err.message : String(err)\n throw new IcebergError(`Network request failed: ${message}`, {\n status: 0,\n details: err,\n })\n }\n\n // 304 Not Modified is a valid response for conditional GETs (If-None-Match).\n // Return early so callers can detect it without throwing.\n if (res.status === 304) {\n return { status: 304, headers: res.headers, data: undefined as T }\n }\n\n const text = await res.text()\n const isJson = (res.headers.get('content-type') || '').includes('application/json')\n const data = isJson && text ? (JSON.parse(text) as T) : (text as T)\n\n if (!res.ok) {\n const errBody = isJson ? (data as IcebergErrorResponse) : undefined\n const errorDetail = errBody?.error\n throw new IcebergError(errorDetail?.message ?? `Request failed with status ${res.status}`, {\n status: res.status,\n icebergType: errorDetail?.type,\n icebergCode: errorDetail?.code,\n details: errBody,\n })\n }\n\n return { status: res.status, headers: res.headers, data: data as T }\n },\n }\n}\n","/**\n * Generate an RFC 9562 UUIDv7 string.\n *\n * The Iceberg REST spec defines `Idempotency-Key` as a UUID format,\n * with the example payloads showing UUIDv7 (timestamp-prefixed). UUIDv7\n * is preferred because keys are roughly time-orderable, which makes\n * server-side dedup windows simpler to reason about.\n *\n * Layout (RFC 9562 §5.7):\n * 48-bit unix-ms timestamp | 4-bit version (0111) | 12-bit rand_a\n * 2-bit variant (10) | 62-bit rand_b\n */\nexport function generateIdempotencyKey(): string {\n const ms = BigInt(Date.now())\n const bytes = new Uint8Array(16)\n\n // 48 bits of unix-ms timestamp (big-endian)\n bytes[0] = Number((ms >> 40n) & 0xffn)\n bytes[1] = Number((ms >> 32n) & 0xffn)\n bytes[2] = Number((ms >> 24n) & 0xffn)\n bytes[3] = Number((ms >> 16n) & 0xffn)\n bytes[4] = Number((ms >> 8n) & 0xffn)\n bytes[5] = Number(ms & 0xffn)\n\n // 10 bytes of randomness\n const rand = new Uint8Array(10)\n cryptoRandom(rand)\n bytes.set(rand, 6)\n\n // Version (0111) in the high nibble of byte 6\n bytes[6] = (bytes[6] & 0x0f) | 0x70\n // Variant (10) in the high two bits of byte 8\n bytes[8] = (bytes[8] & 0x3f) | 0x80\n\n return formatUUID(bytes)\n}\n\nfunction formatUUID(b: Uint8Array): string {\n const hex: string[] = []\n for (let i = 0; i < 16; i++) {\n hex.push(b[i].toString(16).padStart(2, '0'))\n }\n return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex.slice(6, 8).join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10, 16).join('')}`\n}\n\nfunction cryptoRandom(buf: Uint8Array): void {\n const c =\n typeof globalThis.crypto !== 'undefined' &&\n typeof globalThis.crypto.getRandomValues === 'function'\n ? globalThis.crypto\n : undefined\n if (c) {\n c.getRandomValues(buf)\n return\n }\n // Fallback: should not happen in supported environments (Node 20+, modern browsers).\n for (let i = 0; i < buf.length; i++) {\n buf[i] = Math.floor(Math.random() * 256)\n }\n}\n","import type { HttpClient } from '../http/types'\nimport { IcebergError } from '../errors/IcebergError'\nimport { generateIdempotencyKey } from '../utils/idempotency-key'\nimport type {\n CreateNamespaceRequest,\n CreateNamespaceResponse,\n GetNamespaceResponse,\n ListNamespacesOptions,\n ListNamespacesResponse,\n ListNamespacesResult,\n NamespaceIdentifier,\n NamespaceMetadata,\n UpdateNamespacePropertiesRequest,\n UpdateNamespacePropertiesResponse,\n} from './types'\n\n/**\n * Encode a multipart namespace for use as a single URL path segment.\n *\n * Each part is encoded with `encodeURIComponent` (so `/`, `?`, `#`, `%` etc.\n * inside a part survive intact), and parts are joined with the literal `%1F`\n * separator the spec calls for. Note: relying on the URL constructor to\n * encode a raw `\\x1F` byte does the right thing for the separator but does\n * NOT encode `/`, `?`, `#`, `%` inside a part — hence the per-part\n * `encodeURIComponent` here.\n *\n * For the `parent` *query* parameter (not path), the raw `\\x1F` join is the\n * correct input — `URLSearchParams.set` percent-encodes it to `%1F` and\n * pre-encoding would double-encode the `%` to `%25`.\n */\nfunction namespaceToPath(namespace: string[]): string {\n return namespace.map(encodeURIComponent).join('%1F')\n}\n\nfunction namespaceToParentQuery(namespace: string[]): string {\n // Raw 0x1F — URLSearchParams encodes to %1F. Do NOT pre-encode parts here.\n return namespace.join('\\x1F')\n}\n\n/**\n * A prefix resolver. Operations classes accept this so the catalog can defer\n * the choice of path prefix until /v1/config has been fetched (the spec\n * recommends warehouse → server-returned `prefix` over hardcoded names).\n *\n * For simple usage and tests, pass a string and it'll be wrapped automatically.\n */\nexport type PrefixResolver = string | (() => string | Promise<string>)\n\nasync function resolvePrefix(p: PrefixResolver): Promise<string> {\n return typeof p === 'string' ? p : p()\n}\n\nexport class NamespaceOperations {\n constructor(\n private readonly client: HttpClient,\n private readonly prefix: PrefixResolver = ''\n ) {}\n\n async listNamespaces(options: ListNamespacesOptions = {}): Promise<ListNamespacesResult> {\n const prefix = await resolvePrefix(this.prefix)\n\n const query: Record<string, string | undefined> = {}\n if (options.parent) query.parent = namespaceToParentQuery(options.parent.namespace)\n if (options.pageToken !== undefined) query.pageToken = options.pageToken\n if (options.pageSize !== undefined) query.pageSize = String(options.pageSize)\n const hasQuery = Object.keys(query).some((k) => query[k] !== undefined)\n\n const response = await this.client.request<ListNamespacesResponse>({\n method: 'GET',\n path: `${prefix}/namespaces`,\n query: hasQuery ? query : undefined,\n })\n\n return {\n namespaces: (response.data.namespaces ?? []).map((ns) => ({ namespace: ns })),\n nextPageToken: response.data['next-page-token'] ?? undefined,\n }\n }\n\n async createNamespace(\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata\n ): Promise<CreateNamespaceResponse> {\n const prefix = await resolvePrefix(this.prefix)\n const request: CreateNamespaceRequest = {\n namespace: id.namespace,\n properties: metadata?.properties,\n }\n\n const response = await this.client.request<CreateNamespaceResponse>({\n method: 'POST',\n path: `${prefix}/namespaces`,\n body: request,\n headers: { 'Idempotency-Key': generateIdempotencyKey() },\n })\n\n return response.data\n }\n\n async dropNamespace(id: NamespaceIdentifier): Promise<void> {\n const prefix = await resolvePrefix(this.prefix)\n await this.client.request<void>({\n method: 'DELETE',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}`,\n headers: { 'Idempotency-Key': generateIdempotencyKey() },\n })\n }\n\n async loadNamespaceMetadata(id: NamespaceIdentifier): Promise<NamespaceMetadata> {\n const prefix = await resolvePrefix(this.prefix)\n const response = await this.client.request<GetNamespaceResponse>({\n method: 'GET',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}`,\n })\n\n return {\n properties: response.data.properties ?? {},\n }\n }\n\n async namespaceExists(id: NamespaceIdentifier): Promise<boolean> {\n const prefix = await resolvePrefix(this.prefix)\n try {\n await this.client.request<void>({\n method: 'HEAD',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}`,\n })\n return true\n } catch (error) {\n if (error instanceof IcebergError && error.status === 404) {\n return false\n }\n throw error\n }\n }\n\n async updateNamespaceProperties(\n id: NamespaceIdentifier,\n request: UpdateNamespacePropertiesRequest\n ): Promise<UpdateNamespacePropertiesResponse> {\n const prefix = await resolvePrefix(this.prefix)\n const response = await this.client.request<UpdateNamespacePropertiesResponse>({\n method: 'POST',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}/properties`,\n body: request,\n headers: { 'Idempotency-Key': generateIdempotencyKey() },\n })\n return response.data\n }\n\n async createNamespaceIfNotExists(\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata\n ): Promise<CreateNamespaceResponse | void> {\n try {\n return await this.createNamespace(id, metadata)\n } catch (error) {\n if (error instanceof IcebergError && error.status === 409) {\n return\n }\n throw error\n }\n }\n}\n","import type { HttpClient } from '../http/types'\nimport { IcebergError } from '../errors/IcebergError'\nimport { generateIdempotencyKey } from '../utils/idempotency-key'\nimport type { PrefixResolver } from './namespaces'\nimport type {\n CommitTableRequest,\n CommitTableResponse,\n CreateTableRequest,\n DropTableRequest,\n ListTablesOptions,\n ListTablesResponse,\n ListTablesResult,\n LoadTableOptions,\n LoadTableResponse,\n LoadTableResultWithEtag,\n NamespaceIdentifier,\n RegisterTableRequest,\n RenameTableRequest,\n TableIdentifier,\n TableMetadata,\n UpdateTableRequest,\n} from './types'\n\nfunction namespaceToPath(namespace: string[]): string {\n return namespace.map(encodeURIComponent).join('%1F')\n}\n\nfunction tableSegment(name: string): string {\n return encodeURIComponent(name)\n}\n\nasync function resolvePrefix(p: PrefixResolver): Promise<string> {\n return typeof p === 'string' ? p : p()\n}\n\nexport class TableOperations {\n constructor(\n private readonly client: HttpClient,\n private readonly prefix: PrefixResolver = '',\n private readonly accessDelegation?: string\n ) {}\n\n async listTables(\n namespace: NamespaceIdentifier,\n options: ListTablesOptions = {}\n ): Promise<ListTablesResult> {\n const prefix = await resolvePrefix(this.prefix)\n const query: Record<string, string | undefined> = {}\n if (options.pageToken !== undefined) query.pageToken = options.pageToken\n if (options.pageSize !== undefined) query.pageSize = String(options.pageSize)\n const hasQuery = Object.keys(query).some((k) => query[k] !== undefined)\n\n const response = await this.client.request<ListTablesResponse>({\n method: 'GET',\n path: `${prefix}/namespaces/${namespaceToPath(namespace.namespace)}/tables`,\n query: hasQuery ? query : undefined,\n })\n\n return {\n identifiers: response.data.identifiers ?? [],\n nextPageToken: response.data['next-page-token'] ?? undefined,\n }\n }\n\n async createTable(\n namespace: NamespaceIdentifier,\n request: CreateTableRequest\n ): Promise<TableMetadata> {\n const result = await this.createTableResult(namespace, request)\n return result.metadata\n }\n\n /**\n * Spec-aligned `LoadTableResult` wrapper for create. Returns the full server\n * response (metadata, metadata-location, config, storage-credentials) plus\n * the captured ETag header. Use this when `accessDelegation` is set so the\n * server-vended credentials are reachable.\n */\n async createTableResult(\n namespace: NamespaceIdentifier,\n request: CreateTableRequest\n ): Promise<LoadTableResultWithEtag> {\n const prefix = await resolvePrefix(this.prefix)\n const headers: Record<string, string> = { 'Idempotency-Key': generateIdempotencyKey() }\n if (this.accessDelegation) {\n headers['X-Iceberg-Access-Delegation'] = this.accessDelegation\n }\n\n const response = await this.client.request<LoadTableResponse>({\n method: 'POST',\n path: `${prefix}/namespaces/${namespaceToPath(namespace.namespace)}/tables`,\n body: request,\n headers,\n })\n\n return {\n ...response.data,\n etag: response.headers.get('etag'),\n }\n }\n\n async updateTable(\n id: TableIdentifier,\n request: UpdateTableRequest\n ): Promise<CommitTableResponse> {\n const prefix = await resolvePrefix(this.prefix)\n const response = await this.client.request<LoadTableResponse>({\n method: 'POST',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}/tables/${tableSegment(id.name)}`,\n body: request,\n headers: { 'Idempotency-Key': generateIdempotencyKey() },\n })\n\n const metadataLocation = response.data['metadata-location']\n if (!metadataLocation) {\n // Spec requires both `metadata` and `metadata-location` on\n // CommitTableResponse. A 200 without `metadata-location` means the\n // server is misbehaving; surface it instead of silently returning ''.\n throw new IcebergError(\n 'Server returned 200 without required `metadata-location` field on CommitTableResponse',\n { status: response.status, details: response.data }\n )\n }\n\n return {\n 'metadata-location': metadataLocation,\n metadata: response.data.metadata,\n }\n }\n\n /** Spec-aligned alias for {@link updateTable}. */\n async commitTable(\n id: TableIdentifier,\n request: CommitTableRequest\n ): Promise<CommitTableResponse> {\n return this.updateTable(id, request)\n }\n\n async dropTable(id: TableIdentifier, options?: DropTableRequest): Promise<void> {\n const prefix = await resolvePrefix(this.prefix)\n await this.client.request<void>({\n method: 'DELETE',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}/tables/${tableSegment(id.name)}`,\n query: { purgeRequested: String(options?.purge ?? false) },\n headers: { 'Idempotency-Key': generateIdempotencyKey() },\n })\n }\n\n async loadTable(id: TableIdentifier): Promise<TableMetadata>\n async loadTable(id: TableIdentifier, options: LoadTableOptions): Promise<TableMetadata | null>\n async loadTable(id: TableIdentifier, options?: LoadTableOptions): Promise<TableMetadata | null> {\n const result = await this.loadTableResult(id, options)\n return result ? result.metadata : null\n }\n\n /**\n * Spec-aligned `LoadTableResult` wrapper. Returns the full server response\n * (metadata, metadata-location, config, storage-credentials) plus the captured\n * ETag header. Returns `null` when an `ifNoneMatch` was supplied and the server\n * answered 304.\n */\n async loadTableResult(\n id: TableIdentifier,\n options?: LoadTableOptions\n ): Promise<LoadTableResultWithEtag | null> {\n const prefix = await resolvePrefix(this.prefix)\n const headers: Record<string, string> = {}\n if (this.accessDelegation) {\n headers['X-Iceberg-Access-Delegation'] = this.accessDelegation\n }\n if (options?.ifNoneMatch) {\n headers['If-None-Match'] = options.ifNoneMatch\n }\n const query: Record<string, string | undefined> = {}\n if (options?.snapshots) query.snapshots = options.snapshots\n\n const response = await this.client.request<LoadTableResponse>({\n method: 'GET',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}/tables/${tableSegment(id.name)}`,\n headers,\n query: Object.keys(query).length ? query : undefined,\n })\n\n if (response.status === 304) {\n return null\n }\n\n return {\n ...response.data,\n etag: response.headers.get('etag'),\n }\n }\n\n async tableExists(id: TableIdentifier): Promise<boolean> {\n const prefix = await resolvePrefix(this.prefix)\n const headers: Record<string, string> = {}\n if (this.accessDelegation) {\n headers['X-Iceberg-Access-Delegation'] = this.accessDelegation\n }\n\n try {\n await this.client.request<void>({\n method: 'HEAD',\n path: `${prefix}/namespaces/${namespaceToPath(id.namespace)}/tables/${tableSegment(id.name)}`,\n headers,\n })\n return true\n } catch (error) {\n if (error instanceof IcebergError && error.status === 404) {\n return false\n }\n throw error\n }\n }\n\n async registerTable(\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest\n ): Promise<TableMetadata> {\n const result = await this.registerTableResult(namespace, request)\n return result.metadata\n }\n\n async registerTableResult(\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest\n ): Promise<LoadTableResultWithEtag> {\n const prefix = await resolvePrefix(this.prefix)\n const headers: Record<string, string> = { 'Idempotency-Key': generateIdempotencyKey() }\n if (this.accessDelegation) {\n headers['X-Iceberg-Access-Delegation'] = this.accessDelegation\n }\n const response = await this.client.request<LoadTableResponse>({\n method: 'POST',\n path: `${prefix}/namespaces/${namespaceToPath(namespace.namespace)}/register`,\n body: request,\n headers,\n })\n return {\n ...response.data,\n etag: response.headers.get('etag'),\n }\n }\n\n async renameTable(request: RenameTableRequest): Promise<void> {\n const prefix = await resolvePrefix(this.prefix)\n await this.client.request<void>({\n method: 'POST',\n path: `${prefix}/tables/rename`,\n body: request,\n headers: { 'Idempotency-Key': generateIdempotencyKey() },\n })\n }\n\n async createTableIfNotExists(\n namespace: NamespaceIdentifier,\n request: CreateTableRequest\n ): Promise<TableMetadata> {\n try {\n return await this.createTable(namespace, request)\n } catch (error) {\n if (error instanceof IcebergError && error.status === 409) {\n return await this.loadTable({ namespace: namespace.namespace, name: request.name })\n }\n throw error\n }\n }\n}\n","import { createFetchClient } from '../http/createFetchClient'\nimport type { AuthConfig, HttpClient } from '../http/types'\nimport { NamespaceOperations } from './namespaces'\nimport { TableOperations } from './tables'\nimport type {\n CatalogConfig,\n CommitTableRequest,\n CommitTableResponse,\n CreateNamespaceResponse,\n CreateTableRequest,\n DropTableRequest,\n ListNamespacesOptions,\n ListNamespacesResult,\n ListTablesOptions,\n ListTablesResult,\n LoadTableOptions,\n LoadTableResultWithEtag,\n NamespaceIdentifier,\n NamespaceMetadata,\n RegisterTableRequest,\n RenameTableRequest,\n TableIdentifier,\n TableMetadata,\n UpdateNamespacePropertiesRequest,\n UpdateNamespacePropertiesResponse,\n UpdateTableRequest,\n} from './types'\n\n/**\n * Access delegation mechanisms supported by the Iceberg REST Catalog.\n *\n * - `vended-credentials`: Server provides temporary credentials for data access\n * - `remote-signing`: Server signs requests on behalf of the client\n */\nexport type AccessDelegation = 'vended-credentials' | 'remote-signing'\n\n/**\n * Configuration options for the Iceberg REST Catalog client.\n */\nexport interface IcebergRestCatalogOptions {\n /** Base URL of the Iceberg REST Catalog API */\n baseUrl: string\n /**\n * Warehouse identifier. The client passes this to `GET /v1/config?warehouse=…`\n * on first use; the server-returned `overrides.prefix` is then used for all\n * subsequent requests. This is the spec-recommended way to address a warehouse\n * (e.g., a Cloudflare R2 bucket) and replaces the older `catalogName` flow.\n */\n warehouse?: string\n /**\n * Alias for {@link warehouse} kept for backward compatibility. If both are\n * set, `warehouse` wins.\n */\n catalogName?: string\n /** Authentication configuration */\n auth?: AuthConfig\n /** Custom fetch implementation (defaults to globalThis.fetch) */\n fetch?: typeof fetch\n /**\n * Access delegation mechanisms to request from the server.\n * When specified, the X-Iceberg-Access-Delegation header will be sent\n * with supported operations (createTable, loadTable).\n *\n * @example ['vended-credentials']\n * @example ['vended-credentials', 'remote-signing']\n */\n accessDelegation?: AccessDelegation[]\n}\n\n/**\n * Client for interacting with an Apache Iceberg REST Catalog.\n *\n * This class provides methods for managing namespaces and tables in an Iceberg catalog.\n * It handles authentication, request formatting, and error handling automatically.\n *\n * @example\n * ```typescript\n * const catalog = new IcebergRestCatalog({\n * baseUrl: 'https://my-catalog.example.com',\n * warehouse: 'my-warehouse',\n * auth: { type: 'bearer', token: process.env.ICEBERG_TOKEN }\n * });\n *\n * // First call lazily fetches /v1/config?warehouse=my-warehouse\n * await catalog.createNamespace({ namespace: ['analytics'] });\n * ```\n */\nexport class IcebergRestCatalog {\n private readonly client: HttpClient\n private readonly namespaceOps: NamespaceOperations\n private readonly tableOps: TableOperations\n private readonly accessDelegation?: string\n private readonly warehouse?: string\n\n private prefixPromise?: Promise<string>\n private cachedConfigPromise?: Promise<CatalogConfig>\n\n /**\n * Creates a new Iceberg REST Catalog client.\n *\n * @param options - Configuration options for the catalog client\n */\n constructor(options: IcebergRestCatalogOptions) {\n const baseUrl = options.baseUrl.endsWith('/') ? options.baseUrl : `${options.baseUrl}/`\n\n this.warehouse = options.warehouse ?? options.catalogName\n\n this.client = createFetchClient({\n baseUrl,\n auth: options.auth,\n fetchImpl: options.fetch,\n })\n\n // Format accessDelegation as comma-separated string per spec\n this.accessDelegation = options.accessDelegation?.join(',')\n\n const getPrefix = () => this.resolvePrefix()\n this.namespaceOps = new NamespaceOperations(this.client, getPrefix)\n this.tableOps = new TableOperations(this.client, getPrefix, this.accessDelegation)\n }\n\n /**\n * Fetch and cache the server's catalog configuration. Subsequent calls return\n * the same object. Calling this is optional — operations will trigger it\n * lazily on first use.\n *\n * Caches the in-flight promise (not just the resolved value) so concurrent\n * first-callers don't all fire their own `/v1/config` request.\n */\n async loadConfig(): Promise<CatalogConfig> {\n if (!this.cachedConfigPromise) {\n const query: Record<string, string | undefined> = {}\n if (this.warehouse !== undefined) query.warehouse = this.warehouse\n this.cachedConfigPromise = this.client\n .request<CatalogConfig>({\n method: 'GET',\n path: 'v1/config',\n query: Object.keys(query).length ? query : undefined,\n })\n .then((response) => response.data)\n .catch((err) => {\n // Don't cache failures — the next caller deserves to try again.\n this.cachedConfigPromise = undefined\n throw err\n })\n }\n return this.cachedConfigPromise\n }\n\n private async resolvePrefix(): Promise<string> {\n if (!this.prefixPromise) {\n this.prefixPromise = this.computePrefix()\n }\n return this.prefixPromise\n }\n\n private async computePrefix(): Promise<string> {\n if (this.warehouse === undefined) {\n // No warehouse → no /config call. Use plain `v1` prefix.\n return 'v1'\n }\n try {\n const config = await this.loadConfig()\n const serverPrefix = config.overrides?.prefix ?? config.defaults?.prefix\n return serverPrefix ? `v1/${serverPrefix}` : `v1/${this.warehouse}`\n } catch {\n // /config is optional in some deployments; fall back to using the\n // warehouse as a literal path segment (matches the legacy catalogName\n // behavior).\n return `v1/${this.warehouse}`\n }\n }\n\n /**\n * Lists all namespaces in the catalog.\n *\n * @returns Paginated namespace list with optional `nextPageToken`\n *\n * @example\n * ```typescript\n * const { namespaces } = await catalog.listNamespaces();\n *\n * // List children under a parent\n * const { namespaces: children } = await catalog.listNamespaces({\n * parent: { namespace: ['analytics'] },\n * });\n *\n * // Paginate\n * const page1 = await catalog.listNamespaces({ pageSize: 100 });\n * const page2 = await catalog.listNamespaces({ pageSize: 100, pageToken: page1.nextPageToken });\n * ```\n */\n async listNamespaces(options: ListNamespacesOptions = {}): Promise<ListNamespacesResult> {\n return this.namespaceOps.listNamespaces(options)\n }\n\n /**\n * Creates a new namespace in the catalog.\n */\n async createNamespace(\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata\n ): Promise<CreateNamespaceResponse> {\n return this.namespaceOps.createNamespace(id, metadata)\n }\n\n /**\n * Drops a namespace from the catalog.\n *\n * The namespace must be empty (contain no tables) before it can be dropped.\n */\n async dropNamespace(id: NamespaceIdentifier): Promise<void> {\n await this.namespaceOps.dropNamespace(id)\n }\n\n /**\n * Loads metadata for a namespace.\n */\n async loadNamespaceMetadata(id: NamespaceIdentifier): Promise<NamespaceMetadata> {\n return this.namespaceOps.loadNamespaceMetadata(id)\n }\n\n /**\n * Set or remove properties on a namespace.\n */\n async updateNamespaceProperties(\n id: NamespaceIdentifier,\n request: UpdateNamespacePropertiesRequest\n ): Promise<UpdateNamespacePropertiesResponse> {\n return this.namespaceOps.updateNamespaceProperties(id, request)\n }\n\n /**\n * Lists tables in a namespace.\n *\n * @returns Paginated table list with optional `nextPageToken`\n */\n async listTables(\n namespace: NamespaceIdentifier,\n options: ListTablesOptions = {}\n ): Promise<ListTablesResult> {\n return this.tableOps.listTables(namespace, options)\n }\n\n /**\n * Creates a new table in the catalog.\n */\n async createTable(\n namespace: NamespaceIdentifier,\n request: CreateTableRequest\n ): Promise<TableMetadata> {\n return this.tableOps.createTable(namespace, request)\n }\n\n /**\n * Spec-aligned `LoadTableResult` wrapper for create. Returns the full server\n * response (metadata, metadata-location, server `config`, `storage-credentials`)\n * plus the captured ETag. Use this when `accessDelegation` is set so the\n * server-vended credentials are reachable.\n */\n async createTableResult(\n namespace: NamespaceIdentifier,\n request: CreateTableRequest\n ): Promise<LoadTableResultWithEtag> {\n return this.tableOps.createTableResult(namespace, request)\n }\n\n /**\n * Commit updates to a table using the spec-aligned `{ requirements, updates }` shape.\n *\n * @example\n * ```typescript\n * await catalog.updateTable(\n * { namespace: ['analytics'], name: 'events' },\n * {\n * requirements: [],\n * updates: [{ action: 'set-properties', updates: { 'read.split.target-size': '134217728' } }],\n * },\n * );\n * ```\n */\n async updateTable(\n id: TableIdentifier,\n request: UpdateTableRequest\n ): Promise<CommitTableResponse> {\n return this.tableOps.updateTable(id, request)\n }\n\n /** Spec-aligned alias for {@link updateTable}. */\n async commitTable(\n id: TableIdentifier,\n request: CommitTableRequest\n ): Promise<CommitTableResponse> {\n return this.tableOps.commitTable(id, request)\n }\n\n /**\n * Drops a table from the catalog.\n */\n async dropTable(id: TableIdentifier, options?: DropTableRequest): Promise<void> {\n await this.tableOps.dropTable(id, options)\n }\n\n /**\n * Loads metadata for a table.\n *\n * Pass `ifNoneMatch` (a previous ETag) to perform a conditional GET. If the\n * server returns 304 Not Modified, the method returns `null`.\n */\n async loadTable(id: TableIdentifier): Promise<TableMetadata>\n async loadTable(id: TableIdentifier, options: LoadTableOptions): Promise<TableMetadata | null>\n async loadTable(id: TableIdentifier, options?: LoadTableOptions): Promise<TableMetadata | null> {\n return options ? this.tableOps.loadTable(id, options) : this.tableOps.loadTable(id)\n }\n\n /**\n * Spec-aligned `LoadTableResult` wrapper, including server `config`,\n * `storage-credentials`, and the response `ETag`. Returns `null` on 304.\n */\n async loadTableResult(\n id: TableIdentifier,\n options?: LoadTableOptions\n ): Promise<LoadTableResultWithEtag | null> {\n return this.tableOps.loadTableResult(id, options)\n }\n\n /**\n * Checks if a namespace exists in the catalog.\n */\n async namespaceExists(id: NamespaceIdentifier): Promise<boolean> {\n return this.namespaceOps.namespaceExists(id)\n }\n\n /**\n * Checks if a table exists in the catalog.\n */\n async tableExists(id: TableIdentifier): Promise<boolean> {\n return this.tableOps.tableExists(id)\n }\n\n /**\n * Creates a namespace if it does not exist.\n */\n async createNamespaceIfNotExists(\n id: NamespaceIdentifier,\n metadata?: NamespaceMetadata\n ): Promise<CreateNamespaceResponse | void> {\n return this.namespaceOps.createNamespaceIfNotExists(id, metadata)\n }\n\n /**\n * Creates a table if it does not exist.\n */\n async createTableIfNotExists(\n namespace: NamespaceIdentifier,\n request: CreateTableRequest\n ): Promise<TableMetadata> {\n return this.tableOps.createTableIfNotExists(namespace, request)\n }\n\n /**\n * Register an existing metadata file as a table in the given namespace.\n */\n async registerTable(\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest\n ): Promise<TableMetadata> {\n return this.tableOps.registerTable(namespace, request)\n }\n\n /**\n * Spec-aligned `LoadTableResult` wrapper for register.\n */\n async registerTableResult(\n namespace: NamespaceIdentifier,\n request: RegisterTableRequest\n ): Promise<LoadTableResultWithEtag> {\n return this.tableOps.registerTableResult(namespace, request)\n }\n\n /**\n * Rename a table. Servers may or may not support cross-namespace renames.\n */\n async renameTable(request: RenameTableRequest): Promise<void> {\n return this.tableOps.renameTable(request)\n }\n}\n","export interface NamespaceIdentifier {\n namespace: string[]\n}\n\nexport interface NamespaceMetadata {\n properties: Record<string, string>\n}\n\nexport interface TableIdentifier {\n namespace: string[]\n name: string\n}\n\n/**\n * Primitive types in Iceberg - all represented as strings.\n * Parameterized types use string format: decimal(precision,scale) and fixed[length]\n *\n * Note: The OpenAPI spec defines PrimitiveType as `type: string`, so any string is valid.\n * We include known types for autocomplete, plus a catch-all for flexibility.\n */\nexport type PrimitiveType =\n | 'boolean'\n | 'int'\n | 'long'\n | 'float'\n | 'double'\n | 'string'\n | 'timestamp'\n | 'date'\n | 'time'\n | 'timestamptz'\n | 'uuid'\n | 'binary'\n | `decimal(${number},${number})`\n | `fixed[${number}]`\n | (string & {}) // catch-all for any format (e.g., \"decimal(10, 2)\" with spaces) and future types\n\n/**\n * Regex patterns for parsing parameterized types.\n * These allow flexible whitespace matching.\n */\nconst DECIMAL_REGEX = /^decimal\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/\nconst FIXED_REGEX = /^fixed\\s*\\[\\s*(\\d+)\\s*\\]$/\n\n/**\n * Parse a decimal type string into its components.\n * Handles any whitespace formatting (e.g., \"decimal(10,2)\", \"decimal(10, 2)\", \"decimal( 10 , 2 )\").\n *\n * @param type - The type string to parse\n * @returns Object with precision and scale, or null if not a valid decimal type\n */\nexport function parseDecimalType(type: string): { precision: number; scale: number } | null {\n const match = type.match(DECIMAL_REGEX)\n if (!match) return null\n return {\n precision: parseInt(match[1], 10),\n scale: parseInt(match[2], 10),\n }\n}\n\n/**\n * Parse a fixed type string into its length.\n * Handles any whitespace formatting (e.g., \"fixed[16]\", \"fixed[ 16 ]\").\n *\n * @param type - The type string to parse\n * @returns Object with length, or null if not a valid fixed type\n */\nexport function parseFixedType(type: string): { length: number } | null {\n const match = type.match(FIXED_REGEX)\n if (!match) return null\n return {\n length: parseInt(match[1], 10),\n }\n}\n\n/**\n * Check if a type string is a decimal type.\n */\nexport function isDecimalType(type: string): boolean {\n return DECIMAL_REGEX.test(type)\n}\n\n/**\n * Check if a type string is a fixed type.\n */\nexport function isFixedType(type: string): boolean {\n return FIXED_REGEX.test(type)\n}\n\n/**\n * Compare two Iceberg type strings for equality, ignoring whitespace differences.\n * This is useful when comparing types from user input vs catalog responses,\n * as catalogs may normalize whitespace differently.\n *\n * @param a - First type string\n * @param b - Second type string\n * @returns true if the types are equivalent\n */\nexport function typesEqual(a: string, b: string): boolean {\n // For decimal types, compare parsed values\n const decimalA = parseDecimalType(a)\n const decimalB = parseDecimalType(b)\n if (decimalA && decimalB) {\n return decimalA.precision === decimalB.precision && decimalA.scale === decimalB.scale\n }\n\n // For fixed types, compare parsed values\n const fixedA = parseFixedType(a)\n const fixedB = parseFixedType(b)\n if (fixedA && fixedB) {\n return fixedA.length === fixedB.length\n }\n\n // For other types, direct string comparison\n return a === b\n}\n\n/**\n * Struct type - a nested structure containing fields.\n * Used for nested records within a field.\n */\nexport interface StructType {\n type: 'struct'\n fields: StructField[]\n}\n\n/**\n * List type - an array of elements.\n */\nexport interface ListType {\n type: 'list'\n 'element-id': number\n element: IcebergType\n 'element-required': boolean\n}\n\n/**\n * Map type - a key-value mapping.\n */\nexport interface MapType {\n type: 'map'\n 'key-id': number\n key: IcebergType\n 'value-id': number\n value: IcebergType\n 'value-required': boolean\n}\n\n/**\n * Union of all Iceberg types.\n * Can be a primitive type (string) or a complex type (struct, list, map).\n */\nexport type IcebergType = PrimitiveType | StructType | ListType | MapType\n\n/**\n * Primitive type values for default values.\n * Represents the possible values for initial-default and write-default.\n */\nexport type PrimitiveTypeValue = boolean | number | string\n\n/**\n * A field within a struct (used in nested StructType).\n */\nexport interface StructField {\n id: number\n name: string\n type: IcebergType\n required: boolean\n doc?: string\n 'initial-default'?: PrimitiveTypeValue\n 'write-default'?: PrimitiveTypeValue\n}\n\n/**\n * A field within a table schema (top-level).\n * Equivalent to StructField but kept for backwards compatibility.\n */\nexport interface TableField {\n id: number\n name: string\n type: IcebergType\n required: boolean\n doc?: string\n 'initial-default'?: PrimitiveTypeValue\n 'write-default'?: PrimitiveTypeValue\n}\n\nexport interface TableSchema {\n type: 'struct'\n fields: TableField[]\n 'schema-id'?: number\n 'identifier-field-ids'?: number[]\n}\n\nexport interface PartitionField {\n 'source-id': number\n 'field-id'?: number\n name: string\n transform: string\n}\n\nexport interface PartitionSpec {\n 'spec-id'?: number\n fields: PartitionField[]\n}\n\nexport interface SortField {\n 'source-id': number\n transform: string\n direction: 'asc' | 'desc'\n 'null-order': 'nulls-first' | 'nulls-last'\n}\n\nexport interface SortOrder {\n 'order-id': number\n fields: SortField[]\n}\n\nexport interface SnapshotReference {\n type: 'tag' | 'branch'\n 'snapshot-id': number\n 'max-ref-age-ms'?: number\n 'max-snapshot-age-ms'?: number\n 'min-snapshots-to-keep'?: number\n}\n\nexport interface Snapshot {\n 'snapshot-id': number\n 'parent-snapshot-id'?: number\n 'sequence-number'?: number\n 'timestamp-ms': number\n 'manifest-list': string\n summary: { operation: 'append' | 'replace' | 'overwrite' | 'delete'; [key: string]: string }\n 'schema-id'?: number\n 'first-row-id'?: number\n 'added-rows'?: number\n}\n\nexport interface BlobMetadata {\n type: string\n 'snapshot-id': number\n 'sequence-number': number\n fields: number[]\n properties?: Record<string, string>\n}\n\nexport interface StatisticsFile {\n 'snapshot-id': number\n 'statistics-path': string\n 'file-size-in-bytes': number\n 'file-footer-size-in-bytes': number\n 'blob-metadata': BlobMetadata[]\n}\n\nexport interface PartitionStatisticsFile {\n 'snapshot-id': number\n 'statistics-path': string\n 'file-size-in-bytes': number\n}\n\nexport interface EncryptedKey {\n 'key-id': string\n 'encrypted-key-metadata': string\n 'encrypted-by-id'?: string\n properties?: Record<string, string>\n}\n\nexport interface CreateTableRequest {\n name: string\n schema: TableSchema\n location?: string\n 'partition-spec'?: PartitionSpec\n 'write-order'?: SortOrder\n properties?: Record<string, string>\n 'stage-create'?: boolean\n}\n\nexport interface RegisterTableRequest {\n name: string\n 'metadata-location': string\n overwrite?: boolean\n}\n\nexport interface RenameTableRequest {\n source: TableIdentifier\n destination: TableIdentifier\n}\n\n/**\n * Spec-aligned table commit request shape: requirements + updates arrays.\n * Used by `updateTable` / `commitTable`.\n *\n * Both `requirements` and `updates` are required by the spec — pass an empty\n * array if there are no preconditions to assert.\n */\nexport interface CommitTableRequest {\n identifier?: TableIdentifier\n requirements: TableRequirement[]\n updates: TableUpdate[]\n}\n\n/**\n * @deprecated Use `CommitTableRequest` (with `updates` and optional `requirements`) instead.\n * This alias is kept for callers migrating from 0.x; new code should use the spec-aligned shape.\n */\nexport type UpdateTableRequest = CommitTableRequest\n\n/* ===== TableUpdate discriminated union (per OpenAPI spec) ===== */\n\nexport interface AssignUUIDUpdate {\n action: 'assign-uuid'\n uuid: string\n}\n\nexport interface UpgradeFormatVersionUpdate {\n action: 'upgrade-format-version'\n 'format-version': number\n}\n\nexport interface AddSchemaUpdate {\n action: 'add-schema'\n schema: TableSchema\n /** @deprecated server-managed; included for backward compat with older catalogs */\n 'last-column-id'?: number\n}\n\nexport interface SetCurrentSchemaUpdate {\n action: 'set-current-schema'\n 'schema-id': number\n}\n\nexport interface AddPartitionSpecUpdate {\n action: 'add-spec'\n spec: PartitionSpec\n}\n\nexport interface SetDefaultSpecUpdate {\n action: 'set-default-spec'\n 'spec-id': number\n}\n\nexport interface AddSortOrderUpdate {\n action: 'add-sort-order'\n 'sort-order': SortOrder\n}\n\nexport interface SetDefaultSortOrderUpdate {\n action: 'set-default-sort-order'\n 'sort-order-id': number\n}\n\nexport interface AddSnapshotUpdate {\n action: 'add-snapshot'\n snapshot: Snapshot\n}\n\nexport interface SetSnapshotRefUpdate extends SnapshotReference {\n action: 'set-snapshot-ref'\n 'ref-name': string\n}\n\nexport interface RemoveSnapshotsUpdate {\n action: 'remove-snapshots'\n 'snapshot-ids': number[]\n}\n\nexport interface RemoveSnapshotRefUpdate {\n action: 'remove-snapshot-ref'\n 'ref-name': string\n}\n\nexport interface SetLocationUpdate {\n action: 'set-location'\n location: string\n}\n\nexport interface SetPropertiesUpdate {\n action: 'set-properties'\n updates: Record<string, string>\n}\n\nexport interface RemovePropertiesUpdate {\n action: 'remove-properties'\n removals: string[]\n}\n\nexport interface SetStatisticsUpdate {\n action: 'set-statistics'\n statistics: StatisticsFile\n /** @deprecated derive from `statistics.snapshot-id` */\n 'snapshot-id'?: number\n}\n\nexport interface RemoveStatisticsUpdate {\n action: 'remove-statistics'\n 'snapshot-id': number\n}\n\nexport interface SetPartitionStatisticsUpdate {\n action: 'set-partition-statistics'\n 'partition-statistics': PartitionStatisticsFile\n}\n\nexport interface RemovePartitionStatisticsUpdate {\n action: 'remove-partition-statistics'\n 'snapshot-id': number\n}\n\nexport interface RemovePartitionSpecsUpdate {\n action: 'remove-partition-specs'\n 'spec-ids': number[]\n}\n\nexport interface RemoveSchemasUpdate {\n action: 'remove-schemas'\n 'schema-ids': number[]\n}\n\nexport interface AddEncryptionKeyUpdate {\n action: 'add-encryption-key'\n 'encryption-key': EncryptedKey\n}\n\nexport interface RemoveEncryptionKeyUpdate {\n action: 'remove-encryption-key'\n 'key-id': string\n}\n\nexport type TableUpdate =\n | AssignUUIDUpdate\n | UpgradeFormatVersionUpdate\n | AddSchemaUpdate\n | SetCurrentSchemaUpdate\n | AddPartitionSpecUpdate\n | SetDefaultSpecUpdate\n | AddSortOrderUpdate\n | SetDefaultSortOrderUpdate\n | AddSnapshotUpdate\n | SetSnapshotRefUpdate\n | RemoveSnapshotsUpdate\n | RemoveSnapshotRefUpdate\n | SetLocationUpdate\n | SetPropertiesUpdate\n | RemovePropertiesUpdate\n | SetStatisticsUpdate\n | RemoveStatisticsUpdate\n | SetPartitionStatisticsUpdate\n | RemovePartitionStatisticsUpdate\n | RemovePartitionSpecsUpdate\n | RemoveSchemasUpdate\n | AddEncryptionKeyUpdate\n | RemoveEncryptionKeyUpdate\n\n/* ===== TableRequirement discriminated union (per OpenAPI spec) ===== */\n\nexport interface AssertCreate {\n type: 'assert-create'\n}\n\nexport interface AssertTableUUID {\n type: 'assert-table-uuid'\n uuid: string\n}\n\nexport interface AssertRefSnapshotId {\n type: 'assert-ref-snapshot-id'\n ref: string\n 'snapshot-id': number | null\n}\n\nexport interface AssertLastAssignedFieldId {\n type: 'assert-last-assigned-field-id'\n 'last-assigned-field-id': number\n}\n\nexport interface AssertCurrentSchemaId {\n type: 'assert-current-schema-id'\n 'current-schema-id': number\n}\n\nexport interface AssertLastAssignedPartitionId {\n type: 'assert-last-assigned-partition-id'\n 'last-assigned-partition-id': number\n}\n\nexport interface AssertDefaultSpecId {\n type: 'assert-default-spec-id'\n 'default-spec-id': number\n}\n\nexport interface AssertDefaultSortOrderId {\n type: 'assert-default-sort-order-id'\n 'default-sort-order-id': number\n}\n\nexport type TableRequirement =\n | AssertCreate\n | AssertTableUUID\n | AssertRefSnapshotId\n | AssertLastAssignedFieldId\n | AssertCurrentSchemaId\n | AssertLastAssignedPartitionId\n | AssertDefaultSpecId\n | AssertDefaultSortOrderId\n\nexport interface DropTableRequest {\n purge?: boolean\n}\n\nexport interface TableMetadata {\n 'format-version': number\n 'table-uuid': string\n location?: string\n 'last-updated-ms'?: number\n 'last-column-id'?: number\n schemas: TableSchema[]\n 'current-schema-id': number\n 'partition-specs': PartitionSpec[]\n 'default-spec-id'?: number\n 'last-partition-id'?: number\n 'sort-orders': SortOrder[]\n 'default-sort-order-id'?: number\n properties: Record<string, string>\n 'metadata-location'?: string\n 'current-snapshot-id'?: number\n snapshots?: Snapshot[]\n 'snapshot-log'?: { 'snapshot-id': number; 'timestamp-ms': number }[]\n 'metadata-log'?: { 'metadata-file': string; 'timestamp-ms': number }[]\n refs?: Record<string, SnapshotReference>\n 'last-sequence-number'?: number\n 'next-row-id'?: number\n statistics?: StatisticsFile[]\n 'partition-statistics'?: PartitionStatisticsFile[]\n 'encryption-keys'?: EncryptedKey[]\n /** Optional name field returned by some catalogs */\n name?: string\n}\n\nexport interface StorageCredential {\n prefix: string\n config: Record<string, string>\n}\n\nexport interface CreateNamespaceRequest {\n namespace: string[]\n properties?: Record<string, string>\n}\n\nexport interface CreateNamespaceResponse {\n namespace: string[]\n properties?: Record<string, string>\n}\n\nexport interface GetNamespaceResponse {\n namespace: string[]\n properties?: Record<string, string> | null\n}\n\nexport interface UpdateNamespacePropertiesRequest {\n removals?: string[]\n updates?: Record<string, string>\n}\n\nexport interface UpdateNamespacePropertiesResponse {\n updated: string[]\n removed: string[]\n missing?: string[] | null\n}\n\nexport interface ListNamespacesResponse {\n namespaces?: string[][]\n 'next-page-token'?: string | null\n}\n\nexport interface ListTablesResponse {\n identifiers?: TableIdentifier[]\n 'next-page-token'?: string | null\n}\n\n/**\n * Spec-aligned LoadTableResult (named LoadTableResponse here for backward compat).\n * Returned by GET /tables/{t}, POST /tables, and POST /tables/{t} (commit).\n */\nexport interface LoadTableResponse {\n metadata: TableMetadata\n 'metadata-location'?: string\n config?: Record<string, string>\n 'storage-credentials'?: StorageCredential[]\n}\n\nexport type LoadTableResult = LoadTableResponse\n\nexport interface CommitTableResponse {\n 'metadata-location': string\n metadata: TableMetadata\n}\n\n/**\n * Catalog configuration as returned by GET /v1/config?warehouse=...\n *\n * Servers can use `overrides.prefix` to direct subsequent requests to a\n * server-specific path prefix (e.g., the warehouse identifier), which is\n * the recommended pattern over hard-coded `catalogName` configuration.\n */\nexport interface CatalogConfig {\n defaults: Record<string, string>\n overrides: Record<string, string>\n endpoints?: string[]\n 'idempotency-key-lifetime'?: string\n}\n\n/* ===== Method options ===== */\n\nexport interface ListNamespacesOptions {\n parent?: NamespaceIdentifier\n pageToken?: string\n pageSize?: number\n}\n\nexport interface ListTablesOptions {\n pageToken?: string\n pageSize?: number\n}\n\nexport interface ListNamespacesResult {\n namespaces: NamespaceIdentifier[]\n nextPageToken?: string\n}\n\nexport interface ListTablesResult {\n identifiers: TableIdentifier[]\n nextPageToken?: string\n}\n\nexport interface LoadTableOptions {\n /** ETag value from a previous response; server returns 304 (and we return null) if unchanged. */\n ifNoneMatch?: string\n /**\n * Which snapshots the server should include in the returned metadata.\n * - `'all'`: return every snapshot currently valid for the table\n * - `'refs'`: only snapshots referenced by branches or tags\n * Default if omitted is `'all'` per spec.\n */\n snapshots?: 'all' | 'refs'\n}\n\nexport interface LoadTableResultWithEtag extends LoadTableResponse {\n etag: string | null\n}\n\n/**\n * Gets the current (active) schema from table metadata.\n *\n * @param metadata - Table metadata containing schemas array and current-schema-id\n * @returns The current table schema, or undefined if not found\n */\nexport function getCurrentSchema(metadata: TableMetadata): TableSchema | undefined {\n return metadata.schemas.find((s) => s['schema-id'] === metadata['current-schema-id'])\n}\n","{\n \"tag\": \"apache-iceberg-1.11.0-rc1\",\n \"_comment\": \"Single source of truth for the Iceberg REST OpenAPI version this client tracks. Re-exported as ICEBERG_REST_SPEC_TAG, used by scripts/spec-source.mjs and test/spec-conformance/load-spec.ts to fetch the YAML at build/test time. Bump together with a release. Note: bumped from 1.10.0 to 1.11.0-rc1 because the client emits Idempotency-Key headers which were not part of 1.10.0 — the spec-conformance tests would reject the implementation against the older tag.\"\n}\n","import pin from '../spec-pin.json' with { type: 'json' }\n\n/**\n * Git tag of `apache/iceberg` that this client is aligned to. The\n * spec-conformance test suite fetches and validates against the OpenAPI YAML\n * from this exact ref, so types, request bodies, and response handling here\n * match the spec at this version.\n *\n * @example 'apache-iceberg-1.10.0'\n */\nexport const ICEBERG_REST_SPEC_TAG: string = pin.tag\n\n/**\n * Direct link to the OpenAPI YAML this client tracks.\n */\nexport const ICEBERG_REST_SPEC_URL: string = `https://raw.githubusercontent.com/apache/iceberg/${pin.tag}/open-api/rest-catalog-open-api.yaml`\n","import { IcebergRestCatalog, IcebergError } from 'iceberg-js'\nimport { DEFAULT_HEADERS } from '../lib/constants'\nimport { StorageError } from '../lib/common/errors'\nimport { Fetch, get, post, remove } from '../lib/common/fetch'\nimport { isValidBucketName } from '../lib/common/helpers'\nimport BaseApiClient from '../lib/common/BaseApiClient'\nimport { AnalyticBucket } from '../lib/types'\n\ntype WrapAsyncMethod<T> = T extends (...args: infer A) => Promise<infer R>\n ? (...args: A) => Promise<{ data: R; error: null } | { data: null; error: IcebergError }>\n : T\n\nexport type WrappedIcebergRestCatalog = {\n [K in keyof IcebergRestCatalog]: WrapAsyncMethod<IcebergRestCatalog[K]>\n}\n\n/**\n * Client class for managing Analytics Buckets using Iceberg tables\n * Provides methods for creating, listing, and deleting analytics buckets\n */\nexport default class StorageAnalyticsClient extends BaseApiClient<StorageError> {\n /**\n * @alpha\n *\n * Creates a new StorageAnalyticsClient instance\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Analytics Buckets\n * @param url - The base URL for the storage API\n * @param headers - HTTP headers to include in requests\n * @param fetch - Optional custom fetch implementation\n *\n * @example Using supabase-js (recommended)\n * ```typescript\n * import { createClient } from '@supabase/supabase-js'\n *\n * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')\n * const { data, error } = await supabase.storage.analytics.listBuckets()\n * ```\n *\n * @example Standalone import for bundle-sensitive environments\n * ```typescript\n * import { StorageAnalyticsClient } from '@supabase/storage-js'\n *\n * const client = new StorageAnalyticsClient(url, headers)\n * ```\n */\n constructor(url: string, headers: { [key: string]: string } = {}, fetch?: Fetch) {\n const finalUrl = url.replace(/\\/$/, '')\n const finalHeaders = { ...DEFAULT_HEADERS, ...headers }\n super(finalUrl, finalHeaders, fetch, 'storage')\n }\n\n /**\n * @alpha\n *\n * Creates a new analytics bucket using Iceberg tables\n * Analytics buckets are optimized for analytical queries and data processing\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Analytics Buckets\n * @param name A unique name for the bucket you are creating\n * @returns Promise with response containing newly created analytics bucket or error\n *\n * @example Create analytics bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .analytics\n * .createBucket('analytics-data')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"name\": \"analytics-data\",\n * \"type\": \"ANALYTICS\",\n * \"format\": \"iceberg\",\n * \"created_at\": \"2024-05-22T22:26:05.100Z\",\n * \"updated_at\": \"2024-05-22T22:26:05.100Z\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - Creates a new analytics bucket using Iceberg tables\n * - Analytics buckets are optimized for analytical queries and data processing\n */\n async createBucket(name: string): Promise<\n | {\n data: AnalyticBucket\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await post(this.fetch, `${this.url}/bucket`, { name }, { headers: this.headers })\n })\n }\n\n /**\n * @alpha\n *\n * Retrieves the details of all Analytics Storage buckets within an existing project\n * Only returns buckets of type 'ANALYTICS'\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Analytics Buckets\n * @param options Query parameters for listing buckets\n * @param options.limit Maximum number of buckets to return\n * @param options.offset Number of buckets to skip\n * @param options.sortColumn Column to sort by ('name', 'created_at', 'updated_at')\n * @param options.sortOrder Sort order ('asc' or 'desc')\n * @param options.search Search term to filter bucket names\n * @returns Promise with response containing array of analytics buckets or error\n *\n * @example List analytics buckets\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .analytics\n * .listBuckets({\n * limit: 10,\n * offset: 0,\n * sortColumn: 'created_at',\n * sortOrder: 'desc'\n * })\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": [\n * {\n * \"name\": \"analytics-data\",\n * \"type\": \"ANALYTICS\",\n * \"format\": \"iceberg\",\n * \"created_at\": \"2024-05-22T22:26:05.100Z\",\n * \"updated_at\": \"2024-05-22T22:26:05.100Z\"\n * }\n * ],\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - Retrieves the details of all Analytics Storage buckets within an existing project\n * - Only returns buckets of type 'ANALYTICS'\n */\n async listBuckets(options?: {\n limit?: number\n offset?: number\n sortColumn?: 'name' | 'created_at' | 'updated_at'\n sortOrder?: 'asc' | 'desc'\n search?: string\n }): Promise<\n | {\n data: AnalyticBucket[]\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n // Build query string from options\n const queryParams = new URLSearchParams()\n if (options?.limit !== undefined) queryParams.set('limit', options.limit.toString())\n if (options?.offset !== undefined) queryParams.set('offset', options.offset.toString())\n if (options?.sortColumn) queryParams.set('sortColumn', options.sortColumn)\n if (options?.sortOrder) queryParams.set('sortOrder', options.sortOrder)\n if (options?.search) queryParams.set('search', options.search)\n\n const queryString = queryParams.toString()\n const url = queryString ? `${this.url}/bucket?${queryString}` : `${this.url}/bucket`\n\n return await get(this.fetch, url, { headers: this.headers })\n })\n }\n\n /**\n * @alpha\n *\n * Deletes an existing analytics bucket\n * A bucket can't be deleted with existing objects inside it\n * You must first empty the bucket before deletion\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Analytics Buckets\n * @param bucketName The unique identifier of the bucket you would like to delete\n * @returns Promise with response containing success message or error\n *\n * @example Delete analytics bucket\n * ```js\n * const { data, error } = await supabase\n * .storage\n * .analytics\n * .deleteBucket('analytics-data')\n * ```\n *\n * Response:\n * ```json\n * {\n * \"data\": {\n * \"message\": \"Successfully deleted\"\n * },\n * \"error\": null\n * }\n * ```\n *\n * @remarks\n * - Deletes an analytics bucket\n */\n async deleteBucket(bucketName: string): Promise<\n | {\n data: { message: string }\n error: null\n }\n | {\n data: null\n error: StorageError\n }\n > {\n return this.handleOperation(async () => {\n return await remove(\n this.fetch,\n `${this.url}/bucket/${bucketName}`,\n {},\n { headers: this.headers }\n )\n })\n }\n\n /**\n * @alpha\n *\n * Get an Iceberg REST Catalog client configured for a specific analytics bucket\n * Use this to perform advanced table and namespace operations within the bucket\n * The returned client provides full access to the Apache Iceberg REST Catalog API\n * with the Supabase `{ data, error }` pattern for consistent error handling on all operations.\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Analytics Buckets\n * @param bucketName - The name of the analytics bucket (warehouse) to connect to\n * @returns The wrapped Iceberg catalog client\n * @throws {StorageError} If the bucket name is invalid\n *\n * @example Get catalog and create table\n * ```js\n * // First, create an analytics bucket\n * const { data: bucket, error: bucketError } = await supabase\n * .storage\n * .analytics\n * .createBucket('analytics-data')\n *\n * // Get the Iceberg catalog for that bucket\n * const catalog = supabase.storage.analytics.from('analytics-data')\n *\n * // Create a namespace\n * const { error: nsError } = await catalog.createNamespace({ namespace: ['default'] })\n *\n * // Create a table with schema\n * const { data: tableMetadata, error: tableError } = await catalog.createTable(\n * { namespace: ['default'] },\n * {\n * name: 'events',\n * schema: {\n * type: 'struct',\n * fields: [\n * { id: 1, name: 'id', type: 'long', required: true },\n * { id: 2, name: 'timestamp', type: 'timestamp', required: true },\n * { id: 3, name: 'user_id', type: 'string', required: false }\n * ],\n * 'schema-id': 0,\n * 'identifier-field-ids': [1]\n * },\n * 'partition-spec': {\n * 'spec-id': 0,\n * fields: []\n * },\n * 'write-order': {\n * 'order-id': 0,\n * fields: []\n * },\n * properties: {\n * 'write.format.default': 'parquet'\n * }\n * }\n * )\n * ```\n *\n * @example List tables in namespace\n * ```js\n * const catalog = supabase.storage.analytics.from('analytics-data')\n *\n * // List all tables in the default namespace\n * const { data: tables, error: listError } = await catalog.listTables({ namespace: ['default'] })\n * if (listError) {\n * if (listError.isNotFound()) {\n * console.log('Namespace not found')\n * }\n * return\n * }\n * console.log(tables) // [{ namespace: ['default'], name: 'events' }]\n * ```\n *\n * @example Working with namespaces\n * ```js\n * const catalog = supabase.storage.analytics.from('analytics-data')\n *\n * // List all namespaces\n * const { data: namespaces } = await catalog.listNamespaces()\n *\n * // Create namespace with properties\n * await catalog.createNamespace(\n * { namespace: ['production'] },\n * { properties: { owner: 'data-team', env: 'prod' } }\n * )\n * ```\n *\n * @example Cleanup operations\n * ```js\n * const catalog = supabase.storage.analytics.from('analytics-data')\n *\n * // Drop table with purge option (removes all data)\n * const { error: dropError } = await catalog.dropTable(\n * { namespace: ['default'], name: 'events' },\n * { purge: true }\n * )\n *\n * if (dropError?.isNotFound()) {\n * console.log('Table does not exist')\n * }\n *\n * // Drop namespace (must be empty)\n * await catalog.dropNamespace({ namespace: ['default'] })\n * ```\n *\n * @remarks\n * This method provides a bridge between Supabase's bucket management and the standard\n * Apache Iceberg REST Catalog API. The bucket name maps to the Iceberg warehouse parameter.\n * All authentication and configuration is handled automatically using your Supabase credentials.\n *\n * **Error Handling**: Invalid bucket names throw immediately. All catalog\n * operations return `{ data, error }` where errors are `IcebergError` instances from iceberg-js.\n * Use helper methods like `error.isNotFound()` or check `error.status` for specific error handling.\n * Use `.throwOnError()` on the analytics client if you prefer exceptions for catalog operations.\n *\n * **Cleanup Operations**: When using `dropTable`, the `purge: true` option permanently\n * deletes all table data. Without it, the table is marked as deleted but data remains.\n *\n * **Library Dependency**: The returned catalog wraps `IcebergRestCatalog` from iceberg-js.\n * For complete API documentation and advanced usage, refer to the\n * [iceberg-js documentation](https://supabase.github.io/iceberg-js/).\n */\n from(bucketName: string): WrappedIcebergRestCatalog {\n // Validate bucket name using same rules as Supabase Storage API backend\n if (!isValidBucketName(bucketName)) {\n throw new StorageError(\n 'Invalid bucket name: File, folder, and bucket names must follow AWS object key naming guidelines ' +\n 'and should avoid the use of any other characters.'\n )\n }\n\n // Construct the Iceberg REST Catalog URL\n // The base URL is /storage/v1/iceberg\n // Note: IcebergRestCatalog from iceberg-js automatically adds /v1/ prefix to API paths\n // so we should NOT append /v1 here (it would cause double /v1/v1/ in the URL)\n const catalog = new IcebergRestCatalog({\n baseUrl: this.url,\n catalogName: bucketName, // Maps to the warehouse parameter in Supabase's implementation\n auth: {\n type: 'custom',\n getHeaders: async () => this.headers,\n },\n fetch: this.fetch,\n })\n\n const shouldThrowOnError = this.shouldThrowOnError\n\n const wrappedCatalog = new Proxy(catalog, {\n get(target, prop: keyof IcebergRestCatalog) {\n const value = target[prop]\n if (typeof value !== 'function') {\n return value\n }\n\n return async (...args: unknown[]) => {\n try {\n const data = await (value as Function).apply(target, args)\n return { data, error: null }\n } catch (error) {\n if (shouldThrowOnError) {\n throw error\n }\n return { data: null, error: error as IcebergError }\n }\n }\n },\n }) as unknown as WrappedIcebergRestCatalog\n\n return wrappedCatalog\n }\n}\n","import { DEFAULT_HEADERS } from '../lib/constants'\nimport { StorageError } from '../lib/common/errors'\nimport { Fetch, vectorsApi } from '../lib/common/fetch'\nimport BaseApiClient from '../lib/common/BaseApiClient'\nimport {\n ApiResponse,\n VectorIndex,\n ListIndexesOptions,\n ListIndexesResponse,\n VectorDataType,\n DistanceMetric,\n MetadataConfiguration,\n} from '../lib/types'\n\n/**\n * @alpha\n *\n * Options for creating a vector index\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n */\nexport interface CreateIndexOptions {\n vectorBucketName: string\n indexName: string\n dataType: VectorDataType\n dimension: number\n distanceMetric: DistanceMetric\n metadataConfiguration?: MetadataConfiguration\n}\n\n/**\n * @hidden\n * Base implementation for vector index operations.\n * Use {@link VectorBucketScope} via `supabase.storage.vectors.from('bucket')` instead.\n */\nexport default class VectorIndexApi extends BaseApiClient<StorageError> {\n /** Creates a new VectorIndexApi instance */\n constructor(url: string, headers: { [key: string]: string } = {}, fetch?: Fetch) {\n const finalUrl = url.replace(/\\/$/, '')\n const finalHeaders = { ...DEFAULT_HEADERS, 'Content-Type': 'application/json', ...headers }\n super(finalUrl, finalHeaders, fetch, 'vectors')\n }\n\n /** Creates a new vector index within a bucket */\n async createIndex(options: CreateIndexOptions): Promise<ApiResponse<undefined>> {\n return this.handleOperation(async () => {\n const data = await vectorsApi.post(this.fetch, `${this.url}/CreateIndex`, options, {\n headers: this.headers,\n })\n return data || {}\n })\n }\n\n /** Retrieves metadata for a specific vector index */\n async getIndex(\n vectorBucketName: string,\n indexName: string\n ): Promise<ApiResponse<{ index: VectorIndex }>> {\n return this.handleOperation(async () => {\n return await vectorsApi.post(\n this.fetch,\n `${this.url}/GetIndex`,\n { vectorBucketName, indexName },\n { headers: this.headers }\n )\n })\n }\n\n /** Lists vector indexes within a bucket with optional filtering and pagination */\n async listIndexes(options: ListIndexesOptions): Promise<ApiResponse<ListIndexesResponse>> {\n return this.handleOperation(async () => {\n return await vectorsApi.post(this.fetch, `${this.url}/ListIndexes`, options, {\n headers: this.headers,\n })\n })\n }\n\n /** Deletes a vector index and all its data */\n async deleteIndex(vectorBucketName: string, indexName: string): Promise<ApiResponse<undefined>> {\n return this.handleOperation(async () => {\n const data = await vectorsApi.post(\n this.fetch,\n `${this.url}/DeleteIndex`,\n { vectorBucketName, indexName },\n { headers: this.headers }\n )\n return data || {}\n })\n }\n}\n","import { DEFAULT_HEADERS } from '../lib/constants'\nimport { StorageError } from '../lib/common/errors'\nimport { Fetch, vectorsApi } from '../lib/common/fetch'\nimport BaseApiClient from '../lib/common/BaseApiClient'\nimport {\n ApiResponse,\n PutVectorsOptions,\n GetVectorsOptions,\n GetVectorsResponse,\n DeleteVectorsOptions,\n ListVectorsOptions,\n ListVectorsResponse,\n QueryVectorsOptions,\n QueryVectorsResponse,\n} from '../lib/types'\n\n/**\n * @hidden\n * Base implementation for vector data operations.\n * Use {@link VectorIndexScope} via `supabase.storage.vectors.from('bucket').index('idx')` instead.\n */\nexport default class VectorDataApi extends BaseApiClient<StorageError> {\n /** Creates a new VectorDataApi instance */\n constructor(url: string, headers: { [key: string]: string } = {}, fetch?: Fetch) {\n const finalUrl = url.replace(/\\/$/, '')\n const finalHeaders = { ...DEFAULT_HEADERS, 'Content-Type': 'application/json', ...headers }\n super(finalUrl, finalHeaders, fetch, 'vectors')\n }\n\n /** Inserts or updates vectors in batch (1-500 per request) */\n async putVectors(options: PutVectorsOptions): Promise<ApiResponse<undefined>> {\n // Validate batch size\n if (options.vectors.length < 1 || options.vectors.length > 500) {\n throw new Error('Vector batch size must be between 1 and 500 items')\n }\n\n return this.handleOperation(async () => {\n const data = await vectorsApi.post(this.fetch, `${this.url}/PutVectors`, options, {\n headers: this.headers,\n })\n return data || {}\n })\n }\n\n /** Retrieves vectors by their keys in batch */\n async getVectors(options: GetVectorsOptions): Promise<ApiResponse<GetVectorsResponse>> {\n return this.handleOperation(async () => {\n return await vectorsApi.post(this.fetch, `${this.url}/GetVectors`, options, {\n headers: this.headers,\n })\n })\n }\n\n /** Lists vectors in an index with pagination */\n async listVectors(options: ListVectorsOptions): Promise<ApiResponse<ListVectorsResponse>> {\n // Validate segment configuration\n if (options.segmentCount !== undefined) {\n if (options.segmentCount < 1 || options.segmentCount > 16) {\n throw new Error('segmentCount must be between 1 and 16')\n }\n if (options.segmentIndex !== undefined) {\n if (options.segmentIndex < 0 || options.segmentIndex >= options.segmentCount) {\n throw new Error(`segmentIndex must be between 0 and ${options.segmentCount - 1}`)\n }\n }\n }\n\n return this.handleOperation(async () => {\n return await vectorsApi.post(this.fetch, `${this.url}/ListVectors`, options, {\n headers: this.headers,\n })\n })\n }\n\n /** Queries for similar vectors using approximate nearest neighbor search */\n async queryVectors(options: QueryVectorsOptions): Promise<ApiResponse<QueryVectorsResponse>> {\n return this.handleOperation(async () => {\n return await vectorsApi.post(this.fetch, `${this.url}/QueryVectors`, options, {\n headers: this.headers,\n })\n })\n }\n\n /** Deletes vectors by their keys in batch (1-500 per request) */\n async deleteVectors(options: DeleteVectorsOptions): Promise<ApiResponse<undefined>> {\n // Validate batch size\n if (options.keys.length < 1 || options.keys.length > 500) {\n throw new Error('Keys batch size must be between 1 and 500 items')\n }\n\n return this.handleOperation(async () => {\n const data = await vectorsApi.post(this.fetch, `${this.url}/DeleteVectors`, options, {\n headers: this.headers,\n })\n return data || {}\n })\n }\n}\n","import { DEFAULT_HEADERS } from '../lib/constants'\nimport { StorageError } from '../lib/common/errors'\nimport { Fetch, vectorsApi } from '../lib/common/fetch'\nimport BaseApiClient from '../lib/common/BaseApiClient'\nimport {\n ApiResponse,\n VectorBucket,\n ListVectorBucketsOptions,\n ListVectorBucketsResponse,\n} from '../lib/types'\n\n/**\n * @hidden\n * Base implementation for vector bucket operations.\n * Use {@link StorageVectorsClient} via `supabase.storage.vectors` instead.\n */\nexport default class VectorBucketApi extends BaseApiClient<StorageError> {\n /** Creates a new VectorBucketApi instance */\n constructor(url: string, headers: { [key: string]: string } = {}, fetch?: Fetch) {\n const finalUrl = url.replace(/\\/$/, '')\n const finalHeaders = { ...DEFAULT_HEADERS, 'Content-Type': 'application/json', ...headers }\n super(finalUrl, finalHeaders, fetch, 'vectors')\n }\n\n /** Creates a new vector bucket */\n async createBucket(vectorBucketName: string): Promise<ApiResponse<undefined>> {\n return this.handleOperation(async () => {\n const data = await vectorsApi.post(\n this.fetch,\n `${this.url}/CreateVectorBucket`,\n { vectorBucketName },\n { headers: this.headers }\n )\n return data || {}\n })\n }\n\n /** Retrieves metadata for a specific vector bucket */\n async getBucket(vectorBucketName: string): Promise<ApiResponse<{ vectorBucket: VectorBucket }>> {\n return this.handleOperation(async () => {\n return await vectorsApi.post(\n this.fetch,\n `${this.url}/GetVectorBucket`,\n { vectorBucketName },\n { headers: this.headers }\n )\n })\n }\n\n /** Lists vector buckets with optional filtering and pagination */\n async listBuckets(\n options: ListVectorBucketsOptions = {}\n ): Promise<ApiResponse<ListVectorBucketsResponse>> {\n return this.handleOperation(async () => {\n return await vectorsApi.post(this.fetch, `${this.url}/ListVectorBuckets`, options, {\n headers: this.headers,\n })\n })\n }\n\n /** Deletes a vector bucket (must be empty first) */\n async deleteBucket(vectorBucketName: string): Promise<ApiResponse<undefined>> {\n return this.handleOperation(async () => {\n const data = await vectorsApi.post(\n this.fetch,\n `${this.url}/DeleteVectorBucket`,\n { vectorBucketName },\n { headers: this.headers }\n )\n return data || {}\n })\n }\n}\n","import VectorIndexApi, { CreateIndexOptions } from './VectorIndexApi'\nimport VectorDataApi from './VectorDataApi'\nimport { Fetch } from '../lib/common/fetch'\nimport VectorBucketApi from './VectorBucketApi'\nimport {\n ApiResponse,\n DeleteVectorsOptions,\n GetVectorsOptions,\n ListIndexesOptions,\n ListVectorsOptions,\n ListVectorBucketsOptions,\n ListVectorBucketsResponse,\n PutVectorsOptions,\n QueryVectorsOptions,\n VectorBucket,\n} from '../lib/types'\n\n/**\n *\n * @alpha\n *\n * Configuration options for the Storage Vectors client\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n */\nexport interface StorageVectorsClientOptions {\n /**\n * Custom headers to include in all requests\n */\n headers?: { [key: string]: string }\n /**\n * Custom fetch implementation (optional)\n * Useful for testing or custom request handling\n */\n fetch?: Fetch\n}\n\n/**\n *\n * @alpha\n *\n * Main client for interacting with S3 Vectors API\n * Provides access to bucket, index, and vector data operations\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * **Usage Patterns:**\n *\n * ```typescript\n * const { data, error } = await supabase\n * .storage\n * .vectors\n * .createBucket('embeddings-prod')\n *\n * // Access index operations via buckets\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * await bucket.createIndex({\n * indexName: 'documents',\n * dataType: 'float32',\n * dimension: 1536,\n * distanceMetric: 'cosine'\n * })\n *\n * // Access vector operations via index\n * const index = bucket.index('documents')\n * await index.putVectors({\n * vectors: [\n * { key: 'doc-1', data: { float32: [...] }, metadata: { title: 'Intro' } }\n * ]\n * })\n *\n * // Query similar vectors\n * const { data } = await index.queryVectors({\n * queryVector: { float32: [...] },\n * topK: 5,\n * returnDistance: true\n * })\n * ```\n */\nexport class StorageVectorsClient extends VectorBucketApi {\n /**\n * @alpha\n *\n * Creates a StorageVectorsClient that can manage buckets, indexes, and vectors.\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param url - Base URL of the Storage Vectors REST API.\n * @param options.headers - Optional headers (for example `Authorization`) applied to every request.\n * @param options.fetch - Optional custom `fetch` implementation for non-browser runtimes.\n *\n * @example Using supabase-js (recommended)\n * ```typescript\n * import { createClient } from '@supabase/supabase-js'\n *\n * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * ```\n *\n * @example Standalone import for bundle-sensitive environments\n * ```typescript\n * import { StorageVectorsClient } from '@supabase/storage-js'\n *\n * const client = new StorageVectorsClient(url, options)\n * ```\n */\n constructor(url: string, options: StorageVectorsClientOptions = {}) {\n super(url, options.headers || {}, options.fetch)\n }\n\n /**\n *\n * @alpha\n *\n * Access operations for a specific vector bucket\n * Returns a scoped client for index and vector operations within the bucket\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param vectorBucketName - Name of the vector bucket\n * @returns Bucket-scoped client with index and vector operations\n *\n * @example Accessing a vector bucket\n * ```typescript\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * ```\n */\n from(vectorBucketName: string): VectorBucketScope {\n return new VectorBucketScope(this.url, this.headers, vectorBucketName, this.fetch)\n }\n\n /**\n *\n * @alpha\n *\n * Creates a new vector bucket\n * Vector buckets are containers for vector indexes and their data\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param vectorBucketName - Unique name for the vector bucket\n * @returns Promise with empty response on success or error\n *\n * @example Creating a vector bucket\n * ```typescript\n * const { data, error } = await supabase\n * .storage\n * .vectors\n * .createBucket('embeddings-prod')\n * ```\n */\n async createBucket(vectorBucketName: string): Promise<ApiResponse<undefined>> {\n return super.createBucket(vectorBucketName)\n }\n\n /**\n *\n * @alpha\n *\n * Retrieves metadata for a specific vector bucket\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param vectorBucketName - Name of the vector bucket\n * @returns Promise with bucket metadata or error\n *\n * @example Get bucket metadata\n * ```typescript\n * const { data, error } = await supabase\n * .storage\n * .vectors\n * .getBucket('embeddings-prod')\n *\n * console.log('Bucket created:', data?.vectorBucket.creationTime)\n * ```\n */\n async getBucket(vectorBucketName: string): Promise<ApiResponse<{ vectorBucket: VectorBucket }>> {\n return super.getBucket(vectorBucketName)\n }\n\n /**\n *\n * @alpha\n *\n * Lists all vector buckets with optional filtering and pagination\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Optional filters (prefix, maxResults, nextToken)\n * @returns Promise with list of buckets or error\n *\n * @example List vector buckets\n * ```typescript\n * const { data, error } = await supabase\n * .storage\n * .vectors\n * .listBuckets({ prefix: 'embeddings-' })\n *\n * data?.vectorBuckets.forEach(bucket => {\n * console.log(bucket.vectorBucketName)\n * })\n * ```\n */\n async listBuckets(\n options: ListVectorBucketsOptions = {}\n ): Promise<ApiResponse<ListVectorBucketsResponse>> {\n return super.listBuckets(options)\n }\n\n /**\n *\n * @alpha\n *\n * Deletes a vector bucket (bucket must be empty)\n * All indexes must be deleted before deleting the bucket\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param vectorBucketName - Name of the vector bucket to delete\n * @returns Promise with empty response on success or error\n *\n * @example Delete a vector bucket\n * ```typescript\n * const { data, error } = await supabase\n * .storage\n * .vectors\n * .deleteBucket('embeddings-old')\n * ```\n */\n async deleteBucket(vectorBucketName: string): Promise<ApiResponse<undefined>> {\n return super.deleteBucket(vectorBucketName)\n }\n}\n\n/**\n *\n * @alpha\n *\n * Scoped client for operations within a specific vector bucket\n * Provides index management and access to vector operations\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n */\nexport class VectorBucketScope extends VectorIndexApi {\n private vectorBucketName: string\n\n /**\n * @alpha\n *\n * Creates a helper that automatically scopes all index operations to the provided bucket.\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @example Creating a vector bucket scope\n * ```typescript\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * ```\n */\n constructor(\n url: string,\n headers: { [key: string]: string },\n vectorBucketName: string,\n fetch?: Fetch\n ) {\n super(url, headers, fetch)\n this.vectorBucketName = vectorBucketName\n }\n\n /**\n *\n * @alpha\n *\n * Creates a new vector index in this bucket\n * Convenience method that automatically includes the bucket name\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Index configuration (vectorBucketName is automatically set)\n * @returns Promise with empty response on success or error\n *\n * @example Creating a vector index\n * ```typescript\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * await bucket.createIndex({\n * indexName: 'documents-openai',\n * dataType: 'float32',\n * dimension: 1536,\n * distanceMetric: 'cosine',\n * metadataConfiguration: {\n * nonFilterableMetadataKeys: ['raw_text']\n * }\n * })\n * ```\n */\n override async createIndex(options: Omit<CreateIndexOptions, 'vectorBucketName'>) {\n return super.createIndex({\n ...options,\n vectorBucketName: this.vectorBucketName,\n })\n }\n\n /**\n *\n * @alpha\n *\n * Lists indexes in this bucket\n * Convenience method that automatically includes the bucket name\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Listing options (vectorBucketName is automatically set)\n * @returns Promise with response containing indexes array and pagination token or error\n *\n * @example List indexes\n * ```typescript\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * const { data } = await bucket.listIndexes({ prefix: 'documents-' })\n * ```\n */\n override async listIndexes(options: Omit<ListIndexesOptions, 'vectorBucketName'> = {}) {\n return super.listIndexes({\n ...options,\n vectorBucketName: this.vectorBucketName,\n })\n }\n\n /**\n *\n * @alpha\n *\n * Retrieves metadata for a specific index in this bucket\n * Convenience method that automatically includes the bucket name\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param indexName - Name of the index to retrieve\n * @returns Promise with index metadata or error\n *\n * @example Get index metadata\n * ```typescript\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * const { data } = await bucket.getIndex('documents-openai')\n * console.log('Dimension:', data?.index.dimension)\n * ```\n */\n override async getIndex(indexName: string) {\n return super.getIndex(this.vectorBucketName, indexName)\n }\n\n /**\n *\n * @alpha\n *\n * Deletes an index from this bucket\n * Convenience method that automatically includes the bucket name\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param indexName - Name of the index to delete\n * @returns Promise with empty response on success or error\n *\n * @example Delete an index\n * ```typescript\n * const bucket = supabase.storage.vectors.from('embeddings-prod')\n * await bucket.deleteIndex('old-index')\n * ```\n */\n override async deleteIndex(indexName: string) {\n return super.deleteIndex(this.vectorBucketName, indexName)\n }\n\n /**\n *\n * @alpha\n *\n * Access operations for a specific index within this bucket\n * Returns a scoped client for vector data operations\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param indexName - Name of the index\n * @returns Index-scoped client with vector data operations\n *\n * @example Accessing an index\n * ```typescript\n * const index = supabase.storage.vectors.from('embeddings-prod').index('documents-openai')\n *\n * // Insert vectors\n * await index.putVectors({\n * vectors: [\n * { key: 'doc-1', data: { float32: [...] }, metadata: { title: 'Intro' } }\n * ]\n * })\n *\n * // Query similar vectors\n * const { data } = await index.queryVectors({\n * queryVector: { float32: [...] },\n * topK: 5\n * })\n * ```\n */\n index(indexName: string): VectorIndexScope {\n return new VectorIndexScope(\n this.url,\n this.headers,\n this.vectorBucketName,\n indexName,\n this.fetch\n )\n }\n}\n\n/**\n *\n * @alpha\n *\n * Scoped client for operations within a specific vector index\n * Provides vector data operations (put, get, list, query, delete)\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n */\nexport class VectorIndexScope extends VectorDataApi {\n private vectorBucketName: string\n private indexName: string\n\n /**\n *\n * @alpha\n *\n * Creates a helper that automatically scopes all vector operations to the provided bucket/index names.\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @example Creating a vector index scope\n * ```typescript\n * const index = supabase.storage.vectors.from('embeddings-prod').index('documents-openai')\n * ```\n */\n constructor(\n url: string,\n headers: { [key: string]: string },\n vectorBucketName: string,\n indexName: string,\n fetch?: Fetch\n ) {\n super(url, headers, fetch)\n this.vectorBucketName = vectorBucketName\n this.indexName = indexName\n }\n\n /**\n *\n * @alpha\n *\n * Inserts or updates vectors in this index\n * Convenience method that automatically includes bucket and index names\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Vector insertion options (bucket and index names automatically set)\n * @returns Promise with empty response on success or error\n *\n * @example Insert vectors into an index\n * ```typescript\n * const index = supabase.storage.vectors.from('embeddings-prod').index('documents-openai')\n * await index.putVectors({\n * vectors: [\n * {\n * key: 'doc-1',\n * data: { float32: [0.1, 0.2, ...] },\n * metadata: { title: 'Introduction', page: 1 }\n * }\n * ]\n * })\n * ```\n */\n override async putVectors(options: Omit<PutVectorsOptions, 'vectorBucketName' | 'indexName'>) {\n return super.putVectors({\n ...options,\n vectorBucketName: this.vectorBucketName,\n indexName: this.indexName,\n })\n }\n\n /**\n *\n * @alpha\n *\n * Retrieves vectors by keys from this index\n * Convenience method that automatically includes bucket and index names\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Vector retrieval options (bucket and index names automatically set)\n * @returns Promise with response containing vectors array or error\n *\n * @example Get vectors by keys\n * ```typescript\n * const index = supabase.storage.vectors.from('embeddings-prod').index('documents-openai')\n * const { data } = await index.getVectors({\n * keys: ['doc-1', 'doc-2'],\n * returnMetadata: true\n * })\n * ```\n */\n override async getVectors(options: Omit<GetVectorsOptions, 'vectorBucketName' | 'indexName'>) {\n return super.getVectors({\n ...options,\n vectorBucketName: this.vectorBucketName,\n indexName: this.indexName,\n })\n }\n\n /**\n *\n * @alpha\n *\n * Lists vectors in this index with pagination\n * Convenience method that automatically includes bucket and index names\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Listing options (bucket and index names automatically set)\n * @returns Promise with response containing vectors array and pagination token or error\n *\n * @example List vectors with pagination\n * ```typescript\n * const index = supabase.storage.vectors.from('embeddings-prod').index('documents-openai')\n * const { data } = await index.listVectors({\n * maxResults: 500,\n * returnMetadata: true\n * })\n * ```\n */\n override async listVectors(\n options: Omit<ListVectorsOptions, 'vectorBucketName' | 'indexName'> = {}\n ) {\n return super.listVectors({\n ...options,\n vectorBucketName: this.vectorBucketName,\n indexName: this.indexName,\n })\n }\n\n /**\n *\n * @alpha\n *\n * Queries for similar vectors in this index\n * Convenience method that automatically includes bucket and index names\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Query options (bucket and index names automatically set)\n * @returns Promise with response containing matches array of similar vectors ordered by distance or error\n *\n * @example Query similar vectors\n * ```typescript\n * const index = supabase.storage.vectors.from('embeddings-prod').index('documents-openai')\n * const { data } = await index.queryVectors({\n * queryVector: { float32: [0.1, 0.2, ...] },\n * topK: 5,\n * filter: { category: 'technical' },\n * returnDistance: true,\n * returnMetadata: true\n * })\n * ```\n */\n override async queryVectors(\n options: Omit<QueryVectorsOptions, 'vectorBucketName' | 'indexName'>\n ) {\n return super.queryVectors({\n ...options,\n vectorBucketName: this.vectorBucketName,\n indexName: this.indexName,\n })\n }\n\n /**\n *\n * @alpha\n *\n * Deletes vectors by keys from this index\n * Convenience method that automatically includes bucket and index names\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n * @param options - Deletion options (bucket and index names automatically set)\n * @returns Promise with empty response on success or error\n *\n * @example Delete vectors by keys\n * ```typescript\n * const index = supabase.storage.vectors.from('embeddings-prod').index('documents-openai')\n * await index.deleteVectors({\n * keys: ['doc-1', 'doc-2', 'doc-3']\n * })\n * ```\n */\n override async deleteVectors(\n options: Omit<DeleteVectorsOptions, 'vectorBucketName' | 'indexName'>\n ) {\n return super.deleteVectors({\n ...options,\n vectorBucketName: this.vectorBucketName,\n indexName: this.indexName,\n })\n }\n}\n","import StorageFileApi from './packages/StorageFileApi'\nimport StorageBucketApi from './packages/StorageBucketApi'\nimport StorageAnalyticsClient from './packages/StorageAnalyticsClient'\nimport { Fetch } from './lib/common/fetch'\nimport { StorageVectorsClient } from './packages/StorageVectorsClient'\n\nexport interface StorageClientOptions {\n useNewHostname?: boolean\n}\n\nexport class StorageClient extends StorageBucketApi {\n /**\n * Creates a client for Storage buckets, files, analytics, and vectors.\n *\n * @category Storage\n * @subcategory File Buckets\n *\n * @example Using supabase-js (recommended)\n * ```ts\n * import { createClient } from '@supabase/supabase-js'\n *\n * const supabase = createClient('https://xyzcompany.supabase.co', 'your-publishable-key')\n * const avatars = supabase.storage.from('avatars')\n * ```\n *\n * @example Standalone import for bundle-sensitive environments\n * ```ts\n * import { StorageClient } from '@supabase/storage-js'\n *\n * const storage = new StorageClient('https://xyzcompany.supabase.co/storage/v1', {\n * apikey: 'your-publishable-key',\n * })\n * const avatars = storage.from('avatars')\n * ```\n */\n constructor(\n url: string,\n headers: { [key: string]: string } = {},\n fetch?: Fetch,\n opts?: StorageClientOptions\n ) {\n super(url, headers, fetch, opts)\n }\n\n /**\n * Perform file operation in a bucket.\n *\n * @category Storage\n * @subcategory File Buckets\n *\n * @param id The bucket id to operate on.\n *\n * @example Accessing a bucket\n * ```typescript\n * const avatars = supabase.storage.from('avatars')\n * ```\n */\n from(id: string): StorageFileApi {\n return new StorageFileApi(this.url, this.headers, id, this.fetch)\n }\n\n /**\n *\n * @alpha\n *\n * Access vector storage operations.\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Vector Buckets\n *\n * @returns A StorageVectorsClient instance configured with the current storage settings.\n */\n get vectors(): StorageVectorsClient {\n return new StorageVectorsClient(this.url + '/vector', {\n headers: this.headers,\n fetch: this.fetch,\n })\n }\n\n /**\n *\n * @alpha\n *\n * Access analytics storage operations using Iceberg tables.\n *\n * **Public alpha:** This API is part of a public alpha release and may not be available to your account type.\n *\n * @category Storage\n * @subcategory Analytics Buckets\n *\n * @returns A StorageAnalyticsClient instance configured with the current storage settings.\n */\n get analytics(): StorageAnalyticsClient {\n return new StorageAnalyticsClient(this.url + '/iceberg', this.headers, this.fetch)\n }\n}\n","/**\n * WorkBuddy Cloud Storage facade(#89098)\n *\n * 生成应用只使用环境内固定的 `runtime` 逻辑 Bucket。物理 COS Bucket 与 envId\n * BasePath 由 TCB 管理,SDK 不感知;Bucket 创建/删除/清空属于可信控制面,\n * 不暴露给终端应用。\n */\n\nimport { CLOUD_MODULE_PATHS } from '../paths.js';\nimport type { CloudRuntimeConfig } from '../types.js';\nimport type StorageFileApi from '../vendor/storage/packages/StorageFileApi.js';\nimport { StorageClient } from '../vendor/storage/index.js';\n\nexport const RUNTIME_STORAGE_BUCKET = 'runtime';\nexport const DEFAULT_SIGNED_URL_TTL_SECONDS = 10 * 60;\nexport const MAX_SIGNED_URL_TTL_SECONDS = 60 * 60;\n\nexport type CloudStorageFileBody =\n | ArrayBuffer\n | ArrayBufferView\n | Blob\n | File\n | FormData\n | ReadableStream<Uint8Array>\n | URLSearchParams\n | string;\n\nexport interface CloudStorageFileOptions {\n cacheControl?: string;\n contentType?: string;\n upsert?: boolean;\n duplex?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface CloudStorageListOptions {\n limit?: number;\n offset?: number;\n sortBy?: { column?: string; order?: string };\n search?: string;\n}\n\nexport interface CloudStorageCursorListOptions {\n limit?: number;\n prefix?: string;\n cursor?: string;\n with_delimiter?: boolean;\n sortBy?: {\n column: 'name' | 'updated_at' | 'created_at';\n order?: 'asc' | 'desc';\n };\n}\n\nexport interface CloudStorageMetadata {\n eTag?: string;\n size?: number;\n mimetype?: string;\n cacheControl?: string;\n lastModified?: string;\n contentLength?: number;\n httpStatusCode?: number;\n [key: string]: unknown;\n}\n\nexport interface CloudStorageFile {\n name: string;\n id: string | null;\n updated_at: string | null;\n created_at: string | null;\n last_accessed_at: string | null;\n metadata: CloudStorageMetadata | null;\n}\n\nexport interface CloudStorageObjectInfo {\n id: string;\n version: string;\n name: string;\n bucketId: string;\n createdAt: string;\n size?: number;\n cacheControl?: string;\n contentType?: string;\n etag?: string;\n lastModified?: string;\n metadata?: CloudStorageMetadata;\n}\n\nexport interface CloudStorageCursorObject {\n name: string;\n key?: string;\n id: string;\n updated_at: string;\n created_at: string;\n metadata: CloudStorageMetadata | null;\n}\n\nexport interface CloudStorageCursorFolder {\n name: string;\n key?: string;\n}\n\nexport interface CloudStorageListResult {\n hasNext: boolean;\n folders: CloudStorageCursorFolder[];\n objects: CloudStorageCursorObject[];\n nextCursor?: string;\n}\n\nexport interface CloudStorageError {\n name: string;\n message: string;\n status?: number;\n statusCode?: string;\n code?: string;\n cause?: unknown;\n}\n\nexport type CloudStorageResult<T> =\n | { data: T; error: null }\n | { data: null; error: CloudStorageError };\n\n/** SDK 路径非法。请求尚未发出。 */\nexport class CloudStoragePathError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CloudStoragePathError';\n }\n}\n\nexport class WorkBuddyStorageDownload implements Promise<CloudStorageResult<Blob>> {\n readonly [Symbol.toStringTag] = 'WorkBuddyStorageDownload';\n\n constructor(\n private readonly blob: () => Promise<CloudStorageResult<Blob>>,\n private readonly stream: () => Promise<CloudStorageResult<ReadableStream>>,\n ) {}\n\n asStream(): Promise<CloudStorageResult<ReadableStream>> {\n return this.stream();\n }\n\n then<TResult1 = CloudStorageResult<Blob>, TResult2 = never>(\n onfulfilled?:\n | ((value: CloudStorageResult<Blob>) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.blob().then(onfulfilled, onrejected);\n }\n\n catch<TResult = never>(\n onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null,\n ): Promise<CloudStorageResult<Blob> | TResult> {\n return this.blob().catch(onrejected);\n }\n\n finally(onfinally?: (() => void) | null): Promise<CloudStorageResult<Blob>> {\n return this.blob().finally(onfinally);\n }\n}\n\nexport class WorkBuddyStorageBucket {\n private readonly fileApi: StorageFileApi;\n\n constructor(fileApi: unknown) {\n this.fileApi = fileApi as StorageFileApi;\n }\n\n upload(\n path: string,\n body: CloudStorageFileBody,\n options?: CloudStorageFileOptions,\n ): Promise<CloudStorageResult<{ id: string; path: string; fullPath: string }>> {\n return mapStorageResult(\n this.fileApi.upload(validateObjectPath(path), body, options),\n );\n }\n\n update(\n path: string,\n body: CloudStorageFileBody,\n options?: CloudStorageFileOptions,\n ): Promise<CloudStorageResult<{ id: string; path: string; fullPath: string }>> {\n return mapStorageResult(\n this.fileApi.update(validateObjectPath(path), body, options),\n );\n }\n\n list(\n prefix = '',\n options?: CloudStorageListOptions,\n ): Promise<CloudStorageResult<CloudStorageFile[]>> {\n return mapStorageResult(\n this.fileApi.list(validateObjectPrefix(prefix), options),\n );\n }\n\n listPage(\n options?: CloudStorageCursorListOptions,\n ): Promise<CloudStorageResult<CloudStorageListResult>> {\n return mapStorageResult(\n this.fileApi.listV2({\n ...options,\n prefix: validateObjectPrefix(options?.prefix ?? ''),\n }),\n );\n }\n\n info(path: string): Promise<CloudStorageResult<CloudStorageObjectInfo>> {\n return mapStorageResult(this.fileApi.info(validateObjectPath(path)));\n }\n\n async exists(path: string): Promise<CloudStorageResult<boolean>> {\n const result = await this.fileApi.exists(validateObjectPath(path));\n if (result.error) {\n return { data: null, error: normalizeStorageError(result.error) };\n }\n return { data: result.data, error: null };\n }\n\n download(path: string): WorkBuddyStorageDownload {\n const builder = this.fileApi.download(validateObjectPath(path));\n return new WorkBuddyStorageDownload(\n () => mapStorageResult(builder),\n () => mapStorageResult(builder.asStream()),\n );\n }\n\n remove(paths: string[]): Promise<CloudStorageResult<CloudStorageFile[]>> {\n if (paths.length === 0) {\n throw new CloudStoragePathError('remove requires at least one object path.');\n }\n return mapStorageResult(this.fileApi.remove(paths.map(validateObjectPath)));\n }\n\n copy(\n fromPath: string,\n toPath: string,\n ): Promise<CloudStorageResult<{ path: string }>> {\n return mapStorageResult(\n this.fileApi.copy(validateObjectPath(fromPath), validateObjectPath(toPath)),\n );\n }\n\n move(\n fromPath: string,\n toPath: string,\n ): Promise<CloudStorageResult<{ message: string }>> {\n return mapStorageResult(\n this.fileApi.move(validateObjectPath(fromPath), validateObjectPath(toPath)),\n );\n }\n\n createSignedUrl(\n path: string,\n expiresIn = DEFAULT_SIGNED_URL_TTL_SECONDS,\n ): Promise<CloudStorageResult<{ signedUrl: string }>> {\n return mapStorageResult(\n this.fileApi.createSignedUrl(\n validateObjectPath(path),\n validateSignedURLTTL(expiresIn),\n ),\n );\n }\n\n createSignedUrls(\n paths: string[],\n expiresIn = DEFAULT_SIGNED_URL_TTL_SECONDS,\n ): Promise<CloudStorageResult<Array<{\n error: string | null;\n path: string | null;\n signedURL: string | null;\n signedUrl: string | null;\n }>>> {\n if (paths.length === 0) {\n throw new CloudStoragePathError('createSignedUrls requires at least one object path.');\n }\n return mapStorageResult(\n this.fileApi.createSignedUrls(\n paths.map(validateObjectPath),\n validateSignedURLTTL(expiresIn),\n ),\n );\n }\n\n createSignedUploadUrl(\n path: string,\n options?: { upsert?: boolean },\n ): Promise<CloudStorageResult<{ signedUrl: string; token: string; path: string }>> {\n return mapStorageResult(\n this.fileApi.createSignedUploadUrl(validateObjectPath(path), {\n upsert: options?.upsert ?? false,\n }),\n );\n }\n\n uploadToSignedUrl(\n path: string,\n token: string,\n body: CloudStorageFileBody,\n options?: CloudStorageFileOptions,\n ): Promise<CloudStorageResult<{ path: string; fullPath: string }>> {\n if (!token) {\n throw new CloudStoragePathError('signed upload token is required.');\n }\n return mapStorageResult(\n this.fileApi.uploadToSignedUrl(validateObjectPath(path), token, body, options),\n );\n }\n}\n\nexport class WorkBuddyStorageModule extends WorkBuddyStorageBucket {\n private readonly runtime: WorkBuddyStorageBucket;\n\n constructor(client: unknown) {\n const storageClient = client as StorageClient;\n const runtimeApi = storageClient.from(RUNTIME_STORAGE_BUCKET);\n super(runtimeApi);\n this.runtime = new WorkBuddyStorageBucket(runtimeApi);\n }\n\n /**\n * 兼容 bucket-native 调用形态,但只允许固定的 `runtime`。\n * 终端应用不能枚举、创建或切换逻辑 Bucket。\n */\n from(bucketID: typeof RUNTIME_STORAGE_BUCKET = RUNTIME_STORAGE_BUCKET): WorkBuddyStorageBucket {\n if (bucketID !== RUNTIME_STORAGE_BUCKET) {\n throw new CloudStoragePathError(\n `Only the \"${RUNTIME_STORAGE_BUCKET}\" storage bucket is available.`,\n );\n }\n return this.runtime;\n }\n\n userPath(userID: string, relativePath: string): string {\n return scopedPath('users', userID, relativePath);\n }\n\n sharedPath(ownerID: string, relativePath: string): string {\n return scopedPath('shared', ownerID, relativePath);\n }\n}\n\nexport function createStorageModule(\n config: CloudRuntimeConfig,\n fetch: typeof globalThis.fetch,\n): WorkBuddyStorageModule {\n const client = new StorageClient(`${config.endpoint}${CLOUD_MODULE_PATHS.storage}`, {}, fetch);\n return new WorkBuddyStorageModule(client);\n}\n\nfunction scopedPath(scope: 'users' | 'shared', ownerID: string, relativePath: string): string {\n const owner = validatePathSegment(ownerID, 'owner/user id');\n const relative = validatePath(relativePath, false);\n return validateObjectPath(`${scope}/${owner}/${relative}`);\n}\n\nexport function validateObjectPath(path: string): string {\n const normalized = validatePath(path, false);\n if (!normalized.includes('/')) {\n throw new CloudStoragePathError(\n 'Object paths must use users/<uid>/... or shared/<ownerUid>/....',\n );\n }\n const [scope, owner, ...rest] = normalized.split('/');\n if ((scope !== 'users' && scope !== 'shared') || !owner || rest.length === 0) {\n throw new CloudStoragePathError(\n 'Object paths must use users/<uid>/... or shared/<ownerUid>/....',\n );\n }\n return normalized;\n}\n\nexport function validateObjectPrefix(prefix: string): string {\n if (prefix === '') {\n return '';\n }\n const normalized = validatePath(prefix, true);\n const [scope, owner] = normalized.split('/');\n if (scope === 'shared' && !owner) {\n return 'shared';\n }\n if ((scope !== 'users' && scope !== 'shared') || !owner) {\n throw new CloudStoragePathError(\n 'List prefixes must start with users/<uid> or shared/<ownerUid>.',\n );\n }\n return normalized;\n}\n\nfunction validatePath(path: string, allowTrailingSlash: boolean): string {\n if (typeof path !== 'string' || path.trim() === '') {\n throw new CloudStoragePathError('Storage path must be a non-empty relative path.');\n }\n let decoded = path.trim();\n for (let index = 0; index < 3; index += 1) {\n try {\n const next = decodeURIComponent(decoded);\n if (next === decoded) break;\n decoded = next;\n } catch {\n throw new CloudStoragePathError('Storage path contains invalid URL encoding.');\n }\n }\n if (\n decoded.startsWith('/')\n || decoded.includes('\\\\')\n || decoded.includes('\\0')\n || decoded.includes('//')\n || (!allowTrailingSlash && decoded.endsWith('/'))\n ) {\n throw new CloudStoragePathError('Storage path is not a safe relative object path.');\n }\n const normalized = allowTrailingSlash ? decoded.replace(/\\/+$/, '') : decoded;\n const segments = normalized.split('/');\n if (segments.some(segment => segment === '' || segment === '.' || segment === '..')) {\n throw new CloudStoragePathError('Storage path traversal is not allowed.');\n }\n return normalized;\n}\n\nfunction validatePathSegment(value: string, label: string): string {\n if (!value) {\n throw new CloudStoragePathError(`${label} is not a valid storage path segment.`);\n }\n let decoded = value;\n for (let index = 0; index < 3; index += 1) {\n try {\n const next = decodeURIComponent(decoded);\n if (next === decoded) break;\n decoded = next;\n } catch {\n throw new CloudStoragePathError(`${label} contains invalid URL encoding.`);\n }\n }\n if (\n decoded.includes('/')\n || decoded.includes('\\\\')\n || decoded.includes('\\0')\n || decoded === '.'\n || decoded === '..'\n ) {\n throw new CloudStoragePathError(`${label} is not a valid storage path segment.`);\n }\n return decoded;\n}\n\nfunction validateSignedURLTTL(expiresIn: number): number {\n if (\n !Number.isInteger(expiresIn)\n || expiresIn <= 0\n || expiresIn > MAX_SIGNED_URL_TTL_SECONDS\n ) {\n throw new CloudStoragePathError(\n `Signed URL expiry must be an integer between 1 and ${MAX_SIGNED_URL_TTL_SECONDS} seconds.`,\n );\n }\n return expiresIn;\n}\n\nasync function mapStorageResult<T>(\n source: PromiseLike<{ data: T | null; error: unknown | null }>,\n): Promise<CloudStorageResult<T>> {\n const result = await source;\n if (result.error) {\n return { data: null, error: normalizeStorageError(result.error) };\n }\n if (result.data === null) {\n return {\n data: null,\n error: {\n name: 'CloudStorageResponseError',\n message: 'Storage API returned neither data nor an error.',\n },\n };\n }\n return { data: result.data, error: null };\n}\n\nfunction normalizeStorageError(error: unknown): CloudStorageError {\n if (error instanceof Error) {\n const source = error as Error & {\n status?: number;\n statusCode?: string;\n code?: string;\n };\n return {\n name: source.name,\n message: source.message,\n status: source.status,\n statusCode: source.statusCode,\n code: source.code,\n cause: error,\n };\n }\n return {\n name: 'CloudStorageError',\n message: String(error),\n cause: error,\n };\n}\n","/**\n * 客户端核心入口(#89098)\n */\n\nimport { resolveRuntimeConfig } from './config.js';\nimport { anonymousTokenProvider, createCloudFetch } from './http/fetch.js';\nimport { AuthModule } from './modules/auth/index.js';\nimport { createDatabaseModule, WorkBuddyDatabaseModule } from './modules/database.js';\nimport { LlmModule } from './modules/llm.js';\nimport { createStorageModule } from './modules/storage.js';\nimport type { CloudRuntimeConfig, WorkBuddyCloudOptions } from './types.js';\nimport type { WorkBuddyStorageModule } from './modules/storage.js';\n\n/**\n * 一个应用一个实例。**初始化一次**,四个模块共用同一份配置与同一个 fetch。\n *\n * ============================================================================\n * 身份怎么流到 database / storage\n *\n * AuthModule 是**唯一**的身份来源。共享 fetch 拿到的是\n * `() => this.auth.getAccessToken()` 这个函数 —— 每个请求发出前都会调它一次,\n * 于是登录/登出/续期后,database 与 storage 自动带上最新身份,不需要重建\n * client,也不需要调用方手动搬 token。\n *\n * ⚠️ **client 上刻意没有 `sessionToken` 之类的字段。** 会话的唯一真源是\n * AuthModule 背后的 localStorage:在这里缓存一份副本会在「另一个标签页登出/\n * 续期」时变脏,而拿着脏句柄去续期会让会话永久锁死(见\n * modules/auth/session-manager.ts 顶部说明)。supabase-js 与 CloudBase SDK\n * 都是同一个结论 —— 状态归 auth,client 层只持有取值函数。\n * ============================================================================\n */\nexport class WorkBuddyCloudClient<Database = unknown> {\n /** PostgREST 语义的数据库模块(`/.cloud/database/rest`)。 */\n readonly database: WorkBuddyDatabaseModule<Database>;\n readonly auth: AuthModule;\n /** 对象存储客户端(`/.cloud/storage`)。 */\n readonly storage: WorkBuddyStorageModule;\n readonly llm: LlmModule;\n\n constructor(\n private readonly config: CloudRuntimeConfig,\n options: Pick<WorkBuddyCloudOptions, 'storage'> = {},\n ) {\n // auth 自己的请求走**不带 session provider** 的出口:`/auth/v1/token`\n // 就是续期端点,让它去调「取 token(必要时先续期)」会死锁。\n this.auth = new AuthModule(config, createCloudFetch(config, anonymousTokenProvider), {\n storage: options.storage,\n });\n\n // 其余三个模块共用带身份的出口。\n const fetch = createCloudFetch(config, () => this.auth.getAccessToken());\n this.database = createDatabaseModule<Database>(config, fetch);\n this.storage = createStorageModule(config, fetch);\n this.llm = new LlmModule(config, fetch);\n }\n\n /** 归一化后的数据面基址(无尾斜杠)。 */\n get endpoint(): string {\n return this.config.endpoint;\n }\n\n /** 归一化后的环境中心 OAuth Relay 基址(无尾斜杠)。 */\n get oauthRelayBaseUrl(): string {\n return this.config.oauthRelayBaseUrl;\n }\n}\n\n/**\n * 创建 WorkBuddy Cloud 客户端。\n *\n * `endpoint`、`oauthRelayBaseUrl` 与 `publishableKey` 来自云服务开通后下发的\n * `publicConfig`,都不含 envId 与 provider 凭据(设计文档 §5.2)。\n *\n * ```ts\n * const cloud = createWorkBuddyCloud({\n * endpoint: 'https://my-app.workbuddy.link',\n * oauthRelayBaseUrl: 'https://api.workbuddy.cn/v2/as/genie-baas/oauth',\n * publishableKey: 'wbpk_wbapp_demo_abc123',\n * });\n *\n * await cloud.auth.signInWithPassword({ email, password });\n * // 登录后 database / storage 自动带上身份,不需要手动传 token。\n * const { data, error } = await cloud.database.from('todos').select('id, title');\n * ```\n *\n * 传入类型生成器产出的 `Database` 类型可得到强类型查询(对齐 supabase 的\n * `createClient<Database>()`):`createWorkBuddyCloud<Database>({ ... })`。\n *\n * @throws {WorkBuddyCloudConfigError} 配置缺失或格式不合法时**立即**抛出。\n */\nexport function createWorkBuddyCloud<Database = unknown>(\n options: WorkBuddyCloudOptions,\n): WorkBuddyCloudClient<Database> {\n return new WorkBuddyCloudClient<Database>(resolveRuntimeConfig(options), {\n storage: options.storage,\n });\n}\n","/**\n * 错误归一(骨架,#89098)\n *\n * CloudBase 侧存在**三套**错误体,直接把它们暴露给生成应用会让每个调用点都要\n * 分别判形状:\n *\n * 1. auth(OAuth2) `{ error, error_description, error_uri, details }`\n * 2. PostgREST(数据) `{ message, details, hint, code }`\n * 3. functions / 存储 `{ code, message, requestId }`\n *\n * 这里统一成一个**判别联合**,让调用方能 `switch (error.kind)` 且被 TS 穷尽检查 ——\n * 这一点刻意比 Supabase 做得更严:它只给一个笼统 error 类 + 字符串 code,无法穷尽。\n */\n\n/**\n * 归一后的错误类别。\n *\n * `kind` 是稳定的编程契约,`message` 只供展示 —— 不要去 match message 文本。\n */\nexport type CloudErrorKind =\n /** 未登录 / token 失效。TCB 返 `invalid_grant` 时应清空本地凭据(§5.3)。 */\n | 'unauthenticated'\n /** 已登录但无权限,通常是 RLS 拒绝。 */\n | 'permission-denied'\n | 'not-found'\n /** 参数或请求体不合法。 */\n | 'invalid-request'\n /** 一期未放行的端点(captcha / device code 等,§5.4)。 */\n | 'unimplemented'\n /** 额度耗尽或环境已销毁,读写必然失败(§11.3)。 */\n | 'credits-exhausted'\n | 'rate-limited'\n /** 网关或上游故障。 */\n | 'backend-unavailable'\n /** fetch 层失败(离线、DNS、CORS、超时)。 */\n | 'network'\n /** 无法归类 —— 保留原始信息,不要吞掉。 */\n | 'unknown';\n\n/** 归一后的错误。四个模块只抛/返回这一种形状。 */\nexport interface CloudError {\n kind: CloudErrorKind;\n /** 面向用户的可读信息。 */\n message: string;\n /** HTTP 状态码;网络层失败时为 0。 */\n status: number;\n /** 上游原始错误码(PostgREST 的 `42501`、OAuth2 的 `invalid_grant` 等),便于排查。 */\n code?: string;\n /** 上游原始错误体,**原样保留** —— 归一不等于丢信息。 */\n cause?: unknown;\n}\n\n/**\n * 成功/失败信封。\n *\n * 必须是**判别联合**(两个成员的 union),不能写成 `{ data?: T; error?: E }` ——\n * 后者会让 `if (error) return` 之后的 `data` 收窄失效,这是 Supabase 该设计\n * 最容易被抄错的地方。\n */\nexport type CloudResult<T> =\n | { data: T; error: null }\n | { data: null; error: CloudError };\n\n/** 该错误是否意味着应清空本地凭据并要求重新登录。 */\nexport function shouldClearCredentials(error: CloudError): boolean {\n return error.kind === 'unauthenticated' || error.code === 'invalid_grant';\n}\n"],"mappings":"ufAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,gBAAAE,EAAA,uBAAAC,EAAA,sBAAAC,EAAA,qBAAAC,EAAA,0BAAAC,EAAA,mCAAAC,GAAA,cAAAC,EAAA,+BAAAC,GAAA,2BAAAC,GAAA,2BAAAC,EAAA,yBAAAC,GAAA,8BAAAC,EAAA,4BAAAC,GAAA,2BAAAC,EAAA,6BAAAC,GAAA,2BAAAC,GAAA,2BAAAC,GAAA,wBAAAC,GAAA,yBAAAC,GAAA,2BAAAC,KC2EO,IAAMC,EAAN,cAAwCC,KAAAA,CA3E/C,MA2E+CA,CAAAA,EAAAA,kCAC3C,YAAYC,EAAiB,CACzB,MAAMA,CAAAA,EACN,KAAKC,KAAO,2BAChB,CACJ,ECrEA,IAAMC,GAA0B,SAEhC,SAASC,GAAiBC,EAAgBC,EAAa,CACnD,GAAI,OAAOD,GAAU,UAAYA,EAAME,KAAI,IAAO,GAC9C,MAAM,IAAIC,EACN,GAAGF,CAAAA,8CAAmD,EAI9D,IAAMG,EAAUJ,EAAME,KAAI,EAEtBG,EACJ,GAAI,CACAA,EAAS,IAAIC,IAAIF,CAAAA,CACrB,MAAQ,CACJ,MAAM,IAAID,EACN,GAAGF,CAAAA,uCAA4CG,CAAAA,EAAS,CAEhE,CAEA,GAAIC,EAAOE,WAAa,UAAYF,EAAOE,WAAa,QACpD,MAAM,IAAIJ,EACN,GAAGF,CAAAA,yCAA8CI,EAAOE,QAAQ,EAAE,EAK1E,OAAOH,EAAQI,QAAQ,OAAQ,EAAA,CACnC,CA1BST,EAAAA,GAAAA,oBA4BT,SAASU,GAAwBC,EAAuB,CACpD,GAAI,OAAOA,GAAmB,UAAYA,EAAeR,KAAI,IAAO,GAChE,MAAM,IAAIC,EACN,4DAAA,EAIR,IAAMC,EAAUM,EAAeR,KAAI,EACnC,GAAI,CAACJ,GAAwBa,KAAKP,CAAAA,EAE9B,MAAM,IAAID,EAA0B,yCAAA,EAGxC,OAAOC,CACX,CAdSK,EAAAA,GAAAA,2BAgBT,SAASG,GAAaC,EAAyC,CAC3D,GAAIA,EACA,OAAOA,EAGX,GAAI,OAAOC,WAAWC,OAAU,WAC5B,MAAM,IAAIZ,EACN,6EAAA,EAKR,OAAOW,WAAWC,MAAMC,KAAKF,UAAAA,CACjC,CAbSF,EAAAA,GAAAA,gBAgBF,SAASK,GAAqBC,EAA8B,CAC/D,GAAI,CAACA,GAAW,OAAOA,GAAY,SAC/B,MAAM,IAAIf,EACN,+EAAA,EAIR,OAAOgB,OAAOC,OAAO,CACjBC,SAAUtB,GAAiBmB,EAAQG,SAAU,UAAA,EAC7CC,kBAAmBvB,GAAiBmB,EAAQI,kBAAmB,mBAAA,EAC/DZ,eAAgBD,GAAwBS,EAAQR,cAAc,EAC9DK,MAAOH,GAAaM,EAAQH,KAAK,CACrC,CAAA,CACJ,CAbgBE,EAAAA,GAAAA,wBClDT,IAAMM,GAAyB,yBAqC/B,SAASC,GACZC,EACAC,EAAqC,CAErC,MAAO,OAAOC,EAAOC,IAAAA,CACjB,IAAMC,EAAU,IAAIC,QAAQF,GAAMC,OAAAA,EASlC,GANAA,EAAQE,IAAIR,GAAwBE,EAAOO,cAAc,EAMrD,CAACH,EAAQI,IAAI,eAAA,EAAkB,CAC/B,IAAMC,EAAQ,MAAMR,EAAAA,EAChBQ,GACAL,EAAQE,IAAI,gBAAiB,UAAUG,CAAAA,EAAO,CAEtD,CAEA,OAAOT,EAAOU,MAAMR,EAAO,CAAE,GAAGC,EAAMC,QAAAA,CAAQ,CAAA,CAClD,CACJ,CAvBgBL,EAAAA,GAAAA,oBA0BT,IAAMY,GAA+CC,EAAA,IAAMC,QAAQC,QAAQC,MAAAA,EAAtB,0BC5ErD,IAAMC,EAAoB,UASpBC,EAAgEC,OAAOC,OAAO,CACvFC,KAAM,GAAGJ,CAAAA,QACTK,SAAU,GAAGL,CAAAA,iBACbM,QAAS,GAAGN,CAAAA,WACZO,IAAK,GAAGP,CAAAA,MACZ,CAAA,ECFO,IAAMQ,EAAa,CACtBC,OAAQ,aACRC,OAAQ,aACRC,mBAAoB,2BAEpBC,MAAO,YACPC,QAAS,mBACTC,OAAQ,cAERC,aAAc,mBAEdC,mBAAoB,0BAEpBC,cAAe,YAEfC,KAAM,gBAENC,aAAc,mBAClB,EAkBO,SAASC,GAAaC,EAAkBC,EAAkB,CAC7D,IAAMC,EAAOF,GAAW,CAAC,EACnBG,EAAc,OAAOD,EAAIE,cAAiB,SAAWF,EAAIE,aAAe,GAC9E,GAAI,CAACD,EACD,MAAME,GAAkB,8BAAA,EAE5B,IAAMC,EAAe,OAAOJ,EAAIK,eAAkB,SAAWL,EAAIK,cAAgB,GAG3EC,EAAe,OAAON,EAAIO,YAAe,SAAWP,EAAIO,WAAa,EAE3E,MAAO,CACHN,YAAAA,EACAG,aAAAA,EACAI,UAAWT,EAAaO,EAAe,IACvCG,KAAMC,GAAuBV,CAAAA,CACjC,CACJ,CAjBgBH,EAAAA,GAAAA,gBA0BhB,SAASa,GAAuBV,EAAe,CAC3C,IAAMW,EAAcX,EAAIY,eAAiB,GACzC,MAAO,CACHC,GAAI,OAAOb,EAAIc,KAAQ,SAAWd,EAAIc,IAAM,GAC5CH,YAAAA,EACAX,IAAKA,CACT,CACJ,CAPSU,EAAAA,GAAAA,0BAeF,SAASK,GAAUjB,EAAgB,CACtC,IAAME,EAAOF,GAAW,CAAC,EACnBe,EACF,OAAOb,EAAIc,KAAQ,SAAWd,EAAIc,IAAM,OAAOd,EAAIgB,KAAQ,SAAWhB,EAAIgB,IAAM,GAC9EC,EAAYjB,EAAIkB,eAAiB,CAAC,EACxC,MAAO,CACHL,GAAAA,EACAM,MAAOC,EAAWpB,EAAImB,KAAK,GAAKC,EAAWH,EAASE,KAAK,EACzDE,MAAOD,EAAWpB,EAAIsB,YAAY,GAAKF,EAAWpB,EAAIqB,KAAK,EAE3DV,YAAaX,EAAIY,eAAiB,IAAQZ,EAAIuB,QAAU,YACxDvB,IAAAA,CACJ,CACJ,CAbgBe,EAAAA,GAAAA,aAehB,SAASK,EAAWI,EAAU,CAC1B,OAAO,OAAOA,GAAM,UAAYA,IAAM,GAAKA,EAAIC,MACnD,CAFSL,EAAAA,EAAAA,cAqBF,SAASM,GAAmBC,EAAgB7B,EAAgB,CAC/D,IAAME,EAAOF,GAAW,CAAC,EACnB8B,EAAO,OAAO5B,EAAI6B,OAAU,SAAW7B,EAAI6B,MAAQJ,OACnDK,EACFV,EAAWpB,EAAI+B,iBAAiB,GAChCX,EAAWpB,EAAI8B,OAAO,GACtBV,EAAWpB,EAAIgC,GAAG,GAClB,QAAQL,CAAAA,GAEZ,MAAO,CAAEM,KAAMC,GAAUP,EAAQC,CAAAA,EAAOE,QAAAA,EAASH,OAAAA,EAAQC,KAAAA,EAAMO,MAAOrC,CAAQ,CAClF,CAVgB4B,EAAAA,GAAAA,sBAYhB,SAASQ,GAAUP,EAAgBC,EAAa,CAC5C,GAAIA,IAAS,gBACT,MAAO,kBAEX,OAAQD,EAAAA,CACJ,IAAK,KACD,MAAO,kBACX,IAAK,KAGD,MAAO,kBACX,IAAK,KACD,MAAO,oBACX,IAAK,KACD,MAAO,YACX,IAAK,KACD,MAAO,eACX,IAAK,KACD,MAAO,gBACX,IAAK,KACD,MAAO,sBACX,QACI,OAAOA,GAAU,IAAM,sBAAwB,SACvD,CACJ,CAxBSO,EAAAA,GAAAA,aAiCF,SAASE,EAAsBC,EAAY,CAE9C,MAAO,CACHJ,KAAM,UACNH,QAAS,kDAHGO,aAAeC,MAAQD,EAAIP,QAAUS,OAAOF,CAAAA,CAGGP,GAC3DH,OAAQ,EACRQ,MAAOE,CACX,CACJ,CARgBD,EAAAA,EAAAA,yBAUhB,SAASjC,GAAkBqC,EAAc,CACrC,IAAMC,EAAI,IAAIH,MAAM,yBAAyBE,CAAAA,EAAQ,EACrDC,SAAER,KAAO,UACTQ,EAAEd,OAAS,EACJc,CACX,CALStC,EAAAA,GAAAA,qBClHF,IAAMuC,GAAN,KAAMA,CA5Eb,MA4EaA,CAAAA,EAAAA,uBACQC,MACAC,QACAC,KACAC,sBACAC,IAGTC,SAAgD,KAShDC,aAAe,EAGfC,YAAoD,KAE5D,YAAYC,EAA6B,CACrC,KAAKR,MAAQQ,EAAKR,MAClB,KAAKC,QAAUO,EAAKP,QACpB,KAAKC,KAAOM,EAAKN,KACjB,KAAKC,sBAAwBK,EAAKL,sBAClC,KAAKC,IAAMI,EAAKJ,KAAOK,KAAKL,GAChC,CAGAM,MAA4B,CACxB,OAAO,KAAKV,MAAMW,KAAI,CAC1B,CAQA,MAAMC,QAAuC,CACzC,IAAMC,EAAU,KAAKb,MAAMW,KAAI,EAC/B,OAAKE,EAGA,KAAKC,WAAWD,CAAAA,EAGhBA,EAAQE,aAKN,KAAKC,YAAYH,CAAAA,EAFb,KAAKI,QAAO,EALZJ,EAHA,IAWf,CAQA,MAAMK,cAA6C,CAC/C,IAAML,EAAU,KAAKb,MAAMW,KAAI,EAC/B,OAAKE,GAASE,aAGP,KAAKC,YAAYH,EAAS,CAAEM,eAAgB,EAAK,CAAA,EAF7C,IAGf,CAGAC,aAAaC,EAAqC,CAC9C,YAAKd,YAAc,KACnB,KAAKP,MAAMsB,MAAMD,CAAAA,EACjB,KAAKnB,KAAK,YAAamB,CAAAA,EAChBA,CACX,CAGAE,iBAAiBF,EAAqC,CAClD,YAAKrB,MAAMsB,MAAMD,CAAAA,EACjB,KAAKnB,KAAK,eAAgBmB,CAAAA,EACnBA,CACX,CAOAG,OAAc,CACV,KAAKlB,cAAgB,EACrB,KAAKC,YAAc,KACnB,KAAKF,SAAW,KAChB,KAAKL,MAAMwB,MAAK,EAChB,KAAKtB,KAAK,aAAc,IAAA,CAC5B,CAGQY,WAAWO,EAAgC,CAG/C,OAAI,OAAOA,EAAQI,WAAc,SACtB,GAEJJ,EAAQI,UAAY,KAAKrB,IAAG,EAAKsB,GAC5C,CAGQV,YACJH,EACAL,EAAqC,CAAC,EACV,CAC5B,GAAI,KAAKH,SACL,OAAO,KAAKA,SAEhB,GAAI,CAACG,EAAKW,gBAAkB,KAAKQ,WAAWd,EAAQE,YAAY,EAE5D,OAAOa,QAAQC,QAAQ,IAAA,EAE3B,IAAMC,EAAO,KAAKC,UAAUlB,CAAAA,EAASmB,QAAQ,IAAA,CACzC,KAAK3B,SAAW,IACpB,CAAA,EACA,YAAKA,SAAWyB,EACTA,CACX,CAEQH,WAAWZ,EAA+B,CAC9C,IAAMkB,EAAI,KAAK1B,YACf,OACI0B,IAAM,MACNA,EAAEC,QAAUnB,GACZ,KAAKX,IAAG,EAAK6B,EAAEE,GAAKC,GAE5B,CAGA,MAAcL,UAAUlB,EAAqD,CACzE,IAAMwB,EAAc,KAAK/B,aACnBgC,EAAezB,EAAQE,aAEzBwB,EACJ,GAAI,CACAA,EAAO,MAAM,KAAKtC,QAAQqC,CAAAA,CAC9B,OAASE,EAAK,CACV,OAAO,KAAKC,gBAAgBH,EAAcE,CAAAA,CAC9C,CAGA,GAAI,KAAKlC,eAAiB+B,EAGtB,YAAKrC,MAAMwB,MAAK,EACT,KAOX,IAAMkB,EAAS,KAAK1C,MAAMW,KAAI,EAC9B,OAAI+B,GAAUA,EAAO3B,eAAiBuB,EAC3BI,GAGX,KAAKnC,YAAc,KACnB,KAAKP,MAAMsB,MAAMiB,CAAAA,EACjB,KAAKrC,KAAK,kBAAmBqC,CAAAA,EACtBA,EACX,CAWQE,gBAAgBE,EAAgBH,EAAmC,CACvE,OAAI,KAAKrC,sBAAsBqC,CAAAA,EACpB,KAAKvB,QAAO,GAEvB,KAAKV,YAAc,CAAE2B,MAAOS,EAAQR,GAAI,KAAK/B,IAAG,CAAG,EAC5C,KACX,CAGQa,SAAgB,CACpB,YAAKjB,MAAMwB,MAAK,EAChB,KAAKjB,YAAc,KACnB,KAAKL,KAAK,aAAc,IAAA,EACjB,IACX,CACJ,ECrPA,IAAM0C,GAAqB,2BAGpB,SAASC,IAAAA,CACZ,IAAMC,EAAM,IAAIC,IAChB,MAAO,CACHC,QAASC,EAACC,GAAMJ,EAAIK,IAAID,CAAAA,GAAM,KAArB,WACTE,QAASH,EAAA,CAACC,EAAGG,IAAAA,CAAWP,EAAIQ,IAAIJ,EAAGG,CAAAA,GAA1B,WACTE,WAAYN,EAACC,GAAAA,CAAWJ,EAAIU,OAAON,CAAAA,GAAvB,aAChB,CACJ,CAPgBL,EAAAA,GAAAA,uBAgBT,SAASY,GAAeC,EAA4B,CACvD,GAAIA,EACA,OAAOA,EAEX,GAAI,CACA,IAAMC,EAAQ,sBACdC,kBAAWC,aAAaT,QAAQO,EAAO,GAAA,EACvCC,WAAWC,aAAaN,WAAWI,CAAAA,EAC5BC,WAAWC,YACtB,MAAQ,CACJ,OAAOhB,GAAAA,CACX,CACJ,CAZgBY,EAAAA,GAAAA,kBAqBT,IAAMK,GAAN,KAAMA,CAnEb,MAmEaA,CAAAA,EAAAA,6BACQC,IAEjB,YACqBC,EACjBC,EACF,MAFmBD,QAAAA,EAGjB,KAAKD,IAAMnB,GAAqBqB,CACpC,CASAC,MAA4B,CACxB,IAAIC,EACJ,GAAI,CACAA,EAAM,KAAKH,QAAQhB,QAAQ,KAAKe,GAAG,CACvC,MAAQ,CACJ,OAAO,IACX,CACA,GAAI,CAACI,EACD,OAAO,KAEX,GAAI,CACA,IAAMC,EAASC,KAAKC,MAAMH,CAAAA,EAC1B,OAAOI,GAAgBH,CAAAA,EAAUA,EAAS,KAAKI,QAAO,CAC1D,MAAQ,CACJ,OAAO,KAAKA,QAAO,CACvB,CACJ,CAEAC,MAAMC,EAA6B,CAC/B,GAAI,CACA,KAAKV,QAAQZ,QAAQ,KAAKW,IAAKM,KAAKM,UAAUD,CAAAA,CAAAA,CAClD,MAAQ,CAGR,CACJ,CAEAE,OAAc,CACV,GAAI,CACA,KAAKZ,QAAQT,WAAW,KAAKQ,GAAG,CACpC,MAAQ,CAER,CACJ,CAEQS,SAAgB,CACpB,YAAKI,MAAK,EACH,IACX,CACJ,EASA,SAASL,GAAgBM,EAAc,CACnC,GAAI,CAACA,GAAS,OAAOA,GAAU,SAC3B,MAAO,GAEX,IAAMC,EAAID,EACV,OACI,OAAOC,EAAEC,aAAgB,UACzBD,EAAEC,cAAgB,IAClB,OAAOD,EAAEE,cAAiB,UAC1B,OAAOF,EAAEG,WAAc,UACvB,CAAC,CAACH,EAAEI,MACJ,OAAOJ,EAAEI,MAAS,QAE1B,CAbSX,EAAAA,GAAAA,mBC7EF,IAAMY,EAAN,KAAMA,CAvDb,MAuDaA,CAAAA,EAAAA,yBAEAC,QAEQC,SACAC,QACAC,kBACAC,UAAY,IAAIC,IACzBC,eAAiB,EAUzB,YACIC,EACiBC,EACjBC,EAA0B,CAAC,EAC7B,MAFmBD,MAAAA,EAGjB,KAAKR,QAAU,GAAGO,EAAOG,QAAQ,GAAGC,EAAmBC,IAAI,GAC3D,KAAKT,kBAAoBI,EAAOJ,kBAChC,KAAKD,QAAUW,GAAeJ,EAAKP,OAAO,EAC1C,KAAKD,SAAW,IAAIa,GAAe,CAC/BC,MAAO,IAAIC,GAAa,KAAKd,QAASK,EAAOU,cAAc,EAC3DC,QAASC,EAACC,GAAW,KAAKC,sBAAsBD,CAAAA,EAAvC,WACTE,KAAMH,EAAA,CAACI,EAAOC,IAAY,KAAKC,OAAOF,EAAOC,CAAAA,EAAvC,QACNE,sBAAuBP,EAACQ,GAAQC,GAAaD,CAAAA,GAAQE,GAAoBF,CAAAA,EAAlD,wBAC3B,CAAA,CACJ,CAYA,MAAMG,gBAA8C,CAEhD,OADgB,MAAM,KAAK7B,SAAS8B,OAAM,IAC1BC,WACpB,CAOA,MAAMC,mBAAmBC,EAAsE,CAC3F,MAAI,CAACA,EAAYC,OAAS,CAACD,EAAYE,SAC5BC,EAAKC,EAAW,gDAAA,CAAA,EAEpB,KAAKC,eAAeC,EAAWC,OAAQ,CAC1CC,SAAUR,EAAYC,MACtBC,SAAUF,EAAYE,QAC1B,CAAA,CACJ,CAQA,MAAMO,OACFT,EACkC,CAClC,GAAI,CAACA,EAAYC,MACb,OAAOE,EAAKC,EAAW,uBAAA,CAAA,EAE3B,GAAI,CAACJ,EAAYU,kBACb,OAAOP,EACHC,EACI,yHACI,CAAA,EAIhB,IAAMO,EAAgC,CAClCC,mBAAoBZ,EAAYU,iBACpC,EACAC,OAAAA,EAAKV,MAAQD,EAAYC,MACrBD,EAAYE,WAAUS,EAAKT,SAAWF,EAAYE,UAC/C,KAAKG,eAAeC,EAAWG,OAAQE,CAAAA,CAClD,CAWA,MAAME,QAAQb,EAAiE,CAC3E,GAAI,CAACA,EAAYC,MACb,OAAOE,EAAKC,EAAW,wBAAA,CAAA,EAE3B,IAAMO,EAAgC,CAClCV,MAAOD,EAAYC,MACnBa,MAAO,OACX,EACId,EAAYe,kBAAiBJ,EAAKK,kBAAoBhB,EAAYe,iBAEtE,IAAME,EAAM,MAAM,KAAKC,QAAQZ,EAAWa,aAAc,CAAEC,OAAQ,OAAQT,KAAAA,CAAK,CAAA,EAC/E,GAAIM,EAAII,MACJ,OAAOlB,EAAKc,EAAII,KAAK,EAEzB,IAAMC,EAAWL,EAAIM,MAAQ,CAAC,EACxBC,EACF,OAAOF,EAAQG,iBAAoB,SAAWH,EAAQG,gBAAkB,GAC5E,OAAKD,EAGEE,EAAG,CAAEF,eAAAA,EAAgBG,eAAgBL,EAAQM,UAAY,EAAK,CAAA,EAF1DzB,EAAKC,EAAW,sCAAA,CAAA,CAG/B,CAGA,MAAMyB,cACF7B,EACwC,CACxC,IAAM8B,EAAO,MAAM,KAAKjB,QAAQb,CAAAA,EAChC,GAAI8B,EAAKT,MACL,OAAOlB,EAAK2B,EAAKT,KAAK,EAE1B,GAAM,CAAEG,eAAAA,EAAgBG,eAAAA,CAAc,EAAKG,EAAKP,KAChD,OAAOG,EAAG,CACNF,eAAAA,EACAG,eAAAA,EACAI,OAAQJ,EACRK,OAAQ/C,EAAA,CAAC,CAAEgD,MAAAA,CAAK,IACZ,KAAKC,UAAU,CACXV,eAAAA,EACAS,MAAAA,EACAhC,MAAOD,EAAYC,MACnB0B,eAAAA,CACJ,CAAA,EANI,SAOZ,CAAA,CACJ,CAYA,MAAMO,UACFC,EACkC,CAClC,GAAI,CAACA,EAAOX,gBAAkB,CAACW,EAAOF,OAAS,CAACE,EAAOlC,MACnD,OAAOE,EAAKC,EAAW,oDAAA,CAAA,EAE3B,IAAMgC,EAAW,MAAM,KAAKlB,QAAQZ,EAAW+B,mBAAoB,CAC/DjB,OAAQ,OACRT,KAAM,CACFc,gBAAiBU,EAAOX,eACxBc,kBAAmBH,EAAOF,KAC9B,CACJ,CAAA,EACA,GAAIG,EAASf,MACT,OAAOlB,EAAKiC,EAASf,KAAK,EAE9B,IAAMkB,EAAMH,EAASb,MAAQ,CAAC,EACxBb,EACF,OAAO6B,EAAG3B,oBAAuB,SAAW2B,EAAG3B,mBAAqB,GACxE,OAAKF,EAIDyB,EAAOR,eACA,KAAKtB,eAAeC,EAAWC,OAAQ,CAC1CC,SAAU2B,EAAOlC,MACjBW,mBAAoBF,CACxB,CAAA,EAEG,KAAKD,OAAO,CACfR,MAAOkC,EAAOlC,MACdC,SAAUiC,EAAOjC,UAAY,GAC7BQ,kBAAAA,CACJ,CAAA,EAbWP,EAAKC,EAAW,yCAAA,CAAA,CAc/B,CAgBA,MAAMoC,gBAAgBC,EAAkE,CACpF,GAAIA,EAAQC,WAAa,SACrB,OAAOvC,EAAKC,EAAW,gDAAA,CAAA,EAE3B,IAAMuC,EAAaF,EAAQE,YAAcC,GAAAA,EACzC,OAAKD,EAKE,KAAKE,gBAAgBJ,EAASE,CAAAA,EAJ1BxC,EACHC,EAAW,mEAAA,CAAA,CAIvB,CAQA,MAAM0C,oBAAoBC,EAA4D,CAClF,IAAMC,EAAgBD,GAAUE,GAAAA,EAC5BC,EAAQF,EACZ,GAAI,CACI,gBAAgBG,KAAKH,CAAAA,IACrBE,EAAQ,IAAIE,IAAIJ,CAAAA,EAAeD,OAEvC,MAAQ,CACJ,OAAO5C,EAAKC,EAAW,+BAAA,CAAA,CAC3B,CACA,IAAM+B,EAAS,IAAIkB,gBAAgBH,CAAAA,EAE7BI,EAAanB,EAAOoB,IAAI,OAAA,GAAYpB,EAAOoB,IAAI,mBAAA,EACrD,GAAID,EACA,OAAOnD,EAAK,CACRqD,KAAM,kBACNC,QAAS,wCAAwCH,CAAAA,GACjDI,OAAQ,CACZ,CAAA,EAEJ,IAAMC,EAAOxB,EAAOoB,IAAI,MAAA,EACxB,GAAI,CAACI,EACD,OAAOjC,EAAG,IAAA,EAGd,IAAMkC,EAAQzB,EAAOoB,IAAI,OAAA,GAAY,GAC/BM,EAAa1B,EAAOoB,IAAI,aAAA,EAC9B,GAAIM,IAAe,eACf,OAAO1D,EAAKC,EAAW,kDAAA,CAAA,EAE3B,GAAI,CAACwD,EACD,OAAOzD,EAAKC,EAAW,+BAAA,CAAA,EAG3B,IAAMO,EAAgC,CAClCmD,YAAaD,EACbE,cAAeJ,EACfC,MAAAA,EACAI,gBAAiB,CAAEJ,MAAAA,CAAM,CAC7B,EACA,OAAO,KAAKvD,eAAeC,EAAW2D,mBAAoBtD,CAAAA,CAC9D,CAGA,MAAMuD,sBACFjE,EAC4C,CAC5C,GAAI,CAACA,EACD,OAAOE,EAAKC,EAAW,sCAAA,CAAA,EAE3B,IAAM0B,EAAO,MAAM,KAAKZ,QAAQZ,EAAWa,aAAc,CACrDC,OAAQ,OACRT,KAAM,CAAEV,MAAAA,EAAOa,MAAO,iBAAkBqD,OAAQ,MAAO,CAC3D,CAAA,EACA,GAAIrC,EAAKT,MACL,OAAOlB,EAAK2B,EAAKT,KAAK,EAE1B,IAAMC,EAAWQ,EAAKP,MAAQ,CAAC,EACzBC,EACF,OAAOF,EAAQG,iBAAoB,SAAWH,EAAQG,gBAAkB,GAC5E,OAAKD,EAGEE,EAAG,CACN0C,WAAYnF,EAAA,MAAO,CAAEoF,MAAAA,EAAOnE,SAAAA,CAAQ,IAAE,CAClC,IAAMkC,EAAW,MAAM,KAAKlB,QAAQZ,EAAW+B,mBAAoB,CAC/DjB,OAAQ,OACRT,KAAM,CACFc,gBAAiBD,EACjBc,kBAAmB+B,CACvB,CACJ,CAAA,EACA,GAAIjC,EAASf,MACT,OAAOlB,EAAKiC,EAASf,KAAK,EAE9B,IAAMiD,EAAmBlC,EAASb,MAAQ,CAAC,EACrCb,EACF,OAAO4D,EAAgB1D,oBAAuB,SACxC0D,EAAgB1D,mBAChB,GACV,GAAI,CAACF,EACD,OAAOP,EAAKC,EAAW,yCAAA,CAAA,EAE3B,IAAMmE,EAAQ,MAAM,KAAKrD,QAAQZ,EAAWkE,cAAe,CACvDpD,OAAQ,OACRT,KAAM,CACFV,MAAAA,EACAwE,aAAcvE,EACdU,mBAAoBF,CACxB,CACJ,CAAA,EACA,GAAI6D,EAAMlD,MACN,OAAOlB,EAAKoE,EAAMlD,KAAK,EAE3B,IAAMqD,EAAW,MAAM,KAAK3E,mBAAmB,CAAEE,MAAAA,EAAOC,SAAAA,CAAS,CAAA,EACjE,OAAKwE,EAASrD,OACV,KAAK9B,OAAO,oBAAqBmF,EAASnD,IAAI,EAE3CmD,CACX,EAnCY,aAoChB,CAAA,EAvCWvE,EAAKC,EAAW,sCAAA,CAAA,CAwC/B,CAGA,MAAMuE,oBACF3E,EACkC,CAClC,IAAMiC,EAAQ,MAAM,KAAKrC,eAAc,EACvC,GAAI,CAACqC,EACD,OAAO9B,EAAK,CAAEqD,KAAM,kBAAmBC,QAAS,oBAAqBC,OAAQ,CAAE,CAAA,EAEnF,IAAMkB,EAAO,MAAM,KAAK1D,QAAQZ,EAAWsE,KAAM,CAC7CxD,OAAQ,OACRa,MAAAA,EACAtB,KAAM,CAAET,SAAUF,EAAY6E,WAAY,CAC9C,CAAA,EACA,GAAID,EAAKvD,MACL,OAAOlB,EAAKyE,EAAKvD,KAAK,EAE1B,IAAMC,EAAWsD,EAAKrD,MAAQ,CAAC,EACzBuD,EAAY,OAAOxD,EAAQyD,YAAe,SAAWzD,EAAQyD,WAAa,GAChF,GAAI,CAACD,EACD,OAAO3E,EAAKC,EAAW,iCAAA,CAAA,EAE3B,IAAM4E,EAAU,MAAM,KAAK9D,QAAQZ,EAAW2E,aAAc,CACxD7D,OAAQ,QACRa,MAAAA,EACAtB,KAAM,CAAEoE,WAAYD,EAAWL,aAAczE,EAAYkF,WAAY,CACzE,CAAA,EACA,GAAIF,EAAQ3D,MACR,OAAOlB,EAAK6E,EAAQ3D,KAAK,EAE7B,IAAM/B,EAAU,MAAM,KAAK6F,WAAU,EACrC,OAAI7F,EAAQiC,MACR,KAAKhC,OAAO,eAAgBD,EAAQiC,IAAI,EACjCG,EAAGpC,EAAQiC,IAAI,GAEnBpB,EAAKb,EAAQ+B,OAAS,CACzBmC,KAAM,kBACNC,QAAS,oBACTC,OAAQ,CACZ,CAAA,CACJ,CAYA,MAAMyB,YAAwD,CAC1D,GAAI,CACA,OAAOzD,EAAG,MAAM,KAAK3D,SAAS8B,OAAM,CAAA,CACxC,OAASJ,EAAK,CACV,OAAOU,EAAKT,GAAaD,CAAAA,EAAOA,EAAM2F,EAAsB3F,CAAAA,CAAAA,CAChE,CACJ,CAGA,MAAM4F,gBAA4D,CAC9D,GAAI,CACA,OAAO3D,EAAG,MAAM,KAAK3D,SAASuH,aAAY,CAAA,CAC9C,OAAS7F,EAAK,CACV,OAAOU,EAAKT,GAAaD,CAAAA,EAAOA,EAAM2F,EAAsB3F,CAAAA,CAAAA,CAChE,CACJ,CAQA,MAAM8F,SAA2C,CAC7C,IAAMtD,EAAQ,MAAM,KAAKrC,eAAc,EACvC,GAAI,CAACqC,EACD,OAAO9B,EAAK,CAAEqD,KAAM,kBAAmBC,QAAS,oBAAqBC,OAAQ,CAAE,CAAA,EAEnF,IAAMzC,EAAM,MAAM,KAAKC,QAAQZ,EAAWkF,OAAQ,CAAEpE,OAAQ,MAAOa,MAAAA,CAAM,CAAA,EACzE,OAAIhB,EAAII,OAGA1B,GAAoBsB,EAAII,KAAK,GAC7B,KAAKtD,SAAS0H,MAAK,EAEhBtF,EAAKc,EAAII,KAAK,GAElBK,EAAGgE,GAAUzE,EAAIM,IAAI,CAAA,CAChC,CASA,MAAMoE,SAAsC,CACxC,IAAMrG,EAAU,KAAKvB,SAAS6H,KAAI,EAClC,OAAItG,GAASQ,aAGT,MAAM,KAAKoB,QAAQZ,EAAWqF,QAAS,CACnCvE,OAAQ,OACRT,KAAM,CAAC,EACPsB,MAAO3C,EAAQQ,WACnB,CAAA,EAEJ,KAAK/B,SAAS0H,MAAK,EACZ/D,EAAG,IAAA,CACd,CAQAmE,kBAAkBC,EAA8C,CAC5D,IAAMC,EAAK,KAAK3H,iBAChB,YAAKF,UAAU8H,IAAID,EAAID,CAAAA,EAGvBG,GAAWH,EAAU,kBAAmB,KAAK/H,SAAS6H,KAAI,CAAA,EACnD,IAAA,CAAW,KAAK1H,UAAUgI,OAAOH,CAAAA,EAC5C,CAOA,MAAclD,gBACVJ,EACAE,EACmC,CAGnC,IAAMmD,EAAW,IAAI1C,IAAIT,CAAAA,EACnBwD,EAAQ,IAAI/C,IAAI,GAAG,KAAKnF,iBAAiB,YAAY,EAC3DkI,OAAAA,EAAMC,aAAaJ,IAAI,WAAYvD,EAAQC,QAAQ,EACnDyD,EAAMC,aAAaJ,IAAI,eAAgBF,EAASO,SAAQ,CAAA,EAEjD3E,EAAG,CAAE4E,IAAKH,EAAME,SAAQ,CAAG,CAAA,CACtC,CAGA,MAAclH,sBAAsBD,EAAuC,CAGvE,IAAM+B,EAAM,MAAM,KAAKC,QAAQZ,EAAW2B,MAAO,CAC7Cb,OAAQ,OACRT,KAAM,CAAE4F,WAAY,gBAAiBC,cAAetH,CAAO,CAC/D,CAAA,EACA,GAAI+B,EAAII,MACJ,MAAMJ,EAAII,MAEd,OAAOoF,GAAaxF,EAAIM,KAAMmF,KAAKC,IAAG,CAAA,CAC1C,CAGA,MAActG,eACVuG,EACAjG,EACApC,EAA6C,CAAC,EACZ,CAClC,IAAM0C,EAAM,MAAM,KAAKC,QAAQ0F,EAAM,CAAExF,OAAQ,OAAQT,KAAAA,EAAMkG,QAAStI,EAAKsI,OAAQ,CAAA,EACnF,GAAI5F,EAAII,MACJ,OAAOlB,EAAKc,EAAII,KAAK,EAEzB,GAAI,CACA,OAAOK,EAAG,KAAK3D,SAAS+I,aAAaL,GAAaxF,EAAIM,KAAMmF,KAAKC,IAAG,CAAA,CAAA,CAAA,CACxE,OAASlH,EAAK,CACV,OAAOU,EAAKT,GAAaD,CAAAA,EAAOA,EAAM2F,EAAsB3F,CAAAA,CAAAA,CAChE,CACJ,CAGA,MAAcyB,QACV0F,EACAG,EAM6B,CAC7B,IAAMF,EAAkC,CAAE,GAAGE,EAAKF,OAAQ,EACtDE,EAAKpG,OAASqG,SAGdH,EAAQ,cAAA,EAAkB,oBAE1BE,EAAK9E,QACL4E,EAAQI,cAAgB,UAAUF,EAAK9E,KAAK,IAGhD,IAAIiF,EACJ,GAAI,CACAA,EAAW,MAAM,KAAK5I,MAAM,KAAKR,QAAU8I,EAAM,CAC7CxF,OAAQ2F,EAAK3F,OACbyF,QAAAA,EACAlG,KAAMoG,EAAKpG,OAASqG,OAAYA,OAAYG,KAAKC,UAAUL,EAAKpG,IAAI,CACxE,CAAA,CACJ,OAASlB,EAAK,CAGV,OAAOU,EAAKiF,EAAsB3F,CAAAA,CAAAA,CACtC,CAEA,IAAM6B,EAAU,MAAM+F,GAASH,CAAAA,EAC/B,OAAKA,EAASxF,GAGPA,EAAGJ,CAAAA,EAFCnB,EAAKmH,GAAmBJ,EAASxD,OAAQpC,CAAAA,CAAAA,CAGxD,CAGQ/B,OAAOF,EAAuBC,EAAoC,CACtE,QAAWiI,KAAM,KAAKrJ,UAAUsJ,OAAM,EAClCvB,GAAWsB,EAAIlI,EAAOC,CAAAA,CAE9B,CACJ,EAMA,SAASoC,EAAMH,EAAO,CAClB,MAAO,CAAEA,KAAAA,EAAMF,MAAO,IAAK,CAC/B,CAFSK,EAAAA,EAAAA,MAIT,SAASvB,EAAQkB,EAAiB,CAC9B,MAAO,CAAEE,KAAM,KAAMF,MAAAA,CAAM,CAC/B,CAFSlB,EAAAA,EAAAA,QAIT,SAASC,EAAWqD,EAAe,CAC/B,MAAO,CAAED,KAAM,kBAAmBC,QAAAA,EAASC,OAAQ,CAAE,CACzD,CAFStD,EAAAA,EAAAA,cAIT,SAASV,GAAa+H,EAAU,CAC5B,MAAO,CAAC,CAACA,GAAK,OAAOA,GAAM,UAAY,OAAQA,EAAiBjE,MAAS,QAC7E,CAFS9D,EAAAA,GAAAA,gBAKT,SAASC,GAAoB0B,EAAiB,CAC1C,OAAOA,EAAMmC,OAAS,mBAAqBnC,EAAMsC,OAAS,eAC9D,CAFShE,EAAAA,GAAAA,uBAIT,eAAe0H,GAASH,EAAkB,CACtC,IAAMQ,EAAO,MAAMR,EAASQ,KAAI,EAChC,GAAI,CAACA,EACD,OAAO,KAEX,GAAI,CACA,OAAOP,KAAKQ,MAAMD,CAAAA,CACtB,MAAQ,CAEJ,MAAO,CAAEjE,QAASiE,CAAK,CAC3B,CACJ,CAXeL,EAAAA,GAAAA,YAaf,SAASpB,GACLsB,EACAlI,EACAC,EAA4B,CAE5B,GAAI,CACAiI,EAAGlI,EAAOC,CAAAA,CACd,MAAQ,CAER,CACJ,CAVS2G,EAAAA,GAAAA,cAaT,SAASrD,IAAAA,CACL,IAAMgF,EAAMC,WAAWC,SACvB,OAAOF,EAAMA,EAAIG,OAASH,EAAII,SAAW,EAC7C,CAHSpF,EAAAA,GAAAA,kBAKT,SAASK,IAAAA,CACL,OAAO4E,WAAWC,UAAU/E,QAAU,EAC1C,CAFSE,EAAAA,GAAAA,qBC1oBF,IAAMgF,GAAgBC,EAACC,GAC5BC,KAAKC,IAAI,IAAO,GAAKF,EAAc,GAAA,EADR,iBAQhBG,GAAyB,CAAC,IAAK,KAK/BC,GAAoB,CAAC,MAAO,OAAQ,WCLjD,IAAqBC,EAArB,cAA4CC,KAAAA,CAxB5C,MAwB4CA,CAAAA,EAAAA,uBAC1CC,QACAC,KACAC,KAeA,YAAYC,EAA2E,CACrF,MAAMA,EAAQC,OAAO,EACrB,KAAKC,KAAO,iBACZ,KAAKL,QAAUG,EAAQH,QACvB,KAAKC,KAAOE,EAAQF,KACpB,KAAKC,KAAOC,EAAQD,IACtB,CAEAI,QAAyF,CACvF,MAAO,CACLD,KAAM,KAAKA,KACXD,QAAS,KAAKA,QACdJ,QAAS,KAAKA,QACdC,KAAM,KAAKA,KACXC,KAAM,KAAKA,IACb,CACF,CACF,ECrCA,SAASK,GAAMC,EAAYC,EAAoB,CAC7C,OAAO,IAAIC,QAASC,GAAAA,CAClB,GAAIF,GAAQG,QAAS,CACnBD,EAAAA,EACA,MACF,CACA,IAAME,EAAKC,WAAW,IAAA,CACpBL,GAAQM,oBAAoB,QAASC,CAAAA,EACrCL,EAAAA,CACF,EAAGH,CAAAA,EACH,SAASQ,GAAAA,CACPC,aAAaJ,CAAAA,EACbF,EAAAA,CACF,CAHSK,EAAAA,EAAAA,WAITP,GAAQS,iBAAiB,QAASF,CAAAA,CACpC,CAAA,CACF,CAhBST,EAAAA,GAAAA,SAqBT,SAASY,GACPC,EACAC,EACAC,EACAC,EAAqB,CAarB,MAVI,GAACA,GAAgBD,GAAgBE,GAKjC,CAACC,GAAkBC,SAASN,CAAAA,GAK5B,CAACO,GAAuBD,SAASL,CAAAA,EAKvC,CAtBSF,EAAAA,GAAAA,eAwBT,IAA8BS,GAA9B,KAA8BA,CA5D9B,MA4D8BA,CAAAA,EAAAA,yBAOlBR,OACAS,IACAC,QACAC,OACAC,KACAC,mBAAqB,GACrBxB,OACAyB,MACAC,cACAC,iBACAC,eAGAd,aAAwB,GAyBlC,YAAYe,EAcT,CACD,KAAKlB,OAASkB,EAAQlB,OACtB,KAAKS,IAAMS,EAAQT,IACnB,KAAKC,QAAU,IAAIS,QAAQD,EAAQR,OAAO,EAC1C,KAAKC,OAASO,EAAQP,OACtB,KAAKC,KAAOM,EAAQN,KACpB,KAAKC,mBAAqBK,EAAQL,oBAAsB,GACxD,KAAKxB,OAAS6B,EAAQ7B,OACtB,KAAK0B,cAAgBG,EAAQH,eAAiB,GAC9C,KAAKC,iBAAmBE,EAAQF,kBAAoB,GACpD,KAAKC,eAAiBC,EAAQD,gBAAkB,IAChD,KAAKd,aAAee,EAAQE,OAAS,GAEjCF,EAAQJ,MACV,KAAKA,MAAQI,EAAQJ,MAErB,KAAKA,MAAQA,KAEjB,CAWAO,cAA8D,CAC5D,YAAKR,mBAAqB,GACnB,IACT,CAoDAS,YAAmB,CACjB,GAAI,KAAKZ,QAAQa,IAAI,QAAA,IAAc,WACjC,MAAM,IAAIC,MAAM,wCAAA,EAElB,YAAKR,iBAAmB,GACjB,IACT,CAkBAS,UAAUC,EAAcC,EAAqB,CAC3C,YAAKjB,QAAU,IAAIS,QAAQ,KAAKT,OAAO,EACvC,KAAKA,QAAQkB,IAAIF,EAAMC,CAAAA,EAChB,IACT,CAuBAP,MAAMS,EAAwB,CAC5B,YAAK1B,aAAe0B,EACb,IACT,CAEAC,KAMEC,EAQAC,EACkC,CAclC,GAZI,KAAKrB,SAAWsB,SAET,CAAC,MAAO,QAAQ3B,SAAS,KAAKN,MAAM,EAC7C,KAAKU,QAAQkB,IAAI,iBAAkB,KAAKjB,MAAM,EAE9C,KAAKD,QAAQkB,IAAI,kBAAmB,KAAKjB,MAAM,GAE7C,KAAKX,SAAW,OAAS,KAAKA,SAAW,QAC3C,KAAKU,QAAQkB,IAAI,eAAgB,kBAAA,EAI/B,KAAKZ,iBAAkB,CACzB,IAAMkB,EAAgB,KAAKxB,QAAQa,IAAI,QAAA,EACnCW,IAAkB,oCACpB,KAAKxB,QAAQkB,IAAI,SAAU,kDAAA,GAClB,CAACM,GAAiBA,IAAkB,qBAC7C,KAAKxB,QAAQkB,IAAI,SAAU,iDAAA,CAE/B,CAIA,IAAMO,EAAS,KAAKrB,MAiFhBsB,EA9EqBC,EAAA,SAAA,CAOvB,IAAInC,EAAe,EAEnB,OAAa,CAMX,IAAMQ,EAAkC,CAAC,EACzC,KAAKA,QAAQ4B,QAAQ,CAACX,EAAOY,IAAAA,CAC3B7B,EAAQ6B,CAAAA,EAAOZ,CACjB,CAAA,EACIzB,EAAe,IACjBQ,EAAQ,eAAA,EAAmB8B,OAAOtC,CAAAA,GAIpC,IAAIkC,EACJ,GAAI,CACFA,EAAM,MAAMD,EAAO,KAAK1B,IAAIgC,SAAQ,EAAI,CACtCzC,OAAQ,KAAKA,OACbU,QAAAA,EACAE,KAAM8B,KAAKC,UAAU,KAAK/B,KAAM,CAACgC,EAAGjB,IAClC,OAAOA,GAAU,SAAWA,EAAMc,SAAQ,EAAKd,CAAAA,EAEjDtC,OAAQ,KAAKA,MACf,CAAA,CAKF,OAASwD,EAAiB,CAOxB,GALIA,GAAYnB,OAAS,cAAgBmB,GAAYC,OAAS,aAK1D,CAACzC,GAAkBC,SAAS,KAAKN,MAAM,EACzC,MAAM6C,EAIR,GAAI,KAAK1C,cAAgBD,EAAeE,EAAqB,CAC3D,IAAM2C,EAAQC,GAAc9C,CAAAA,EAC5BA,IACA,MAAMf,GAAM4D,EAAO,KAAK1D,MAAM,EAC9B,QACF,CAGA,MAAMwD,CACR,CAGA,GAAI9C,GAAY,KAAKC,OAAQoC,EAAInC,OAAQC,EAAc,KAAKC,YAAY,EAAG,CACzE,IAAM8C,EAAmBb,EAAI1B,SAASa,IAAI,aAAA,GAAkB,KACtDwB,EACJE,IAAqB,KACjBC,KAAKC,IAAI,EAAGC,SAASH,EAAkB,EAAA,GAAO,CAAA,EAAK,IACnDD,GAAc9C,CAAAA,EACpB,MAAMkC,EAAIiB,KAAI,EACdnD,IACA,MAAMf,GAAM4D,EAAO,KAAK1D,MAAM,EAC9B,QACF,CAEA,OAAO,MAAM,KAAKiE,gBAAgBlB,CAAAA,CACpC,CACF,EA5EyB,oBA8EfmB,EAEV,OAAK,KAAK1C,qBACRuB,EAAMA,EAAIoB,MAAOX,GAAAA,CAIf,IAAIY,EAAe,GACfC,EAAO,GACPZ,EAAO,GAGLa,EAAQd,GAAYc,MAC1B,GAAIA,EAAO,CACT,IAAMC,EAAeD,GAAOE,SAAW,GACjCC,EAAYH,GAAOb,MAAQ,GAEjCW,EAAe,GAAGZ,GAAYnB,MAAQ,YAAA,KAAiBmB,GAAYgB,OAAAA,GACnEJ,GAAgB;;aAAkBE,GAAOjC,MAAQ,OAAA,KAAYkC,CAAAA,GACzDE,IACFL,GAAgB,KAAKK,CAAAA,KAEnBH,GAAOI,QACTN,GAAgB;EAAKE,EAAMI,KAAK,GAEpC,MAEEN,EAAeZ,GAAYkB,OAAS,GAItC,IAAMC,EAAY,KAAKvD,IAAIgC,SAAQ,EAAGwB,OAGtC,OAAIpB,GAAYnB,OAAS,cAAgBmB,GAAYC,OAAS,aAC5DA,EAAO,GACPY,EAAO,uDAEHM,EAAY,KAAK/C,iBACnByC,GAAQ,+BAA+BM,CAAAA,2NAKzCL,GAAOjC,OAAS,wBAChBiC,GAAOb,OAAS,8BAEhBA,EAAO,GACPY,EAAO,uDAEHM,EAAY,KAAK/C,iBACnByC,GAAQ,yBAAyBM,CAAAA,uKAI9B,CACLE,QAAS,GACTC,MAAO,CACLN,QAAS,GAAGhB,GAAYnB,MAAQ,YAAA,KAAiBmB,GAAYgB,OAAAA,GAC7DO,QAASX,EACTC,KAAMA,EACNZ,KAAMA,CACR,EACAuB,KAAM,KACNC,MAAO,KACPrE,OAAQ,EACRsE,WAAY,EACd,CACF,CAAA,GAIAnC,EAKAN,KAAKC,EAAaC,CAAAA,CACtB,CAKA,MAAcsB,gBAAgBlB,EAO3B,CACD,IAAI+B,EAAQ,KACRE,EAAO,KACPC,EAAuB,KACvBrE,EAASmC,EAAInC,OACbsE,EAAanC,EAAImC,WAErB,GAAInC,EAAIoC,GAAI,CACV,GAAI,KAAKxE,SAAW,OAAQ,CAC1B,IAAMY,EAAO,MAAMwB,EAAIiB,KAAI,EAC3B,GAAIzC,IAAS,GAEN,GAAI,KAAKF,QAAQa,IAAI,QAAA,IAAc,WACxC8C,EAAOzD,UAEP,KAAKF,QAAQa,IAAI,QAAA,GACjB,KAAKb,QAAQa,IAAI,QAAA,GAAWjB,SAAS,iCAAA,EAErC+D,EAAOzD,MAEP,IAAI,CACFyD,EAAO3B,KAAK+B,MAAM7D,CAAAA,CACpB,MAAQ,CAKN,GAHAuD,EAAQ,CAAEN,QAASjD,CAAK,EACxByD,EAAO,KAEH,KAAKxD,mBACP,MAAM,IAAI6D,EAAe,CAAEb,QAASjD,EAAMwD,QAAS,GAAIV,KAAM,GAAIZ,KAAM,EAAG,CAAA,CAE9E,CAEJ,CAEA,IAAM6B,EAAc,KAAKjE,QAAQa,IAAI,QAAA,GAAWqD,MAAM,iCAAA,EAChDC,EAAezC,EAAI1B,QAAQa,IAAI,eAAA,GAAkBuD,MAAM,GAAA,EAM7D,GALIH,GAAeE,GAAgBA,EAAaZ,OAAS,IACvDK,EAAQlB,SAASyB,EAAa,CAAA,CAAE,GAI9B,KAAK9D,eAAiBgE,MAAMC,QAAQX,CAAAA,EACtC,GAAIA,EAAKJ,OAAS,GAahB,GAZAE,EAAQ,CAENrB,KAAM,WACNsB,QAAS,mBAAmBC,EAAKJ,MAAM,0DACvCP,KAAM,KACNG,QAAS,uDACX,EACAQ,EAAO,KACPC,EAAQ,KACRrE,EAAS,IACTsE,EAAa,iBAET,KAAK1D,mBAGP,MAAM,IAAI6D,EAAe,CAAE,GAAGP,EAAOT,KAAMS,EAAMT,MAAQ,EAAG,CAAA,OAErDW,EAAKJ,SAAW,EACzBI,EAAOA,EAAK,CAAA,EAEZA,EAAO,IAGb,KAAO,CACL,IAAMzD,EAAO,MAAMwB,EAAIiB,KAAI,EAE3B,GAAI,CACFc,EAAQzB,KAAK+B,MAAM7D,CAAAA,EAGfmE,MAAMC,QAAQb,CAAAA,GAAU/B,EAAInC,SAAW,MACzCoE,EAAO,CAAA,EACPF,EAAQ,KACRlE,EAAS,IACTsE,EAAa,KAEjB,MAAQ,CAEFnC,EAAInC,SAAW,KAAOW,IAAS,IACjCX,EAAS,IACTsE,EAAa,cAEbJ,EAAQ,CACNN,QAASjD,CACX,CAEJ,CAEA,GAAIuD,GAAS,KAAKtD,mBAChB,MAAM,IAAI6D,EAAeP,CAAAA,CAE7B,CAEA,MAAO,CACLD,QAASC,IAAU,KACnBA,MAAAA,EACAE,KAAAA,EACAC,MAAAA,EACArE,OAAAA,EACAsE,WAAAA,CACF,CACF,CAWAU,SAIE,CAEA,OAAO,IAKT,CAgGAC,eAYE,CACA,OAAO,IAUT,CACF,EC5sBA,IAAqBC,GAArB,cASUC,EAAAA,CAhBV,MAgBUA,CAAAA,EAAAA,kCACRC,cASE,CACA,OAAO,MAAMA,aAAAA,CAUf,CA+CAC,OAIEC,EAcA,CAEA,IAAIC,EAAS,GACPC,GAAkBF,GAAW,KAChCG,MAAM,EAAA,EACNC,IAAKC,GACA,KAAKC,KAAKD,CAAAA,GAAM,CAACJ,EACZ,IAELI,IAAM,MACRJ,EAAS,CAACA,GAELI,EACT,EACCE,KAAK,EAAA,EACR,YAAKC,IAAIC,aAAaC,IAAI,SAAUR,CAAAA,EACpC,KAAKS,QAAQC,OAAO,SAAU,uBAAA,EACvB,IAcT,CAwOAC,MACEC,EACA,CACEC,UAAAA,EAAY,GACZC,WAAAA,EACAC,aAAAA,EACAC,gBAAAA,EAAkBD,CAAY,EAM5B,CAAC,EACC,CACN,IAAME,EAAMD,EAAkB,GAAGA,CAAAA,SAA0B,QACrDE,EAAgB,KAAKZ,IAAIC,aAAaY,IAAIF,CAAAA,EAEhD,YAAKX,IAAIC,aAAaC,IACpBS,EACA,GAAGC,EAAgB,GAAGA,CAAAA,IAAmB,EAAA,GAAKN,CAAAA,IAAUC,EAAY,MAAQ,MAAA,GAC1EC,IAAeM,OAAY,GAAKN,EAAa,cAAgB,YAAA,EAC7D,EAEG,IACT,CAsGAO,MACEC,EACA,CACEP,aAAAA,EACAC,gBAAAA,EAAkBD,CAAY,EACyB,CAAC,EACpD,CACN,IAAME,EAAM,OAAOD,EAAoB,IAAc,QAAU,GAAGA,CAAAA,SAClE,YAAKV,IAAIC,aAAaC,IAAIS,EAAK,GAAGK,CAAAA,EAAM,EACjC,IACT,CAyDAC,MACEC,EACAC,EACA,CACEV,aAAAA,EACAC,gBAAAA,EAAkBD,CAAY,EACyB,CAAC,EACpD,CACN,IAAMW,EACJ,OAAOV,EAAoB,IAAc,SAAW,GAAGA,CAAAA,UACnDW,EAAW,OAAOX,EAAoB,IAAc,QAAU,GAAGA,CAAAA,SACvE,YAAKV,IAAIC,aAAaC,IAAIkB,EAAW,GAAGF,CAAAA,EAAM,EAE9C,KAAKlB,IAAIC,aAAaC,IAAImB,EAAU,GAAGF,EAAKD,EAAO,CAAA,EAAG,EAC/C,IACT,CAoEAI,YAAYC,EAA2B,CACrC,YAAKA,OAASA,EACP,IACT,CA4CAC,QAIE,CACA,YAAKrB,QAAQD,IAAI,SAAU,mCAAA,EACpB,IACT,CAyCAuB,aAEqE,CAGnE,YAAKC,cAAgB,GACd,IACT,CAyCAC,KAA6D,CAC3D,YAAKxB,QAAQD,IAAI,SAAU,UAAA,EACpB,IACT,CAQA0B,SAAkF,CAChF,YAAKzB,QAAQD,IAAI,SAAU,sBAAA,EACpB,IACT,CAkGA2B,QAAQ,CACNC,QAAAA,EAAU,GACVC,QAAAA,EAAU,GACVC,SAAAA,EAAW,GACXC,QAAAA,EAAU,GACVC,IAAAA,EAAM,GACNC,OAAAA,EAAS,MAAM,EAQb,CAAC,EAAG,CACN,IAAMC,EAAU,CACdN,EAAU,UAAY,KACtBC,EAAU,UAAY,KACtBC,EAAW,WAAa,KACxBC,EAAU,UAAY,KACtBC,EAAM,MAAQ,MAEbG,OAAOC,OAAAA,EACPvC,KAAK,GAAA,EAEFwC,EAAe,KAAKpC,QAAQU,IAAI,QAAA,GAAa,mBAKnD,OAJA,KAAKV,QAAQD,IACX,SACA,8BAA8BiC,CAAAA,UAAgBI,CAAAA,cAA0BH,CAAAA,GAAU,EAEhFD,IAAW,OACN,KAMA,IAEX,CA+BAK,UAAiB,CACf,YAAKrC,QAAQC,OAAO,SAAU,aAAA,EACvB,IACT,CAyCAqC,SASE,CACA,OAAO,IAUT,CAWAC,YAAY1B,EAKiE,CAC3E,YAAKb,QAAQC,OAAO,SAAU,iBAAA,EAC9B,KAAKD,QAAQC,OAAO,SAAU,gBAAgBY,CAAAA,EAAM,EAC7C,IAKT,CACF,EC5/BA,IAAM2B,GAA+B,IAAIC,OAAO,OAAA,EA2D3BC,EAArB,cASUC,EAAAA,CAvGV,MAuGUA,CAAAA,EAAAA,+BAURC,cASE,CACA,OAAO,MAAMA,aAAAA,CAUf,CAgDAC,GACEC,EAOAC,EAKM,CACN,YAAKC,IAAIC,aAAaC,OAAOJ,EAAkB,MAAMC,CAAAA,EAAO,EACrD,IACT,CAqDAI,IACEL,EAOAC,EAKM,CACN,YAAKC,IAAIC,aAAaC,OAAOJ,EAAkB,OAAOC,CAAAA,EAAO,EACtD,IACT,CAoDAK,GAAGN,EAAgBC,EAAsB,CACvC,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMC,CAAAA,EAAO,EAC3C,IACT,CAoDAM,IAAIP,EAAgBC,EAAsB,CACxC,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOC,CAAAA,EAAO,EAC5C,IACT,CAgDAO,GAAGR,EAAgBC,EAAsB,CACvC,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMC,CAAAA,EAAO,EAC3C,IACT,CAoDAQ,IAAIT,EAAgBC,EAAsB,CACxC,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOC,CAAAA,EAAO,EAC5C,IACT,CAgDAS,KAAKV,EAAgBW,EAAuB,CAC1C,YAAKT,IAAIC,aAAaC,OAAOJ,EAAQ,QAAQW,CAAAA,EAAS,EAC/C,IACT,CAgBAC,UAAUZ,EAAgBa,EAAmC,CAC3D,YAAKX,IAAIC,aAAaC,OAAOJ,EAAQ,cAAca,EAASC,KAAK,GAAA,CAAA,GAAO,EACjE,IACT,CAgBAC,UAAUf,EAAgBa,EAAmC,CAC3D,YAAKX,IAAIC,aAAaC,OAAOJ,EAAQ,cAAca,EAASC,KAAK,GAAA,CAAA,GAAO,EACjE,IACT,CAgDAE,MAAMhB,EAAgBW,EAAuB,CAC3C,YAAKT,IAAIC,aAAaC,OAAOJ,EAAQ,SAASW,CAAAA,EAAS,EAChD,IACT,CAgBAM,WAAWjB,EAAgBa,EAAmC,CAC5D,YAAKX,IAAIC,aAAaC,OAAOJ,EAAQ,eAAea,EAASC,KAAK,GAAA,CAAA,GAAO,EAClE,IACT,CAgBAI,WAAWlB,EAAgBa,EAAmC,CAC5D,YAAKX,IAAIC,aAAaC,OAAOJ,EAAQ,eAAea,EAASC,KAAK,GAAA,CAAA,GAAO,EAClE,IACT,CAWAK,WAAWnB,EAAgBW,EAAuB,CAChD,YAAKT,IAAIC,aAAaC,OAAOJ,EAAQ,SAASW,CAAAA,EAAS,EAChD,IACT,CAWAS,YAAYpB,EAAgBW,EAAuB,CACjD,YAAKT,IAAIC,aAAaC,OAAOJ,EAAQ,UAAUW,CAAAA,EAAS,EACjD,IACT,CA6DAU,GAAGrB,EAAgBC,EAA6B,CAC9C,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMC,CAAAA,EAAO,EAC3C,IACT,CAYAqB,WACEtB,EACAC,EAKM,CACN,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,cAAcC,CAAAA,EAAO,EACnD,IACT,CAkDAsB,GACEvB,EACAwB,EAUM,CACN,IAAMC,EAAgBC,MAAMC,KAAK,IAAIC,IAAIJ,CAAAA,CAAAA,EACtCK,IAAKC,GAGA,OAAOA,GAAM,UAAYpC,GAA6BqC,KAAKD,CAAAA,EAAW,IAAIA,CAAAA,IAClE,GAAGA,CAAAA,EACjB,EACChB,KAAK,GAAA,EACR,YAAKZ,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOyB,CAAAA,GAAgB,EACrD,IACT,CAQAO,MACEhC,EACAwB,EAOM,CACN,IAAMC,EAAgBC,MAAMC,KAAK,IAAIC,IAAIJ,CAAAA,CAAAA,EACtCK,IAAKC,GAGA,OAAOA,GAAM,UAAYpC,GAA6BqC,KAAKD,CAAAA,EAAW,IAAIA,CAAAA,IAClE,GAAGA,CAAAA,EACjB,EACChB,KAAK,GAAA,EACR,YAAKZ,IAAIC,aAAaC,OAAOJ,EAAQ,WAAWyB,CAAAA,GAAgB,EACzD,IACT,CAwIAQ,SAASjC,EAAgBC,EAAoE,CAC3F,OAAI,OAAOA,GAAU,SAGnB,KAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMC,CAAAA,EAAO,EACzCyB,MAAMQ,QAAQjC,CAAAA,EAEvB,KAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOC,EAAMa,KAAK,GAAA,CAAA,GAAO,EAG9D,KAAKZ,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMmC,KAAKC,UAAUnC,CAAAA,CAAAA,EAAQ,EAE7D,IACT,CAyIAoC,YAAYrC,EAAgBC,EAAoE,CAC9F,OAAI,OAAOA,GAAU,SAEnB,KAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMC,CAAAA,EAAO,EACzCyB,MAAMQ,QAAQjC,CAAAA,EAEvB,KAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOC,EAAMa,KAAK,GAAA,CAAA,GAAO,EAG9D,KAAKZ,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMmC,KAAKC,UAAUnC,CAAAA,CAAAA,EAAQ,EAE7D,IACT,CA4DAqC,QAAQtC,EAAgBuC,EAAqB,CAC3C,YAAKrC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMuC,CAAAA,EAAO,EAC3C,IACT,CA6DAC,SAASxC,EAAgBuC,EAAqB,CAC5C,YAAKrC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOuC,CAAAA,EAAO,EAC5C,IACT,CA2DAE,QAAQzC,EAAgBuC,EAAqB,CAC3C,YAAKrC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMuC,CAAAA,EAAO,EAC3C,IACT,CA6DAG,SAAS1C,EAAgBuC,EAAqB,CAC5C,YAAKrC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOuC,CAAAA,EAAO,EAC5C,IACT,CA4DAI,cAAc3C,EAAgBuC,EAAqB,CACjD,YAAKrC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOuC,CAAAA,EAAO,EAC5C,IACT,CAmGAK,SAAS5C,EAAgBC,EAA0C,CACjE,OAAI,OAAOA,GAAU,SAEnB,KAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMC,CAAAA,EAAO,EAGlD,KAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAOC,EAAMa,KAAK,GAAA,CAAA,GAAO,EAEzD,IACT,CAoHA+B,WACE7C,EACA8C,EACA,CAAEC,OAAAA,EAAQC,KAAAA,CAAI,EAAmE,CAAC,EAC5E,CACN,IAAIC,EAAW,GACXD,IAAS,QACXC,EAAW,KACFD,IAAS,SAClBC,EAAW,KACFD,IAAS,cAClBC,EAAW,KAEb,IAAMC,EAAaH,IAAWI,OAAY,GAAK,IAAIJ,CAAAA,IACnD,YAAK7C,IAAIC,aAAaC,OAAOJ,EAAQ,GAAGiD,CAAAA,MAAcC,CAAAA,IAAcJ,CAAAA,EAAO,EACpE,IACT,CAgDAM,MAAMN,EAAsC,CAC1CO,cAAOC,QAAQR,CAAAA,EAGZS,OAAO,CAAC,CAACC,EAAGvD,CAAAA,IAAWA,IAAUkD,MAAAA,EACjCM,QAAQ,CAAC,CAACzD,EAAQC,CAAAA,IAAM,CACvB,KAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,MAAMC,CAAAA,EAAO,CACpD,CAAA,EACK,IACT,CAkGAyD,IACE1D,EACA2D,EACA1D,EAWK,CACL,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,OAAO2D,CAAAA,IAAY1D,CAAAA,EAAO,EACxD,IACT,CAyJA2D,GACEC,EACA,CACEC,aAAAA,EACAC,gBAAAA,EAAkBD,CAAY,EACyB,CAAC,EACpD,CACN,IAAME,EAAMD,EAAkB,GAAGA,CAAAA,MAAuB,KACxD,YAAK7D,IAAIC,aAAaC,OAAO4D,EAAK,IAAIH,CAAAA,GAAU,EACzC,IACT,CAyHAN,OAAOvD,EAAgB2D,EAAkB1D,EAAsB,CAC7D,YAAKC,IAAIC,aAAaC,OAAOJ,EAAQ,GAAG2D,CAAAA,IAAY1D,CAAAA,EAAO,EACpD,IACT,CACF,ECloEA,IAAqBgE,GAArB,KAAqBA,CAXrB,MAWqBA,CAAAA,EAAAA,8BAOnBC,IACAC,QACAC,OACAC,OACAC,MACAC,eAQAC,MAiCA,YACEN,EACA,CACEC,QAAAA,EAAU,CAAC,EACXC,OAAAA,EACAE,MAAAA,EACAC,eAAAA,EAAiB,IACjBC,MAAAA,CAAK,EAQP,CACA,KAAKN,IAAMA,EACX,KAAKC,QAAU,IAAIM,QAAQN,CAAAA,EAC3B,KAAKC,OAASA,EACd,KAAKE,MAAQA,EACb,KAAKC,eAAiBA,EACtB,KAAKC,MAAQA,CACf,CAKQE,mBAAoD,CAC1D,MAAO,CACLR,IAAK,IAAIS,IAAI,KAAKT,IAAIU,SAAQ,CAAA,EAC9BT,QAAS,IAAIM,QAAQ,KAAKN,OAAO,CACnC,CACF,CAsyBAU,OAWEC,EACAC,EAYA,CACA,GAAM,CAAEC,KAAAA,EAAO,GAAOC,MAAAA,CAAK,EAAKF,GAAW,CAAC,EAEtCG,EAASF,EAAO,OAAS,MAE3BG,EAAS,GACPC,GAAkBN,GAAW,KAChCO,MAAM,EAAA,EACNC,IAAKC,GACA,KAAKC,KAAKD,CAAAA,GAAM,CAACJ,EACZ,IAELI,IAAM,MACRJ,EAAS,CAACA,GAELI,EACT,EACCE,KAAK,EAAA,EAEF,CAAEvB,IAAAA,EAAKC,QAAAA,CAAO,EAAK,KAAKO,kBAAiB,EAC/CR,OAAAA,EAAIwB,aAAaC,IAAI,SAAUP,CAAAA,EAE3BH,GACFd,EAAQyB,OAAO,SAAU,SAASX,CAAAA,EAAO,EAGpC,IAAIY,EAAuB,CAChCX,OAAAA,EACAhB,IAAAA,EACAC,QAAAA,EACAC,OAAQ,KAAKA,OACbE,MAAO,KAAKA,MACZC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CA0HAsB,OACEC,EASA,CACEd,MAAAA,EACAe,cAAAA,EAAgB,EAAI,EAIlB,CAAC,EASL,CACA,IAAMd,EAAS,OACT,CAAEhB,IAAAA,EAAKC,QAAAA,CAAO,EAAK,KAAKO,kBAAiB,EAS/C,GAPIO,GACFd,EAAQyB,OAAO,SAAU,SAASX,CAAAA,EAAO,EAEtCe,GACH7B,EAAQyB,OAAO,SAAU,iBAAiB,EAGxCK,MAAMC,QAAQH,CAAAA,EAAS,CACzB,IAAMjB,EAAUiB,EAAOI,OAAO,CAACC,EAAKC,IAAMD,EAAIE,OAAOC,OAAOC,KAAKH,CAAAA,CAAAA,EAAK,CAAA,CAAE,EACxE,GAAIvB,EAAQ2B,OAAS,EAAG,CACtB,IAAMC,EAAgB,IAAI,IAAIC,IAAI7B,CAAAA,GAAUQ,IAAKsB,GAAW,IAAIA,CAAAA,GAAS,EACzE1C,EAAIwB,aAAaC,IAAI,UAAWe,EAAcjB,KAAK,GAAA,CAAA,CACrD,CACF,CAEA,OAAO,IAAII,EAAuB,CAChCX,OAAAA,EACAhB,IAAAA,EACAC,QAAAA,EACAC,OAAQ,KAAKA,OACbyC,KAAMd,EACNzB,MAAO,KAAKA,OAASA,MACrBC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CA4NAsC,OACEf,EASA,CACEgB,WAAAA,EACAC,iBAAAA,EAAmB,GACnB/B,MAAAA,EACAe,cAAAA,EAAgB,EAAI,EAMlB,CAAC,EASL,CACA,IAAMd,EAAS,OACT,CAAEhB,IAAAA,EAAKC,QAAAA,CAAO,EAAK,KAAKO,kBAAiB,EAY/C,GAVAP,EAAQyB,OAAO,SAAU,cAAcoB,EAAmB,SAAW,OAAA,aAAoB,EAErFD,IAAeE,QAAW/C,EAAIwB,aAAaC,IAAI,cAAeoB,CAAAA,EAC9D9B,GACFd,EAAQyB,OAAO,SAAU,SAASX,CAAAA,EAAO,EAEtCe,GACH7B,EAAQyB,OAAO,SAAU,iBAAA,EAGvBK,MAAMC,QAAQH,CAAAA,EAAS,CACzB,IAAMjB,EAAUiB,EAAOI,OAAO,CAACC,EAAKC,IAAMD,EAAIE,OAAOC,OAAOC,KAAKH,CAAAA,CAAAA,EAAK,CAAA,CAAE,EACxE,GAAIvB,EAAQ2B,OAAS,EAAG,CACtB,IAAMC,EAAgB,IAAI,IAAIC,IAAI7B,CAAAA,GAAUQ,IAAKsB,GAAW,IAAIA,CAAAA,GAAS,EACzE1C,EAAIwB,aAAaC,IAAI,UAAWe,EAAcjB,KAAK,GAAA,CAAA,CACrD,CACF,CAEA,OAAO,IAAII,EAAuB,CAChCX,OAAAA,EACAhB,IAAAA,EACAC,QAAAA,EACAC,OAAQ,KAAKA,OACbyC,KAAMd,EACNzB,MAAO,KAAKA,OAASA,MACrBC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CAsJA0C,OACEnB,EAIA,CACEd,MAAAA,CAAK,EAGH,CAAC,EASL,CACA,IAAMC,EAAS,QACT,CAAEhB,IAAAA,EAAKC,QAAAA,CAAO,EAAK,KAAKO,kBAAiB,EAE/C,OAAIO,GACFd,EAAQyB,OAAO,SAAU,SAASX,CAAAA,EAAO,EAGpC,IAAIY,EAAuB,CAChCX,OAAAA,EACAhB,IAAAA,EACAC,QAAAA,EACAC,OAAQ,KAAKA,OACbyC,KAAMd,EACNzB,MAAO,KAAKA,OAASA,MACrBC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CAiIA2C,OAAO,CACLlC,MAAAA,CAAK,EAGH,CAAC,EAQH,CACA,IAAMC,EAAS,SACT,CAAEhB,IAAAA,EAAKC,QAAAA,CAAO,EAAK,KAAKO,kBAAiB,EAE/C,OAAIO,GACFd,EAAQyB,OAAO,SAAU,SAASX,CAAAA,EAAO,EAGpC,IAAIY,EAAuB,CAChCX,OAAAA,EACAhB,IAAAA,EACAC,QAAAA,EACAC,OAAQ,KAAKA,OACbE,MAAO,KAAKA,OAASA,MACrBC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CACF,ECptDA,IAAqB4C,EAArB,MAAqBA,CAAAA,CAfrB,MAeqBA,CAAAA,EAAAA,wBAkBnBC,IACAC,QACAC,WACAC,MACAC,eAGAC,MA0CA,YACEL,EACA,CACEC,QAAAA,EAAU,CAAC,EACXK,OAAAA,EACAH,MAAAA,EACAI,QAAAA,EACAH,eAAAA,EAAiB,IACjBC,MAAAA,CAAK,EAQH,CAAC,EACL,CACA,KAAKL,IAAMA,EACX,KAAKC,QAAU,IAAIO,QAAQP,CAAAA,EAC3B,KAAKC,WAAaI,EAClB,KAAKF,eAAiBA,EAEtB,IAAMK,EAAgBN,GAASO,WAAWP,MAGtCI,IAAYI,QAAaJ,EAAU,EACrC,KAAKJ,MAAQ,CAACS,EAAOC,IAAAA,CACnB,IAAMC,EAAa,IAAIC,gBACjBC,EAAYC,WAAW,IAAMH,EAAWI,MAAK,EAAIX,CAAAA,EAGjDY,EAAiBN,GAAMO,OAC7B,GAAID,EAAgB,CAElB,GAAIA,EAAeE,QACjBC,oBAAaN,CAAAA,EACNP,EAAcG,EAAOC,CAAAA,EAI9B,IAAMU,EAAeC,EAAA,IAAA,CACnBF,aAAaN,CAAAA,EACbF,EAAWI,MAAK,CAClB,EAHqB,gBAIrBC,OAAAA,EAAeM,iBAAiB,QAASF,EAAc,CAAEG,KAAM,EAAK,CAAA,EAE7DjB,EAAcG,EAAO,CAC1B,GAAGC,EACHO,OAAQN,EAAWM,MACrB,CAAA,EAAGO,QAAQ,IAAA,CACTL,aAAaN,CAAAA,EACbG,EAAeS,oBAAoB,QAASL,CAAAA,CAC9C,CAAA,CACF,CAEA,OAAOd,EAAcG,EAAO,CAC1B,GAAGC,EACHO,OAAQN,EAAWM,MACrB,CAAA,EAAGO,QAAQ,IAAML,aAAaN,CAAAA,CAAAA,CAChC,EAEA,KAAKb,MAAQM,EAEf,KAAKJ,MAAQA,CACf,CAeAwB,KACEC,EACwD,CACxD,GAAI,CAACA,GAAY,OAAOA,GAAa,UAAYA,EAASC,KAAI,IAAO,GACnE,MAAM,IAAIC,MAAM,6DAAA,EAGlB,IAAMhC,EAAM,IAAIiC,IAAI,GAAG,KAAKjC,GAAG,IAAI8B,CAAAA,EAAU,EAC7C,OAAO,IAAII,GAAsBlC,EAAK,CACpCC,QAAS,IAAIO,QAAQ,KAAKP,OAAO,EACjCK,OAAQ,KAAKJ,WACbC,MAAO,KAAKA,MACZC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CAWAC,OACEA,EAMA,CACA,OAAO,IAAIP,EAAgB,KAAKC,IAAK,CACnCC,QAAS,KAAKA,QACdK,OAAAA,EACAH,MAAO,KAAKA,MACZC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CAuKA8B,IAMEC,EACAC,EAAa,CAAC,EACd,CACEC,KAAAA,EAAO,GACPC,IAAAA,EAAM,GACNC,MAAAA,CAAK,EAKH,CAAC,EASL,CACA,IAAIC,EACEzC,EAAM,IAAIiC,IAAI,GAAG,KAAKjC,GAAG,QAAQoC,CAAAA,EAAI,EACvCM,EAEEC,EAAYnB,EAACoB,GACjBA,IAAM,MAAQ,OAAOA,GAAM,WAAa,CAACC,MAAMC,QAAQF,CAAAA,GAAMA,EAAEG,KAAKJ,CAAAA,GADpD,aAEZK,EAAgBV,GAAQW,OAAOC,OAAOb,CAAAA,EAAgBU,KAAKJ,CAAAA,EAC7DK,GACFP,EAAS,OACTC,EAAOL,GACEC,GAAQC,GACjBE,EAASH,EAAO,OAAS,MACzBW,OAAOE,QAAQd,CAAAA,EAGZe,OAAO,CAAC,CAACC,EAAGC,CAAAA,IAAWA,IAAU3C,MAAAA,EAEjC4C,IAAI,CAAC,CAACC,EAAMF,CAAAA,IAAW,CAACE,EAAMX,MAAMC,QAAQQ,CAAAA,EAAS,IAAIA,EAAMG,KAAK,GAAA,CAAA,IAAU,GAAGH,CAAAA,GAAQ,EACzFI,QAAQ,CAAC,CAACF,EAAMF,CAAAA,IAAM,CACrBtD,EAAI2D,aAAaC,OAAOJ,EAAMF,CAAAA,CAChC,CAAA,IAEFb,EAAS,OACTC,EAAOL,GAGT,IAAMpC,EAAU,IAAIO,QAAQ,KAAKP,OAAO,EACxC,OAAI+C,EACF/C,EAAQ4D,IAAI,SAAUrB,EAAQ,SAASA,CAAAA,kBAAyB,gBAAA,EACvDA,GACTvC,EAAQ4D,IAAI,SAAU,SAASrB,CAAAA,EAAO,EAGjC,IAAIsB,EAAuB,CAChCrB,OAAAA,EACAzC,IAAAA,EACAC,QAAAA,EACAK,OAAQ,KAAKJ,WACbwC,KAAAA,EACAvC,MAAO,KAAKA,OAASA,MACrBC,eAAgB,KAAKA,eACrBC,MAAO,KAAKA,KACd,CAAA,CACF,CACF,EC/YO,IAAM0D,GAAN,KAAMA,CAzCb,MAyCaA,CAAAA,EAAAA,gCAKQC,OAEjB,YAAYC,EAA4BC,EAAgC,CAGpE,KAAKF,OAAS,IAAIG,EACd,GAAGF,EAAOG,QAAQ,GAAGC,EAAmBC,QAAQ,GAChD,CAAEJ,MAAAA,CAAM,CAAA,EAMZ,KAAKK,KAAO,KAAKP,OAAOO,KAAKC,KAAK,KAAKR,MAAM,EAC7C,KAAKS,IAAM,KAAKT,OAAOS,IAAID,KAAK,KAAKR,MAAM,CAC/C,CASSO,KAMAE,IAMT,IAAIC,KAAc,CACd,OAAO,KAAKV,OAAOU,GACvB,CACJ,EAKO,SAASC,GACZV,EACAC,EAA8B,CAE9B,OAAO,IAAIH,GAAkCE,EAAQC,CAAAA,CACzD,CALgBS,EAAAA,GAAAA,wBCtDT,IAAMC,EAAN,cAA+BC,KAAAA,CApCtC,MAoCsCA,CAAAA,EAAAA,yBACzBC,MACAC,OACAC,UACAC,aAET,YACIH,EACAI,EAA6B,CAAC,EAChC,CACE,IAAMC,EACF,OAAOL,GAAU,SACX,CAAEM,QAASN,EAAOO,KAAM,eAAgBC,MAAO,KAAMC,KAAM,IAAK,EAChET,EACV,MAAMK,EAASC,OAAO,EACtB,KAAKI,KAAO,mBACZ,KAAKV,MAAQK,EACb,KAAKJ,OAASG,EAAKH,OACnB,KAAKC,UAAYE,EAAKF,UACtB,KAAKC,aAAeC,EAAKD,aACrBC,EAAKO,QAAUC,SACT,UAAW,MACbC,OAAOC,eAAe,KAAM,QAAS,CACjCC,MAAOX,EAAKO,MACZK,SAAU,GACVC,WAAY,GACZC,aAAc,EAClB,CAAA,EAGZ,CACJ,EAUO,SAASC,GAAgBC,EAA0B,CACtD,GAAI,CAACA,EAAa,OAElB,IAAMC,EAAUD,EAAYE,KAAI,EAG1BC,EAAQC,OAAOH,CAAAA,EACrB,GAAI,CAACI,MAAMF,CAAAA,GAAUA,GAAS,GAAKC,OAAOE,UAAUH,CAAAA,EAChD,OAAOA,EAAQ,IAInB,IAAMI,EAASC,KAAKC,MAAMR,CAAAA,EAC1B,GAAI,CAACI,MAAME,CAAAA,EAAS,CAChB,IAAMG,EAAOH,EAASC,KAAKG,IAAG,EAC9B,OAAOD,EAAO,EAAIA,EAAO,CAC7B,CAGJ,CAnBgBX,EAAAA,GAAAA,mBCVhB,SAASa,KAAeC,EAAiB,CACrC,OAAOA,EAAOC,KAAMC,GAA2B,OAAOA,GAAU,UAAYA,EAAMC,OAAS,CAAA,CAC/F,CAFSJ,EAAAA,EAAAA,eAIT,SAASK,KAAeJ,EAAiB,CACrC,OAAOA,EAAOC,KAAMC,GAA2B,OAAOA,GAAU,UAAYG,OAAOC,SAASJ,CAAAA,CAAAA,CAChG,CAFSE,EAAAA,EAAAA,eAIT,SAASG,MAAgBP,EAAiB,CACtC,OAAOA,EAAOC,KAAMC,GAA4B,OAAOA,GAAU,SAAA,CACrE,CAFSK,EAAAA,GAAAA,gBAIT,SAASC,GAAgBN,EAAc,CACnC,GAAI,CAACA,GAAS,OAAOA,GAAU,SAAU,OACzC,IAAMO,EAAMP,EACNQ,EAAQC,MAAMC,QAAQH,EAAIC,KAAK,EAAID,EAAIC,MAAMG,OAAQC,GAAyB,OAAOA,GAAS,QAAA,EAAYC,OAC1GC,EAASL,MAAMC,QAAQH,EAAIO,MAAM,EAAIP,EAAIO,OAAOH,OAAQC,GAAyB,OAAOA,GAAS,QAAA,EAAYC,OACnH,OAAOL,GAAOP,QAAUa,GAAQb,OAAS,CAAE,GAAIO,GAAOP,OAAS,CAAEO,MAAAA,CAAM,EAAI,CAAC,EAAI,GAAIM,GAAQb,OAAS,CAAEa,OAAAA,CAAO,EAAI,CAAC,CAAG,EAAID,MAC9H,CANSP,EAAAA,GAAAA,mBAQT,SAASS,GAAkBf,EAAc,CACrC,GAAI,CAACA,GAAS,OAAOA,GAAU,SAAU,OAEzC,IAAMgB,EAAUC,OAAOD,QADXhB,CACmBO,EAAKI,OAAO,CAAC,CAAA,CAAGO,CAAAA,IAAa,OAAOA,GAAY,SAAA,EAC/E,OAAOF,EAAQf,OAASgB,OAAOE,YAAYH,CAAAA,EAAsCH,MACrF,CALSE,EAAAA,GAAAA,qBAOT,SAASK,GAAapB,EAAc,CAChC,GAAI,CAACA,GAAS,OAAOA,GAAU,SAAU,OACzC,IAAMO,EAAMP,EACNqB,EAA8B,CAChC,GAAIxB,EAAYU,EAAIe,QAAQ,EAAI,CAAEA,SAAUf,EAAIe,QAAS,EAAI,CAAC,EAC9D,GAAIpB,EAAYK,EAAIgB,qBAAqB,IAAMV,OAAY,CAAEU,sBAAuBhB,EAAIgB,qBAAsB,EAAI,CAAC,EACnH,GAAIrB,EAAYK,EAAIiB,sBAAsB,IAAMX,OAAY,CAAEW,uBAAwBjB,EAAIiB,sBAAuB,EAAI,CAAC,EACtH,GAAI3B,EAAYU,EAAIkB,WAAW,EAAI,CAAEA,YAAalB,EAAIkB,WAAY,EAAI,CAAC,CAC3E,EACA,OAAOR,OAAOS,KAAKL,CAAAA,EAASpB,OAASoB,EAAUR,MACnD,CAVSO,EAAAA,GAAAA,gBAmBF,SAASO,GAAepB,EAAgB,CAC3C,IAAMqB,EAAK/B,EAAYU,EAAIqB,GAAIrB,EAAIsB,EAAE,EACrC,OAAKD,EAEE,CACHA,GAAAA,EACAE,KAAMjC,EAAYU,EAAIuB,KAAMvB,EAAIwB,IAAI,GAAKH,EACzC,GAAI/B,EAAYU,EAAIyB,SAAUzB,EAAI0B,QAAQ,EAAI,CAAED,SAAUnC,EAAYU,EAAIyB,SAAUzB,EAAI0B,QAAQ,CAAE,EAAI,CAAC,EACvG,GAAIpC,EAAYU,EAAI2B,OAAQ3B,EAAI4B,MAAM,EAAI,CAAED,OAAQrC,EAAYU,EAAI2B,OAAQ3B,EAAI4B,MAAM,CAAE,EAAI,CAAC,EAC7F,GAAItC,EAAYU,EAAI6B,OAAQ7B,EAAI8B,MAAM,EAAI,CAAED,OAAQvC,EAAYU,EAAI6B,OAAQ7B,EAAI8B,MAAM,CAAE,EAAI,CAAC,EAC7F,GAAIxC,EAAYU,EAAI+B,QAAS/B,EAAIgC,OAAO,EAAI,CAAED,QAASzC,EAAYU,EAAI+B,QAAS/B,EAAIgC,OAAO,CAAE,EAAI,CAAC,EAClG,GAAI1C,EAAYU,EAAIiC,YAAajC,EAAIkC,WAAW,EAAI,CAAED,YAAa3C,EAAYU,EAAIiC,YAAajC,EAAIkC,WAAW,CAAE,EAAI,CAAC,EACtH,GAAI5C,EAAYU,EAAImC,cAAenC,EAAIoC,aAAa,EAAI,CAAED,cAAe7C,EAAYU,EAAImC,cAAenC,EAAIoC,aAAa,CAAE,EAAI,CAAC,EAChI,GAAI9C,EAAYU,EAAIqC,cAAerC,EAAIsC,aAAa,EAAI,CAAED,cAAe/C,EAAYU,EAAIqC,cAAerC,EAAIsC,aAAa,CAAE,EAAI,CAAC,EAChI,GAAIhD,EAAYU,EAAIuC,QAASvC,EAAIwC,OAAO,EAAI,CAAED,QAASjD,EAAYU,EAAIuC,QAASvC,EAAIwC,OAAO,CAAE,EAAI,CAAC,EAClG,GAAI7C,EAAYK,EAAIyC,cAAezC,EAAI0C,aAAa,IAAMpC,OAAY,CAAEmC,cAAe9C,EAAYK,EAAIyC,cAAezC,EAAI0C,aAAa,CAAE,EAAI,CAAC,EAC9I,GAAI/C,EAAYK,EAAI2C,eAAgB3C,EAAI4C,cAAc,IAAMtC,OAAY,CAAEqC,eAAgBhD,EAAYK,EAAI2C,eAAgB3C,EAAI4C,cAAc,CAAE,EAAI,CAAC,EACnJ,GAAIjD,EAAYK,EAAI6C,gBAAiB7C,EAAI8C,eAAe,IAAMxC,OAAY,CAAEuC,gBAAiBlD,EAAYK,EAAI6C,gBAAiB7C,EAAI8C,eAAe,CAAE,EAAI,CAAC,EACxJ,GAAI/C,GAAgBC,EAAI+C,YAAc/C,EAAIgD,UAAU,EAAI,CAAED,WAAYhD,GAAgBC,EAAI+C,YAAc/C,EAAIgD,UAAU,CAAE,EAAI,CAAC,EAC7H,GAAIxC,GAAkBR,EAAIiD,cAAgBjD,EAAIkD,YAAY,EAAI,CAAED,aAAczC,GAAkBR,EAAIiD,cAAgBjD,EAAIkD,YAAY,CAAE,EAAI,CAAC,EAC3IvC,QAASb,GAAaE,EAAIW,QAASX,EAAImD,OAAO,GAAK,GACnD,GAAIrD,GAAaE,EAAIoD,UAAWpD,EAAIqD,SAAS,IAAM/C,OAAY,CAAE8C,UAAWtD,GAAaE,EAAIoD,UAAWpD,EAAIqD,SAAS,CAAE,EAAI,CAAC,EAC5H,GAAI1D,EAAYK,EAAIsD,UAAWtD,EAAIuD,SAAS,IAAMjD,OAAY,CAAEgD,UAAW3D,EAAYK,EAAIsD,UAAWtD,EAAIuD,SAAS,CAAE,EAAI,CAAC,EAC1H,GAAI1C,GAAab,EAAIc,SAAWd,EAAIwD,OAAO,EAAI,CAAE1C,QAASD,GAAab,EAAIc,SAAWd,EAAIwD,OAAO,CAAE,EAAI,CAAC,CAC5G,EAtBgB,IAuBpB,CAzBgBpC,EAAAA,GAAAA,kBA4BT,IAAMqC,GAAN,KAAMA,CA7Ib,MA6IaA,CAAAA,EAAAA,gCACT,YACqBC,EACAC,EACnB,MAFmBD,QAAAA,OACAC,MAAAA,CAClB,CAUH,MAAMC,KAAKC,EAAiD,CACxD,IAAIC,EACJ,GAAI,CACAA,EAAW,MAAM,KAAKH,MAAM,GAAG,KAAKD,OAAO,UAAW,CAClDK,OAAQ,MACRC,QAAS,CAAEC,OAAQ,kBAAmB,EACtCJ,OAAAA,CACJ,CAAA,CACJ,OAASK,EAAK,CACV,MAAIA,aAAeC,OAASD,EAAI3C,OAAS,aAC/B2C,EAEJ,IAAIE,EACN,CACIC,QAAS,kBAAmBH,GAAeG,SAAW,SAAA,GACtDC,KAAM,eACNC,MAAO,KACPC,KAAM,uBACV,EACA,CAAEC,MAAOP,CAAI,CAAA,CAErB,CAEA,GAAI,CAACJ,EAASY,GACV,MAAM,MAAMC,GAAUb,CAAAA,EAG1B,IAAMc,EAAO,MAAMd,EAASc,KAAI,EAC5BC,EACJ,GAAI,CACAA,EAASC,KAAKC,MAAMH,CAAAA,CACxB,MAAQ,CACJ,MAAM,IAAIR,EAAiB,CACvBC,QAAS,gDACTC,KAAM,eACNC,MAAO,KACPC,KAAM,0BACV,CAAA,CACJ,CAKA,IAAMQ,EAA2B9E,MAAMC,QAAQ0E,CAAAA,EACxCA,EACD3E,MAAMC,QAAS0E,GAAiCI,IAAAA,EAC1CJ,EAAmCI,KACrC,CAAA,EAEJC,EAA2B,CAAA,EACjC,QAAWlF,KAAOgF,EAAW,CACzB,IAAMG,EAAa/D,GAAepB,CAAAA,EAC9BmF,GAAYD,EAAOE,KAAKD,CAAAA,CAChC,CACA,OAAOD,CACX,CACJ,EAQA,eAAsBP,GAAUb,EAAkB,CAC9C,IAAMc,EAAO,MAAMd,EAASc,KAAI,EAAGS,MAAM,IAAM,EAAA,EAC3CC,EAEJ,GAAI,CACA,IAAMT,EAASC,KAAKC,MAAMH,CAAAA,EAC1B,GAAIC,GAAU,OAAOA,GAAW,UAAYA,EAAOU,MAAO,CACtD,IAAMC,EAAIX,EAAOU,MACjBD,EAAW,CACPjB,QAAS,OAAOmB,EAAEnB,SAAY,SAAWmB,EAAEnB,QAAU,QAAQP,EAAS2B,MAAM,GAC5EnB,KAAM,OAAOkB,EAAElB,MAAS,SAAWkB,EAAElB,KAAO,eAC5CC,MAAOiB,EAAEjB,QAAUjE,OAAY,KAAOkF,EAAEjB,MACxCC,KAAMgB,EAAEhB,OAASlE,OAAY,KAAOkF,EAAEhB,IAC1C,CACJ,MACIc,EAAW,CACPjB,QAAS,OAAOQ,GAAW,SAAWA,EAAS,QAAQf,EAAS2B,MAAM,GACtEnB,KAAM,eACNC,MAAO,KACPC,KAAM,IACV,CAER,MAAQ,CACJc,EAAW,CACPjB,QAASO,GAAQ,QAAQd,EAAS2B,MAAM,GACxCnB,KAAM,eACNC,MAAO,KACPC,KAAM,IACV,CACJ,CAEA,IAAMkB,EAAY5B,EAASE,QAAQ2B,IAAI,cAAA,GAAmBrF,OACpDsF,EAAeC,GAAgB/B,EAASE,QAAQ2B,IAAI,aAAA,CAAA,EAE1D,OAAO,IAAIvB,EAAiBkB,EAAU,CAClCG,OAAQ3B,EAAS2B,OACjBC,UAAAA,EACAE,aAAAA,CACJ,CAAA,CACJ,CAvCsBjB,EAAAA,GAAAA,aC9LtB,IAAMmB,GAAN,KAAMA,CA7BN,MA6BMA,CAAAA,EAAAA,mBACMC,MAAuB,KACvBC,UAAsB,CAAA,EAM9BC,OAAOC,EAA+B,CAElC,IAAIC,EAAID,EAMR,GALIC,EAAEC,SAAS,IAAA,IACXD,EAAIA,EAAEE,MAAM,EAAG,EAAC,GAIhBF,IAAM,GAAI,CACV,GAAI,KAAKJ,QAAU,MAAQ,KAAKC,UAAUM,SAAW,EACjD,OAAO,KAEX,IAAMC,EAAe,CACjBR,MAAO,KAAKA,MACZS,KAAM,KAAKR,UAAUS,KAAK;CAAA,CAC9B,EACA,YAAKV,MAAQ,KACb,KAAKC,UAAY,CAAA,EACVO,CACX,CAGA,GAAIJ,EAAEO,WAAW,GAAA,EACb,OAAO,KAIX,IAAMC,EAAWR,EAAES,QAAQ,GAAA,EACvBC,EACAC,EACJ,GAAIH,IAAa,GACbE,EAAQV,EACRW,EAAQ,OACL,CACHD,EAAQV,EAAEE,MAAM,EAAGM,CAAAA,EAEnB,IAAII,EAAOZ,EAAEE,MAAMM,EAAW,CAAA,EAC1BI,EAAKL,WAAW,GAAA,IAChBK,EAAOA,EAAKV,MAAM,CAAA,GAEtBS,EAAQC,CACZ,CAEA,OAAIF,IAAU,QACV,KAAKd,MAAQe,EACND,IAAU,QACjB,KAAKb,UAAUgB,KAAKF,CAAAA,EAIjB,IACX,CAGAG,OAAyB,CACrB,GAAI,KAAKlB,QAAU,MAAQ,KAAKC,UAAUM,SAAW,EACjD,OAAO,KAEX,IAAMC,EAAe,CACjBR,MAAO,KAAKA,MACZS,KAAM,KAAKR,UAAUS,KAAK;CAAA,CAC9B,EACA,YAAKV,MAAQ,KACb,KAAKC,UAAY,CAAA,EACVO,CACX,CACJ,EASMW,GAAN,KAAMA,CAhHN,MAgHMA,CAAAA,EAAAA,oBACMC,OAAqB,IAAIC,WACzBC,QAER,aAAc,CAEV,KAAKA,QAAU,IAAIC,YAAY,OAAA,CACnC,CAQArB,OAAOsB,EAA6B,CAEhC,IAAMC,EAAU,IAAIJ,WAAW,KAAKD,OAAOb,OAASiB,EAAMjB,MAAM,EAChEkB,EAAQC,IAAI,KAAKN,MAAM,EACvBK,EAAQC,IAAIF,EAAO,KAAKJ,OAAOb,MAAM,EACrC,KAAKa,OAASK,EAEd,IAAME,EAAkB,CAAA,EACpBC,EAAQ,EAEZ,QAASC,EAAI,EAAGA,EAAI,KAAKT,OAAOb,OAAQsB,IACpC,GAAI,KAAKT,OAAOS,CAAAA,IAAO,IAAiB,KAAKT,OAAOS,CAAAA,IAAO,GAAe,CAEtE,IAAMC,EAAY,KAAKV,OAAOW,SAASH,EAAOC,CAAAA,EACxC1B,EAAO,KAAKmB,QAAQpB,OAAO4B,EAAW,CAAEE,OAAQ,EAAK,CAAA,EAC3DL,EAAMV,KAAKd,CAAAA,EAGP,KAAKiB,OAAOS,CAAAA,IAAO,IAAQA,EAAI,EAAI,KAAKT,OAAOb,QAAU,KAAKa,OAAOS,EAAI,CAAA,IAAO,IAChFA,IAEJD,EAAQC,EAAI,CAChB,CAIJ,OAAID,EAAQ,IACR,KAAKR,OAAS,KAAKA,OAAOd,MAAMsB,CAAAA,GAG7BD,CACX,CAMAT,OAAkB,CACd,GAAI,KAAKE,OAAOb,SAAW,EAAG,CAE1B,IAAM0B,EAAY,KAAKX,QAAQpB,OAAM,EACrC,OAAO+B,EAAY,CAACA,GAAa,CAAA,CACrC,CACA,IAAM9B,EAAO,KAAKmB,QAAQpB,OAAO,KAAKkB,OAAQ,CAAEY,OAAQ,EAAM,CAAA,EAC9D,YAAKZ,OAAS,IAAIC,WACXlB,EAAO,CAACA,GAAQ,CAAA,CAC3B,CACJ,EAGa+B,GAAW,SAYxB,eAAuBC,GACnBC,EACAC,EAAoB,CAEpB,IAAMC,EAAa,IAAIvC,GACjBwC,EAAc,IAAIpB,GAClBqB,EAASJ,EAAKK,UAAS,EAGzBC,EAAU,GACRC,EAAUC,EAAA,IAAA,CACZF,EAAU,GACVF,EAAOK,OAAM,EAAGC,MAAM,IAAA,CAAO,CAAA,CACjC,EAHgB,WAKhB,GAAIT,EAAQ,CACR,GAAIA,EAAOK,QACP,OAEJL,EAAOU,iBAAiB,QAASJ,EAAS,CAAEK,KAAM,EAAK,CAAA,CAC3D,CAEA,GAAI,CACA,OAAa,CACT,GAAIN,EACA,OAGJ,IAAIO,EACJ,GAAI,CACAA,EAAS,MAAMT,EAAOU,KAAI,CAC9B,OAASC,EAAK,CAEV,GAAIT,GAAYS,aAAeC,OAASD,EAAIE,OAAS,aACjD,OAEJ,MAAMF,CACV,CAEA,GAAM,CAAEG,KAAAA,EAAMvC,MAAAA,CAAK,EAAKkC,EACxB,GAAIK,EAAM,MAEV,QAAWnD,KAAQoC,EAAYrC,OAAOa,CAAAA,EAAQ,CAC1C,IAAMP,EAAK8B,EAAWpC,OAAOC,CAAAA,EACzBK,IAAI,MAAMA,EAClB,CACJ,CAGA,QAAWL,KAAQoC,EAAYrB,MAAK,EAAI,CACpC,IAAMV,EAAK8B,EAAWpC,OAAOC,CAAAA,EACzBK,IAAI,MAAMA,EAClB,CACA,IAAM+C,EAAUjB,EAAWpB,MAAK,EAC5BqC,IAAS,MAAMA,EACvB,QAAA,CACQlB,GACAA,EAAOmB,oBAAoB,QAASb,CAAAA,EAExC,GAAI,CACAH,EAAOiB,YAAW,CACtB,MAAQ,CAER,CACJ,CACJ,CAjEuBtB,EAAAA,GAAAA,iBCnKvB,SAASuB,GAAgBC,EAAY,CACjC,GAAI,CACA,IAAMC,EAASC,KAAKC,MAAMH,CAAAA,EAC1B,GAAIC,GAAU,OAAOA,GAAW,SAAU,CACtC,IAAMG,EAAWH,EAAOI,OAASJ,EACjC,GAAIG,GAAY,OAAOA,GAAa,SAChC,OAAO,IAAIE,EAAiB,CACxBC,QAAS,OAAOH,EAASG,SAAY,SAAWH,EAASG,QAAU,eACnEC,KAAM,OAAOJ,EAASI,MAAS,SAAWJ,EAASI,KAAO,eAC1DC,MAAOL,EAASK,QAAUC,OAAY,KAAON,EAASK,MACtDE,KAAMP,EAASO,OAASD,OAAY,KAAON,EAASO,IACxD,CAAA,CAER,CACJ,MAAQ,CAER,CACA,OAAO,IAAIL,EAAiB,CACxBC,QAASP,GAAQ,eACjBQ,KAAM,eACNC,MAAO,KACPE,KAAM,IACV,CAAA,CACJ,CAvBSZ,EAAAA,GAAAA,mBA0BF,IAAMa,GAAN,KAAMA,CApDb,MAoDaA,CAAAA,EAAAA,yCACT,YACqBC,EACAC,EACnB,MAFmBD,QAAAA,OACAC,MAAAA,CAClB,CAWHC,OACIC,EAC4D,CAC5D,OAAIA,EAAMC,SAAW,GACV,KAAKC,gBAAgBF,CAAAA,EAEzB,KAAKG,mBAAmBH,CAAAA,CACnC,CAKA,MAAcG,mBACVH,EACuB,CAEvB,GAAIA,EAAMI,eACN,MAAM,IAAId,EAAiB,CACvBC,QAAS,mDACTC,KAAM,wBACNC,MAAO,iBACPE,KAAM,2BACV,CAAA,EAIJ,GAAM,CAAEU,OAAAA,EAAQ,GAAGC,CAAAA,EAASN,EAExBM,EAAKL,SAAWP,OAChB,OAAOY,EAAKL,OAEZK,EAAKL,OAAS,GAGlB,IAAIM,EACJ,GAAI,CACAA,EAAW,MAAM,KAAKT,MAAM,GAAG,KAAKD,OAAO,oBAAqB,CAC5DW,OAAQ,OACRC,QAAS,CACLC,OAAQ,mBACR,eAAgB,kBACpB,EACAJ,KAAMpB,KAAKyB,UAAUL,CAAAA,EACrBD,OAAAA,CACJ,CAAA,CACJ,OAASO,EAAK,CACV,MAAIA,aAAeC,OAASD,EAAIE,OAAS,aAC/BF,EAEJ,IAAItB,EACN,CACIC,QAAS,kBAAmBqB,GAAerB,SAAW,SAAA,GACtDC,KAAM,eACNC,MAAO,KACPE,KAAM,uBACV,EACA,CAAEoB,MAAOH,CAAI,CAAA,CAErB,CAEA,GAAI,CAACL,EAASS,GACV,MAAM,MAAMC,GAAUV,CAAAA,EAG1B,IAAMW,EAAO,MAAMX,EAASW,KAAI,EAChC,GAAI,CACA,OAAOhC,KAAKC,MAAM+B,CAAAA,CACtB,MAAQ,CACJ,MAAM,IAAI5B,EAAiB,CACvBC,QAAS,yDACTC,KAAM,eACNC,MAAO,KACPE,KAAM,0BACV,CAAA,CACJ,CACJ,CAYA,MAAeO,gBACXF,EACkD,CAClD,GAAM,CAAEK,OAAAA,EAAQ,GAAGC,CAAAA,EAASN,EAC5BM,EAAKL,OAAS,GAEd,IAAIM,EACJ,GAAI,CACAA,EAAW,MAAM,KAAKT,MAAM,GAAG,KAAKD,OAAO,oBAAqB,CAC5DW,OAAQ,OACRC,QAAS,CACLC,OAAQ,oBACR,eAAgB,kBACpB,EACAJ,KAAMpB,KAAKyB,UAAUL,CAAAA,EACrBD,OAAAA,CACJ,CAAA,CACJ,OAASO,EAAK,CACV,GAAIA,aAAeC,OAASD,EAAIE,OAAS,aACrC,OAEJ,MAAM,IAAIxB,EACN,CACIC,QAAS,kBAAmBqB,GAAerB,SAAW,SAAA,GACtDC,KAAM,eACNC,MAAO,KACPE,KAAM,uBACV,EACA,CAAEoB,MAAOH,CAAI,CAAA,CAErB,CAGA,GAAI,CAACL,EAASS,GACV,MAAM,MAAMC,GAAUV,CAAAA,EAG1B,GAAI,CAACA,EAASD,KACV,MAAM,IAAIhB,EAAiB,CACvBC,QAAS,wDACTC,KAAM,eACNC,MAAO,KACPE,KAAM,0BACV,CAAA,EAGJ,IAAIwB,EAAe,GACfC,EAAQ,GAEZ,GAAI,CACA,cAAiBC,KAAYC,GAAcf,EAASD,KAAMD,CAAAA,EAAS,CAE/D,GAAIgB,EAASE,QAAU,QACnBH,MAAAA,EAAQ,GACFrC,GAAgBsC,EAASrC,IAAI,EAIvC,GAAIqC,EAASE,QAAU,MAAQF,EAASE,QAAU,GAAI,CAClD,GAAIF,EAASrC,OAASwC,GAAU,CAC5BL,EAAe,GACf,MACJ,CAEA,GAAI,CAACE,EAASrC,KAEV,SAGJ,IAAIyC,EACJ,GAAI,CACAA,EAAQvC,KAAKC,MAAMkC,EAASrC,IAAI,CACpC,MAAQ,CACJoC,MAAAA,EAAQ,GACF,IAAI9B,EAAiB,CACvBC,QAAS,6BAA6B8B,EAASrC,IAAI,GACnDQ,KAAM,eACNC,MAAO,KACPE,KAAM,0BACV,CAAA,CACJ,CAGA,GAAI8B,GAAS,OAAOA,GAAU,UAAY,UAAWA,EAAO,CACxDL,EAAQ,GACR,IAAMM,EAAUD,EAAwDpC,MACxE,MAAM,IAAIC,EAAiB,CACvBC,QAAS,OAAOmC,GAAQnC,SAAY,SAAWmC,EAAOnC,QAAU,eAChEC,KAAM,OAAOkC,GAAQlC,MAAS,SAAWkC,EAAOlC,KAAO,eACvDC,MAAOiC,GAAQjC,QAAUC,OAAY,KAAQgC,EAAOjC,MACpDE,KAAM+B,GAAQ/B,OAASD,OAAY,KAAQgC,EAAO/B,IACtD,CAAA,CACJ,CAEA,MAAM8B,CACV,CACJ,CACJ,OAASb,EAAK,CAEV,GAAIA,aAAeC,OAASD,EAAIE,OAAS,aACrC,OAEJM,MAAAA,EAAQ,GACFR,CACV,CAGA,GAAI,CAACO,GAAgB,CAACC,GAAS,CAACf,GAAQsB,QACpC,MAAM,IAAIrC,EAAiB,CACvBC,QAAS,6CACTC,KAAM,eACNC,MAAO,KACPE,KAAM,4BACV,CAAA,CAER,CACJ,ECxPO,IAAMiC,EAAN,KAAMA,CAtBb,MAsBaA,CAAAA,EAAAA,wBAEAC,QAGAC,OAGAC,KAIT,YACIC,EACiBC,EACnB,MADmBA,MAAAA,EAEjB,KAAKJ,QAAU,GAAGG,EAAOE,QAAQ,GAAGC,EAAmBC,GAAG,GAC1D,KAAKN,OAAS,IAAIO,GAAU,KAAKR,QAAS,KAAKI,KAAK,EACpD,KAAKF,KAAO,CACRO,YAAa,IAAIC,GAAmB,KAAKV,QAAS,KAAKI,KAAK,CAChE,CACJ,CACJ,EClCO,IAAMO,EAAN,cAA2BC,KAAAA,CAVlC,MAUkCA,CAAAA,EAAAA,qBACtBC,iBAAmB,GACnBC,UACVC,OACAC,WAEA,YACEC,EACAH,EAA4B,UAC5BC,EACAC,EACA,CACA,MAAMC,CAAAA,EACN,KAAKH,UAAYA,EACjB,KAAKI,KAAOJ,IAAc,UAAY,sBAAwB,eAC9D,KAAKC,OAASA,EACd,KAAKC,WAAaA,CACpB,CAEAG,QAKE,CACA,MAAO,CACLD,KAAM,KAAKA,KACXD,QAAS,KAAKA,QACdF,OAAQ,KAAKA,OACbC,WAAY,KAAKA,UACnB,CACF,CACF,EAOO,SAASI,EAAeC,EAAc,CAC3C,OAAO,OAAOA,GAAU,UAAYA,IAAU,MAAQ,qBAAsBA,CAC9E,CAFgBD,EAAAA,EAAAA,kBAQT,IAAME,EAAN,cAA8BX,CAAAA,CAzDrC,MAyDqCA,CAAAA,EAAAA,wBAC1BI,OACAC,WAOTO,KAEA,YACEN,EACAF,EACAC,EACAF,EAA4B,UAC5BS,EACA,CACA,MAAMN,EAASH,EAAWC,EAAQC,CAAAA,EAClC,KAAKE,KAAOJ,IAAc,UAAY,yBAA2B,kBACjE,KAAKC,OAASA,EACd,KAAKC,WAAaA,EAClB,KAAKO,KAAOA,CACd,CAEAJ,QAME,CACA,MAAO,CACL,GAAG,MAAMA,OAAAA,EACTI,KAAM,KAAKA,IACb,CACF,CACF,EAMaC,EAAN,cAAkCb,CAAAA,CApGzC,MAoGyCA,CAAAA,EAAAA,4BACvCc,cAEA,YAAYR,EAAiBQ,EAAwBX,EAA4B,UAAW,CAC1F,MAAMG,EAASH,CAAAA,EACf,KAAKI,KAAOJ,IAAc,UAAY,6BAA+B,sBACrE,KAAKW,cAAgBA,CACvB,CACF,EClGO,SAASC,EACdC,EACAC,EACAC,EAAa,CAEb,IAAMC,EAAS,CAAE,GAAGH,CAAQ,EACtBI,EAAYH,EAAKI,YAAW,EAElC,QAAWC,KAAOC,OAAOC,KAAKL,CAAAA,EACxBG,EAAID,YAAW,IAAOD,GACxB,OAAOD,EAAOG,CAAAA,EAIlBH,OAAAA,EAAOC,CAAAA,EAAaF,EACbC,CACT,CAhBgBJ,EAAAA,EAAAA,aA0BT,SAASU,GAAiBT,EAA+B,CAC9D,IAAMG,EAAiC,CAAC,EACxC,OAAW,CAACG,EAAKJ,CAAAA,IAAUK,OAAOG,QAAQV,CAAAA,EACxCG,EAAOG,EAAID,YAAW,CAAA,EAAMH,EAE9B,OAAOC,CACT,CANgBM,EAAAA,GAAAA,oBC3BT,IAAME,GAAeC,EAACC,GACvBA,EACK,IAAIC,IAASD,EAAAA,GAAeC,CAAAA,EAE9B,IAAIA,IAASC,MAAAA,GAASD,CAAAA,EAJH,gBAyBrB,IAAME,GAAgBC,EAACC,GAAAA,CAC5B,GAAI,OAAOA,GAAU,UAAYA,IAAU,KACzC,MAAO,GAGT,IAAMC,EAAYC,OAAOC,eAAeH,CAAAA,EACxC,OACGC,IAAc,MACbA,IAAcC,OAAOD,WACrBC,OAAOC,eAAeF,CAAAA,IAAe,OACvC,EAAEG,OAAOC,eAAeL,IACxB,EAAEI,OAAOE,YAAYN,EAEzB,EAb6B,iBAsBhBO,GAAmBR,EAACS,GAAAA,CAC/B,GAAIC,MAAMC,QAAQF,CAAAA,EAChB,OAAOA,EAAKG,IAAKC,GAAOL,GAAiBK,CAAAA,CAAAA,EACpC,GAAI,OAAOJ,GAAS,YAAcA,IAASN,OAAOM,CAAAA,EACvD,OAAOA,EAGT,IAAMK,EAA8B,CAAC,EACrCX,cAAOY,QAAQN,CAAAA,EAAMO,QAAQ,CAAC,CAACC,EAAKhB,CAAAA,IAAM,CACxC,IAAMiB,EAASD,EAAIE,QAAQ,gBAAkBC,GAAMA,EAAEC,YAAW,EAAGF,QAAQ,QAAS,EAAA,CAAA,EACpFL,EAAOI,CAAAA,EAAUV,GAAiBP,CAAAA,CACpC,CAAA,EAEOa,CACT,EAdgC,oBA+BnBQ,GAAoBtB,EAACuB,GAC5B,CAACA,GAAc,OAAOA,GAAe,UAKrCA,EAAWC,SAAW,GAAKD,EAAWC,OAAS,KAK/CD,EAAWE,KAAI,IAAOF,GAOtBA,EAAWG,SAAS,GAAA,GAAQH,EAAWG,SAAS,IAAA,EAC3C,GAMe,4BACDC,KAAKJ,CAAAA,EA1BG,qBAsE1B,IAAMK,GAAoBC,EAACC,GAChCA,EAAKC,MAAM,GAAA,EAAKC,IAAIC,kBAAAA,EAAoBC,KAAK,GAAA,EADd,qBCjIjC,IAAMC,GAAmBC,EAACC,GAAAA,CACxB,GAAI,OAAOA,GAAQ,UAAYA,IAAQ,KAAM,CAC3C,IAAMC,EAAID,EACV,GAAI,OAAOC,EAAEC,KAAQ,SAAU,OAAOD,EAAEC,IACxC,GAAI,OAAOD,EAAEE,SAAY,SAAU,OAAOF,EAAEE,QAC5C,GAAI,OAAOF,EAAEG,mBAAsB,SAAU,OAAOH,EAAEG,kBACtD,GAAI,OAAOH,EAAEI,OAAU,SAAU,OAAOJ,EAAEI,MAC1C,GAAI,OAAOJ,EAAEI,OAAU,UAAYJ,EAAEI,QAAU,KAAM,CACnD,IAAMC,EAASL,EAAEI,MACjB,GAAI,OAAOC,EAAOH,SAAY,SAAU,OAAOG,EAAOH,OACxD,CACF,CACA,OAAOI,KAAKC,UAAUR,CAAAA,CACxB,EAbyB,oBAsBnBS,GAAcV,EAAA,MAClBM,EACAK,EACAC,EACAC,IAAAA,CAWA,GALEP,IAAU,MACV,OAAOA,GAAU,UACjB,SAAUA,GACV,OAAQA,EAAkCQ,MAAS,WAEjC,CAClB,IAAMC,EAAgBT,EAElBU,EAASC,SAASC,OAAOH,EAAcC,MAAM,EAAG,EAAA,EAC/CG,OAAOC,SAASJ,CAAAA,IACnBA,EAAS,KAGXD,EACGD,KAAI,EACJO,KACEpB,GAAAA,CACC,IAAMqB,EAAarB,GAAKqB,YAAcrB,GAAKsB,MAAQP,EAAS,GAC5DL,EACE,IAAIa,EAAgBzB,GAAiBE,CAAAA,EAAMe,EAAQM,EAAYT,EAAWZ,GAAKsB,IAAAA,CAAAA,CAEnF,CAAA,EAEDE,MAAM,IAAA,CACL,IAAMH,EAAaN,EAAS,GACtBZ,EAAUW,EAAcW,YAAc,QAAQV,CAAAA,SACpDL,EAAO,IAAIa,EAAgBpB,EAASY,EAAQM,EAAYT,CAAAA,CAAAA,CAC1D,CAAA,CACJ,MACEF,EAAO,IAAIgB,EAAoB5B,GAAiBO,CAAAA,EAAQA,EAAOO,CAAAA,CAAAA,CAEnE,EAzCoB,eAmDde,GAAoB5B,EAAA,CACxB6B,EACAjB,EACAkB,EACAC,IAAAA,CAEA,IAAMC,EAA+B,CAAEH,OAAAA,EAAQI,QAASrB,GAASqB,SAAW,CAAC,CAAE,EAE/E,GAAIJ,IAAW,OAASA,IAAW,QAAU,CAACE,EAC5C,MAAO,CAAE,GAAGC,EAAQ,GAAGF,CAAW,EAGpC,GAAII,GAAcH,CAAAA,EAAO,CACvB,IAAME,EAAUrB,GAASqB,SAAW,CAAC,EACjCE,EAEJ,OAAW,CAACC,EAAKC,CAAAA,IAAUC,OAAOC,QAAQN,CAAAA,EACpCG,EAAII,YAAW,IAAO,iBACxBL,EAAcE,GAIlBL,EAAOC,QAAUQ,EAAUR,EAAS,eAAgBE,GAAe,kBAAA,EACnEH,EAAOD,KAAOvB,KAAKC,UAAUsB,CAAAA,CAC/B,MACEC,EAAOD,KAAOA,EAGhB,OAAInB,GAAS8B,SACXV,EAAOU,OAAS9B,EAAQ8B,QAGnB,CAAE,GAAGV,EAAQ,GAAGF,CAAW,CACpC,EAjC0B,qBA8C1B,eAAea,GACbC,EACAf,EACAgB,EACAjC,EACAkB,EACAC,EACAlB,EAAyB,CAEzB,OAAO,IAAIiC,QAAQ,CAACC,EAASpC,IAAAA,CAC3BiC,EAAQC,EAAKjB,GAAkBC,EAAQjB,EAASkB,EAAYC,CAAAA,CAAAA,EACzDV,KAAM2B,GAAAA,CACL,GAAI,CAACA,EAAOC,GAAI,MAAMD,EACtB,GAAIpC,GAASsC,cAAe,OAAOF,EAMnC,GAAInC,IAAc,UAAW,CAC3B,IAAMsB,EAAca,EAAOf,QAAQkB,IAAI,cAAA,EAIvC,GAHsBH,EAAOf,QAAQkB,IAAI,gBAAA,IAGnB,KAAOH,EAAOhC,SAAW,IAC7C,MAAO,CAAC,EAIV,GAAI,CAACmB,GAAe,CAACA,EAAYiB,SAAS,kBAAA,EACxC,MAAO,CAAC,CAEZ,CAEA,OAAOJ,EAAOlC,KAAI,CACpB,CAAA,EACCO,KAAMgC,GAASN,EAAQM,CAAAA,CAAAA,EACvB5B,MAAOnB,GAAUI,GAAYJ,EAAOK,EAAQC,EAASC,CAAAA,CAAAA,CAC1D,CAAA,CACF,CAvCe8B,EAAAA,GAAAA,kBA8CR,SAASW,GAAezC,EAA4B,UAAS,CAClE,MAAO,CASLsC,IAAKnD,EAAA,MACH4C,EACAC,EACAjC,EACAkB,IAEOa,GAAeC,EAAS,MAAOC,EAAKjC,EAASkB,EAAYyB,OAAW1C,CAAAA,EANxE,OAkBL2C,KAAMxD,EAAA,MACJ4C,EACAC,EACAd,EACAnB,EACAkB,IAEOa,GAAeC,EAAS,OAAQC,EAAKjC,EAASkB,EAAYC,EAAMlB,CAAAA,EAPnE,QAmBN4C,IAAKzD,EAAA,MACH4C,EACAC,EACAd,EACAnB,EACAkB,IAEOa,GAAeC,EAAS,MAAOC,EAAKjC,EAASkB,EAAYC,EAAMlB,CAAAA,EAPnE,OAkBL6C,KAAM1D,EAAA,MACJ4C,EACAC,EACAjC,EACAkB,IAEOa,GACLC,EACA,OACAC,EACA,CACE,GAAGjC,EACHsC,cAAe,EACjB,EACApB,EACAyB,OACA1C,CAAAA,EAhBE,QA6BN8C,OAAQ3D,EAAA,MACN4C,EACAC,EACAd,EACAnB,EACAkB,IAEOa,GAAeC,EAAS,SAAUC,EAAKjC,EAASkB,EAAYC,EAAMlB,CAAAA,EAPnE,SASV,CACF,CAxGgByC,EAAAA,GAAAA,kBA2GhB,IAAMM,GAAaN,GAAe,SAAA,EACrB,CAAEH,IAAAA,EAAKK,KAAAA,EAAMC,IAAAA,GAAKC,KAAAA,GAAMC,OAAAA,CAAM,EAAKC,GAGnCC,EAAaP,GAAe,SAAA,ECpSzC,IAA8BQ,EAA9B,KAA8BA,CAZ9B,MAY8BA,CAAAA,EAAAA,sBAClBC,IACAC,QACAC,MACAC,mBAAqB,GACrBC,UASV,YACEJ,EACAC,EAAqC,CAAC,EACtCC,EACAE,EAA4B,UAC5B,CACA,KAAKJ,IAAMA,EACX,KAAKC,QAAUI,GAAiBJ,CAAAA,EAChC,KAAKC,MAAQI,GAAaJ,CAAAA,EAC1B,KAAKE,UAAYA,CACnB,CAQOG,cAAqB,CAC1B,YAAKJ,mBAAqB,GACnB,IACT,CAUOK,UAAUC,EAAcC,EAAqB,CAClD,YAAKT,QAAUU,EAAc,KAAKV,QAASQ,EAAMC,CAAAA,EAC1C,IACT,CA2BA,MAAgBE,gBACdC,EACmE,CACnE,GAAI,CAEF,MAAO,CAAEC,KADI,MAAMD,EAAAA,EACJE,MAAO,IAAK,CAC7B,OAASA,EAAO,CACd,GAAI,KAAKZ,mBACP,MAAMY,EAER,GAAIC,EAAeD,CAAAA,EACjB,MAAO,CAAED,KAAM,KAAMC,MAAOA,CAAgB,EAE9C,MAAMA,CACR,CACF,CACF,ECpGA,IAAqBE,GAArB,KAAqBA,CAHrB,MAGqBA,CAAAA,EAAAA,4DACV,CAACC,OAAOC,WAAW,EAAY,wBAChCC,QAA0D,KAElE,YACUC,EACAC,EACR,MAFQD,WAAAA,OACAC,mBAAAA,CACP,CAEHC,KACEC,EAGAC,EAC8B,CAC9B,OAAO,KAAKC,WAAU,EAAGH,KAAKC,EAAaC,CAAAA,CAC7C,CAEAE,MACEF,EACmD,CACnD,OAAO,KAAKC,WAAU,EAAGC,MAAMF,CAAAA,CACjC,CAEAG,QAAQC,EAA0E,CAChF,OAAO,KAAKH,WAAU,EAAGE,QAAQC,CAAAA,CACnC,CAEQH,YAAsD,CAC5D,OAAK,KAAKN,UACR,KAAKA,QAAU,KAAKU,QAAO,GAEtB,KAAKV,OACd,CAEA,MAAcU,SAAmD,CAC/D,GAAI,CAGF,MAAO,CACLC,MAHa,MAAM,KAAKV,WAAU,GAGrBW,KACbC,MAAO,IACT,CACF,OAASA,EAAO,CACd,GAAI,KAAKX,mBACP,MAAMW,EAGR,GAAIC,EAAeD,CAAAA,EACjB,MAAO,CAAEF,KAAM,KAAME,MAAAA,CAAM,EAG7B,MAAMA,CACR,CACF,CACF,ECtDA,IAAqBE,GAArB,KAAqBA,CAJrB,MAIqBA,CAAAA,EAAAA,0DACV,CAACC,OAAOC,WAAW,EAAY,sBAChCC,QAAgD,KAExD,YACUC,EACAC,EACR,MAFQD,WAAAA,OACAC,mBAAAA,CACP,CAEHC,UAAkC,CAChC,OAAO,IAAIC,GAAsB,KAAKH,WAAY,KAAKC,kBAAkB,CAC3E,CAEAG,KACEC,EACAC,EAC8B,CAC9B,OAAO,KAAKC,WAAU,EAAGH,KAAKC,EAAaC,CAAAA,CAC7C,CAEAE,MACEF,EACyC,CACzC,OAAO,KAAKC,WAAU,EAAGC,MAAMF,CAAAA,CACjC,CAEAG,QAAQC,EAAgE,CACtE,OAAO,KAAKH,WAAU,EAAGE,QAAQC,CAAAA,CACnC,CAEQH,YAA4C,CAClD,OAAK,KAAKR,UACR,KAAKA,QAAU,KAAKY,QAAO,GAEtB,KAAKZ,OACd,CAEA,MAAcY,SAAyC,CACrD,GAAI,CAGF,MAAO,CACLC,KAAM,MAHO,MAAM,KAAKZ,WAAU,GAGfa,KAAI,EACvBC,MAAO,IACT,CACF,OAASA,EAAO,CACd,GAAI,KAAKb,mBACP,MAAMa,EAGR,GAAIC,EAAeD,CAAAA,EACjB,MAAO,CAAEF,KAAM,KAAME,MAAAA,CAAM,EAG7B,MAAMA,CACR,CACF,CACF,ECpCA,IAAME,GAAyB,CAC7BC,MAAO,IACPC,OAAQ,EACRC,OAAQ,CACNC,OAAQ,OACRC,MAAO,KACT,CACF,EAEMC,GAAoC,CACxCC,aAAc,OACdC,YAAa,2BACbC,OAAQ,EACV,EAcqBC,GAArB,cAA4CC,CAAAA,CApD5C,MAoD4CA,CAAAA,EAAAA,uBAChCC,SAEV,YACEC,EACAC,EAAqC,CAAC,EACtCF,EACAG,EACA,CACA,MAAMF,EAAKC,EAASC,EAAO,SAAA,EAC3B,KAAKH,SAAWA,CAClB,CASA,MAAcI,eACZC,EACAC,EACAC,EACAC,EAUA,CACA,OAAO,KAAKC,gBAAgB,SAAA,CAC1B,IAAIC,EACEC,EAAU,CAAE,GAAGjB,GAAsB,GAAGc,CAAY,EACtDN,EAAkC,CACpC,GAAG,KAAKA,QACR,GAAIG,IAAW,QAAU,CAAE,WAAYO,OAAOD,EAAQd,MAAM,CAAa,CAC3E,EAEMgB,EAAWF,EAAQE,SAsCzB,GApCI,OAAOC,KAAS,KAAeP,aAAoBO,MACrDJ,EAAO,IAAIK,SACXL,EAAKM,OAAO,eAAgBL,EAAQhB,YAAY,EAC5CkB,GACFH,EAAKM,OAAO,WAAY,KAAKC,eAAeJ,CAAAA,CAAAA,EAE9CH,EAAKM,OAAO,GAAIT,CAAAA,GACP,OAAOQ,SAAa,KAAeR,aAAoBQ,UAChEL,EAAOH,EAEFG,EAAKQ,IAAI,cAAA,GACZR,EAAKM,OAAO,eAAgBL,EAAQhB,YAAY,EAE9CkB,GAAY,CAACH,EAAKQ,IAAI,UAAA,GACxBR,EAAKM,OAAO,WAAY,KAAKC,eAAeJ,CAAAA,CAAAA,IAG9CH,EAAOH,EACPL,EAAQ,eAAA,EAAmB,WAAWS,EAAQhB,YAAY,GAC1DO,EAAQ,cAAA,EAAkBS,EAAQf,YAE9BiB,IACFX,EAAQ,YAAA,EAAgB,KAAKiB,SAAS,KAAKF,eAAeJ,CAAAA,CAAAA,IAMzD,OAAOO,eAAmB,KAAeV,aAAgBU,gBACzDV,GAAQ,OAAOA,GAAS,UAAY,SAAUA,GAAQ,OAAOA,EAAKW,MAAS,aAE9D,CAACV,EAAQW,SACvBX,EAAQW,OAAS,SAIjBd,GAAaN,QACf,OAAW,CAACqB,EAAKC,CAAAA,IAAUC,OAAOC,QAAQlB,EAAYN,OAAO,EAC3DA,EAAUyB,EAAUzB,EAASqB,EAAKC,CAAAA,EAItC,IAAMI,EAAY,KAAKC,oBAAoBvB,CAAAA,EACrCwB,EAAQ,KAAKC,cAAcH,CAAAA,EAC3BI,EAAO,MAAO3B,GAAU,MAAQ4B,GAAMC,GAC1C,KAAK/B,MACL,GAAG,KAAKF,GAAG,WAAW6B,CAAAA,GACtBpB,EACA,CAAER,QAAAA,EAAS,GAAIS,GAASW,OAAS,CAAEA,OAAQX,EAAQW,MAAO,EAAI,CAAC,CAAG,CAAA,EAGpE,MAAO,CAAEhB,KAAMsB,EAAWO,GAAIH,EAAKI,GAAIC,SAAUL,EAAKM,GAAI,CAC5D,CAAA,CACF,CAqEA,MAAMC,OACJjC,EACAC,EACAC,EAUA,CACA,OAAO,KAAKJ,eAAe,OAAQE,EAAMC,EAAUC,CAAAA,CACrD,CAwCA,MAAMgC,kBACJlC,EACAmC,EACAlC,EACAC,EACA,CACA,IAAMoB,EAAY,KAAKC,oBAAoBvB,CAAAA,EACrCwB,EAAQ,KAAKC,cAAcH,CAAAA,EAE3B3B,EAAM,IAAIyC,IAAI,KAAKzC,IAAM,uBAAuB6B,CAAAA,EAAO,EAC7D7B,OAAAA,EAAI0C,aAAaC,IAAI,QAASH,CAAAA,EAEvB,KAAKhC,gBAAgB,SAAA,CAC1B,IAAIC,EACEC,EAAU,CAAE,GAAGjB,GAAsB,GAAGc,CAAY,EACtDN,EAAkC,CACpC,GAAG,KAAKA,QACH,WAAYU,OAAOD,EAAQd,MAAM,CACxC,EAEMgB,EAAWF,EAAQE,SAkCzB,GAhCI,OAAOC,KAAS,KAAeP,aAAoBO,MACrDJ,EAAO,IAAIK,SACXL,EAAKM,OAAO,eAAgBL,EAAQhB,YAAY,EAC5CkB,GACFH,EAAKM,OAAO,WAAY,KAAKC,eAAeJ,CAAAA,CAAAA,EAE9CH,EAAKM,OAAO,GAAIT,CAAAA,GACP,OAAOQ,SAAa,KAAeR,aAAoBQ,UAChEL,EAAOH,EACFG,EAAKQ,IAAI,cAAA,GACZR,EAAKM,OAAO,eAAgBL,EAAQhB,YAAY,EAE9CkB,GAAY,CAACH,EAAKQ,IAAI,UAAA,GACxBR,EAAKM,OAAO,WAAY,KAAKC,eAAeJ,CAAAA,CAAAA,IAG9CH,EAAOH,EACPL,EAAQ,eAAA,EAAmB,WAAWS,EAAQhB,YAAY,GAC1DO,EAAQ,cAAA,EAAkBS,EAAQf,YAC9BiB,IACFX,EAAQ,YAAA,EAAgB,KAAKiB,SAAS,KAAKF,eAAeJ,CAAAA,CAAAA,IAIzD,OAAOO,eAAmB,KAAeV,aAAgBU,gBACzDV,GAAQ,OAAOA,GAAS,UAAY,SAAUA,GAAQ,OAAOA,EAAKW,MAAS,aAE9D,CAACV,EAAQW,SACvBX,EAAQW,OAAS,SAIjBd,GAAaN,QACf,OAAW,CAACqB,EAAKC,CAAAA,IAAUC,OAAOC,QAAQlB,EAAYN,OAAO,EAC3DA,EAAUyB,EAAUzB,EAASqB,EAAKC,CAAAA,EAItC,IAAMQ,EAAO,MAAMC,GAAI,KAAK9B,MAAOF,EAAI4C,SAAQ,EAAInC,EAAgB,CACjER,QAAAA,EACA,GAAIS,GAASW,OAAS,CAAEA,OAAQX,EAAQW,MAAO,EAAI,CAAC,CACtD,CAAA,EAEA,MAAO,CAAEhB,KAAMsB,EAAWS,SAAUL,EAAKM,GAAI,CAC/C,CAAA,CACF,CAuCA,MAAMQ,sBACJxC,EACAK,EAUA,CACA,OAAO,KAAKF,gBAAgB,SAAA,CAC1B,IAAIqB,EAAQ,KAAKC,cAAczB,CAAAA,EAEzBJ,EAAU,CAAE,GAAG,KAAKA,OAAQ,EAE9BS,GAASd,SACXK,EAAQ,UAAA,EAAc,QAGxB,IAAM8B,EAAO,MAAME,EACjB,KAAK/B,MACL,GAAG,KAAKF,GAAG,uBAAuB6B,CAAAA,GAClC,CAAC,EACD,CAAE5B,QAAAA,CAAQ,CAAA,EAGND,EAAM,IAAIyC,IAAI,KAAKzC,IAAM+B,EAAK/B,GAAG,EAEjCwC,EAAQxC,EAAI0C,aAAaI,IAAI,OAAA,EAEnC,GAAI,CAACN,EACH,MAAM,IAAIO,EAAa,0BAAA,EAGzB,MAAO,CAAEC,UAAWhD,EAAI4C,SAAQ,EAAIvC,KAAAA,EAAMmC,MAAAA,CAAM,CAClD,CAAA,CACF,CAyDA,MAAMS,OACJ5C,EACAC,EAWAC,EAUA,CACA,OAAO,KAAKJ,eAAe,MAAOE,EAAMC,EAAUC,CAAAA,CACpD,CAoCA,MAAM2C,KACJC,EACAC,EACA1C,EAUA,CACA,OAAO,KAAKF,gBAAgB,SACnB,MAAMyB,EACX,KAAK/B,MACL,GAAG,KAAKF,GAAG,eACX,CACED,SAAU,KAAKA,SACfsD,UAAWF,EACXG,eAAgBF,EAChBG,kBAAmB7C,GAAS6C,iBAC9B,EACA,CAAEtD,QAAS,KAAKA,OAAQ,CAAA,CAE5B,CACF,CAoCA,MAAMuD,KACJL,EACAC,EACA1C,EAUA,CACA,OAAO,KAAKF,gBAAgB,UAYnB,CAAEH,MAXI,MAAM4B,EACjB,KAAK/B,MACL,GAAG,KAAKF,GAAG,eACX,CACED,SAAU,KAAKA,SACfsD,UAAWF,EACXG,eAAgBF,EAChBG,kBAAmB7C,GAAS6C,iBAC9B,EACA,CAAEtD,QAAS,KAAKA,OAAQ,CAAA,GAENoC,GAAI,EAC1B,CACF,CA6DA,MAAMoB,gBACJpD,EACAqD,EACAhD,EAcA,CACA,OAAO,KAAKF,gBAAgB,SAAA,CAC1B,IAAIqB,EAAQ,KAAKC,cAAczB,CAAAA,EAEzBsD,EACJ,OAAOjD,GAASkD,WAAc,UAC9BlD,EAAQkD,YAAc,MACtBpC,OAAOqC,KAAKnD,EAAQkD,SAAS,EAAEE,OAAS,EAEtC/B,EAAO,MAAME,EACf,KAAK/B,MACL,GAAG,KAAKF,GAAG,gBAAgB6B,CAAAA,GAC3B,CAAE6B,UAAAA,EAAW,GAAIC,EAAe,CAAEC,UAAWlD,EAASkD,SAAU,EAAI,CAAC,CAAG,EACxE,CAAE3D,QAAS,KAAKA,OAAQ,CAAA,EAGpB8D,EAAQ,IAAIC,gBACdtD,GAASuD,UACXF,EAAMpB,IAAI,WAAYjC,EAAQuD,WAAa,GAAO,GAAKvD,EAAQuD,QAAQ,EACrEvD,GAASwD,YAAc,MAAMH,EAAMpB,IAAI,aAAchC,OAAOD,EAAQwD,UAAU,CAAA,EAClF,IAAMC,EAAcJ,EAAMnB,SAAQ,EAQlC,MAAO,CAAEI,UAJSoB,UAChB,GAAG,KAAKpE,GAAG,GAAG+B,EAAKsC,SAAS,GAAGF,EAAc,IAAIA,CAAAA,GAAgB,EAAA,EAAI,CAGpD,CACrB,CAAA,CACF,CAgDA,MAAMG,iBACJC,EACAb,EACAhD,EAeA,CACA,OAAO,KAAKF,gBAAgB,SAAA,CAC1B,IAAMuB,EAAO,MAAME,EACjB,KAAK/B,MACL,GAAG,KAAKF,GAAG,gBAAgB,KAAKD,QAAQ,GACxC,CAAE2D,UAAAA,EAAWa,MAAAA,CAAM,EACnB,CAAEtE,QAAS,KAAKA,OAAQ,CAAA,EAGpB8D,EAAQ,IAAIC,gBAEdtD,GAASuD,UACXF,EAAMpB,IAAI,WAAYjC,EAAQuD,WAAa,GAAO,GAAKvD,EAAQuD,QAAQ,EACrEvD,GAASwD,YAAc,MAAMH,EAAMpB,IAAI,aAAchC,OAAOD,EAAQwD,UAAU,CAAA,EAElF,IAAMC,EAAcJ,EAAMnB,SAAQ,EAElC,OAAOb,EAAKyC,IACTC,IAAoF,CACnF,GAAGA,EACHzB,UAAWyB,EAAMJ,UACbD,UAAU,GAAG,KAAKpE,GAAG,GAAGyE,EAAMJ,SAAS,GAAGF,EAAc,IAAIA,CAAAA,GAAgB,EAAA,EAAI,EAChF,IACN,EAAA,CAEJ,CAAA,CACF,CAmEAF,SACE5D,EACAK,EACAgE,EACqB,CAKrB,IAAMC,EAHJ,OAAOjE,GAASkD,WAAc,UAC9BlD,EAAQkD,YAAc,MACtBpC,OAAOqC,KAAKnD,EAAQkD,SAAS,EAAEE,OAAS,EACD,6BAA+B,SAElEC,EAAQ,IAAIC,gBACdtD,GAASkD,WAAW,KAAKgB,0BAA0Bb,EAAOrD,EAAQkD,SAAS,EAC3ElD,GAASwD,YAAc,MAAMH,EAAMpB,IAAI,aAAchC,OAAOD,EAAQwD,UAAU,CAAA,EAClF,IAAMC,EAAcJ,EAAMnB,SAAQ,EAE5Bf,EAAQ,KAAKC,cAAczB,CAAAA,EAC3BwE,EAAaC,EAAA,IACjBhC,EACE,KAAK5C,MACL,GAAG,KAAKF,GAAG,IAAI2E,CAAAA,IAAc9C,CAAAA,GAAQsC,EAAc,IAAIA,CAAAA,GAAgB,EAAA,GACvE,CACElE,QAAS,KAAKA,QACd8E,cAAe,EACjB,EACAL,CAAAA,EARe,cAUnB,OAAO,IAAIM,GAAoBH,EAAY,KAAKI,kBAAkB,CACpE,CA0BA,MAAMC,KAAK7E,EAST,CACA,IAAMwB,EAAQ,KAAKC,cAAczB,CAAAA,EAEjC,OAAO,KAAKG,gBAAgB,SAAA,CAC1B,IAAMuB,EAAO,MAAMe,EAAI,KAAK5C,MAAO,GAAG,KAAKF,GAAG,gBAAgB6B,CAAAA,GAAS,CACrE5B,QAAS,KAAKA,OAChB,CAAA,EAEA,OAAOkF,GAAiBpD,CAAAA,CAC1B,CAAA,CACF,CAkBA,MAAMqD,OAAO/E,EASX,CACA,IAAMwB,EAAQ,KAAKC,cAAczB,CAAAA,EAEjC,GAAI,CACF,aAAMgF,GAAK,KAAKnF,MAAO,GAAG,KAAKF,GAAG,WAAW6B,CAAAA,GAAS,CACpD5B,QAAS,KAAKA,OAChB,CAAA,EAEO,CAAE8B,KAAM,GAAMuD,MAAO,IAAK,CACnC,OAASA,EAAO,CACd,GAAI,KAAKL,mBACP,MAAMK,EAER,GAAIC,EAAeD,CAAAA,EAAQ,CAEzB,IAAME,EACJF,aAAiBG,EACbH,EAAME,OACNF,aAAiBI,EACdJ,EAAMK,eAAsCH,OAC7CI,OAER,GAAIJ,IAAWI,QAAa,CAAC,IAAK,KAAKC,SAASL,CAAAA,EAC9C,MAAO,CAAEzD,KAAM,GAAOuD,MAAAA,CAAM,CAEhC,CAEA,MAAMA,CACR,CACF,CA6DAQ,aACEzF,EACAK,EAKiC,CACjC,IAAMmB,EAAQ,KAAKC,cAAczB,CAAAA,EAE3B0D,EAAQ,IAAIC,gBACdtD,GAASuD,UAAUF,EAAMpB,IAAI,WAAYjC,EAAQuD,WAAa,GAAO,GAAKvD,EAAQuD,QAAQ,EAC1FvD,GAASkD,WAAW,KAAKgB,0BAA0Bb,EAAOrD,EAAQkD,SAAS,EAC3ElD,GAASwD,YAAc,MAAMH,EAAMpB,IAAI,aAAchC,OAAOD,EAAQwD,UAAU,CAAA,EAClF,IAAMC,EAAcJ,EAAMnB,SAAQ,EAM5B+B,EAHJ,OAAOjE,GAASkD,WAAc,UAC9BlD,EAAQkD,YAAc,MACtBpC,OAAOqC,KAAKnD,EAAQkD,SAAS,EAAEE,OAAS,EACD,eAAiB,SAE1D,MAAO,CACL/B,KAAM,CACJgE,UACE3B,UAAU,GAAG,KAAKpE,GAAG,IAAI2E,CAAAA,WAAqB9C,CAAAA,EAAO,GACpDsC,EAAc,IAAIA,CAAAA,GAAgB,GACvC,CACF,CACF,CAmCA,MAAM6B,OAAOzB,EASX,CACA,OAAO,KAAK/D,gBAAgB,SACnB,MAAMwF,EACX,KAAK9F,MACL,GAAG,KAAKF,GAAG,WAAW,KAAKD,QAAQ,GACnC,CAAEkG,SAAU1B,CAAM,EAClB,CAAEtE,QAAS,KAAKA,OAAQ,CAAA,CAE5B,CACF,CA2CA,MAAMiG,WACJ7F,EACAK,EACAgE,EAUA,CACA,OAAO,KAAKlE,gBAAgB,SAAA,CAC1B,IAAMqB,EAAQsE,GAAkB,KAAKrE,cAAczB,CAAAA,CAAAA,EAC7C0D,EAAQ,IAAIC,gBACdtD,GAAS0F,iBACXrC,EAAMpB,IAAI,kBAAmB,MAAA,EAE/B,IAAMwB,EAAcJ,EAAMnB,SAAQ,EAElC,OAAO,MAAMoD,EACX,KAAK9F,MACL,GAAG,KAAKF,GAAG,QAAQ6B,CAAAA,GAAQsC,EAAc,IAAIA,CAAAA,GAAgB,EAAA,GAC7D,CAAC,EACD,CAAElE,QAAS,KAAKA,OAAQ,EACxByE,CAAAA,CAEJ,CAAA,CACF,CAmJA,MAAM2B,KACJhG,EACAK,EACAgE,EAUA,CACA,OAAO,KAAKlE,gBAAgB,SAAA,CAG1B,IAAMlB,EAASoB,GAASpB,OACpB,CAAE,GAAGH,GAAuBG,OAAQ,GAAGoB,EAAQpB,MAAO,EACtDH,GAAuBG,OACrBmB,EAAO,CAAE,GAAGtB,GAAwB,GAAGuB,EAASpB,OAAAA,EAAQgH,OAAQjG,GAAQ,EAAG,EACjF,OAAO,MAAM4B,EACX,KAAK/B,MACL,GAAG,KAAKF,GAAG,gBAAgB,KAAKD,QAAQ,GACxCU,EACA,CAAER,QAAS,KAAKA,OAAQ,EACxByE,CAAAA,CAEJ,CAAA,CACF,CAiDA,MAAM6B,OACJ7F,EACAgE,EAUA,CACA,OAAO,KAAKlE,gBAAgB,SAAA,CAC1B,IAAMC,EAAO,CAAE,GAAGC,CAAQ,EAC1B,OAAO,MAAMuB,EACX,KAAK/B,MACL,GAAG,KAAKF,GAAG,mBAAmB,KAAKD,QAAQ,GAC3CU,EACA,CAAER,QAAS,KAAKA,OAAQ,EACxByE,CAAAA,CAEJ,CAAA,CACF,CAEU1D,eAAeJ,EAA+B,CACtD,OAAO4F,KAAKC,UAAU7F,CAAAA,CACxB,CAEAM,SAASa,EAAc,CACrB,OAAI,OAAO2E,OAAW,IACbA,OAAOC,KAAK5E,CAAAA,EAAMa,SAAS,QAAA,EAE7BgE,KAAK7E,CAAAA,CACd,CAEQD,cAAczB,EAAc,CAClC,MAAO,GAAG,KAAKN,QAAQ,IAAIM,EAAKwG,QAAQ,OAAQ,EAAA,CAAA,EAClD,CAEQjF,oBAAoBvB,EAAc,CACxC,OAAOA,EAAKwG,QAAQ,WAAY,EAAA,EAAIA,QAAQ,OAAQ,GAAA,CACtD,CAGQjC,0BACNb,EACAH,EACiB,CACjB,OAAIA,EAAUkD,OAAO/C,EAAMpB,IAAI,QAASiB,EAAUkD,MAAMlE,SAAQ,CAAA,EAC5DgB,EAAUmD,QAAQhD,EAAMpB,IAAI,SAAUiB,EAAUmD,OAAOnE,SAAQ,CAAA,EAC/DgB,EAAUoD,QAAQjD,EAAMpB,IAAI,SAAUiB,EAAUoD,MAAM,EACtDpD,EAAUqD,QAAQlD,EAAMpB,IAAI,SAAUiB,EAAUqD,MAAM,EACtDrD,EAAUsD,SAASnD,EAAMpB,IAAI,UAAWiB,EAAUsD,QAAQtE,SAAQ,CAAA,EAE/DmB,CACT,CACF,EC5+CO,IAAMoD,GAAU,UCLhB,IAAMC,EAAkB,CAC7B,gBAAiB,cAAcC,EAAAA,EACjC,ECWA,IAAqBC,GAArB,cAA8CC,CAAAA,CAd9C,MAc8CA,CAAAA,EAAAA,yBAC5C,YACEC,EACAC,EAAqC,CAAC,EACtCC,EACAC,EACA,CACA,IAAMC,EAAU,IAAIC,IAAIL,CAAAA,EAIpBG,GAAMG,gBACe,yBAAyBC,KAAKH,EAAQI,QAAQ,GAC/C,CAACJ,EAAQI,SAASC,SAAS,mBAAA,IAC/CL,EAAQI,SAAWJ,EAAQI,SAASE,QAAQ,YAAa,mBAAA,GAI7D,IAAMC,EAAWP,EAAQQ,KAAKF,QAAQ,MAAO,EAAA,EACvCG,EAAe,CAAE,GAAGC,EAAiB,GAAGb,CAAQ,EAEtD,MAAMU,EAAUE,EAAcX,EAAO,SAAA,CACvC,CAyCA,MAAMa,YAAYC,EAShB,CACA,OAAO,KAAKC,gBAAgB,SAAA,CAC1B,IAAMC,EAAc,KAAKC,+BAA+BH,CAAAA,EACxD,OAAO,MAAMI,EAAI,KAAKlB,MAAO,GAAG,KAAKF,GAAG,UAAUkB,CAAAA,GAAe,CAC/DjB,QAAS,KAAKA,OAChB,CAAA,CACF,CAAA,CACF,CA0CA,MAAMoB,UAAUC,EASd,CACA,OAAO,KAAKL,gBAAgB,SACnB,MAAMG,EAAI,KAAKlB,MAAO,GAAG,KAAKF,GAAG,WAAWsB,CAAAA,GAAM,CAAErB,QAAS,KAAKA,OAAQ,CAAA,CACnF,CACF,CA8CA,MAAMsB,aACJD,EACAN,EAKI,CACFQ,OAAQ,EACV,EAUA,CACA,OAAO,KAAKP,gBAAgB,SACnB,MAAMQ,EACX,KAAKvB,MACL,GAAG,KAAKF,GAAG,UACX,CACEsB,GAAAA,EACAI,KAAMJ,EACNK,KAAMX,EAAQW,KACdH,OAAQR,EAAQQ,OAChBI,gBAAiBZ,EAAQa,cACzBC,mBAAoBd,EAAQe,gBAC9B,EACA,CAAE9B,QAAS,KAAKA,OAAQ,CAAA,CAE5B,CACF,CA4CA,MAAM+B,aACJV,EACAN,EAcA,CACA,OAAO,KAAKC,gBAAgB,SACnB,MAAMgB,GACX,KAAK/B,MACL,GAAG,KAAKF,GAAG,WAAWsB,CAAAA,GACtB,CACEA,GAAAA,EACAI,KAAMJ,EACNE,OAAQR,EAAQQ,OAChBI,gBAAiBZ,EAAQa,cACzBC,mBAAoBd,EAAQe,gBAC9B,EACA,CAAE9B,QAAS,KAAKA,OAAQ,CAAA,CAE5B,CACF,CAiCA,MAAMiC,YAAYZ,EAShB,CACA,OAAO,KAAKL,gBAAgB,SACnB,MAAMQ,EAAK,KAAKvB,MAAO,GAAG,KAAKF,GAAG,WAAWsB,CAAAA,SAAY,CAAC,EAAG,CAAErB,QAAS,KAAKA,OAAQ,CAAA,CAC9F,CACF,CAkCA,MAAMkC,aAAab,EASjB,CACA,OAAO,KAAKL,gBAAgB,SACnB,MAAMmB,EAAO,KAAKlC,MAAO,GAAG,KAAKF,GAAG,WAAWsB,CAAAA,GAAM,CAAC,EAAG,CAAErB,QAAS,KAAKA,OAAQ,CAAA,CAC1F,CACF,CAsCA,MAAMoC,iBACJf,EACAN,EACAsB,EAUA,CACA,OAAO,KAAKrB,gBAAgB,SAAA,CAC1B,IAAMsB,EAAQ,IAAIC,gBACdxB,GAASyB,iBACXF,EAAMG,IAAI,kBAAmB,MAAA,EAE/B,IAAMxB,EAAcqB,EAAMI,SAAQ,EAElC,OAAO,MAAMP,EACX,KAAKlC,MACL,GAAG,KAAKF,GAAG,QAAQ4C,GAAkBtB,CAAAA,CAAAA,GAAMJ,EAAc,IAAIA,CAAAA,GAAgB,EAAA,GAC7E,CAAC,EACD,CAAEjB,QAAS,KAAKA,OAAQ,EACxBqC,CAAAA,CAEJ,CAAA,CACF,CAEQnB,+BAA+BH,EAAqC,CAC1E,IAAM6B,EAAiC,CAAC,EACxC,OAAI7B,IACE,UAAWA,IACb6B,EAAOC,MAAQC,OAAO/B,EAAQ8B,KAAK,GAEjC,WAAY9B,IACd6B,EAAOG,OAASD,OAAO/B,EAAQgC,MAAM,GAEnChC,EAAQiC,SACVJ,EAAOI,OAASjC,EAAQiC,QAEtBjC,EAAQkC,aACVL,EAAOK,WAAalC,EAAQkC,YAE1BlC,EAAQmC,YACVN,EAAOM,UAAYnC,EAAQmC,YAGxBC,OAAOC,KAAKR,CAAAA,EAAQS,OAAS,EAAI,IAAM,IAAId,gBAAgBK,CAAAA,EAAQF,SAAQ,EAAK,EACzF,CACF,EC9dO,IAAMY,EAAN,cAA2B,KAAM,OAAA,CAAAC,EAAA,qBAOtC,YACEC,EACAC,EAMA,CACA,MAAMD,CAAO,EACb,KAAK,KAAO,eACZ,KAAK,OAASC,EAAK,OACnB,KAAK,YAAcA,EAAK,YACxB,KAAK,YAAcA,EAAK,YACxB,KAAK,QAAUA,EAAK,QAKpB,KAAK,qBAAuBA,EAAK,cAAgB,6BACnD,CAKA,YAAsB,CACpB,OAAO,KAAK,SAAW,GACzB,CAKA,YAAsB,CACpB,OAAO,KAAK,SAAW,GACzB,CAKA,yBAAmC,CACjC,OAAO,KAAK,SAAW,GACzB,CACF,EC1DO,SAASC,GACdC,EACAC,EACAC,EACQ,CACR,IAAMC,EAAM,IAAI,IAAIF,EAAMD,CAAO,EAEjC,GAAIE,EACF,OAAW,CAACE,EAAKC,CAAK,IAAK,OAAO,QAAQH,CAAK,EACzCG,IAAU,QACZF,EAAI,aAAa,IAAIC,EAAKC,CAAK,EAKrC,OAAOF,EAAI,SAAA,CACb,CAhBgBP,EAAAG,GAAA,YCIhB,eAAeO,GAAiBC,EAAoD,CAClF,MAAI,CAACA,GAAQA,EAAK,OAAS,OAClB,CAAA,EAGLA,EAAK,OAAS,SACT,CAAE,cAAe,UAAUA,EAAK,KAAK,EAAA,EAG1CA,EAAK,OAAS,SACT,CAAE,CAACA,EAAK,IAAI,EAAGA,EAAK,KAAA,EAGzBA,EAAK,OAAS,SACT,MAAMA,EAAK,WAAA,EAGb,CAAA,CACT,CAlBeX,EAAAU,GAAA,oBAoBR,SAASE,GAAkBC,EAInB,CACb,IAAMC,EAAUD,EAAQ,WAAa,WAAW,MAEhD,MAAO,CACL,MAAM,QAAW,CACf,OAAAE,EACA,KAAAV,EACA,MAAAC,EACA,KAAAU,EACA,QAAAC,CAAA,EACwC,CACxC,IAAMV,EAAMJ,GAASU,EAAQ,QAASR,EAAMC,CAAK,EAC3CY,EAAc,MAAMR,GAAiBG,EAAQ,IAAI,EAEnDM,EACJ,GAAI,CACFA,EAAM,MAAML,EAAQP,EAAK,CACvB,OAAAQ,EACA,QAAS,CACP,GAAIC,EAAO,CAAE,eAAgB,kBAAA,EAAuB,CAAA,EACpD,GAAGE,EACH,GAAGD,CAAA,EAEL,KAAMD,EAAO,KAAK,UAAUA,CAAI,EAAI,MAAA,CACrC,CACH,OAASI,EAAK,CAIZ,GAAIA,aAAerB,EAAc,MAAMqB,EACvC,IAAMnB,EAAUmB,aAAe,MAAQA,EAAI,QAAU,OAAOA,CAAG,EAC/D,MAAM,IAAIrB,EAAa,2BAA2BE,CAAO,GAAI,CAC3D,OAAQ,EACR,QAASmB,CAAA,CACV,CACH,CAIA,GAAID,EAAI,SAAW,IACjB,MAAO,CAAE,OAAQ,IAAK,QAASA,EAAI,QAAS,KAAM,MAAA,EAGpD,IAAME,EAAO,MAAMF,EAAI,KAAA,EACjBG,GAAUH,EAAI,QAAQ,IAAI,cAAc,GAAK,IAAI,SAAS,kBAAkB,EAC5EI,EAAOD,GAAUD,EAAQ,KAAK,MAAMA,CAAI,EAAWA,EAEzD,GAAI,CAACF,EAAI,GAAI,CACX,IAAMK,EAAUF,EAAUC,EAAgC,OACpDE,EAAcD,GAAS,MAC7B,MAAM,IAAIzB,EAAa0B,GAAa,SAAW,8BAA8BN,EAAI,MAAM,GAAI,CACzF,OAAQA,EAAI,OACZ,YAAaM,GAAa,KAC1B,YAAaA,GAAa,KAC1B,QAASD,CAAA,CACV,CACH,CAEA,MAAO,CAAE,OAAQL,EAAI,OAAQ,QAASA,EAAI,QAAS,KAAAI,CAAA,CACrD,CAAA,CAEJ,CAjEgBvB,EAAAY,GAAA,qBCZT,SAASc,GAAiC,CAC/C,IAAMC,EAAK,OAAO,KAAK,IAAA,CAAK,EACtBC,EAAQ,IAAI,WAAW,EAAE,EAG/BA,EAAM,CAAC,EAAI,OAAQD,GAAM,IAAO,KAAK,EACrCC,EAAM,CAAC,EAAI,OAAQD,GAAM,IAAO,KAAK,EACrCC,EAAM,CAAC,EAAI,OAAQD,GAAM,IAAO,KAAK,EACrCC,EAAM,CAAC,EAAI,OAAQD,GAAM,IAAO,KAAK,EACrCC,EAAM,CAAC,EAAI,OAAQD,GAAM,GAAM,KAAK,EACpCC,EAAM,CAAC,EAAI,OAAOD,EAAK,KAAK,EAG5B,IAAME,EAAO,IAAI,WAAW,EAAE,EAC9B,OAAAC,GAAaD,CAAI,EACjBD,EAAM,IAAIC,EAAM,CAAC,EAGjBD,EAAM,CAAC,EAAKA,EAAM,CAAC,EAAI,GAAQ,IAE/BA,EAAM,CAAC,EAAKA,EAAM,CAAC,EAAI,GAAQ,IAExBG,GAAWH,CAAK,CACzB,CAvBgB5B,EAAA0B,EAAA,0BAyBhB,SAASK,GAAWC,EAAuB,CACzC,IAAMC,EAAgB,CAAA,EACtB,QAASC,EAAI,EAAGA,EAAI,GAAIA,IACtBD,EAAI,KAAKD,EAAEE,CAAC,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAE7C,MAAO,GAAGD,EAAI,MAAM,EAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAIA,EAAI,MAAM,EAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAIA,EAAI,MAAM,EAAG,CAAC,EAAE,KAAK,EAAE,CAAC,IAAIA,EAAI,MAAM,EAAG,EAAE,EAAE,KAAK,EAAE,CAAC,IAAIA,EAAI,MAAM,GAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EACvJ,CANSjC,EAAA+B,GAAA,cAQT,SAASD,GAAaK,EAAuB,CAC3C,IAAMC,EACJ,OAAO,WAAW,OAAW,KAC7B,OAAO,WAAW,OAAO,iBAAoB,WACzC,WAAW,OACX,OACN,GAAIA,EAAG,CACLA,EAAE,gBAAgBD,CAAG,EACrB,MACF,CAEA,QAASD,EAAI,EAAGA,EAAIC,EAAI,OAAQD,IAC9BC,EAAID,CAAC,EAAI,KAAK,MAAM,KAAK,OAAA,EAAW,GAAG,CAE3C,CAdSlC,EAAA8B,GAAA,gBCfT,SAASO,GAAgBC,EAA6B,CACpD,OAAOA,EAAU,IAAI,kBAAkB,EAAE,KAAK,KAAK,CACrD,CAFStC,EAAAqC,GAAA,mBAIT,SAASE,GAAuBD,EAA6B,CAE3D,OAAOA,EAAU,KAAK,GAAM,CAC9B,CAHStC,EAAAuC,GAAA,0BAcT,eAAeC,EAAcC,EAAoC,CAC/D,OAAO,OAAOA,GAAM,SAAWA,EAAIA,EAAA,CACrC,CAFezC,EAAAwC,EAAA,iBAIR,IAAME,GAAN,KAA0B,OAAA,CAAA1C,EAAA,4BAC/B,YACmB2C,EACAC,EAAyB,GAC1C,CAFiB,KAAA,OAAAD,EACA,KAAA,OAAAC,CAChB,CAEH,MAAM,eAAe/B,EAAiC,CAAA,EAAmC,CACvF,IAAM+B,EAAS,MAAMJ,EAAc,KAAK,MAAM,EAExClC,EAA4C,CAAA,EAC9CO,EAAQ,SAAQP,EAAM,OAASiC,GAAuB1B,EAAQ,OAAO,SAAS,GAC9EA,EAAQ,YAAc,SAAWP,EAAM,UAAYO,EAAQ,WAC3DA,EAAQ,WAAa,SAAAP,EAAiB,SAAW,OAAOO,EAAQ,QAAQ,GAC5E,IAAMgC,EAAW,OAAO,KAAKvC,CAAK,EAAE,KAAMwC,GAAMxC,EAAMwC,CAAC,IAAM,MAAS,EAEhEC,EAAW,MAAM,KAAK,OAAO,QAAgC,CACjE,OAAQ,MACR,KAAM,GAAGH,CAAM,cACf,MAAOC,EAAWvC,EAAQ,MAAA,CAC3B,EAED,MAAO,CACL,YAAayC,EAAS,KAAK,YAAc,CAAA,GAAI,IAAKC,IAAQ,CAAE,UAAWA,CAAA,EAAK,EAC5E,cAAeD,EAAS,KAAK,iBAAiB,GAAK,MAAA,CAEvD,CAEA,MAAM,gBACJE,EACAC,EACkC,CAClC,IAAMN,EAAS,MAAMJ,EAAc,KAAK,MAAM,EACxCW,EAAkC,CACtC,UAAWF,EAAG,UACd,WAAYC,GAAU,UAAA,EAUxB,OAPiB,MAAM,KAAK,OAAO,QAAiC,CAClE,OAAQ,OACR,KAAM,GAAGN,CAAM,cACf,KAAMO,EACN,QAAS,CAAE,kBAAmBzB,EAAA,CAAuB,CAAE,CACxD,GAEe,IAClB,CAEA,MAAM,cAAcuB,EAAwC,CAC1D,IAAML,EAAS,MAAMJ,EAAc,KAAK,MAAM,EAC9C,MAAM,KAAK,OAAO,QAAc,CAC9B,OAAQ,SACR,KAAM,GAAGI,CAAM,eAAeP,GAAgBY,EAAG,SAAS,CAAC,GAC3D,QAAS,CAAE,kBAAmBvB,EAAA,CAAuB,CAAE,CACxD,CACH,CAEA,MAAM,sBAAsBuB,EAAqD,CAC/E,IAAML,EAAS,MAAMJ,EAAc,KAAK,MAAM,EAM9C,MAAO,CACL,YANe,MAAM,KAAK,OAAO,QAA8B,CAC/D,OAAQ,MACR,KAAM,GAAGI,CAAM,eAAeP,GAAgBY,EAAG,SAAS,CAAC,EAAA,CAC5D,GAGsB,KAAK,YAAc,CAAA,CAAC,CAE7C,CAEA,MAAM,gBAAgBA,EAA2C,CAC/D,IAAML,EAAS,MAAMJ,EAAc,KAAK,MAAM,EAC9C,GAAI,CACF,aAAM,KAAK,OAAO,QAAc,CAC9B,OAAQ,OACR,KAAM,GAAGI,CAAM,eAAeP,GAAgBY,EAAG,SAAS,CAAC,EAAA,CAC5D,EACM,EACT,OAASG,EAAO,CACd,GAAIA,aAAiBrD,GAAgBqD,EAAM,SAAW,IACpD,MAAO,GAET,MAAMA,CACR,CACF,CAEA,MAAM,0BACJH,EACAE,EAC4C,CAC5C,IAAMP,EAAS,MAAMJ,EAAc,KAAK,MAAM,EAO9C,OANiB,MAAM,KAAK,OAAO,QAA2C,CAC5E,OAAQ,OACR,KAAM,GAAGI,CAAM,eAAeP,GAAgBY,EAAG,SAAS,CAAC,cAC3D,KAAME,EACN,QAAS,CAAE,kBAAmBzB,EAAA,CAAuB,CAAE,CACxD,GACe,IAClB,CAEA,MAAM,2BACJuB,EACAC,EACyC,CACzC,GAAI,CACF,OAAO,MAAM,KAAK,gBAAgBD,EAAIC,CAAQ,CAChD,OAASE,EAAO,CACd,GAAIA,aAAiBrD,GAAgBqD,EAAM,SAAW,IACpD,OAEF,MAAMA,CACR,CACF,CACF,EC5IA,SAASf,EAAgBC,EAA6B,CACpD,OAAOA,EAAU,IAAI,kBAAkB,EAAE,KAAK,KAAK,CACrD,CAFSD,EAAAA,EAAAA,oBAIT,SAASgB,GAAaC,EAAsB,CAC1C,OAAO,mBAAmBA,CAAI,CAChC,CAFStD,EAAAqD,GAAA,gBAIT,eAAeb,EAAcC,EAAoC,CAC/D,OAAO,OAAOA,GAAM,SAAWA,EAAIA,EAAA,CACrC,CAFeD,EAAAA,EAAAA,kBAIR,IAAMe,GAAN,KAAsB,OAAA,CAAAvD,EAAA,wBAC3B,YACmB2C,EACAC,EAAyB,GACzBY,EACjB,CAHiB,KAAA,OAAAb,EACA,KAAA,OAAAC,EACA,KAAA,iBAAAY,CAChB,CAEH,MAAM,WACJlB,EACAzB,EAA6B,CAAA,EACF,CAC3B,IAAM+B,EAAS,MAAMJ,EAAc,KAAK,MAAM,EACxClC,EAA4C,CAAA,EAC9CO,EAAQ,YAAc,SAAWP,EAAM,UAAYO,EAAQ,WAC3DA,EAAQ,WAAa,SAAAP,EAAiB,SAAW,OAAOO,EAAQ,QAAQ,GAC5E,IAAMgC,EAAW,OAAO,KAAKvC,CAAK,EAAE,KAAMwC,GAAMxC,EAAMwC,CAAC,IAAM,MAAS,EAEhEC,EAAW,MAAM,KAAK,OAAO,QAA4B,CAC7D,OAAQ,MACR,KAAM,GAAGH,CAAM,eAAeP,EAAgBC,EAAU,SAAS,CAAC,UAClE,MAAOO,EAAWvC,EAAQ,MAAA,CAC3B,EAED,MAAO,CACL,YAAayC,EAAS,KAAK,aAAe,CAAA,EAC1C,cAAeA,EAAS,KAAK,iBAAiB,GAAK,MAAA,CAEvD,CAEA,MAAM,YACJT,EACAa,EACwB,CAExB,OADe,MAAM,KAAK,kBAAkBb,EAAWa,CAAO,GAChD,QAChB,CAQA,MAAM,kBACJb,EACAa,EACkC,CAClC,IAAMP,EAAS,MAAMJ,EAAc,KAAK,MAAM,EACxCvB,EAAkC,CAAE,kBAAmBS,EAAA,CAAuB,EAChF,KAAK,mBACPT,EAAQ,6BAA6B,EAAI,KAAK,kBAGhD,IAAM8B,EAAW,MAAM,KAAK,OAAO,QAA2B,CAC5D,OAAQ,OACR,KAAM,GAAGH,CAAM,eAAeP,EAAgBC,EAAU,SAAS,CAAC,UAClE,KAAMa,EACN,QAAAlC,CAAA,CACD,EAED,MAAO,CACL,GAAG8B,EAAS,KACZ,KAAMA,EAAS,QAAQ,IAAI,MAAM,CAAA,CAErC,CAEA,MAAM,YACJE,EACAE,EAC8B,CAC9B,IAAMP,EAAS,MAAMJ,EAAc,KAAK,MAAM,EACxCO,EAAW,MAAM,KAAK,OAAO,QAA2B,CAC5D,OAAQ,OACR,KAAM,GAAGH,CAAM,eAAeP,EAAgBY,EAAG,SAAS,CAAC,WAAWI,GAAaJ,EAAG,IAAI,CAAC,GAC3F,KAAME,EACN,QAAS,CAAE,kBAAmBzB,EAAA,CAAuB,CAAE,CACxD,EAEK+B,EAAmBV,EAAS,KAAK,mBAAmB,EAC1D,GAAI,CAACU,EAIH,MAAM,IAAI1D,EACR,wFACA,CAAE,OAAQgD,EAAS,OAAQ,QAASA,EAAS,IAAA,CAAK,EAItD,MAAO,CACL,oBAAqBU,EACrB,SAAUV,EAAS,KAAK,QAAA,CAE5B,CAGA,MAAM,YACJE,EACAE,EAC8B,CAC9B,OAAO,KAAK,YAAYF,EAAIE,CAAO,CACrC,CAEA,MAAM,UAAUF,EAAqBpC,EAA2C,CAC9E,IAAM+B,EAAS,MAAMJ,EAAc,KAAK,MAAM,EAC9C,MAAM,KAAK,OAAO,QAAc,CAC9B,OAAQ,SACR,KAAM,GAAGI,CAAM,eAAeP,EAAgBY,EAAG,SAAS,CAAC,WAAWI,GAAaJ,EAAG,IAAI,CAAC,GAC3F,MAAO,CAAE,eAAgB,OAAOpC,GAAS,OAAS,EAAK,CAAA,EACvD,QAAS,CAAE,kBAAmBa,EAAA,CAAuB,CAAE,CACxD,CACH,CAIA,MAAM,UAAUuB,EAAqBpC,EAA2D,CAC9F,IAAM6C,EAAS,MAAM,KAAK,gBAAgBT,EAAIpC,CAAO,EACrD,OAAO6C,EAASA,EAAO,SAAW,IACpC,CAQA,MAAM,gBACJT,EACApC,EACyC,CACzC,IAAM+B,EAAS,MAAMJ,EAAc,KAAK,MAAM,EACxCvB,EAAkC,CAAA,EACpC,KAAK,mBACPA,EAAQ,6BAA6B,EAAI,KAAK,kBAE5CJ,GAAS,cACXI,EAAQ,eAAe,EAAIJ,EAAQ,aAErC,IAAMP,EAA4C,CAAA,EAC9CO,GAAS,YAAWP,EAAM,UAAYO,EAAQ,WAElD,IAAMkC,EAAW,MAAM,KAAK,OAAO,QAA2B,CAC5D,OAAQ,MACR,KAAM,GAAGH,CAAM,eAAeP,EAAgBY,EAAG,SAAS,CAAC,WAAWI,GAAaJ,EAAG,IAAI,CAAC,GAC3F,QAAAhC,EACA,MAAO,OAAO,KAAKX,CAAK,EAAE,OAASA,EAAQ,MAAA,CAC5C,EAED,OAAIyC,EAAS,SAAW,IACf,KAGF,CACL,GAAGA,EAAS,KACZ,KAAMA,EAAS,QAAQ,IAAI,MAAM,CAAA,CAErC,CAEA,MAAM,YAAYE,EAAuC,CACvD,IAAML,EAAS,MAAMJ,EAAc,KAAK,MAAM,EACxCvB,EAAkC,CAAA,EACpC,KAAK,mBACPA,EAAQ,6BAA6B,EAAI,KAAK,kBAGhD,GAAI,CACF,aAAM,KAAK,OAAO,QAAc,CAC9B,OAAQ,OACR,KAAM,GAAG2B,CAAM,eAAeP,EAAgBY,EAAG,SAAS,CAAC,WAAWI,GAAaJ,EAAG,IAAI,CAAC,GAC3F,QAAAhC,CAAA,CACD,EACM,EACT,OAASmC,EAAO,CACd,GAAIA,aAAiBrD,GAAgBqD,EAAM,SAAW,IACpD,MAAO,GAET,MAAMA,CACR,CACF,CAEA,MAAM,cACJd,EACAa,EACwB,CAExB,OADe,MAAM,KAAK,oBAAoBb,EAAWa,CAAO,GAClD,QAChB,CAEA,MAAM,oBACJb,EACAa,EACkC,CAClC,IAAMP,EAAS,MAAMJ,EAAc,KAAK,MAAM,EACxCvB,EAAkC,CAAE,kBAAmBS,EAAA,CAAuB,EAChF,KAAK,mBACPT,EAAQ,6BAA6B,EAAI,KAAK,kBAEhD,IAAM8B,EAAW,MAAM,KAAK,OAAO,QAA2B,CAC5D,OAAQ,OACR,KAAM,GAAGH,CAAM,eAAeP,EAAgBC,EAAU,SAAS,CAAC,YAClE,KAAMa,EACN,QAAAlC,CAAA,CACD,EACD,MAAO,CACL,GAAG8B,EAAS,KACZ,KAAMA,EAAS,QAAQ,IAAI,MAAM,CAAA,CAErC,CAEA,MAAM,YAAYI,EAA4C,CAC5D,IAAMP,EAAS,MAAMJ,EAAc,KAAK,MAAM,EAC9C,MAAM,KAAK,OAAO,QAAc,CAC9B,OAAQ,OACR,KAAM,GAAGI,CAAM,iBACf,KAAMO,EACN,QAAS,CAAE,kBAAmBzB,EAAA,CAAuB,CAAE,CACxD,CACH,CAEA,MAAM,uBACJY,EACAa,EACwB,CACxB,GAAI,CACF,OAAO,MAAM,KAAK,YAAYb,EAAWa,CAAO,CAClD,OAASC,EAAO,CACd,GAAIA,aAAiBrD,GAAgBqD,EAAM,SAAW,IACpD,OAAO,MAAM,KAAK,UAAU,CAAE,UAAWd,EAAU,UAAW,KAAMa,EAAQ,IAAA,CAAM,EAEpF,MAAMC,CACR,CACF,CACF,ECpLaO,GAAN,KAAyB,OAAA,CAAA3D,EAAA,2BAe9B,YAAYa,EAAoC,CAC9C,IAAMT,EAAUS,EAAQ,QAAQ,SAAS,GAAG,EAAIA,EAAQ,QAAU,GAAGA,EAAQ,OAAO,IAEpF,KAAK,UAAYA,EAAQ,WAAaA,EAAQ,YAE9C,KAAK,OAASD,GAAkB,CAC9B,QAAAR,EACA,KAAMS,EAAQ,KACd,UAAWA,EAAQ,KAAA,CACpB,EAGD,KAAK,iBAAmBA,EAAQ,kBAAkB,KAAK,GAAG,EAE1D,IAAM+C,EAAY5D,EAAA,IAAM,KAAK,cAAA,EAAX,aAClB,KAAK,aAAe,IAAI0C,GAAoB,KAAK,OAAQkB,CAAS,EAClE,KAAK,SAAW,IAAIL,GAAgB,KAAK,OAAQK,EAAW,KAAK,gBAAgB,CACnF,CAUA,MAAM,YAAqC,CACzC,GAAI,CAAC,KAAK,oBAAqB,CAC7B,IAAMtD,EAA4C,CAAA,EAC9C,KAAK,YAAc,SAAWA,EAAM,UAAY,KAAK,WACzD,KAAK,oBAAsB,KAAK,OAC7B,QAAuB,CACtB,OAAQ,MACR,KAAM,YACN,MAAO,OAAO,KAAKA,CAAK,EAAE,OAASA,EAAQ,MAAA,CAC5C,EACA,KAAMyC,GAAaA,EAAS,IAAI,EAChC,MAAO3B,GAAQ,CAEd,WAAK,oBAAsB,OACrBA,CACR,CAAC,CACL,CACA,OAAO,KAAK,mBACd,CAEA,MAAc,eAAiC,CAC7C,OAAK,KAAK,gBACR,KAAK,cAAgB,KAAK,cAAA,GAErB,KAAK,aACd,CAEA,MAAc,eAAiC,CAC7C,GAAI,KAAK,YAAc,OAErB,MAAO,KAET,GAAI,CACF,IAAMyC,EAAS,MAAM,KAAK,WAAA,EACpBC,EAAeD,EAAO,WAAW,QAAUA,EAAO,UAAU,OAClE,OAAOC,EAAe,MAAMA,CAAY,GAAK,MAAM,KAAK,SAAS,EACnE,MAAQ,CAIN,MAAO,MAAM,KAAK,SAAS,EAC7B,CACF,CAqBA,MAAM,eAAejD,EAAiC,CAAA,EAAmC,CACvF,OAAO,KAAK,aAAa,eAAeA,CAAO,CACjD,CAKA,MAAM,gBACJoC,EACAC,EACkC,CAClC,OAAO,KAAK,aAAa,gBAAgBD,EAAIC,CAAQ,CACvD,CAOA,MAAM,cAAcD,EAAwC,CAC1D,MAAM,KAAK,aAAa,cAAcA,CAAE,CAC1C,CAKA,MAAM,sBAAsBA,EAAqD,CAC/E,OAAO,KAAK,aAAa,sBAAsBA,CAAE,CACnD,CAKA,MAAM,0BACJA,EACAE,EAC4C,CAC5C,OAAO,KAAK,aAAa,0BAA0BF,EAAIE,CAAO,CAChE,CAOA,MAAM,WACJb,EACAzB,EAA6B,CAAA,EACF,CAC3B,OAAO,KAAK,SAAS,WAAWyB,EAAWzB,CAAO,CACpD,CAKA,MAAM,YACJyB,EACAa,EACwB,CACxB,OAAO,KAAK,SAAS,YAAYb,EAAWa,CAAO,CACrD,CAQA,MAAM,kBACJb,EACAa,EACkC,CAClC,OAAO,KAAK,SAAS,kBAAkBb,EAAWa,CAAO,CAC3D,CAgBA,MAAM,YACJF,EACAE,EAC8B,CAC9B,OAAO,KAAK,SAAS,YAAYF,EAAIE,CAAO,CAC9C,CAGA,MAAM,YACJF,EACAE,EAC8B,CAC9B,OAAO,KAAK,SAAS,YAAYF,EAAIE,CAAO,CAC9C,CAKA,MAAM,UAAUF,EAAqBpC,EAA2C,CAC9E,MAAM,KAAK,SAAS,UAAUoC,EAAIpC,CAAO,CAC3C,CAUA,MAAM,UAAUoC,EAAqBpC,EAA2D,CAC9F,OAAOA,EAAU,KAAK,SAAS,UAAUoC,EAAIpC,CAAO,EAAI,KAAK,SAAS,UAAUoC,CAAE,CACpF,CAMA,MAAM,gBACJA,EACApC,EACyC,CACzC,OAAO,KAAK,SAAS,gBAAgBoC,EAAIpC,CAAO,CAClD,CAKA,MAAM,gBAAgBoC,EAA2C,CAC/D,OAAO,KAAK,aAAa,gBAAgBA,CAAE,CAC7C,CAKA,MAAM,YAAYA,EAAuC,CACvD,OAAO,KAAK,SAAS,YAAYA,CAAE,CACrC,CAKA,MAAM,2BACJA,EACAC,EACyC,CACzC,OAAO,KAAK,aAAa,2BAA2BD,EAAIC,CAAQ,CAClE,CAKA,MAAM,uBACJZ,EACAa,EACwB,CACxB,OAAO,KAAK,SAAS,uBAAuBb,EAAWa,CAAO,CAChE,CAKA,MAAM,cACJb,EACAa,EACwB,CACxB,OAAO,KAAK,SAAS,cAAcb,EAAWa,CAAO,CACvD,CAKA,MAAM,oBACJb,EACAa,EACkC,CAClC,OAAO,KAAK,SAAS,oBAAoBb,EAAWa,CAAO,CAC7D,CAKA,MAAM,YAAYA,EAA4C,CAC5D,OAAO,KAAK,SAAS,YAAYA,CAAO,CAC1C,CACF,EElYA,IAAAY,GAAA,CACE,IAAO,2BAET,ECOaC,GAAgCD,GAAI,IAKpCE,GAAgC,oDAAoDF,GAAI,GAAG,uCCKxG,IAAqBG,GAArB,cAAoDC,CAAAA,CApBpD,MAoBoDA,CAAAA,EAAAA,+BA6BlD,YAAYC,EAAaC,EAAqC,CAAC,EAAGC,EAAe,CAC/E,IAAMC,EAAWH,EAAII,QAAQ,MAAO,EAAA,EAC9BC,EAAe,CAAE,GAAGC,EAAiB,GAAGL,CAAQ,EACtD,MAAME,EAAUE,EAAcH,EAAO,SAAA,CACvC,CAyCA,MAAMK,aAAaC,EASjB,CACA,OAAO,KAAKC,gBAAgB,SACnB,MAAMC,EAAK,KAAKR,MAAO,GAAG,KAAKF,GAAG,UAAW,CAAEQ,KAAAA,CAAK,EAAG,CAAEP,QAAS,KAAKA,OAAQ,CAAA,CACxF,CACF,CAqDA,MAAMU,YAAYC,EAehB,CACA,OAAO,KAAKH,gBAAgB,SAAA,CAE1B,IAAMI,EAAc,IAAIC,gBACpBF,GAASG,QAAUC,QAAWH,EAAYI,IAAI,QAASL,EAAQG,MAAMG,SAAQ,CAAA,EAC7EN,GAASO,SAAWH,QAAWH,EAAYI,IAAI,SAAUL,EAAQO,OAAOD,SAAQ,CAAA,EAChFN,GAASQ,YAAYP,EAAYI,IAAI,aAAcL,EAAQQ,UAAU,EACrER,GAASS,WAAWR,EAAYI,IAAI,YAAaL,EAAQS,SAAS,EAClET,GAASU,QAAQT,EAAYI,IAAI,SAAUL,EAAQU,MAAM,EAE7D,IAAMC,EAAcV,EAAYK,SAAQ,EAClClB,EAAMuB,EAAc,GAAG,KAAKvB,GAAG,WAAWuB,CAAAA,GAAgB,GAAG,KAAKvB,GAAG,UAE3E,OAAO,MAAMwB,EAAI,KAAKtB,MAAOF,EAAK,CAAEC,QAAS,KAAKA,OAAQ,CAAA,CAC5D,CAAA,CACF,CAqCA,MAAMwB,aAAaC,EASjB,CACA,OAAO,KAAKjB,gBAAgB,SACnB,MAAMkB,EACX,KAAKzB,MACL,GAAG,KAAKF,GAAG,WAAW0B,CAAAA,GACtB,CAAC,EACD,CAAEzB,QAAS,KAAKA,OAAQ,CAAA,CAE5B,CACF,CA8HA2B,KAAKF,EAA+C,CAElD,GAAI,CAACG,GAAkBH,CAAAA,EACrB,MAAM,IAAII,EACR,oJACE,EAQN,IAAMC,EAAU,IAAIC,GAAmB,CACrCC,QAAS,KAAKjC,IACdkC,YAAaR,EACbS,KAAM,CACJC,KAAM,SACNC,WAAYC,EAAA,SAAY,KAAKrC,QAAjB,aACd,EACAC,MAAO,KAAKA,KACd,CAAA,EAEMqC,EAAqB,KAAKA,mBAuBhC,OArBuB,IAAIC,MAAMT,EAAS,CACxCP,IAAIiB,EAAQC,EAA8B,CACxC,IAAMC,EAAQF,EAAOC,CAAAA,EACrB,OAAI,OAAOC,GAAU,WACZA,EAGF,SAAUC,IAAAA,CACf,GAAI,CAEF,MAAO,CAAEC,KADI,MAAOF,EAAmBG,MAAML,EAAQG,CAAAA,EACtCG,MAAO,IAAK,CAC7B,OAASA,EAAO,CACd,GAAIR,EACF,MAAMQ,EAER,MAAO,CAAEF,KAAM,KAAME,MAAOA,CAAsB,CACpD,CACF,CACF,CACF,CAAA,CAGF,CACF,EChYA,IAAqBC,GAArB,cAA4CC,CAAAA,CAnC5C,MAmC4CA,CAAAA,EAAAA,uBAE1C,YAAYC,EAAaC,EAAqC,CAAC,EAAGC,EAAe,CAC/E,IAAMC,EAAWH,EAAII,QAAQ,MAAO,EAAA,EAC9BC,EAAe,CAAE,GAAGC,EAAiB,eAAgB,mBAAoB,GAAGL,CAAQ,EAC1F,MAAME,EAAUE,EAAcH,EAAO,SAAA,CACvC,CAGA,MAAMK,YAAYC,EAA8D,CAC9E,OAAO,KAAKC,gBAAgB,SACb,MAAMC,EAAWC,KAAK,KAAKT,MAAO,GAAG,KAAKF,GAAG,eAAgBQ,EAAS,CACjFP,QAAS,KAAKA,OAChB,CAAA,GACe,CAAC,CAClB,CACF,CAGA,MAAMW,SACJC,EACAC,EAC8C,CAC9C,OAAO,KAAKL,gBAAgB,SACnB,MAAMC,EAAWC,KACtB,KAAKT,MACL,GAAG,KAAKF,GAAG,YACX,CAAEa,iBAAAA,EAAkBC,UAAAA,CAAU,EAC9B,CAAEb,QAAS,KAAKA,OAAQ,CAAA,CAE5B,CACF,CAGA,MAAMc,YAAYP,EAAwE,CACxF,OAAO,KAAKC,gBAAgB,SACnB,MAAMC,EAAWC,KAAK,KAAKT,MAAO,GAAG,KAAKF,GAAG,eAAgBQ,EAAS,CAC3EP,QAAS,KAAKA,OAChB,CAAA,CACF,CACF,CAGA,MAAMe,YAAYH,EAA0BC,EAAoD,CAC9F,OAAO,KAAKL,gBAAgB,SACb,MAAMC,EAAWC,KAC5B,KAAKT,MACL,GAAG,KAAKF,GAAG,eACX,CAAEa,iBAAAA,EAAkBC,UAAAA,CAAU,EAC9B,CAAEb,QAAS,KAAKA,OAAQ,CAAA,GAEX,CAAC,CAClB,CACF,CACF,ECpEA,IAAqBgB,GAArB,cAA2CC,CAAAA,CArB3C,MAqB2CA,CAAAA,EAAAA,sBAEzC,YAAYC,EAAaC,EAAqC,CAAC,EAAGC,EAAe,CAC/E,IAAMC,EAAWH,EAAII,QAAQ,MAAO,EAAA,EAC9BC,EAAe,CAAE,GAAGC,EAAiB,eAAgB,mBAAoB,GAAGL,CAAQ,EAC1F,MAAME,EAAUE,EAAcH,EAAO,SAAA,CACvC,CAGA,MAAMK,WAAWC,EAA6D,CAE5E,GAAIA,EAAQC,QAAQC,OAAS,GAAKF,EAAQC,QAAQC,OAAS,IACzD,MAAM,IAAIC,MAAM,mDAAA,EAGlB,OAAO,KAAKC,gBAAgB,SACb,MAAMC,EAAWC,KAAK,KAAKZ,MAAO,GAAG,KAAKF,GAAG,cAAeQ,EAAS,CAChFP,QAAS,KAAKA,OAChB,CAAA,GACe,CAAC,CAClB,CACF,CAGA,MAAMc,WAAWP,EAAsE,CACrF,OAAO,KAAKI,gBAAgB,SACnB,MAAMC,EAAWC,KAAK,KAAKZ,MAAO,GAAG,KAAKF,GAAG,cAAeQ,EAAS,CAC1EP,QAAS,KAAKA,OAChB,CAAA,CACF,CACF,CAGA,MAAMe,YAAYR,EAAwE,CAExF,GAAIA,EAAQS,eAAiBC,OAAW,CACtC,GAAIV,EAAQS,aAAe,GAAKT,EAAQS,aAAe,GACrD,MAAM,IAAIN,MAAM,uCAAA,EAElB,GAAIH,EAAQW,eAAiBD,SACvBV,EAAQW,aAAe,GAAKX,EAAQW,cAAgBX,EAAQS,cAC9D,MAAM,IAAIN,MAAM,sCAAsCH,EAAQS,aAAe,CAAA,EAAG,CAGtF,CAEA,OAAO,KAAKL,gBAAgB,SACnB,MAAMC,EAAWC,KAAK,KAAKZ,MAAO,GAAG,KAAKF,GAAG,eAAgBQ,EAAS,CAC3EP,QAAS,KAAKA,OAChB,CAAA,CACF,CACF,CAGA,MAAMmB,aAAaZ,EAA0E,CAC3F,OAAO,KAAKI,gBAAgB,SACnB,MAAMC,EAAWC,KAAK,KAAKZ,MAAO,GAAG,KAAKF,GAAG,gBAAiBQ,EAAS,CAC5EP,QAAS,KAAKA,OAChB,CAAA,CACF,CACF,CAGA,MAAMoB,cAAcb,EAAgE,CAElF,GAAIA,EAAQc,KAAKZ,OAAS,GAAKF,EAAQc,KAAKZ,OAAS,IACnD,MAAM,IAAIC,MAAM,iDAAA,EAGlB,OAAO,KAAKC,gBAAgB,SACb,MAAMC,EAAWC,KAAK,KAAKZ,MAAO,GAAG,KAAKF,GAAG,iBAAkBQ,EAAS,CACnFP,QAAS,KAAKA,OAChB,CAAA,GACe,CAAC,CAClB,CACF,CACF,ECjFA,IAAqBsB,GAArB,cAA6CC,CAAAA,CAhB7C,MAgB6CA,CAAAA,EAAAA,wBAE3C,YAAYC,EAAaC,EAAqC,CAAC,EAAGC,EAAe,CAC/E,IAAMC,EAAWH,EAAII,QAAQ,MAAO,EAAA,EAC9BC,EAAe,CAAE,GAAGC,EAAiB,eAAgB,mBAAoB,GAAGL,CAAQ,EAC1F,MAAME,EAAUE,EAAcH,EAAO,SAAA,CACvC,CAGA,MAAMK,aAAaC,EAA2D,CAC5E,OAAO,KAAKC,gBAAgB,SACb,MAAMC,EAAWC,KAC5B,KAAKT,MACL,GAAG,KAAKF,GAAG,sBACX,CAAEQ,iBAAAA,CAAiB,EACnB,CAAEP,QAAS,KAAKA,OAAQ,CAAA,GAEX,CAAC,CAClB,CACF,CAGA,MAAMW,UAAUJ,EAAgF,CAC9F,OAAO,KAAKC,gBAAgB,SACnB,MAAMC,EAAWC,KACtB,KAAKT,MACL,GAAG,KAAKF,GAAG,mBACX,CAAEQ,iBAAAA,CAAiB,EACnB,CAAEP,QAAS,KAAKA,OAAQ,CAAA,CAE5B,CACF,CAGA,MAAMY,YACJC,EAAoC,CAAC,EACY,CACjD,OAAO,KAAKL,gBAAgB,SACnB,MAAMC,EAAWC,KAAK,KAAKT,MAAO,GAAG,KAAKF,GAAG,qBAAsBc,EAAS,CACjFb,QAAS,KAAKA,OAChB,CAAA,CACF,CACF,CAGA,MAAMc,aAAaP,EAA2D,CAC5E,OAAO,KAAKC,gBAAgB,SACb,MAAMC,EAAWC,KAC5B,KAAKT,MACL,GAAG,KAAKF,GAAG,sBACX,CAAEQ,iBAAAA,CAAiB,EACnB,CAAEP,QAAS,KAAKA,OAAQ,CAAA,GAEX,CAAC,CAClB,CACF,CACF,ECOO,IAAMe,GAAN,cAAmCC,EAAAA,CA/E1C,MA+E0CA,CAAAA,EAAAA,6BA6BxC,YAAYC,EAAaC,EAAuC,CAAC,EAAG,CAClE,MAAMD,EAAKC,EAAQC,SAAW,CAAC,EAAGD,EAAQE,KAAK,CACjD,CAqBAC,KAAKC,EAA6C,CAChD,OAAO,IAAIC,GAAkB,KAAKN,IAAK,KAAKE,QAASG,EAAkB,KAAKF,KAAK,CACnF,CAwBA,MAAMI,aAAaF,EAA2D,CAC5E,OAAO,MAAME,aAAaF,CAAAA,CAC5B,CAyBA,MAAMG,UAAUH,EAAgF,CAC9F,OAAO,MAAMG,UAAUH,CAAAA,CACzB,CA2BA,MAAMI,YACJR,EAAoC,CAAC,EACY,CACjD,OAAO,MAAMQ,YAAYR,CAAAA,CAC3B,CAwBA,MAAMS,aAAaL,EAA2D,CAC5E,OAAO,MAAMK,aAAaL,CAAAA,CAC5B,CACF,EAWaC,GAAN,cAAgCK,EAAAA,CA/PvC,MA+PuCA,CAAAA,EAAAA,0BAC7BN,iBAgBR,YACEL,EACAE,EACAG,EACAF,EACA,CACA,MAAMH,EAAKE,EAASC,CAAAA,EACpB,KAAKE,iBAAmBA,CAC1B,CA8BA,MAAeO,YAAYX,EAAuD,CAChF,OAAO,MAAMW,YAAY,CACvB,GAAGX,EACHI,iBAAkB,KAAKA,gBACzB,CAAA,CACF,CAsBA,MAAeQ,YAAYZ,EAAwD,CAAC,EAAG,CACrF,OAAO,MAAMY,YAAY,CACvB,GAAGZ,EACHI,iBAAkB,KAAKA,gBACzB,CAAA,CACF,CAuBA,MAAeS,SAASC,EAAmB,CACzC,OAAO,MAAMD,SAAS,KAAKT,iBAAkBU,CAAAA,CAC/C,CAsBA,MAAeC,YAAYD,EAAmB,CAC5C,OAAO,MAAMC,YAAY,KAAKX,iBAAkBU,CAAAA,CAClD,CAkCAE,MAAMF,EAAqC,CACzC,OAAO,IAAIG,GACT,KAAKlB,IACL,KAAKE,QACL,KAAKG,iBACLU,EACA,KAAKZ,KAAK,CAEd,CACF,EAWae,GAAN,cAA+BC,EAAAA,CA7btC,MA6bsCA,CAAAA,EAAAA,yBAC5Bd,iBACAU,UAiBR,YACEf,EACAE,EACAG,EACAU,EACAZ,EACA,CACA,MAAMH,EAAKE,EAASC,CAAAA,EACpB,KAAKE,iBAAmBA,EACxB,KAAKU,UAAYA,CACnB,CA8BA,MAAeK,WAAWnB,EAAoE,CAC5F,OAAO,MAAMmB,WAAW,CACtB,GAAGnB,EACHI,iBAAkB,KAAKA,iBACvBU,UAAW,KAAKA,SAClB,CAAA,CACF,CAyBA,MAAeM,WAAWpB,EAAoE,CAC5F,OAAO,MAAMoB,WAAW,CACtB,GAAGpB,EACHI,iBAAkB,KAAKA,iBACvBU,UAAW,KAAKA,SAClB,CAAA,CACF,CAyBA,MAAeO,YACbrB,EAAsE,CAAC,EACvE,CACA,OAAO,MAAMqB,YAAY,CACvB,GAAGrB,EACHI,iBAAkB,KAAKA,iBACvBU,UAAW,KAAKA,SAClB,CAAA,CACF,CA4BA,MAAeQ,aACbtB,EACA,CACA,OAAO,MAAMsB,aAAa,CACxB,GAAGtB,EACHI,iBAAkB,KAAKA,iBACvBU,UAAW,KAAKA,SAClB,CAAA,CACF,CAwBA,MAAeS,cACbvB,EACA,CACA,OAAO,MAAMuB,cAAc,CACzB,GAAGvB,EACHI,iBAAkB,KAAKA,iBACvBU,UAAW,KAAKA,SAClB,CAAA,CACF,CACF,ECznBO,IAAMU,GAAN,cAA4BC,EAAAA,CAVnC,MAUmCA,CAAAA,EAAAA,sBAyBjC,YACEC,EACAC,EAAqC,CAAC,EACtCC,EACAC,EACA,CACA,MAAMH,EAAKC,EAASC,EAAOC,CAAAA,CAC7B,CAeAC,KAAKC,EAA4B,CAC/B,OAAO,IAAIC,GAAe,KAAKN,IAAK,KAAKC,QAASI,EAAI,KAAKH,KAAK,CAClE,CAeA,IAAIK,SAAgC,CAClC,OAAO,IAAIC,GAAqB,KAAKR,IAAM,UAAW,CACpDC,QAAS,KAAKA,QACdC,MAAO,KAAKA,KACd,CAAA,CACF,CAeA,IAAIO,WAAoC,CACtC,OAAO,IAAIC,GAAuB,KAAKV,IAAM,WAAY,KAAKC,QAAS,KAAKC,KAAK,CACnF,CACF,ECpFO,IAAMS,EAAyB,UACzBC,GAAiC,IACjCC,GAA6B,KA2G7BC,EAAN,cAAoCC,KAAAA,CA1H3C,MA0H2CA,CAAAA,EAAAA,8BACvC,YAAYC,EAAiB,CACzB,MAAMA,CAAAA,EACN,KAAKC,KAAO,uBAChB,CACJ,EAEaC,GAAN,KAAMA,CAjIb,MAiIaA,CAAAA,EAAAA,6CACA,CAACC,OAAOC,WAAW,EAAI,2BAEhC,YACqBC,EACAC,EACnB,MAFmBD,KAAAA,OACAC,OAAAA,CAClB,CAEHC,UAAwD,CACpD,OAAO,KAAKD,OAAM,CACtB,CAEAE,KACIC,EAGAC,EAC4B,CAC5B,OAAO,KAAKL,KAAI,EAAGG,KAAKC,EAAaC,CAAAA,CACzC,CAEAC,MACID,EAC2C,CAC3C,OAAO,KAAKL,KAAI,EAAGM,MAAMD,CAAAA,CAC7B,CAEAE,QAAQC,EAAoE,CACxE,OAAO,KAAKR,KAAI,EAAGO,QAAQC,CAAAA,CAC/B,CACJ,EAEaC,EAAN,KAAMA,CAjKb,MAiKaA,CAAAA,EAAAA,+BACQC,QAEjB,YAAYA,EAAkB,CAC1B,KAAKA,QAAUA,CACnB,CAEAC,OACIC,EACAC,EACAC,EAC2E,CAC3E,OAAOC,EACH,KAAKL,QAAQC,OAAOK,EAAmBJ,CAAAA,EAAOC,EAAMC,CAAAA,CAAAA,CAE5D,CAEAG,OACIL,EACAC,EACAC,EAC2E,CAC3E,OAAOC,EACH,KAAKL,QAAQO,OAAOD,EAAmBJ,CAAAA,EAAOC,EAAMC,CAAAA,CAAAA,CAE5D,CAEAI,KACIC,EAAS,GACTL,EAC+C,CAC/C,OAAOC,EACH,KAAKL,QAAQQ,KAAKE,GAAqBD,CAAAA,EAASL,CAAAA,CAAAA,CAExD,CAEAO,SACIP,EACmD,CACnD,OAAOC,EACH,KAAKL,QAAQY,OAAO,CAChB,GAAGR,EACHK,OAAQC,GAAqBN,GAASK,QAAU,EAAA,CACpD,CAAA,CAAA,CAER,CAEAI,KAAKX,EAAmE,CACpE,OAAOG,EAAiB,KAAKL,QAAQa,KAAKP,EAAmBJ,CAAAA,CAAAA,CAAAA,CACjE,CAEA,MAAMY,OAAOZ,EAAoD,CAC7D,IAAMa,EAAS,MAAM,KAAKf,QAAQc,OAAOR,EAAmBJ,CAAAA,CAAAA,EAC5D,OAAIa,EAAOC,MACA,CAAEC,KAAM,KAAMD,MAAOE,GAAsBH,EAAOC,KAAK,CAAE,EAE7D,CAAEC,KAAMF,EAAOE,KAAMD,MAAO,IAAK,CAC5C,CAEAG,SAASjB,EAAwC,CAC7C,IAAMkB,EAAU,KAAKpB,QAAQmB,SAASb,EAAmBJ,CAAAA,CAAAA,EACzD,OAAO,IAAIf,GACP,IAAMkB,EAAiBe,CAAAA,EACvB,IAAMf,EAAiBe,EAAQ5B,SAAQ,CAAA,CAAA,CAE/C,CAEA6B,OAAOC,EAAkE,CACrE,GAAIA,EAAMC,SAAW,EACjB,MAAM,IAAIxC,EAAsB,2CAAA,EAEpC,OAAOsB,EAAiB,KAAKL,QAAQqB,OAAOC,EAAME,IAAIlB,CAAAA,CAAAA,CAAAA,CAC1D,CAEAmB,KACIC,EACAC,EAC6C,CAC7C,OAAOtB,EACH,KAAKL,QAAQyB,KAAKnB,EAAmBoB,CAAAA,EAAWpB,EAAmBqB,CAAAA,CAAAA,CAAAA,CAE3E,CAEAC,KACIF,EACAC,EACgD,CAChD,OAAOtB,EACH,KAAKL,QAAQ4B,KAAKtB,EAAmBoB,CAAAA,EAAWpB,EAAmBqB,CAAAA,CAAAA,CAAAA,CAE3E,CAEAE,gBACI3B,EACA4B,EAAYjD,GACsC,CAClD,OAAOwB,EACH,KAAKL,QAAQ6B,gBACTvB,EAAmBJ,CAAAA,EACnB6B,GAAqBD,CAAAA,CAAAA,CAAAA,CAGjC,CAEAE,iBACIV,EACAQ,EAAYjD,GAMX,CACD,GAAIyC,EAAMC,SAAW,EACjB,MAAM,IAAIxC,EAAsB,qDAAA,EAEpC,OAAOsB,EACH,KAAKL,QAAQgC,iBACTV,EAAME,IAAIlB,CAAAA,EACVyB,GAAqBD,CAAAA,CAAAA,CAAAA,CAGjC,CAEAG,sBACI/B,EACAE,EAC+E,CAC/E,OAAOC,EACH,KAAKL,QAAQiC,sBAAsB3B,EAAmBJ,CAAAA,EAAO,CACzDgC,OAAQ9B,GAAS8B,QAAU,EAC/B,CAAA,CAAA,CAER,CAEAC,kBACIjC,EACAkC,EACAjC,EACAC,EAC+D,CAC/D,GAAI,CAACgC,EACD,MAAM,IAAIrD,EAAsB,kCAAA,EAEpC,OAAOsB,EACH,KAAKL,QAAQmC,kBAAkB7B,EAAmBJ,CAAAA,EAAOkC,EAAOjC,EAAMC,CAAAA,CAAAA,CAE9E,CACJ,EAEaiC,GAAN,cAAqCtC,CAAAA,CAvT5C,MAuT4CA,CAAAA,EAAAA,+BACvBuC,QAEjB,YAAYC,EAAiB,CAEzB,IAAMC,EADgBD,EACWE,KAAK7D,CAAAA,EACtC,MAAM4D,CAAAA,EACN,KAAKF,QAAU,IAAIvC,EAAuByC,CAAAA,CAC9C,CAMAC,KAAKC,EAA0C9D,EAAgD,CAC3F,GAAI8D,IAAa9D,EACb,MAAM,IAAIG,EACN,aAAaH,CAAAA,gCAAsD,EAG3E,OAAO,KAAK0D,OAChB,CAEAK,SAASC,EAAgBC,EAA8B,CACnD,OAAOC,GAAW,QAASF,EAAQC,CAAAA,CACvC,CAEAE,WAAWC,EAAiBH,EAA8B,CACtD,OAAOC,GAAW,SAAUE,EAASH,CAAAA,CACzC,CACJ,EAEO,SAASI,GACZC,EACAC,EAA8B,CAE9B,IAAMZ,EAAS,IAAIa,GAAc,GAAGF,EAAOG,QAAQ,GAAGC,EAAmBC,OAAO,GAAI,CAAC,EAAGJ,CAAAA,EACxF,OAAO,IAAId,GAAuBE,CAAAA,CACtC,CANgBU,EAAAA,GAAAA,uBAQhB,SAASH,GAAWU,EAA2BR,EAAiBH,EAAoB,CAChF,IAAMY,EAAQC,GAAoBV,EAAS,eAAA,EACrCW,EAAWC,GAAaf,EAAc,EAAA,EAC5C,OAAOvC,EAAmB,GAAGkD,CAAAA,IAASC,CAAAA,IAASE,CAAAA,EAAU,CAC7D,CAJSb,EAAAA,GAAAA,cAMF,SAASxC,EAAmBJ,EAAY,CAC3C,IAAM2D,EAAaD,GAAa1D,EAAM,EAAA,EACtC,GAAI,CAAC2D,EAAWC,SAAS,GAAA,EACrB,MAAM,IAAI/E,EACN,iEAAA,EAGR,GAAM,CAACyE,EAAOC,EAAO,GAAGM,CAAAA,EAAQF,EAAWG,MAAM,GAAA,EACjD,GAAKR,IAAU,SAAWA,IAAU,UAAa,CAACC,GAASM,EAAKxC,SAAW,EACvE,MAAM,IAAIxC,EACN,iEAAA,EAGR,OAAO8E,CACX,CAdgBvD,EAAAA,EAAAA,sBAgBT,SAASI,GAAqBD,EAAc,CAC/C,GAAIA,IAAW,GACX,MAAO,GAEX,IAAMoD,EAAaD,GAAanD,EAAQ,EAAA,EAClC,CAAC+C,EAAOC,CAAAA,EAASI,EAAWG,MAAM,GAAA,EACxC,GAAIR,IAAU,UAAY,CAACC,EACvB,MAAO,SAEX,GAAKD,IAAU,SAAWA,IAAU,UAAa,CAACC,EAC9C,MAAM,IAAI1E,EACN,iEAAA,EAGR,OAAO8E,CACX,CAfgBnD,EAAAA,GAAAA,wBAiBhB,SAASkD,GAAa1D,EAAc+D,EAA2B,CAC3D,GAAI,OAAO/D,GAAS,UAAYA,EAAKgE,KAAI,IAAO,GAC5C,MAAM,IAAInF,EAAsB,iDAAA,EAEpC,IAAIoF,EAAUjE,EAAKgE,KAAI,EACvB,QAASE,EAAQ,EAAGA,EAAQ,EAAGA,GAAS,EACpC,GAAI,CACA,IAAMC,EAAOC,mBAAmBH,CAAAA,EAChC,GAAIE,IAASF,EAAS,MACtBA,EAAUE,CACd,MAAQ,CACJ,MAAM,IAAItF,EAAsB,6CAAA,CACpC,CAEJ,GACIoF,EAAQI,WAAW,GAAA,GAChBJ,EAAQL,SAAS,IAAA,GACjBK,EAAQL,SAAS,IAAA,GACjBK,EAAQL,SAAS,IAAA,GAChB,CAACG,GAAsBE,EAAQK,SAAS,GAAA,EAE5C,MAAM,IAAIzF,EAAsB,kDAAA,EAEpC,IAAM8E,EAAaI,EAAqBE,EAAQM,QAAQ,OAAQ,EAAA,EAAMN,EAEtE,GADiBN,EAAWG,MAAM,GAAA,EACrBU,KAAKC,GAAWA,IAAY,IAAMA,IAAY,KAAOA,IAAY,IAAA,EAC1E,MAAM,IAAI5F,EAAsB,wCAAA,EAEpC,OAAO8E,CACX,CA7BSD,EAAAA,GAAAA,gBA+BT,SAASF,GAAoBkB,EAAeC,EAAa,CACrD,GAAI,CAACD,EACD,MAAM,IAAI7F,EAAsB,GAAG8F,CAAAA,uCAA4C,EAEnF,IAAIV,EAAUS,EACd,QAASR,EAAQ,EAAGA,EAAQ,EAAGA,GAAS,EACpC,GAAI,CACA,IAAMC,EAAOC,mBAAmBH,CAAAA,EAChC,GAAIE,IAASF,EAAS,MACtBA,EAAUE,CACd,MAAQ,CACJ,MAAM,IAAItF,EAAsB,GAAG8F,CAAAA,iCAAsC,CAC7E,CAEJ,GACIV,EAAQL,SAAS,GAAA,GACdK,EAAQL,SAAS,IAAA,GACjBK,EAAQL,SAAS,IAAA,GACjBK,IAAY,KACZA,IAAY,KAEf,MAAM,IAAIpF,EAAsB,GAAG8F,CAAAA,uCAA4C,EAEnF,OAAOV,CACX,CAxBST,EAAAA,GAAAA,uBA0BT,SAAS3B,GAAqBD,EAAiB,CAC3C,GACI,CAACgD,OAAOC,UAAUjD,CAAAA,GACfA,GAAa,GACbA,EAAYhD,GAEf,MAAM,IAAIC,EACN,sDAAsDD,EAAAA,WAAqC,EAGnG,OAAOgD,CACX,CAXSC,EAAAA,GAAAA,wBAaT,eAAe1B,EACX2E,EAA8D,CAE9D,IAAMjE,EAAS,MAAMiE,EACrB,OAAIjE,EAAOC,MACA,CAAEC,KAAM,KAAMD,MAAOE,GAAsBH,EAAOC,KAAK,CAAE,EAEhED,EAAOE,OAAS,KACT,CACHA,KAAM,KACND,MAAO,CACH9B,KAAM,4BACND,QAAS,iDACb,CACJ,EAEG,CAAEgC,KAAMF,EAAOE,KAAMD,MAAO,IAAK,CAC5C,CAjBeX,EAAAA,EAAAA,oBAmBf,SAASa,GAAsBF,EAAc,CACzC,GAAIA,aAAiBhC,MAAO,CACxB,IAAMgG,EAAShE,EAKf,MAAO,CACH9B,KAAM8F,EAAO9F,KACbD,QAAS+F,EAAO/F,QAChBgG,OAAQD,EAAOC,OACfC,WAAYF,EAAOE,WACnBC,KAAMH,EAAOG,KACbC,MAAOpE,CACX,CACJ,CACA,MAAO,CACH9B,KAAM,oBACND,QAASoG,OAAOrE,CAAAA,EAChBoE,MAAOpE,CACX,CACJ,CArBSE,EAAAA,GAAAA,yBChcF,IAAMoE,GAAN,KAAMA,CA/Bb,MA+BaA,CAAAA,EAAAA,oCAEAC,SACAC,KAEAC,QACAC,IAET,YACqBC,EACjBC,EAAkD,CAAC,EACrD,MAFmBD,OAAAA,EAKjB,KAAKH,KAAO,IAAIK,EAAWF,EAAQG,GAAiBH,EAAQI,EAAAA,EAAyB,CACjFN,QAASG,EAAQH,OACrB,CAAA,EAGA,IAAMO,EAAQF,GAAiBH,EAAQ,IAAM,KAAKH,KAAKS,eAAc,CAAA,EACrE,KAAKV,SAAWW,GAA+BP,EAAQK,CAAAA,EACvD,KAAKP,QAAUU,GAAoBR,EAAQK,CAAAA,EAC3C,KAAKN,IAAM,IAAIU,EAAUT,EAAQK,CAAAA,CACrC,CAGA,IAAIK,UAAmB,CACnB,OAAO,KAAKV,OAAOU,QACvB,CAGA,IAAIC,mBAA4B,CAC5B,OAAO,KAAKX,OAAOW,iBACvB,CACJ,EAyBO,SAASC,GACZX,EAA8B,CAE9B,OAAO,IAAIN,GAA+BkB,GAAqBZ,CAAAA,EAAU,CACrEH,QAASG,EAAQH,OACrB,CAAA,CACJ,CANgBc,EAAAA,GAAAA,wBC1BT,SAASE,GAAuBC,EAAiB,CACpD,OAAOA,EAAMC,OAAS,mBAAqBD,EAAME,OAAS,eAC9D,CAFgBH,EAAAA,GAAAA","names":["index_exports","__export","AuthModule","CLOUD_MODULE_PATHS","CLOUD_PATH_PREFIX","CloudOpenAIError","CloudStoragePathError","DEFAULT_SIGNED_URL_TTL_SECONDS","LlmModule","MAX_SIGNED_URL_TTL_SECONDS","PUBLISHABLE_KEY_HEADER","RUNTIME_STORAGE_BUCKET","WorkBuddyCloudClient","WorkBuddyCloudConfigError","WorkBuddyDatabaseModule","WorkBuddyStorageBucket","WorkBuddyStorageDownload","WorkBuddyStorageModule","anonymousTokenProvider","createMemoryStorage","createWorkBuddyCloud","shouldClearCredentials","WorkBuddyCloudConfigError","Error","message","name","PUBLISHABLE_KEY_PATTERN","normalizeHttpUrl","value","field","trim","WorkBuddyCloudConfigError","trimmed","parsed","URL","protocol","replace","normalizePublishableKey","publishableKey","test","resolveFetch","candidate","globalThis","fetch","bind","resolveRuntimeConfig","options","Object","freeze","endpoint","oauthRelayBaseUrl","PUBLISHABLE_KEY_HEADER","createCloudFetch","config","getSessionToken","input","init","headers","Headers","set","publishableKey","has","token","fetch","anonymousTokenProvider","__name","Promise","resolve","undefined","CLOUD_PATH_PREFIX","CLOUD_MODULE_PATHS","Object","freeze","auth","database","storage","llm","AUTH_PATHS","signUp","signIn","signInWithProvider","token","signOut","userMe","verification","verificationVerify","resetPassword","sudo","userPassword","parseSession","payload","receivedAt","raw","accessToken","access_token","sessionShapeError","refreshToken","refresh_token","expiresInSec","expires_in","expiresAt","user","userFromSessionPayload","isAnonymous","is_anonymous","id","sub","parseUser","uid","metadata","user_metadata","email","pickString","phone","phone_number","scope","v","undefined","normalizeHttpError","status","code","error","message","error_description","msg","kind","errorKind","cause","normalizeNetworkError","err","Error","String","reason","e","SessionManager","store","refresh","emit","isCredentialsRejected","now","inflight","signOutEpoch","lastFailure","opts","Date","peek","read","ensure","current","isExpiring","refreshToken","refreshOnce","abandon","forceRefresh","ignoreCooldown","commitSignIn","session","write","commitUserUpdate","clear","expiresAt","EXPIRY_MARGIN_MS","inCooldown","Promise","resolve","task","doRefresh","finally","f","token","at","REFRESH_FAILURE_COOLDOWN_MS","epochBefore","handleBefore","next","err","onRefreshFailed","latest","handle","STORAGE_KEY_PREFIX","createMemoryStorage","map","Map","getItem","__name","k","get","setItem","v","set","removeItem","delete","resolveStorage","candidate","probe","globalThis","localStorage","SessionStore","key","storage","publishableKey","read","raw","parsed","JSON","parse","isStoredSession","discard","write","session","stringify","clear","value","s","accessToken","refreshToken","expiresAt","user","AuthModule","baseUrl","sessions","storage","oauthRelayBaseUrl","listeners","Map","nextListenerId","config","fetch","opts","endpoint","CLOUD_MODULE_PATHS","auth","resolveStorage","SessionManager","store","SessionStore","publishableKey","refresh","__name","handle","exchangeRefreshHandle","emit","event","session","notify","isCredentialsRejected","err","isCloudError","rejectedCredentials","getAccessToken","ensure","accessToken","signInWithPassword","credentials","email","password","fail","badRequest","postForSession","AUTH_PATHS","signIn","username","signUp","verificationToken","body","verification_token","sendOtp","usage","emailRedirectTo","email_redirect_to","res","request","verification","method","error","payload","data","verificationId","verification_id","ok","isExistingUser","is_user","signInWithOtp","sent","isUser","verify","token","verifyOtp","params","verified","verificationVerify","verification_code","vt","signInWithOAuth","options","provider","redirectTo","currentPageUrl","startRelayOAuth","handleOAuthCallback","search","callbackInput","currentPageSearch","query","test","URL","URLSearchParams","oauthError","get","kind","message","status","code","state","providerId","provider_id","provider_code","provider_params","signInWithProvider","resetPasswordForEmail","target","updateUser","nonce","verifiedPayload","reset","resetPassword","new_password","signedIn","resetPasswordForOld","sudo","oldPassword","sudoToken","sudo_token","updated","userPassword","newPassword","getSession","normalizeNetworkError","refreshSession","forceRefresh","getUser","userMe","clear","parseUser","signOut","peek","onAuthStateChange","callback","id","set","safeInvoke","delete","relay","searchParams","toString","url","grant_type","refresh_token","parseSession","Date","now","path","headers","commitSignIn","init","undefined","Authorization","response","JSON","stringify","readBody","normalizeHttpError","cb","values","v","text","parse","loc","globalThis","location","origin","pathname","getRetryDelay","__name","attemptIndex","Math","min","RETRYABLE_STATUS_CODES","RETRYABLE_METHODS","PostgrestError","Error","details","hint","code","context","message","name","toJSON","sleep","ms","signal","Promise","resolve","aborted","id","setTimeout","removeEventListener","onAbort","clearTimeout","addEventListener","shouldRetry","method","status","attemptCount","retryEnabled","DEFAULT_MAX_RETRIES","RETRYABLE_METHODS","includes","RETRYABLE_STATUS_CODES","PostgrestBuilder","url","headers","schema","body","shouldThrowOnError","fetch","isMaybeSingle","shouldStripNulls","urlLengthLimit","builder","Headers","retry","throwOnError","stripNulls","get","Error","setHeader","name","value","set","enabled","then","onfulfilled","onrejected","undefined","currentAccept","_fetch","res","__name","forEach","key","String","toString","JSON","stringify","_","fetchError","code","delay","getRetryDelay","retryAfterHeader","Math","max","parseInt","text","processResponse","executeWithRetry","catch","errorDetails","hint","cause","causeMessage","message","causeCode","stack","urlLength","length","success","error","details","data","count","statusText","ok","parse","PostgrestError","countHeader","match","contentRange","split","Array","isArray","returns","overrideTypes","PostgrestTransformBuilder","PostgrestBuilder","throwOnError","select","columns","quoted","cleanedColumns","split","map","c","test","join","url","searchParams","set","headers","append","order","column","ascending","nullsFirst","foreignTable","referencedTable","key","existingOrder","get","undefined","limit","rows","range","from","to","keyOffset","keyLimit","abortSignal","signal","single","maybeSingle","isMaybeSingle","csv","geojson","explain","analyze","verbose","settings","buffers","wal","format","options","filter","Boolean","forMediatype","rollback","returns","maxAffected","PostgrestReservedCharsRegexp","RegExp","PostgrestFilterBuilder","PostgrestTransformBuilder","throwOnError","eq","column","value","url","searchParams","append","neq","gt","gte","lt","lte","like","pattern","likeAllOf","patterns","join","likeAnyOf","ilike","ilikeAllOf","ilikeAnyOf","regexMatch","regexIMatch","is","isDistinct","in","values","cleanedValues","Array","from","Set","map","s","test","notIn","contains","isArray","JSON","stringify","containedBy","rangeGt","range","rangeGte","rangeLt","rangeLte","rangeAdjacent","overlaps","textSearch","query","config","type","typePart","configPart","undefined","match","Object","entries","filter","_","forEach","not","operator","or","filters","foreignTable","referencedTable","key","PostgrestQueryBuilder","url","headers","schema","signal","fetch","urlLengthLimit","retry","Headers","cloneRequestState","URL","toString","select","columns","options","head","count","method","quoted","cleanedColumns","split","map","c","test","join","searchParams","set","append","PostgrestFilterBuilder","insert","values","defaultToNull","Array","isArray","reduce","acc","x","concat","Object","keys","length","uniqueColumns","Set","column","body","upsert","onConflict","ignoreDuplicates","undefined","update","delete","PostgrestClient","url","headers","schemaName","fetch","urlLengthLimit","retry","schema","timeout","Headers","originalFetch","globalThis","undefined","input","init","controller","AbortController","timeoutId","setTimeout","abort","existingSignal","signal","aborted","clearTimeout","abortHandler","__name","addEventListener","once","finally","removeEventListener","from","relation","trim","Error","URL","PostgrestQueryBuilder","rpc","fn","args","head","get","count","method","body","_isObject","v","Array","isArray","some","_hasObjectArg","Object","values","entries","filter","_","value","map","name","join","forEach","searchParams","append","set","PostgrestFilterBuilder","WorkBuddyDatabaseModule","client","config","fetch","PostgrestClient","endpoint","CLOUD_MODULE_PATHS","database","from","bind","rpc","url","createDatabaseModule","CloudOpenAIError","Error","error","status","requestId","retryAfterMs","init","errorObj","message","type","param","code","name","cause","undefined","Object","defineProperty","value","writable","enumerable","configurable","parseRetryAfter","headerValue","trimmed","trim","asNum","Number","isNaN","isInteger","asDate","Date","parse","diff","now","stringField","values","find","value","length","numberField","Number","isFinite","booleanField","modalitiesField","raw","input","Array","isArray","filter","item","undefined","output","capabilitiesField","entries","Object","enabled","fromEntries","pricingField","pricing","currency","inputPerMillionTokens","outputPerMillionTokens","displayText","keys","normalizeModel","id","ID","name","Name","provider","Provider","vendor","Vendor","family","Family","version","Version","description","Description","descriptionZh","DescriptionZh","descriptionEn","DescriptionEn","iconUrl","IconURL","contextWindow","ContextWindow","maxInputTokens","MaxInputTokens","maxOutputTokens","MaxOutputTokens","modalities","Modalities","capabilities","Capabilities","Enabled","isDefault","IsDefault","sortOrder","SortOrder","Pricing","ModelsAPI","baseUrl","fetch","list","signal","response","method","headers","Accept","err","Error","CloudOpenAIError","message","type","param","code","cause","ok","httpError","text","parsed","JSON","parse","rawModels","data","models","normalized","push","catch","errorObj","error","e","status","requestId","get","retryAfterMs","parseRetryAfter","SSEDecoder","event","dataParts","decode","line","l","endsWith","slice","length","ev","data","join","startsWith","colonIdx","indexOf","field","value","rest","push","flush","LineDecoder","buffer","Uint8Array","decoder","TextDecoder","chunk","newData","set","lines","start","i","lineBytes","subarray","stream","remaining","SSE_DONE","iterSSEEvents","body","signal","sseDecoder","lineDecoder","reader","getReader","aborted","onAbort","__name","cancel","catch","addEventListener","once","result","read","err","Error","name","done","finalEv","removeEventListener","releaseLock","extractSSEError","data","parsed","JSON","parse","errorObj","error","CloudOpenAIError","message","type","param","undefined","code","ChatCompletionsAPI","baseUrl","fetch","create","input","stream","createStreaming","createNonStreaming","stream_options","signal","body","response","method","headers","Accept","stringify","err","Error","name","cause","ok","httpError","text","receivedDone","threw","sseEvent","iterSSEEvents","event","SSE_DONE","chunk","errObj","aborted","LlmModule","baseUrl","models","chat","config","fetch","endpoint","CLOUD_MODULE_PATHS","llm","ModelsAPI","completions","ChatCompletionsAPI","StorageError","Error","__isStorageError","namespace","status","statusCode","message","name","toJSON","isStorageError","error","StorageApiError","code","StorageUnknownError","originalError","setHeader","headers","name","value","result","nameLower","toLowerCase","key","Object","keys","normalizeHeaders","entries","resolveFetch","__name","customFetch","args","fetch","isPlainObject","__name","value","prototype","Object","getPrototypeOf","Symbol","toStringTag","iterator","recursiveToCamel","item","Array","isArray","map","el","result","entries","forEach","key","newKey","replace","c","toUpperCase","isValidBucketName","bucketName","length","trim","includes","test","encodeStoragePath","__name","path","split","map","encodeURIComponent","join","_getErrorMessage","__name","err","e","msg","message","error_description","error","nested","JSON","stringify","handleError","reject","options","namespace","json","responseError","status","parseInt","String","Number","isFinite","then","statusCode","code","StorageApiError","catch","statusText","StorageUnknownError","_getRequestParams","method","parameters","body","params","headers","isPlainObject","contentType","key","value","Object","entries","toLowerCase","setHeader","duplex","_handleRequest","fetcher","url","Promise","resolve","result","ok","noResolveJson","get","includes","data","createFetchApi","undefined","post","put","head","remove","defaultApi","vectorsApi","BaseApiClient","url","headers","fetch","shouldThrowOnError","namespace","normalizeHeaders","resolveFetch","throwOnError","setHeader","name","value","setHeaderUtil","handleOperation","operation","data","error","isStorageError","StreamDownloadBuilder","Symbol","toStringTag","promise","downloadFn","shouldThrowOnError","then","onfulfilled","onrejected","getPromise","catch","finally","onfinally","execute","data","body","error","isStorageError","BlobDownloadBuilder","Symbol","toStringTag","promise","downloadFn","shouldThrowOnError","asStream","StreamDownloadBuilder","then","onfulfilled","onrejected","getPromise","catch","finally","onfinally","execute","data","blob","error","isStorageError","DEFAULT_SEARCH_OPTIONS","limit","offset","sortBy","column","order","DEFAULT_FILE_OPTIONS","cacheControl","contentType","upsert","StorageFileApi","BaseApiClient","bucketId","url","headers","fetch","uploadOrUpdate","method","path","fileBody","fileOptions","handleOperation","body","options","String","metadata","Blob","FormData","append","encodeMetadata","has","toBase64","ReadableStream","pipe","duplex","key","value","Object","entries","setHeader","cleanPath","_removeEmptyFolders","_path","_getFinalPath","data","put","post","id","Id","fullPath","Key","upload","uploadToSignedUrl","token","URL","searchParams","set","toString","createSignedUploadUrl","get","StorageError","signedUrl","update","move","fromPath","toPath","sourceKey","destinationKey","destinationBucket","copy","createSignedUrl","expiresIn","hasTransform","transform","keys","length","query","URLSearchParams","download","cacheNonce","queryString","encodeURI","signedURL","createSignedUrls","paths","map","datum","parameters","renderPath","applyTransformOptsToQuery","downloadFn","__name","noResolveJson","BlobDownloadBuilder","shouldThrowOnError","info","recursiveToCamel","exists","head","error","isStorageError","status","StorageApiError","StorageUnknownError","originalError","undefined","includes","getPublicUrl","publicUrl","remove","prefixes","purgeCache","encodeStoragePath","transformations","list","prefix","listV2","JSON","stringify","Buffer","from","btoa","replace","width","height","resize","format","quality","version","DEFAULT_HEADERS","version","StorageBucketApi","BaseApiClient","url","headers","fetch","opts","baseUrl","URL","useNewHostname","test","hostname","includes","replace","finalUrl","href","finalHeaders","DEFAULT_HEADERS","listBuckets","options","handleOperation","queryString","listBucketOptionsToQueryString","get","getBucket","id","createBucket","public","post","name","type","file_size_limit","fileSizeLimit","allowed_mime_types","allowedMimeTypes","updateBucket","put","emptyBucket","deleteBucket","remove","purgeBucketCache","parameters","query","URLSearchParams","transformations","set","toString","encodeStoragePath","params","limit","String","offset","search","sortColumn","sortOrder","Object","keys","length","IcebergError","__name","message","opts","buildUrl","baseUrl","path","query","url","key","value","buildAuthHeaders","auth","createFetchClient","options","fetchFn","method","body","headers","authHeaders","res","err","text","isJson","data","errBody","errorDetail","generateIdempotencyKey","ms","bytes","rand","cryptoRandom","formatUUID","b","hex","i","buf","c","namespaceToPath","namespace","namespaceToParentQuery","resolvePrefix","p","NamespaceOperations","client","prefix","hasQuery","k","response","ns","id","metadata","request","error","tableSegment","name","TableOperations","accessDelegation","metadataLocation","result","IcebergRestCatalog","getPrefix","config","serverPrefix","spec_pin_default","ICEBERG_REST_SPEC_TAG","ICEBERG_REST_SPEC_URL","StorageAnalyticsClient","BaseApiClient","url","headers","fetch","finalUrl","replace","finalHeaders","DEFAULT_HEADERS","createBucket","name","handleOperation","post","listBuckets","options","queryParams","URLSearchParams","limit","undefined","set","toString","offset","sortColumn","sortOrder","search","queryString","get","deleteBucket","bucketName","remove","from","isValidBucketName","StorageError","catalog","IcebergRestCatalog","baseUrl","catalogName","auth","type","getHeaders","__name","shouldThrowOnError","Proxy","target","prop","value","args","data","apply","error","VectorIndexApi","BaseApiClient","url","headers","fetch","finalUrl","replace","finalHeaders","DEFAULT_HEADERS","createIndex","options","handleOperation","vectorsApi","post","getIndex","vectorBucketName","indexName","listIndexes","deleteIndex","VectorDataApi","BaseApiClient","url","headers","fetch","finalUrl","replace","finalHeaders","DEFAULT_HEADERS","putVectors","options","vectors","length","Error","handleOperation","vectorsApi","post","getVectors","listVectors","segmentCount","undefined","segmentIndex","queryVectors","deleteVectors","keys","VectorBucketApi","BaseApiClient","url","headers","fetch","finalUrl","replace","finalHeaders","DEFAULT_HEADERS","createBucket","vectorBucketName","handleOperation","vectorsApi","post","getBucket","listBuckets","options","deleteBucket","StorageVectorsClient","VectorBucketApi","url","options","headers","fetch","from","vectorBucketName","VectorBucketScope","createBucket","getBucket","listBuckets","deleteBucket","VectorIndexApi","createIndex","listIndexes","getIndex","indexName","deleteIndex","index","VectorIndexScope","VectorDataApi","putVectors","getVectors","listVectors","queryVectors","deleteVectors","StorageClient","StorageBucketApi","url","headers","fetch","opts","from","id","StorageFileApi","vectors","StorageVectorsClient","analytics","StorageAnalyticsClient","RUNTIME_STORAGE_BUCKET","DEFAULT_SIGNED_URL_TTL_SECONDS","MAX_SIGNED_URL_TTL_SECONDS","CloudStoragePathError","Error","message","name","WorkBuddyStorageDownload","Symbol","toStringTag","blob","stream","asStream","then","onfulfilled","onrejected","catch","finally","onfinally","WorkBuddyStorageBucket","fileApi","upload","path","body","options","mapStorageResult","validateObjectPath","update","list","prefix","validateObjectPrefix","listPage","listV2","info","exists","result","error","data","normalizeStorageError","download","builder","remove","paths","length","map","copy","fromPath","toPath","move","createSignedUrl","expiresIn","validateSignedURLTTL","createSignedUrls","createSignedUploadUrl","upsert","uploadToSignedUrl","token","WorkBuddyStorageModule","runtime","client","runtimeApi","from","bucketID","userPath","userID","relativePath","scopedPath","sharedPath","ownerID","createStorageModule","config","fetch","StorageClient","endpoint","CLOUD_MODULE_PATHS","storage","scope","owner","validatePathSegment","relative","validatePath","normalized","includes","rest","split","allowTrailingSlash","trim","decoded","index","next","decodeURIComponent","startsWith","endsWith","replace","some","segment","value","label","Number","isInteger","source","status","statusCode","code","cause","String","WorkBuddyCloudClient","database","auth","storage","llm","config","options","AuthModule","createCloudFetch","anonymousTokenProvider","fetch","getAccessToken","createDatabaseModule","createStorageModule","LlmModule","endpoint","oauthRelayBaseUrl","createWorkBuddyCloud","resolveRuntimeConfig","shouldClearCredentials","error","kind","code"]}
|