feat(api): add account workspaces and signed content events

This commit is contained in:
justme committed 2026-10-14 04:05:30 +08:00
1 parent 937b774a93
commit 7b8d61d1ba
63 files changed
+5407 -370

No files matched your search

+455 -234
View File
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: WebDrop API
version: 2.1.0
version: 6.0.0
servers:
- url: /api/v1
@@ -15,6 +15,388 @@ tags:
- name: account
paths:
/accounts/profile:
get:
tags: [account]
parameters:
- name: X-WD-Account
in: header
required: true
schema: { type: string }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/AccountProfile'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
patch:
tags: [account]
parameters:
- name: X-WD-Account
in: header
required: true
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/AccountProfileRequest' }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/AccountProfile'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/accounts/spaces:
get:
tags: [account]
parameters:
- name: X-WD-Account
in: header
required: true
schema: { type: string }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
type: array
items: { $ref: '../contracts/api.schemas.json#/$defs/ChannelInfo' }
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/structure:
get:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: X-WD-Account
in: header
required: false
schema: { type: string }
- $ref: '#/components/parameters/Role'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/channels:
post:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceChannelRequest' }
responses:
'201':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceChannelCreatedBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/channels/{channelId}:
patch:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: channelId
in: path
required: true
schema: { type: string, format: uuid }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceNameRequest' }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/channels/{channelId}/group:
put:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: channelId
in: path
required: true
schema: { type: string, format: uuid }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceGroupRequest' }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/groups:
post:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceNameRequest' }
responses:
'201':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceGroupCreatedBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/groups/{groupId}:
patch:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: groupId
in: path
required: true
schema: { type: string, format: uuid }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceNameRequest' }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/folders:
post:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceFolderRequest' }
responses:
'201':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/folders/{folderId}:
patch:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: folderId
in: path
required: true
schema: { type: string, format: uuid }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceNameRequest' }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/spaces/{id}/locations:
put:
tags: [channel]
parameters:
- name: id
in: path
required: true
schema: { type: string }
- name: X-WD-Account
in: header
required: true
schema: { type: string }
- $ref: '#/components/parameters/RoleWriter'
- $ref: '#/components/parameters/Endpoint'
- name: Authorization
in: header
schema: { type: string }
requestBody:
required: true
content:
application/json:
schema: { $ref: '../contracts/api.schemas.json#/$defs/WorkspaceMoveRequest' }
responses:
'200':
description: 服务端权威数据
content:
application/json:
schema:
$ref: '../contracts/api.schemas.json#/$defs/WorkspaceBody'
'400': { $ref: '#/components/responses/Error' }
'401': { $ref: '#/components/responses/Error' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/accounts/channels:
get:
tags: [account]
@@ -244,7 +626,7 @@ paths:
post:
tags: [channel]
security: [{ bearer: [], accountBearer: [] }]
summary: 邀请已注册用户
summary: 原子提交账号邀请及服务端授权计划要求的域密钥包
requestBody:
required: true
content:
@@ -253,6 +635,26 @@ paths:
responses:
'204': { description: 已邀请 }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/channels/{id}/invitations/{username}/crypto-plan:
get:
tags: [channel]
security: [{ bearer: [], accountBearer: [] }]
summary: 获取新成员域密钥封装计划
description: 返回由服务端历史策略和当前成员权限计算的 epoch 与收件人集合;提交时服务端会重新计算并校验。
parameters:
- { $ref: '#/components/parameters/ChannelId' }
- { $ref: '#/components/parameters/RoleOwner' }
- { name: username, in: path, required: true, schema: { type: string } }
responses:
'200':
description: 服务端计算的加密授权计划
content:
application/json:
schema: { $ref: '#/components/schemas/InvitationCryptoPlan' }
'403': { $ref: '#/components/responses/Error' }
'404': { $ref: '#/components/responses/Error' }
'409': { $ref: '#/components/responses/Error' }
/channels/{id}/invitations/{username}:
delete:
tags: [channel]
@@ -299,8 +701,8 @@ paths:
- { $ref: '#/components/parameters/ChannelId' }
get:
tags: [channel]
summary: 读取频道信息(不占席位)
description: 任意角色可调用。用于加入前预览席位占用和核对模式。
summary: 读取频道信息(不占成员名额)
description: 任意角色可调用。`seats_used` 表示唯一账号成员数加匿名访客终端数,不是设备数。
security: [{ bearer: [] }]
parameters:
- { $ref: '#/components/parameters/Role' }
@@ -355,11 +757,11 @@ paths:
- { $ref: '#/components/parameters/ChannelId' }
post:
tags: [seat]
summary: 加入频道(占用席位)
summary: 登记当前设备并加入频道
description: |
幂等:同一终端重复调用返回同一席位,不重复占用。
席位已满返回 403 `seats_full`。
读取频道信息和 owner 管理接口不占席位;频道内容、席位信息/设备名等其余操作要求终端已入席,否则 403 `not_joined`。
幂等:同一终端重复调用返回同一设备席位,不重复登记。
同一账号的设备不限量,账号首次加入时才占一个成员名额;成员名额已满返回 403 `seats_full`。
未登录访客每个终端单独计一个成员名额。读取频道信息和 owner 管理接口不占成员名额;频道内容、设备席位/设备名等操作要求终端已入席,否则 403 `not_joined`。
security: [{ bearer: [] }]
parameters:
- { $ref: '#/components/parameters/Role' }
@@ -375,7 +777,7 @@ paths:
'404': { $ref: '#/components/responses/Error' }
get:
tags: [seat]
summary: 查看席位列表(所有者)
summary: 查看已加入设备列表(所有者)
description: 有效的 owner 凭据即可调用,不要求 owner 终端占用席位。
security: [{ bearer: [] }]
parameters:
@@ -437,8 +839,8 @@ paths:
/channels/{id}/seats/{endpointHash}:
delete:
tags: [seat]
summary: 释放席位(所有者)
description: 有效的 owner 凭据即可调用,不要求 owner 终端占用席位。被释放终端后续请求返回 `not_joined`;向订阅者推送 `{"t":"seats"}`。
summary: 撤销单台设备(所有者)
description: 有效的 owner 凭据即可调用,不要求 owner 终端占用设备席位。被释放终端后续请求返回 `not_joined`;账号成员身份及人数名额保留;向订阅者推送 `{"t":"seats"}`。
security: [{ bearer: [] }]
parameters:
- { $ref: '#/components/parameters/ChannelId' }
@@ -917,87 +1319,43 @@ components:
schemas:
AccountChannel:
type: object
required: [channel_id, role, payload, created_at]
properties:
channel_id: { $ref: '#/components/schemas/Base64Url' }
role: { type: string, enum: [owner, member] }
payload: { type: string, minLength: 1, maxLength: 16384 }
created_at: { type: integer, format: int64 }
$ref: '../contracts/api.schemas.json#/$defs/AccountChannelBody'
AccountDevice:
type: object
required: [id, name, created_at, last_seen, current]
properties:
id: { type: string, format: uuid }
name: { type: string, minLength: 1, maxLength: 80 }
created_at: { type: integer, format: int64 }
last_seen: { type: integer, format: int64 }
current: { type: boolean }
$ref: '../contracts/api.schemas.json#/$defs/AccountDeviceBody'
PublicKey:
type: object
required: [public_key]
properties:
public_key: { type: string, maxLength: 1024 }
$ref: '../contracts/api.schemas.json#/$defs/PublicKeyBody'
ChannelInvitation:
type: object
required: [channel_id, username, payload, created_at]
properties:
channel_id: { $ref: '#/components/schemas/Base64Url' }
username: { type: string }
payload: { type: string, maxLength: 16384, description: 客户端加密的成员链接 }
created_at: { type: integer, format: int64 }
$ref: '../contracts/api.schemas.json#/$defs/InvitationBody'
InvitationRequest:
type: object
required: [username, payload]
properties:
username: { type: string }
payload: { type: string, maxLength: 16384 }
$ref: '../contracts/api.schemas.json#/$defs/InvitationRequest'
InvitationCryptoPlan:
$ref: '../contracts/api.schemas.json#/$defs/InvitationCryptoPlan'
ChannelMember:
type: object
required: [username, role, joined_at]
properties:
username: { type: string }
role: { type: string, enum: [owner, member] }
joined_at: { type: integer, format: int64 }
$ref: '../contracts/api.schemas.json#/$defs/MemberBody'
AccountRegister:
type: object
required: [username, salt, verifier, vault, public_key]
properties:
username: { type: string, minLength: 3, maxLength: 32, pattern: '^[A-Za-z0-9_-]+$' }
salt: { type: string, contentEncoding: base64, minLength: 24, maxLength: 24 }
verifier: { type: string, contentEncoding: base64, minLength: 44, maxLength: 44 }
vault: { type: string, contentEncoding: base64, maxLength: 1733336 }
public_key: { type: string, maxLength: 1024, description: P-256 ECDH 公钥 JWK 的 JSON 字符串 }
$ref: '../contracts/api.schemas.json#/$defs/AccountRegisterRequest'
AccountSaltRequest:
type: object
required: [username]
properties:
username: { type: string, minLength: 3, maxLength: 32 }
$ref: '../contracts/api.schemas.json#/$defs/AccountSaltRequest'
AccountSalt:
type: object
required: [salt]
properties:
salt: { type: string, contentEncoding: base64 }
$ref: '../contracts/api.schemas.json#/$defs/AccountSaltBody'
AccountSessionRequest:
type: object
required: [username, verifier]
properties:
device_id: { type: string, format: uuid }
device_name: { type: string, minLength: 1, maxLength: 80 }
username: { type: string }
verifier: { type: string, contentEncoding: base64 }
$ref: '../contracts/api.schemas.json#/$defs/AccountSessionRequest'
AccountSession:
type: object
required: [username, token]
properties:
username: { type: string }
token: { type: string, contentEncoding: base64 }
$ref: '../contracts/api.schemas.json#/$defs/AccountSessionBody'
AccountVault:
type: object
required: [revision, vault]
properties:
revision: { type: integer, format: int64, minimum: 0 }
vault: { type: string, contentEncoding: base64, maxLength: 1733336 }
$ref: '../contracts/api.schemas.json#/$defs/AccountVaultBody'
Base64Url:
type: string
pattern: '^[A-Za-z0-9_-]+$'
@@ -1043,186 +1401,49 @@ components:
oldest_seq: { type: integer, format: int64, description: "清理水位 + 1;0 < from < oldest_seq 的续传需要从 0 全量同步" }
ServerInfo:
type: object
required: [protocol, contract_version, limits, captcha, transports]
properties:
protocol: { type: integer, const: 1 }
contract_version: { type: string, example: 2.0.0, description: API 契约的 SemVer。破坏性变更递增主版本。 }
captcha:
type: object
required: [provider, enabled]
properties:
provider: { type: string, enum: [none, cap] }
enabled: { type: boolean }
api_endpoint:
type: string
description: Cap widget 要连接的地址(data-cap-api-endpoint),仅在启用时出现
transports:
type: object
properties:
websocket: { type: boolean }
sse: { type: boolean }
http3: { type: boolean }
limits:
type: object
properties:
max_payload_bytes: { type: integer }
max_frames_per_item: { type: integer }
max_channel_bytes: { type: integer, format: int64 }
max_seats: { type: integer }
max_ttl_seconds: { type: integer }
$ref: '../contracts/api.schemas.json#/$defs/ServerInfoBody'
ChannelMode:
type: string
enum: [enc, raw]
$ref: '../contracts/api.schemas.json#/$defs/ChannelMode'
DeletePolicy:
type: string
enum: [owner_only, own, anyone]
$ref: '../contracts/api.schemas.json#/$defs/DeletePolicy'
ChannelSettings:
type: object
required: [seats, members_can_upload, delete_policy, ttl_seconds, max_items, file_max_downloads, ui_restrict_copy_download]
properties:
join_policy: { type: string, enum: [open, invite], default: open }
allow_guests: { type: boolean, default: true }
name: { type: string, maxLength: 48, description: "共享频道名,所有成员和服务端可见" }
seats: { type: integer, minimum: 1, default: 2 }
members_can_upload: { type: boolean, default: true }
delete_policy: { $ref: '#/components/schemas/DeletePolicy' }
ttl_seconds: { type: integer, minimum: 60, maximum: 604800, default: 86400 }
max_items: { type: integer, minimum: 1, default: 1000 }
file_max_downloads: { type: integer, minimum: 0, default: 10, description: "0 为不限,仅对 GATED 条目生效" }
ui_restrict_copy_download: { type: boolean, default: false, description: "仅供前端展示,服务端不强制" }
$ref: '../contracts/api.schemas.json#/$defs/ChannelSettings'
ChannelSettingsPatch:
type: object
description: ChannelSettings 的全部字段均可选
properties:
join_policy: { type: string, enum: [open, invite] }
allow_guests: { type: boolean }
join_password: { type: string, maxLength: 256, description: 至少 8 字符;空字符串清除;省略保持原值 }
name: { type: string, maxLength: 48, description: "更新共享频道名;空字符串清除名称" }
seats: { type: integer, minimum: 1 }
members_can_upload: { type: boolean }
delete_policy: { $ref: '#/components/schemas/DeletePolicy' }
ttl_seconds: { type: integer, minimum: 60, maximum: 604800 }
max_items: { type: integer, minimum: 1 }
file_max_downloads: { type: integer, minimum: 0 }
ui_restrict_copy_download: { type: boolean }
$ref: '../contracts/api.schemas.json#/$defs/ChannelSettingsPatch'
CreateChannelRequest:
type: object
required: [id, mode, settings, owner_hash]
properties:
key_package: { type: string, minLength: 1, maxLength: 16384, description: 用创建者账号公钥封装的 owner 凭据 }
join_password: { type: string, minLength: 8, maxLength: 256 }
id: { $ref: '#/components/schemas/Base64Url' }
mode: { $ref: '#/components/schemas/ChannelMode' }
settings: { $ref: '#/components/schemas/ChannelSettings' }
read_hash:
$ref: '#/components/schemas/Base64Url'
description: SHA-256(T_read),enc 模式必填,raw 模式省略
write_hash:
$ref: '#/components/schemas/Base64Url'
description: SHA-256(T_write 或 W),仅在成员可上传时提供
owner_hash:
$ref: '#/components/schemas/Base64Url'
description: SHA-256(T_owner)
$ref: '../contracts/api.schemas.json#/$defs/CreateChannelRequest'
ShareSettings:
type: object
required: [ttl_seconds, max_visitors, file_max_downloads]
properties:
ttl_seconds: { type: integer, minimum: 60, maximum: 604800, default: 86400 }
max_visitors: { type: integer, minimum: 0, maximum: 10000, default: 0, description: 0 为不限 }
file_max_downloads: { type: integer, minimum: 0, default: 10, description: 0 为不限 }
$ref: '../contracts/api.schemas.json#/$defs/ShareSettings'
ShareSettingsPatch:
type: object
description: ShareSettings 的字段均可选。
properties:
ttl_seconds: { type: integer, minimum: 60, maximum: 604800 }
max_visitors: { type: integer, minimum: 0, maximum: 10000 }
file_max_downloads: { type: integer, minimum: 0 }
$ref: '../contracts/api.schemas.json#/$defs/ShareSettingsPatch'
CreateShareRequest:
type: object
required: [id, read_hash, owner_hash]
properties:
id: { $ref: '#/components/schemas/Base64Url' }
read_hash: { $ref: '#/components/schemas/Base64Url', description: SHA-256(T_read) }
owner_hash: { $ref: '#/components/schemas/Base64Url', description: SHA-256(T_owner) }
settings: { $ref: '#/components/schemas/ShareSettings' }
$ref: '../contracts/api.schemas.json#/$defs/CreateShareRequest'
FinishShareRequest:
type: object
required: [manifest_item_id]
properties:
manifest_item_id: { $ref: '#/components/schemas/Base64Url' }
$ref: '../contracts/api.schemas.json#/$defs/FinishShareRequest'
ShareItemInfo:
type: object
required: [item_id, bytes, frames, max_downloads, downloads_left]
properties:
complete: { type: boolean }
item_id: { $ref: '#/components/schemas/Base64Url' }
bytes: { type: integer, format: int64 }
frames: { type: integer }
max_downloads: { type: integer, format: int64, description: 0 为不限 }
downloads_left: { type: [integer, 'null'], format: int64, description: "null 表示不限" }
$ref: '../contracts/api.schemas.json#/$defs/ShareItemInfo'
ShareInfo:
type: object
required: [id, state, expires_at, created_at, settings, items]
properties:
id: { $ref: '#/components/schemas/Base64Url' }
state: { type: string, enum: [draft, sealed] }
expires_at: { type: integer, format: int64 }
created_at: { type: integer, format: int64 }
sealed_at: { type: [integer, 'null'], format: int64 }
manifest_item_id: { type: [string, 'null'], description: 清单条目 id }
settings: { $ref: '#/components/schemas/ShareSettings' }
items:
type: array
items: { $ref: '#/components/schemas/ShareItemInfo' }
$ref: '../contracts/api.schemas.json#/$defs/ShareInfo'
ChannelInfo:
type: object
required: [id, mode, settings, seats_used, oldest_seq, last_seq, created_at, expires_at]
properties:
password_required: { type: boolean }
creator_account: { type: string }
id: { $ref: '#/components/schemas/Base64Url' }
mode: { $ref: '#/components/schemas/ChannelMode' }
settings: { $ref: '#/components/schemas/ChannelSettings' }
seats_used: { type: integer }
oldest_seq: { type: integer, format: int64 }
last_seq: { type: integer, format: int64 }
created_at: { type: integer, format: int64 }
expires_at: { type: integer, format: int64 }
$ref: '../contracts/api.schemas.json#/$defs/ChannelInfo'
SeatJoined:
type: object
required: [endpoint_hash, joined_at, seats_used, seats_max]
properties:
endpoint_hash: { $ref: '#/components/schemas/Base64Url' }
joined_at: { type: integer, format: int64 }
seats_used: { type: integer }
seats_max: { type: integer }
$ref: '../contracts/api.schemas.json#/$defs/SeatJoined'
Seat:
type: object
required: [endpoint_hash, joined_at]
properties:
endpoint_hash: { $ref: '#/components/schemas/Base64Url' }
joined_at: { type: integer, format: int64 }
label:
type: [string, 'null']
description: 加密的设备名(base64url),用 K_enc 解密;未设置为 null
$ref: '../contracts/api.schemas.json#/$defs/SeatInfo'
AppendResult:
type: object
required: [seq]
properties:
seq: { type: integer, format: int64 }
$ref: '../contracts/api.schemas.json#/$defs/AppendResult'