feat: harden loose-offline sync for user JWT, schema, and console ops

Enable Binding-scoped agent push/pull, empty-table schema ensure, SyncPage inspect/drop-table, default module import, and agent-bound publish docs from the 宇恒联调意见.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
whm
2026-08-05 09:47:35 +08:00
parent 76cdcd760e
commit b04b180d30
59 changed files with 4762 additions and 308 deletions

View File

@@ -0,0 +1,87 @@
package dbsync
import (
"context"
"fmt"
"strings"
)
// DropTableResult 控制台删表结果。
type DropTableResult struct {
OK bool `json:"ok"`
Side string `json:"side"`
Table string `json:"table"`
Dropped bool `json:"dropped"`
MetaCleared int64 `json:"meta_cleared,omitempty"`
Message string `json:"message,omitempty"`
}
// DropTableOnEndpoint 删除业务表(禁止 _ajz_*);并清理 _ajz_sync_meta 中该表残留。
// 注意:仅作用于当前 endpoint线上 A 或本机 B不向另一侧同步 DDL。
func DropTableOnEndpoint(ctx context.Context, ep Endpoint, side, table string) (*DropTableResult, error) {
table = strings.TrimSpace(table)
side = strings.TrimSpace(side)
if side == "" {
side = "remote"
}
if table == "" {
return nil, fmt.Errorf("table required")
}
if strings.HasPrefix(table, "_ajz_") {
return nil, fmt.Errorf("同步系统表不可删: %s", table)
}
if strings.EqualFold(table, "sqlite_master") || strings.HasPrefix(strings.ToLower(table), "sqlite_") {
return nil, fmt.Errorf("系统表不可删: %s", table)
}
db, owned, err := openInspectDB(ep)
if err != nil {
return &DropTableResult{OK: false, Side: side, Table: table, Message: err.Error()}, err
}
if owned {
defer db.Close()
}
exists, err := tableExists(ctx, db, ep.Driver, table)
if err != nil {
return nil, err
}
if !exists {
return &DropTableResult{
OK: true,
Side: side,
Table: table,
Dropped: false,
Message: "表不存在(可能已删)",
}, nil
}
ddl := fmt.Sprintf(`DROP TABLE IF EXISTS %s`, quoteIdent(ep.Driver, table))
if _, err := db.ExecContext(ctx, ddl); err != nil {
return nil, fmt.Errorf("drop table: %w", err)
}
var metaCleared int64
if metaExists, _ := tableExists(ctx, db, ep.Driver, MetaTable); metaExists {
q := fmt.Sprintf(`DELETE FROM %s WHERE table_name = ?`, quoteIdent(ep.Driver, MetaTable))
if ep.Driver == DriverPostgres {
q = fmt.Sprintf(`DELETE FROM %s WHERE table_name = $1`, quoteIdent(ep.Driver, MetaTable))
}
res, err := db.ExecContext(ctx, q, table)
if err == nil && res != nil {
metaCleared, _ = res.RowsAffected()
}
}
// 若该 DSN 在 remote 池里,丢掉缓存连接,避免旧 schema 缓存感。
InvalidateRemote(ep.Driver, ep.DSN)
return &DropTableResult{
OK: true,
Side: side,
Table: table,
Dropped: true,
MetaCleared: metaCleared,
Message: "已删除;若另一侧仍有同名表,不会自动同步删除,需分别处理或避免再次 push/ensure",
}, nil
}