openapi: 3.0.3
info:
  title: PG Storage API
  version: 1.0.0
  description: '
    CloudBase PG 模式云存储 HTTP API，提供 Bucket 与 Object 的 CRUD、签名 URL、对象元信息、分片上传等能力。

    **适用环境**：PG 形态环境。传统形态环境请使用 [传统模式云存储 HTTP API](/http-api/storage/云存储)。

    **权限模型**：基于 PostgreSQL RLS（行级安全策略），三种角色：service_role（BYPASSRLS）、authenticated（受
    RLS 约束）、anon（受 RLS 约束）。详见 [PG 模式云存储 - 权限管理](/storage/pg/data-permission)。'
servers:
  - url: https://{envId}.api.tcloudbasegateway.com
    description: TCB openapi endpoint
    variables:
      envId:
        default: "your-envId"
        description: 环境 ID
tags:
  - name: Bucket
    description: 存储桶管理
  - name: Object
    description: 对象管理（上传、下载、删除、复制、移动）
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'JWT Bearer Token，通过 `Authorization: Bearer <token>` 头传递。

        Token 来源决定角色：

        - **service_role**：使用 service_role API Key 作为 token（服务端管理场景）

        - **authenticated**：使用用户登录后获取的 JWT（普通用户场景）

        - **anon**：不携带 Authorization 头或使用 anon key（匿名场景）'
  schemas:
    Bucket:
      type: object
      properties:
        id:
          type: string
          description: Bucket ID
          example: avatars
        name:
          type: string
          description: Bucket 名称
          example: avatars
        owner_id:
          type: string
          nullable: true
          description: 创建者 ID
        public:
          type: boolean
          description: 是否公开
          example: false
        type:
          type: string
          description: 存储桶类型
          enum:
            - STANDARD
            - ANALYTICS
          example: STANDARD
        file_size_limit:
          type: integer
          nullable: true
          description: 文件大小限制（字节）
          example: 1048576
        allowed_mime_types:
          type: array
          nullable: true
          items:
            type: string
          description: 允许的 MIME 类型
          example:
            - image/png
            - image/jpeg
        created_at:
          type: string
          format: date-time
          description: 创建时间
        updated_at:
          type: string
          format: date-time
          description: 更新时间
    ObjectUploadResult:
      type: object
      properties:
        Id:
          type: string
          description: 对象 UUID
          example: 550e8400-e29b-41d4-a716-446655440000
        Key:
          type: string
          description: 对象完整路径（bucketId/objectName）
          example: avatars/photo.png
    FullObjectResponse:
      type: object
      properties:
        name:
          type: string
        bucket_id:
          type: string
        owner_id:
          type: string
          nullable: true
        version:
          type: string
          nullable: true
        id:
          type: string
          nullable: true
        updated_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
          nullable: true
        last_accessed_at:
          type: string
          format: date-time
          nullable: true
        metadata:
          type: object
        user_metadata:
          type: object
    ObjectInfoResponse:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        version:
          type: string
          nullable: true
        bucket_id:
          type: string
        size:
          type: integer
          nullable: true
          description: 文件大小（字节）
        content_type:
          type: string
          nullable: true
        cache_control:
          type: string
          nullable: true
        etag:
          type: string
          nullable: true
        metadata:
          type: object
          description: 用户自定义元数据
        last_modified:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
          nullable: true
    ListObjectsV2Response:
      type: object
      properties:
        folders:
          type: array
          items:
            $ref: '#/components/schemas/ListObjectsV2Entry'
        objects:
          type: array
          items:
            $ref: '#/components/schemas/ListObjectsV2Entry'
        hasNext:
          type: boolean
        nextCursor:
          type: string
          description: 下一页游标
        nextCursorKey:
          type: string
          description: 下一页起始 key
    ListObjectsV2Entry:
      type: object
      properties:
        key:
          type: string
          nullable: true
        name:
          type: string
        id:
          type: string
          nullable: true
        updated_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
          nullable: true
        last_accessed_at:
          type: string
          format: date-time
          nullable: true
        metadata:
          type: object
          nullable: true
    SearchObjectResponse:
      type: object
      properties:
        name:
          type: string
        bucket_id:
          type: string
        owner_id:
          type: string
          nullable: true
        version:
          type: string
          nullable: true
        id:
          type: string
          nullable: true
        updated_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
          nullable: true
        last_accessed_at:
          type: string
          format: date-time
          nullable: true
        metadata:
          type: object
        user_metadata:
          type: object
    SignedURLResult:
      type: object
      properties:
        error:
          type: string
          nullable: true
        path:
          type: string
        signedURL:
          type: string
          nullable: true
        fullSignedURL:
          type: string
          nullable: true
    ErrorResponse:
      type: object
      description: WarpGinHandlerFunc 路径的错误响应格式（用于大部分接口：所有 bucket 接口 + 已改造的 object
        接口）
      properties:
        code:
          type: string
          description: 错误码，如 INVALID_PARAM、STORAGE_PG_REQUEST_FAIL
        message:
          type: string
          description: 错误信息，末尾会追加 docs 引用链接
        requestId:
          type: string
          description: 请求 ID
      required:
        - code
        - message
        - requestId
    StreamErrorResponse:
      type: object
      description: RespondWithError 路径的错误响应格式（用于流式/未改造的 object 接口：GetObject、GetPublicObject、GetSignedObject、HeadObjectInfo
        等）
      properties:
        statusCode:
          type: string
          description: HTTP 状态码字符串形式
        code:
          type: string
          description: 错误码
        error:
          type: string
          description: 与 code 相同
        message:
          type: string
          description: 错误信息
      required:
        - statusCode
        - error
        - message
    MessageResponse:
      type: object
      properties:
        message:
          type: string
  parameters:
    bucketId:
      name: bucketId
      in: path
      required: true
      schema:
        type: string
      description: Bucket ID
      example: avatars
    objectName:
      name: objectName
      in: path
      required: true
      schema:
        type: string
      description: 对象名称（支持路径，如 folder/file.png）
      example: folder/photo.png
