@cloudbase/js-sdk 3.6.2 → 3.6.3-beta.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","mappings":"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","sources":["webpack://@cloudbase/js-sdk/./empty-module.js","webpack://@cloudbase/js-sdk/webpack/bootstrap","webpack://@cloudbase/js-sdk/webpack/runtime/define property getters","webpack://@cloudbase/js-sdk/webpack/runtime/hasOwnProperty shorthand","webpack://@cloudbase/js-sdk/errors.ts/","webpack://@cloudbase/js-sdk/encoding.ts/","webpack://@cloudbase/js-sdk/http.ts/","webpack://@cloudbase/js-sdk/download-builder.ts/","webpack://@cloudbase/js-sdk/storage-file-api-neo.ts/","webpack://@cloudbase/js-sdk/validation.ts/","webpack://@cloudbase/js-sdk/storage-bucket-api-neo.ts/","webpack://@cloudbase/js-sdk/common.ts/","webpack://@cloudbase/js-sdk/external module \"@cloudbase/adapter-interface\"","webpack://@cloudbase/js-sdk/util.ts/","webpack://@cloudbase/js-sdk/index.ts/","webpack://@cloudbase/js-sdk/web.ts/","webpack://@cloudbase/js-sdk/cache.ts/","webpack://@cloudbase/js-sdk/events.ts/","webpack://@cloudbase/js-sdk/langEvent.ts/","webpack://@cloudbase/js-sdk/decorators.ts/","webpack://@cloudbase/js-sdk/external module \"jwt-decode\"","webpack://@cloudbase/js-sdk/cloudbase-storage.ts/","webpack://@cloudbase/js-sdk/storage-file-api-classic.ts/"],"sourcesContent":["// 空模块占位文件,用于 webpack 解析纯类型包(@cloudbase/types)的子路径引用\n// 这些引用只有 TypeScript 类型,编译后会被擦除,运行时不需要任何内容\nmodule.exports = {}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","export class StorageError extends Error {\n protected __isStorageError = true\n\n constructor(message: string) {\n super(message)\n this.name = 'StorageError'\n }\n}\n\nexport function isStorageError(error: unknown): error is StorageError {\n return typeof error === 'object' && error !== null && '__isStorageError' in error\n}\n\nexport class StorageApiError extends StorageError {\n status: number\n statusCode: string\n\n constructor(message: string, status: number, statusCode: string) {\n super(message)\n this.name = 'StorageApiError'\n this.status = status\n this.statusCode = statusCode\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n statusCode: this.statusCode,\n }\n }\n}\n\nexport class StorageUnknownError extends StorageError {\n originalError: unknown\n\n constructor(message: string, originalError: unknown) {\n super(message)\n this.name = 'StorageUnknownError'\n this.originalError = originalError\n }\n}\n","type BufferLike = {\n byteLength(data: string): number\n from(data: string): { toString(encoding: 'base64'): string }\n}\n\ntype GlobalWithBuffer = typeof globalThis & {\n Buffer?: BufferLike\n}\n\nfunction getBuffer(): BufferLike | undefined {\n return (globalThis as GlobalWithBuffer).Buffer\n}\n\nexport function getStringByteLength(data: string): number | undefined {\n return getBuffer()?.byteLength(data)\n}\n\nexport function toBase64(data: string): string {\n const buffer = getBuffer()\n if (buffer) {\n return buffer.from(data).toString('base64')\n }\n return btoa(data)\n}\n\n/**\n * 对对象名按 `/` 分段做 URL 编码(保留路径分隔符)。\n *\n * 用于把 Bucket 内相对路径安全地拼进 URL path,避免空格、`#`、`?`、`%`、中文等字符\n * 破坏或截断 URL(query 段已单独编码,此处仅处理 path 段)。仅对每段做 `encodeURIComponent`,\n * 不编码分隔符 `/`,与 supabase-js 的处理方式一致。\n *\n * @param cleanName 已由 `cleanPath` 规整过的相对路径(无首尾斜杠、无重复斜杠)。\n */\nexport function encodeObjectName(cleanName: string): string {\n return cleanName\n .split('/')\n .map(segment => encodeURIComponent(segment))\n .join('/')\n}\n","import { StorageApiError, StorageError, isStorageError } from './supabase/errors'\nimport { Result, FetchParameters } from './types'\n\n/**\n * 客户端运行上下文:`{ config, request }`。\n */\nexport interface Context {\n config: any\n request: any\n}\n\n/** 网关相对前缀:GATEWAY base 已含 `/v1`,原始 fetch 用 origin,需补 `/v1/storages`。 */\nconst STORAGE_API_PREFIX = '/v1/storages'\n\nfunction buildQueryString(query?: Record<string, any>): string {\n if (!query) return ''\n const parts: string[] = []\n Object.keys(query).forEach((key) => {\n const value = query[key]\n if (value === undefined || value === null) return\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n })\n return parts.join('&')\n}\n\n/**\n * 统一执行操作并返回 `{ data, error }`;`throwOnError` 开启时失败抛异常,成功仍返回 `{ data, error: null }`。\n */\nexport async function handleOperation<T>(fn: () => Promise<T>, shouldThrowOnError: boolean): Promise<Result<T>> {\n try {\n const data = await fn()\n return { data, error: null }\n } catch (error: any) {\n if (shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return { data: null, error }\n }\n return { data: null, error: new StorageError(error?.message || String(error)) }\n }\n}\n\n/**\n * Storage HTTP 请求封装。\n *\n * - JSON 端点:`request.fetch`(自动注入 `Authorization`,`shouldThrowOnError: false` 以便手动解析错误码)。\n * - Blob 下载:`reqClass.get`(避免 Node 适配器 `fetch` 强制 `res.json()` 破坏二进制流)。\n */\nexport class Http {\n constructor(public readonly ctx: Context) {}\n\n private get request() {\n return this.ctx.request\n }\n\n /** 网关 origin(如 `https://{env}.api.tcloudbasegateway.com`,不含 `/v1`)。 */\n gatewayOrigin(): string {\n return this.request.getBaseEndPoint('GATEWAY')\n }\n\n /** 拼接完整 API URL。 */\n buildUrl(path: string, query?: Record<string, any>): string {\n let url = `${this.gatewayOrigin()}${STORAGE_API_PREFIX}${path}`\n const qs = buildQueryString(query)\n if (qs) {\n url += (url.includes('?') ? '&' : '?') + qs\n }\n return url\n }\n\n /** 把后端返回的相对 `signedURL` 拼成完整 URL。 */\n toFullUrl(maybeRelative: string): string {\n if (!maybeRelative) return maybeRelative\n if (/^https?:\\/\\//.test(maybeRelative) || maybeRelative.startsWith('//')) {\n return maybeRelative\n }\n return `${this.gatewayOrigin()}${STORAGE_API_PREFIX}${maybeRelative.startsWith('/') ? '' : '/'}${maybeRelative}`\n }\n\n /** JSON / 表单 / 二进制请求,返回解析后的 body;非 2xx 抛 StorageApiError。 */\n async send<T = any>(opts: {\n method: string\n path: string\n /** JSON body(会被 stringify)。与 rawBody 互斥。 */\n json?: any\n /** 原始 body(FormData / Blob / 二进制 / 字符串),用于上传。 */\n rawBody?: any\n headers?: Record<string, string>\n query?: Record<string, any>\n /** 是否携带登录态,默认 true。签名上传 / 公开下载传 false。 */\n withCredentials?: boolean\n /** 请求取消信号,透传给底层 fetch。 */\n signal?: AbortSignal\n /** fetch 缓存策略,透传给底层 fetch。 */\n cache?: FetchParameters['cache']\n }): Promise<T> {\n const url = this.buildUrl(opts.path, opts.query)\n const method = opts.method.toUpperCase()\n const isBodyless = ['GET', 'HEAD'].includes(method)\n\n const headers: Record<string, string> = { ...(opts.headers || {}) }\n let body: any\n if (!isBodyless) {\n if (opts.rawBody !== undefined) {\n body = opts.rawBody\n } else if (opts.json !== undefined) {\n headers['Content-Type'] = headers['Content-Type'] || 'application/json'\n body = JSON.stringify(opts.json)\n }\n }\n\n const res = await this.request.fetch({\n url,\n method,\n headers,\n ...(body !== undefined ? { body } : {}),\n withCredentials: opts.withCredentials !== false,\n shouldThrowOnError: false,\n ...(opts.signal ? { signal: opts.signal } : {}),\n ...(opts.cache ? { cache: opts.cache } : {}),\n })\n\n return this.unwrap<T>(res, url)\n }\n\n /**\n * 下载,返回原始 `Response`。走 `request.fetch({ stream: true })` 让适配器透出未消费的原生 `Response`。\n *\n * 上层按终态决定如何消费——`response.blob()` 得 `Blob`,或 `response.body` 得 `ReadableStream`。\n *\n * @remarks 依赖底层适配器 `fetch` 透出 `response`(web / Node 适配器均已支持)。\n */\n async download(opts: {\n path: string\n headers?: Record<string, string>\n query?: Record<string, any>\n withCredentials?: boolean\n /** 请求取消信号,透传给底层 fetch。 */\n signal?: AbortSignal\n /** fetch 缓存策略,透传给底层 fetch。 */\n cache?: FetchParameters['cache']\n }): Promise<{ response: Response; status: number; header: any }> {\n const url = this.buildUrl(opts.path, opts.query)\n\n const res = await this.request.fetch({\n url,\n method: 'GET',\n headers: { ...(opts.headers || {}) },\n stream: true,\n withCredentials: opts.withCredentials !== false,\n shouldThrowOnError: false,\n ...(opts.signal ? { signal: opts.signal } : {}),\n ...(opts.cache ? { cache: opts.cache } : {}),\n })\n\n // signal 被中断时,底层可能 resolve 出空响应;这里显式抛出中断错误,避免误判为成功。\n if (opts.signal?.aborted) {\n throw new StorageApiError('The download was aborted', 0, 'STORAGE_PG_ABORTED')\n }\n\n const status = Number(res?.statusCode ?? 200)\n if (status === 304) {\n throw new StorageApiError('Not Modified', status, 'STORAGE_PG_NOT_MODIFIED')\n }\n if (status >= 400) {\n throw new StorageApiError(`Download failed with status ${status}`, status, 'STORAGE_PG_REQUEST_FAIL')\n }\n\n const response: Response = res?.response\n if (!response) {\n throw new StorageApiError('Underlying adapter did not expose the raw Response', status, 'STORAGE_PG_NO_RESPONSE')\n }\n return { response, status, header: res?.header }\n }\n\n private async unwrap<T>(res: any, url: string): Promise<T> {\n const status = Number(res?.statusCode ?? res?.status ?? 200)\n let body = res?.data\n try {\n body = await body\n } catch (e) {\n body = undefined\n }\n\n if (status >= 200 && status < 300) {\n return body as T\n }\n\n // 兼容两类错误体:ErrorResponse { code, message, requestId } 与 StreamErrorResponse { statusCode, error, message }\n const code = body?.code || body?.error || 'STORAGE_PG_REQUEST_FAIL'\n const message = body?.message || `Storage request failed with status ${status}: ${url}`\n throw new StorageApiError(message, status, code)\n }\n}\n","import { StorageError, StorageApiError, isStorageError } from './supabase/errors'\nimport { encodeObjectName } from './encoding'\nimport { Http } from './http'\nimport { Result, DownloadOptions, FetchParameters } from './types'\n\n/** 把任意错误规整为 `StorageError`。 */\nfunction toStorageError(error: any): StorageError {\n return isStorageError(error) ? error : new StorageError(error?.message || String(error))\n}\n\n/** 下载构建器内部共享上下文。 */\nexport interface DownloadContext {\n http: Http\n bucketId: string\n cleanName: string\n options?: DownloadOptions\n parameters?: FetchParameters\n /** 调用方实例级自定义请求头,会并入下载请求(条件请求头优先级更高)。 */\n headers?: Record<string, string>\n shouldThrowOnError: boolean\n}\n\n/** 由下载选项构建条件请求头与 query。 */\nfunction buildHeadersAndQuery(options?: DownloadOptions): {\n headers: Record<string, string>\n query: Record<string, any>\n} {\n const query: Record<string, any> = {}\n if (options?.download !== undefined) {\n query.download = options.download === true ? '' : options.download\n }\n if (options?.cacheNonce !== undefined) {\n query.cacheNonce = String(options.cacheNonce)\n }\n return { headers: {}, query }\n}\n\n/**\n * 流式下载构建器(两阶段下载的「流」终态)。\n *\n * 实现 `PromiseLike`,可直接 `await`,resolve 为 `Result<ReadableStream>`。\n * 由 `DownloadBuilder.asStream()` 创建,直接返回原生 `Response.body`。\n */\nexport class StreamDownloadBuilder implements PromiseLike<Result<ReadableStream<Uint8Array>>> {\n constructor(private ctx: DownloadContext) {}\n\n then<TResult1 = Result<ReadableStream<Uint8Array>>, TResult2 = never>(\n onfulfilled?: ((value: Result<ReadableStream<Uint8Array>>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n\n private async execute(): Promise<Result<ReadableStream<Uint8Array>>> {\n try {\n const { headers, query } = buildHeadersAndQuery(this.ctx.options)\n const { response } = await this.ctx.http.download({\n path: `/object/${this.ctx.bucketId}/${encodeObjectName(this.ctx.cleanName)}`,\n headers: { ...this.ctx.headers, ...headers },\n query,\n signal: this.ctx.parameters?.signal,\n cache: this.ctx.parameters?.cache,\n })\n if (!response.body) {\n throw new StorageApiError('Response body is empty', response.status, 'STORAGE_PG_EMPTY_BODY')\n }\n return { data: response.body, error: null }\n } catch (error: any) {\n if (this.ctx.shouldThrowOnError) throw error\n return { data: null, error: toStorageError(error) }\n }\n }\n}\n\n/**\n * 下载构建器(thenable)。\n *\n * 默认终态为 `Blob`:直接 `await bucket.download(path)` 即得 `Result<Blob>`,\n * 调用方式与返回普通 Promise 完全一致(惰性执行,`await` / `.then()` 时才真正发请求)。\n *\n * 链式 `.asStream()` 切换为流式终态,返回 `StreamDownloadBuilder`(resolve 为 `Result<ReadableStream>`)。\n * 此设计对齐 Supabase `download().asStream()` 的使用效果,但实现为自有的轻量 thenable,不依赖其内部类。\n *\n * @example\n * ```ts\n * // 默认:Blob\n * const { data: blob } = await bucket.download('a.png')\n * // 流式:ReadableStream(适合 Node 大文件,避免整体读入内存)\n * const { data: stream } = await bucket.download('big.zip').asStream()\n * ```\n */\nexport class DownloadBuilder implements PromiseLike<Result<Blob>> {\n constructor(private ctx: DownloadContext) {}\n\n /** 切换为流式下载终态,返回 `StreamDownloadBuilder`。 */\n asStream(): StreamDownloadBuilder {\n return new StreamDownloadBuilder(this.ctx)\n }\n\n then<TResult1 = Result<Blob>, TResult2 = never>(\n onfulfilled?: ((value: Result<Blob>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n\n private async execute(): Promise<Result<Blob>> {\n try {\n const { headers, query } = buildHeadersAndQuery(this.ctx.options)\n const { response } = await this.ctx.http.download({\n path: `/object/${this.ctx.bucketId}/${encodeObjectName(this.ctx.cleanName)}`,\n headers: { ...this.ctx.headers, ...headers },\n query,\n signal: this.ctx.parameters?.signal,\n cache: this.ctx.parameters?.cache,\n })\n // 直接复用原生 Response.blob()(与 Supabase 一致),content-type 由 Response 自动保留。\n return { data: await response.blob(), error: null }\n } catch (error: any) {\n if (this.ctx.shouldThrowOnError) throw error\n return { data: null, error: toStorageError(error) }\n }\n }\n}\n","import { StorageError } from './supabase/errors'\nimport { toBase64, encodeObjectName } from './encoding'\nimport { Http, handleOperation } from './http'\nimport { DownloadBuilder } from './download-builder'\nimport {\n FileBody,\n Result,\n UploadOptions,\n UploadResult,\n DownloadOptions,\n ListOptions,\n ListObjectsResponse,\n ObjectInfo,\n FullObject,\n DestinationOptions,\n SignedUrlOptions,\n SignedUrlResult,\n SignedUrlsResultItem,\n CreateSignedUploadUrlResult,\n PublicUrlOptions,\n FetchParameters,\n} from './types'\n\nconst DEFAULT_UPLOAD_OPTIONS: UploadOptions = {\n cacheControl: '3600',\n contentType: 'text/plain;charset=UTF-8',\n upsert: false,\n}\n\n/** 批量删除单次上限。 */\nconst REMOVE_BATCH_LIMIT = 100\n/** 批量签名单次上限。 */\nconst SIGN_BATCH_LIMIT = 500\n\n/** 从 FormData 中提取出的、服务端支持的元信息字段(值为原始字符串)。 */\ninterface UploadFormFields {\n cacheControl?: string\n contentType?: string\n metadata?: string\n}\n\n/**\n * 单 Bucket 对象操作客户端。\n *\n * 通过 `app.storage.from(bucketId)` 获取。所有 `objectName` 均为 Bucket 内相对路径,\n * 走 `/v1/storages/object/{bucketId}/{name}` 通道,权限由 `storage.objects` / `storage.buckets`\n * 的 RLS 策略判定。\n */\nexport class StorageFileApi {\n public readonly bucketId: string\n private http: Http\n private shouldThrowOnError: boolean\n /** 实例级自定义请求头,对该实例后续所有请求生效(见 setHeader)。对齐 Supabase 的 `this.headers`。 */\n private headers: Record<string, string> = {}\n\n constructor(http: Http, bucketId: string, shouldThrowOnError = false) {\n this.http = http\n this.bucketId = bucketId\n this.shouldThrowOnError = shouldThrowOnError\n }\n\n /** 启用错误抛出模式。开启后请求失败会抛异常;请求成功仍返回 `{ data, error: null }`。 */\n throwOnError(): this {\n this.shouldThrowOnError = true\n return this\n }\n\n /**\n * 设置自定义请求头(链式)。\n *\n * 对齐 Supabase `BaseApiClient.setHeader`:设置后对**当前实例**后续的所有请求生效。\n * 单次请求内部使用的功能性头(如上传的 `Content-Type` / `x-upsert`)优先级更高,会覆盖此处同名头。\n *\n * 每个 `from(bucketId)` 返回独立实例(持有自定义头的独立副本),互不影响;返回 `this` 以支持链式调用。\n *\n * @param name 请求头名称,非空字符串。\n * @param value 请求头值。\n * @throws 当 name 为空,或 name/value 含 CR/LF(防止请求头注入)时抛 `StorageError`。\n */\n setHeader(name: string, value: string): this {\n if (typeof name !== 'string' || name.trim() === '') {\n throw new StorageError('setHeader requires a non-empty header name')\n }\n if (/[\\r\\n]/.test(name) || (typeof value === 'string' && /[\\r\\n]/.test(value))) {\n throw new StorageError('setHeader does not allow CR/LF characters in header name or value')\n }\n // 写时复制:仅改动当前实例自己的头表,对齐 Supabase 语义。\n this.headers = { ...this.headers, [name]: String(value) }\n return this\n }\n\n /**\n * 直接上传对象,默认不覆盖同名对象。\n *\n * 需要当前用户已登录(携带 Authorization header),适合**服务端或可信客户端**直接上传。\n * 权限由 `storage.objects` 表的 RLS `INSERT` / `UPDATE` 策略判定。\n *\n * 上传行为:\n * - `fileOptions.upsert` 默认 `false`:目标路径已有对象时,上传失败。\n * - `fileOptions.upsert` 设为 `true`:目标路径已有对象时,覆盖写入。\n * - 成功时返回 `{ id, path, fullPath }`,其中 `fullPath` 为 `bucketId/objectName`。\n *\n * 如需让**不受信客户端**(如浏览器前端)上传文件,应改用 `createSignedUploadUrl` + `uploadToSignedUrl` 组合,\n * 服务端先生成临时签名 token,客户端凭 token 上传,无需暴露登录凭证。\n *\n * @param path Bucket 内相对路径。\n * @param fileBody 文件内容。\n * @param fileOptions 上传选项,如 `contentType`、`cacheControl`、`upsert`、`metadata`。\n * @see createSignedUploadUrl uploadToSignedUrl\n */\n async upload(path: string, fileBody: FileBody, fileOptions?: UploadOptions): Promise<Result<UploadResult>> {\n return this.uploadOrUpdate('POST', path, fileBody, fileOptions)\n }\n\n /**\n * 覆盖更新对象。\n *\n * 与 `upload` 共享同一底层,区别:\n * - 使用 `PUT` 方法(语义为覆盖),不追加 `x-upsert` 头。\n * - 目标路径不存在时也会创建(upsert 行为,与后端实现有关)。\n * - 成功时返回 `{ id, path, fullPath }`。\n *\n * @param path Bucket 内相对路径。\n * @param fileBody 文件内容。\n * @param fileOptions 上传选项,如 `contentType`、`cacheControl`、`metadata`。\n */\n async update(path: string, fileBody: FileBody, fileOptions?: UploadOptions): Promise<Result<UploadResult>> {\n return this.uploadOrUpdate('PUT', path, fileBody, fileOptions)\n }\n\n /**\n * 下载对象。返回**下载构建器**(thenable),默认 `await` 得到 `Blob`。\n *\n * 需要登录态,权限由 `storage.objects` 的 RLS `SELECT` 策略判定。\n *\n * 两种终态(对齐 Supabase `download().asStream()` 的使用效果):\n * - 默认:`await bucket.download(path)` → `Result<Blob>`。\n * - 流式:`await bucket.download(path).asStream()` → `Result<ReadableStream>`,适合 Node 大文件等\n * 不希望整体读入内存的场景。\n *\n * 两者统一走原生 `fetch` 的 `Response`:流式终态返回 `Response.body`,Blob 终态调 `Response.blob()`。\n *\n * 下载行为:\n * - 惰性执行:请求在 `await` / `.then()` 时才真正发出。\n * - 返回的 `Blob` 不会自动触发浏览器下载或渲染,需配合 `URL.createObjectURL` 手动处理。\n * - 支持 `parameters.signal`(AbortSignal)取消进行中的下载。\n *\n * @param path Bucket 内相对路径。\n * @param options 下载选项,支持 `download`(触发浏览器下载)、`cacheNonce`(绕过 CDN 缓存)。\n * @param parameters 请求控制参数,支持 `signal` / `cache`。\n * @returns `DownloadBuilder`:可 `await` 得 `Result<Blob>`,或 `.asStream()` 后得 `Result<ReadableStream>`。\n */\n download(\n path: string,\n options?: DownloadOptions,\n parameters?: FetchParameters,\n ): DownloadBuilder {\n return new DownloadBuilder({\n http: this.http,\n bucketId: this.bucketId,\n cleanName: this.cleanPath(path),\n options,\n parameters,\n headers: this.headers,\n shouldThrowOnError: this.shouldThrowOnError,\n })\n }\n\n /**\n * 获取对象列表(游标分页)。\n *\n * 列出 Bucket 下指定前缀的对象和文件夹。采用**游标分页**,与 Supabase 的 `listV2` 对应。\n *\n * - 首次查询不传 `cursor`,后续用上一页的 `nextCursor` 传入继续翻页。\n * - 返回 `{ folders, objects, hasNext, nextCursor }`(区别于 Supabase `list` 的 offset 分页 `FileObject[]`)。\n * - `path` 不传或为空时列出 Bucket 根目录。\n * - `options.withDelimiter` 为 `true` 时,以 `/` 为分隔符将文件夹和文件分开。\n * - `options.sortBy` 支持按 `name`、`created_at`、`updated_at` 排序。\n *\n * @param path 路径前缀,不传表示 Bucket 根目录。\n * @param options 列表选项,支持 `limit`、`cursor`、`withDelimiter`、`sortBy`。\n * @param parameters 请求控制参数,支持 `signal` / `cache`。\n * @remarks 本方法对应 Supabase 的 `listV2`(游标分页),而非 `list`(offset 分页)。\n */\n async list(path?: string, options?: ListOptions, parameters?: FetchParameters): Promise<Result<ListObjectsResponse>> {\n return handleOperation(async () => {\n const body: Record<string, any> = { prefix: path || '' }\n if (options?.limit !== undefined) body.limit = options.limit\n if (options?.cursor !== undefined) body.cursor = options.cursor\n if (options?.withDelimiter !== undefined) body.with_delimiter = options.withDelimiter\n if (options?.sortBy !== undefined) body.sortBy = options.sortBy\n\n return this.send<ListObjectsResponse>({\n method: 'POST',\n path: `/object/list/${this.bucketId}`,\n json: body,\n signal: parameters?.signal,\n cache: parameters?.cache,\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 删除一个或多个对象。\n *\n * 权限由 `storage.objects` 的 RLS `DELETE` 策略判定。\n *\n * - 后端单次最多删除 100 个对象,超出时 SDK 自动分批发送。\n * - 返回所有被成功删除的对象信息(`FullObject[]`)。\n *\n * @param paths Bucket 内相对路径数组。\n */\n async remove(paths: string[]): Promise<Result<FullObject[]>> {\n return handleOperation(async () => {\n const names = paths.map(n => this.cleanPath(n))\n const result: FullObject[] = []\n for (let i = 0; i < names.length; i += REMOVE_BATCH_LIMIT) {\n const batch = names.slice(i, i + REMOVE_BATCH_LIMIT)\n const deleted = await this.send<FullObject[]>({\n method: 'DELETE',\n path: `/object/${this.bucketId}`,\n json: { prefixes: batch },\n })\n if (Array.isArray(deleted)) result.push(...deleted)\n }\n return result\n }, this.shouldThrowOnError)\n }\n\n /**\n * 复制对象,支持跨 Bucket。\n *\n * 权限由 `storage.objects` 的 RLS 策略判定:读取源需要 `SELECT` 权限,写入目标需要 `INSERT` 权限。\n *\n * 复制行为:\n * - `options.destinationBucket` 不传时在同一 Bucket 内复制;传入时跨 Bucket 复制。\n * - `options.upsert` 为 `true` 时,目标路径已有对象则覆盖;否则复制失败。\n * - `options.copyMetadata` 默认为 `undefined`(由服务端决定是否复制原 metadata)。\n * 设为 `false` 并传 `options.metadata` 时,用新 metadata 替换原对象的 metadata。\n * - 返回目标对象的完整路径 `bucketId/objectName`。\n *\n * @param fromPath 源对象 Bucket 内相对路径。\n * @param toPath 目标对象相对路径。\n * @param options 目标 Bucket、覆盖、元数据复制等选项。\n */\n async copy(fromPath: string, toPath: string, options?: DestinationOptions): Promise<Result<{ path: string }>> {\n return handleOperation(async () => {\n const headers = this.buildCopyMoveHeaders(options)\n const data = await this.send<{ Key: string }>({\n method: 'POST',\n path: '/object/copy',\n json: {\n bucketId: this.bucketId,\n sourceKey: this.cleanPath(fromPath),\n destinationKey: this.cleanPath(toPath),\n destinationBucket: options?.destinationBucket,\n copyMetadata: options?.copyMetadata,\n metadata: options?.metadata,\n },\n headers,\n })\n return { path: data.Key }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 移动对象,支持跨 Bucket;源对象会被删除。\n *\n * 语义为\"复制到目标 → 删除源\",非原地重命名。跨 Bucket 时源 Bucket 的对象会被删除。\n * 权限由 `storage.objects` 的 RLS 策略判定:读取源需要 `SELECT`,写入目标需要 `INSERT`,删除源需要 `DELETE`。\n *\n * 移动行为:\n * - `options.destinationBucket` 不传时在同一 Bucket 内移动。\n * - 成功时返回 `{ message: 'Successfully moved' }`。\n *\n * @param fromPath 源对象 Bucket 内相对路径。\n * @param toPath 目标对象相对路径。\n * @param options 目标 Bucket 等选项。\n */\n async move(fromPath: string, toPath: string, options?: DestinationOptions): Promise<Result<{ message: string }>> {\n return handleOperation(async () => {\n const data = await this.send<{ message: string }>({\n method: 'POST',\n path: '/object/move',\n json: {\n bucketId: this.bucketId,\n sourceKey: this.cleanPath(fromPath),\n destinationKey: this.cleanPath(toPath),\n destinationBucket: options?.destinationBucket,\n },\n })\n return { message: data.message || 'Successfully moved' }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 获取对象元信息。\n *\n * 返回对象在 `storage.objects` 表中的记录信息,包括 `bucketId`、`version`、`etag`、\n * `contentType`、`cacheControl`、`metadata`、`lastModified`、`createdAt` 等。\n *\n * - 对象不存在时返回 `{ data: null, error: StorageError }`。\n *\n * @param path Bucket 内相对路径。\n */\n async info(path: string): Promise<Result<ObjectInfo>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const data = await this.send<any>({\n method: 'GET',\n path: `/object/info/${this.bucketId}/${this.encodePath(cleanName)}`,\n })\n return {\n id: data.id,\n name: data.name,\n version: data.version,\n bucketId: data.bucket_id,\n size: data.size,\n contentType: data.content_type,\n cacheControl: data.cache_control,\n etag: data.etag,\n metadata: data.metadata,\n lastModified: data.last_modified,\n createdAt: data.created_at,\n }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 判断对象是否存在。\n *\n * 底层调用 `info` 端点:\n * - 后端返回 HTTP 200 → 存在(返回 `true`)。\n * - 后端返回 HTTP 400 或 404 → 不存在(返回 `false`)。\n * - 其他异常(如 500)→ 返回 `{ data: null, error }`。\n *\n * @param path Bucket 内相对路径。\n */\n async exists(path: string): Promise<Result<boolean>> {\n try {\n const cleanName = this.cleanPath(path)\n await this.send<any>({\n method: 'GET',\n path: `/object/info/${this.bucketId}/${this.encodePath(cleanName)}`,\n })\n return { data: true, error: null }\n } catch (error: any) {\n const status = (error as any)?.status\n if (status !== undefined && [400, 404].includes(Number(status))) {\n return { data: false, error: null }\n }\n if (this.shouldThrowOnError) throw error\n return { data: null, error: error instanceof StorageError ? error : new StorageError(error?.message || String(error)) }\n }\n }\n\n /**\n * 生成单个签名下载 URL。\n *\n * 需要登录态,权限由 `storage.objects` 的 RLS `SELECT` 策略判定。\n *\n * 签名 URL 行为:\n * - `expiresIn` 以秒为单位,过期后 URL 不可用。\n * - 返回的 `fullSignedURL` 是服务端已拼接好的完整 URL,客户端可直接使用(无需再拼 HOST)。\n * - `options.download` 为 `true` 时在 URL 后追加 `?download`,浏览器访问时自动触发下载;\n * 传字符串时指定下载文件名(`?download=<filename>`)。\n * - 不支持图片 `transform` 转换选项。\n *\n * @param path Bucket 内相对路径。\n * @param expiresIn 过期时间,单位为秒。\n * @param options 签名下载 URL 选项;当前仅支持 `download`,不支持图片 `transform`。\n */\n async createSignedUrl(\n path: string,\n expiresIn: number,\n options?: SignedUrlOptions,\n ): Promise<Result<SignedUrlResult>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const data = await this.send<{ signedURL?: string; fullSignedURL?: string }>({\n method: 'POST',\n path: `/object/sign/${this.bucketId}/${this.encodePath(cleanName)}`,\n json: { expiresIn },\n })\n const base = data.fullSignedURL || this.http.toFullUrl(data.signedURL || '')\n return { fullSignedURL: this.appendUrlOptions(base, options) }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 为多个对象批量生成签名下载 URL。\n *\n * 需要登录态,权限由 `storage.objects` 的 RLS `SELECT` 策略判定。\n *\n * 批量签名行为:\n * - 后端单次最多 500 个,超出时 SDK 自动分批发送。\n * - 返回数组中每个元素包含 `path`(请求路径)、`fullSignedURL`(完整签名 URL,生成失败时为 `null`)、`error`。\n * - 部分路径生成失败不会影响其他路径,失败的项 `fullSignedURL` 为 `null`,`error` 为错误信息。\n * - `options.download` 为 `true` 时在 URL 后追加 `?download` 参数。\n *\n * @param paths Bucket 内相对路径数组。\n * @param expiresIn 过期时间,单位为秒。\n * @param options 签名下载 URL 选项;当前仅支持 `download`,不支持图片 `transform`。\n */\n async createSignedUrls(\n paths: string[],\n expiresIn: number,\n options?: SignedUrlOptions,\n ): Promise<Result<SignedUrlsResultItem[]>> {\n return handleOperation(async () => {\n const names = paths.map(n => this.cleanPath(n))\n const result: SignedUrlsResultItem[] = []\n for (let i = 0; i < names.length; i += SIGN_BATCH_LIMIT) {\n const batch = names.slice(i, i + SIGN_BATCH_LIMIT)\n const data = await this.send<Array<{ path: string; signedURL?: string | null; fullSignedURL?: string | null; error?: string | null }>>({\n method: 'POST',\n path: `/object/sign/${this.bucketId}`,\n json: { expiresIn, paths: batch },\n })\n data.forEach((item) => {\n const base = item.fullSignedURL || (item.signedURL ? this.http.toFullUrl(item.signedURL) : null)\n result.push({\n path: item.path,\n fullSignedURL: base ? this.appendUrlOptions(base, options) : null,\n error: item.error ?? null,\n })\n })\n }\n return result\n }, this.shouldThrowOnError)\n }\n\n /**\n * 两阶段上传(第一阶段):生成签名上传 URL,需登录态。\n *\n * 服务端基于调用者身份 + RLS 策略判断是否有 `INSERT` 权限,生成临时签名 URL 和 token。\n * 适合的场景:服务端鉴定用户权限后,将 `token` 下发给**不受信客户端**(如浏览器前端),\n * 让客户端用 `uploadToSignedUrl` 直接上传文件,无需暴露登录凭证。\n *\n * 签名上传 URL 行为:\n * - 返回的 `fullSignedURL` 是服务端已拼接好的完整上传 URL,客户端可直接使用。\n * - 返回的 `token` 是临时凭证,与 `uploadToSignedUrl` 配合使用。\n * - `options.upsert` 为 `true` 时,目标路径已有对象时允许覆盖。\n * - 与 `upload` 的区别:\n * - `upload`:一步完成,需登录态,适合服务端/可信客户端直接上传。\n * - `createSignedUploadUrl` + `uploadToSignedUrl`:**两阶段上传**——第一阶段需登录态生成 token,\n * 第二阶段无需登录态(凭 token 鉴权),适合浏览器直传、第三方上报等场景。\n *\n * @param path Bucket 内相对路径。\n * @param options 签名上传选项,`upsert=true` 时允许覆盖。\n * @see upload uploadToSignedUrl\n */\n async createSignedUploadUrl(\n path: string,\n options?: { upsert?: boolean },\n ): Promise<Result<CreateSignedUploadUrlResult>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const headers: Record<string, string> = {}\n if (options?.upsert) headers['x-upsert'] = 'true'\n\n const data = await this.send<{ url?: string; fullURL?: string; token: string }>({\n method: 'POST',\n path: `/object/upload/sign/${this.bucketId}/${this.encodePath(cleanName)}`,\n headers,\n })\n const fullSignedURL = data.fullURL || this.http.toFullUrl(data.url || '')\n return { fullSignedURL, path: cleanName, token: data.token }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 两阶段上传(第二阶段):使用签名上传 token 上传对象,无需登录态。\n *\n * 配合 `createSignedUploadUrl` 完成两阶段上传:\n * 1. 服务端调用 `createSignedUploadUrl(path)` 生成 token(需登录态)\n * 2. 客户端调用本方法,凭 token 上传文件(无需登录态)\n *\n * 上传行为:\n * - 请求**不携带**登录态(`withCredentials: false`),仅凭 `token` 鉴权。\n * - `path` 和 `token` 必须与之前调用 `createSignedUploadUrl` 的返回值对应。\n * - 与 `upload` 的区别:\n * - `upload`:需登录态,适合服务端/可信客户端。\n * - `uploadToSignedUrl`:无需登录态,仅凭 `token` 鉴权,适合浏览器直传。\n *\n * @param path Bucket 内相对路径,需与 `createSignedUploadUrl` 的 `path` 一致。\n * @param token `createSignedUploadUrl()` 返回的 `token`。\n * @param fileBody 文件内容。\n * @param fileOptions 上传选项。\n * @see createSignedUploadUrl upload\n */\n async uploadToSignedUrl(\n path: string,\n token: string,\n fileBody: FileBody,\n fileOptions?: UploadOptions,\n ): Promise<Result<{ path: string; fullPath: string }>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const { body, headers } = this.buildUploadBody(fileBody, fileOptions)\n\n const data = await this.send<{ Key: string }>({\n method: 'PUT',\n path: `/object/upload/sign/${this.bucketId}/${this.encodePath(cleanName)}`,\n query: { token },\n rawBody: body,\n headers,\n withCredentials: false,\n })\n return { path: cleanName, fullPath: data.Key }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 获取 public bucket 对象的公开访问 URL(同步,不发请求,不返回 error)。\n *\n * **同步方法**,不发起网络请求,不会抛异常。\n *\n * 公开 URL 行为:\n * - URL 由客户端直接拼接 `{gateway}/v1/storages/object/public/{bucketId}/{path}` 得到。\n * - 拼接过程不会被 RLS 策略拦截,但 URL 是否可访问取决于 Bucket 的 `public` 属性。\n * - `options.download` 为 `true` 时在 URL 后追加 `?download`。\n * - 不支持图片 `transform` 选项。\n *\n * @param path Bucket 内相对路径。\n * @param options 公开 URL 选项;当前仅支持 `download`,不支持图片 `transform`。\n */\n getPublicUrl(path: string, options?: PublicUrlOptions): { data: { publicUrl: string } } {\n const cleanName = this.cleanPath(path)\n const base = this.http.buildUrl(`/object/public/${this.bucketId}/${this.encodePath(cleanName)}`)\n return { data: { publicUrl: this.appendUrlOptions(base, options) } }\n }\n\n // ---------- 内部工具 ----------\n\n /**\n * 统一发请求:把实例级自定义头并入每个请求。\n * 单次请求显式传入的功能性头(如 `Content-Type` / `x-upsert`)优先级更高,会覆盖同名自定义头。\n */\n private send<T = any>(opts: Parameters<Http['send']>[0]): Promise<T> {\n return this.http.send<T>({ ...opts, headers: { ...this.headers, ...(opts.headers || {}) } })\n }\n\n private async uploadOrUpdate(\n method: 'POST' | 'PUT',\n path: string,\n fileBody: FileBody,\n fileOptions?: UploadOptions,\n ): Promise<Result<UploadResult>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const { body, headers } = this.buildUploadBody(fileBody, fileOptions)\n\n if (method === 'POST') {\n // x-upsert 不放进 FormData:它是请求级行为开关而非对象元信息,服务端需在解析 body 前读到;\n // 且 binary 直传路径没有表单字段可放,统一走 header 以保持两条上传路径一致。\n headers['x-upsert'] = String(Boolean(fileOptions?.upsert))\n }\n\n const data = await this.send<{ Id: string; Key: string }>({\n method,\n path: `/object/${this.bucketId}/${this.encodePath(cleanName)}`,\n rawBody: body,\n headers,\n })\n\n return { id: data.Id, path: cleanName, fullPath: data.Key }\n }, this.shouldThrowOnError)\n }\n\n private cleanPath(path: string): string {\n const clean = path.replace(/^\\/+|\\/+$/g, '').replace(/\\/+/g, '/')\n // 客户端纵深防御:拒绝 `..` 段,避免 URL 规范化后逃出 bucket 路径前缀(路径穿越)。\n // encodeURIComponent('..') === '..',无法靠编码消除,必须显式拦截。\n if (clean.split('/').some(seg => seg === '..')) {\n throw new StorageError('invalid path: \"..\" segment is not allowed')\n }\n return clean\n }\n\n /** 把 `cleanPath` 后的对象名编码为可安全拼进 URL path 的形式(保留 `/` 分隔符)。 */\n private encodePath(cleanName: string): string {\n return encodeObjectName(cleanName)\n }\n\n private buildUploadBody(\n fileBody: FileBody,\n fileOptions?: UploadOptions,\n ): { body: any; headers: Record<string, string> } {\n const headers: Record<string, string> = { ...(fileOptions?.headers || {}) }\n let body: any = fileBody\n\n // 与 supabase-js 一致的按类型分流策略:\n // - Blob / File → multipart/form-data:cacheControl / contentType / metadata 走表单字段,\n // Content-Type 为 CORS 安全值,不触发自定义头预检(浏览器最常见的文件上传场景)。\n // - FormData → 取其中的文件内容,并允许携带服务端支持的元信息字段;同样走 multipart 表单。\n // - 其它(string / ArrayBuffer / 二进制视图 / 流等)→ Binary 直传:元信息走请求头。\n // 该路径会发送 cache-control / x-metadata 等自定义头,浏览器下需要网关在\n // Access-Control-Allow-Headers 放行,否则触发 CORS 预检失败。\n const isFormData = typeof FormData !== 'undefined' && fileBody instanceof FormData\n const isBlob = typeof Blob !== 'undefined' && fileBody instanceof Blob\n if (isBlob || isFormData) {\n let file: Blob\n let fields: UploadFormFields = {}\n if (isFormData) {\n const extracted = this.extractFromFormData(fileBody as FormData)\n file = extracted.file\n fields = extracted.fields\n } else {\n file = fileBody as Blob\n }\n\n // 元信息取值优先级:fileOptions(显式传入)> FormData 携带 > 默认值。\n const cacheControl = fileOptions?.cacheControl ?? fields.cacheControl ?? DEFAULT_UPLOAD_OPTIONS.cacheControl\n const contentType = fileOptions?.contentType ?? fields.contentType\n const metadata = fileOptions?.metadata !== undefined ? JSON.stringify(fileOptions.metadata) : fields.metadata\n\n const form = new FormData()\n if (cacheControl !== undefined) form.append('cacheControl', String(cacheControl))\n // contentType 不落默认值:Blob / File 自带 MIME 类型,强制写默认值反而会覆盖真实类型。\n if (contentType !== undefined) form.append('contentType', contentType)\n if (metadata !== undefined) form.append('metadata', metadata)\n // file 放在最后:服务端边解析 multipart 边落库,要求文件部分排在所有元信息字段之后,\n // 先拿到 cacheControl / metadata 才能写库。\n form.append('', file)\n body = form\n } else {\n body = fileBody\n const cacheControl = fileOptions?.cacheControl ?? DEFAULT_UPLOAD_OPTIONS.cacheControl\n const contentType = fileOptions?.contentType ?? DEFAULT_UPLOAD_OPTIONS.contentType\n headers['cache-control'] = `max-age=${cacheControl}`\n if (contentType) headers['content-type'] = contentType\n if (fileOptions?.metadata) headers['x-metadata'] = this.toBase64(JSON.stringify(fileOptions.metadata))\n }\n\n return { body, headers }\n }\n\n /**\n * 从用户传入的上传 FormData 中提取文件内容,以及服务端支持的元信息字段。\n *\n * - 文件部分:单个对象上传只对应一个文件,缺少或多于一个均抛错。\n * - 元信息字段:服务端仅支持 `cacheControl` / `contentType` / `metadata`,这几个会被取出(其值仍可被\n * `fileOptions` 覆盖,覆盖逻辑在调用方);其余不支持的字段对上传无意义,宽松忽略并打印一次告警。\n *\n * @param source 用户传入的原始 FormData。\n */\n private extractFromFormData(source: FormData): { file: Blob; fields: UploadFormFields } {\n const fields: UploadFormFields = {}\n let file: Blob | undefined\n let fileCount = 0\n const ignoredFields: string[] = []\n source.forEach((value, key) => {\n // File 是 Blob 的子类,二进制内容统一按文件部分处理。\n if (typeof Blob !== 'undefined' && value instanceof Blob) {\n file = value\n fileCount += 1\n return\n }\n if (key === 'cacheControl' || key === 'contentType' || key === 'metadata') {\n fields[key] = String(value)\n return\n }\n ignoredFields.push(key)\n })\n\n if (ignoredFields.length > 0) {\n console.warn(`Ignored unsupported FormData field(s): [${ignoredFields.join(', ')}]. Only file, cacheControl, contentType and metadata are supported`)\n }\n\n if (fileCount === 0 || !file) {\n throw new StorageError('FormData must contain a file')\n }\n if (fileCount > 1) {\n throw new StorageError('FormData must contain exactly one file')\n }\n return { file, fields }\n }\n\n private buildCopyMoveHeaders(options?: DestinationOptions): Record<string, string> {\n const headers: Record<string, string> = {}\n if (options?.upsert) headers['x-upsert'] = 'true'\n if (options?.copyMetadata === false && options?.metadata) {\n headers['x-metadata'] = this.toBase64(JSON.stringify(options.metadata))\n }\n return headers\n }\n\n private appendUrlOptions(url: string, options?: SignedUrlOptions | PublicUrlOptions): string {\n const params: string[] = []\n if (options?.download !== undefined) {\n const value = options.download === true ? '' : String(options.download)\n params.push(`download=${encodeURIComponent(value)}`)\n }\n if (options?.cacheNonce !== undefined) {\n params.push(`cacheNonce=${encodeURIComponent(String(options.cacheNonce))}`)\n }\n\n if (params.length === 0) return url\n const separator = url.includes('?') ? '&' : '?'\n return `${url}${separator}${params.join('&')}`\n }\n\n private toBase64(data: string): string {\n return toBase64(data)\n }\n}\n","import { StorageError } from './supabase/errors'\n\n/**\n * `bucketId` 采用「黑名单」式校验:只拦截**一定会破坏 URL path 语义**或\n * **明显不安全**的字符,其余字符一律放行,给服务端命名规则保留灵活性。\n *\n * `bucketId` 会被**未编码**地直接拼进 `/bucket/{bucketId}`、\n * `/object/{bucketId}/{name}` 等路径,因此以下字符必须禁止:\n * - 控制字符与空白:`\\x00-\\x20`(含空格、Tab、换行)与 DEL(`\\x7F`);\n * - URL 路径分隔/结构字符:`/`、`\\`、`?`、`#`;\n * - 百分号 `%`:避免与 percent-encoding 产生二义(双重解码风险)。\n *\n * 其余字符(字母、数字、`.`、`_`、`-`、以及大多数可见符号、Unicode 等)\n * 是否合法交由服务端判定,客户端不做过度限制。\n */\nconst FORBIDDEN_BUCKET_ID_PATTERN = /[\\x00-\\x20\\x7f/\\\\?#%]/\n\n/** `bucketId` 最大长度(仅作防御性上界,避免异常超长输入)。 */\nconst BUCKET_ID_MAX_LENGTH = 256\n\n/** 判断 `bucketId` 是否为合法格式(不抛错版本)。 */\nexport function isValidBucketId(bucketId: unknown): bucketId is string {\n return (\n typeof bucketId === 'string'\n && bucketId.length > 0\n && bucketId.length <= BUCKET_ID_MAX_LENGTH\n && !FORBIDDEN_BUCKET_ID_PATTERN.test(bucketId)\n )\n}\n\n/**\n * 校验 `bucketId` 格式,非法时抛出 `StorageError`。\n *\n * 在 `handleOperation` 包裹内调用时,异常会被转成 `{ data: null, error }` 返回;\n * 在 `from()` 等同步入口调用时则直接抛出。\n *\n * @param bucketId 待校验的 Bucket ID。\n * @param caller 调用方方法名,用于错误信息定位(如 `from`、`createBucket`)。\n */\nexport function assertValidBucketId(bucketId: unknown, caller: string): asserts bucketId is string {\n if (typeof bucketId !== 'string' || bucketId.length === 0) {\n throw new StorageError(`[storage.${caller}] bucketId is required`)\n }\n if (bucketId.length > BUCKET_ID_MAX_LENGTH) {\n throw new StorageError(`[storage.${caller}] invalid bucketId: length must be 1-${BUCKET_ID_MAX_LENGTH}`)\n }\n const forbidden = FORBIDDEN_BUCKET_ID_PATTERN.exec(bucketId)\n if (forbidden) {\n const message = `[storage.${caller}] invalid bucketId \"${bucketId}\": `\n + `contains forbidden character ${JSON.stringify(forbidden[0])}; `\n + 'must not contain whitespace, control chars, \"/\", \"\\\\\", \"?\", \"#\" or \"%\"'\n throw new StorageError(message)\n }\n}\n","import { Context, Http, handleOperation } from './http'\nimport { assertValidBucketId } from './validation'\nimport {\n Result,\n Bucket,\n ListBucketOptions,\n CreateBucketOptions,\n UpdateBucketOptions,\n MessageResponse,\n} from './types'\n\n/**\n * Bucket 管理基类。提供 Supabase 同名 Bucket 管理 API:\n * `listBuckets` / `getBucket` / `createBucket` / `updateBucket` / `deleteBucket`。\n * `emptyBucket` 暂不开放(见 §12.2);也不提供 `headBucket`、Bucket CORS、Bucket ACL 等 COS/S3 风格 Bucket API。\n *\n * 持有 `http`(由运行上下文 `{ config, request }` 构造)与 `throwOnError` 状态,\n * 子类(`app.storage` 命名空间)在此之上提供 `from()` 分流。\n */\nexport class StorageBucketApi {\n protected http: Http\n protected shouldThrowOnError: boolean\n\n constructor(context?: Context, shouldThrowOnError = false) {\n this.http = new Http(context as Context)\n this.shouldThrowOnError = shouldThrowOnError\n }\n\n throwOnError(): this {\n this.shouldThrowOnError = true\n return this\n }\n\n /**\n * 获取 Bucket 列表(偏移分页 + 扁平排序)。\n *\n * @param options 查询参数:`limit`、`offset`、`sortColumn`、`sortOrder`、`search`。\n */\n async listBuckets(options?: ListBucketOptions): Promise<Result<Bucket[]>> {\n return handleOperation(() => {\n const query: Record<string, any> = {}\n if (options?.limit !== undefined) query.limit = options.limit\n if (options?.offset !== undefined) query.offset = options.offset\n if (options?.sortColumn) query.sortColumn = options.sortColumn\n if (options?.sortOrder) query.sortOrder = options.sortOrder\n if (options?.search) query.search = options.search\n\n return this.http.send<Bucket[]>({\n method: 'GET',\n path: '/bucket/',\n query,\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 获取指定 Bucket 详情。\n *\n * @param bucketId Bucket ID。\n */\n async getBucket(bucketId: string): Promise<Result<Bucket>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'getBucket')\n return this.http.send<Bucket>({\n method: 'GET',\n path: `/bucket/${bucketId}`,\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 创建 Bucket。\n *\n * @param bucketId Bucket ID,同时作为后端 `id` 与 `name` 传入。\n * @param options 创建参数:`public`、`fileSizeLimit`、`allowedMimeTypes`、`type`。\n * @remarks `public` 默认 `false`。\n */\n async createBucket(bucketId: string, options?: CreateBucketOptions): Promise<Result<{ name: string }>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'createBucket')\n return this.http.send<{ name: string }>({\n method: 'POST',\n path: '/bucket/',\n json: {\n id: bucketId,\n name: bucketId,\n public: options?.public ?? false,\n type: options?.type,\n file_size_limit: options?.fileSizeLimit,\n allowed_mime_types: options?.allowedMimeTypes,\n },\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 更新 Bucket 配置。\n *\n * @param bucketId Bucket ID。\n * @param options 更新参数:`public`、`fileSizeLimit`、`allowedMimeTypes`。不支持更新 `type`。\n */\n async updateBucket(bucketId: string, options: UpdateBucketOptions): Promise<Result<MessageResponse>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'updateBucket')\n return this.http.send<MessageResponse>({\n method: 'PUT',\n path: `/bucket/${bucketId}`,\n json: {\n public: options.public,\n file_size_limit: options.fileSizeLimit,\n allowed_mime_types: options.allowedMimeTypes,\n },\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 删除空 Bucket。\n *\n * @param bucketId Bucket ID。\n * @remarks Bucket 非空时后端会返回错误。\n */\n async deleteBucket(bucketId: string): Promise<Result<MessageResponse>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'deleteBucket')\n return this.http.send<MessageResponse>({\n method: 'DELETE',\n path: `/bucket/${bucketId}`,\n })\n }, this.shouldThrowOnError)\n }\n}\n","let sdkName = '@cloudbase/js-sdk'\nexport function setSdkName(name: string) {\n sdkName = name\n}\nexport function getSdkName() {\n return sdkName\n}\n\nlet PROTOCOL = 'https:'\n\nexport function setProtocol(protocol: 'http:' | 'https:') {\n PROTOCOL = protocol\n}\n\nexport function getProtocol() {\n return PROTOCOL\n}\n// 是否为开发模式\nexport const IS_DEBUG_MODE = typeof process === 'undefined' || typeof process.env === 'undefined' ? false : process.env.NODE_ENV === 'development'\n// 问答社区链接\nexport const COMMUNITY_SITE_URL = 'https://support.qq.com/products/148793'\n","var x = y => { var x = {}; __webpack_require__.d(x, y); return x; }\nvar y = x => () => x\nconst __WEBPACK_NAMESPACE_OBJECT__ = x({ [\"AbstractSDKRequest\"]: () => __WEBPACK_EXTERNAL_MODULE__cloudbase_adapter_interface_74717cc6__.AbstractSDKRequest, [\"AbstractStorage\"]: () => __WEBPACK_EXTERNAL_MODULE__cloudbase_adapter_interface_74717cc6__.AbstractStorage });","import { KV } from '@cloudbase/types'\nimport { getSdkName } from '../constants'\n\nexport function isArray(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object Array]'\n}\nexport function isString(val: any): boolean {\n return typeof val === 'string'\n}\nexport function isUndefined(val: any): boolean {\n return typeof val === 'undefined'\n}\nexport function isPalinObject(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object Object]'\n}\nexport function isNull(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object Null]'\n}\nexport function isInstanceOf(instance: any, construct: any): boolean {\n return instance instanceof construct\n}\nexport function isFormData(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object FormData]'\n}\nexport function genSeqId(): string {\n return Math.random().toString(16)\n .slice(2)\n}\nexport function generateRequestId() {\n let d = new Date().getTime()\n let d2 = (Date?.now && Date.now() * 1000) || 0\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n let r = Math.random() * 16\n if (d > 0) {\n r = (d + r) % 16 | 0\n d = Math.floor(d / 16)\n } else {\n r = (d2 + r) % 16 | 0\n d2 = Math.floor(d2 / 16)\n }\n return (c === 'x' ? r : (r & 0x7) | 0x8).toString(16)\n })\n}\nexport function formatUrl(PROTOCOL: string, url: string, query: KV<any> = {}): string {\n const urlHasQuery = /\\?/.test(url)\n let queryString = ''\n Object.keys(query).forEach((key) => {\n if (queryString === '') {\n !urlHasQuery && (url += '?')\n } else {\n queryString += '&'\n }\n queryString += `${key}=${encodeURIComponent(query[key])}`\n })\n url += queryString\n if (/^http(s)?:\\/\\//.test(url)) {\n return url\n }\n return `${PROTOCOL}${url}`\n}\n\nexport function toQueryString(query: KV<any> = {}) {\n const queryString = []\n Object.keys(query).forEach((key) => {\n queryString.push(`${key}=${encodeURIComponent(query[key])}`)\n })\n return queryString.join('&')\n}\n\nexport function getQuery(name: string, url?: string) {\n if (typeof window === 'undefined') {\n return false\n }\n // 参数:变量名,url为空则表从当前页面的url中取\n const u = url || decodeURIComponent(window.location.search)\n const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`)\n const r = u.substr(u.indexOf('?') + 1).match(reg)\n return r !== null && r !== undefined ? r[2] : ''\n}\n\nexport const getHash = function (name: string) {\n if (typeof window === 'undefined') {\n return ''\n }\n const matches = window.location.hash.match(new RegExp(`[#?&/]${name}=([^&#]*)`))\n return matches ? matches[1] : ''\n}\n\nexport function removeParam(key: string, sourceURL: string) {\n let rtn = sourceURL.split('?')[0]\n let param\n let params = []\n const queryString = sourceURL.indexOf('?') !== -1 ? sourceURL.split('?')[1] : ''\n if (queryString !== '') {\n params = queryString.split('&')\n for (let i = params.length - 1; i >= 0; i -= 1) {\n /* eslint-disable-next-line */\n param = params[i].split('=')[0]\n if (param === key) {\n params.splice(i, 1)\n }\n }\n rtn = `${rtn}?${params.join('&')}`\n }\n return rtn\n}\n\nexport function createPromiseCallback() {\n let cb: any = {}\n if (!Promise) {\n cb = () => {}\n cb.promise = {}\n\n const throwPromiseNotDefined = () => {\n throw new Error('Your Node runtime does support ES6 Promises. '\n + 'Set \"global.Promise\" to your preferred implementation of promises.',)\n }\n\n Object.defineProperty(cb.promise, 'then', { get: throwPromiseNotDefined })\n Object.defineProperty(cb.promise, 'catch', { get: throwPromiseNotDefined })\n return cb\n }\n\n const promise = new Promise((resolve, reject) => {\n cb = (err, data) => {\n if (err) return reject(err)\n return resolve(data)\n }\n })\n cb.promise = promise\n return cb\n}\n\nexport function execCallback(fn: Function | null | undefined, err: any, data = null) {\n if (fn && typeof fn === 'function') {\n return fn(err, data)\n }\n if (err) {\n throw err\n }\n return data\n}\n\nexport function printWarn(error: string, msg: string) {\n console.warn(`[${getSdkName()}][${error}]:${msg}`)\n}\n\nexport function printError(error: string, msg: string) {\n console.error({\n code: error,\n msg: `[${getSdkName()}][${error}]:${msg}`,\n })\n}\nexport function printInfo(error: string, msg: string) {\n console.log(`[${getSdkName()}][${error}]:${msg}`)\n}\nexport function throwError(error: string, msg: string) {\n throw new Error(JSON.stringify({\n code: error,\n msg: `[${getSdkName()}][${error}]:${msg}`,\n }),)\n}\n\ninterface IPrintGroupLogOptions {\n title: string\n subtitle: string | object\n content: {\n type: 'info' | 'warn' | 'error'\n body: string | Error\n }[]\n printTrace?: boolean\n collapsed?: boolean\n}\nexport function printGroupLog(options: IPrintGroupLogOptions) {\n const { title, subtitle = '', content = [], printTrace = false, collapsed = false } = options\n if (collapsed) {\n (console.groupCollapsed || console.error)(title, subtitle)\n } else {\n (console.group || console.error)(title, subtitle)\n }\n for (const tip of content) {\n const { type, body } = tip\n switch (type) {\n case 'info':\n console.log(body)\n break\n case 'warn':\n console.warn(body)\n break\n case 'error':\n console.error(body)\n break\n }\n }\n if (printTrace) {\n (console.trace || console.log)('stack trace:')\n }\n console.groupEnd?.()\n}\n\nexport const sleep = (ms = 0) => new Promise(r => setTimeout(r, ms))\n\nexport function transformPhone(phoneNumber: string) {\n return `+86${phoneNumber}`\n}\n\nexport const parseQueryString = (queryString) => {\n queryString = queryString.replace(/^\\?/, '')\n const params = {}\n const pairs = queryString.split('&')\n\n pairs.forEach((item) => {\n let [key, value] = item.split('=')\n key = decodeURIComponent(key)\n value = decodeURIComponent(value)\n if (key) {\n if (params[key]) {\n if (Array.isArray(params[key])) {\n params[key].push(value)\n } else {\n params[key] = [params[key], value]\n }\n } else {\n params[key] = value\n }\n }\n })\n\n return params\n}\n\n// 解析URL参数\nexport function parseCaptcha(url) {\n let queryObj: any = {}\n const matched = url.match(/^(data:.*?)(\\?[^#\\s]*)?$/)\n if (matched) {\n // eslint-disable-next-line prefer-destructuring\n url = matched[1]\n const search = matched[2]\n if (search) {\n queryObj = parseQueryString(search)\n }\n }\n const { token, ...restQueryObj } = queryObj\n if (/^data:/.test(url) && !token) {\n return {\n error: 'invalid_argument',\n error_description: `invalid captcha data: ${url}`,\n }\n }\n if (!token) {\n return {\n error: 'unimplemented',\n error_description: 'need to impl captcha data',\n }\n }\n // 解析url得到的参数\n return {\n state: restQueryObj.state,\n token, // 验证码token\n captchaData: url, // 验证码base64图片\n }\n}\n","export * from './common'\nexport * from './errors'\n\nexport const OATUH_LOGINTYPE = 'constants'\n","import {\n SDKAdapterInterface,\n AbstractSDKRequest,\n IRequestOptions,\n ResponseObject,\n IUploadRequestOptions,\n IRequestConfig,\n IRequestMethod,\n IFetchOptions,\n} from '@cloudbase/adapter-interface'\nimport { isFormData, formatUrl, toQueryString } from '../../libs/util'\nimport { getProtocol } from '../../constants/common'\n\n/**\n * @class WebRequest\n */\nclass WebRequest extends AbstractSDKRequest {\n // 默认不限超时\n private readonly timeout: number\n // 超时提示文案\n private readonly timeoutMsg: string\n // 超时受限请求类型,默认所有请求均受限\n private readonly restrictedMethods: Array<IRequestMethod>\n constructor(config: IRequestConfig) {\n super()\n const { timeout, timeoutMsg, restrictedMethods } = config\n this.timeout = timeout || 0\n this.timeoutMsg = timeoutMsg || '请求超时'\n this.restrictedMethods = restrictedMethods || ['get', 'post', 'upload', 'download']\n }\n public get(options: IRequestOptions): Promise<ResponseObject> {\n return this.request(\n {\n ...options,\n method: 'get',\n },\n this.restrictedMethods.includes('get'),\n )\n }\n public post(options: IRequestOptions): Promise<ResponseObject> {\n return this.request(\n {\n ...options,\n method: 'post',\n },\n this.restrictedMethods.includes('post'),\n )\n }\n public put(options: IRequestOptions): Promise<ResponseObject> {\n return this.request({\n ...options,\n method: 'put',\n })\n }\n public upload(options: IUploadRequestOptions): Promise<ResponseObject> {\n const { data, file, name, method, headers = {} } = options\n const reqMethod = { post: 'post', put: 'put' }[method?.toLowerCase()] || 'put'\n // 上传方式为post时,需转换为FormData\n const formData = new FormData()\n if (reqMethod === 'post') {\n Object.keys(data).forEach((key) => {\n formData.append(key, data[key])\n })\n formData.append('key', name)\n formData.append('file', file)\n return this.request(\n {\n ...options,\n data: formData,\n method: reqMethod,\n },\n this.restrictedMethods.includes('upload'),\n )\n }\n return this.request(\n {\n ...options,\n method: 'put',\n headers,\n body: file,\n },\n this.restrictedMethods.includes('upload'),\n )\n }\n public async download(options: IRequestOptions): Promise<any> {\n try {\n const { data } = await this.get({\n ...options,\n headers: {}, // 下载资源请求不经过service,header清空\n responseType: 'blob',\n })\n const url = window.URL.createObjectURL(new Blob([data]))\n const fileName = decodeURIComponent(new URL(options.url).pathname.split('/').pop() || '')\n const link = document.createElement('a')\n\n link.href = url\n link.setAttribute('download', fileName)\n link.style.display = 'none'\n\n document.body.appendChild(link)\n link.click()\n // 回收内存\n window.URL.revokeObjectURL(url)\n document.body.removeChild(link)\n } catch (e) {}\n return new Promise((resolve) => {\n resolve({\n statusCode: 200,\n tempFilePath: options.url,\n })\n })\n }\n async fetch(options: IFetchOptions & { shouldThrowOnError?: boolean }): Promise<ResponseObject> {\n const abortController = new AbortController()\n const { url, enableAbort = false, stream = false, signal, timeout: _timeout, shouldThrowOnError = true } = options\n\n const timeout = _timeout ?? this.timeout\n\n // FIXME(内存泄漏): { once: true } 只在 abort 事件【触发后】才解绑监听器。\n // 如果请求正常完成、从未 abort,该监听器会一直残留在外部 signal 上。\n // 当调用方复用同一长生命周期 signal 反复发请求时,监听器仍会持续累积。\n // 根治方式:在请求结束(finally)时 removeEventListener 主动解绑,\n // 而不能仅依赖 { once: true }。此处暂仅记录,不改动逻辑。\n if (signal) {\n if (signal.aborted) abortController.abort()\n signal.addEventListener('abort', () => abortController.abort())\n }\n\n let timer = null\n if (enableAbort && timeout) {\n timer = setTimeout(() => {\n console.warn(this.timeoutMsg)\n abortController.abort(new Error(this.timeoutMsg))\n }, timeout)\n }\n\n const res = await fetch(url, {\n ...options,\n signal: abortController.signal,\n })\n .then(async (response) => {\n clearTimeout(timer)\n if (shouldThrowOnError) {\n // 404 等等也会进 resolve,所以要再通过 ok 判断\n return response.ok ? response : Promise.reject(await response.json())\n }\n return response\n })\n .catch((x) => {\n clearTimeout(timer)\n // 传输级失败(网络中断、CORS 预检被拒、请求被 abort 等)时 fetch 会 reject,\n // 此时没有可解析的 Response。无论 shouldThrowOnError 取值都必须把真实错误抛出,\n // 否则 res 会变成 undefined,下方读取 res.headers 会抛出令人误解的\n // \"Cannot read properties of undefined (reading 'headers')\",掩盖真正的错误原因。\n return Promise.reject(x)\n })\n\n return {\n // eslint-disable-next-line no-nested-ternary\n data: stream ? res.body : res.headers.get('content-type')?.includes('application/json') ? res.json() : res.text(),\n statusCode: res.status,\n header: res.headers,\n // 透出原始 Response,便于上层按需 .blob() / .arrayBuffer() / 读取 body 流,避免二次包装。\n response: res,\n }\n }\n /**\n * @param {IRequestOptions} options\n * @param {boolean} enableAbort 是否超时中断请求\n */\n protected request(options: IRequestOptions, enableAbort = false): Promise<ResponseObject> {\n const method = String(options.method).toLowerCase() || 'get'\n return new Promise((resolve) => {\n const { url, headers = {}, data, responseType, withCredentials, body, onUploadProgress } = options\n const realUrl = formatUrl(getProtocol(), url, method === 'get' ? data : {})\n const ajax = new XMLHttpRequest()\n ajax.open(method, realUrl)\n responseType && (ajax.responseType = responseType)\n // 支持通过 AbortSignal 取消请求:已 abort 立即取消;否则用 { once: true }\n // 监听,触发后自动解绑,避免复用同一 AbortController 多次请求时累积监听器。\n //\n // FIXME(内存泄漏): { once: true } 只在 abort 事件【触发后】才解绑监听器。\n // 如果请求正常完成、从未 abort,该监听器会一直残留在外部 signal 上。\n // 当调用方复用同一长生命周期 signal 反复发请求时,监听器仍会持续累积。\n // 根治方式:在请求结束(readyState===4 / onloadend)时 removeEventListener\n // 主动解绑,而不能仅依赖 { once: true }。此处暂仅记录,不改动逻辑。\n const signal = (options as any).signal as AbortSignal | undefined\n if (signal) {\n if (signal.aborted) {\n ajax.abort()\n } else {\n signal.addEventListener('abort', () => ajax.abort(), { once: true })\n }\n }\n Object.keys(headers).forEach((key) => {\n ajax.setRequestHeader(key, headers[key])\n })\n let timer\n if (onUploadProgress) {\n ajax.upload.addEventListener('progress', onUploadProgress)\n }\n ajax.onreadystatechange = () => {\n const result: ResponseObject = {}\n if (ajax.readyState === 4) {\n const headers = ajax.getAllResponseHeaders()\n const arr = headers.trim().split(/[\\r\\n]+/)\n // Create a map of header names to values\n const headerMap = {}\n arr.forEach((line) => {\n const parts = line.split(': ')\n const header = parts.shift().toLowerCase()\n const value = parts.join(': ')\n headerMap[header] = value\n })\n result.header = headerMap\n result.statusCode = ajax.status\n try {\n // 上传post请求返回数据格式为xml,此处容错\n result.data = responseType === 'blob' ? ajax.response : JSON.parse(ajax.responseText)\n } catch (e) {\n result.data = responseType === 'blob' ? ajax.response : ajax.responseText\n }\n clearTimeout(timer)\n resolve(result)\n }\n }\n if (enableAbort && this.timeout) {\n timer = setTimeout(() => {\n console.warn(this.timeoutMsg)\n ajax.abort()\n }, this.timeout)\n }\n // 处理 payload\n let payload\n if (isFormData(data)) {\n // FormData,不处理\n payload = data\n } else if (headers['content-type'] === 'application/x-www-form-urlencoded') {\n payload = toQueryString(data)\n } else if (body) {\n payload = body\n } else {\n // 其它情况\n payload = data ? JSON.stringify(data) : undefined\n }\n\n if (withCredentials) {\n ajax.withCredentials = true\n }\n ajax.send(payload)\n })\n }\n}\n\nfunction genAdapter() {\n const adapter: SDKAdapterInterface & { type?: 'default' | '' } = {\n type: 'default',\n root: window,\n reqClass: WebRequest,\n wsClass: WebSocket,\n localStorage,\n }\n return adapter\n}\n\nexport { genAdapter, WebRequest }\n","import { StorageInterface, AbstractStorage, SDKAdapterInterface } from '@cloudbase/adapter-interface'\nimport { ICloudbaseCache, ICacheConfig } from '@cloudbase/types/cache'\nimport { KV, Persistence, ICloudbasePlatformInfo } from '@cloudbase/types'\nimport { printWarn } from './util'\nimport { ERRORS, getSdkName } from '../constants'\n\n/**\n * persitence=none时登录态保存在内存中\n */\nclass TcbCacheObject extends AbstractStorage {\n private readonly root: any\n constructor(root: any) {\n super()\n this.root = root\n if (!root.tcbCacheObject) {\n root.tcbCacheObject = {}\n }\n }\n public setItem(key: string, value: any) {\n this.root.tcbCacheObject[key] = value\n }\n public getItem(key: string) {\n return this.root.tcbCacheObject[key]\n }\n public removeItem(key: string) {\n delete this.root.tcbCacheObject[key]\n }\n public clear() {\n delete this.root.tcbCacheObject\n }\n}\n/**\n * 工厂函数\n */\nfunction createStorage(persistence: Persistence, adapter: SDKAdapterInterface): StorageInterface {\n switch (persistence) {\n case 'local':\n if (!adapter.localStorage) {\n printWarn(ERRORS.INVALID_PARAMS, 'localStorage is not supported on current platform')\n // 不支持localstorage的平台降级为none\n return new TcbCacheObject(adapter.root)\n }\n return adapter.localStorage\n case 'none':\n return new TcbCacheObject(adapter.root)\n default:\n if (!adapter.localStorage) {\n printWarn(ERRORS.INVALID_PARAMS, 'localStorage is not supported on current platform')\n // 不支持localstorage的平台降级为none\n return new TcbCacheObject(adapter.root)\n }\n return adapter.localStorage\n }\n}\n\nexport class CloudbaseCache implements ICloudbaseCache {\n public keys: KV<string> = {}\n\n private persistenceTag: Persistence\n private platformInfo: ICloudbasePlatformInfo\n private storage: StorageInterface\n\n constructor(config: ICacheConfig) {\n const { persistence, platformInfo = {}, keys = {} } = config\n this.platformInfo = platformInfo\n if (!this.storage) {\n this.persistenceTag = this.platformInfo.adapter.primaryStorage || persistence\n this.storage = createStorage(this.persistenceTag, this.platformInfo.adapter)\n this.keys = keys\n }\n }\n /**\n * @getter storage模式-同步/异步\n */\n get mode() {\n return this.storage.mode || 'sync'\n }\n get persistence(): Persistence {\n return this.persistenceTag\n }\n\n public setStore(key: string, value: any, version?: any) {\n if (this.mode === 'async') {\n printWarn(ERRORS.INVALID_OPERATION, 'current platform\\'s storage is asynchronous, please use setStoreAsync insteed')\n return\n }\n if (!this.storage) {\n return\n }\n\n try {\n const val = {\n version: version || 'localCachev1',\n content: value,\n }\n this.storage.setItem(key, JSON.stringify(val))\n } catch (e) {\n throw new Error(JSON.stringify({\n code: ERRORS.OPERATION_FAIL,\n msg: `[${getSdkName()}][${ERRORS.OPERATION_FAIL}]setStore failed`,\n info: e,\n }))\n }\n\n return\n }\n public async setStoreAsync(key: string, value: any, version?: any) {\n if (!this.storage) {\n return\n }\n\n try {\n const val = {\n version: version || 'localCachev1',\n content: value,\n }\n await this.storage.setItem(key, JSON.stringify(val))\n } catch (e) {\n return\n }\n\n return\n }\n public getStore(key: string, version?: string) {\n if (this.mode === 'async') {\n printWarn(ERRORS.INVALID_OPERATION, 'current platform\\'s storage is asynchronous, please use getStoreAsync insteed')\n return\n }\n try {\n // 测试用例使用\n if (typeof process !== 'undefined' && process.env?.tcb_token) {\n return process.env.tcb_token\n }\n\n if (!this.storage) {\n return ''\n }\n } catch (e) {\n return ''\n }\n\n version = version || 'localCachev1'\n\n const content = this.storage.getItem(key)\n if (!content) {\n return ''\n }\n\n if (content.indexOf(version) >= 0) {\n const d = JSON.parse(content)\n return d.content\n }\n return ''\n }\n public async getStoreAsync(key: string, version?: string) {\n try {\n // 测试用例使用\n if (typeof process !== 'undefined' && process.env?.tcb_token) {\n return process.env.tcb_token\n }\n\n if (!this.storage) {\n return ''\n }\n } catch (e) {\n return ''\n }\n\n version = version || 'localCachev1'\n\n const content = await this.storage.getItem(key)\n if (!content) {\n return ''\n }\n\n if (content.indexOf(version) >= 0) {\n const d = JSON.parse(content)\n return d.content\n }\n return ''\n }\n public removeStore(key: string) {\n if (this.mode === 'async') {\n printWarn(ERRORS.INVALID_OPERATION, 'current platform\\'s storage is asynchronous, please use removeStoreAsync insteed')\n return\n }\n this.storage.removeItem(key)\n }\n public async removeStoreAsync(key: string) {\n await this.storage.removeItem(key)\n }\n}\n","import { isString, isInstanceOf } from './util'\nimport { Listeners, ICloudbaseEventEmitter } from '@cloudbase/types/events'\n\n\n/**\n * @private\n * @function _addEventListener - 添加监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @param {Listeners} listeners - 已存响应函数集合\n */\nfunction customeAddEventListener(name: string, listener: Function, listeners: Listeners) {\n listeners[name] = listeners[name] || []\n listeners[name].push(listener)\n}\n/**\n * @private\n * @function _removeEventListener - 移除监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @param {Listeners} listeners - 已存响应函数集合\n */\nfunction customRemoveEventListener(name: string, listener: Function, listeners: Listeners) {\n if (listeners?.[name]) {\n const index = listeners[name].indexOf(listener)\n if (index !== -1) {\n listeners[name].splice(index, 1)\n }\n }\n}\ninterface IEvent {\n name: string;\n target: any;\n data: any;\n}\n/**\n * 自定义事件\n * @class CloudbaseEvent\n * @param {string} name - 类型\n * @param {any} data - 数据\n */\nexport class CloudbaseEvent implements IEvent {\n public readonly name: string\n public target: any\n public data: any\n\n constructor(name: string, data: any) {\n this.data = data || null\n this.name = name\n }\n}\n/**\n * 自定义错误事件\n * @class IErrorEvent\n * @extends CloudbaseEvent\n * @param {Error} error - 错误信息对象\n * @param {any} data - 数据\n */\nexport class IErrorEvent extends CloudbaseEvent {\n public readonly error: Error\n constructor(error: Error, data?: any) {\n super('error', { error, data })\n this.error = error\n }\n}\n\n/**\n * @class CloudbaseEventEmitter\n */\nexport class CloudbaseEventEmitter implements ICloudbaseEventEmitter {\n /**\n * @private\n * @readonly\n * @property {Listeners} listeners - 响应函数集合\n * @default `{}`\n */\n private readonly listeners: Listeners = {}\n\n /**\n * @public\n * @method on - 添加监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @return `this`\n */\n public on(name: string, listener: Function): this {\n customeAddEventListener(name, listener, this.listeners)\n return this\n }\n /**\n * @public\n * @method off - 移除监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @return `this`\n */\n public off(name: string, listener: Function): this {\n customRemoveEventListener(name, listener, this.listeners)\n return this\n }\n /**\n * @public\n * @method fire - 触发事件\n * @param {string|CloudbaseEvent} event - event\n * @return `this`\n */\n public fire(event: string | CloudbaseEvent, data?: any): this {\n // 打印错误信息\n if (isInstanceOf(event, IErrorEvent)) {\n console.error((event as IErrorEvent).error)\n return this\n }\n\n const ev: CloudbaseEvent = isString(event) ? new CloudbaseEvent(event as string, data || {}) : event as CloudbaseEvent\n\n const { name } = ev\n\n if (this.listens(name)) {\n ev.target = this\n\n const handlers = this.listeners[name] ? [...this.listeners[name]] : []\n for (const fn of handlers) {\n fn.call(this, ev)\n }\n }\n\n return this\n }\n\n /**\n * @private\n * @method listens - 判断是否监听了name事件\n * @param {string} name - event名称\n * @return `boolean`\n */\n private listens(name: string): boolean {\n return this.listeners[name] && this.listeners[name].length > 0\n }\n}\n\n\nconst eventEmitter = new CloudbaseEventEmitter()\n\nexport function addEventListener(event: string, callback: Function) {\n eventEmitter.on(event, callback)\n}\n\nexport function activateEvent(event: string, data: any = {}) {\n eventEmitter.fire(event, data)\n}\n\nexport function removeEventListener(event: string, callback: Function) {\n eventEmitter.off(event, callback)\n}\n","import { CloudbaseEventEmitter } from './events'\n\nexport const bus = new CloudbaseEventEmitter()\n\nexport const LANG_CHANGE_EVENT = 'lang_change'\n","import { printGroupLog } from '../libs/util'\nimport { IS_DEBUG_MODE } from '../constants'\n\ninterface ICatchErrorsDecoratorOptions {\n mode?: 'sync' | 'async';\n customInfo?: {\n className?: string;\n methodName?: string;\n };\n title?: string;\n messages?: string[];\n}\n// firefox的stack格式与chrome不同\nlet isFirefox = false\nif (typeof navigator !== 'undefined' && navigator.userAgent) {\n isFirefox = navigator.userAgent.indexOf('Firefox') !== -1\n}\n/**\n * decorate在stack中一般都特定的规范\n */\nconst REG_STACK_DECORATE = isFirefox\n ? /(\\.js\\/)?__decorate(\\$\\d+)?<@.*\\d$/\n : /(\\/\\w+\\.js\\.)?__decorate(\\$\\d+)?\\s*\\(.*\\)$/\nconst REG_STACK_LINK = /https?:\\/\\/.+:\\d*\\/.*\\.js:\\d+:\\d+/\n/**\n * debug模式强化日志信息\n * @param options\n */\nexport function catchErrorsDecorator(options: ICatchErrorsDecoratorOptions) {\n const { mode = 'async', customInfo = {}, title, messages = [] } = options\n\n return function (\n target: any,\n methodName: string,\n descriptor: TypedPropertyDescriptor<Function>\n ) {\n // 生产环境禁用\n if (!IS_DEBUG_MODE) {\n return\n }\n const className = customInfo.className || target.constructor.name\n const fnName = customInfo.methodName || methodName\n const fn = descriptor.value\n\n // 被decorator装饰的源码link\n // 在descriptor.value外部此处创建的stack层次可触达源码\n // 而descriptor.value内部有可能由于stack太深无法触达\n const sourceLink = getSourceLink(new Error())\n\n if (mode === 'sync') {\n descriptor.value = function (...args: any[]) {\n // 此处的stack作用主要是为了获取被decorator装饰的源码class和method名称\n const innerErr: any = getRewritedError({\n err: new Error(),\n className,\n methodName: fnName,\n sourceLink,\n })\n try {\n return fn.apply(this, args)\n } catch (err) {\n let failErr = err\n const { message: errMsg, error, error_description: errorDescription } = err\n const logs: any = {\n title: title || `${className}.${fnName} failed`,\n content: [{\n type: 'error',\n body: err,\n }],\n }\n // 只特殊处理SDK业务逻辑抛出的错误-JSON string\n if (errMsg && /^\\{.*\\}$/.test(errMsg)) {\n const msg = JSON.parse(errMsg)\n logs.subtitle = errMsg\n if (msg.code) {\n if (innerErr) {\n innerErr.code = msg.code\n innerErr.msg = msg.msg\n } else {\n err.code = msg.code\n err.message = msg.msg\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n }\n\n // oauth 错误特殊处理\n if (error && errorDescription) {\n logs.subtitle = errorDescription\n if (innerErr) {\n innerErr.code = error\n innerErr.msg = errorDescription\n } else {\n err.code = error\n err.message = errorDescription\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n printGroupLog(logs)\n throw failErr\n }\n }\n } else {\n descriptor.value = async function (...args: any[]) {\n const innerErr: any = getRewritedError({\n err: new Error(),\n className,\n methodName: fnName,\n sourceLink,\n })\n\n try {\n return await fn.apply(this, args)\n } catch (err) {\n let failErr = err\n const { message: errMsg, error, error_description: errorDescription } = err\n const logs: any = {\n title: title || `${className}.${fnName} failed`,\n content: [{\n type: 'error',\n body: err,\n }],\n }\n // 只特殊处理SDK业务逻辑抛出的错误-JSON string\n if (errMsg && /^\\{.*\\}$/.test(errMsg)) {\n const msg = JSON.parse(errMsg)\n logs.subtitle = msg\n if (msg.code) {\n if (innerErr) {\n innerErr.code = msg.code\n innerErr.message = msg.msg\n } else {\n err.code = msg.code\n err.message = msg.msg\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n }\n\n // oauth 错误特殊处理\n if (error && errorDescription) {\n logs.subtitle = errorDescription\n if (innerErr) {\n innerErr.code = error\n innerErr.msg = errorDescription\n } else {\n err.code = error\n err.message = errorDescription\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n printGroupLog(logs)\n throw failErr\n }\n }\n }\n }\n}\n\n/**\n * 在原始堆栈中查找装饰器条目并返回源码链接link\n * @param err\n */\nfunction getSourceLink(err: Error) {\n let sourceLink = ''\n const outterErrStacks = err.stack.split('\\n')\n const indexOfDecorator = outterErrStacks.findIndex(str => REG_STACK_DECORATE.test(str))\n\n if (indexOfDecorator !== -1) {\n const match = REG_STACK_LINK.exec(outterErrStacks[indexOfDecorator + 1] || '')\n\n sourceLink = match ? match[0] : ''\n }\n return sourceLink\n}\n\n/**\n * 在原始堆栈中查找装饰器条目,剔除其后的无用堆栈,并将链接替换为源码link\n * @param options\n */\nfunction getRewritedError(options: {\n err: Error;\n className: string;\n methodName: string;\n sourceLink: string;\n}) {\n const { err, className, methodName, sourceLink } = options\n // 找不到源码link返回null,后续逻辑将打印原堆栈信息\n if (!sourceLink) {\n return null\n }\n\n const innerErrStack = err.stack.split('\\n')\n const REG_STACK_INNER_METHOD = isFirefox\n ? /^catchErrorsDecorator\\/<\\/descriptor.value@.*\\d$/\n : new RegExp(`${className}\\\\.descriptor.value\\\\s*\\\\[as\\\\s${methodName}\\\\]\\\\s*\\\\(.*\\\\)$`)\n const REG_STACK_INNER_METHOD_WITHOUT_LINK = isFirefox\n ? /^catchErrorsDecorator\\/<\\/descriptor.value/\n : new RegExp(`${className}\\\\.descriptor.value\\\\s*\\\\[as\\\\s${methodName}\\\\]`)\n const indexOfSource = innerErrStack.findIndex(str => REG_STACK_INNER_METHOD.test(str))\n let innerErr: Error\n if (indexOfSource !== -1) {\n // @ts-ignore\n const realErrStack = innerErrStack.filter((v, i) => i > indexOfSource)\n realErrStack.unshift(innerErrStack[indexOfSource]\n .replace(REG_STACK_INNER_METHOD_WITHOUT_LINK, `${className}.${methodName}`)\n .replace(REG_STACK_LINK, sourceLink))\n innerErr = new Error()\n innerErr.stack = `${isFirefox ? '@debugger' : 'Error'}\\n${realErrStack.join('\\n')}`\n }\n return innerErr\n}\n","var x = y => { var x = {}; __webpack_require__.d(x, y); return x; }\nvar y = x => () => x\nconst __WEBPACK_NAMESPACE_OBJECT__ = x({ [\"default\"]: () => __WEBPACK_EXTERNAL_MODULE_jwt_decode_b659f100__[\"default\"] });","import { constants, utils, helpers } from '@cloudbase/utilities'\nimport { getStringByteLength } from './encoding'\nimport {\n ICloudbaseFileMetaDataRes,\n ICloudbaseFileInfo,\n ICloudbaseUploadFileParams,\n ICloudbaseUploadFileResult,\n ICloudbaseGetUploadMetadataParams,\n ICloudbaseDeleteFileParams,\n ICloudbaseDeleteFileResult,\n ICloudbaseGetTempFileURLResult,\n ICloudbaseGetTempFileURLParams,\n ICloudbaseDownloadFileResult,\n ICloudbaseDownloadFileParams,\n ICloudbaseCopyFileParams,\n ICloudbaseCopyFileResult,\n} from '@cloudbase/types/storage'\n\nexport enum EUploadMethod {\n put = 'put',\n post = 'post',\n}\n\nexport interface IUploadMetadata {\n url: string\n token: string\n authorization: string\n fileId: string\n cosFileId: string\n download_url?: string\n}\n\nconst { getSdkName, ERRORS, COMMUNITY_SITE_URL } = constants\nconst { isArray, isString, isPalinObject, execCallback } = utils\n/** catchErrorsDecorator 装饰器要放在index入口文件,意面有的编译找不到其sourcemap,例如HBuilderX */\nconst { catchErrorsDecorator } = helpers as { catchErrorsDecorator: (options: unknown) => MethodDecorator }\n\nexport const COMPONENT_NAME = 'storage'\n\n/**\n * 网关(GATEWAY 模式)下的对象操作集合,统一走 `/v1/storages/*` HTTP 接口。\n *\n * `objectId` 第一段被解释为 `bucket_id`、其余为对象名(§1.2.2),\n * 权限由 `storage.objects` / `storage.buckets` 的 RLS 策略判定。\n *\n * 注意:这组接口与原生对象 API(StorageFileApi,`/object/{bucketId}/{name}`)\n * 是两套不同通道——前者是 `/v1/storages/*` 兼容路径,后者是原生 `bucketId + objectName` 路径。\n */\ntype CustomReqOpts = ICloudbaseUploadFileParams['customReqOpts']\n\ntype GatewayObjectResult = {\n code?: string\n message?: string\n authorization?: string\n token?: string\n uploadUrl?: string\n cloudObjectId?: string\n cloudObjectMeta?: string\n downloadUrl?: string\n}\n\ntype GatewayResponse<T> = Record<string, unknown> & {\n data?: T\n requestId?: string\n code?: string\n}\n\ntype GatewayRequest = {\n gateWay(payload: unknown, customReqOpts?: CustomReqOpts): Promise<GatewayResponse<GatewayObjectResult[]>>\n}\n\n/**\n * 网关获取 COS 上传预签名时使用的签名头,不等同于实际 XHR 上传请求头。\n *\n * 需要重点关注的 key:\n * - `content-length`:PUT body 的字节长度。后端用它参与 COS 签名,也会用于校验 Bucket 的 `file_size_limit` 配置。\n * - `content-type`:上传对象的 MIME 类型。后端用它参与 COS 签名,也会用于校验 Bucket 的 `allowed_mime_types` 配置;实际 PUT 上传时也需要发送同值。\n *\n * 调用方显式传入的其他 headers 会按原样放入签名头;这些 header 一旦参与签名,实际上传请求也必须发送同名同值 header。\n */\ntype SignedHeader = Record<string, string[]>\n\nconst storageGateWay = {\n getUploadInfo: async (\n request: GatewayRequest,\n params: { path: string; signedHeader?: SignedHeader },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'get-objects-upload-info',\n data: [\n {\n objectId: params.path,\n ...(params.signedHeader ? { signedHeader: params.signedHeader } : {}),\n },\n ],\n },\n customReqOpts,\n )\n const data = res.data?.[0] || {}\n\n return {\n ...res,\n data: {\n ...(data.code ? { ...data } : {}),\n authorization: data.authorization,\n token: data.token,\n url: data.uploadUrl,\n fileId: data.cloudObjectId,\n cosFileId: data.cloudObjectMeta,\n download_url: data.downloadUrl,\n },\n } as unknown as ICloudbaseFileMetaDataRes\n },\n getDownLoadInfo: async (\n request: GatewayRequest,\n params: { convertedFileList: Array<{ fileid: string; max_age?: number }> },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'get-objects-download-info',\n data: params.convertedFileList.map(v => ({ cloudObjectId: v.fileid })),\n },\n customReqOpts,\n )\n return {\n ...res,\n data: {\n download_list: res.data?.map(v => ({\n code: v.code || 'SUCCESS',\n message: v.message,\n fileid: v.cloudObjectId,\n download_url: v.downloadUrl,\n fileID: v.cloudObjectId,\n tempFileURL: v.downloadUrl,\n })),\n },\n }\n },\n delete: async (\n request: GatewayRequest,\n params: { fileList: Array<string> },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'delete-objects',\n data: params.fileList.map(v => ({ cloudObjectId: v })),\n },\n customReqOpts,\n )\n return {\n ...res,\n data: {\n delete_list: res.data?.map(v => ({\n code: v.code || 'SUCCESS',\n fileID: v.cloudObjectId,\n message: v.message,\n })),\n },\n }\n },\n copyFile: async (\n request: GatewayRequest,\n params: {\n convertedFileList: Array<{ src_path: string; dst_path: string; overwrite?: boolean; remove_original?: boolean }>\n },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'copy-objects',\n data: params.convertedFileList.map(v => ({\n srcPath: v.src_path,\n dstPath: v.dst_path,\n overwrite: v.overwrite,\n removeOriginal: v.remove_original,\n })),\n },\n customReqOpts,\n )\n return {\n ...res,\n data: {\n copy_list: res.data?.map(v => ({\n code: v.code || 'SUCCESS',\n fileID: v.cloudObjectId,\n message: v.message,\n })),\n },\n }\n },\n}\n\nexport interface ICloudbaseContext {\n config: any\n request: any\n}\n\ntype TempFileURLItem = NonNullable<ICloudbaseGetTempFileURLResult['fileList']>[number]\ntype FileInfoItem = Pick<TempFileURLItem, 'code' | 'fileID' | 'tempFileURL'> & {\n message?: TempFileURLItem['message']\n fileName?: string\n cloudId?: TempFileURLItem['fileID']\n contentType?: string\n mime?: string\n size?: number\n cacheControl?: string\n lastModified?: string\n etag?: string\n}\n\n/** 常见扩展名 → MIME 类型,用于上传时推断 content-type。 */\nconst MIME_BY_EXT: Record<string, string> = {\n txt: 'text/plain',\n json: 'application/json',\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n csv: 'text/csv',\n xml: 'application/xml',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n pdf: 'application/pdf',\n zip: 'application/zip',\n gz: 'application/gzip',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n}\n\n/**\n * 推断上传内容的 content-type,按可靠性从高到低:\n * ① 内容自带的 MIME(File/Blob.type,由浏览器/系统给出,最可靠);\n * ② 按云端路径扩展名映射;\n * ③ 兜底 application/octet-stream。\n * @param file 上传内容(可能是 Blob/File,也可能是字符串/ArrayBuffer 等无 type 形态)\n * @param path 云端路径,用于按扩展名兜底推断\n */\nfunction inferContentType(file: any, path: string): string {\n if (typeof Blob !== 'undefined' && file instanceof Blob && file.type) {\n return file.type\n }\n const m = /\\.([a-zA-Z0-9]+)$/.exec(path || '')\n const ext = m ? m[1].toLowerCase() : ''\n return MIME_BY_EXT[ext] || 'application/octet-stream'\n}\n\n/**\n * 尽力计算上传内容的字节长度(content-length)。\n *\n * 支持(可准确得到字节数):\n * - Blob / File:取 .size;\n * - ArrayBuffer:取 .byteLength;\n * - TypedArray / DataView(含 Node Buffer,为 Uint8Array 子类):取 .byteLength;\n * - 字符串「内容」:按 UTF-8 计算(浏览器用 new Blob([s]).size,Node 回退 Buffer.byteLength);\n * - 带数字 size 字段的对象:取 .size。\n *\n * 不支持(返回 undefined):\n * - 可读流:Node fs.ReadStream / Web ReadableStream —— 长度未知、边读边传,与「预签名 PUT 需先知长度」的模型冲突,无法同步求值;\n * - FormData:用于 POST multipart 上传,不会进入 PUT 网关分支,故不处理;\n * - 小程序本地路径字符串(wx 的 filePath 是文件路径而非内容):\n * 注意会被误当作「字符串内容」计算成路径本身的字节数,调用方如走该形态应显式传 content-length;\n * - 其它无 size 信息的自定义对象。\n */\nfunction resolveUploadByteLength(file: any, fileContent: any): number | undefined {\n const target = file ?? fileContent\n if (target === null) return undefined\n if (typeof Blob !== 'undefined' && target instanceof Blob) return target.size\n if (typeof ArrayBuffer !== 'undefined') {\n if (target instanceof ArrayBuffer) return target.byteLength\n if (typeof ArrayBuffer.isView === 'function' && ArrayBuffer.isView(target)) {\n return (target as ArrayBufferView).byteLength\n }\n }\n if (typeof target === 'string') {\n if (typeof Blob !== 'undefined') return new Blob([target]).size\n const byteLength = getStringByteLength(target)\n if (typeof byteLength === 'number') return byteLength\n return target.length\n }\n if (typeof target === 'object' && typeof (target as any).size === 'number') {\n return (target as any).size\n }\n return undefined\n}\n\n/** 判断 headers(不区分大小写)是否已包含某个字段。 */\nfunction hasHeader(headers: Record<string, string>, name: string): boolean {\n const lower = name.toLowerCase()\n return Object.keys(headers).some(k => k.toLowerCase() === lower)\n}\n\nfunction toSignedHeader(headers: Record<string, string>): SignedHeader {\n return Object.keys(headers).reduce(\n (result: SignedHeader, key) => ({ ...result, [key]: [headers[key]] }),\n {},\n )\n}\n\n/**\n * 传统云存储基类:提供顶层对象操作(`uploadFile` / `getTempFileURL` / `downloadFile` /\n * `deleteFile` / `copyFile` / `getFileInfo`),即「传统 SDK API」。\n *\n * 这些方法由 `isGateWay()` 决定底层通道(GATEWAY 走 `/v1/storages/*`,否则走旧版 CLOUD_API `request.send`)。\n * `cloudPath` 第一段须为 `bucket_id`、其余为对象名(§1.2.2);`fileID` 形态为\n * `cloud://env.cosBucket/<bucketId>/<name>`(路径含 bucket 段),权限由 PostgreSQL RLS(基于 `bucket_id`)判定。\n * 上传需 content-length / content-type 参与 COS 签名及 Bucket 配置校验(`uploadFile` 已自动补全)。\n *\n * @remarks 若 `cloudPath` 不含 bucket 前缀(如 `a.txt` 或首段桶不存在),服务端报\n * `STORAGE_BUCKET_NOT_FOUND`;缺 content-length 则报 `STORAGE_CONTENT_LENGTH_REQUIRED`。\n */\nexport class CloudbaseStorage {\n /**\n * 运行上下文(`{ config, request }`)。\n *\n * - 组件模式:实例由 `new CloudbaseStorage()`(无参)创建,方法被提取后重新绑定到 cloudbase 实例,\n * `this.config` / `this.request` 由该实例提供,本字段为空、原型 getter 不参与解析。\n * - 组合模式:由 `StorageClient`(入口 `supabaseComponent`)注入 context,方法以本实例为 `this`\n * 运行,`this.config` / `this.request` 经下方 getter 从 context 读取。\n */\n protected context?: ICloudbaseContext\n\n constructor(context?: ICloudbaseContext) {\n this.context = context\n }\n\n // @ts-ignore — 组件模式下 this 为 cloudbase 实例、走其自身 config,本 getter 不参与解析\n get config() {\n // @ts-ignore\n return this.context?.config\n }\n\n // @ts-ignore — 同上\n get request() {\n return this.context?.request\n }\n\n /**\n * 是否为网关模式(GATEWAY)。\n *\n * 用于区分「走新版 `/v1/storages/*` 网关」还是「走旧版 CLOUD_API(`request.send`)」。\n */\n public isGateWay() {\n // @ts-ignore\n const { config } = this\n const endPointMode = config.endPointMode || 'CLOUD_API'\n\n return endPointMode === 'GATEWAY'\n }\n\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'uploadFile',\n },\n title: '上传文件失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 uploadFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async uploadFile(\n params: Omit<ICloudbaseUploadFileParams, 'filePath'> & { filePath?: string },\n callback?: Function,\n ): Promise<ICloudbaseUploadFileResult> {\n const { cloudPath, filePath, onUploadProgress, method = 'put', headers = {}, fileContent } = params\n if (!isString(cloudPath) || (!filePath && !fileContent)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.uploadFile] invalid params`,\n }),)\n }\n const uploadMethod = { put: EUploadMethod.put, post: EUploadMethod.post }[method.toLocaleLowerCase()] || EUploadMethod.put\n\n const isGateway = this.isGateWay()\n const signedHeaders: Record<string, string> = { ...headers }\n const uploadHeaders: Record<string, string> = Object.keys(headers).reduce((result: Record<string, string>, key) => {\n if (key.toLowerCase() !== 'content-length') {\n result[key] = headers[key]\n }\n return result\n }, {})\n\n // 网关 PUT 直传时,COS 签名需要 content-length / content-type 参与;\n // 也会用它们校验 Bucket 的 file_size_limit / allowed_mime_types 配置,\n // 否则后端 get-objects-upload-info 会报 STORAGE_CONTENT_LENGTH_REQUIRED 等错误。\n // content-length 仅用于 signedHeader,不污染实际 XHR headers;content-type 需要参与签名也需要实际发送。\n if (uploadMethod === EUploadMethod.put && isGateway) {\n if (!hasHeader(signedHeaders, 'content-length')) {\n const byteLength = resolveUploadByteLength(filePath, fileContent)\n if (typeof byteLength === 'number') {\n signedHeaders['content-length'] = String(byteLength)\n }\n }\n if (!hasHeader(signedHeaders, 'content-type')) {\n // 优先取内容自带的 MIME(Blob.type),否则按 cloudPath 扩展名兜底\n signedHeaders['content-type'] = inferContentType(filePath, cloudPath)\n }\n if (!hasHeader(uploadHeaders, 'content-type')) {\n uploadHeaders['content-type'] = inferContentType(filePath, cloudPath)\n }\n }\n\n // 调用 getUploadMetadata 获取上传元数据\n const metadataResult = await this.getUploadMetadata({\n cloudPath,\n method: uploadMethod,\n headers: uploadMethod === EUploadMethod.put && !isGateway ? uploadHeaders : undefined,\n signedHeader: uploadMethod === EUploadMethod.put && isGateway ? toSignedHeader(signedHeaders) : undefined,\n customReqOpts: params.customReqOpts,\n })\n\n const { data: metadata, requestId } = metadataResult\n\n // 网关获取上传信息失败(如 STORAGE_CONTENT_LENGTH_REQUIRED)时,metadata 会带 code/message\n // 而无 url/authorization/token;必须在此中断,避免拿空 url 继续发起无效 PUT 上传。\n const metaErr: any = metadata\n if (metaErr?.code || !metaErr?.url) {\n const code = metaErr?.code || ERRORS.OPERATION_FAIL\n const message = metaErr?.message || 'get upload info failed'\n return execCallback(\n callback,\n new Error(`[${getSdkName()}][${code}][${COMPONENT_NAME}]:${message}`),\n )\n }\n\n const { url, authorization, token, fileId, cosFileId, download_url: downloadUrl } = metadata\n\n const commonParams = {\n url,\n file: filePath,\n name: cloudPath,\n onUploadProgress,\n fileContent,\n fileId,\n requestId,\n }\n\n const putParams = {\n ...commonParams,\n method: EUploadMethod.put,\n headers: {\n ...uploadHeaders,\n authorization,\n 'x-cos-meta-fileid': cosFileId,\n 'x-cos-security-token': token,\n },\n }\n\n const postParams = {\n ...commonParams,\n method: EUploadMethod.post,\n data: {\n key: cloudPath,\n signature: authorization,\n 'x-cos-meta-fileid': cosFileId,\n success_action_status: '201',\n 'x-cos-security-token': token,\n },\n }\n\n const uploadConfig = {\n [EUploadMethod.put]: {\n params: putParams,\n isSuccess: (code: number) => code >= 200 && code < 300,\n },\n [EUploadMethod.post]: {\n params: postParams,\n isSuccess: (code: number) => code === 201,\n },\n }\n\n // @ts-ignore\n const res = await this.request.upload(uploadConfig[uploadMethod].params)\n\n if (uploadConfig[uploadMethod].isSuccess(res.statusCode)) {\n return execCallback(callback, null, {\n fileID: fileId,\n download_url: downloadUrl,\n requestId,\n })\n }\n return execCallback(\n callback,\n new Error(`[${getSdkName()}][${ERRORS.OPERATION_FAIL}][${COMPONENT_NAME}]:${res.data}`),\n )\n }\n\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'getUploadMetadata',\n },\n title: '获取上传元信息失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 getUploadMetadata() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async getUploadMetadata(\n params: ICloudbaseGetUploadMetadataParams & {\n method?: EUploadMethod\n headers?: Record<string, string>\n signedHeader?: SignedHeader\n },\n callback?: Function,\n ): Promise<{ data: IUploadMetadata; requestId: string }> {\n const { cloudPath, method, headers, signedHeader } = params\n if (!isString(cloudPath)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getUploadMetadata] invalid cloudPath`,\n }),)\n }\n // @ts-ignore\n const { request } = this\n const action = 'storage.getUploadMetadata'\n\n try {\n let metaData: ICloudbaseFileMetaDataRes\n\n const metaDataParam: {\n path: string\n method?: EUploadMethod\n headers?: Record<string, string>\n signedHeader?: SignedHeader\n } = { path: cloudPath }\n const isGateway = this.isGateWay()\n\n if (method) {\n metaDataParam.method = method\n }\n if (method === EUploadMethod.put) {\n if (isGateway && signedHeader) {\n metaDataParam.signedHeader = signedHeader\n } else if (!isGateway && headers) {\n metaDataParam.headers = headers\n }\n }\n\n if (isGateway) {\n metaData = await storageGateWay.getUploadInfo(request, metaDataParam, params.customReqOpts)\n } else {\n metaData = await request.send(action, metaDataParam, params.customReqOpts)\n }\n return execCallback(callback, null, metaData)\n } catch (err) {\n return execCallback(callback, err)\n }\n }\n\n /**\n * 删除文件(按 fileID 批量)。\n *\n * 服务端从 `cloudObjectId` 反解 `bucket_id + name`,先按 RLS 删 `storage.objects`\n * 元数据再删 COS 对象;调用方传的 fileID 应来自上传返回值(已含 bucket 段)。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'deleteFile',\n },\n title: '删除文件失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 deleteFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async deleteFile(\n params: ICloudbaseDeleteFileParams,\n callback?: Function,\n ): Promise<ICloudbaseDeleteFileResult> {\n const { fileList } = params\n\n if (!fileList || !isArray(fileList) || fileList.length === 0) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.deleteFile] fileList must not be empty`,\n }),)\n }\n\n for (const fileId of fileList) {\n if (!fileId || !isString(fileId)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.deleteFile] fileID must be string`,\n }),)\n }\n }\n\n const action = 'storage.batchDeleteFile'\n // @ts-ignore\n const { request } = this\n let res: any = {}\n\n if (this.isGateWay()) {\n res = await storageGateWay.delete(request, { fileList }, params.customReqOpts)\n } else {\n res = await request.send(\n action,\n {\n fileid_list: fileList,\n },\n params.customReqOpts,\n )\n }\n\n if (res.code) {\n return execCallback(callback, null, res)\n }\n const data = {\n fileList: res.data.delete_list,\n requestId: res.requestId,\n }\n return execCallback(callback, null, data)\n }\n\n /**\n * 获取文件临时下载链接(按 fileID 批量)。\n *\n * 服务端从 `cloudObjectId` 拆出 `bucket_id + name`,先查元数据并执行 RLS 校验,\n * 再经 COS `HEAD` 确认物理文件后生成下载 URL(无权限或不存在则该项返回错误码)。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'getTempFileURL',\n },\n title: '获取文件下载链接',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 getTempFileURL() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async getTempFileURL(\n params: ICloudbaseGetTempFileURLParams,\n callback?: Function,\n ): Promise<ICloudbaseGetTempFileURLResult> {\n const { fileList } = params\n\n if (!fileList || !isArray(fileList) || fileList.length === 0) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] fileList must not be empty`,\n }),)\n }\n\n const convertedFileList: Array<{ fileid: string; max_age?: number }> = []\n for (const file of fileList) {\n if (isPalinObject(file)) {\n if (!Object.prototype.hasOwnProperty.call(file, 'fileID')) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] file info must include fileID`,\n }),)\n }\n\n convertedFileList.push({\n fileid: (file as ICloudbaseFileInfo).fileID,\n max_age: (file as ICloudbaseFileInfo).maxAge || 7200,\n })\n } else if (isString(file)) {\n convertedFileList.push({\n fileid: file as string,\n })\n } else {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] invalid fileList`,\n }),)\n }\n }\n\n const action = 'storage.batchGetDownloadUrl'\n // @ts-ignore\n const { request } = this\n let res: any = {}\n\n if (this.isGateWay()) {\n res = await storageGateWay.getDownLoadInfo(request, { convertedFileList }, params.customReqOpts)\n } else {\n res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)\n }\n\n if (res.code) {\n return execCallback(callback, null, res)\n }\n\n return execCallback(callback, null, {\n fileList: res.data.download_list,\n requestId: res.requestId,\n })\n }\n\n /**\n * 下载文件,返回内容(内部先取临时 URL 再拉取)。\n *\n * 同 `getTempFileURL`,先经元数据 + RLS 校验再下载;`fileID` 须含 bucket 段。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'downloadFile',\n },\n title: '下载文件失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 downloadFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async downloadFile(\n params: ICloudbaseDownloadFileParams,\n callback?: Function,\n ): Promise<ICloudbaseDownloadFileResult> {\n const { fileID } = params\n if (!isString(fileID)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] fileID must be string`,\n }),)\n }\n\n const tmpUrlRes = await this.getTempFileURL.call(this, {\n fileList: [\n {\n fileID,\n maxAge: 600,\n },\n ],\n customReqOpts: params.customReqOpts,\n })\n\n const res = tmpUrlRes.fileList![0]\n\n if (res.code !== 'SUCCESS') {\n return execCallback(callback, res)\n }\n // @ts-ignore\n const { request } = this\n\n const tmpUrl = encodeURI(res.download_url!)\n\n const result = await request.download({ url: tmpUrl, tempFilePath: params.tempFilePath })\n return execCallback(callback, null, result)\n }\n\n /**\n * 批量复制文件(按源/目标 fileID)。\n *\n * 服务端从源/目标路径各拆出 `bucket_id + name`,经 RLS 校验读写权限后执行\n * 底层 COS 复制(支持跨 bucket,前提是两个 bucket 段都解析成功且有权限)。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'copyFile',\n },\n title: '批量复制文件',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 copyFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async copyFile(params: ICloudbaseCopyFileParams, callback?: Function): Promise<ICloudbaseCopyFileResult> {\n const { fileList } = params\n\n if (!fileList || !isArray(fileList) || fileList.length === 0) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.copyFile] fileList must not be empty`,\n }),)\n }\n\n const convertedFileList = []\n\n for (const file of fileList) {\n const { srcPath, dstPath } = file\n if (!srcPath || !dstPath || typeof srcPath !== 'string' || typeof dstPath !== 'string') {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath may not be empty`,\n }),)\n }\n if (srcPath === dstPath) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath can not be the same`,\n }),)\n }\n // if (basename(srcPath) !== basename(dstPath)) {\n // throw new Error(JSON.stringify({\n // code: ERRORS.INVALID_PARAMS,\n // msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath file name must be the same`,\n // }),)\n // }\n convertedFileList.push({\n src_path: srcPath,\n dst_path: dstPath,\n overwrite: file.overwrite,\n remove_original: file.removeOriginal,\n })\n }\n\n // @ts-ignore\n const { request } = this\n let res: any = {}\n\n if (this.isGateWay()) {\n res = await storageGateWay.copyFile(request, { convertedFileList }, params.customReqOpts)\n } else {\n const action = 'storage.batchCopyFile'\n res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)\n }\n\n if (res.code) {\n return execCallback(callback, null, res)\n }\n\n return execCallback(callback, null, {\n fileList: res.data.copy_list,\n requestId: res.requestId,\n })\n }\n\n /**\n * 获取文件元信息(大小、contentType、etag、lastModified 等,内部基于临时 URL + COS HEAD)。\n *\n * 服务端解析 `bucket_id + name` 并通过 RLS 后返回;元数据以 COS 对象为准\n * (`storage.objects` 的完整元信息建议改用 `from(bucketId).info()`)。\n */\n public async getFileInfo(params: ICloudbaseGetTempFileURLParams): Promise<{\n fileList: FileInfoItem[]\n requestId: string\n }> {\n const fileInfo = await this.getTempFileURL(params)\n\n if (fileInfo?.fileList && fileInfo?.fileList?.length > 0) {\n const fileList = await Promise.all(fileInfo.fileList.map(async (item: TempFileURLItem) => {\n if (item.code !== 'SUCCESS') {\n return {\n code: item.code,\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n message: item.message,\n }\n }\n\n try {\n // @ts-ignore\n const { request } = this\n const res = await request.fetch({ url: item.tempFileURL, method: 'HEAD' })\n let { header } = res\n\n if (typeof Headers !== 'undefined' && header instanceof Headers) {\n const normalizedHeader: Record<string, string> = {}\n header.forEach((value, key) => {\n normalizedHeader[key] = value\n })\n header = normalizedHeader\n }\n // eslint-disable-next-line radix\n const fileSize = parseInt(header['content-length']) || 0\n const contentType = header['content-type'] || ''\n\n if ([400, 404].includes(Number(res.statusCode))) {\n return {\n code: 'FILE_NOT_FOUND',\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n message: 'file not found',\n }\n }\n\n const fileInfo: FileInfoItem = {\n code: item.code,\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n cloudId: item.fileID,\n fileName: item.fileID.split('/').pop(),\n contentType,\n mime: contentType.split(';')[0].trim(),\n size: fileSize,\n etag: header.etag || '',\n lastModified: header['last-modified'] || '',\n cacheControl: header['cache-control'] || '',\n }\n\n return fileInfo\n } catch (e) {\n const message = typeof e === 'object' && e !== null && 'message' in e\n ? String((e as { message?: unknown }).message)\n : undefined\n return {\n code: 'FETCH_FILE_INFO_ERROR',\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n message,\n }\n }\n }),)\n\n return {\n fileList,\n requestId: fileInfo.requestId!,\n }\n }\n\n return {\n fileList: [],\n requestId: fileInfo.requestId!,\n }\n }\n}\n","import { constants } from '@cloudbase/utilities'\nimport { Camelize, FileBody, FileObject, FileObjectV2, FileOptions, TransformOptions } from './supabase/types'\nimport { isStorageError, StorageError } from './supabase/errors'\nimport { CloudbaseStorage, ICloudbaseContext, COMPONENT_NAME } from './cloudbase-storage'\nimport { toBase64 } from './encoding'\n\nconst { ERRORS } = constants\n\n/**\n * 传统 CloudBase 对象操作客户端(Supabase-like 包装层,底层仍走传统云存储 HTTP API,即 `CloudbaseStorage` 的顶层方法)。\n *\n * 通过 `app.storage.from()`(不传 bucketId)获取,与 PG 原生的 `StorageFileApi` 对等但**通道不同**。\n *\n * 两环境下的行为:\n * - 传统环境:原生用法,`upload/download/remove` 走传统接口,path 为 COS Bucket 内相对路径。\n * - Neo 环境:因底层仍是传统兼容路径,**path 第一段同样会被服务端当作 PG `bucket_id`**;\n * 且本类 `bucketId` 恒为空串、构造时从不赋值,故 `getPublicUrl/createSignedUrl` 等需要拼 `cloud://` 的方法\n * 必须传**完整 fileID**(而非相对 path),否则 `_normalizeCloudId` 抛 `bucketId is not set`。\n * PG 环境若要按 bucket 语义做原生对象操作,应改用 `app.storage.from(bucketId)`(StorageFileApi)。\n */\nexport class ClassicStorageFileApi {\n protected shouldThrowOnError = false\n protected bucketId = ''\n protected context?: ICloudbaseContext\n\n /**\n * 底层传统云存储能力(组合而非继承)。\n *\n * 本类只是把这套底层方法(`uploadFile` / `copyFile` / `getTempFileURL` / `getFileInfo` /\n * `deleteFile` / `getUploadMetadata`)重新包装成 Supabase 风格签名,因此通过**委托**复用,\n * 而不继承——避免把基类的传统 API 一并暴露在本类实例上。\n *\n * 这里刻意标注为 `any`:基类方法均挂 `@catchErrorsDecorator`,该装饰器签名 TS 无法解析,\n * 原先继承时 `this.uploadFile()` 等返回值本就被降级为 `any`,本类的结果处理代码也是按 `any` 编写的。\n * 用 `any` 持有可忠实保留改造前的行为,避免暴露一批本被掩盖的松散类型告警。\n */\n private storage: any\n\n constructor(context?: ICloudbaseContext, shouldThrowOnError = false) {\n this.context = context\n this.shouldThrowOnError = shouldThrowOnError\n // 注入同一 context,使底层 storage 的 config/request 与本类一致\n this.storage = new CloudbaseStorage(context)\n }\n\n get config() {\n // @ts-ignore\n return this.context?.config\n }\n\n get request() {\n // @ts-ignore\n return this.context?.request\n }\n\n throwOnError(): this {\n this.shouldThrowOnError = true\n return this\n }\n\n /**\n * 上传文件。\n *\n * 与 Supabase `StorageFileApi.upload(path, fileBody, fileOptions?)` 的差异:\n * - **参数命名**:一致(`path` / `fileBody` / `fileOptions`)。\n * - **默认行为**:本实现默认 `upsert: true`(覆盖),Supabase 默认 `upsert: false`(不覆盖)。\n * - **metadata 传递**:经 CloudBase 私有头 `x-cos-metadata-metadata` 传递,Supabase 走 `x-metadata` / FormData。\n * - **返回值**:`fullPath` 直接等于入参 `path`;Supabase 的 `fullPath` 为 `bucketId/path` 形态。\n */\n async upload(\n path: string,\n fileBody: FileBody,\n fileOptions?: FileOptions,\n ): Promise<\n { data: { id: string; path: string; fullPath: string }; error: null } | { data: null; error: StorageError }\n > {\n const options = { upsert: true, ...fileOptions }\n const { cacheControl, contentType, metadata } = options\n try {\n const cloudPath = this.getCloudPath(path)\n const uploadFileParams: Parameters<CloudbaseStorage['uploadFile']>[0] = {\n cloudPath,\n filePath: fileBody as any,\n }\n\n if (cacheControl || contentType || metadata) {\n const headers: Record<string, string> = {}\n if (cacheControl) {\n headers['cache-control'] = cacheControl\n }\n if (contentType) {\n headers['content-type'] = contentType\n }\n\n if (metadata) {\n headers['x-cos-metadata-metadata'] = this.toBase64(JSON.stringify(metadata))\n }\n\n uploadFileParams.headers = headers\n }\n\n const result = await this.storage.uploadFile(uploadFileParams)\n\n // IUploadFileRes 没有 code 字段,如果没有 fileID 则表示失败\n if (!result.fileID) {\n throw new Error(JSON.stringify({\n code: ERRORS.OPERATION_FAIL,\n msg: `[${COMPONENT_NAME}.update] no fileID returned`,\n }),)\n }\n\n return {\n data: {\n id: result.fileID,\n path,\n fullPath: path,\n },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 使用签名 URL 上传文件。\n *\n * 与 Supabase `StorageFileApi.uploadToSignedUrl(path, token, fileBody, fileOptions?)` 的差异:\n * - **参数命名**:一致,但第二参 `token` 在本实现中被**忽略**(命名为 `_token`)。\n * - **行为**:不走签名 URL 通道,内部直接委托 `upload()`,因此 `token` 无实际作用。\n */\n async uploadToSignedUrl(\n path: string,\n _token: string,\n fileBody: FileBody,\n fileOptions?: FileOptions,\n ): Promise<\n { data: { id: string; path: string; fullPath: string }; error: null } | { data: null; error: StorageError }\n > {\n return this.upload(path, fileBody, fileOptions)\n }\n\n /**\n * 创建签名上传 URL。\n *\n * 与 Supabase `StorageFileApi.createSignedUploadUrl(path, options?: { upsert })` 的差异:\n * - **参数缺失**:**缺第二参 `options`**(不支持 `upsert`)。\n * - **返回值**:在 `{ signedUrl, token, path }` 基础上额外返回 CloudBase 私有字段\n * `authorization` / `id` / `cosFileId` / `downloadUrl`(供 `uploadToSignedUrl` 等使用)。\n */\n async createSignedUploadUrl(path: string): Promise<\n | {\n data: {\n signedUrl: string\n token: string\n path: string\n // CloudBase 额外的元数据字段\n authorization?: string\n id?: string\n cosFileId?: string\n downloadUrl?: string\n }\n error: null\n }\n | { data: null; error: StorageError }\n > {\n try {\n const cloudPath = this.getCloudPath(path)\n\n const { data: metadata } = await this.storage.getUploadMetadata({ cloudPath })\n\n return {\n data: {\n signedUrl: metadata.url,\n token: metadata.token,\n path,\n // 返回 CloudBase 的额外元数据,供 uploadToSignedUrl 使用\n authorization: metadata.authorization,\n id: metadata.fileId,\n cosFileId: metadata.cosFileId,\n downloadUrl: metadata.download_url,\n },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n return {\n data: null,\n error: error instanceof StorageError ? error : new StorageError(error.message),\n }\n }\n }\n\n /**\n * 更新(覆盖)文件。\n *\n * 与 Supabase `StorageFileApi.update(path, fileBody, fileOptions?)` 的差异:\n * - **参数命名**:一致。\n * - **行为**:强制 `upsert: true` 后委托 `upload()`;Supabase 的 `update` 同样总是覆盖,语义基本一致。\n */\n async update(\n path: string,\n fileBody: FileBody,\n fileOptions?: FileOptions,\n ): Promise<\n { data: { id: string; path: string; fullPath: string }; error: null } | { data: null; error: StorageError }\n > {\n return this.upload(path, fileBody, { ...fileOptions, upsert: true })\n }\n\n /**\n * 移动文件。\n *\n * 与 Supabase `StorageFileApi.move(fromPath, toPath, options?: DestinationOptions)` 的差异:\n * - **参数缺失**:**缺第三参 `options`**(不支持 `destinationBucket` 等,已注释占位)。\n * - **底层实现**:通过 `copyFile(removeOriginal: true)` 模拟移动。\n * - **返回值**:`data.message` 为 `File moved from X to Y`;Supabase 固定返回 `Successfully moved`。\n */\n async move(\n fromPath: string,\n toPath: string,\n // options?: DestinationOptions,\n ): Promise<{ data: { message: string }; error: null } | { data: null; error: StorageError }> {\n try {\n const result = await this.storage.copyFile({\n fileList: [\n {\n srcPath: this.getCloudPath(fromPath),\n dstPath: this.getCloudPath(toPath),\n overwrite: true,\n removeOriginal: true,\n },\n ],\n })\n\n if (result.fileList[0].code && result.fileList[0].code !== 'SUCCESS') {\n throw new StorageError(result.fileList[0].message || 'Move failed')\n }\n\n return {\n data: { message: `File moved from ${fromPath} to ${toPath}` },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 复制文件。\n *\n * 与 Supabase `StorageFileApi.copy(fromPath, toPath, options?: DestinationOptions)` 的差异:\n * - **参数缺失**:**缺第三参 `options`**(不支持 `destinationBucket` 等,已注释占位)。\n * - **返回值**:`data.path` 为清洗后的目标相对路径;Supabase 返回后端 `data.Key`(`bucketId/path` 形态)。\n */\n async copy(\n fromPath: string,\n toPath: string,\n // options?: DestinationOptions,\n ): Promise<{ data: { path: string }; error: null } | { data: null; error: StorageError }> {\n try {\n const result = await this.storage.copyFile({\n fileList: [\n {\n srcPath: this.getCloudPath(fromPath),\n dstPath: this.getCloudPath(toPath),\n overwrite: true,\n removeOriginal: false,\n },\n ],\n })\n\n if (result.fileList[0].code && result.fileList[0].code !== 'SUCCESS') {\n throw new StorageError(result.fileList[0].message || 'Copy failed')\n }\n\n return {\n data: { path: this.getCloudPath(toPath) },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return { data: null, error }\n }\n throw error\n }\n }\n\n /**\n * 创建签名下载 URL。\n *\n * 与 Supabase `StorageFileApi.createSignedUrl(path, expiresIn, options?: { download, transform, cacheNonce })` 的差异:\n * - **参数命名**:一致(`path` / `expiresIn` / `options`)。\n * - **options 缺字段**:仅支持 `download` / `transform`,**缺 `cacheNonce`**。\n * - **底层实现**:基于 `getTempFileURL` 的临时 URL;`transform` 走腾讯云数据万象 imageMogr2,与 Supabase 的转换参数不同。\n */\n async createSignedUrl(\n path: string,\n expiresIn: number,\n options?: {\n download?: string | boolean\n transform?: TransformOptions\n },\n ): Promise<{ data: { signedUrl: string }; error: null } | { data: null; error: StorageError }> {\n try {\n const cloudPath = this.normalizeCloudId(path)\n const result = await this.storage.getTempFileURL({\n fileList: [\n {\n fileID: cloudPath,\n maxAge: expiresIn,\n },\n ],\n })\n\n // IGetFileUrlItem 有 code 字段但没有 message 字段\n if (result.fileList[0].code !== 'SUCCESS') {\n throw new StorageError(`Failed to create signed URL: [${result.fileList[0].code}] ${result.fileList[0].fileID}`)\n }\n\n let signedUrl = result.fileList[0].download_url\n\n // 构建查询参数\n const queryParams: string[] = []\n\n // 如果有 download 参数,添加到 URL 中\n if (options?.download !== undefined) {\n if (typeof options.download === 'string') {\n // download 是文件名\n queryParams.push(`download=${encodeURIComponent(options.download)}`)\n } else if (options.download === true) {\n // download 是 true,使用原文件名或默认值\n queryParams.push('download=true')\n }\n }\n\n // 如果有图片转换参数,添加到 URL 中\n if (options?.transform) {\n const transformQuery = this.transformOptsToQueryString(options.transform)\n if (transformQuery) {\n queryParams.push(transformQuery)\n }\n }\n\n // 拼接所有查询参数\n if (queryParams.length > 0) {\n const separator = signedUrl.includes('?') ? '&' : '?'\n signedUrl = `${signedUrl}${separator}${queryParams.join('&')}`\n }\n\n return {\n data: { signedUrl },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 批量创建签名下载 URL。\n *\n * 与 Supabase `StorageFileApi.createSignedUrls(paths, expiresIn, options?: { download, cacheNonce })` 的差异:\n * - **参数缺失**:**缺第三参 `options`**(不支持 `download` / `cacheNonce`,已注释占位)。\n * - **返回项结构**:`{ path, signedUrl, error }`;Supabase 还会返回原始 `signedURL` 字段。\n */\n async createSignedUrls(\n paths: string[],\n expiresIn: number,\n // options?: {\n // download?: string | boolean\n // },\n ): Promise<\n | { data: Array<{ path: string; signedUrl: string; error: string | null }>; error: null }\n | { data: null; error: StorageError }\n > {\n try {\n const fileList = paths.map(p => ({\n fileID: this.normalizeCloudId(p),\n maxAge: expiresIn,\n }))\n\n const result = await this.storage.getTempFileURL({ fileList })\n\n return {\n data: result.fileList.map((item: any, index: number) => ({\n path: paths[index],\n signedUrl: item.tempFileURL || '',\n error: item.code === 'SUCCESS' ? null : item.message,\n })),\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 下载文件,返回 Blob。\n *\n * 与 Supabase `StorageFileApi.download(path, options?: { transform, cacheNonce }, parameters?)` 的差异:\n * - **第二参类型**:本实现 `options` 直接是 `TransformOptions`,Supabase 是包裹形态 `{ transform, cacheNonce }`。\n * - **参数缺失**:缺 `cacheNonce`、以及第三参 `parameters`(fetch 选项 / AbortSignal)。\n * - **返回值**:返回 `Promise<{ data: Blob; error }>`;Supabase 返回 `BlobDownloadBuilder`(可链式 `throwOnError`)。\n */\n async download(\n path: string,\n options?: TransformOptions,\n ): Promise<{\n data: Blob | null\n error: StorageError | null\n }> {\n try {\n return {\n data: await (async () => {\n const signedUrlResult = await this.createSignedUrl(path, 600, { transform: options })\n if (signedUrlResult.error) {\n throw signedUrlResult.error\n }\n const tmpUrl = encodeURI(signedUrlResult.data?.signedUrl)\n\n const { data } = await (this as any).request.reqClass.get({\n url: tmpUrl,\n headers: {}, // 下载资源请求不经过service,header清空\n responseType: 'blob',\n })\n\n if (!data) {\n throw new StorageError('Download failed: no file content')\n }\n\n // 将 Buffer 转换为 Uint8Array 以兼容 Blob\n return new Blob([data])\n })(),\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 获取文件信息\n *\n * 与 Supabase `StorageFileApi.info(path)` 的差异:\n * - **参数命名**:本实现命名为 `pathOrFileId`(Supabase 为 `path`),且额外支持传入 `cloud://` 完整 fileID。\n * - **返回值**:同为 `Camelize<FileObjectV2>`,但 `metadata` 恒为 `{}`、`version` 恒为 `'1'`,部分时间字段为近似值。\n *\n * @param pathOrFileId - 相对路径(如 'images/photo.jpg')或 CloudBase fileID(以 'cloud://' 开头)\n * @returns 文件信息对象\n *\n * @example\n * ```typescript\n * // 使用相对路径\n * const { data } = await bucket.info('images/photo.jpg')\n *\n * // 使用 CloudBase fileID\n * const { data } = await bucket.info('cloud://env-id.xxxx-xxxx/images/photo.jpg')\n * ```\n */\n async info(pathOrFileId: string,): Promise<{ data: Camelize<FileObjectV2>; error: null } | { data: null; error: StorageError }> {\n try {\n // 判断是 fileID 还是相对路径\n const isFileId = pathOrFileId.startsWith('cloud://')\n const displayName = isFileId ? this.extractPathFromFileId(pathOrFileId) : pathOrFileId\n const bucketId = isFileId ? this.extractBucketFromFileId(pathOrFileId) : this.bucketId\n\n const fileInfo = await this.storage.getFileInfo({\n fileList: [this.normalizeCloudId(pathOrFileId)],\n })\n\n const item = fileInfo.fileList[0]\n\n if (item.code !== 'SUCCESS') {\n throw new StorageError(item.message)\n }\n\n const now = new Date().toISOString()\n const lastModified = (item.lastModified ? new Date(item.lastModified) : new Date()).toISOString()\n return {\n data: {\n id: item.fileID,\n version: '1',\n name: displayName,\n bucketId,\n updatedAt: lastModified,\n createdAt: lastModified,\n lastAccessedAt: now,\n size: item.size,\n cacheControl: item.cacheControl,\n contentType: item.contentType,\n etag: item.etag,\n lastModified,\n metadata: {},\n },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n return {\n data: null,\n error: error instanceof StorageError ? error : new StorageError(error.message),\n }\n }\n }\n\n /**\n * 判断文件是否存在。\n *\n * 与 Supabase `StorageFileApi.exists(path)` 的差异:\n * - **参数命名**:本实现命名为 `pathOrFileId`(Supabase 为 `path`),且额外支持 `cloud://` fileID。\n * - **底层实现**:基于 `getFileInfo`,将 `FILE_NOT_FOUND` 视为不存在;Supabase 用 HEAD 请求 + 400/404 判定。\n */\n async exists(pathOrFileId: string): Promise<{ data: boolean; error: null } | { data: null; error: StorageError }> {\n try {\n // 判断是 fileID 还是相对路径\n const fileInfo = await this.storage.getFileInfo({\n fileList: [this.normalizeCloudId(pathOrFileId)],\n })\n\n const item = fileInfo.fileList[0]\n\n if (item.code === 'FILE_NOT_FOUND') {\n return {\n data: false,\n error: null,\n }\n }\n\n if (item.code !== 'SUCCESS') {\n throw new StorageError(item.message)\n }\n\n return { data: true, error: null }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 获取公开访问 URL。\n *\n * 与 Supabase `StorageFileApi.getPublicUrl(path, options?)` 的差异:\n * - **同步性**:Supabase 为**同步**方法直接返回 `{ data: { publicUrl } }`;本实现为 **`async`**(返回 Promise),调用方式不兼容。\n * - **底层实现**:实际返回的是 600s 的签名 URL(基于 `createSignedUrl`),而非真正的永久公开直链。\n * - **options 缺字段**:支持 `download` / `transform`,缺 `cacheNonce`。\n * - **返回值**:失败时返回 `{ data: null, error }`;Supabase 不返回 error。\n */\n async getPublicUrl(\n path: string,\n options?: {\n download?: string | boolean\n transform?: TransformOptions\n },\n ): Promise<\n | {\n data: { publicUrl: string }\n }\n | { data: null; error: StorageError }\n > {\n const res = await this.createSignedUrl(path, 600, options)\n\n if (res.data) {\n return {\n data: { publicUrl: res.data.signedUrl },\n }\n }\n\n return { data: null, error: res.error as StorageError }\n }\n\n /**\n * 批量删除文件。\n *\n * 与 Supabase `StorageFileApi.remove(paths)` 的差异:\n * - **参数命名**:一致(`paths: string[]`)。\n * - **返回值**:返回的 `FileObject[]` 仍包含 Supabase 新版已不再返回的废弃字段(`bucket_id` / `owner` / `buckets`),\n * 且这些字段多为占位/未知值。\n * - **实现开销**:删除前会先分批(每组 10 个)拉取文件信息以补全返回结构。\n */\n async remove(paths: string[]): Promise<{ data: FileObject[]; error: null } | { data: null; error: StorageError }> {\n try {\n // 分组获取文件信息,每组最多10个\n const chunkSize = 10\n const pathChunks: string[][] = []\n for (let i = 0; i < paths.length; i += chunkSize) {\n pathChunks.push(paths.slice(i, i + chunkSize))\n }\n\n // 并行获取所有分组的文件信息\n const fileInfoResults = await Promise.all(pathChunks.map(chunk => Promise.all(chunk.map(path => this.info(path)))),)\n\n // 合并所有文件信息并构建映射表(path -> fileInfo)\n const fileInfoMap = new Map<string, Camelize<FileObjectV2>>()\n fileInfoResults.forEach((chunkResults, chunkIndex) => {\n chunkResults.forEach((result, index) => {\n if (result.data) {\n fileInfoMap.set(paths[chunkIndex * chunkSize + index], result.data)\n }\n })\n })\n\n // 执行删除操作\n const fileList = paths.map(p => this.normalizeCloudId(p))\n const result: { fileList: Array<{ code?: string }> } = await this.storage.deleteFile({ fileList })\n\n // IDeleteFileRes 的 fileList 数组中每个项有 code 字段\n const failedFiles = result.fileList.filter(item => item.code !== 'SUCCESS')\n if (failedFiles.length > 0) {\n throw new StorageError(`Delete failed for ${failedFiles.length} file(s)`)\n }\n\n const now = new Date().toISOString()\n\n // 使用获取到的文件信息构建返回数据\n return {\n data: paths.map((p) => {\n const info = fileInfoMap.get(p)\n return {\n name: info?.name,\n id: info?.id,\n bucket_id: info?.bucketId,\n owner: undefined, // 无法计算owner\n updated_at: info?.updatedAt || now,\n created_at: info?.createdAt,\n last_accessed_at: info?.lastAccessedAt || now,\n metadata: info?.metadata || {},\n /**\n * TODO: 获取补全 Bucket 信息\n */\n buckets: {\n id: info?.bucketId,\n name: info?.bucketId,\n owner: undefined, // 无法计算owner\n public: false, // 未知\n created_at: '', // 未知\n updated_at: now, // 未知\n },\n } as unknown as FileObject\n }),\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 列举文件。\n *\n * 与 Supabase `StorageFileApi.list(path?, options?: SearchOptions, parameters?)` 的差异:\n * - **未实现**:本实现直接抛 `Not implemented`,且**无任何参数**;Supabase 支持前缀路径、分页/排序选项与 fetch 参数。\n */\n async list() {\n throw new StorageError('Not implemented')\n }\n\n private getCloudPath(path: string): string {\n // 清理路径:移除首尾斜杠,合并多个斜杠\n const cleanPath = path.replace(/^\\/|\\/$/g, '').replace(/\\/+/g, '/')\n\n // 否则返回清理后的相对路径\n return cleanPath\n }\n\n private normalizeCloudId(path: string) {\n // 如果已经是 cloud:// 格式,直接返回\n if (/^cloud:\\/\\//.test(path)) {\n return path\n }\n const cleanPath = this.getCloudPath(path)\n\n // 如果设置了 bucketId,构建完整的 cloud:// 路径\n if (this.bucketId) {\n // 获取环境 ID\n const envId = this.config?.env || ''\n if (envId) {\n return `cloud://${envId}.${this.bucketId}/${cleanPath}`\n }\n } else {\n throw new StorageError('bucketId is not set')\n }\n }\n\n private toBase64(data: string) {\n return toBase64(data)\n }\n\n /**\n * 将 TransformOptions 转换为腾讯云数据万象的 imageMogr2 查询字符串\n *\n * 腾讯云数据万象使用 imageMogr2 接口进行图片处理,支持以下参数:\n * - /thumbnail/<Width>x<Height> - 缩放\n * - /format/<Format> - 格式转换\n * - /quality/<Quality> - 质量调整\n * - /rquality/<Quality> - 相对质量\n *\n * @param transform - Supabase TransformOptions\n * @returns 腾讯云数据万象的查询字符串\n *\n * @example\n * ```typescript\n * transformOptsToQueryString({ width: 300, height: 200, quality: 80, format: 'origin' })\n * // 返回: 'imageMogr2/thumbnail/300x200/quality/80'\n * ```\n */\n private transformOptsToQueryString(transform: TransformOptions): string {\n const params: string[] = ['imageMogr2']\n\n // 处理缩放参数\n if (transform.width || transform.height) {\n const width = transform.width || ''\n const height = transform.height || ''\n\n // 根据 resize 模式选择不同的缩放方式\n if (transform.resize === 'fill') {\n // fill: 强制缩放到指定尺寸,可能变形\n params.push(`thumbnail/${width}x${height}!`)\n } else if (transform.resize === 'contain') {\n // contain: 等比缩放,完整显示在指定尺寸内\n params.push(`thumbnail/${width}x${height}`)\n } else {\n // cover (默认): 等比缩放,填充指定尺寸,可能裁剪\n // 使用 /thumbnail/<Width>x<Height>^ 表示填充模式\n params.push(`thumbnail/${width}x${height}^`)\n }\n }\n\n // 处理格式转换\n // format: 'origin' 表示保持原格式,不传此参数\n if (transform.format && transform.format !== 'origin') {\n params.push(`format/${transform.format}`)\n }\n\n // 处理质量参数\n if (transform.quality !== undefined) {\n // 腾讯云数据万象的 quality 参数范围是 1-100\n const quality = Math.max(1, Math.min(100, transform.quality))\n params.push(`quality/${quality}`)\n }\n\n return params.join('/')\n }\n\n /**\n * 从 CloudBase fileID 中提取文件路径\n *\n * @param fileId - CloudBase fileID (格式: cloud://env-id.bucket/path/to/file.jpg)\n * @returns 提取的文件路径\n *\n * @example\n * ```typescript\n * extractPathFromFileId('cloud://test-env.test-bucket/images/photo.jpg')\n * // 返回: 'images/photo.jpg'\n *\n * extractPathFromFileId('cloud://test-env.test-bucket/file.txt')\n * // 返回: 'file.txt'\n * ```\n */\n private extractPathFromFileId(fileId: string): string {\n // fileID 格式: cloud://env-id.bucket/path/to/file.jpg\n // 需要提取第一个 / 后面的所有内容(包括 bucket 和路径)\n // 然后再提取 bucket 后面的路径部分\n\n // 移除 cloud:// 前缀\n const withoutProtocol = fileId.replace(/^cloud:\\/\\//, '')\n\n // 分割为 [env-id.bucket, path, to, file.jpg]\n const parts = withoutProtocol.split('/')\n\n if (parts.length < 2) {\n // 如果无法解析,返回完整的 fileID\n return fileId\n }\n\n // 移除第一部分(env-id.bucket),返回剩余路径\n return parts.slice(1).join('/')\n }\n\n /**\n * 从 CloudBase fileID 中提取 bucket 名称\n *\n * @param fileId - CloudBase fileID (格式: cloud://env-id.bucket/path/to/file.jpg)\n * @returns 提取的 bucket 名称\n *\n * @example\n * ```typescript\n * extractBucketFromFileId('cloud://test-env.test-bucket/images/photo.jpg')\n * // 返回: 'test-bucket'\n *\n * extractBucketFromFileId('cloud://prod-env.my-bucket/file.txt')\n * // 返回: 'my-bucket'\n * ```\n */\n private extractBucketFromFileId(fileId: string): string {\n // fileID 格式: cloud://env-id.bucket/path/to/file.jpg\n // 需要提取 env-id.bucket 中的 bucket 部分\n\n // 移除 cloud:// 前缀\n const withoutProtocol = fileId.replace(/^cloud:\\/\\//, '')\n\n // 分割为 [env-id.bucket, path, to, file.jpg]\n const parts = withoutProtocol.split('/')\n\n if (parts.length < 1) {\n // 如果无法解析,返回默认 bucket\n return ''\n }\n\n // 第一部分是 env-id.bucket,提取 bucket 部分\n // 格式: env-id.bucket 或 env-id.bucket-name\n const envAndBucket = parts[0]\n\n // 查找第一个点的位置\n const dotIndex = envAndBucket.indexOf('.')\n\n if (dotIndex === -1) {\n // 如果没有点,返回整个字符串\n return envAndBucket\n }\n\n // 返回点后面的部分(bucket 名称)\n return envAndBucket.substring(dotIndex + 1)\n }\n}\n"],"names":["module","exports","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","d","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","StorageError","_super","message","_this","this","__isStorageError","name","__extends","Error","isStorageError","error","StorageApiError","status","statusCode","toJSON","getBuffer","globalThis","Buffer","toBase64","data","buffer","from","toString","btoa","encodeObjectName","cleanName","split","map","segment","encodeURIComponent","join","originalError","STORAGE_API_PREFIX","handleOperation","fn","shouldThrowOnError","Promise","_a","sent","error_1","String","Http","ctx","request","gatewayOrigin","getBaseEndPoint","buildUrl","path","query","url","concat","qs","parts","keys","forEach","value","push","buildQueryString","includes","toFullUrl","maybeRelative","test","startsWith","send","opts","method","toUpperCase","isBodyless","headers","__assign","rawBody","body","json","JSON","stringify","fetch","withCredentials","signal","cache","res","unwrap","download","stream","_c","aborted","Number","_b","response","header","code","toStorageError","buildHeadersAndQuery","options","cacheNonce","StreamDownloadBuilder","then","onfulfilled","onrejected","execute","http","bucketId","parameters","_d","DownloadBuilder","asStream","_e","blob","error_2","DEFAULT_UPLOAD_OPTIONS","StorageFileApi","throwOnError","setHeader","trim","upload","fileBody","fileOptions","uploadOrUpdate","update","cleanPath","list","__awaiter","prefix","limit","cursor","withDelimiter","with_delimiter","sortBy","remove","paths","names","n","result","i","length","batch","slice","prefixes","deleted","Array","isArray","apply","copy","fromPath","toPath","buildCopyMoveHeaders","sourceKey","destinationKey","destinationBucket","copyMetadata","metadata","Key","move","info","encodePath","id","version","bucket_id","size","contentType","content_type","cacheControl","cache_control","etag","lastModified","last_modified","createdAt","created_at","exists","createSignedUrl","expiresIn","base","fullSignedURL","signedURL","appendUrlOptions","createSignedUrls","item","createSignedUploadUrl","upsert","fullURL","token","uploadToSignedUrl","buildUploadBody","fullPath","getPublicUrl","publicUrl","Boolean","Id","clean","replace","some","seg","isFormData","FormData","Blob","file","fields","extracted","extractFromFormData","form","append","source","fileCount","ignoredFields","console","warn","params","separator","FORBIDDEN_BUCKET_ID_PATTERN","assertValidBucketId","caller","forbidden","exec","StorageBucketApi","context","listBuckets","offset","sortColumn","sortOrder","search","getBucket","createBucket","public","type","file_size_limit","fileSizeLimit","allowed_mime_types","allowedMimeTypes","updateBucket","deleteBucket","getSdkName","ERRORS","INVALID_PARAMS","INVALID_SYNTAX","INVALID_OPERATION","OPERATION_FAIL","NETWORK_ERROR","UNKOWN_ERROR","adapter_interface_namespaceObject","y","AbstractSDKRequest","__WEBPACK_EXTERNAL_MODULE__cloudbase_adapter_interface_74717cc6__","AbstractStorage","x","isString","val","printWarn","msg","RUNTIME","WebRequest","config","timeout","timeoutMsg","restrictedMethods","post","put","reqMethod","toLowerCase","formData","responseType","window","URL","createObjectURL","fileName","decodeURIComponent","pathname","pop","link","document","createElement","href","setAttribute","style","display","appendChild","click","revokeObjectURL","removeChild","resolve","tempFilePath","abortController","AbortController","enableAbort","_timeout","abort","addEventListener","timer","setTimeout","clearTimeout","ok","reject","catch","text","onUploadProgress","realUrl","PROTOCOL","urlHasQuery","queryString","formatUrl","ajax","XMLHttpRequest","open","payload","once","setRequestHeader","onreadystatechange","readyState","arr","getAllResponseHeaders","headerMap_1","line","shift","parse","responseText","e","toQueryString","TcbCacheObject","root","tcbCacheObject","setItem","getItem","removeItem","clear","CloudbaseCache","persistence","platformInfo","storage","persistenceTag","adapter","primaryStorage","localStorage","createStorage","mode","setStore","content","setStoreAsync","getStore","process","tcb_token","indexOf","getStoreAsync","removeStore","removeStoreAsync","CloudbaseEvent","IErrorEvent","CloudbaseEventEmitter","listeners","on","listener","customeAddEventListener","off","index","splice","customRemoveEventListener","fire","event","ev","listens","target","_i","handlers_1","__spreadArray","navigator","userAgent","external_jwt_decode_namespaceObject","external_jwt_decode_x","default","__WEBPACK_EXTERNAL_MODULE_jwt_decode_b659f100__","jwtDecode","EUploadMethod","constants","COMMUNITY_SITE_URL","utils","isPalinObject","execCallback","err","catchErrorsDecorator","customInfo","title","messages","methodName","descriptor","COMPONENT_NAME","storageGateWay","customReqOpts","gateWay","objectId","signedHeader","authorization","uploadUrl","fileId","cloudObjectId","cosFileId","cloudObjectMeta","download_url","downloadUrl","convertedFileList","v","fileid","download_list","fileID","tempFileURL","fileList","delete_list","srcPath","src_path","dstPath","dst_path","overwrite","removeOriginal","remove_original","copy_list","MIME_BY_EXT","txt","html","htm","css","js","csv","xml","png","jpg","jpeg","gif","webp","svg","ico","pdf","zip","gz","mp4","webm","mp3","wav","inferContentType","m","ext","hasHeader","lower","k","toSignedHeader","reduce","CloudbaseStorage","isGateWay","endPointMode","uploadFile","callback","cloudPath","filePath","fileContent","uploadMethod","toLocaleLowerCase","isGateway","signedHeaders","uploadHeaders","byteLength","ArrayBuffer","isView","resolveUploadByteLength","getUploadMetadata","metadataResult","requestId","metaErr","putParams","commonParams","postParams","signature","success_action_status","isSuccess","uploadConfig","action","metaData","metaDataParam","err_1","deleteFile","fileList_1","fileid_list","getTempFileURL","fileList_2","max_age","maxAge","file_list","downloadFile","tmpUrlRes","tmpUrl","encodeURI","copyFile","fileList_3","getFileInfo","fileInfo","all","Headers","normalizedHeader_1","fileSize","parseInt","cloudId","mime","e_1","__decorate","className","Function","_f","ICloudbaseDeleteFileParams","_g","_h","_j","ICloudbaseGetTempFileURLParams","_k","_l","_m","ICloudbaseDownloadFileParams","_o","_p","_q","ICloudbaseCopyFileParams","_r","_s","_t","ClassicStorageFileApi","getCloudPath","uploadFileParams","_token","signedUrl","error_3","error_4","normalizeCloudId","queryParams","transform","transformQuery","transformOptsToQueryString","error_5","p","error_6","signedUrlResult","reqClass","error_7","pathOrFileId","isFileId","displayName","extractPathFromFileId","extractBucketFromFileId","now","Date","toISOString","updatedAt","lastAccessedAt","error_8","error_9","chunkSize_1","pathChunks","chunk","fileInfoResults","fileInfoMap_1","Map","chunkResults","chunkIndex","set","failedFiles","filter","now_1","owner","updated_at","last_accessed_at","buckets","error_10","envId","env","width","height","resize","format","quality","Math","max","min","envAndBucket","dotIndex","substring","component","entity","StorageClient","supabaseComponent","IIFE","storageCache","WeakMap","has","instance","Proxy","_target","configurable","cloudbase","registerComponent","registerStorage","app","registerStorageOrigin"],"sourceRoot":""}
1
+ {"version":3,"file":"index.esm.js","mappings":"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","sources":["webpack://@cloudbase/js-sdk/./empty-module.js","webpack://@cloudbase/js-sdk/webpack/bootstrap","webpack://@cloudbase/js-sdk/webpack/runtime/define property getters","webpack://@cloudbase/js-sdk/webpack/runtime/hasOwnProperty shorthand","webpack://@cloudbase/js-sdk/errors.ts/","webpack://@cloudbase/js-sdk/encoding.ts/","webpack://@cloudbase/js-sdk/http.ts/","webpack://@cloudbase/js-sdk/download-builder.ts/","webpack://@cloudbase/js-sdk/storage-file-api-neo.ts/","webpack://@cloudbase/js-sdk/validation.ts/","webpack://@cloudbase/js-sdk/storage-bucket-api-neo.ts/","webpack://@cloudbase/js-sdk/common.ts/","webpack://@cloudbase/js-sdk/external module \"@cloudbase/adapter-interface\"","webpack://@cloudbase/js-sdk/util.ts/","webpack://@cloudbase/js-sdk/index.ts/","webpack://@cloudbase/js-sdk/web.ts/","webpack://@cloudbase/js-sdk/cache.ts/","webpack://@cloudbase/js-sdk/events.ts/","webpack://@cloudbase/js-sdk/langEvent.ts/","webpack://@cloudbase/js-sdk/decorators.ts/","webpack://@cloudbase/js-sdk/external module \"jwt-decode\"","webpack://@cloudbase/js-sdk/cloudbase-storage.ts/","webpack://@cloudbase/js-sdk/storage-file-api-classic.ts/"],"sourcesContent":["// 空模块占位文件,用于 webpack 解析纯类型包(@cloudbase/types)的子路径引用\n// 这些引用只有 TypeScript 类型,编译后会被擦除,运行时不需要任何内容\nmodule.exports = {}\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","export class StorageError extends Error {\n protected __isStorageError = true\n\n constructor(message: string) {\n super(message)\n this.name = 'StorageError'\n }\n}\n\nexport function isStorageError(error: unknown): error is StorageError {\n return typeof error === 'object' && error !== null && '__isStorageError' in error\n}\n\nexport class StorageApiError extends StorageError {\n status: number\n statusCode: string\n\n constructor(message: string, status: number, statusCode: string) {\n super(message)\n this.name = 'StorageApiError'\n this.status = status\n this.statusCode = statusCode\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n statusCode: this.statusCode,\n }\n }\n}\n\nexport class StorageUnknownError extends StorageError {\n originalError: unknown\n\n constructor(message: string, originalError: unknown) {\n super(message)\n this.name = 'StorageUnknownError'\n this.originalError = originalError\n }\n}\n","type BufferLike = {\n byteLength(data: string): number\n from(data: string): { toString(encoding: 'base64'): string }\n}\n\ntype GlobalWithBuffer = typeof globalThis & {\n Buffer?: BufferLike\n}\n\nfunction getBuffer(): BufferLike | undefined {\n return (globalThis as GlobalWithBuffer).Buffer\n}\n\nexport function getStringByteLength(data: string): number | undefined {\n return getBuffer()?.byteLength(data)\n}\n\nexport function toBase64(data: string): string {\n const buffer = getBuffer()\n if (buffer) {\n return buffer.from(data).toString('base64')\n }\n return btoa(data)\n}\n\n/**\n * 对对象名按 `/` 分段做 URL 编码(保留路径分隔符)。\n *\n * 用于把 Bucket 内相对路径安全地拼进 URL path,避免空格、`#`、`?`、`%`、中文等字符\n * 破坏或截断 URL(query 段已单独编码,此处仅处理 path 段)。仅对每段做 `encodeURIComponent`,\n * 不编码分隔符 `/`,与 supabase-js 的处理方式一致。\n *\n * @param cleanName 已由 `cleanPath` 规整过的相对路径(无首尾斜杠、无重复斜杠)。\n */\nexport function encodeObjectName(cleanName: string): string {\n return cleanName\n .split('/')\n .map(segment => encodeURIComponent(segment))\n .join('/')\n}\n","import { StorageApiError, StorageError, isStorageError } from './supabase/errors'\nimport { Result, FetchParameters } from './types'\n\n/**\n * 客户端运行上下文:`{ config, request }`。\n */\nexport interface Context {\n config: any\n request: any\n}\n\n/** 网关相对前缀:GATEWAY base 已含 `/v1`,原始 fetch 用 origin,需补 `/v1/storages`。 */\nconst STORAGE_API_PREFIX = '/v1/storages'\n\nfunction buildQueryString(query?: Record<string, any>): string {\n if (!query) return ''\n const parts: string[] = []\n Object.keys(query).forEach((key) => {\n const value = query[key]\n if (value === undefined || value === null) return\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)\n })\n return parts.join('&')\n}\n\n/**\n * 统一执行操作并返回 `{ data, error }`;`throwOnError` 开启时失败抛异常,成功仍返回 `{ data, error: null }`。\n */\nexport async function handleOperation<T>(fn: () => Promise<T>, shouldThrowOnError: boolean): Promise<Result<T>> {\n try {\n const data = await fn()\n return { data, error: null }\n } catch (error: any) {\n if (shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return { data: null, error }\n }\n return { data: null, error: new StorageError(error?.message || String(error)) }\n }\n}\n\n/**\n * Storage HTTP 请求封装。\n *\n * - JSON 端点:`request.fetch`(自动注入 `Authorization`,`shouldThrowOnError: false` 以便手动解析错误码)。\n * - Blob 下载:`reqClass.get`(避免 Node 适配器 `fetch` 强制 `res.json()` 破坏二进制流)。\n */\nexport class Http {\n constructor(public readonly ctx: Context) {}\n\n private get request() {\n return this.ctx.request\n }\n\n /** 网关 origin(如 `https://{env}.api.tcloudbasegateway.com`,不含 `/v1`)。 */\n gatewayOrigin(): string {\n return this.request.getBaseEndPoint('GATEWAY')\n }\n\n /** 拼接完整 API URL。 */\n buildUrl(path: string, query?: Record<string, any>): string {\n let url = `${this.gatewayOrigin()}${STORAGE_API_PREFIX}${path}`\n const qs = buildQueryString(query)\n if (qs) {\n url += (url.includes('?') ? '&' : '?') + qs\n }\n return url\n }\n\n /** 把后端返回的相对 `signedURL` 拼成完整 URL。 */\n toFullUrl(maybeRelative: string): string {\n if (!maybeRelative) return maybeRelative\n if (/^https?:\\/\\//.test(maybeRelative) || maybeRelative.startsWith('//')) {\n return maybeRelative\n }\n return `${this.gatewayOrigin()}${STORAGE_API_PREFIX}${maybeRelative.startsWith('/') ? '' : '/'}${maybeRelative}`\n }\n\n /** JSON / 表单 / 二进制请求,返回解析后的 body;非 2xx 抛 StorageApiError。 */\n async send<T = any>(opts: {\n method: string\n path: string\n /** JSON body(会被 stringify)。与 rawBody 互斥。 */\n json?: any\n /** 原始 body(FormData / Blob / 二进制 / 字符串),用于上传。 */\n rawBody?: any\n headers?: Record<string, string>\n query?: Record<string, any>\n /** 是否携带登录态,默认 true。签名上传 / 公开下载传 false。 */\n withCredentials?: boolean\n /** 请求取消信号,透传给底层 fetch。 */\n signal?: AbortSignal\n /** fetch 缓存策略,透传给底层 fetch。 */\n cache?: FetchParameters['cache']\n }): Promise<T> {\n const url = this.buildUrl(opts.path, opts.query)\n const method = opts.method.toUpperCase()\n const isBodyless = ['GET', 'HEAD'].includes(method)\n\n const headers: Record<string, string> = { ...(opts.headers || {}) }\n let body: any\n if (!isBodyless) {\n if (opts.rawBody !== undefined) {\n body = opts.rawBody\n } else if (opts.json !== undefined) {\n headers['Content-Type'] = headers['Content-Type'] || 'application/json'\n body = JSON.stringify(opts.json)\n }\n }\n\n const res = await this.request.fetch({\n url,\n method,\n headers,\n ...(body !== undefined ? { body } : {}),\n withCredentials: opts.withCredentials !== false,\n shouldThrowOnError: false,\n ...(opts.signal ? { signal: opts.signal } : {}),\n ...(opts.cache ? { cache: opts.cache } : {}),\n })\n\n return this.unwrap<T>(res, url)\n }\n\n /**\n * 下载,返回原始 `Response`。走 `request.fetch({ stream: true })` 让适配器透出未消费的原生 `Response`。\n *\n * 上层按终态决定如何消费——`response.blob()` 得 `Blob`,或 `response.body` 得 `ReadableStream`。\n *\n * @remarks 依赖底层适配器 `fetch` 透出 `response`(web / Node 适配器均已支持)。\n */\n async download(opts: {\n path: string\n headers?: Record<string, string>\n query?: Record<string, any>\n withCredentials?: boolean\n /** 请求取消信号,透传给底层 fetch。 */\n signal?: AbortSignal\n /** fetch 缓存策略,透传给底层 fetch。 */\n cache?: FetchParameters['cache']\n }): Promise<{ response: Response; status: number; header: any }> {\n const url = this.buildUrl(opts.path, opts.query)\n\n const res = await this.request.fetch({\n url,\n method: 'GET',\n headers: { ...(opts.headers || {}) },\n stream: true,\n withCredentials: opts.withCredentials !== false,\n shouldThrowOnError: false,\n ...(opts.signal ? { signal: opts.signal } : {}),\n ...(opts.cache ? { cache: opts.cache } : {}),\n })\n\n // signal 被中断时,底层可能 resolve 出空响应;这里显式抛出中断错误,避免误判为成功。\n if (opts.signal?.aborted) {\n throw new StorageApiError('The download was aborted', 0, 'STORAGE_PG_ABORTED')\n }\n\n const status = Number(res?.statusCode ?? 200)\n if (status === 304) {\n throw new StorageApiError('Not Modified', status, 'STORAGE_PG_NOT_MODIFIED')\n }\n if (status >= 400) {\n throw new StorageApiError(`Download failed with status ${status}`, status, 'STORAGE_PG_REQUEST_FAIL')\n }\n\n const response: Response = res?.response\n if (!response) {\n throw new StorageApiError('Underlying adapter did not expose the raw Response', status, 'STORAGE_PG_NO_RESPONSE')\n }\n return { response, status, header: res?.header }\n }\n\n private async unwrap<T>(res: any, url: string): Promise<T> {\n const status = Number(res?.statusCode ?? res?.status ?? 200)\n let body = res?.data\n try {\n body = await body\n } catch (e) {\n body = undefined\n }\n\n if (status >= 200 && status < 300) {\n return body as T\n }\n\n // 兼容两类错误体:ErrorResponse { code, message, requestId } 与 StreamErrorResponse { statusCode, error, message }\n const code = body?.code || body?.error || 'STORAGE_PG_REQUEST_FAIL'\n const message = body?.message || `Storage request failed with status ${status}: ${url}`\n throw new StorageApiError(message, status, code)\n }\n}\n","import { StorageError, StorageApiError, isStorageError } from './supabase/errors'\nimport { encodeObjectName } from './encoding'\nimport { Http } from './http'\nimport { Result, DownloadOptions, FetchParameters } from './types'\n\n/** 把任意错误规整为 `StorageError`。 */\nfunction toStorageError(error: any): StorageError {\n return isStorageError(error) ? error : new StorageError(error?.message || String(error))\n}\n\n/** 下载构建器内部共享上下文。 */\nexport interface DownloadContext {\n http: Http\n bucketId: string\n cleanName: string\n options?: DownloadOptions\n parameters?: FetchParameters\n /** 调用方实例级自定义请求头,会并入下载请求(条件请求头优先级更高)。 */\n headers?: Record<string, string>\n shouldThrowOnError: boolean\n}\n\n/** 由下载选项构建条件请求头与 query。 */\nfunction buildHeadersAndQuery(options?: DownloadOptions): {\n headers: Record<string, string>\n query: Record<string, any>\n} {\n const query: Record<string, any> = {}\n if (options?.download !== undefined) {\n query.download = options.download === true ? '' : options.download\n }\n if (options?.cacheNonce !== undefined) {\n query.cacheNonce = String(options.cacheNonce)\n }\n return { headers: {}, query }\n}\n\n/**\n * 流式下载构建器(两阶段下载的「流」终态)。\n *\n * 实现 `PromiseLike`,可直接 `await`,resolve 为 `Result<ReadableStream>`。\n * 由 `DownloadBuilder.asStream()` 创建,直接返回原生 `Response.body`。\n */\nexport class StreamDownloadBuilder implements PromiseLike<Result<ReadableStream<Uint8Array>>> {\n constructor(private ctx: DownloadContext) {}\n\n then<TResult1 = Result<ReadableStream<Uint8Array>>, TResult2 = never>(\n onfulfilled?: ((value: Result<ReadableStream<Uint8Array>>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n\n private async execute(): Promise<Result<ReadableStream<Uint8Array>>> {\n try {\n const { headers, query } = buildHeadersAndQuery(this.ctx.options)\n const { response } = await this.ctx.http.download({\n path: `/object/${this.ctx.bucketId}/${encodeObjectName(this.ctx.cleanName)}`,\n headers: { ...this.ctx.headers, ...headers },\n query,\n signal: this.ctx.parameters?.signal,\n cache: this.ctx.parameters?.cache,\n })\n if (!response.body) {\n throw new StorageApiError('Response body is empty', response.status, 'STORAGE_PG_EMPTY_BODY')\n }\n return { data: response.body, error: null }\n } catch (error: any) {\n if (this.ctx.shouldThrowOnError) throw error\n return { data: null, error: toStorageError(error) }\n }\n }\n}\n\n/**\n * 下载构建器(thenable)。\n *\n * 默认终态为 `Blob`:直接 `await bucket.download(path)` 即得 `Result<Blob>`,\n * 调用方式与返回普通 Promise 完全一致(惰性执行,`await` / `.then()` 时才真正发请求)。\n *\n * 链式 `.asStream()` 切换为流式终态,返回 `StreamDownloadBuilder`(resolve 为 `Result<ReadableStream>`)。\n * 此设计对齐 Supabase `download().asStream()` 的使用效果,但实现为自有的轻量 thenable,不依赖其内部类。\n *\n * @example\n * ```ts\n * // 默认:Blob\n * const { data: blob } = await bucket.download('a.png')\n * // 流式:ReadableStream(适合 Node 大文件,避免整体读入内存)\n * const { data: stream } = await bucket.download('big.zip').asStream()\n * ```\n */\nexport class DownloadBuilder implements PromiseLike<Result<Blob>> {\n constructor(private ctx: DownloadContext) {}\n\n /** 切换为流式下载终态,返回 `StreamDownloadBuilder`。 */\n asStream(): StreamDownloadBuilder {\n return new StreamDownloadBuilder(this.ctx)\n }\n\n then<TResult1 = Result<Blob>, TResult2 = never>(\n onfulfilled?: ((value: Result<Blob>) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,\n ): PromiseLike<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n\n private async execute(): Promise<Result<Blob>> {\n try {\n const { headers, query } = buildHeadersAndQuery(this.ctx.options)\n const { response } = await this.ctx.http.download({\n path: `/object/${this.ctx.bucketId}/${encodeObjectName(this.ctx.cleanName)}`,\n headers: { ...this.ctx.headers, ...headers },\n query,\n signal: this.ctx.parameters?.signal,\n cache: this.ctx.parameters?.cache,\n })\n // 直接复用原生 Response.blob()(与 Supabase 一致),content-type 由 Response 自动保留。\n return { data: await response.blob(), error: null }\n } catch (error: any) {\n if (this.ctx.shouldThrowOnError) throw error\n return { data: null, error: toStorageError(error) }\n }\n }\n}\n","import { StorageError } from './supabase/errors'\nimport { toBase64, encodeObjectName } from './encoding'\nimport { Http, handleOperation } from './http'\nimport { DownloadBuilder } from './download-builder'\nimport {\n FileBody,\n Result,\n UploadOptions,\n UploadResult,\n DownloadOptions,\n ListOptions,\n ListObjectsResponse,\n ObjectInfo,\n FullObject,\n DestinationOptions,\n SignedUrlOptions,\n SignedUrlResult,\n SignedUrlsResultItem,\n CreateSignedUploadUrlResult,\n PublicUrlOptions,\n FetchParameters,\n} from './types'\n\nconst DEFAULT_UPLOAD_OPTIONS: UploadOptions = {\n cacheControl: '3600',\n contentType: 'text/plain;charset=UTF-8',\n upsert: false,\n}\n\n/** 批量删除单次上限。 */\nconst REMOVE_BATCH_LIMIT = 100\n/** 批量签名单次上限。 */\nconst SIGN_BATCH_LIMIT = 500\n\n/** 从 FormData 中提取出的、服务端支持的元信息字段(值为原始字符串)。 */\ninterface UploadFormFields {\n cacheControl?: string\n contentType?: string\n metadata?: string\n}\n\n/**\n * 单 Bucket 对象操作客户端。\n *\n * 通过 `app.storage.from(bucketId)` 获取。所有 `objectName` 均为 Bucket 内相对路径,\n * 走 `/v1/storages/object/{bucketId}/{name}` 通道,权限由 `storage.objects` / `storage.buckets`\n * 的 RLS 策略判定。\n */\nexport class StorageFileApi {\n public readonly bucketId: string\n private http: Http\n private shouldThrowOnError: boolean\n /** 实例级自定义请求头,对该实例后续所有请求生效(见 setHeader)。对齐 Supabase 的 `this.headers`。 */\n private headers: Record<string, string> = {}\n\n constructor(http: Http, bucketId: string, shouldThrowOnError = false) {\n this.http = http\n this.bucketId = bucketId\n this.shouldThrowOnError = shouldThrowOnError\n }\n\n /** 启用错误抛出模式。开启后请求失败会抛异常;请求成功仍返回 `{ data, error: null }`。 */\n throwOnError(): this {\n this.shouldThrowOnError = true\n return this\n }\n\n /**\n * 设置自定义请求头(链式)。\n *\n * 对齐 Supabase `BaseApiClient.setHeader`:设置后对**当前实例**后续的所有请求生效。\n * 单次请求内部使用的功能性头(如上传的 `Content-Type` / `x-upsert`)优先级更高,会覆盖此处同名头。\n *\n * 每个 `from(bucketId)` 返回独立实例(持有自定义头的独立副本),互不影响;返回 `this` 以支持链式调用。\n *\n * @param name 请求头名称,非空字符串。\n * @param value 请求头值。\n * @throws 当 name 为空,或 name/value 含 CR/LF(防止请求头注入)时抛 `StorageError`。\n */\n setHeader(name: string, value: string): this {\n if (typeof name !== 'string' || name.trim() === '') {\n throw new StorageError('setHeader requires a non-empty header name')\n }\n if (/[\\r\\n]/.test(name) || (typeof value === 'string' && /[\\r\\n]/.test(value))) {\n throw new StorageError('setHeader does not allow CR/LF characters in header name or value')\n }\n // 写时复制:仅改动当前实例自己的头表,对齐 Supabase 语义。\n this.headers = { ...this.headers, [name]: String(value) }\n return this\n }\n\n /**\n * 直接上传对象,默认不覆盖同名对象。\n *\n * 需要当前用户已登录(携带 Authorization header),适合**服务端或可信客户端**直接上传。\n * 权限由 `storage.objects` 表的 RLS `INSERT` / `UPDATE` 策略判定。\n *\n * 上传行为:\n * - `fileOptions.upsert` 默认 `false`:目标路径已有对象时,上传失败。\n * - `fileOptions.upsert` 设为 `true`:目标路径已有对象时,覆盖写入。\n * - 成功时返回 `{ id, path, fullPath }`,其中 `fullPath` 为 `bucketId/objectName`。\n *\n * 如需让**不受信客户端**(如浏览器前端)上传文件,应改用 `createSignedUploadUrl` + `uploadToSignedUrl` 组合,\n * 服务端先生成临时签名 token,客户端凭 token 上传,无需暴露登录凭证。\n *\n * @param path Bucket 内相对路径。\n * @param fileBody 文件内容。\n * @param fileOptions 上传选项,如 `contentType`、`cacheControl`、`upsert`、`metadata`。\n * @see createSignedUploadUrl uploadToSignedUrl\n */\n async upload(path: string, fileBody: FileBody, fileOptions?: UploadOptions): Promise<Result<UploadResult>> {\n return this.uploadOrUpdate('POST', path, fileBody, fileOptions)\n }\n\n /**\n * 覆盖更新对象。\n *\n * 与 `upload` 共享同一底层,区别:\n * - 使用 `PUT` 方法(语义为覆盖),不追加 `x-upsert` 头。\n * - 目标路径不存在时也会创建(upsert 行为,与后端实现有关)。\n * - 成功时返回 `{ id, path, fullPath }`。\n *\n * @param path Bucket 内相对路径。\n * @param fileBody 文件内容。\n * @param fileOptions 上传选项,如 `contentType`、`cacheControl`、`metadata`。\n */\n async update(path: string, fileBody: FileBody, fileOptions?: UploadOptions): Promise<Result<UploadResult>> {\n return this.uploadOrUpdate('PUT', path, fileBody, fileOptions)\n }\n\n /**\n * 下载对象。返回**下载构建器**(thenable),默认 `await` 得到 `Blob`。\n *\n * 需要登录态,权限由 `storage.objects` 的 RLS `SELECT` 策略判定。\n *\n * 两种终态(对齐 Supabase `download().asStream()` 的使用效果):\n * - 默认:`await bucket.download(path)` → `Result<Blob>`。\n * - 流式:`await bucket.download(path).asStream()` → `Result<ReadableStream>`,适合 Node 大文件等\n * 不希望整体读入内存的场景。\n *\n * 两者统一走原生 `fetch` 的 `Response`:流式终态返回 `Response.body`,Blob 终态调 `Response.blob()`。\n *\n * 下载行为:\n * - 惰性执行:请求在 `await` / `.then()` 时才真正发出。\n * - 返回的 `Blob` 不会自动触发浏览器下载或渲染,需配合 `URL.createObjectURL` 手动处理。\n * - 支持 `parameters.signal`(AbortSignal)取消进行中的下载。\n *\n * @param path Bucket 内相对路径。\n * @param options 下载选项,支持 `download`(触发浏览器下载)、`cacheNonce`(绕过 CDN 缓存)。\n * @param parameters 请求控制参数,支持 `signal` / `cache`。\n * @returns `DownloadBuilder`:可 `await` 得 `Result<Blob>`,或 `.asStream()` 后得 `Result<ReadableStream>`。\n */\n download(\n path: string,\n options?: DownloadOptions,\n parameters?: FetchParameters,\n ): DownloadBuilder {\n return new DownloadBuilder({\n http: this.http,\n bucketId: this.bucketId,\n cleanName: this.cleanPath(path),\n options,\n parameters,\n headers: this.headers,\n shouldThrowOnError: this.shouldThrowOnError,\n })\n }\n\n /**\n * 获取对象列表(游标分页)。\n *\n * 列出 Bucket 下指定前缀的对象和文件夹。采用**游标分页**,与 Supabase 的 `listV2` 对应。\n *\n * - 首次查询不传 `cursor`,后续用上一页的 `nextCursor` 传入继续翻页。\n * - 返回 `{ folders, objects, hasNext, nextCursor }`(区别于 Supabase `list` 的 offset 分页 `FileObject[]`)。\n * - `path` 不传或为空时列出 Bucket 根目录。\n * - `options.withDelimiter` 为 `true` 时,以 `/` 为分隔符将文件夹和文件分开。\n * - `options.sortBy` 支持按 `name`、`created_at`、`updated_at` 排序。\n *\n * @param path 路径前缀,不传表示 Bucket 根目录。\n * @param options 列表选项,支持 `limit`、`cursor`、`withDelimiter`、`sortBy`。\n * @param parameters 请求控制参数,支持 `signal` / `cache`。\n * @remarks 本方法对应 Supabase 的 `listV2`(游标分页),而非 `list`(offset 分页)。\n */\n async list(path?: string, options?: ListOptions, parameters?: FetchParameters): Promise<Result<ListObjectsResponse>> {\n return handleOperation(async () => {\n const body: Record<string, any> = { prefix: path || '' }\n if (options?.limit !== undefined) body.limit = options.limit\n if (options?.cursor !== undefined) body.cursor = options.cursor\n if (options?.withDelimiter !== undefined) body.with_delimiter = options.withDelimiter\n if (options?.sortBy !== undefined) body.sortBy = options.sortBy\n\n return this.send<ListObjectsResponse>({\n method: 'POST',\n path: `/object/list/${this.bucketId}`,\n json: body,\n signal: parameters?.signal,\n cache: parameters?.cache,\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 删除一个或多个对象。\n *\n * 权限由 `storage.objects` 的 RLS `DELETE` 策略判定。\n *\n * - 后端单次最多删除 100 个对象,超出时 SDK 自动分批发送。\n * - 返回所有被成功删除的对象信息(`FullObject[]`)。\n *\n * @param paths Bucket 内相对路径数组。\n */\n async remove(paths: string[]): Promise<Result<FullObject[]>> {\n return handleOperation(async () => {\n const names = paths.map(n => this.cleanPath(n))\n const result: FullObject[] = []\n for (let i = 0; i < names.length; i += REMOVE_BATCH_LIMIT) {\n const batch = names.slice(i, i + REMOVE_BATCH_LIMIT)\n const deleted = await this.send<FullObject[]>({\n method: 'DELETE',\n path: `/object/${this.bucketId}`,\n json: { prefixes: batch },\n })\n if (Array.isArray(deleted)) result.push(...deleted)\n }\n return result\n }, this.shouldThrowOnError)\n }\n\n /**\n * 复制对象,支持跨 Bucket。\n *\n * 权限由 `storage.objects` 的 RLS 策略判定:读取源需要 `SELECT` 权限,写入目标需要 `INSERT` 权限。\n *\n * 复制行为:\n * - `options.destinationBucket` 不传时在同一 Bucket 内复制;传入时跨 Bucket 复制。\n * - `options.upsert` 为 `true` 时,目标路径已有对象则覆盖;否则复制失败。\n * - `options.copyMetadata` 默认为 `undefined`(由服务端决定是否复制原 metadata)。\n * 设为 `false` 并传 `options.metadata` 时,用新 metadata 替换原对象的 metadata。\n * - 返回目标对象的完整路径 `bucketId/objectName`。\n *\n * @param fromPath 源对象 Bucket 内相对路径。\n * @param toPath 目标对象相对路径。\n * @param options 目标 Bucket、覆盖、元数据复制等选项。\n */\n async copy(fromPath: string, toPath: string, options?: DestinationOptions): Promise<Result<{ path: string }>> {\n return handleOperation(async () => {\n const headers = this.buildCopyMoveHeaders(options)\n const data = await this.send<{ Key: string }>({\n method: 'POST',\n path: '/object/copy',\n json: {\n bucketId: this.bucketId,\n sourceKey: this.cleanPath(fromPath),\n destinationKey: this.cleanPath(toPath),\n destinationBucket: options?.destinationBucket,\n copyMetadata: options?.copyMetadata,\n metadata: options?.metadata,\n },\n headers,\n })\n return { path: data.Key }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 移动对象,支持跨 Bucket;源对象会被删除。\n *\n * 语义为\"复制到目标 → 删除源\",非原地重命名。跨 Bucket 时源 Bucket 的对象会被删除。\n * 权限由 `storage.objects` 的 RLS 策略判定:读取源需要 `SELECT`,写入目标需要 `INSERT`,删除源需要 `DELETE`。\n *\n * 移动行为:\n * - `options.destinationBucket` 不传时在同一 Bucket 内移动。\n * - 成功时返回 `{ message: 'Successfully moved' }`。\n *\n * @param fromPath 源对象 Bucket 内相对路径。\n * @param toPath 目标对象相对路径。\n * @param options 目标 Bucket 等选项。\n */\n async move(fromPath: string, toPath: string, options?: DestinationOptions): Promise<Result<{ message: string }>> {\n return handleOperation(async () => {\n const data = await this.send<{ message: string }>({\n method: 'POST',\n path: '/object/move',\n json: {\n bucketId: this.bucketId,\n sourceKey: this.cleanPath(fromPath),\n destinationKey: this.cleanPath(toPath),\n destinationBucket: options?.destinationBucket,\n },\n })\n return { message: data.message || 'Successfully moved' }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 获取对象元信息。\n *\n * 返回对象在 `storage.objects` 表中的记录信息,包括 `bucketId`、`version`、`etag`、\n * `contentType`、`cacheControl`、`metadata`、`lastModified`、`createdAt` 等。\n *\n * - 对象不存在时返回 `{ data: null, error: StorageError }`。\n *\n * @param path Bucket 内相对路径。\n */\n async info(path: string): Promise<Result<ObjectInfo>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const data = await this.send<any>({\n method: 'GET',\n path: `/object/info/${this.bucketId}/${this.encodePath(cleanName)}`,\n })\n return {\n id: data.id,\n name: data.name,\n version: data.version,\n bucketId: data.bucket_id,\n size: data.size,\n contentType: data.content_type,\n cacheControl: data.cache_control,\n etag: data.etag,\n metadata: data.metadata,\n lastModified: data.last_modified,\n createdAt: data.created_at,\n }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 判断对象是否存在。\n *\n * 底层调用 `info` 端点:\n * - 后端返回 HTTP 200 → 存在(返回 `true`)。\n * - 后端返回 HTTP 400 或 404 → 不存在(返回 `false`)。\n * - 其他异常(如 500)→ 返回 `{ data: null, error }`。\n *\n * @param path Bucket 内相对路径。\n */\n async exists(path: string): Promise<Result<boolean>> {\n try {\n const cleanName = this.cleanPath(path)\n await this.send<any>({\n method: 'GET',\n path: `/object/info/${this.bucketId}/${this.encodePath(cleanName)}`,\n })\n return { data: true, error: null }\n } catch (error: any) {\n const status = (error as any)?.status\n if (status !== undefined && [400, 404].includes(Number(status))) {\n return { data: false, error: null }\n }\n if (this.shouldThrowOnError) throw error\n return { data: null, error: error instanceof StorageError ? error : new StorageError(error?.message || String(error)) }\n }\n }\n\n /**\n * 生成单个签名下载 URL。\n *\n * 需要登录态,权限由 `storage.objects` 的 RLS `SELECT` 策略判定。\n *\n * 签名 URL 行为:\n * - `expiresIn` 以秒为单位,过期后 URL 不可用。\n * - 返回的 `fullSignedURL` 是服务端已拼接好的完整 URL,客户端可直接使用(无需再拼 HOST)。\n * - `options.download` 为 `true` 时在 URL 后追加 `?download`,浏览器访问时自动触发下载;\n * 传字符串时指定下载文件名(`?download=<filename>`)。\n * - 不支持图片 `transform` 转换选项。\n *\n * @param path Bucket 内相对路径。\n * @param expiresIn 过期时间,单位为秒。\n * @param options 签名下载 URL 选项;当前仅支持 `download`,不支持图片 `transform`。\n */\n async createSignedUrl(\n path: string,\n expiresIn: number,\n options?: SignedUrlOptions,\n ): Promise<Result<SignedUrlResult>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const data = await this.send<{ signedURL?: string; fullSignedURL?: string }>({\n method: 'POST',\n path: `/object/sign/${this.bucketId}/${this.encodePath(cleanName)}`,\n json: { expiresIn },\n })\n const base = data.fullSignedURL || this.http.toFullUrl(data.signedURL || '')\n return { fullSignedURL: this.appendUrlOptions(base, options) }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 为多个对象批量生成签名下载 URL。\n *\n * 需要登录态,权限由 `storage.objects` 的 RLS `SELECT` 策略判定。\n *\n * 批量签名行为:\n * - 后端单次最多 500 个,超出时 SDK 自动分批发送。\n * - 返回数组中每个元素包含 `path`(请求路径)、`fullSignedURL`(完整签名 URL,生成失败时为 `null`)、`error`。\n * - 部分路径生成失败不会影响其他路径,失败的项 `fullSignedURL` 为 `null`,`error` 为错误信息。\n * - `options.download` 为 `true` 时在 URL 后追加 `?download` 参数。\n *\n * @param paths Bucket 内相对路径数组。\n * @param expiresIn 过期时间,单位为秒。\n * @param options 签名下载 URL 选项;当前仅支持 `download`,不支持图片 `transform`。\n */\n async createSignedUrls(\n paths: string[],\n expiresIn: number,\n options?: SignedUrlOptions,\n ): Promise<Result<SignedUrlsResultItem[]>> {\n return handleOperation(async () => {\n const names = paths.map(n => this.cleanPath(n))\n const result: SignedUrlsResultItem[] = []\n for (let i = 0; i < names.length; i += SIGN_BATCH_LIMIT) {\n const batch = names.slice(i, i + SIGN_BATCH_LIMIT)\n const data = await this.send<Array<{ path: string; signedURL?: string | null; fullSignedURL?: string | null; error?: string | null }>>({\n method: 'POST',\n path: `/object/sign/${this.bucketId}`,\n json: { expiresIn, paths: batch },\n })\n data.forEach((item) => {\n const base = item.fullSignedURL || (item.signedURL ? this.http.toFullUrl(item.signedURL) : null)\n result.push({\n path: item.path,\n fullSignedURL: base ? this.appendUrlOptions(base, options) : null,\n error: item.error ?? null,\n })\n })\n }\n return result\n }, this.shouldThrowOnError)\n }\n\n /**\n * 两阶段上传(第一阶段):生成签名上传 URL,需登录态。\n *\n * 服务端基于调用者身份 + RLS 策略判断是否有 `INSERT` 权限,生成临时签名 URL 和 token。\n * 适合的场景:服务端鉴定用户权限后,将 `token` 下发给**不受信客户端**(如浏览器前端),\n * 让客户端用 `uploadToSignedUrl` 直接上传文件,无需暴露登录凭证。\n *\n * 签名上传 URL 行为:\n * - 返回的 `fullSignedURL` 是服务端已拼接好的完整上传 URL,客户端可直接使用。\n * - 返回的 `token` 是临时凭证,与 `uploadToSignedUrl` 配合使用。\n * - `options.upsert` 为 `true` 时,目标路径已有对象时允许覆盖。\n * - 与 `upload` 的区别:\n * - `upload`:一步完成,需登录态,适合服务端/可信客户端直接上传。\n * - `createSignedUploadUrl` + `uploadToSignedUrl`:**两阶段上传**——第一阶段需登录态生成 token,\n * 第二阶段无需登录态(凭 token 鉴权),适合浏览器直传、第三方上报等场景。\n *\n * @param path Bucket 内相对路径。\n * @param options 签名上传选项,`upsert=true` 时允许覆盖。\n * @see upload uploadToSignedUrl\n */\n async createSignedUploadUrl(\n path: string,\n options?: { upsert?: boolean },\n ): Promise<Result<CreateSignedUploadUrlResult>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const headers: Record<string, string> = {}\n if (options?.upsert) headers['x-upsert'] = 'true'\n\n const data = await this.send<{ url?: string; fullURL?: string; token: string }>({\n method: 'POST',\n path: `/object/upload/sign/${this.bucketId}/${this.encodePath(cleanName)}`,\n headers,\n })\n const fullSignedURL = data.fullURL || this.http.toFullUrl(data.url || '')\n return { fullSignedURL, path: cleanName, token: data.token }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 两阶段上传(第二阶段):使用签名上传 token 上传对象,无需登录态。\n *\n * 配合 `createSignedUploadUrl` 完成两阶段上传:\n * 1. 服务端调用 `createSignedUploadUrl(path)` 生成 token(需登录态)\n * 2. 客户端调用本方法,凭 token 上传文件(无需登录态)\n *\n * 上传行为:\n * - 请求**不携带**登录态(`withCredentials: false`),仅凭 `token` 鉴权。\n * - `path` 和 `token` 必须与之前调用 `createSignedUploadUrl` 的返回值对应。\n * - 与 `upload` 的区别:\n * - `upload`:需登录态,适合服务端/可信客户端。\n * - `uploadToSignedUrl`:无需登录态,仅凭 `token` 鉴权,适合浏览器直传。\n *\n * @param path Bucket 内相对路径,需与 `createSignedUploadUrl` 的 `path` 一致。\n * @param token `createSignedUploadUrl()` 返回的 `token`。\n * @param fileBody 文件内容。\n * @param fileOptions 上传选项。\n * @see createSignedUploadUrl upload\n */\n async uploadToSignedUrl(\n path: string,\n token: string,\n fileBody: FileBody,\n fileOptions?: UploadOptions,\n ): Promise<Result<{ path: string; fullPath: string }>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const { body, headers } = this.buildUploadBody(fileBody, fileOptions)\n\n const data = await this.send<{ Key: string }>({\n method: 'PUT',\n path: `/object/upload/sign/${this.bucketId}/${this.encodePath(cleanName)}`,\n query: { token },\n rawBody: body,\n headers,\n withCredentials: false,\n })\n return { path: cleanName, fullPath: data.Key }\n }, this.shouldThrowOnError)\n }\n\n /**\n * 获取 public bucket 对象的公开访问 URL(同步,不发请求,不返回 error)。\n *\n * **同步方法**,不发起网络请求,不会抛异常。\n *\n * 公开 URL 行为:\n * - URL 由客户端直接拼接 `{gateway}/v1/storages/object/public/{bucketId}/{path}` 得到。\n * - 拼接过程不会被 RLS 策略拦截,但 URL 是否可访问取决于 Bucket 的 `public` 属性。\n * - `options.download` 为 `true` 时在 URL 后追加 `?download`。\n * - 不支持图片 `transform` 选项。\n *\n * @param path Bucket 内相对路径。\n * @param options 公开 URL 选项;当前仅支持 `download`,不支持图片 `transform`。\n */\n getPublicUrl(path: string, options?: PublicUrlOptions): { data: { publicUrl: string } } {\n const cleanName = this.cleanPath(path)\n const base = this.http.buildUrl(`/object/public/${this.bucketId}/${this.encodePath(cleanName)}`)\n return { data: { publicUrl: this.appendUrlOptions(base, options) } }\n }\n\n // ---------- 内部工具 ----------\n\n /**\n * 统一发请求:把实例级自定义头并入每个请求。\n * 单次请求显式传入的功能性头(如 `Content-Type` / `x-upsert`)优先级更高,会覆盖同名自定义头。\n */\n private send<T = any>(opts: Parameters<Http['send']>[0]): Promise<T> {\n return this.http.send<T>({ ...opts, headers: { ...this.headers, ...(opts.headers || {}) } })\n }\n\n private async uploadOrUpdate(\n method: 'POST' | 'PUT',\n path: string,\n fileBody: FileBody,\n fileOptions?: UploadOptions,\n ): Promise<Result<UploadResult>> {\n return handleOperation(async () => {\n const cleanName = this.cleanPath(path)\n const { body, headers } = this.buildUploadBody(fileBody, fileOptions)\n\n if (method === 'POST') {\n // x-upsert 不放进 FormData:它是请求级行为开关而非对象元信息,服务端需在解析 body 前读到;\n // 且 binary 直传路径没有表单字段可放,统一走 header 以保持两条上传路径一致。\n headers['x-upsert'] = String(Boolean(fileOptions?.upsert))\n }\n\n const data = await this.send<{ Id: string; Key: string }>({\n method,\n path: `/object/${this.bucketId}/${this.encodePath(cleanName)}`,\n rawBody: body,\n headers,\n })\n\n return { id: data.Id, path: cleanName, fullPath: data.Key }\n }, this.shouldThrowOnError)\n }\n\n private cleanPath(path: string): string {\n const clean = path.replace(/^\\/+|\\/+$/g, '').replace(/\\/+/g, '/')\n // 客户端纵深防御:拒绝 `..` 段,避免 URL 规范化后逃出 bucket 路径前缀(路径穿越)。\n // encodeURIComponent('..') === '..',无法靠编码消除,必须显式拦截。\n if (clean.split('/').some(seg => seg === '..')) {\n throw new StorageError('invalid path: \"..\" segment is not allowed')\n }\n return clean\n }\n\n /** 把 `cleanPath` 后的对象名编码为可安全拼进 URL path 的形式(保留 `/` 分隔符)。 */\n private encodePath(cleanName: string): string {\n return encodeObjectName(cleanName)\n }\n\n private buildUploadBody(\n fileBody: FileBody,\n fileOptions?: UploadOptions,\n ): { body: any; headers: Record<string, string> } {\n const headers: Record<string, string> = { ...(fileOptions?.headers || {}) }\n let body: any = fileBody\n\n // 与 supabase-js 一致的按类型分流策略:\n // - Blob / File → multipart/form-data:cacheControl / contentType / metadata 走表单字段,\n // Content-Type 为 CORS 安全值,不触发自定义头预检(浏览器最常见的文件上传场景)。\n // - FormData → 取其中的文件内容,并允许携带服务端支持的元信息字段;同样走 multipart 表单。\n // - 其它(string / ArrayBuffer / 二进制视图 / 流等)→ Binary 直传:元信息走请求头。\n // 该路径会发送 cache-control / x-metadata 等自定义头,浏览器下需要网关在\n // Access-Control-Allow-Headers 放行,否则触发 CORS 预检失败。\n const isFormData = typeof FormData !== 'undefined' && fileBody instanceof FormData\n const isBlob = typeof Blob !== 'undefined' && fileBody instanceof Blob\n if (isBlob || isFormData) {\n let file: Blob\n let fields: UploadFormFields = {}\n if (isFormData) {\n const extracted = this.extractFromFormData(fileBody as FormData)\n file = extracted.file\n fields = extracted.fields\n } else {\n file = fileBody as Blob\n }\n\n // 元信息取值优先级:fileOptions(显式传入)> FormData 携带 > 默认值。\n const cacheControl = fileOptions?.cacheControl ?? fields.cacheControl ?? DEFAULT_UPLOAD_OPTIONS.cacheControl\n const contentType = fileOptions?.contentType ?? fields.contentType\n const metadata = fileOptions?.metadata !== undefined ? JSON.stringify(fileOptions.metadata) : fields.metadata\n\n const form = new FormData()\n if (cacheControl !== undefined) form.append('cacheControl', String(cacheControl))\n // contentType 不落默认值:Blob / File 自带 MIME 类型,强制写默认值反而会覆盖真实类型。\n if (contentType !== undefined) form.append('contentType', contentType)\n if (metadata !== undefined) form.append('metadata', metadata)\n // file 放在最后:服务端边解析 multipart 边落库,要求文件部分排在所有元信息字段之后,\n // 先拿到 cacheControl / metadata 才能写库。\n form.append('', file)\n body = form\n } else {\n body = fileBody\n const cacheControl = fileOptions?.cacheControl ?? DEFAULT_UPLOAD_OPTIONS.cacheControl\n const contentType = fileOptions?.contentType ?? DEFAULT_UPLOAD_OPTIONS.contentType\n headers['cache-control'] = `max-age=${cacheControl}`\n if (contentType) headers['content-type'] = contentType\n if (fileOptions?.metadata) headers['x-metadata'] = this.toBase64(JSON.stringify(fileOptions.metadata))\n }\n\n return { body, headers }\n }\n\n /**\n * 从用户传入的上传 FormData 中提取文件内容,以及服务端支持的元信息字段。\n *\n * - 文件部分:单个对象上传只对应一个文件,缺少或多于一个均抛错。\n * - 元信息字段:服务端仅支持 `cacheControl` / `contentType` / `metadata`,这几个会被取出(其值仍可被\n * `fileOptions` 覆盖,覆盖逻辑在调用方);其余不支持的字段对上传无意义,宽松忽略并打印一次告警。\n *\n * @param source 用户传入的原始 FormData。\n */\n private extractFromFormData(source: FormData): { file: Blob; fields: UploadFormFields } {\n const fields: UploadFormFields = {}\n let file: Blob | undefined\n let fileCount = 0\n const ignoredFields: string[] = []\n source.forEach((value, key) => {\n // File 是 Blob 的子类,二进制内容统一按文件部分处理。\n if (typeof Blob !== 'undefined' && value instanceof Blob) {\n file = value\n fileCount += 1\n return\n }\n if (key === 'cacheControl' || key === 'contentType' || key === 'metadata') {\n fields[key] = String(value)\n return\n }\n ignoredFields.push(key)\n })\n\n if (ignoredFields.length > 0) {\n console.warn(`Ignored unsupported FormData field(s): [${ignoredFields.join(', ')}]. Only file, cacheControl, contentType and metadata are supported`)\n }\n\n if (fileCount === 0 || !file) {\n throw new StorageError('FormData must contain a file')\n }\n if (fileCount > 1) {\n throw new StorageError('FormData must contain exactly one file')\n }\n return { file, fields }\n }\n\n private buildCopyMoveHeaders(options?: DestinationOptions): Record<string, string> {\n const headers: Record<string, string> = {}\n if (options?.upsert) headers['x-upsert'] = 'true'\n if (options?.copyMetadata === false && options?.metadata) {\n headers['x-metadata'] = this.toBase64(JSON.stringify(options.metadata))\n }\n return headers\n }\n\n private appendUrlOptions(url: string, options?: SignedUrlOptions | PublicUrlOptions): string {\n const params: string[] = []\n if (options?.download !== undefined) {\n const value = options.download === true ? '' : String(options.download)\n params.push(`download=${encodeURIComponent(value)}`)\n }\n if (options?.cacheNonce !== undefined) {\n params.push(`cacheNonce=${encodeURIComponent(String(options.cacheNonce))}`)\n }\n\n if (params.length === 0) return url\n const separator = url.includes('?') ? '&' : '?'\n return `${url}${separator}${params.join('&')}`\n }\n\n private toBase64(data: string): string {\n return toBase64(data)\n }\n}\n","import { StorageError } from './supabase/errors'\n\n/**\n * `bucketId` 采用「黑名单」式校验:只拦截**一定会破坏 URL path 语义**或\n * **明显不安全**的字符,其余字符一律放行,给服务端命名规则保留灵活性。\n *\n * `bucketId` 会被**未编码**地直接拼进 `/bucket/{bucketId}`、\n * `/object/{bucketId}/{name}` 等路径,因此以下字符必须禁止:\n * - 控制字符与空白:`\\x00-\\x20`(含空格、Tab、换行)与 DEL(`\\x7F`);\n * - URL 路径分隔/结构字符:`/`、`\\`、`?`、`#`;\n * - 百分号 `%`:避免与 percent-encoding 产生二义(双重解码风险)。\n *\n * 其余字符(字母、数字、`.`、`_`、`-`、以及大多数可见符号、Unicode 等)\n * 是否合法交由服务端判定,客户端不做过度限制。\n */\nconst FORBIDDEN_BUCKET_ID_PATTERN = /[\\x00-\\x20\\x7f/\\\\?#%]/\n\n/** `bucketId` 最大长度(仅作防御性上界,避免异常超长输入)。 */\nconst BUCKET_ID_MAX_LENGTH = 256\n\n/** 判断 `bucketId` 是否为合法格式(不抛错版本)。 */\nexport function isValidBucketId(bucketId: unknown): bucketId is string {\n return (\n typeof bucketId === 'string'\n && bucketId.length > 0\n && bucketId.length <= BUCKET_ID_MAX_LENGTH\n && !FORBIDDEN_BUCKET_ID_PATTERN.test(bucketId)\n )\n}\n\n/**\n * 校验 `bucketId` 格式,非法时抛出 `StorageError`。\n *\n * 在 `handleOperation` 包裹内调用时,异常会被转成 `{ data: null, error }` 返回;\n * 在 `from()` 等同步入口调用时则直接抛出。\n *\n * @param bucketId 待校验的 Bucket ID。\n * @param caller 调用方方法名,用于错误信息定位(如 `from`、`createBucket`)。\n */\nexport function assertValidBucketId(bucketId: unknown, caller: string): asserts bucketId is string {\n if (typeof bucketId !== 'string' || bucketId.length === 0) {\n throw new StorageError(`[storage.${caller}] bucketId is required`)\n }\n if (bucketId.length > BUCKET_ID_MAX_LENGTH) {\n throw new StorageError(`[storage.${caller}] invalid bucketId: length must be 1-${BUCKET_ID_MAX_LENGTH}`)\n }\n const forbidden = FORBIDDEN_BUCKET_ID_PATTERN.exec(bucketId)\n if (forbidden) {\n const message = `[storage.${caller}] invalid bucketId \"${bucketId}\": `\n + `contains forbidden character ${JSON.stringify(forbidden[0])}; `\n + 'must not contain whitespace, control chars, \"/\", \"\\\\\", \"?\", \"#\" or \"%\"'\n throw new StorageError(message)\n }\n}\n","import { Context, Http, handleOperation } from './http'\nimport { assertValidBucketId } from './validation'\nimport {\n Result,\n Bucket,\n ListBucketOptions,\n CreateBucketOptions,\n UpdateBucketOptions,\n MessageResponse,\n} from './types'\n\n/**\n * Bucket 管理基类。提供 Supabase 同名 Bucket 管理 API:\n * `listBuckets` / `getBucket` / `createBucket` / `updateBucket` / `deleteBucket`。\n * `emptyBucket` 暂不开放(见 §12.2);也不提供 `headBucket`、Bucket CORS、Bucket ACL 等 COS/S3 风格 Bucket API。\n *\n * 持有 `http`(由运行上下文 `{ config, request }` 构造)与 `throwOnError` 状态,\n * 子类(`app.storage` 命名空间)在此之上提供 `from()` 分流。\n */\nexport class StorageBucketApi {\n protected http: Http\n protected shouldThrowOnError: boolean\n\n constructor(context?: Context, shouldThrowOnError = false) {\n this.http = new Http(context as Context)\n this.shouldThrowOnError = shouldThrowOnError\n }\n\n throwOnError(): this {\n this.shouldThrowOnError = true\n return this\n }\n\n /**\n * 获取 Bucket 列表(偏移分页 + 扁平排序)。\n *\n * @param options 查询参数:`limit`、`offset`、`sortColumn`、`sortOrder`、`search`。\n */\n async listBuckets(options?: ListBucketOptions): Promise<Result<Bucket[]>> {\n return handleOperation(() => {\n const query: Record<string, any> = {}\n if (options?.limit !== undefined) query.limit = options.limit\n if (options?.offset !== undefined) query.offset = options.offset\n if (options?.sortColumn) query.sortColumn = options.sortColumn\n if (options?.sortOrder) query.sortOrder = options.sortOrder\n if (options?.search) query.search = options.search\n\n return this.http.send<Bucket[]>({\n method: 'GET',\n path: '/bucket/',\n query,\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 获取指定 Bucket 详情。\n *\n * @param bucketId Bucket ID。\n */\n async getBucket(bucketId: string): Promise<Result<Bucket>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'getBucket')\n return this.http.send<Bucket>({\n method: 'GET',\n path: `/bucket/${bucketId}`,\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 创建 Bucket。\n *\n * @param bucketId Bucket ID,同时作为后端 `id` 与 `name` 传入。\n * @param options 创建参数:`public`、`fileSizeLimit`、`allowedMimeTypes`、`type`。\n * @remarks `public` 默认 `false`。\n */\n async createBucket(bucketId: string, options?: CreateBucketOptions): Promise<Result<{ name: string }>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'createBucket')\n return this.http.send<{ name: string }>({\n method: 'POST',\n path: '/bucket/',\n json: {\n id: bucketId,\n name: bucketId,\n public: options?.public ?? false,\n type: options?.type,\n file_size_limit: options?.fileSizeLimit,\n allowed_mime_types: options?.allowedMimeTypes,\n },\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 更新 Bucket 配置。\n *\n * @param bucketId Bucket ID。\n * @param options 更新参数:`public`、`fileSizeLimit`、`allowedMimeTypes`。不支持更新 `type`。\n */\n async updateBucket(bucketId: string, options: UpdateBucketOptions): Promise<Result<MessageResponse>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'updateBucket')\n return this.http.send<MessageResponse>({\n method: 'PUT',\n path: `/bucket/${bucketId}`,\n json: {\n public: options.public,\n file_size_limit: options.fileSizeLimit,\n allowed_mime_types: options.allowedMimeTypes,\n },\n })\n }, this.shouldThrowOnError)\n }\n\n /**\n * 删除空 Bucket。\n *\n * @param bucketId Bucket ID。\n * @remarks Bucket 非空时后端会返回错误。\n */\n async deleteBucket(bucketId: string): Promise<Result<MessageResponse>> {\n return handleOperation(() => {\n assertValidBucketId(bucketId, 'deleteBucket')\n return this.http.send<MessageResponse>({\n method: 'DELETE',\n path: `/bucket/${bucketId}`,\n })\n }, this.shouldThrowOnError)\n }\n}\n","let sdkName = '@cloudbase/js-sdk'\nexport function setSdkName(name: string) {\n sdkName = name\n}\nexport function getSdkName() {\n return sdkName\n}\n\nlet PROTOCOL = 'https:'\n\nexport function setProtocol(protocol: 'http:' | 'https:') {\n PROTOCOL = protocol\n}\n\nexport function getProtocol() {\n return PROTOCOL\n}\n// 是否为开发模式\nexport const IS_DEBUG_MODE = typeof process === 'undefined' || typeof process.env === 'undefined' ? false : process.env.NODE_ENV === 'development'\n// 问答社区链接\nexport const COMMUNITY_SITE_URL = 'https://support.qq.com/products/148793'\n","var x = y => { var x = {}; __webpack_require__.d(x, y); return x; }\nvar y = x => () => x\nconst __WEBPACK_NAMESPACE_OBJECT__ = x({ [\"AbstractSDKRequest\"]: () => __WEBPACK_EXTERNAL_MODULE__cloudbase_adapter_interface_74717cc6__.AbstractSDKRequest, [\"AbstractStorage\"]: () => __WEBPACK_EXTERNAL_MODULE__cloudbase_adapter_interface_74717cc6__.AbstractStorage });","import { KV } from '@cloudbase/types'\nimport { getSdkName } from '../constants'\n\nexport function isArray(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object Array]'\n}\nexport function isString(val: any): boolean {\n return typeof val === 'string'\n}\nexport function isUndefined(val: any): boolean {\n return typeof val === 'undefined'\n}\nexport function isPalinObject(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object Object]'\n}\nexport function isNull(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object Null]'\n}\nexport function isInstanceOf(instance: any, construct: any): boolean {\n return instance instanceof construct\n}\nexport function isFormData(val: any): boolean {\n return Object.prototype.toString.call(val) === '[object FormData]'\n}\nexport function genSeqId(): string {\n return Math.random().toString(16)\n .slice(2)\n}\nexport function generateRequestId() {\n let d = new Date().getTime()\n let d2 = (Date?.now && Date.now() * 1000) || 0\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n let r = Math.random() * 16\n if (d > 0) {\n r = (d + r) % 16 | 0\n d = Math.floor(d / 16)\n } else {\n r = (d2 + r) % 16 | 0\n d2 = Math.floor(d2 / 16)\n }\n return (c === 'x' ? r : (r & 0x7) | 0x8).toString(16)\n })\n}\nexport function formatUrl(PROTOCOL: string, url: string, query: KV<any> = {}): string {\n const urlHasQuery = /\\?/.test(url)\n let queryString = ''\n Object.keys(query).forEach((key) => {\n if (queryString === '') {\n !urlHasQuery && (url += '?')\n } else {\n queryString += '&'\n }\n queryString += `${key}=${encodeURIComponent(query[key])}`\n })\n url += queryString\n if (/^http(s)?:\\/\\//.test(url)) {\n return url\n }\n return `${PROTOCOL}${url}`\n}\n\nexport function toQueryString(query: KV<any> = {}) {\n const queryString = []\n Object.keys(query).forEach((key) => {\n queryString.push(`${key}=${encodeURIComponent(query[key])}`)\n })\n return queryString.join('&')\n}\n\nexport function getQuery(name: string, url?: string) {\n if (typeof window === 'undefined') {\n return false\n }\n // 参数:变量名,url为空则表从当前页面的url中取\n const u = url || decodeURIComponent(window.location.search)\n const reg = new RegExp(`(^|&)${name}=([^&]*)(&|$)`)\n const r = u.substr(u.indexOf('?') + 1).match(reg)\n return r !== null && r !== undefined ? r[2] : ''\n}\n\nexport const getHash = function (name: string) {\n if (typeof window === 'undefined') {\n return ''\n }\n const matches = window.location.hash.match(new RegExp(`[#?&/]${name}=([^&#]*)`))\n return matches ? matches[1] : ''\n}\n\nexport function removeParam(key: string, sourceURL: string) {\n let rtn = sourceURL.split('?')[0]\n let param\n let params = []\n const queryString = sourceURL.indexOf('?') !== -1 ? sourceURL.split('?')[1] : ''\n if (queryString !== '') {\n params = queryString.split('&')\n for (let i = params.length - 1; i >= 0; i -= 1) {\n /* eslint-disable-next-line */\n param = params[i].split('=')[0]\n if (param === key) {\n params.splice(i, 1)\n }\n }\n rtn = `${rtn}?${params.join('&')}`\n }\n return rtn\n}\n\nexport function createPromiseCallback() {\n let cb: any = {}\n if (!Promise) {\n cb = () => {}\n cb.promise = {}\n\n const throwPromiseNotDefined = () => {\n throw new Error('Your Node runtime does support ES6 Promises. '\n + 'Set \"global.Promise\" to your preferred implementation of promises.',)\n }\n\n Object.defineProperty(cb.promise, 'then', { get: throwPromiseNotDefined })\n Object.defineProperty(cb.promise, 'catch', { get: throwPromiseNotDefined })\n return cb\n }\n\n const promise = new Promise((resolve, reject) => {\n cb = (err, data) => {\n if (err) return reject(err)\n return resolve(data)\n }\n })\n cb.promise = promise\n return cb\n}\n\nexport function execCallback(fn: Function | null | undefined, err: any, data = null) {\n if (fn && typeof fn === 'function') {\n return fn(err, data)\n }\n if (err) {\n throw err\n }\n return data\n}\n\nexport function printWarn(error: string, msg: string) {\n console.warn(`[${getSdkName()}][${error}]:${msg}`)\n}\n\nexport function printError(error: string, msg: string) {\n console.error({\n code: error,\n msg: `[${getSdkName()}][${error}]:${msg}`,\n })\n}\nexport function printInfo(error: string, msg: string) {\n console.log(`[${getSdkName()}][${error}]:${msg}`)\n}\nexport function throwError(error: string, msg: string) {\n throw new Error(JSON.stringify({\n code: error,\n msg: `[${getSdkName()}][${error}]:${msg}`,\n }),)\n}\n\ninterface IPrintGroupLogOptions {\n title: string\n subtitle: string | object\n content: {\n type: 'info' | 'warn' | 'error'\n body: string | Error\n }[]\n printTrace?: boolean\n collapsed?: boolean\n}\nexport function printGroupLog(options: IPrintGroupLogOptions) {\n const { title, subtitle = '', content = [], printTrace = false, collapsed = false } = options\n if (collapsed) {\n (console.groupCollapsed || console.error)(title, subtitle)\n } else {\n (console.group || console.error)(title, subtitle)\n }\n for (const tip of content) {\n const { type, body } = tip\n switch (type) {\n case 'info':\n console.log(body)\n break\n case 'warn':\n console.warn(body)\n break\n case 'error':\n console.error(body)\n break\n }\n }\n if (printTrace) {\n (console.trace || console.log)('stack trace:')\n }\n console.groupEnd?.()\n}\n\nexport const sleep = (ms = 0) => new Promise(r => setTimeout(r, ms))\n\nexport function transformPhone(phoneNumber: string) {\n return `+86${phoneNumber}`\n}\n\nexport const parseQueryString = (queryString) => {\n queryString = queryString.replace(/^\\?/, '')\n const params = {}\n const pairs = queryString.split('&')\n\n pairs.forEach((item) => {\n let [key, value] = item.split('=')\n key = decodeURIComponent(key)\n value = decodeURIComponent(value)\n if (key) {\n if (params[key]) {\n if (Array.isArray(params[key])) {\n params[key].push(value)\n } else {\n params[key] = [params[key], value]\n }\n } else {\n params[key] = value\n }\n }\n })\n\n return params\n}\n\n// 解析URL参数\nexport function parseCaptcha(url) {\n let queryObj: any = {}\n const matched = url.match(/^(data:.*?)(\\?[^#\\s]*)?$/)\n if (matched) {\n // eslint-disable-next-line prefer-destructuring\n url = matched[1]\n const search = matched[2]\n if (search) {\n queryObj = parseQueryString(search)\n }\n }\n const { token, ...restQueryObj } = queryObj\n if (/^data:/.test(url) && !token) {\n return {\n error: 'invalid_argument',\n error_description: `invalid captcha data: ${url}`,\n }\n }\n if (!token) {\n return {\n error: 'unimplemented',\n error_description: 'need to impl captcha data',\n }\n }\n // 解析url得到的参数\n return {\n state: restQueryObj.state,\n token, // 验证码token\n captchaData: url, // 验证码base64图片\n }\n}\n","export * from './common'\nexport * from './errors'\n\nexport const OATUH_LOGINTYPE = 'constants'\n","import {\n SDKAdapterInterface,\n AbstractSDKRequest,\n IRequestOptions,\n ResponseObject,\n IUploadRequestOptions,\n IRequestConfig,\n IRequestMethod,\n IFetchOptions,\n} from '@cloudbase/adapter-interface'\nimport { isFormData, formatUrl, toQueryString } from '../../libs/util'\nimport { getProtocol } from '../../constants/common'\n\n/**\n * @class WebRequest\n */\nclass WebRequest extends AbstractSDKRequest {\n // 默认不限超时\n private readonly timeout: number\n // 超时提示文案\n private readonly timeoutMsg: string\n // 超时受限请求类型,默认所有请求均受限\n private readonly restrictedMethods: Array<IRequestMethod>\n constructor(config: IRequestConfig) {\n super()\n const { timeout, timeoutMsg, restrictedMethods } = config\n this.timeout = timeout || 0\n this.timeoutMsg = timeoutMsg || '请求超时'\n this.restrictedMethods = restrictedMethods || ['get', 'post', 'upload', 'download']\n }\n public get(options: IRequestOptions): Promise<ResponseObject> {\n return this.request(\n {\n ...options,\n method: 'get',\n },\n this.restrictedMethods.includes('get'),\n )\n }\n public post(options: IRequestOptions): Promise<ResponseObject> {\n return this.request(\n {\n ...options,\n method: 'post',\n },\n this.restrictedMethods.includes('post'),\n )\n }\n public put(options: IRequestOptions): Promise<ResponseObject> {\n return this.request({\n ...options,\n method: 'put',\n })\n }\n public upload(options: IUploadRequestOptions): Promise<ResponseObject> {\n const { data, file, name, method, headers = {} } = options\n const reqMethod = { post: 'post', put: 'put' }[method?.toLowerCase()] || 'put'\n // 上传方式为post时,需转换为FormData\n const formData = new FormData()\n if (reqMethod === 'post') {\n Object.keys(data).forEach((key) => {\n formData.append(key, data[key])\n })\n formData.append('key', name)\n formData.append('file', file)\n return this.request(\n {\n ...options,\n data: formData,\n method: reqMethod,\n },\n this.restrictedMethods.includes('upload'),\n )\n }\n return this.request(\n {\n ...options,\n method: 'put',\n headers,\n body: file,\n },\n this.restrictedMethods.includes('upload'),\n )\n }\n public async download(options: IRequestOptions): Promise<any> {\n try {\n const { data } = await this.get({\n ...options,\n headers: {}, // 下载资源请求不经过service,header清空\n responseType: 'blob',\n })\n const url = window.URL.createObjectURL(new Blob([data]))\n const fileName = decodeURIComponent(new URL(options.url).pathname.split('/').pop() || '')\n const link = document.createElement('a')\n\n link.href = url\n link.setAttribute('download', fileName)\n link.style.display = 'none'\n\n document.body.appendChild(link)\n link.click()\n // 回收内存\n window.URL.revokeObjectURL(url)\n document.body.removeChild(link)\n } catch (e) {}\n return new Promise((resolve) => {\n resolve({\n statusCode: 200,\n tempFilePath: options.url,\n })\n })\n }\n async fetch(options: IFetchOptions & { shouldThrowOnError?: boolean }): Promise<ResponseObject> {\n const abortController = new AbortController()\n const { url, enableAbort = false, stream = false, signal, timeout: _timeout, shouldThrowOnError = true } = options\n\n const timeout = _timeout ?? this.timeout\n\n // FIXME(内存泄漏): { once: true } 只在 abort 事件【触发后】才解绑监听器。\n // 如果请求正常完成、从未 abort,该监听器会一直残留在外部 signal 上。\n // 当调用方复用同一长生命周期 signal 反复发请求时,监听器仍会持续累积。\n // 根治方式:在请求结束(finally)时 removeEventListener 主动解绑,\n // 而不能仅依赖 { once: true }。此处暂仅记录,不改动逻辑。\n if (signal) {\n if (signal.aborted) abortController.abort()\n signal.addEventListener('abort', () => abortController.abort())\n }\n\n let timer = null\n if (enableAbort && timeout) {\n timer = setTimeout(() => {\n console.warn(this.timeoutMsg)\n abortController.abort(new Error(this.timeoutMsg))\n }, timeout)\n }\n\n const res = await fetch(url, {\n ...options,\n signal: abortController.signal,\n })\n .then(async (response) => {\n clearTimeout(timer)\n if (shouldThrowOnError) {\n // 404 等等也会进 resolve,所以要再通过 ok 判断\n return response.ok ? response : Promise.reject(await response.json())\n }\n return response\n })\n .catch((x) => {\n clearTimeout(timer)\n // 传输级失败(网络中断、CORS 预检被拒、请求被 abort 等)时 fetch 会 reject,\n // 此时没有可解析的 Response。无论 shouldThrowOnError 取值都必须把真实错误抛出,\n // 否则 res 会变成 undefined,下方读取 res.headers 会抛出令人误解的\n // \"Cannot read properties of undefined (reading 'headers')\",掩盖真正的错误原因。\n return Promise.reject(x)\n })\n\n return {\n // eslint-disable-next-line no-nested-ternary\n data: stream ? res.body : res.headers.get('content-type')?.includes('application/json') ? res.json() : res.text(),\n statusCode: res.status,\n header: res.headers,\n // 透出原始 Response,便于上层按需 .blob() / .arrayBuffer() / 读取 body 流,避免二次包装。\n response: res,\n }\n }\n /**\n * @param {IRequestOptions} options\n * @param {boolean} enableAbort 是否超时中断请求\n */\n protected request(options: IRequestOptions, enableAbort = false): Promise<ResponseObject> {\n const method = String(options.method).toLowerCase() || 'get'\n return new Promise((resolve) => {\n const { url, headers = {}, data, responseType, withCredentials, body, onUploadProgress } = options\n const realUrl = formatUrl(getProtocol(), url, method === 'get' ? data : {})\n const ajax = new XMLHttpRequest()\n ajax.open(method, realUrl)\n responseType && (ajax.responseType = responseType)\n // 支持通过 AbortSignal 取消请求:已 abort 立即取消;否则用 { once: true }\n // 监听,触发后自动解绑,避免复用同一 AbortController 多次请求时累积监听器。\n //\n // FIXME(内存泄漏): { once: true } 只在 abort 事件【触发后】才解绑监听器。\n // 如果请求正常完成、从未 abort,该监听器会一直残留在外部 signal 上。\n // 当调用方复用同一长生命周期 signal 反复发请求时,监听器仍会持续累积。\n // 根治方式:在请求结束(readyState===4 / onloadend)时 removeEventListener\n // 主动解绑,而不能仅依赖 { once: true }。此处暂仅记录,不改动逻辑。\n const signal = (options as any).signal as AbortSignal | undefined\n if (signal) {\n if (signal.aborted) {\n ajax.abort()\n } else {\n signal.addEventListener('abort', () => ajax.abort(), { once: true })\n }\n }\n Object.keys(headers).forEach((key) => {\n ajax.setRequestHeader(key, headers[key])\n })\n let timer\n if (onUploadProgress) {\n ajax.upload.addEventListener('progress', onUploadProgress)\n }\n ajax.onreadystatechange = () => {\n const result: ResponseObject = {}\n if (ajax.readyState === 4) {\n const headers = ajax.getAllResponseHeaders()\n const arr = headers.trim().split(/[\\r\\n]+/)\n // Create a map of header names to values\n const headerMap = {}\n arr.forEach((line) => {\n const parts = line.split(': ')\n const header = parts.shift().toLowerCase()\n const value = parts.join(': ')\n headerMap[header] = value\n })\n result.header = headerMap\n result.statusCode = ajax.status\n try {\n // 上传post请求返回数据格式为xml,此处容错\n result.data = responseType === 'blob' ? ajax.response : JSON.parse(ajax.responseText)\n } catch (e) {\n result.data = responseType === 'blob' ? ajax.response : ajax.responseText\n }\n clearTimeout(timer)\n resolve(result)\n }\n }\n if (enableAbort && this.timeout) {\n timer = setTimeout(() => {\n console.warn(this.timeoutMsg)\n ajax.abort()\n }, this.timeout)\n }\n // 处理 payload\n let payload\n if (isFormData(data)) {\n // FormData,不处理\n payload = data\n } else if (headers['content-type'] === 'application/x-www-form-urlencoded') {\n payload = toQueryString(data)\n } else if (body) {\n payload = body\n } else {\n // 其它情况\n payload = data ? JSON.stringify(data) : undefined\n }\n\n if (withCredentials) {\n ajax.withCredentials = true\n }\n ajax.send(payload)\n })\n }\n}\n\nfunction genAdapter() {\n const adapter: SDKAdapterInterface & { type?: 'default' | '' } = {\n type: 'default',\n root: window,\n reqClass: WebRequest,\n wsClass: WebSocket,\n localStorage,\n }\n return adapter\n}\n\nexport { genAdapter, WebRequest }\n","import { StorageInterface, AbstractStorage, SDKAdapterInterface } from '@cloudbase/adapter-interface'\nimport { ICloudbaseCache, ICacheConfig } from '@cloudbase/types/cache'\nimport { KV, Persistence, ICloudbasePlatformInfo } from '@cloudbase/types'\nimport { printWarn } from './util'\nimport { ERRORS, getSdkName } from '../constants'\n\n/**\n * persitence=none时登录态保存在内存中\n */\nclass TcbCacheObject extends AbstractStorage {\n private readonly root: any\n constructor(root: any) {\n super()\n this.root = root\n if (!root.tcbCacheObject) {\n root.tcbCacheObject = {}\n }\n }\n public setItem(key: string, value: any) {\n this.root.tcbCacheObject[key] = value\n }\n public getItem(key: string) {\n return this.root.tcbCacheObject[key]\n }\n public removeItem(key: string) {\n delete this.root.tcbCacheObject[key]\n }\n public clear() {\n delete this.root.tcbCacheObject\n }\n}\n/**\n * 工厂函数\n */\nfunction createStorage(persistence: Persistence, adapter: SDKAdapterInterface): StorageInterface {\n switch (persistence) {\n case 'local':\n if (!adapter.localStorage) {\n printWarn(ERRORS.INVALID_PARAMS, 'localStorage is not supported on current platform')\n // 不支持localstorage的平台降级为none\n return new TcbCacheObject(adapter.root)\n }\n return adapter.localStorage\n case 'none':\n return new TcbCacheObject(adapter.root)\n default:\n if (!adapter.localStorage) {\n printWarn(ERRORS.INVALID_PARAMS, 'localStorage is not supported on current platform')\n // 不支持localstorage的平台降级为none\n return new TcbCacheObject(adapter.root)\n }\n return adapter.localStorage\n }\n}\n\nexport class CloudbaseCache implements ICloudbaseCache {\n public keys: KV<string> = {}\n\n private persistenceTag: Persistence\n private platformInfo: ICloudbasePlatformInfo\n private storage: StorageInterface\n\n constructor(config: ICacheConfig) {\n const { persistence, platformInfo = {}, keys = {} } = config\n this.platformInfo = platformInfo\n if (!this.storage) {\n this.persistenceTag = this.platformInfo.adapter.primaryStorage || persistence\n this.storage = createStorage(this.persistenceTag, this.platformInfo.adapter)\n this.keys = keys\n }\n }\n /**\n * @getter storage模式-同步/异步\n */\n get mode() {\n return this.storage.mode || 'sync'\n }\n get persistence(): Persistence {\n return this.persistenceTag\n }\n\n public setStore(key: string, value: any, version?: any) {\n if (this.mode === 'async') {\n printWarn(ERRORS.INVALID_OPERATION, 'current platform\\'s storage is asynchronous, please use setStoreAsync insteed')\n return\n }\n if (!this.storage) {\n return\n }\n\n try {\n const val = {\n version: version || 'localCachev1',\n content: value,\n }\n this.storage.setItem(key, JSON.stringify(val))\n } catch (e) {\n throw new Error(JSON.stringify({\n code: ERRORS.OPERATION_FAIL,\n msg: `[${getSdkName()}][${ERRORS.OPERATION_FAIL}]setStore failed`,\n info: e,\n }))\n }\n\n return\n }\n public async setStoreAsync(key: string, value: any, version?: any) {\n if (!this.storage) {\n return\n }\n\n try {\n const val = {\n version: version || 'localCachev1',\n content: value,\n }\n await this.storage.setItem(key, JSON.stringify(val))\n } catch (e) {\n return\n }\n\n return\n }\n public getStore(key: string, version?: string) {\n if (this.mode === 'async') {\n printWarn(ERRORS.INVALID_OPERATION, 'current platform\\'s storage is asynchronous, please use getStoreAsync insteed')\n return\n }\n try {\n // 测试用例使用\n if (typeof process !== 'undefined' && process.env?.tcb_token) {\n return process.env.tcb_token\n }\n\n if (!this.storage) {\n return ''\n }\n } catch (e) {\n return ''\n }\n\n version = version || 'localCachev1'\n\n const content = this.storage.getItem(key)\n if (!content) {\n return ''\n }\n\n if (content.indexOf(version) >= 0) {\n const d = JSON.parse(content)\n return d.content\n }\n return ''\n }\n public async getStoreAsync(key: string, version?: string) {\n try {\n // 测试用例使用\n if (typeof process !== 'undefined' && process.env?.tcb_token) {\n return process.env.tcb_token\n }\n\n if (!this.storage) {\n return ''\n }\n } catch (e) {\n return ''\n }\n\n version = version || 'localCachev1'\n\n const content = await this.storage.getItem(key)\n if (!content) {\n return ''\n }\n\n if (content.indexOf(version) >= 0) {\n const d = JSON.parse(content)\n return d.content\n }\n return ''\n }\n public removeStore(key: string) {\n if (this.mode === 'async') {\n printWarn(ERRORS.INVALID_OPERATION, 'current platform\\'s storage is asynchronous, please use removeStoreAsync insteed')\n return\n }\n this.storage.removeItem(key)\n }\n public async removeStoreAsync(key: string) {\n await this.storage.removeItem(key)\n }\n}\n","import { isString, isInstanceOf } from './util'\nimport { Listeners, ICloudbaseEventEmitter } from '@cloudbase/types/events'\n\n\n/**\n * @private\n * @function _addEventListener - 添加监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @param {Listeners} listeners - 已存响应函数集合\n */\nfunction customeAddEventListener(name: string, listener: Function, listeners: Listeners) {\n listeners[name] = listeners[name] || []\n listeners[name].push(listener)\n}\n/**\n * @private\n * @function _removeEventListener - 移除监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @param {Listeners} listeners - 已存响应函数集合\n */\nfunction customRemoveEventListener(name: string, listener: Function, listeners: Listeners) {\n if (listeners?.[name]) {\n const index = listeners[name].indexOf(listener)\n if (index !== -1) {\n listeners[name].splice(index, 1)\n }\n }\n}\ninterface IEvent {\n name: string;\n target: any;\n data: any;\n}\n/**\n * 自定义事件\n * @class CloudbaseEvent\n * @param {string} name - 类型\n * @param {any} data - 数据\n */\nexport class CloudbaseEvent implements IEvent {\n public readonly name: string\n public target: any\n public data: any\n\n constructor(name: string, data: any) {\n this.data = data || null\n this.name = name\n }\n}\n/**\n * 自定义错误事件\n * @class IErrorEvent\n * @extends CloudbaseEvent\n * @param {Error} error - 错误信息对象\n * @param {any} data - 数据\n */\nexport class IErrorEvent extends CloudbaseEvent {\n public readonly error: Error\n constructor(error: Error, data?: any) {\n super('error', { error, data })\n this.error = error\n }\n}\n\n/**\n * @class CloudbaseEventEmitter\n */\nexport class CloudbaseEventEmitter implements ICloudbaseEventEmitter {\n /**\n * @private\n * @readonly\n * @property {Listeners} listeners - 响应函数集合\n * @default `{}`\n */\n private readonly listeners: Listeners = {}\n\n /**\n * @public\n * @method on - 添加监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @return `this`\n */\n public on(name: string, listener: Function): this {\n customeAddEventListener(name, listener, this.listeners)\n return this\n }\n /**\n * @public\n * @method off - 移除监听\n * @param {string} name - event名称\n * @param {Function} listener - 响应函数\n * @return `this`\n */\n public off(name: string, listener: Function): this {\n customRemoveEventListener(name, listener, this.listeners)\n return this\n }\n /**\n * @public\n * @method fire - 触发事件\n * @param {string|CloudbaseEvent} event - event\n * @return `this`\n */\n public fire(event: string | CloudbaseEvent, data?: any): this {\n // 打印错误信息\n if (isInstanceOf(event, IErrorEvent)) {\n console.error((event as IErrorEvent).error)\n return this\n }\n\n const ev: CloudbaseEvent = isString(event) ? new CloudbaseEvent(event as string, data || {}) : event as CloudbaseEvent\n\n const { name } = ev\n\n if (this.listens(name)) {\n ev.target = this\n\n const handlers = this.listeners[name] ? [...this.listeners[name]] : []\n for (const fn of handlers) {\n fn.call(this, ev)\n }\n }\n\n return this\n }\n\n /**\n * @private\n * @method listens - 判断是否监听了name事件\n * @param {string} name - event名称\n * @return `boolean`\n */\n private listens(name: string): boolean {\n return this.listeners[name] && this.listeners[name].length > 0\n }\n}\n\n\nconst eventEmitter = new CloudbaseEventEmitter()\n\nexport function addEventListener(event: string, callback: Function) {\n eventEmitter.on(event, callback)\n}\n\nexport function activateEvent(event: string, data: any = {}) {\n eventEmitter.fire(event, data)\n}\n\nexport function removeEventListener(event: string, callback: Function) {\n eventEmitter.off(event, callback)\n}\n","import { CloudbaseEventEmitter } from './events'\n\nexport const bus = new CloudbaseEventEmitter()\n\nexport const LANG_CHANGE_EVENT = 'lang_change'\n","import { printGroupLog } from '../libs/util'\nimport { IS_DEBUG_MODE } from '../constants'\n\ninterface ICatchErrorsDecoratorOptions {\n mode?: 'sync' | 'async';\n customInfo?: {\n className?: string;\n methodName?: string;\n };\n title?: string;\n messages?: string[];\n}\n// firefox的stack格式与chrome不同\nlet isFirefox = false\nif (typeof navigator !== 'undefined' && navigator.userAgent) {\n isFirefox = navigator.userAgent.indexOf('Firefox') !== -1\n}\n/**\n * decorate在stack中一般都特定的规范\n */\nconst REG_STACK_DECORATE = isFirefox\n ? /(\\.js\\/)?__decorate(\\$\\d+)?<@.*\\d$/\n : /(\\/\\w+\\.js\\.)?__decorate(\\$\\d+)?\\s*\\(.*\\)$/\nconst REG_STACK_LINK = /https?:\\/\\/.+:\\d*\\/.*\\.js:\\d+:\\d+/\n/**\n * debug模式强化日志信息\n * @param options\n */\nexport function catchErrorsDecorator(options: ICatchErrorsDecoratorOptions) {\n const { mode = 'async', customInfo = {}, title, messages = [] } = options\n\n return function (\n target: any,\n methodName: string,\n descriptor: TypedPropertyDescriptor<Function>\n ) {\n // 生产环境禁用\n if (!IS_DEBUG_MODE) {\n return\n }\n const className = customInfo.className || target.constructor.name\n const fnName = customInfo.methodName || methodName\n const fn = descriptor.value\n\n // 被decorator装饰的源码link\n // 在descriptor.value外部此处创建的stack层次可触达源码\n // 而descriptor.value内部有可能由于stack太深无法触达\n const sourceLink = getSourceLink(new Error())\n\n if (mode === 'sync') {\n descriptor.value = function (...args: any[]) {\n // 此处的stack作用主要是为了获取被decorator装饰的源码class和method名称\n const innerErr: any = getRewritedError({\n err: new Error(),\n className,\n methodName: fnName,\n sourceLink,\n })\n try {\n return fn.apply(this, args)\n } catch (err) {\n let failErr = err\n const { message: errMsg, error, error_description: errorDescription } = err\n const logs: any = {\n title: title || `${className}.${fnName} failed`,\n content: [{\n type: 'error',\n body: err,\n }],\n }\n // 只特殊处理SDK业务逻辑抛出的错误-JSON string\n if (errMsg && /^\\{.*\\}$/.test(errMsg)) {\n const msg = JSON.parse(errMsg)\n logs.subtitle = errMsg\n if (msg.code) {\n if (innerErr) {\n innerErr.code = msg.code\n innerErr.msg = msg.msg\n } else {\n err.code = msg.code\n err.message = msg.msg\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n }\n\n // oauth 错误特殊处理\n if (error && errorDescription) {\n logs.subtitle = errorDescription\n if (innerErr) {\n innerErr.code = error\n innerErr.msg = errorDescription\n } else {\n err.code = error\n err.message = errorDescription\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n printGroupLog(logs)\n throw failErr\n }\n }\n } else {\n descriptor.value = async function (...args: any[]) {\n const innerErr: any = getRewritedError({\n err: new Error(),\n className,\n methodName: fnName,\n sourceLink,\n })\n\n try {\n return await fn.apply(this, args)\n } catch (err) {\n let failErr = err\n const { message: errMsg, error, error_description: errorDescription } = err\n const logs: any = {\n title: title || `${className}.${fnName} failed`,\n content: [{\n type: 'error',\n body: err,\n }],\n }\n // 只特殊处理SDK业务逻辑抛出的错误-JSON string\n if (errMsg && /^\\{.*\\}$/.test(errMsg)) {\n const msg = JSON.parse(errMsg)\n logs.subtitle = msg\n if (msg.code) {\n if (innerErr) {\n innerErr.code = msg.code\n innerErr.message = msg.msg\n } else {\n err.code = msg.code\n err.message = msg.msg\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n }\n\n // oauth 错误特殊处理\n if (error && errorDescription) {\n logs.subtitle = errorDescription\n if (innerErr) {\n innerErr.code = error\n innerErr.msg = errorDescription\n } else {\n err.code = error\n err.message = errorDescription\n }\n failErr = innerErr || err\n logs.content = messages.map(msg => ({\n type: 'info',\n body: msg,\n }))\n }\n printGroupLog(logs)\n throw failErr\n }\n }\n }\n }\n}\n\n/**\n * 在原始堆栈中查找装饰器条目并返回源码链接link\n * @param err\n */\nfunction getSourceLink(err: Error) {\n let sourceLink = ''\n const outterErrStacks = err.stack.split('\\n')\n const indexOfDecorator = outterErrStacks.findIndex(str => REG_STACK_DECORATE.test(str))\n\n if (indexOfDecorator !== -1) {\n const match = REG_STACK_LINK.exec(outterErrStacks[indexOfDecorator + 1] || '')\n\n sourceLink = match ? match[0] : ''\n }\n return sourceLink\n}\n\n/**\n * 在原始堆栈中查找装饰器条目,剔除其后的无用堆栈,并将链接替换为源码link\n * @param options\n */\nfunction getRewritedError(options: {\n err: Error;\n className: string;\n methodName: string;\n sourceLink: string;\n}) {\n const { err, className, methodName, sourceLink } = options\n // 找不到源码link返回null,后续逻辑将打印原堆栈信息\n if (!sourceLink) {\n return null\n }\n\n const innerErrStack = err.stack.split('\\n')\n const REG_STACK_INNER_METHOD = isFirefox\n ? /^catchErrorsDecorator\\/<\\/descriptor.value@.*\\d$/\n : new RegExp(`${className}\\\\.descriptor.value\\\\s*\\\\[as\\\\s${methodName}\\\\]\\\\s*\\\\(.*\\\\)$`)\n const REG_STACK_INNER_METHOD_WITHOUT_LINK = isFirefox\n ? /^catchErrorsDecorator\\/<\\/descriptor.value/\n : new RegExp(`${className}\\\\.descriptor.value\\\\s*\\\\[as\\\\s${methodName}\\\\]`)\n const indexOfSource = innerErrStack.findIndex(str => REG_STACK_INNER_METHOD.test(str))\n let innerErr: Error\n if (indexOfSource !== -1) {\n // @ts-ignore\n const realErrStack = innerErrStack.filter((v, i) => i > indexOfSource)\n realErrStack.unshift(innerErrStack[indexOfSource]\n .replace(REG_STACK_INNER_METHOD_WITHOUT_LINK, `${className}.${methodName}`)\n .replace(REG_STACK_LINK, sourceLink))\n innerErr = new Error()\n innerErr.stack = `${isFirefox ? '@debugger' : 'Error'}\\n${realErrStack.join('\\n')}`\n }\n return innerErr\n}\n","var x = y => { var x = {}; __webpack_require__.d(x, y); return x; }\nvar y = x => () => x\nconst __WEBPACK_NAMESPACE_OBJECT__ = x({ [\"default\"]: () => __WEBPACK_EXTERNAL_MODULE_jwt_decode_b659f100__[\"default\"] });","import { constants, utils, helpers } from '@cloudbase/utilities'\nimport { getStringByteLength } from './encoding'\nimport {\n ICloudbaseFileMetaDataRes,\n ICloudbaseFileInfo,\n ICloudbaseUploadFileParams,\n ICloudbaseUploadFileResult,\n ICloudbaseGetUploadMetadataParams,\n ICloudbaseDeleteFileParams,\n ICloudbaseDeleteFileResult,\n ICloudbaseGetTempFileURLResult,\n ICloudbaseGetTempFileURLParams,\n ICloudbaseDownloadFileResult,\n ICloudbaseDownloadFileParams,\n ICloudbaseCopyFileParams,\n ICloudbaseCopyFileResult,\n} from '@cloudbase/types/storage'\n\nexport enum EUploadMethod {\n put = 'put',\n post = 'post',\n}\n\nexport interface IUploadMetadata {\n url: string\n token: string\n authorization: string\n fileId: string\n cosFileId: string\n download_url?: string\n}\n\nconst { getSdkName, ERRORS, COMMUNITY_SITE_URL } = constants\nconst { isArray, isString, isPalinObject, execCallback } = utils\n/** catchErrorsDecorator 装饰器要放在index入口文件,意面有的编译找不到其sourcemap,例如HBuilderX */\nconst { catchErrorsDecorator } = helpers as { catchErrorsDecorator: (options: unknown) => MethodDecorator }\n\nexport const COMPONENT_NAME = 'storage'\n\n/**\n * 网关(GATEWAY 模式)下的对象操作集合,统一走 `/v1/storages/*` HTTP 接口。\n *\n * `objectId` 第一段被解释为 `bucket_id`、其余为对象名(§1.2.2),\n * 权限由 `storage.objects` / `storage.buckets` 的 RLS 策略判定。\n *\n * 注意:这组接口与原生对象 API(StorageFileApi,`/object/{bucketId}/{name}`)\n * 是两套不同通道——前者是 `/v1/storages/*` 兼容路径,后者是原生 `bucketId + objectName` 路径。\n */\ntype CustomReqOpts = ICloudbaseUploadFileParams['customReqOpts']\n\ntype GatewayObjectResult = {\n code?: string\n message?: string\n authorization?: string\n token?: string\n uploadUrl?: string\n cloudObjectId?: string\n cloudObjectMeta?: string\n downloadUrl?: string\n}\n\ntype GatewayResponse<T> = Record<string, unknown> & {\n data?: T\n requestId?: string\n code?: string\n}\n\ntype GatewayRequest = {\n gateWay(payload: unknown, customReqOpts?: CustomReqOpts): Promise<GatewayResponse<GatewayObjectResult[]>>\n}\n\n/**\n * 网关获取 COS 上传预签名时使用的签名头,不等同于实际 XHR 上传请求头。\n *\n * 需要重点关注的 key:\n * - `content-length`:PUT body 的字节长度。后端用它参与 COS 签名,也会用于校验 Bucket 的 `file_size_limit` 配置。\n * - `content-type`:上传对象的 MIME 类型。后端用它参与 COS 签名,也会用于校验 Bucket 的 `allowed_mime_types` 配置;实际 PUT 上传时也需要发送同值。\n *\n * 调用方显式传入的其他 headers 会按原样放入签名头;这些 header 一旦参与签名,实际上传请求也必须发送同名同值 header。\n */\ntype SignedHeader = Record<string, string[]>\n\nconst storageGateWay = {\n getUploadInfo: async (\n request: GatewayRequest,\n params: { path: string; signedHeader?: SignedHeader },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'get-objects-upload-info',\n data: [\n {\n objectId: params.path,\n ...(params.signedHeader ? { signedHeader: params.signedHeader } : {}),\n },\n ],\n },\n customReqOpts,\n )\n const data = res.data?.[0] || {}\n\n return {\n ...res,\n data: {\n ...(data.code ? { ...data } : {}),\n authorization: data.authorization,\n token: data.token,\n url: data.uploadUrl,\n fileId: data.cloudObjectId,\n cosFileId: data.cloudObjectMeta,\n download_url: data.downloadUrl,\n },\n } as unknown as ICloudbaseFileMetaDataRes\n },\n getDownLoadInfo: async (\n request: GatewayRequest,\n params: { convertedFileList: Array<{ fileid: string; max_age?: number }> },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'get-objects-download-info',\n data: params.convertedFileList.map(v => ({ cloudObjectId: v.fileid })),\n },\n customReqOpts,\n )\n return {\n ...res,\n data: {\n download_list: res.data?.map(v => ({\n code: v.code || 'SUCCESS',\n message: v.message,\n fileid: v.cloudObjectId,\n download_url: v.downloadUrl,\n fileID: v.cloudObjectId,\n tempFileURL: v.downloadUrl,\n })),\n },\n }\n },\n delete: async (\n request: GatewayRequest,\n params: { fileList: Array<string> },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'delete-objects',\n data: params.fileList.map(v => ({ cloudObjectId: v })),\n },\n customReqOpts,\n )\n return {\n ...res,\n data: {\n delete_list: res.data?.map(v => ({\n code: v.code || 'SUCCESS',\n fileID: v.cloudObjectId,\n message: v.message,\n })),\n },\n }\n },\n copyFile: async (\n request: GatewayRequest,\n params: {\n convertedFileList: Array<{ src_path: string; dst_path: string; overwrite?: boolean; remove_original?: boolean }>\n },\n customReqOpts: CustomReqOpts,\n ) => {\n const res = await request.gateWay(\n {\n path: 'storages',\n name: 'copy-objects',\n data: params.convertedFileList.map(v => ({\n srcPath: v.src_path,\n dstPath: v.dst_path,\n overwrite: v.overwrite,\n removeOriginal: v.remove_original,\n })),\n },\n customReqOpts,\n )\n return {\n ...res,\n data: {\n copy_list: res.data?.map(v => ({\n code: v.code || 'SUCCESS',\n fileID: v.cloudObjectId,\n message: v.message,\n })),\n },\n }\n },\n}\n\nexport interface ICloudbaseContext {\n config: any\n request: any\n}\n\ntype TempFileURLItem = NonNullable<ICloudbaseGetTempFileURLResult['fileList']>[number]\ntype FileInfoItem = Pick<TempFileURLItem, 'code' | 'fileID' | 'tempFileURL'> & {\n message?: TempFileURLItem['message']\n fileName?: string\n cloudId?: TempFileURLItem['fileID']\n contentType?: string\n mime?: string\n size?: number\n cacheControl?: string\n lastModified?: string\n etag?: string\n}\n\n/** 常见扩展名 → MIME 类型,用于上传时推断 content-type。 */\nconst MIME_BY_EXT: Record<string, string> = {\n txt: 'text/plain',\n json: 'application/json',\n html: 'text/html',\n htm: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n csv: 'text/csv',\n xml: 'application/xml',\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n pdf: 'application/pdf',\n zip: 'application/zip',\n gz: 'application/gzip',\n mp4: 'video/mp4',\n webm: 'video/webm',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n}\n\n/**\n * 推断上传内容的 content-type,按可靠性从高到低:\n * ① 内容自带的 MIME(File/Blob.type,由浏览器/系统给出,最可靠);\n * ② 按云端路径扩展名映射;\n * ③ 兜底 application/octet-stream。\n * @param file 上传内容(可能是 Blob/File,也可能是字符串/ArrayBuffer 等无 type 形态)\n * @param path 云端路径,用于按扩展名兜底推断\n */\nfunction inferContentType(file: any, path: string): string {\n if (typeof Blob !== 'undefined' && file instanceof Blob && file.type) {\n return file.type\n }\n const m = /\\.([a-zA-Z0-9]+)$/.exec(path || '')\n const ext = m ? m[1].toLowerCase() : ''\n return MIME_BY_EXT[ext] || 'application/octet-stream'\n}\n\n/**\n * 尽力计算上传内容的字节长度(content-length)。\n *\n * 支持(可准确得到字节数):\n * - Blob / File:取 .size;\n * - ArrayBuffer:取 .byteLength;\n * - TypedArray / DataView(含 Node Buffer,为 Uint8Array 子类):取 .byteLength;\n * - 字符串「内容」:按 UTF-8 计算(浏览器用 new Blob([s]).size,Node 回退 Buffer.byteLength);\n * - 带数字 size 字段的对象:取 .size。\n *\n * 不支持(返回 undefined):\n * - 可读流:Node fs.ReadStream / Web ReadableStream —— 长度未知、边读边传,与「预签名 PUT 需先知长度」的模型冲突,无法同步求值;\n * - FormData:用于 POST multipart 上传,不会进入 PUT 网关分支,故不处理;\n * - 小程序本地路径字符串(wx 的 filePath 是文件路径而非内容):\n * 注意会被误当作「字符串内容」计算成路径本身的字节数,调用方如走该形态应显式传 content-length;\n * - 其它无 size 信息的自定义对象。\n */\nfunction resolveUploadByteLength(file: any, fileContent: any): number | undefined {\n const target = file ?? fileContent\n if (target === null) return undefined\n if (typeof Blob !== 'undefined' && target instanceof Blob) return target.size\n if (typeof ArrayBuffer !== 'undefined') {\n if (target instanceof ArrayBuffer) return target.byteLength\n if (typeof ArrayBuffer.isView === 'function' && ArrayBuffer.isView(target)) {\n return (target as ArrayBufferView).byteLength\n }\n }\n if (typeof target === 'string') {\n if (typeof Blob !== 'undefined') return new Blob([target]).size\n const byteLength = getStringByteLength(target)\n if (typeof byteLength === 'number') return byteLength\n return target.length\n }\n if (typeof target === 'object' && typeof (target as any).size === 'number') {\n return (target as any).size\n }\n return undefined\n}\n\n/** 判断 headers(不区分大小写)是否已包含某个字段。 */\nfunction hasHeader(headers: Record<string, string>, name: string): boolean {\n const lower = name.toLowerCase()\n return Object.keys(headers).some(k => k.toLowerCase() === lower)\n}\n\nfunction toSignedHeader(headers: Record<string, string>): SignedHeader {\n return Object.keys(headers).reduce(\n (result: SignedHeader, key) => ({ ...result, [key]: [headers[key]] }),\n {},\n )\n}\n\n/**\n * 传统云存储基类:提供顶层对象操作(`uploadFile` / `getTempFileURL` / `downloadFile` /\n * `deleteFile` / `copyFile` / `getFileInfo`),即「传统 SDK API」。\n *\n * 这些方法由 `isGateWay()` 决定底层通道(GATEWAY 走 `/v1/storages/*`,否则走旧版 CLOUD_API `request.send`)。\n * `cloudPath` 第一段须为 `bucket_id`、其余为对象名(§1.2.2);`fileID` 形态为\n * `cloud://env.cosBucket/<bucketId>/<name>`(路径含 bucket 段),权限由 PostgreSQL RLS(基于 `bucket_id`)判定。\n * 上传需 content-length / content-type 参与 COS 签名及 Bucket 配置校验(`uploadFile` 已自动补全)。\n *\n * @remarks 若 `cloudPath` 不含 bucket 前缀(如 `a.txt` 或首段桶不存在),服务端报\n * `STORAGE_BUCKET_NOT_FOUND`;缺 content-length 则报 `STORAGE_CONTENT_LENGTH_REQUIRED`。\n */\nexport class CloudbaseStorage {\n /**\n * 运行上下文(`{ config, request }`)。\n *\n * - 组件模式:实例由 `new CloudbaseStorage()`(无参)创建,方法被提取后重新绑定到 cloudbase 实例,\n * `this.config` / `this.request` 由该实例提供,本字段为空、原型 getter 不参与解析。\n * - 组合模式:由 `StorageClient`(入口 `supabaseComponent`)注入 context,方法以本实例为 `this`\n * 运行,`this.config` / `this.request` 经下方 getter 从 context 读取。\n */\n protected context?: ICloudbaseContext\n\n constructor(context?: ICloudbaseContext) {\n this.context = context\n }\n\n // @ts-ignore — 组件模式下 this 为 cloudbase 实例、走其自身 config,本 getter 不参与解析\n get config() {\n // @ts-ignore\n return this.context?.config\n }\n\n // @ts-ignore — 同上\n get request() {\n return this.context?.request\n }\n\n /**\n * 是否为网关模式(GATEWAY)。\n *\n * 用于区分「走新版 `/v1/storages/*` 网关」还是「走旧版 CLOUD_API(`request.send`)」。\n */\n public isGateWay() {\n // @ts-ignore\n const { config } = this\n const endPointMode = config.endPointMode || 'CLOUD_API'\n\n return endPointMode === 'GATEWAY'\n }\n\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'uploadFile',\n },\n title: '上传文件失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 uploadFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async uploadFile(\n params: Omit<ICloudbaseUploadFileParams, 'filePath'> & { filePath?: string },\n callback?: Function,\n ): Promise<ICloudbaseUploadFileResult> {\n const { cloudPath, filePath, onUploadProgress, method = 'put', headers = {}, fileContent } = params\n if (!isString(cloudPath) || (!filePath && !fileContent)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.uploadFile] invalid params`,\n }),)\n }\n const uploadMethod = { put: EUploadMethod.put, post: EUploadMethod.post }[method.toLocaleLowerCase()] || EUploadMethod.put\n\n const isGateway = this.isGateWay()\n const signedHeaders: Record<string, string> = { ...headers }\n const uploadHeaders: Record<string, string> = Object.keys(headers).reduce((result: Record<string, string>, key) => {\n if (key.toLowerCase() !== 'content-length') {\n result[key] = headers[key]\n }\n return result\n }, {})\n\n // 网关 PUT 直传时,COS 签名需要 content-length / content-type 参与;\n // 也会用它们校验 Bucket 的 file_size_limit / allowed_mime_types 配置,\n // 否则后端 get-objects-upload-info 会报 STORAGE_CONTENT_LENGTH_REQUIRED 等错误。\n // content-length 仅用于 signedHeader,不污染实际 XHR headers;content-type 需要参与签名也需要实际发送。\n if (uploadMethod === EUploadMethod.put && isGateway) {\n if (!hasHeader(signedHeaders, 'content-length')) {\n const byteLength = resolveUploadByteLength(filePath, fileContent)\n if (typeof byteLength === 'number') {\n signedHeaders['content-length'] = String(byteLength)\n }\n }\n if (!hasHeader(signedHeaders, 'content-type')) {\n // 优先取内容自带的 MIME(Blob.type),否则按 cloudPath 扩展名兜底\n signedHeaders['content-type'] = inferContentType(filePath, cloudPath)\n }\n if (!hasHeader(uploadHeaders, 'content-type')) {\n uploadHeaders['content-type'] = inferContentType(filePath, cloudPath)\n }\n }\n\n // 调用 getUploadMetadata 获取上传元数据\n const metadataResult = await this.getUploadMetadata({\n cloudPath,\n method: uploadMethod,\n headers: uploadMethod === EUploadMethod.put && !isGateway ? uploadHeaders : undefined,\n signedHeader: uploadMethod === EUploadMethod.put && isGateway ? toSignedHeader(signedHeaders) : undefined,\n customReqOpts: params.customReqOpts,\n })\n\n const { data: metadata, requestId } = metadataResult\n\n // 网关获取上传信息失败(如 STORAGE_CONTENT_LENGTH_REQUIRED)时,metadata 会带 code/message\n // 而无 url/authorization/token;必须在此中断,避免拿空 url 继续发起无效 PUT 上传。\n const metaErr: any = metadata\n if (metaErr?.code || !metaErr?.url) {\n const code = metaErr?.code || ERRORS.OPERATION_FAIL\n const message = metaErr?.message || 'get upload info failed'\n return execCallback(\n callback,\n new Error(`[${getSdkName()}][${code}][${COMPONENT_NAME}]:${message}`),\n )\n }\n\n const { url, authorization, token, fileId, cosFileId, download_url: downloadUrl } = metadata\n\n const commonParams = {\n url,\n file: filePath,\n name: cloudPath,\n onUploadProgress,\n fileContent,\n fileId,\n requestId,\n }\n\n const putParams = {\n ...commonParams,\n method: EUploadMethod.put,\n headers: {\n ...uploadHeaders,\n authorization,\n 'x-cos-meta-fileid': cosFileId,\n 'x-cos-security-token': token,\n },\n }\n\n const postParams = {\n ...commonParams,\n method: EUploadMethod.post,\n data: {\n key: cloudPath,\n signature: authorization,\n 'x-cos-meta-fileid': cosFileId,\n success_action_status: '201',\n 'x-cos-security-token': token,\n },\n }\n\n const uploadConfig = {\n [EUploadMethod.put]: {\n params: putParams,\n isSuccess: (code: number) => code >= 200 && code < 300,\n },\n [EUploadMethod.post]: {\n params: postParams,\n isSuccess: (code: number) => code === 201,\n },\n }\n\n // @ts-ignore\n const res = await this.request.upload(uploadConfig[uploadMethod].params)\n\n if (uploadConfig[uploadMethod].isSuccess(res.statusCode)) {\n return execCallback(callback, null, {\n fileID: fileId,\n download_url: downloadUrl,\n requestId,\n })\n }\n return execCallback(\n callback,\n new Error(`[${getSdkName()}][${ERRORS.OPERATION_FAIL}][${COMPONENT_NAME}]:${res.data}`),\n )\n }\n\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'getUploadMetadata',\n },\n title: '获取上传元信息失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 getUploadMetadata() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async getUploadMetadata(\n params: ICloudbaseGetUploadMetadataParams & {\n method?: EUploadMethod\n headers?: Record<string, string>\n signedHeader?: SignedHeader\n },\n callback?: Function,\n ): Promise<{ data: IUploadMetadata; requestId: string }> {\n const { cloudPath, method, headers, signedHeader } = params\n if (!isString(cloudPath)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getUploadMetadata] invalid cloudPath`,\n }),)\n }\n // @ts-ignore\n const { request } = this\n const action = 'storage.getUploadMetadata'\n\n try {\n let metaData: ICloudbaseFileMetaDataRes\n\n const metaDataParam: {\n path: string\n method?: EUploadMethod\n headers?: Record<string, string>\n signedHeader?: SignedHeader\n } = { path: cloudPath }\n const isGateway = this.isGateWay()\n\n if (method) {\n metaDataParam.method = method\n }\n if (method === EUploadMethod.put) {\n if (isGateway && signedHeader) {\n metaDataParam.signedHeader = signedHeader\n } else if (!isGateway && headers) {\n metaDataParam.headers = headers\n }\n }\n\n if (isGateway) {\n metaData = await storageGateWay.getUploadInfo(request, metaDataParam, params.customReqOpts)\n } else {\n metaData = await request.send(action, metaDataParam, params.customReqOpts)\n }\n return execCallback(callback, null, metaData)\n } catch (err) {\n return execCallback(callback, err)\n }\n }\n\n /**\n * 删除文件(按 fileID 批量)。\n *\n * 服务端从 `cloudObjectId` 反解 `bucket_id + name`,先按 RLS 删 `storage.objects`\n * 元数据再删 COS 对象;调用方传的 fileID 应来自上传返回值(已含 bucket 段)。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'deleteFile',\n },\n title: '删除文件失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 deleteFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async deleteFile(\n params: ICloudbaseDeleteFileParams,\n callback?: Function,\n ): Promise<ICloudbaseDeleteFileResult> {\n const { fileList } = params\n\n if (!fileList || !isArray(fileList) || fileList.length === 0) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.deleteFile] fileList must not be empty`,\n }),)\n }\n\n for (const fileId of fileList) {\n if (!fileId || !isString(fileId)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.deleteFile] fileID must be string`,\n }),)\n }\n }\n\n const action = 'storage.batchDeleteFile'\n // @ts-ignore\n const { request } = this\n let res: any = {}\n\n if (this.isGateWay()) {\n res = await storageGateWay.delete(request, { fileList }, params.customReqOpts)\n } else {\n res = await request.send(\n action,\n {\n fileid_list: fileList,\n },\n params.customReqOpts,\n )\n }\n\n if (res.code) {\n return execCallback(callback, null, res)\n }\n const data = {\n fileList: res.data.delete_list,\n requestId: res.requestId,\n }\n return execCallback(callback, null, data)\n }\n\n /**\n * 获取文件临时下载链接(按 fileID 批量)。\n *\n * 服务端从 `cloudObjectId` 拆出 `bucket_id + name`,先查元数据并执行 RLS 校验,\n * 再经 COS `HEAD` 确认物理文件后生成下载 URL(无权限或不存在则该项返回错误码)。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'getTempFileURL',\n },\n title: '获取文件下载链接',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 getTempFileURL() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async getTempFileURL(\n params: ICloudbaseGetTempFileURLParams,\n callback?: Function,\n ): Promise<ICloudbaseGetTempFileURLResult> {\n const { fileList } = params\n\n if (!fileList || !isArray(fileList) || fileList.length === 0) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] fileList must not be empty`,\n }),)\n }\n\n const convertedFileList: Array<{ fileid: string; max_age?: number }> = []\n for (const file of fileList) {\n if (isPalinObject(file)) {\n if (!Object.prototype.hasOwnProperty.call(file, 'fileID')) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] file info must include fileID`,\n }),)\n }\n\n convertedFileList.push({\n fileid: (file as ICloudbaseFileInfo).fileID,\n max_age: (file as ICloudbaseFileInfo).maxAge || 7200,\n })\n } else if (isString(file)) {\n convertedFileList.push({\n fileid: file as string,\n })\n } else {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] invalid fileList`,\n }),)\n }\n }\n\n const action = 'storage.batchGetDownloadUrl'\n // @ts-ignore\n const { request } = this\n let res: any = {}\n\n if (this.isGateWay()) {\n res = await storageGateWay.getDownLoadInfo(request, { convertedFileList }, params.customReqOpts)\n } else {\n res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)\n }\n\n if (res.code) {\n return execCallback(callback, null, res)\n }\n\n return execCallback(callback, null, {\n fileList: res.data.download_list,\n requestId: res.requestId,\n })\n }\n\n /**\n * 下载文件,返回内容(内部先取临时 URL 再拉取)。\n *\n * 同 `getTempFileURL`,先经元数据 + RLS 校验再下载;`fileID` 须含 bucket 段。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'downloadFile',\n },\n title: '下载文件失败',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 downloadFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async downloadFile(\n params: ICloudbaseDownloadFileParams,\n callback?: Function,\n ): Promise<ICloudbaseDownloadFileResult> {\n const { fileID } = params\n if (!isString(fileID)) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.getTempFileURL] fileID must be string`,\n }),)\n }\n\n const tmpUrlRes = await this.getTempFileURL.call(this, {\n fileList: [\n {\n fileID,\n maxAge: 600,\n },\n ],\n customReqOpts: params.customReqOpts,\n })\n\n const res = tmpUrlRes.fileList![0]\n\n if (res.code !== 'SUCCESS') {\n return execCallback(callback, res)\n }\n // @ts-ignore\n const { request } = this\n\n const tmpUrl = encodeURI(res.download_url!)\n\n const result = await request.download({ url: tmpUrl, tempFilePath: params.tempFilePath })\n return execCallback(callback, null, result)\n }\n\n /**\n * 批量复制文件(按源/目标 fileID)。\n *\n * 服务端从源/目标路径各拆出 `bucket_id + name`,经 RLS 校验读写权限后执行\n * 底层 COS 复制(支持跨 bucket,前提是两个 bucket 段都解析成功且有权限)。\n */\n @catchErrorsDecorator({\n customInfo: {\n className: 'Cloudbase',\n methodName: 'copyFile',\n },\n title: '批量复制文件',\n messages: [\n '请确认以下各项:',\n ' 1 - 调用 copyFile() 的语法或参数是否正确',\n ' 2 - 当前域名是否在安全域名列表中:https://console.cloud.tencent.com/tcb/env/safety',\n ' 3 - 云存储安全规则是否限制了当前登录状态访问',\n `如果问题依然存在,建议到官方问答社区提问或寻找帮助:${COMMUNITY_SITE_URL}`,\n ],\n })\n public async copyFile(params: ICloudbaseCopyFileParams, callback?: Function): Promise<ICloudbaseCopyFileResult> {\n const { fileList } = params\n\n if (!fileList || !isArray(fileList) || fileList.length === 0) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.copyFile] fileList must not be empty`,\n }),)\n }\n\n const convertedFileList = []\n\n for (const file of fileList) {\n const { srcPath, dstPath } = file\n if (!srcPath || !dstPath || typeof srcPath !== 'string' || typeof dstPath !== 'string') {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath may not be empty`,\n }),)\n }\n if (srcPath === dstPath) {\n throw new Error(JSON.stringify({\n code: ERRORS.INVALID_PARAMS,\n msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath can not be the same`,\n }),)\n }\n // if (basename(srcPath) !== basename(dstPath)) {\n // throw new Error(JSON.stringify({\n // code: ERRORS.INVALID_PARAMS,\n // msg: `[${COMPONENT_NAME}.copyFile] srcPath and dstPath file name must be the same`,\n // }),)\n // }\n convertedFileList.push({\n src_path: srcPath,\n dst_path: dstPath,\n overwrite: file.overwrite,\n remove_original: file.removeOriginal,\n })\n }\n\n // @ts-ignore\n const { request } = this\n let res: any = {}\n\n if (this.isGateWay()) {\n res = await storageGateWay.copyFile(request, { convertedFileList }, params.customReqOpts)\n } else {\n const action = 'storage.batchCopyFile'\n res = await request.send(action, { file_list: convertedFileList }, params.customReqOpts)\n }\n\n if (res.code) {\n return execCallback(callback, null, res)\n }\n\n return execCallback(callback, null, {\n fileList: res.data.copy_list,\n requestId: res.requestId,\n })\n }\n\n /**\n * 获取文件元信息(大小、contentType、etag、lastModified 等,内部基于临时 URL + COS HEAD)。\n *\n * 服务端解析 `bucket_id + name` 并通过 RLS 后返回;元数据以 COS 对象为准\n * (`storage.objects` 的完整元信息建议改用 `from(bucketId).info()`)。\n */\n public async getFileInfo(params: ICloudbaseGetTempFileURLParams): Promise<{\n fileList: FileInfoItem[]\n requestId: string\n }> {\n const fileInfo = await this.getTempFileURL(params)\n\n if (fileInfo?.fileList && fileInfo?.fileList?.length > 0) {\n const fileList = await Promise.all(fileInfo.fileList.map(async (item: TempFileURLItem) => {\n if (item.code !== 'SUCCESS') {\n return {\n code: item.code,\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n message: item.message,\n }\n }\n\n try {\n // @ts-ignore\n const { request } = this\n const res = await request.fetch({ url: item.tempFileURL, method: 'HEAD' })\n let { header } = res\n\n if (typeof Headers !== 'undefined' && header instanceof Headers) {\n const normalizedHeader: Record<string, string> = {}\n header.forEach((value, key) => {\n normalizedHeader[key] = value\n })\n header = normalizedHeader\n }\n // eslint-disable-next-line radix\n const fileSize = parseInt(header['content-length']) || 0\n const contentType = header['content-type'] || ''\n\n if ([400, 404].includes(Number(res.statusCode))) {\n return {\n code: 'FILE_NOT_FOUND',\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n message: 'file not found',\n }\n }\n\n const fileInfo: FileInfoItem = {\n code: item.code,\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n cloudId: item.fileID,\n fileName: item.fileID.split('/').pop(),\n contentType,\n mime: contentType.split(';')[0].trim(),\n size: fileSize,\n etag: header.etag || '',\n lastModified: header['last-modified'] || '',\n cacheControl: header['cache-control'] || '',\n }\n\n return fileInfo\n } catch (e) {\n const message = typeof e === 'object' && e !== null && 'message' in e\n ? String((e as { message?: unknown }).message)\n : undefined\n return {\n code: 'FETCH_FILE_INFO_ERROR',\n fileID: item.fileID,\n tempFileURL: item.tempFileURL,\n message,\n }\n }\n }),)\n\n return {\n fileList,\n requestId: fileInfo.requestId!,\n }\n }\n\n return {\n fileList: [],\n requestId: fileInfo.requestId!,\n }\n }\n}\n","import { constants } from '@cloudbase/utilities'\nimport { Camelize, FileBody, FileObject, FileObjectV2, FileOptions, TransformOptions } from './supabase/types'\nimport { Result } from './types'\nimport { isStorageError, StorageError } from './supabase/errors'\nimport { CloudbaseStorage, ICloudbaseContext, COMPONENT_NAME } from './cloudbase-storage'\nimport { toBase64 } from './encoding'\n\nconst { ERRORS } = constants\n\n/**\n * 传统 CloudBase 对象操作客户端(Supabase-like 包装层,底层仍走传统云存储 HTTP API,即 `CloudbaseStorage` 的顶层方法)。\n *\n * 通过 `app.storage.from()`(不传 bucketId)获取,与 PG 原生的 `StorageFileApi` 对等但**通道不同**。\n *\n * 两环境下的行为:\n * - 传统环境:原生用法,`upload/download/remove` 走传统接口,path 为 COS Bucket 内相对路径。\n * - Neo 环境:因底层仍是传统兼容路径,**path 第一段同样会被服务端当作 PG `bucket_id`**;\n * 且本类 `bucketId` 恒为空串、构造时从不赋值,故 `getPublicUrl/createSignedUrl` 等需要拼 `cloud://` 的方法\n * 必须传**完整 fileID**(而非相对 path),否则 `_normalizeCloudId` 抛 `bucketId is not set`。\n * PG 环境若要按 bucket 语义做原生对象操作,应改用 `app.storage.from(bucketId)`(StorageFileApi)。\n */\nexport class ClassicStorageFileApi {\n protected shouldThrowOnError = false\n protected bucketId = ''\n protected context?: ICloudbaseContext\n\n /**\n * 底层传统云存储能力(组合而非继承)。\n *\n * 本类只是把这套底层方法(`uploadFile` / `copyFile` / `getTempFileURL` / `getFileInfo` /\n * `deleteFile` / `getUploadMetadata`)重新包装成 Supabase 风格签名,因此通过**委托**复用,\n * 而不继承——避免把基类的传统 API 一并暴露在本类实例上。\n *\n * 这里刻意标注为 `any`:基类方法均挂 `@catchErrorsDecorator`,该装饰器签名 TS 无法解析,\n * 原先继承时 `this.uploadFile()` 等返回值本就被降级为 `any`,本类的结果处理代码也是按 `any` 编写的。\n * 用 `any` 持有可忠实保留改造前的行为,避免暴露一批本被掩盖的松散类型告警。\n */\n private storage: any\n\n constructor(context?: ICloudbaseContext, shouldThrowOnError = false) {\n this.context = context\n this.shouldThrowOnError = shouldThrowOnError\n // 注入同一 context,使底层 storage 的 config/request 与本类一致\n this.storage = new CloudbaseStorage(context)\n }\n\n get config() {\n // @ts-ignore\n return this.context?.config\n }\n\n get request() {\n // @ts-ignore\n return this.context?.request\n }\n\n throwOnError(): this {\n this.shouldThrowOnError = true\n return this\n }\n\n /**\n * 上传文件。\n *\n * 与 Supabase `StorageFileApi.upload(path, fileBody, fileOptions?)` 的差异:\n * - **参数命名**:一致(`path` / `fileBody` / `fileOptions`)。\n * - **默认行为**:本实现默认 `upsert: true`(覆盖),Supabase 默认 `upsert: false`(不覆盖)。\n * - **metadata 传递**:经 CloudBase 私有头 `x-cos-metadata-metadata` 传递,Supabase 走 `x-metadata` / FormData。\n * - **返回值**:`fullPath` 直接等于入参 `path`;Supabase 的 `fullPath` 为 `bucketId/path` 形态。\n */\n async upload(\n path: string,\n fileBody: FileBody,\n fileOptions?: FileOptions,\n ): Promise<\n Result<{ id: string; path: string; fullPath: string }>\n > {\n const options = { upsert: true, ...fileOptions }\n const { cacheControl, contentType, metadata } = options\n try {\n const cloudPath = this.getCloudPath(path)\n const uploadFileParams: Parameters<CloudbaseStorage['uploadFile']>[0] = {\n cloudPath,\n filePath: fileBody as any,\n }\n\n if (cacheControl || contentType || metadata) {\n const headers: Record<string, string> = {}\n if (cacheControl) {\n headers['cache-control'] = cacheControl\n }\n if (contentType) {\n headers['content-type'] = contentType\n }\n\n if (metadata) {\n headers['x-cos-metadata-metadata'] = this.toBase64(JSON.stringify(metadata))\n }\n\n uploadFileParams.headers = headers\n }\n\n const result = await this.storage.uploadFile(uploadFileParams)\n\n // IUploadFileRes 没有 code 字段,如果没有 fileID 则表示失败\n if (!result.fileID) {\n throw new Error(JSON.stringify({\n code: ERRORS.OPERATION_FAIL,\n msg: `[${COMPONENT_NAME}.update] no fileID returned`,\n }),)\n }\n\n return {\n data: {\n id: result.fileID,\n path,\n fullPath: path,\n },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 使用签名 URL 上传文件。\n *\n * 与 Supabase `StorageFileApi.uploadToSignedUrl(path, token, fileBody, fileOptions?)` 的差异:\n * - **参数命名**:一致,但第二参 `token` 在本实现中被**忽略**(命名为 `_token`)。\n * - **行为**:不走签名 URL 通道,内部直接委托 `upload()`,因此 `token` 无实际作用。\n */\n async uploadToSignedUrl(\n path: string,\n _token: string,\n fileBody: FileBody,\n fileOptions?: FileOptions,\n ): Promise<\n Result<{ id: string; path: string; fullPath: string }>\n > {\n return this.upload(path, fileBody, fileOptions)\n }\n\n /**\n * 创建签名上传 URL。\n *\n * 与 Supabase `StorageFileApi.createSignedUploadUrl(path, options?: { upsert })` 的差异:\n * - **参数缺失**:**缺第二参 `options`**(不支持 `upsert`)。\n * - **返回值**:在 `{ signedUrl, token, path }` 基础上额外返回 CloudBase 私有字段\n * `authorization` / `id` / `cosFileId` / `downloadUrl`(供 `uploadToSignedUrl` 等使用)。\n */\n async createSignedUploadUrl(path: string): Promise<\n Result<{\n signedUrl: string\n token: string\n path: string\n // CloudBase 额外的元数据字段\n authorization?: string\n id?: string\n cosFileId?: string\n downloadUrl?: string\n }>\n > {\n try {\n const cloudPath = this.getCloudPath(path)\n\n const { data: metadata } = await this.storage.getUploadMetadata({ cloudPath })\n\n return {\n data: {\n signedUrl: metadata.url,\n token: metadata.token,\n path,\n // 返回 CloudBase 的额外元数据,供 uploadToSignedUrl 使用\n authorization: metadata.authorization,\n id: metadata.fileId,\n cosFileId: metadata.cosFileId,\n downloadUrl: metadata.download_url,\n },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n return {\n data: null,\n error: error instanceof StorageError ? error : new StorageError(error.message),\n }\n }\n }\n\n /**\n * 更新(覆盖)文件。\n *\n * 与 Supabase `StorageFileApi.update(path, fileBody, fileOptions?)` 的差异:\n * - **参数命名**:一致。\n * - **行为**:强制 `upsert: true` 后委托 `upload()`;Supabase 的 `update` 同样总是覆盖,语义基本一致。\n */\n async update(\n path: string,\n fileBody: FileBody,\n fileOptions?: FileOptions,\n ): Promise<\n Result<{ id: string; path: string; fullPath: string }>\n > {\n return this.upload(path, fileBody, { ...fileOptions, upsert: true })\n }\n\n /**\n * 移动文件。\n *\n * 与 Supabase `StorageFileApi.move(fromPath, toPath, options?: DestinationOptions)` 的差异:\n * - **参数缺失**:**缺第三参 `options`**(不支持 `destinationBucket` 等,已注释占位)。\n * - **底层实现**:通过 `copyFile(removeOriginal: true)` 模拟移动。\n * - **返回值**:`data.message` 为 `File moved from X to Y`;Supabase 固定返回 `Successfully moved`。\n */\n async move(\n fromPath: string,\n toPath: string,\n // options?: DestinationOptions,\n ): Promise<Result<{ message: string }>> {\n try {\n const result = await this.storage.copyFile({\n fileList: [\n {\n srcPath: this.getCloudPath(fromPath),\n dstPath: this.getCloudPath(toPath),\n overwrite: true,\n removeOriginal: true,\n },\n ],\n })\n\n if (result.fileList[0].code && result.fileList[0].code !== 'SUCCESS') {\n throw new StorageError(result.fileList[0].message || 'Move failed')\n }\n\n return {\n data: { message: `File moved from ${fromPath} to ${toPath}` },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 复制文件。\n *\n * 与 Supabase `StorageFileApi.copy(fromPath, toPath, options?: DestinationOptions)` 的差异:\n * - **参数缺失**:**缺第三参 `options`**(不支持 `destinationBucket` 等,已注释占位)。\n * - **返回值**:`data.path` 为清洗后的目标相对路径;Supabase 返回后端 `data.Key`(`bucketId/path` 形态)。\n */\n async copy(\n fromPath: string,\n toPath: string,\n // options?: DestinationOptions,\n ): Promise<Result<{ path: string }>> {\n try {\n const result = await this.storage.copyFile({\n fileList: [\n {\n srcPath: this.getCloudPath(fromPath),\n dstPath: this.getCloudPath(toPath),\n overwrite: true,\n removeOriginal: false,\n },\n ],\n })\n\n if (result.fileList[0].code && result.fileList[0].code !== 'SUCCESS') {\n throw new StorageError(result.fileList[0].message || 'Copy failed')\n }\n\n return {\n data: { path: this.getCloudPath(toPath) },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return { data: null, error }\n }\n throw error\n }\n }\n\n /**\n * 创建签名下载 URL。\n *\n * 与 Supabase `StorageFileApi.createSignedUrl(path, expiresIn, options?: { download, transform, cacheNonce })` 的差异:\n * - **参数命名**:一致(`path` / `expiresIn` / `options`)。\n * - **options 缺字段**:仅支持 `download` / `transform`,**缺 `cacheNonce`**。\n * - **底层实现**:基于 `getTempFileURL` 的临时 URL;`transform` 走腾讯云数据万象 imageMogr2,与 Supabase 的转换参数不同。\n */\n async createSignedUrl(\n path: string,\n expiresIn: number,\n options?: {\n download?: string | boolean\n transform?: TransformOptions\n },\n ): Promise<Result<{ signedUrl: string }>> {\n try {\n const cloudPath = this.normalizeCloudId(path)\n const result = await this.storage.getTempFileURL({\n fileList: [\n {\n fileID: cloudPath,\n maxAge: expiresIn,\n },\n ],\n })\n\n // IGetFileUrlItem 有 code 字段但没有 message 字段\n if (result.fileList[0].code !== 'SUCCESS') {\n throw new StorageError(`Failed to create signed URL: [${result.fileList[0].code}] ${result.fileList[0].fileID}`)\n }\n\n let signedUrl = result.fileList[0].download_url\n\n // 构建查询参数\n const queryParams: string[] = []\n\n // 如果有 download 参数,添加到 URL 中\n if (options?.download !== undefined) {\n if (typeof options.download === 'string') {\n // download 是文件名\n queryParams.push(`download=${encodeURIComponent(options.download)}`)\n } else if (options.download === true) {\n // download 是 true,使用原文件名或默认值\n queryParams.push('download=true')\n }\n }\n\n // 如果有图片转换参数,添加到 URL 中\n if (options?.transform) {\n const transformQuery = this.transformOptsToQueryString(options.transform)\n if (transformQuery) {\n queryParams.push(transformQuery)\n }\n }\n\n // 拼接所有查询参数\n if (queryParams.length > 0) {\n const separator = signedUrl.includes('?') ? '&' : '?'\n signedUrl = `${signedUrl}${separator}${queryParams.join('&')}`\n }\n\n return {\n data: { signedUrl },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 批量创建签名下载 URL。\n *\n * 与 Supabase `StorageFileApi.createSignedUrls(paths, expiresIn, options?: { download, cacheNonce })` 的差异:\n * - **参数缺失**:**缺第三参 `options`**(不支持 `download` / `cacheNonce`,已注释占位)。\n * - **返回项结构**:`{ path, signedUrl, error }`;Supabase 还会返回原始 `signedURL` 字段。\n */\n async createSignedUrls(\n paths: string[],\n expiresIn: number,\n // options?: {\n // download?: string | boolean\n // },\n ): Promise<\n Result<Array<{ path: string; signedUrl: string; error: string | null }>>\n > {\n try {\n const fileList = paths.map(p => ({\n fileID: this.normalizeCloudId(p),\n maxAge: expiresIn,\n }))\n\n const result = await this.storage.getTempFileURL({ fileList })\n\n return {\n data: result.fileList.map((item: any, index: number) => ({\n path: paths[index],\n signedUrl: item.tempFileURL || '',\n error: item.code === 'SUCCESS' ? null : item.message,\n })),\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 下载文件,返回 Blob。\n *\n * 与 Supabase `StorageFileApi.download(path, options?: { transform, cacheNonce }, parameters?)` 的差异:\n * - **第二参类型**:本实现 `options` 直接是 `TransformOptions`,Supabase 是包裹形态 `{ transform, cacheNonce }`。\n * - **参数缺失**:缺 `cacheNonce`、以及第三参 `parameters`(fetch 选项 / AbortSignal)。\n * - **返回值**:返回 `Promise<{ data: Blob; error }>`;Supabase 返回 `BlobDownloadBuilder`(可链式 `throwOnError`)。\n */\n async download(\n path: string,\n options?: TransformOptions,\n ): Promise<{\n data: Blob | null\n error: StorageError | null\n }> {\n try {\n return {\n data: await (async () => {\n const signedUrlResult = await this.createSignedUrl(path, 600, { transform: options })\n if (signedUrlResult.error) {\n throw signedUrlResult.error\n }\n const tmpUrl = encodeURI(signedUrlResult.data?.signedUrl)\n\n const { data } = await (this as any).request.reqClass.get({\n url: tmpUrl,\n headers: {}, // 下载资源请求不经过service,header清空\n responseType: 'blob',\n })\n\n if (!data) {\n throw new StorageError('Download failed: no file content')\n }\n\n // 将 Buffer 转换为 Uint8Array 以兼容 Blob\n return new Blob([data])\n })(),\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 获取文件信息\n *\n * 与 Supabase `StorageFileApi.info(path)` 的差异:\n * - **参数命名**:本实现命名为 `pathOrFileId`(Supabase 为 `path`),且额外支持传入 `cloud://` 完整 fileID。\n * - **返回值**:同为 `Camelize<FileObjectV2>`,但 `metadata` 恒为 `{}`、`version` 恒为 `'1'`,部分时间字段为近似值。\n *\n * @param pathOrFileId - 相对路径(如 'images/photo.jpg')或 CloudBase fileID(以 'cloud://' 开头)\n * @returns 文件信息对象\n *\n * @example\n * ```typescript\n * // 使用相对路径\n * const { data } = await bucket.info('images/photo.jpg')\n *\n * // 使用 CloudBase fileID\n * const { data } = await bucket.info('cloud://env-id.xxxx-xxxx/images/photo.jpg')\n * ```\n */\n async info(pathOrFileId: string,): Promise<Result<Camelize<FileObjectV2>>> {\n try {\n // 判断是 fileID 还是相对路径\n const isFileId = pathOrFileId.startsWith('cloud://')\n const displayName = isFileId ? this.extractPathFromFileId(pathOrFileId) : pathOrFileId\n const bucketId = isFileId ? this.extractBucketFromFileId(pathOrFileId) : this.bucketId\n\n const fileInfo = await this.storage.getFileInfo({\n fileList: [this.normalizeCloudId(pathOrFileId)],\n })\n\n const item = fileInfo.fileList[0]\n\n if (item.code !== 'SUCCESS') {\n throw new StorageError(item.message)\n }\n\n const now = new Date().toISOString()\n const lastModified = (item.lastModified ? new Date(item.lastModified) : new Date()).toISOString()\n return {\n data: {\n id: item.fileID,\n version: '1',\n name: displayName,\n bucketId,\n updatedAt: lastModified,\n createdAt: lastModified,\n lastAccessedAt: now,\n size: item.size,\n cacheControl: item.cacheControl,\n contentType: item.contentType,\n etag: item.etag,\n lastModified,\n metadata: {},\n },\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n return {\n data: null,\n error: error instanceof StorageError ? error : new StorageError(error.message),\n }\n }\n }\n\n /**\n * 判断文件是否存在。\n *\n * 与 Supabase `StorageFileApi.exists(path)` 的差异:\n * - **参数命名**:本实现命名为 `pathOrFileId`(Supabase 为 `path`),且额外支持 `cloud://` fileID。\n * - **底层实现**:基于 `getFileInfo`,将 `FILE_NOT_FOUND` 视为不存在;Supabase 用 HEAD 请求 + 400/404 判定。\n */\n async exists(pathOrFileId: string): Promise<Result<boolean>> {\n try {\n // 判断是 fileID 还是相对路径\n const fileInfo = await this.storage.getFileInfo({\n fileList: [this.normalizeCloudId(pathOrFileId)],\n })\n\n const item = fileInfo.fileList[0]\n\n if (item.code === 'FILE_NOT_FOUND') {\n return {\n data: false,\n error: null,\n }\n }\n\n if (item.code !== 'SUCCESS') {\n throw new StorageError(item.message)\n }\n\n return { data: true, error: null }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 获取公开访问 URL。\n *\n * 与 Supabase `StorageFileApi.getPublicUrl(path, options?)` 的差异:\n * - **同步性**:Supabase 为**同步**方法直接返回 `{ data: { publicUrl } }`;本实现为 **`async`**(返回 Promise),调用方式不兼容。\n * - **底层实现**:实际返回的是 600s 的签名 URL(基于 `createSignedUrl`),而非真正的永久公开直链。\n * - **options 缺字段**:支持 `download` / `transform`,缺 `cacheNonce`。\n * - **返回值**:失败时返回 `{ data: null, error }`;Supabase 不返回 error。\n */\n async getPublicUrl(\n path: string,\n options?: {\n download?: string | boolean\n transform?: TransformOptions\n },\n ): Promise<\n | {\n data: { publicUrl: string }\n }\n | { data: null; error: StorageError }\n > {\n const res = await this.createSignedUrl(path, 600, options)\n\n if (res.data) {\n return {\n data: { publicUrl: res.data.signedUrl },\n }\n }\n\n return { data: null, error: res.error as StorageError }\n }\n\n /**\n * 批量删除文件。\n *\n * 与 Supabase `StorageFileApi.remove(paths)` 的差异:\n * - **参数命名**:一致(`paths: string[]`)。\n * - **返回值**:返回的 `FileObject[]` 仍包含 Supabase 新版已不再返回的废弃字段(`bucket_id` / `owner` / `buckets`),\n * 且这些字段多为占位/未知值。\n * - **实现开销**:删除前会先分批(每组 10 个)拉取文件信息以补全返回结构。\n */\n async remove(paths: string[]): Promise<Result<FileObject[]>> {\n try {\n // 分组获取文件信息,每组最多10个\n const chunkSize = 10\n const pathChunks: string[][] = []\n for (let i = 0; i < paths.length; i += chunkSize) {\n pathChunks.push(paths.slice(i, i + chunkSize))\n }\n\n // 并行获取所有分组的文件信息\n const fileInfoResults = await Promise.all(pathChunks.map(chunk => Promise.all(chunk.map(path => this.info(path)))),)\n\n // 合并所有文件信息并构建映射表(path -> fileInfo)\n const fileInfoMap = new Map<string, Camelize<FileObjectV2>>()\n fileInfoResults.forEach((chunkResults, chunkIndex) => {\n chunkResults.forEach((result, index) => {\n if (result.data) {\n fileInfoMap.set(paths[chunkIndex * chunkSize + index], result.data)\n }\n })\n })\n\n // 执行删除操作\n const fileList = paths.map(p => this.normalizeCloudId(p))\n const result: { fileList: Array<{ code?: string }> } = await this.storage.deleteFile({ fileList })\n\n // IDeleteFileRes 的 fileList 数组中每个项有 code 字段\n const failedFiles = result.fileList.filter(item => item.code !== 'SUCCESS')\n if (failedFiles.length > 0) {\n throw new StorageError(`Delete failed for ${failedFiles.length} file(s)`)\n }\n\n const now = new Date().toISOString()\n\n // 使用获取到的文件信息构建返回数据\n return {\n data: paths.map((p) => {\n const info = fileInfoMap.get(p)\n return {\n name: info?.name,\n id: info?.id,\n bucket_id: info?.bucketId,\n owner: undefined, // 无法计算owner\n updated_at: info?.updatedAt || now,\n created_at: info?.createdAt,\n last_accessed_at: info?.lastAccessedAt || now,\n metadata: info?.metadata || {},\n /**\n * TODO: 获取补全 Bucket 信息\n */\n buckets: {\n id: info?.bucketId,\n name: info?.bucketId,\n owner: undefined, // 无法计算owner\n public: false, // 未知\n created_at: '', // 未知\n updated_at: now, // 未知\n },\n } as unknown as FileObject\n }),\n error: null,\n }\n } catch (error: any) {\n if (this.shouldThrowOnError) throw error\n if (isStorageError(error)) {\n return {\n data: null,\n error,\n }\n }\n throw error\n }\n }\n\n /**\n * 列举文件。\n *\n * 与 Supabase `StorageFileApi.list(path?, options?: SearchOptions, parameters?)` 的差异:\n * - **未实现**:本实现直接抛 `Not implemented`,且**无任何参数**;Supabase 支持前缀路径、分页/排序选项与 fetch 参数。\n */\n async list() {\n throw new StorageError('Not implemented')\n }\n\n private getCloudPath(path: string): string {\n // 清理路径:移除首尾斜杠,合并多个斜杠\n const cleanPath = path.replace(/^\\/|\\/$/g, '').replace(/\\/+/g, '/')\n\n // 否则返回清理后的相对路径\n return cleanPath\n }\n\n private normalizeCloudId(path: string) {\n // 如果已经是 cloud:// 格式,直接返回\n if (/^cloud:\\/\\//.test(path)) {\n return path\n }\n const cleanPath = this.getCloudPath(path)\n\n // 如果设置了 bucketId,构建完整的 cloud:// 路径\n if (this.bucketId) {\n // 获取环境 ID\n const envId = this.config?.env || ''\n if (envId) {\n return `cloud://${envId}.${this.bucketId}/${cleanPath}`\n }\n } else {\n throw new StorageError('bucketId is not set')\n }\n }\n\n private toBase64(data: string) {\n return toBase64(data)\n }\n\n /**\n * 将 TransformOptions 转换为腾讯云数据万象的 imageMogr2 查询字符串\n *\n * 腾讯云数据万象使用 imageMogr2 接口进行图片处理,支持以下参数:\n * - /thumbnail/<Width>x<Height> - 缩放\n * - /format/<Format> - 格式转换\n * - /quality/<Quality> - 质量调整\n * - /rquality/<Quality> - 相对质量\n *\n * @param transform - Supabase TransformOptions\n * @returns 腾讯云数据万象的查询字符串\n *\n * @example\n * ```typescript\n * transformOptsToQueryString({ width: 300, height: 200, quality: 80, format: 'origin' })\n * // 返回: 'imageMogr2/thumbnail/300x200/quality/80'\n * ```\n */\n private transformOptsToQueryString(transform: TransformOptions): string {\n const params: string[] = ['imageMogr2']\n\n // 处理缩放参数\n if (transform.width || transform.height) {\n const width = transform.width || ''\n const height = transform.height || ''\n\n // 根据 resize 模式选择不同的缩放方式\n if (transform.resize === 'fill') {\n // fill: 强制缩放到指定尺寸,可能变形\n params.push(`thumbnail/${width}x${height}!`)\n } else if (transform.resize === 'contain') {\n // contain: 等比缩放,完整显示在指定尺寸内\n params.push(`thumbnail/${width}x${height}`)\n } else {\n // cover (默认): 等比缩放,填充指定尺寸,可能裁剪\n // 使用 /thumbnail/<Width>x<Height>^ 表示填充模式\n params.push(`thumbnail/${width}x${height}^`)\n }\n }\n\n // 处理格式转换\n // format: 'origin' 表示保持原格式,不传此参数\n if (transform.format && transform.format !== 'origin') {\n params.push(`format/${transform.format}`)\n }\n\n // 处理质量参数\n if (transform.quality !== undefined) {\n // 腾讯云数据万象的 quality 参数范围是 1-100\n const quality = Math.max(1, Math.min(100, transform.quality))\n params.push(`quality/${quality}`)\n }\n\n return params.join('/')\n }\n\n /**\n * 从 CloudBase fileID 中提取文件路径\n *\n * @param fileId - CloudBase fileID (格式: cloud://env-id.bucket/path/to/file.jpg)\n * @returns 提取的文件路径\n *\n * @example\n * ```typescript\n * extractPathFromFileId('cloud://test-env.test-bucket/images/photo.jpg')\n * // 返回: 'images/photo.jpg'\n *\n * extractPathFromFileId('cloud://test-env.test-bucket/file.txt')\n * // 返回: 'file.txt'\n * ```\n */\n private extractPathFromFileId(fileId: string): string {\n // fileID 格式: cloud://env-id.bucket/path/to/file.jpg\n // 需要提取第一个 / 后面的所有内容(包括 bucket 和路径)\n // 然后再提取 bucket 后面的路径部分\n\n // 移除 cloud:// 前缀\n const withoutProtocol = fileId.replace(/^cloud:\\/\\//, '')\n\n // 分割为 [env-id.bucket, path, to, file.jpg]\n const parts = withoutProtocol.split('/')\n\n if (parts.length < 2) {\n // 如果无法解析,返回完整的 fileID\n return fileId\n }\n\n // 移除第一部分(env-id.bucket),返回剩余路径\n return parts.slice(1).join('/')\n }\n\n /**\n * 从 CloudBase fileID 中提取 bucket 名称\n *\n * @param fileId - CloudBase fileID (格式: cloud://env-id.bucket/path/to/file.jpg)\n * @returns 提取的 bucket 名称\n *\n * @example\n * ```typescript\n * extractBucketFromFileId('cloud://test-env.test-bucket/images/photo.jpg')\n * // 返回: 'test-bucket'\n *\n * extractBucketFromFileId('cloud://prod-env.my-bucket/file.txt')\n * // 返回: 'my-bucket'\n * ```\n */\n private extractBucketFromFileId(fileId: string): string {\n // fileID 格式: cloud://env-id.bucket/path/to/file.jpg\n // 需要提取 env-id.bucket 中的 bucket 部分\n\n // 移除 cloud:// 前缀\n const withoutProtocol = fileId.replace(/^cloud:\\/\\//, '')\n\n // 分割为 [env-id.bucket, path, to, file.jpg]\n const parts = withoutProtocol.split('/')\n\n if (parts.length < 1) {\n // 如果无法解析,返回默认 bucket\n return ''\n }\n\n // 第一部分是 env-id.bucket,提取 bucket 部分\n // 格式: env-id.bucket 或 env-id.bucket-name\n const envAndBucket = parts[0]\n\n // 查找第一个点的位置\n const dotIndex = envAndBucket.indexOf('.')\n\n if (dotIndex === -1) {\n // 如果没有点,返回整个字符串\n return envAndBucket\n }\n\n // 返回点后面的部分(bucket 名称)\n return envAndBucket.substring(dotIndex + 1)\n }\n}\n"],"names":["module","exports","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","d","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","StorageError","_super","message","_this","this","__isStorageError","name","__extends","Error","isStorageError","error","StorageApiError","status","statusCode","toJSON","getBuffer","globalThis","Buffer","toBase64","data","buffer","from","toString","btoa","encodeObjectName","cleanName","split","map","segment","encodeURIComponent","join","originalError","STORAGE_API_PREFIX","handleOperation","fn","shouldThrowOnError","Promise","_a","sent","error_1","String","Http","ctx","request","gatewayOrigin","getBaseEndPoint","buildUrl","path","query","url","concat","qs","parts","keys","forEach","value","push","buildQueryString","includes","toFullUrl","maybeRelative","test","startsWith","send","opts","method","toUpperCase","isBodyless","headers","__assign","rawBody","body","json","JSON","stringify","fetch","withCredentials","signal","cache","res","unwrap","download","stream","_c","aborted","Number","_b","response","header","code","toStorageError","buildHeadersAndQuery","options","cacheNonce","StreamDownloadBuilder","then","onfulfilled","onrejected","execute","http","bucketId","parameters","_d","DownloadBuilder","asStream","_e","blob","error_2","DEFAULT_UPLOAD_OPTIONS","StorageFileApi","throwOnError","setHeader","trim","upload","fileBody","fileOptions","uploadOrUpdate","update","cleanPath","list","__awaiter","prefix","limit","cursor","withDelimiter","with_delimiter","sortBy","remove","paths","names","n","result","i","length","batch","slice","prefixes","deleted","Array","isArray","apply","copy","fromPath","toPath","buildCopyMoveHeaders","sourceKey","destinationKey","destinationBucket","copyMetadata","metadata","Key","move","info","encodePath","id","version","bucket_id","size","contentType","content_type","cacheControl","cache_control","etag","lastModified","last_modified","createdAt","created_at","exists","createSignedUrl","expiresIn","base","fullSignedURL","signedURL","appendUrlOptions","createSignedUrls","item","createSignedUploadUrl","upsert","fullURL","token","uploadToSignedUrl","buildUploadBody","fullPath","getPublicUrl","publicUrl","Boolean","Id","clean","replace","some","seg","isFormData","FormData","Blob","file","fields","extracted","extractFromFormData","form","append","source","fileCount","ignoredFields","console","warn","params","separator","FORBIDDEN_BUCKET_ID_PATTERN","assertValidBucketId","caller","forbidden","exec","StorageBucketApi","context","listBuckets","offset","sortColumn","sortOrder","search","getBucket","createBucket","public","type","file_size_limit","fileSizeLimit","allowed_mime_types","allowedMimeTypes","updateBucket","deleteBucket","getSdkName","ERRORS","INVALID_PARAMS","INVALID_SYNTAX","INVALID_OPERATION","OPERATION_FAIL","NETWORK_ERROR","UNKOWN_ERROR","adapter_interface_namespaceObject","y","AbstractSDKRequest","__WEBPACK_EXTERNAL_MODULE__cloudbase_adapter_interface_74717cc6__","AbstractStorage","x","isString","val","printWarn","msg","RUNTIME","WebRequest","config","timeout","timeoutMsg","restrictedMethods","post","put","reqMethod","toLowerCase","formData","responseType","window","URL","createObjectURL","fileName","decodeURIComponent","pathname","pop","link","document","createElement","href","setAttribute","style","display","appendChild","click","revokeObjectURL","removeChild","resolve","tempFilePath","abortController","AbortController","enableAbort","_timeout","abort","addEventListener","timer","setTimeout","clearTimeout","ok","reject","catch","text","onUploadProgress","realUrl","PROTOCOL","urlHasQuery","queryString","formatUrl","ajax","XMLHttpRequest","open","payload","once","setRequestHeader","onreadystatechange","readyState","arr","getAllResponseHeaders","headerMap_1","line","shift","parse","responseText","e","toQueryString","TcbCacheObject","root","tcbCacheObject","setItem","getItem","removeItem","clear","CloudbaseCache","persistence","platformInfo","storage","persistenceTag","adapter","primaryStorage","localStorage","createStorage","mode","setStore","content","setStoreAsync","getStore","process","tcb_token","indexOf","getStoreAsync","removeStore","removeStoreAsync","CloudbaseEvent","IErrorEvent","CloudbaseEventEmitter","listeners","on","listener","customeAddEventListener","off","index","splice","customRemoveEventListener","fire","event","ev","listens","target","_i","handlers_1","__spreadArray","navigator","userAgent","external_jwt_decode_namespaceObject","external_jwt_decode_x","default","__WEBPACK_EXTERNAL_MODULE_jwt_decode_b659f100__","jwtDecode","EUploadMethod","constants","COMMUNITY_SITE_URL","utils","isPalinObject","execCallback","err","catchErrorsDecorator","customInfo","title","messages","methodName","descriptor","COMPONENT_NAME","storageGateWay","customReqOpts","gateWay","objectId","signedHeader","authorization","uploadUrl","fileId","cloudObjectId","cosFileId","cloudObjectMeta","download_url","downloadUrl","convertedFileList","v","fileid","download_list","fileID","tempFileURL","fileList","delete_list","srcPath","src_path","dstPath","dst_path","overwrite","removeOriginal","remove_original","copy_list","MIME_BY_EXT","txt","html","htm","css","js","csv","xml","png","jpg","jpeg","gif","webp","svg","ico","pdf","zip","gz","mp4","webm","mp3","wav","inferContentType","m","ext","hasHeader","lower","k","toSignedHeader","reduce","CloudbaseStorage","isGateWay","endPointMode","uploadFile","callback","cloudPath","filePath","fileContent","uploadMethod","toLocaleLowerCase","isGateway","signedHeaders","uploadHeaders","byteLength","ArrayBuffer","isView","resolveUploadByteLength","getUploadMetadata","metadataResult","requestId","metaErr","putParams","commonParams","postParams","signature","success_action_status","isSuccess","uploadConfig","action","metaData","metaDataParam","err_1","deleteFile","fileList_1","fileid_list","getTempFileURL","fileList_2","max_age","maxAge","file_list","downloadFile","tmpUrlRes","tmpUrl","encodeURI","copyFile","fileList_3","getFileInfo","fileInfo","all","Headers","normalizedHeader_1","fileSize","parseInt","cloudId","mime","e_1","__decorate","className","Function","_f","ICloudbaseDeleteFileParams","_g","_h","_j","ICloudbaseGetTempFileURLParams","_k","_l","_m","ICloudbaseDownloadFileParams","_o","_p","_q","ICloudbaseCopyFileParams","_r","_s","_t","ClassicStorageFileApi","getCloudPath","uploadFileParams","_token","signedUrl","error_3","error_4","normalizeCloudId","queryParams","transform","transformQuery","transformOptsToQueryString","error_5","p","error_6","signedUrlResult","reqClass","error_7","pathOrFileId","isFileId","displayName","extractPathFromFileId","extractBucketFromFileId","now","Date","toISOString","updatedAt","lastAccessedAt","error_8","error_9","chunkSize_1","pathChunks","chunk","fileInfoResults","fileInfoMap_1","Map","chunkResults","chunkIndex","set","failedFiles","filter","now_1","owner","updated_at","last_accessed_at","buckets","error_10","envId","env","width","height","resize","format","quality","Math","max","min","envAndBucket","dotIndex","substring","component","entity","StorageClient","supabaseComponent","IIFE","storageCache","WeakMap","has","instance","Proxy","_target","configurable","cloudbase","registerComponent","registerStorage","app","registerStorageOrigin"],"sourceRoot":""}