merge: 合并上游 v0.1.86 到 main 分支

This commit is contained in:
erio
2026-02-25 19:02:10 +08:00
469 changed files with 65006 additions and 3674 deletions

View File

@@ -0,0 +1,13 @@
-- Migration: 045_add_accounts_extra_index
-- 为 accounts.extra 字段添加 GIN 索引,优化 FindByExtraField 查询性能
-- 用于支持通过 extra 字段中的 linked_openai_account_id 快速查找关联的 Sora 账号
CREATE INDEX IF NOT EXISTS idx_accounts_extra_gin
ON accounts USING GIN (extra);
-- 查询示例(使用 @> 操作符)
-- EXPLAIN ANALYZE
-- SELECT * FROM accounts
-- WHERE platform = 'sora'
-- AND extra @> '{"linked_openai_account_id": 123}'::jsonb
-- AND deleted_at IS NULL;

View File

@@ -0,0 +1,24 @@
-- Migration: 046_add_sora_accounts
-- 新增 sora_accounts 扩展表,存储 Sora 账号的 OAuth 凭证
-- 与 accounts 主表形成双表结构:
-- - accounts: 统一账号管理和调度
-- - sora_accounts: Sora gateway 快速读取和资格校验
--
-- 设计说明:
-- - account_id 为主键,外键关联 accounts.id
-- - ON DELETE CASCADE 确保删除账号时自动清理扩展表
-- - access_token/refresh_token 与 accounts.credentials 保持同步
CREATE TABLE IF NOT EXISTS sora_accounts (
account_id BIGINT PRIMARY KEY,
access_token TEXT NOT NULL,
refresh_token TEXT NOT NULL,
session_token TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT fk_sora_accounts_account_id
FOREIGN KEY (account_id) REFERENCES accounts(id)
ON DELETE CASCADE
);
-- 索引说明:主键已自动创建唯一索引,无需额外创建 idx_sora_accounts_account_id

View File

@@ -0,0 +1,11 @@
-- Migration: 047_add_sora_pricing_and_media_type
-- 新增 Sora 按次计费字段与 usage_logs.media_type
ALTER TABLE groups
ADD COLUMN IF NOT EXISTS sora_image_price_360 decimal(20,8),
ADD COLUMN IF NOT EXISTS sora_image_price_540 decimal(20,8),
ADD COLUMN IF NOT EXISTS sora_video_price_per_request decimal(20,8),
ADD COLUMN IF NOT EXISTS sora_video_price_per_request_hd decimal(20,8);
ALTER TABLE usage_logs
ADD COLUMN IF NOT EXISTS media_type VARCHAR(16);

View File

