mirror of
https://github.com/sinanyuntu/trade-message-center.git
synced 2026-09-17 13:22:11 +08:00
fix: allow development database reset on approved remote host
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
## 概览
|
||||
|
||||
本 PR 汇总近期 OneTalk 消息中心的同步、单会话历史重建、商品消息采集和页面交互整理,并补齐共享协议、服务端、Chrome 扩展、数据库迁移及回归测试。
|
||||
|
||||
## 最近改动
|
||||
|
||||
- **消息同步链路**
|
||||
- 移除旧的 flat-history publication flow。
|
||||
- 调整 Plugin ↔ Bright 的同步、ACK、checkpoint 和生命周期处理,确保消息与完成状态按会话边界推进。
|
||||
|
||||
- **单会话历史重建**
|
||||
- 新增 `POST /api/bright/onetalk/accounts/:channelAccountId/conversations/:conversationId/history/rebuild`。
|
||||
- 使用独立的 `rebuild` 权限、精确会话范围和新鲜 heartbeat 选择唯一 Plugin。
|
||||
- 新增 `storage.delete.*`、`history.sync.*`、`rebuild.status` 协议帧,并升级 OneTalk protocol version 到 v7。
|
||||
- 按 `channelAccountId + conversationId` 清理 Plugin 本地消息账本,再通过 Bright 事务清理目标消息/会话级异常并重置消息派生状态。
|
||||
- 通过 `historyGeneration` 隔离重建前后的旧消息、ACK、页面结果和完成结果;服务端 reset 提交后复用现有单会话 full sync,并区分 `server_reset_committed` 与后续 resync 结果。
|
||||
|
||||
- **商品消息采集**
|
||||
- 严格识别 `https://chinese.alibaba.com/product-detail/...-<productId>.html` 商品详情链接。
|
||||
- 归一化为不带 query/token 的 `{ version, kind: "product", sourceUrl, productId }`,沿用现有观察、持久化和读取链路。
|
||||
- 增加 `product` 数据库约束和迁移,不回填既有消息。
|
||||
|
||||
- **OneTalk 页面 DOM 交互整理**
|
||||
- 将动作状态提示、会话 ID 复制、文件上传器定位和会话选择辅助逻辑收敛到 `main-page/dom/`。
|
||||
- 引入 `@testing-library/dom`、`@testing-library/user-event` 和 `jsdom` 验证真实 DOM 控件交互,同时保留现有 SDK 发送路径和 bridge 行为。
|
||||
|
||||
- **契约、数据层与测试**
|
||||
- 扩展共享消息内容、同步、授权、读取和 WebSocket wire contract,并保持严格字段校验。
|
||||
- 新增 `0012_onetalk_history_generation.sql` 和 `0013_nifty_thunderbird.sql` 迁移。
|
||||
- 补充或更新 contract、Chrome extension、server 的同步、历史重建、商品内容、数据库读取和 DOM 回归测试。
|
||||
|
||||
## 影响范围
|
||||
|
||||
- `packages/onetalk-contract`
|
||||
- `apps/chrome-extension`
|
||||
- `apps/server`
|
||||
- OneTalk 数据库迁移及相关测试
|
||||
@@ -17,11 +17,11 @@ export type DevelopmentResetDependencies = {
|
||||
runMigrations?: (databaseUrl: string) => Promise<void>;
|
||||
};
|
||||
|
||||
const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "localhost", "::1"]);
|
||||
const DEVELOPMENT_DATABASE_HOSTNAMES = new Set(["127.0.0.1", "localhost", "::1", "170.9.52.93"]);
|
||||
const entryPath = process.argv[1];
|
||||
const isMainModule = entryPath !== undefined && import.meta.url === pathToFileURL(entryPath).href;
|
||||
|
||||
const isLoopbackDatabaseUrl = (databaseUrl: string): boolean => {
|
||||
const isAllowedDevelopmentDatabaseUrl = (databaseUrl: string): boolean => {
|
||||
let url: URL;
|
||||
|
||||
try {
|
||||
@@ -33,7 +33,7 @@ const isLoopbackDatabaseUrl = (databaseUrl: string): boolean => {
|
||||
const hostname = url.hostname.replace(/^\[|\]$/g, "");
|
||||
const isPostgresUrl = url.protocol === "postgres:" || url.protocol === "postgresql:";
|
||||
|
||||
return isPostgresUrl && LOOPBACK_HOSTNAMES.has(hostname);
|
||||
return isPostgresUrl && DEVELOPMENT_DATABASE_HOSTNAMES.has(hostname);
|
||||
};
|
||||
|
||||
export const readDevelopmentDatabaseUrl = (
|
||||
@@ -45,8 +45,8 @@ export const readDevelopmentDatabaseUrl = (
|
||||
|
||||
const databaseUrl = readDatabaseUrl(environment);
|
||||
|
||||
if (!isLoopbackDatabaseUrl(databaseUrl)) {
|
||||
throw new Error("Development database reset requires a loopback DATABASE_URL");
|
||||
if (!isAllowedDevelopmentDatabaseUrl(databaseUrl)) {
|
||||
throw new Error("Development database reset requires an approved development DATABASE_URL");
|
||||
}
|
||||
|
||||
return databaseUrl;
|
||||
|
||||
@@ -37,6 +37,15 @@ test("accepts and trims a development loopback database URL", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("accepts the dedicated development database server", () => {
|
||||
const databaseUrl = "postgres://postgres:postgres@170.9.52.93:15432/trade_message_center";
|
||||
|
||||
assert.equal(
|
||||
readDevelopmentDatabaseUrl({ ...developmentEnvironment, DATABASE_URL: databaseUrl }),
|
||||
databaseUrl,
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects a reset outside development", () => {
|
||||
assert.throws(
|
||||
() => readDevelopmentDatabaseUrl({ ...developmentEnvironment, NODE_ENV: "production" }),
|
||||
@@ -44,14 +53,14 @@ test("rejects a reset outside development", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("rejects a non-loopback database URL", () => {
|
||||
test("rejects an unapproved development database URL", () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
readDevelopmentDatabaseUrl({
|
||||
...developmentEnvironment,
|
||||
DATABASE_URL: "postgres://postgres:postgres@db.example.com/trade_message_center",
|
||||
}),
|
||||
/loopback DATABASE_URL/,
|
||||
/approved development DATABASE_URL/,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user