@rei-standard/amsg-server 2.6.0-next.11 → 2.6.0-next.13
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 +68 -3
- package/dist/adapters/d1.d.ts +10 -2
- package/dist/adapters/interface.d.ts +12 -5
- package/dist/adapters/neon.d.ts +9 -2
- package/dist/adapters/pg.d.ts +9 -2
- package/dist/adapters/schema.d.ts +12 -1
- package/dist/adapters/schema.sqlite.d.ts +4 -1
- package/dist/{chunk-QGJSWMQP.cjs → chunk-5IOYCCFD.cjs} +302 -38
- package/dist/{chunk-WAFOSZL3.mjs → chunk-B2FDV7YK.mjs} +21 -0
- package/dist/{chunk-HZDUURIR.mjs → chunk-TV7N3RTH.mjs} +301 -37
- package/dist/{chunk-4SIN2R66.cjs → chunk-V2SDWGUB.cjs} +21 -0
- package/dist/cloudflare.cjs +2 -2
- package/dist/cloudflare.mjs +1 -1
- package/dist/handlers/get-message.d.ts +3 -0
- package/dist/index.cjs +23 -21
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +5 -3
- package/dist/lib/agentic-fire.d.ts +20 -0
- package/dist/lib/run-tick.d.ts +15 -0
- package/dist/lib/task-projection.d.ts +14 -1
- package/dist/{neon-2CS4TLNS.cjs → neon-3ASBLLCM.cjs} +37 -15
- package/dist/{neon-YUKD2B77.mjs → neon-CUIGAB2T.mjs} +29 -7
- package/dist/{pg-PM5RYRWH.cjs → pg-IEZTAR43.cjs} +37 -15
- package/dist/{pg-JNQ6VMXC.mjs → pg-KMJPL6QV.mjs} +29 -7
- package/dist/single-user.d.ts +4 -0
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunkV2SDWGUBcjs = require('./chunk-V2SDWGUB.cjs');
|
|
10
10
|
|
|
11
11
|
// src/server/adapters/pg.js
|
|
12
12
|
var _pg = require('pg');
|
|
@@ -30,13 +30,13 @@ var PgAdapter = class {
|
|
|
30
30
|
return result.rows;
|
|
31
31
|
}
|
|
32
32
|
async initSchema() {
|
|
33
|
-
await this._query(
|
|
34
|
-
await this._query(
|
|
35
|
-
for (const migration of
|
|
33
|
+
await this._query(_chunkV2SDWGUBcjs.TABLE_SQL);
|
|
34
|
+
await this._query(_chunkV2SDWGUBcjs.PUSH_SUBSCRIPTION_TABLE_SQL);
|
|
35
|
+
for (const migration of _chunkV2SDWGUBcjs.MIGRATIONS) {
|
|
36
36
|
await this._query(migration.sql);
|
|
37
37
|
}
|
|
38
38
|
const indexResults = [];
|
|
39
|
-
for (const index of
|
|
39
|
+
for (const index of _chunkV2SDWGUBcjs.INDEXES) {
|
|
40
40
|
try {
|
|
41
41
|
await this._query(index.sql);
|
|
42
42
|
indexResults.push({
|
|
@@ -62,11 +62,11 @@ var PgAdapter = class {
|
|
|
62
62
|
`Critical index creation failed (${failedNames}). Please remove duplicate UUID rows and run initSchema again.`
|
|
63
63
|
);
|
|
64
64
|
}
|
|
65
|
-
const tableCheck = await this._query(
|
|
65
|
+
const tableCheck = await this._query(_chunkV2SDWGUBcjs.VERIFY_TABLE_SQL);
|
|
66
66
|
if (tableCheck.length === 0) {
|
|
67
67
|
throw new Error("Table creation verification failed");
|
|
68
68
|
}
|
|
69
|
-
const columns = await this._query(
|
|
69
|
+
const columns = await this._query(_chunkV2SDWGUBcjs.COLUMNS_SQL);
|
|
70
70
|
return {
|
|
71
71
|
columnsCreated: columns.length,
|
|
72
72
|
indexesCreated: indexResults.filter((r) => r.status === "success").length,
|
|
@@ -93,7 +93,7 @@ var PgAdapter = class {
|
|
|
93
93
|
}
|
|
94
94
|
async getTaskByUuid(uuid, userId) {
|
|
95
95
|
const rows = await this._query(
|
|
96
|
-
`SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
|
|
96
|
+
`SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count, created_at, updated_at
|
|
97
97
|
FROM scheduled_messages
|
|
98
98
|
WHERE uuid = $1 AND user_id = $2 AND status = 'pending'
|
|
99
99
|
LIMIT 1`,
|
|
@@ -116,7 +116,7 @@ var PgAdapter = class {
|
|
|
116
116
|
const values = [];
|
|
117
117
|
let idx = 1;
|
|
118
118
|
for (const [key, value] of Object.entries(updates)) {
|
|
119
|
-
if (!
|
|
119
|
+
if (!_chunkV2SDWGUBcjs.UPDATABLE_COLUMNS.has(key)) {
|
|
120
120
|
throw new Error(`[amsg-server pg] rejected unknown update column: ${key}`);
|
|
121
121
|
}
|
|
122
122
|
sets.push(`${key} = $${idx}`);
|
|
@@ -137,7 +137,7 @@ var PgAdapter = class {
|
|
|
137
137
|
let idx = 2;
|
|
138
138
|
if (extraFields) {
|
|
139
139
|
for (const [key, value] of Object.entries(extraFields)) {
|
|
140
|
-
if (!
|
|
140
|
+
if (!_chunkV2SDWGUBcjs.UPDATABLE_COLUMNS.has(key)) {
|
|
141
141
|
throw new Error(`[amsg-server pg] rejected unknown update column: ${key}`);
|
|
142
142
|
}
|
|
143
143
|
sets.push(`${key} = $${idx}`);
|
|
@@ -171,6 +171,7 @@ var PgAdapter = class {
|
|
|
171
171
|
FROM scheduled_messages
|
|
172
172
|
WHERE status = 'pending' AND next_send_at <= NOW()
|
|
173
173
|
AND (lease_until IS NULL OR lease_until <= NOW())
|
|
174
|
+
AND (retry_after IS NULL OR retry_after <= NOW())
|
|
174
175
|
ORDER BY next_send_at ASC
|
|
175
176
|
LIMIT $1`,
|
|
176
177
|
[limit]
|
|
@@ -196,21 +197,42 @@ var PgAdapter = class {
|
|
|
196
197
|
* 比 next_send_at 时两边都截到毫秒:列是 timestamptz(微秒精度),驱动读
|
|
197
198
|
* 出来是 JS Date(毫秒精度),原值送回去可能因为亚毫秒差对不上。
|
|
198
199
|
*
|
|
200
|
+
* 带 serializeGroup 时多一道分组门:同一分组里已经有别的行拿着未到期的租
|
|
201
|
+
* 约,这条就领不走(同一分组同时只跑一条)。判定和写租约在同一条 UPDATE
|
|
202
|
+
* 里完成,「先查再占」的空档天然不存在。分组门只看租约,不看
|
|
203
|
+
* `retry_after`:等着重试的任务其实闲着,不该把同分组的其他任务一起堵住。
|
|
204
|
+
*
|
|
199
205
|
* @param {number} taskId
|
|
200
206
|
* @param {string|Date} expectedNextSendAt - 读这行时拿到的 next_send_at 原值
|
|
201
207
|
* @param {string|Date} leaseUntil - 租期末尾
|
|
202
|
-
* @
|
|
208
|
+
* @param {string|null} [serializeGroup] - 串行分组标识;空表示不参与分组串行
|
|
209
|
+
* @returns {Promise<boolean>} true = 领到了;false = 已被别人领走、同分组有
|
|
210
|
+
* 任务正在跑、或行已不是 pending
|
|
203
211
|
*/
|
|
204
|
-
async claimTask(taskId, expectedNextSendAt, leaseUntil) {
|
|
212
|
+
async claimTask(taskId, expectedNextSendAt, leaseUntil, serializeGroup = null) {
|
|
213
|
+
const grouped = typeof serializeGroup === "string" && serializeGroup.length > 0;
|
|
214
|
+
const params = [leaseUntil, taskId, expectedNextSendAt];
|
|
215
|
+
let setClause = "lease_until = $1, updated_at = NOW()";
|
|
216
|
+
let groupGuard = "";
|
|
217
|
+
if (grouped) {
|
|
218
|
+
params.push(serializeGroup);
|
|
219
|
+
setClause = "lease_until = $1, serialize_group = $4, updated_at = NOW()";
|
|
220
|
+
groupGuard = `
|
|
221
|
+
AND NOT EXISTS (
|
|
222
|
+
SELECT 1 FROM scheduled_messages busy
|
|
223
|
+
WHERE busy.serialize_group = $4 AND busy.id <> $2
|
|
224
|
+
AND busy.status = 'pending' AND busy.lease_until > NOW()
|
|
225
|
+
)`;
|
|
226
|
+
}
|
|
205
227
|
const rows = await this._query(
|
|
206
228
|
`UPDATE scheduled_messages
|
|
207
|
-
SET
|
|
229
|
+
SET ${setClause}
|
|
208
230
|
WHERE id = $2 AND status = 'pending'
|
|
209
231
|
AND date_trunc('milliseconds', next_send_at)
|
|
210
232
|
= date_trunc('milliseconds', $3::timestamptz)
|
|
211
|
-
AND (lease_until IS NULL OR lease_until <= NOW())
|
|
233
|
+
AND (lease_until IS NULL OR lease_until <= NOW())${groupGuard}
|
|
212
234
|
RETURNING id`,
|
|
213
|
-
|
|
235
|
+
params
|
|
214
236
|
);
|
|
215
237
|
return rows.length > 0;
|
|
216
238
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
TABLE_SQL,
|
|
7
7
|
UPDATABLE_COLUMNS,
|
|
8
8
|
VERIFY_TABLE_SQL
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-B2FDV7YK.mjs";
|
|
10
10
|
|
|
11
11
|
// src/server/adapters/pg.js
|
|
12
12
|
import { Pool } from "pg";
|
|
@@ -93,7 +93,7 @@ var PgAdapter = class {
|
|
|
93
93
|
}
|
|
94
94
|
async getTaskByUuid(uuid, userId) {
|
|
95
95
|
const rows = await this._query(
|
|
96
|
-
`SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count
|
|
96
|
+
`SELECT id, user_id, uuid, encrypted_payload, message_type, next_send_at, status, retry_count, created_at, updated_at
|
|
97
97
|
FROM scheduled_messages
|
|
98
98
|
WHERE uuid = $1 AND user_id = $2 AND status = 'pending'
|
|
99
99
|
LIMIT 1`,
|
|
@@ -171,6 +171,7 @@ var PgAdapter = class {
|
|
|
171
171
|
FROM scheduled_messages
|
|
172
172
|
WHERE status = 'pending' AND next_send_at <= NOW()
|
|
173
173
|
AND (lease_until IS NULL OR lease_until <= NOW())
|
|
174
|
+
AND (retry_after IS NULL OR retry_after <= NOW())
|
|
174
175
|
ORDER BY next_send_at ASC
|
|
175
176
|
LIMIT $1`,
|
|
176
177
|
[limit]
|
|
@@ -196,21 +197,42 @@ var PgAdapter = class {
|
|
|
196
197
|
* 比 next_send_at 时两边都截到毫秒:列是 timestamptz(微秒精度),驱动读
|
|
197
198
|
* 出来是 JS Date(毫秒精度),原值送回去可能因为亚毫秒差对不上。
|
|
198
199
|
*
|
|
200
|
+
* 带 serializeGroup 时多一道分组门:同一分组里已经有别的行拿着未到期的租
|
|
201
|
+
* 约,这条就领不走(同一分组同时只跑一条)。判定和写租约在同一条 UPDATE
|
|
202
|
+
* 里完成,「先查再占」的空档天然不存在。分组门只看租约,不看
|
|
203
|
+
* `retry_after`:等着重试的任务其实闲着,不该把同分组的其他任务一起堵住。
|
|
204
|
+
*
|
|
199
205
|
* @param {number} taskId
|
|
200
206
|
* @param {string|Date} expectedNextSendAt - 读这行时拿到的 next_send_at 原值
|
|
201
207
|
* @param {string|Date} leaseUntil - 租期末尾
|
|
202
|
-
* @
|
|
208
|
+
* @param {string|null} [serializeGroup] - 串行分组标识;空表示不参与分组串行
|
|
209
|
+
* @returns {Promise<boolean>} true = 领到了;false = 已被别人领走、同分组有
|
|
210
|
+
* 任务正在跑、或行已不是 pending
|
|
203
211
|
*/
|
|
204
|
-
async claimTask(taskId, expectedNextSendAt, leaseUntil) {
|
|
212
|
+
async claimTask(taskId, expectedNextSendAt, leaseUntil, serializeGroup = null) {
|
|
213
|
+
const grouped = typeof serializeGroup === "string" && serializeGroup.length > 0;
|
|
214
|
+
const params = [leaseUntil, taskId, expectedNextSendAt];
|
|
215
|
+
let setClause = "lease_until = $1, updated_at = NOW()";
|
|
216
|
+
let groupGuard = "";
|
|
217
|
+
if (grouped) {
|
|
218
|
+
params.push(serializeGroup);
|
|
219
|
+
setClause = "lease_until = $1, serialize_group = $4, updated_at = NOW()";
|
|
220
|
+
groupGuard = `
|
|
221
|
+
AND NOT EXISTS (
|
|
222
|
+
SELECT 1 FROM scheduled_messages busy
|
|
223
|
+
WHERE busy.serialize_group = $4 AND busy.id <> $2
|
|
224
|
+
AND busy.status = 'pending' AND busy.lease_until > NOW()
|
|
225
|
+
)`;
|
|
226
|
+
}
|
|
205
227
|
const rows = await this._query(
|
|
206
228
|
`UPDATE scheduled_messages
|
|
207
|
-
SET
|
|
229
|
+
SET ${setClause}
|
|
208
230
|
WHERE id = $2 AND status = 'pending'
|
|
209
231
|
AND date_trunc('milliseconds', next_send_at)
|
|
210
232
|
= date_trunc('milliseconds', $3::timestamptz)
|
|
211
|
-
AND (lease_until IS NULL OR lease_until <= NOW())
|
|
233
|
+
AND (lease_until IS NULL OR lease_until <= NOW())${groupGuard}
|
|
212
234
|
RETURNING id`,
|
|
213
|
-
|
|
235
|
+
params
|
|
214
236
|
);
|
|
215
237
|
return rows.length > 0;
|
|
216
238
|
}
|
package/dist/single-user.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export function createSingleUserServer(config: any): {
|
|
|
40
40
|
totalTimeoutMs: any;
|
|
41
41
|
maxStateValueBytes: any;
|
|
42
42
|
onAfterSend: any;
|
|
43
|
+
onFireSettled: any;
|
|
43
44
|
maxScheduledTasksPerFire: any;
|
|
44
45
|
};
|
|
45
46
|
handlers: {
|
|
@@ -61,6 +62,9 @@ export function createSingleUserServer(config: any): {
|
|
|
61
62
|
messages: {
|
|
62
63
|
GET: (url: any, headers: any) => Promise<any>;
|
|
63
64
|
};
|
|
65
|
+
getMessage: {
|
|
66
|
+
GET: (url: any, headers: any) => Promise<any>;
|
|
67
|
+
};
|
|
64
68
|
vapidPublicKey: {
|
|
65
69
|
GET: Function;
|
|
66
70
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rei-standard/amsg-server",
|
|
3
|
-
"version": "2.6.0-next.
|
|
3
|
+
"version": "2.6.0-next.13",
|
|
4
4
|
"description": "ReiStandard Active Messaging server SDK with pluggable database adapters. Three-axis push schema (messageKind / messageType / messageSubtype) from @rei-standard/amsg-shared. Auto-emits ReasoningPush when the LLM response carries reasoning_content.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|