@@ -0,0 +1,10 @@
-- 存储系统级密钥(如 JWT 签名密钥、TOTP 加密密钥)
CREATE TABLE IF NOT EXISTS security_secrets (
id BIGSERIAL PRIMARY KEY,
key VARCHAR(100) NOT NULL UNIQUE,
value TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_security_secrets_key ON security_secrets (key);

View File

@@ -0,0 +1,55 @@
-- 054_ops_system_logs.sql
-- 统一日志索引表与清理审计表
CREATE TABLE IF NOT EXISTS ops_system_logs (
id BIGSERIAL PRIMARY KEY,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
level VARCHAR(16) NOT NULL,
component VARCHAR(128) NOT NULL DEFAULT '',
message TEXT NOT NULL,
request_id VARCHAR(128),
client_request_id VARCHAR(128),
user_id BIGINT,
account_id BIGINT,
platform VARCHAR(32),
model VARCHAR(128),
extra JSONB NOT NULL DEFAULT '{}'::jsonb
);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_created_at_id
ON ops_system_logs (created_at DESC, id DESC);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_level_created_at
ON ops_system_logs (level, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_component_created_at
ON ops_system_logs (component, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_request_id
ON ops_system_logs (request_id);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_client_request_id
ON ops_system_logs (client_request_id);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_user_id_created_at
ON ops_system_logs (user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_account_id_created_at
ON ops_system_logs (account_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_platform_model_created_at
ON ops_system_logs (platform, model, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_ops_system_logs_message_search
ON ops_system_logs USING GIN (to_tsvector('simple', COALESCE(message, '')));
CREATE TABLE IF NOT EXISTS ops_system_log_cleanup_audits (
id BIGSERIAL PRIMARY KEY,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
operator_id BIGINT NOT NULL,
conditions JSONB NOT NULL DEFAULT '{}'::jsonb,
deleted_rows BIGINT NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_ops_system_log_cleanup_audits_created_at
ON ops_system_log_cleanup_audits (created_at DESC, id DESC);

View File

@@ -0,0 +1,9 @@
-- 迁移:为 api_keys 增加 last_used_at 字段,用于记录 API Key 最近使用时间
-- 幂等执行:可重复运行
ALTER TABLE api_keys
ADD COLUMN IF NOT EXISTS last_used_at TIMESTAMPTZ;
CREATE INDEX IF NOT EXISTS idx_api_keys_last_used_at
ON api_keys(last_used_at)
WHERE deleted_at IS NULL;

View File

@@ -0,0 +1,27 @@
-- 幂等记录表:用于关键写接口的请求去重与结果重放
-- 幂等执行:可重复运行
CREATE TABLE IF NOT EXISTS idempotency_records (
id BIGSERIAL PRIMARY KEY,
scope VARCHAR(128) NOT NULL,
idempotency_key_hash VARCHAR(64) NOT NULL,
request_fingerprint VARCHAR(64) NOT NULL,
status VARCHAR(32) NOT NULL,
response_status INTEGER,
response_body TEXT,
error_reason VARCHAR(128),
locked_until TIMESTAMPTZ,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_idempotency_records_scope_key
ON idempotency_records (scope, idempotency_key_hash);
CREATE INDEX IF NOT EXISTS idx_idempotency_records_expires_at
ON idempotency_records (expires_at);
CREATE INDEX IF NOT EXISTS idx_idempotency_records_status_locked_until
ON idempotency_records (status, locked_until);

View File

@@ -0,0 +1,42 @@
-- Add claude-sonnet-4-6 to model_mapping for all Antigravity accounts
--
-- Background:
-- Antigravity now supports claude-sonnet-4-6
--
-- Strategy:
-- Directly overwrite the entire model_mapping with updated mappings
-- This ensures consistency with DefaultAntigravityModelMapping in constants.go
UPDATE accounts
SET credentials = jsonb_set(
credentials,
'{model_mapping}',
'{
"claude-opus-4-6-thinking": "claude-opus-4-6-thinking",
"claude-opus-4-6": "claude-opus-4-6-thinking",
"claude-opus-4-5-thinking": "claude-opus-4-6-thinking",
"claude-opus-4-5-20251101": "claude-opus-4-6-thinking",
"claude-sonnet-4-6": "claude-sonnet-4-6",
"claude-sonnet-4-5": "claude-sonnet-4-5",
"claude-sonnet-4-5-thinking": "claude-sonnet-4-5-thinking",
"claude-sonnet-4-5-20250929": "claude-sonnet-4-5",
"claude-haiku-4-5": "claude-sonnet-4-5",
"claude-haiku-4-5-20251001": "claude-sonnet-4-5",
"gemini-2.5-flash": "gemini-2.5-flash",
"gemini-2.5-flash-lite": "gemini-2.5-flash-lite",
"gemini-2.5-flash-thinking": "gemini-2.5-flash-thinking",
"gemini-2.5-pro": "gemini-2.5-pro",
"gemini-3-flash": "gemini-3-flash",
"gemini-3-pro-high": "gemini-3-pro-high",
"gemini-3-pro-low": "gemini-3-pro-low",
"gemini-3-pro-image": "gemini-3-pro-image",
"gemini-3-flash-preview": "gemini-3-flash",
"gemini-3-pro-preview": "gemini-3-pro-high",
"gemini-3-pro-image-preview": "gemini-3-pro-image",
"gpt-oss-120b-medium": "gpt-oss-120b-medium",
"tab_flash_lite_preview": "tab_flash_lite_preview"
}'::jsonb
)
WHERE platform = 'antigravity'
AND deleted_at IS NULL
AND credentials->'model_mapping' IS NOT NULL;

View File

@@ -0,0 +1,45 @@
-- Add gemini-3.1-pro-high, gemini-3.1-pro-low, gemini-3.1-pro-preview to model_mapping
--
-- Background:
-- Antigravity now supports gemini-3.1-pro-high and gemini-3.1-pro-low
--
-- Strategy:
-- Directly overwrite the entire model_mapping with updated mappings
-- This ensures consistency with DefaultAntigravityModelMapping in constants.go
UPDATE accounts
SET credentials = jsonb_set(
credentials,
'{model_mapping}',
'{
"claude-opus-4-6-thinking": "claude-opus-4-6-thinking",
"claude-opus-4-6": "claude-opus-4-6-thinking",
"claude-opus-4-5-thinking": "claude-opus-4-6-thinking",
"claude-opus-4-5-20251101": "claude-opus-4-6-thinking",
"claude-sonnet-4-6": "claude-sonnet-4-6",
"claude-sonnet-4-5": "claude-sonnet-4-5",
"claude-sonnet-4-5-thinking": "claude-sonnet-4-5-thinking",
"claude-sonnet-4-5-20250929": "claude-sonnet-4-5",
"claude-haiku-4-5": "claude-sonnet-4-5",
"claude-haiku-4-5-20251001": "claude-sonnet-4-5",
"gemini-2.5-flash": "gemini-2.5-flash",
"gemini-2.5-flash-lite": "gemini-2.5-flash-lite",
"gemini-2.5-flash-thinking": "gemini-2.5-flash-thinking",
"gemini-2.5-pro": "gemini-2.5-pro",
"gemini-3-flash": "gemini-3-flash",
"gemini-3-pro-high": "gemini-3-pro-high",
"gemini-3-pro-low": "gemini-3-pro-low",
"gemini-3-pro-image": "gemini-3-pro-image",
"gemini-3-flash-preview": "gemini-3-flash",
"gemini-3-pro-preview": "gemini-3-pro-high",
"gemini-3-pro-image-preview": "gemini-3-pro-image",
"gemini-3.1-pro-high": "gemini-3.1-pro-high",
"gemini-3.1-pro-low": "gemini-3.1-pro-low",
"gemini-3.1-pro-preview": "gemini-3.1-pro-high",
"gpt-oss-120b-medium": "gpt-oss-120b-medium",
"tab_flash_lite_preview": "tab_flash_lite_preview"
}'::jsonb
)
WHERE platform = 'antigravity'
AND deleted_at IS NULL
AND credentials->'model_mapping' IS NOT NULL;