@rei-standard/amsg-server 2.6.0-next.13 → 2.6.0-next.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -1
- package/dist/adapters/d1.d.ts +130 -0
- package/dist/adapters/interface.d.ts +67 -0
- package/dist/adapters/neon.d.ts +20 -58
- package/dist/adapters/pg-shared.d.ts +114 -0
- package/dist/adapters/pg.d.ts +20 -58
- package/dist/adapters/schema.d.ts +1 -1
- package/dist/adapters/schema.sqlite.d.ts +15 -1
- package/dist/{chunk-B2FDV7YK.mjs → chunk-34I2YSWE.mjs} +10 -0
- package/dist/{chunk-5IOYCCFD.cjs → chunk-H4V7OXHE.cjs} +1326 -384
- package/dist/{chunk-TV7N3RTH.mjs → chunk-KVHR3RCU.mjs} +1324 -382
- package/dist/{chunk-V2SDWGUB.cjs → chunk-OUPM4HAV.cjs} +10 -0
- package/dist/chunk-TFFBMYA2.cjs +95 -0
- package/dist/chunk-UYROU4L3.mjs +95 -0
- package/dist/cloudflare/single-user-worker.d.ts +35 -2
- package/dist/cloudflare.cjs +17 -2
- package/dist/cloudflare.d.ts +3 -1
- package/dist/cloudflare.mjs +18 -3
- package/dist/handlers/outbox.d.ts +7 -0
- package/dist/index.cjs +72 -36
- package/dist/index.d.cts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.mjs +53 -17
- package/dist/lib/client-state-store.d.ts +18 -3
- package/dist/lib/errors.d.ts +93 -0
- package/dist/lib/message-processor.d.ts +8 -2
- package/dist/lib/outbox-store.d.ts +33 -0
- package/dist/lib/push-subscription-store.d.ts +10 -2
- package/dist/lib/request.d.ts +36 -0
- package/dist/lib/run-tick.d.ts +38 -0
- package/dist/lib/schema-version.d.ts +50 -0
- package/dist/lib/validation.d.ts +1 -7
- package/dist/{neon-3ASBLLCM.cjs → neon-G3G4TDAY.cjs} +52 -112
- package/dist/{neon-CUIGAB2T.mjs → neon-GBUF4G76.mjs} +44 -104
- package/dist/{pg-IEZTAR43.cjs → pg-C3JZKBUM.cjs} +49 -112
- package/dist/{pg-KMJPL6QV.mjs → pg-MRXP5MHJ.mjs} +41 -104
- package/dist/single-user.d.ts +4 -0
- package/package.json +2 -2
package/dist/adapters/pg.d.ts
CHANGED
|
@@ -37,75 +37,37 @@ export class PgAdapter {
|
|
|
37
37
|
createTask(params: any): Promise<any[]>;
|
|
38
38
|
getTaskByUuid(uuid: any, userId: any): Promise<any[]>;
|
|
39
39
|
getTaskByUuidOnly(uuid: any): Promise<any[]>;
|
|
40
|
+
/**
|
|
41
|
+
* 这条 uuid 现在是什么状态——不限用户,也不限状态(上面那个只看 pending
|
|
42
|
+
* 行)。`runTask` 用它把「这条已经跑完了」和「压根没这条」分开回报。
|
|
43
|
+
*
|
|
44
|
+
* @param {string} uuid
|
|
45
|
+
* @returns {Promise<{ status: string }|null>}
|
|
46
|
+
*/
|
|
47
|
+
getTaskStatusByUuidOnly(uuid: string): Promise<{
|
|
48
|
+
status: string;
|
|
49
|
+
} | null>;
|
|
40
50
|
updateTaskById(taskId: any, updates: any): Promise<any[]>;
|
|
41
51
|
updateTaskByUuid(uuid: any, userId: any, encryptedPayload: any, extraFields: any): Promise<any[]>;
|
|
42
52
|
deleteTaskById(taskId: any): Promise<boolean>;
|
|
43
53
|
deleteTaskByUuid(uuid: any, userId: any): Promise<boolean>;
|
|
44
54
|
getPendingTasks(limit?: number): Promise<any[][]>;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* 本次投递期间别的 tick 领不走它。
|
|
48
|
-
*
|
|
49
|
-
* 租约写在自己的列上,next_send_at 全程不动——那一列是用户设的触发时刻,
|
|
50
|
-
* 任务列表要读它、循环任务推进下一次也要拿它当基准。
|
|
51
|
-
*
|
|
52
|
-
* 两个 tick 抢同一行时只有一个改得动,另一个拿不到 RETURNING 行,据此跳
|
|
53
|
-
* 过。WHERE 里的两个条件各管一件事:
|
|
54
|
-
* - lease_until 为空或已过期:没人正在跑这条。领了任务的 tick 中途没了
|
|
55
|
-
* 也不会把行焊死,租约到期后自然可以被接手。
|
|
56
|
-
* - next_send_at 等于读这行时看到的值:读出来之后用户又改了排期的话,
|
|
57
|
-
* 这一跳就不该再按旧时刻发。
|
|
58
|
-
*
|
|
59
|
-
* 不加一个 'sending' 状态来表达「正在跑」:status 上有 CHECK 约束,加值
|
|
60
|
-
* 要改表。
|
|
61
|
-
*
|
|
62
|
-
* 比 next_send_at 时两边都截到毫秒:列是 timestamptz(微秒精度),驱动读
|
|
63
|
-
* 出来是 JS Date(毫秒精度),原值送回去可能因为亚毫秒差对不上。
|
|
64
|
-
*
|
|
65
|
-
* 带 serializeGroup 时多一道分组门:同一分组里已经有别的行拿着未到期的租
|
|
66
|
-
* 约,这条就领不走(同一分组同时只跑一条)。判定和写租约在同一条 UPDATE
|
|
67
|
-
* 里完成,「先查再占」的空档天然不存在。分组门只看租约,不看
|
|
68
|
-
* `retry_after`:等着重试的任务其实闲着,不该把同分组的其他任务一起堵住。
|
|
69
|
-
*
|
|
70
|
-
* @param {number} taskId
|
|
71
|
-
* @param {string|Date} expectedNextSendAt - 读这行时拿到的 next_send_at 原值
|
|
72
|
-
* @param {string|Date} leaseUntil - 租期末尾
|
|
73
|
-
* @param {string|null} [serializeGroup] - 串行分组标识;空表示不参与分组串行
|
|
74
|
-
* @returns {Promise<boolean>} true = 领到了;false = 已被别人领走、同分组有
|
|
75
|
-
* 任务正在跑、或行已不是 pending
|
|
76
|
-
*/
|
|
77
|
-
claimTask(taskId: number, expectedNextSendAt: string | Date, leaseUntil: string | Date, serializeGroup?: string | null): Promise<boolean>;
|
|
55
|
+
claimTask(taskId: any, expectedNextSendAt: any, leaseUntil: any, serializeGroup?: any): Promise<boolean>;
|
|
56
|
+
renewTaskLease(taskId: any, leaseUntil: any): Promise<boolean>;
|
|
78
57
|
listTasks(userId: any, opts?: {}): Promise<{
|
|
79
58
|
tasks: any[][];
|
|
80
59
|
total: number;
|
|
81
60
|
}>;
|
|
82
61
|
cleanupOldTasks(days?: number): Promise<number>;
|
|
83
62
|
getTaskStatus(uuid: any, userId: any): Promise<any>;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
*/
|
|
90
|
-
getPushSubscription(userId: string): Promise<{
|
|
63
|
+
getTaskStatusInfo(uuid: any, userId: any): Promise<{
|
|
64
|
+
status: string;
|
|
65
|
+
last_error: string | null;
|
|
66
|
+
}>;
|
|
67
|
+
getPushSubscription(userId: any): Promise<{
|
|
91
68
|
subscription: string;
|
|
92
69
|
updated_at: number;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
* 客户端拿到的新订阅永远比旧的有效,旧的那份只会 410。
|
|
97
|
-
*
|
|
98
|
-
* @param {string} userId
|
|
99
|
-
* @param {string} encryptedSubscription
|
|
100
|
-
* @param {number} updatedAt - epoch 毫秒
|
|
101
|
-
* @returns {Promise<boolean>}
|
|
102
|
-
*/
|
|
103
|
-
upsertPushSubscription(userId: string, encryptedSubscription: string, updatedAt: number): Promise<boolean>;
|
|
104
|
-
/**
|
|
105
|
-
* 删掉这个用户的订阅(设置页「停止接收推送」)。
|
|
106
|
-
*
|
|
107
|
-
* @param {string} userId
|
|
108
|
-
* @returns {Promise<boolean>} true = 确实删掉了一行
|
|
109
|
-
*/
|
|
110
|
-
deletePushSubscription(userId: string): Promise<boolean>;
|
|
70
|
+
}>;
|
|
71
|
+
upsertPushSubscription(userId: any, encryptedSubscription: any, updatedAt: any): Promise<boolean>;
|
|
72
|
+
deletePushSubscription(userId: any): Promise<boolean>;
|
|
111
73
|
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 派生值而不是宿主给的原始 key —— 原始 key 往往是角色 id 之类的宿主数据,
|
|
13
13
|
* 任务内容都是密文落库的,这一列不该成为它的明文出口。
|
|
14
14
|
*/
|
|
15
|
-
export const TABLE_SQL: "\n CREATE TABLE IF NOT EXISTS scheduled_messages (\n id SERIAL PRIMARY KEY,\n user_id VARCHAR(255) NOT NULL,\n uuid VARCHAR(36),\n encrypted_payload TEXT NOT NULL,\n message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('fixed', 'prompted', 'auto', 'instant')),\n next_send_at TIMESTAMP WITH TIME ZONE NOT NULL,\n lease_until TIMESTAMP WITH TIME ZONE,\n retry_after TIMESTAMP WITH TIME ZONE,\n serialize_group VARCHAR(64),\n status VARCHAR(50) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'sent', 'failed')),\n retry_count INTEGER DEFAULT 0,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n";
|
|
15
|
+
export const TABLE_SQL: "\n CREATE TABLE IF NOT EXISTS scheduled_messages (\n id SERIAL PRIMARY KEY,\n user_id VARCHAR(255) NOT NULL,\n uuid VARCHAR(36),\n encrypted_payload TEXT NOT NULL,\n message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('fixed', 'prompted', 'auto', 'instant')),\n next_send_at TIMESTAMP WITH TIME ZONE NOT NULL,\n lease_until TIMESTAMP WITH TIME ZONE,\n retry_after TIMESTAMP WITH TIME ZONE,\n serialize_group VARCHAR(64),\n status VARCHAR(50) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'sent', 'failed')),\n retry_count INTEGER DEFAULT 0,\n last_error TEXT,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n";
|
|
16
16
|
/**
|
|
17
17
|
* 建表语句用的是 CREATE TABLE IF NOT EXISTS,已经存在的表不会被改动,所以
|
|
18
18
|
* 后加的列要单独补。initSchema 每次都会跑一遍,Postgres 的 IF NOT EXISTS
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Index entries mirror the Postgres INDEXES shape ({ name, sql, description,
|
|
15
15
|
* critical }) so both adapters' initSchema() return the same index metadata.
|
|
16
16
|
*/
|
|
17
|
-
export const SQLITE_TABLE_SQL: "\n CREATE TABLE IF NOT EXISTS scheduled_messages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_id TEXT NOT NULL,\n uuid TEXT,\n encrypted_payload TEXT NOT NULL,\n message_type TEXT NOT NULL CHECK (message_type IN ('fixed', 'prompted', 'auto', 'instant')),\n next_send_at TEXT NOT NULL,\n lease_until TEXT,\n retry_after TEXT,\n serialize_group TEXT,\n status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'sent', 'failed')),\n retry_count INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n";
|
|
17
|
+
export const SQLITE_TABLE_SQL: "\n CREATE TABLE IF NOT EXISTS scheduled_messages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_id TEXT NOT NULL,\n uuid TEXT,\n encrypted_payload TEXT NOT NULL,\n message_type TEXT NOT NULL CHECK (message_type IN ('fixed', 'prompted', 'auto', 'instant')),\n next_send_at TEXT NOT NULL,\n lease_until TEXT,\n retry_after TEXT,\n serialize_group TEXT,\n status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'sent', 'failed')),\n retry_count INTEGER NOT NULL DEFAULT 0,\n last_error TEXT,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n )\n";
|
|
18
18
|
/**
|
|
19
19
|
* 建表语句用的是 CREATE TABLE IF NOT EXISTS,已经存在的表不会被改动,所以
|
|
20
20
|
* 后加的列要单独补。initSchema 每次都会跑一遍,列已经在了就跳过。
|
|
@@ -32,3 +32,17 @@ export const SQLITE_INDEXES: {
|
|
|
32
32
|
}[];
|
|
33
33
|
export const CLIENT_STATE_TABLE_SQL: "\n CREATE TABLE IF NOT EXISTS client_state (\n user_id TEXT NOT NULL,\n namespace TEXT NOT NULL,\n key TEXT NOT NULL,\n value TEXT NOT NULL,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (user_id, namespace, key)\n )\n";
|
|
34
34
|
export const PUSH_SUBSCRIPTION_TABLE_SQL: "\n CREATE TABLE IF NOT EXISTS push_subscriptions (\n user_id TEXT PRIMARY KEY,\n subscription TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n )\n";
|
|
35
|
+
export const MESSAGE_OUTBOX_TABLE_SQL: "\n CREATE TABLE IF NOT EXISTS message_outbox (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n user_id TEXT NOT NULL,\n message_id TEXT NOT NULL,\n task_uuid TEXT,\n session_id TEXT,\n message_index INTEGER,\n total_messages INTEGER,\n payload TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n delivered_at INTEGER,\n acked_at INTEGER,\n UNIQUE (user_id, message_id)\n )\n";
|
|
36
|
+
export const MESSAGE_OUTBOX_INDEX_SQL: "\n CREATE INDEX IF NOT EXISTS idx_outbox_unacked\n ON message_outbox (user_id, id)\n WHERE acked_at IS NULL\n";
|
|
37
|
+
/**
|
|
38
|
+
* 这一版代码跑起来需要的表 / 列 / 索引。
|
|
39
|
+
*
|
|
40
|
+
* 索引只列 critical 的那几个(uidx_uuid 之类):其余索引缺了只是慢,缺了它则
|
|
41
|
+
* 是正确性问题。
|
|
42
|
+
*
|
|
43
|
+
* @type {{ tables: Record<string, string[]>, indexes: string[] }}
|
|
44
|
+
*/
|
|
45
|
+
export const SQLITE_REQUIRED_SCHEMA: {
|
|
46
|
+
tables: Record<string, string[]>;
|
|
47
|
+
indexes: string[];
|
|
48
|
+
};
|
|
@@ -12,6 +12,7 @@ var TABLE_SQL = `
|
|
|
12
12
|
serialize_group VARCHAR(64),
|
|
13
13
|
status VARCHAR(50) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'sent', 'failed')),
|
|
14
14
|
retry_count INTEGER DEFAULT 0,
|
|
15
|
+
last_error TEXT,
|
|
15
16
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
16
17
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
17
18
|
)
|
|
@@ -31,6 +32,14 @@ var MIGRATIONS = [
|
|
|
31
32
|
name: "add_serialize_group",
|
|
32
33
|
sql: "ALTER TABLE scheduled_messages ADD COLUMN IF NOT EXISTS serialize_group VARCHAR(64)",
|
|
33
34
|
description: "Serialization group for runScheduledTick serializeBy (2.6.0)"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "add_last_error",
|
|
38
|
+
// 上一次投递失败的脱敏摘要(JSON:{ at, occurrence, reason })。payload 里
|
|
39
|
+
// 的 lastError 是密文里的完整记录,这一列是它的明文出口——payload 本身
|
|
40
|
+
// 解密失败时也写得进去,GET /message 对已失败的行也读得出来。
|
|
41
|
+
sql: "ALTER TABLE scheduled_messages ADD COLUMN IF NOT EXISTS last_error TEXT",
|
|
42
|
+
description: "Sanitized last delivery-failure summary (2.6.0)"
|
|
34
43
|
}
|
|
35
44
|
];
|
|
36
45
|
var INDEXES = [
|
|
@@ -108,6 +117,7 @@ var UPDATABLE_COLUMNS = /* @__PURE__ */ new Set([
|
|
|
108
117
|
"serialize_group",
|
|
109
118
|
"status",
|
|
110
119
|
"retry_count",
|
|
120
|
+
"last_error",
|
|
111
121
|
"created_at",
|
|
112
122
|
"updated_at"
|
|
113
123
|
]);
|