paths:
  /v1/storages/bucket/:
    post:
      summary: 创建 Bucket
      tags:
        - Bucket
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  description: Bucket 名称，不能有前后空白
                  example: avatars
                id:
                  type: string
                  description: Bucket ID，为空时默认使用 name
                  example: avatars
                public:
                  type: boolean
                  description: 是否公开，默认 false
                  default: false
                file_size_limit:
                  anyOf:
                    - type: integer
                      minimum: 0
                      nullable: true
                      example: 1048576
                    - type: string
                      nullable: true
                      example: 100MB
                  description: 文件大小限制，支持整数（字节）或带单位字符串（如 100MB）；null 表示不限制
                allowed_mime_types:
                  type: array
                  nullable: true
                  items:
                    type: string
                  description: 允许上传的 MIME 类型列表
                  example:
                    - image/png
                    - image/jpeg
      responses:
        '200':
          description: 创建成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
        '400':
          description: '参数错误（name 缺失 / file_size_limit 超限 / 名称不合法） / 或缺少 Authorization
            头（message: headers must have required property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Bucket 已存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    get:
      summary: 获取 Bucket 列表
      tags:
        - Bucket
      security:
        - bearerAuth: []
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
          description: 分页限制
        - name: offset
          in: query
          schema:
            type: integer
            minimum: 0
          description: 分页偏移
        - name: sortColumn
          in: query
          schema:
            type: string
            enum:
              - id
              - name
              - created_at
              - updated_at
          description: 排序列
        - name: sortOrder
          in: query
          schema:
            type: string
            enum:
              - asc
              - desc
          description: 排序方向
        - name: search
          in: query
          schema:
            type: string
          description: 搜索关键词
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Bucket'
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/storages/bucket/{bucketId}:
    get:
      summary: 获取 Bucket 信息
      tags:
        - Bucket
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Bucket'
        '404':
          description: Bucket 不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '400':
          description: '缺少 Authorization 头（message: headers must have required property
            ''authorization''）'
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: string
                    example: '400'
                  error:
                    type: string
                    example: Error
                  message:
                    type: string
                    example: headers must have required property 'authorization'
    put:
      summary: 更新 Bucket
      tags:
        - Bucket
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                public:
                  type: boolean
                  description: 是否公开
                file_size_limit:
                  anyOf:
                    - type: integer
                      minimum: 0
                      nullable: true
                    - type: string
                      nullable: true
                  description: 文件大小限制
                allowed_mime_types:
                  type: array
                  nullable: true
                  items:
                    type: string
                  description: 允许的 MIME 类型
      responses:
        '200':
          description: 更新成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        '400':
          description: '参数错误 / body 不是 JSON 对象 / 或缺少 Authorization 头（message: headers
            must have required property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Bucket 不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    delete:
      summary: 删除 Bucket
      description: 删除 Bucket，仅当 Bucket 为空时可删除。
      tags:
        - Bucket
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
      responses:
        '200':
          description: 删除成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        '404':
          description: Bucket 不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Bucket 非空，无法删除
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '400':
          description: '缺少 Authorization 头（message: headers must have required property
            ''authorization''）'
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: string
                    example: '400'
                  error:
                    type: string
                    example: Error
                  message:
                    type: string
                    example: headers must have required property 'authorization'
  /v1/storages/object/list/{bucketId}:
    post:
      summary: 获取对象列表
      tags:
        - Object
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                prefix:
                  type: string
                  description: 路径前缀
                limit:
                  type: integer
                  minimum: 1
                  maximum: 1000
                  description: 分页限制
                cursor:
                  type: string
                  description: 游标（由上一次响应的 nextCursor 提供）
                with_delimiter:
                  type: boolean
                  description: 是否使用 / 作为分隔符区分文件夹
                sortBy:
                  type: object
                  properties:
                    column:
                      type: string
                      enum:
                        - name
                        - created_at
                        - updated_at
                    order:
                      type: string
                      enum:
                        - asc
                        - desc
                      default: asc
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListObjectsV2Response'
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/storages/object/{bucketId}/{objectName}:
    post:
      summary: 创建/上传对象
      description: '上传新对象到指定 Bucket。支持 multipart/form-data 和 binary body 两种上传方式。


        **Multipart 表单上传**：Content-Type 为 multipart/form-data，文件通过 file part 传递，可附带
        cacheControl、contentType、metadata 等字段。


        **Binary Body 直传**：Content-Type 为文件实际 MIME 类型（如 image/png），Body 直接为文件内容，元信息通过
        Header 传递。'
      tags:
        - Object
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
        - name: x-upsert
          in: header
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
          description: 设为 true 时允许覆盖已有对象
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                  description: 文件内容
                cacheControl:
                  type: string
                  description: 缓存时间（秒），自动转换为 max-age=<value>
                contentType:
                  type: string
                  description: 文件 MIME 类型（优先级高于 part header）
                metadata:
                  type: string
                  description: 自定义用户元数据，JSON 字符串，最大 1MB
          application/octet-stream:
            schema:
              type: string
              format: binary
              description: 文件二进制内容
          '*/*':
            schema:
              type: string
              format: binary
              description: 文件二进制内容，Content-Type 作为文件 MIME 类型
      responses:
        '200':
          description: 上传成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectUploadResult'
        '400':
          description: '对象名称不合法 / MIME 类型不被允许 / 或缺少 Authorization 头（message: headers
            must have required property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Bucket 不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: 对象已存在（未设置 x-upsert）
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: 文件大小超过限制
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    put:
      summary: 更新/覆盖对象
      description: '覆盖已有对象，等同于 x-upsert: true 的创建。上传方式同创建对象。'
      tags:
        - Object
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                cacheControl:
                  type: string
                contentType:
                  type: string
                metadata:
                  type: string
          '*/*':
            schema:
              type: string
              format: binary
      responses:
        '200':
          description: 更新成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectUploadResult'
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Bucket 不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '413':
          description: 文件大小超过限制
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    delete:
      summary: 删除对象
      tags:
        - Object
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
      responses:
        '200':
          description: 删除成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessageResponse'
        '404':
          description: 对象不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '400':
          description: '缺少 Authorization 头（message: headers must have required property
            ''authorization''）'
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: string
                    example: '400'
                  error:
                    type: string
                    example: Error
                  message:
                    type: string
                    example: headers must have required property 'authorization'
  /v1/storages/object/{bucketId}:
    delete:
      summary: 删除对象（批量）
      description: 批量删除指定 Bucket 中的多个对象，单次最多 100 个。
      tags:
        - Object
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - prefixes
              properties:
                prefixes:
                  type: array
                  items:
                    type: string
                  description: 要删除的对象名称列表，最多 100 个
                  example:
                    - folder/file1.png
                    - folder/file2.png
      responses:
        '200':
          description: 删除成功，返回被删除对象信息
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/FullObjectResponse'
        '400':
          description: 'INVALID_PARAM: prefixes is required and must not be empty
            / prefixes is too many, max is 100 / 或缺少 Authorization 头（message: headers
            must have required property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    get:
      summary: 下载对象
      description: 以流式方式下载对象。可选携带 JWT：有 JWT 则按角色鉴权；无 JWT 且 bucket 为 public 时以 SuperUser
        身份查询，非 public 则返回 404。
      tags:
        - Object
      security:
        - bearerAuth: []
        - {}
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
        - name: download
          in: query
          schema:
            type: string
          description: 触发浏览器下载，值作为文件名
        - name: If-None-Match
          in: header
          schema:
            type: string
          description: ETag 条件请求
        - name: If-Modified-Since
          in: header
          schema:
            type: string
          description: 时间条件请求
        - name: Range
          in: header
          schema:
            type: string
          description: 范围请求（断点续传）
      responses:
        '200':
          description: 文件流
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '304':
          description: 未修改
        '404':
          description: Bucket 非 public 且未认证 / 对象不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StreamErrorResponse'
    head:
      summary: 获取对象信息
      description: 仅返回响应头。可选携带 JWT：有 JWT 则按角色鉴权；无 JWT 且 bucket 为 public 时以 SuperUser
        身份查询，非 public 则返回 404。
      tags:
        - Object-info
      security:
        - bearerAuth: []
        - {}
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
      responses:
        '200':
          description: 响应头包含文件元信息
        '404':
          description: 对象不存在
  /v1/storages/object/copy:
    post:
      summary: 复制对象
      tags:
        - Object
      security:
        - bearerAuth: []
      parameters:
        - name: x-upsert
          in: header
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
          description: 允许覆盖目标位置已有对象
        - name: x-metadata
          in: header
          schema:
            type: string
          description: 当 copyMetadata=false 时，目标对象使用此 user_metadata（base64 JSON）
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - bucketId
                - sourceKey
                - destinationKey
              properties:
                bucketId:
                  type: string
                  description: 源 Bucket ID
                sourceKey:
                  type: string
                  description: 源对象名称
                destinationKey:
                  type: string
                  description: 目标对象名称
                destinationBucket:
                  type: string
                  description: 目标 Bucket ID，默认与源相同
                metadata:
                  type: object
                  description: 自定义元数据，copyMetadata=false 时与源 metadata 合并。COS 层面仅识别
                    cacheControl、mimetype、contentType 三个字段
                copyMetadata:
                  type: boolean
                  default: true
                  description: 是否复制源对象元数据。true=直接继承（忽略 metadata 字段）；false=合并请求中的 metadata
      responses:
        '200':
          description: 复制成功
          content:
            application/json:
              schema:
                allOf:
                  - type: object
                    properties:
                      Id:
                        type: string
                      Key:
                        type: string
                  - $ref: '#/components/schemas/FullObjectResponse'
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: 源对象不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/storages/object/move:
    post:
      summary: 移动对象
      description: 将对象从源位置移动到目标位置，源对象会被删除。
      tags:
        - Object
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - bucketId
                - sourceKey
                - destinationKey
              properties:
                bucketId:
                  type: string
                  description: 源 Bucket ID
                sourceKey:
                  type: string
                  description: 源对象名称
                destinationKey:
                  type: string
                  description: 目标对象名称
                destinationBucket:
                  type: string
                  description: 目标 Bucket ID，默认与源相同
      responses:
        '200':
          description: 移动成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  Id:
                    type: string
                  Key:
                    type: string
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/storages/object/info/{bucketId}/{objectName}:
    get:
      summary: 获取对象元信息
      description: 可选携带 JWT。有 JWT 则按角色鉴权，无 JWT 且 bucket 为 public 时以 SuperUser 身份查询。
      tags:
        - Object-info
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
      responses:
        '200':
          description: 对象元信息
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectInfoResponse'
        '404':
          description: 对象不存在
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StreamErrorResponse'
      security:
        - bearerAuth: []
        - {}
  /v1/storages/object/sign/{bucketId}/{objectName}:
    post:
      summary: 获取预签名下载链接
      tags:
        - Object-sign
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - expiresIn
              properties:
                expiresIn:
                  type: integer
                  minimum: 1
                  description: 过期时间（秒）
                  example: 3600
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  signedURL:
                    type: string
                  fullSignedURL:
                    type: string
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
  /v1/storages/object/sign/{bucketId}:
    post:
      summary: 获取预签名下载链接（批量）
      description: 获取多个对象生成预签名下载链接，单次最多 500 个。
      tags:
        - Object-sign
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - expiresIn
                - paths
              properties:
                expiresIn:
                  type: integer
                  minimum: 1
                  description: 过期时间（秒）
                paths:
                  type: array
                  items:
                    type: string
                  maxItems: 500
                  description: 对象名称列表
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/SignedURLResult'
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    get:
      summary: 通过预签名下载链接下载对象
      description: 使用预签名下载链接下载对象，不需要 Authorization。支持 GET（返回文件流）和 HEAD（仅返回响应头）。
      tags:
        - Object-sign
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
        - name: token
          in: query
          required: true
          schema:
            type: string
          description: 签名 token
        - name: download
          in: query
          schema:
            type: string
          description: 触发浏览器下载，值作为文件名
      responses:
        '200':
          description: 文件流
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '304':
          description: 未修改（缓存命中）
        '401':
          description: 'token 缺失时返回 STORAGE_PG_INVALID_JWT（message: token is required）；token
            验证失败返回 STORAGE_PG_INVALID_JWT；签名不匹配返回 STORAGE_PG_INVALID_SIGNATURE'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StreamErrorResponse'
      security: []
    head:
      summary: 通过预签名下载链接获取对象信息
      description: 与 GET 签名下载相同逻辑，但仅返回响应头（Content-Type、Content-Length、ETag 等），不返回文件内容。用于预检文件信息。
      tags:
        - Object-sign
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
        - name: token
          in: query
          required: true
          schema:
            type: string
          description: 签名 token
      responses:
        '200':
          description: 响应头包含文件元信息
        '401':
          description: token 缺失 / token 无效或已过期 / 签名不匹配
      security: []
  /v1/storages/object/upload/sign/{bucketId}/{objectName}:
    post:
      summary: 获取预签名上传链接
      description: 获取预签名上传链接，可指定有效期（默认60秒），可通过该上传链接上传对象。
      tags:
        - Object-sign
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
        - name: x-upsert
          in: header
          schema:
            type: string
            enum:
              - 'true'
              - 'false'
          description: 允许覆盖
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  url:
                    type: string
                    description: 签名上传 URL
                  fullURL:
                    type: string
                    description: 完整签名上传 URL
                  token:
                    type: string
                    description: JWT token
        '400':
          description: '参数错误 / 或缺少 Authorization 头（message: headers must have required
            property ''authorization''）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    put:
      summary: 通过预签名上传链接上传对象
      description: 通过预签名上传链接上传对象，不需要 Authorization（public 路由）。
      tags:
        - Object-sign
      parameters:
        - $ref: '#/components/parameters/bucketId'
        - $ref: '#/components/parameters/objectName'
        - name: token
          in: query
          required: true
          schema:
            type: string
          description: 签名上传 token（由 POST 生成签名上传 URL 接口返回）
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
          '*/*':
            schema:
              type: string
              format: binary
      responses:
        '200':
          description: 上传成功
          content:
            application/json:
              schema:
                type: object
                properties:
                  Key:
                    type: string
        '400':
          description: 'token 缺失（INVALID_PARAM, message: querystring must have required
            property ''token''）/ 对象名称不合法（STORAGE_PG_INVALID_KEY）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: 'token 验证失败（STORAGE_PG_INVALID_JWT）/ 签名不匹配（STORAGE_PG_INVALID_SIGNATURE,
            message: The signature is invalid）'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
