@zhin.js/plugin-reminder 1.0.3 → 1.0.5
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 +4 -0
- package/lib/storage.d.ts +4 -0
- package/lib/storage.d.ts.map +1 -0
- package/lib/storage.js +49 -0
- package/lib/storage.js.map +1 -0
- package/package.json +9 -9
- package/plugin.js +5 -2
- package/src/storage.ts +52 -0
package/README.md
CHANGED
|
@@ -110,3 +110,7 @@ schedules/poll/index.ts # 正式 Schedule Feature 入口
|
|
|
110
110
|
| `reminder_cancel` | 按 id 取消;需批准 |
|
|
111
111
|
|
|
112
112
|
与原生 `schedule_add` 的区别:本插件到点**向会话发送提醒文案**;`schedule_*` 到点**再次唤醒 Agent**(可带 cron / 工作日等)。绝对时间仍须带 `Z` 或 `±hh:mm`。
|
|
113
|
+
|
|
114
|
+
### 事务化任务存储
|
|
115
|
+
|
|
116
|
+
提醒与管理员 RSS 的任务、认领、操作回执和文章明细使用独立数据表,在一个事务中提交;原 CAS JSON 只用于首次迁移。支持 SQLite、MySQL、PostgreSQL,升级须完整重启,不能与旧版本进程混写。`unknown` 投递仍不会自动重试。迁移和字段说明见[结构化存储](../../../docs/operations/structured-storage.md)。
|
package/lib/storage.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type PluginDatabaseHost } from 'zhin.js/plugin-runtime';
|
|
2
|
+
/** Both pools keep their existing CAS API but persist independent rows atomically. */
|
|
3
|
+
export declare function createReminderState(database: PluginDatabaseHost): import("zhin.js").PluginStateStore;
|
|
4
|
+
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kBAAkB,EAA6B,MAAM,wBAAwB,CAAC;AA8CrF,sFAAsF;AACtF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,kBAAkB,sCAE/D"}
|
package/lib/storage.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createRelationalStateStore, TASK_TARGET_COLUMNS, TASK_RECEIPT_COLUMNS, encodeTaskTarget, decodeTaskTarget, encodeTaskReceipts, decodeTaskReceipts, encodeStorageIdentity, decodeStorageIdentity } from 'zhin.js/plugin-runtime';
|
|
2
|
+
import { REMINDER_STATE_KEY } from './service.js';
|
|
3
|
+
import { ADMIN_REMINDER_STATE_KEY } from './admin-tasks.js';
|
|
4
|
+
const taskColumns = {
|
|
5
|
+
id: { type: 'text', length: 36, primary: true }, position: { type: 'integer', nullable: false },
|
|
6
|
+
...TASK_TARGET_COLUMNS, sender_id: { type: 'text', nullable: true }, creation: { type: 'text', nullable: true },
|
|
7
|
+
content: { type: 'text', nullable: false }, state: { type: 'text', length: 24, nullable: false },
|
|
8
|
+
created_at: { type: 'bigint', nullable: false }, next_run_at: { type: 'bigint', nullable: false },
|
|
9
|
+
interval_ms: { type: 'bigint', nullable: true }, claim_id: { type: 'text', nullable: true },
|
|
10
|
+
last_run_at: { type: 'bigint', nullable: true }, detail: { type: 'text', nullable: false },
|
|
11
|
+
};
|
|
12
|
+
function codec(admin) {
|
|
13
|
+
const table = admin ? 'admin_reminder_tasks' : 'reminder_tasks';
|
|
14
|
+
const receipts = 'admin_reminder_receipts';
|
|
15
|
+
return {
|
|
16
|
+
key: admin ? ADMIN_REMINDER_STATE_KEY : REMINDER_STATE_KEY,
|
|
17
|
+
header: { table: `${table}_book`, definition: {
|
|
18
|
+
version: { type: 'integer', nullable: true }, revision: { type: 'text', nullable: true },
|
|
19
|
+
} },
|
|
20
|
+
tables: { [table]: taskColumns, ...(admin ? { [receipts]: TASK_RECEIPT_COLUMNS } : {}) },
|
|
21
|
+
encode(value) {
|
|
22
|
+
const book = value;
|
|
23
|
+
if (book.version !== 1 || !Array.isArray(book.tasks))
|
|
24
|
+
throw new Error('Unsupported reminder book; original state was preserved');
|
|
25
|
+
return { header: { version: book.version, revision: 'revision' in book ? book.revision : null }, rows: {
|
|
26
|
+
[table]: book.tasks.map((task, position) => ({ id: task.id, position, ...encodeTaskTarget(task.target),
|
|
27
|
+
sender_id: 'senderId' in task ? encodeStorageIdentity(task.senderId) : null,
|
|
28
|
+
creation: 'creation' in task ? task.creation : null, content: encodeStorageIdentity(task.text),
|
|
29
|
+
state: 'status' in task ? task.status : task.state, created_at: task.createdAt, next_run_at: task.nextRunAt,
|
|
30
|
+
interval_ms: task.intervalMs, claim_id: task.claimId, last_run_at: task.lastRunAt, detail: encodeStorageIdentity(task.detail) })),
|
|
31
|
+
...(admin ? { [receipts]: encodeTaskReceipts(book.receipts) } : {}),
|
|
32
|
+
} };
|
|
33
|
+
},
|
|
34
|
+
decode(header, rows) {
|
|
35
|
+
return { version: Number(header.version), ...(admin ? { revision: String(header.revision) } : {}),
|
|
36
|
+
tasks: rows[table].map(row => ({ id: String(row.id), target: decodeTaskTarget(row), text: decodeStorageIdentity(row.content),
|
|
37
|
+
createdAt: Number(row.created_at), nextRunAt: Number(row.next_run_at), intervalMs: row.interval_ms == null ? null : Number(row.interval_ms),
|
|
38
|
+
claimId: row.claim_id == null ? null : String(row.claim_id), lastRunAt: row.last_run_at == null ? null : Number(row.last_run_at), detail: decodeStorageIdentity(row.detail),
|
|
39
|
+
...(admin ? { creation: String(row.creation), state: String(row.state) } : { senderId: decodeStorageIdentity(row.sender_id), status: String(row.state) }),
|
|
40
|
+
})), ...(admin ? { receipts: decodeTaskReceipts(rows[receipts]) } : {}),
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Both pools keep their existing CAS API but persist independent rows atomically. */
|
|
46
|
+
export function createReminderState(database) {
|
|
47
|
+
return createRelationalStateStore(database, [codec(false), codec(true)]);
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-reminder",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Persistent personal reminders for Zhin Plugin Runtime",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -22,15 +22,15 @@
|
|
|
22
22
|
"schema.json"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@zhin.js/im-contract": "1.1.
|
|
26
|
-
"@zhin.js/skill": "1.1.
|
|
27
|
-
"@zhin.js/tool": "1.1.
|
|
25
|
+
"@zhin.js/im-contract": "1.1.6",
|
|
26
|
+
"@zhin.js/skill": "1.1.9",
|
|
27
|
+
"@zhin.js/tool": "1.1.9"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"zod": "^4.0.0",
|
|
31
|
-
"zhin.js": "^1.1.
|
|
32
|
-
"@zhin.js/command": "^1.1.
|
|
33
|
-
"@zhin.js/schedule-feature": "^1.1.
|
|
31
|
+
"zhin.js": "^1.1.15",
|
|
32
|
+
"@zhin.js/command": "^1.1.10",
|
|
33
|
+
"@zhin.js/schedule-feature": "^1.1.8"
|
|
34
34
|
},
|
|
35
35
|
"peerDependenciesMeta": {
|
|
36
36
|
"@zhin.js/command": {
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"typescript": "^6.0.3",
|
|
48
48
|
"vitest": "^4.1.10",
|
|
49
49
|
"zod": "^4.4.3",
|
|
50
|
-
"
|
|
51
|
-
"zhin.js": "1.1.
|
|
50
|
+
"zhin.js": "1.1.15",
|
|
51
|
+
"@zhin.js/schedule-feature": "1.1.8"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22.19.0"
|
package/plugin.js
CHANGED
|
@@ -3,6 +3,7 @@ import { databaseHostToken, definePlugin, outboundHostToken } from 'zhin.js';
|
|
|
3
3
|
import { pluginVerificationToken, pluginTaskProviderToken } from 'zhin.js/plugin-runtime';
|
|
4
4
|
import { randomUUID } from 'node:crypto';
|
|
5
5
|
import { assertReminderTimezone } from "./lib/config.js";
|
|
6
|
+
import { createReminderState } from "./lib/storage.js";
|
|
6
7
|
import { ReminderService } from "./lib/service.js";
|
|
7
8
|
import { reminderServiceToken } from "./lib/runtime.js";
|
|
8
9
|
export default definePlugin({
|
|
@@ -12,11 +13,13 @@ export default definePlugin({
|
|
|
12
13
|
setup(context) {
|
|
13
14
|
const config = context.config.get();
|
|
14
15
|
assertReminderTimezone(config.timezone);
|
|
15
|
-
const
|
|
16
|
+
const database = context.resources.use(databaseHostToken);
|
|
17
|
+
const state = database.state;
|
|
18
|
+
const taskState = createReminderState(database);
|
|
16
19
|
const outbound = context.resources.use(outboundHostToken);
|
|
17
20
|
if (!outbound.sendTarget)
|
|
18
21
|
throw new Error('提醒需要支持精确 DeliveryTarget 的 Outbound Host');
|
|
19
|
-
const service = new ReminderService(
|
|
22
|
+
const service = new ReminderService(taskState, outbound, config);
|
|
20
23
|
context.resources.provide(reminderServiceToken, service);
|
|
21
24
|
context.resources.provide(pluginTaskProviderToken, service.administratorTasks);
|
|
22
25
|
context.resources.provide(pluginVerificationToken, {
|
package/src/storage.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createRelationalStateStore, TASK_TARGET_COLUMNS, TASK_RECEIPT_COLUMNS, encodeTaskTarget, decodeTaskTarget,
|
|
2
|
+
encodeTaskReceipts, decodeTaskReceipts, encodeStorageIdentity, decodeStorageIdentity,
|
|
3
|
+
type PluginDatabaseHost, type RelationalStateCodec } from 'zhin.js/plugin-runtime';
|
|
4
|
+
import { REMINDER_STATE_KEY, type ReminderBook } from './service.js';
|
|
5
|
+
import { ADMIN_REMINDER_STATE_KEY, type AdminReminderBook } from './admin-tasks.js';
|
|
6
|
+
|
|
7
|
+
const taskColumns = {
|
|
8
|
+
id: { type: 'text', length: 36, primary: true }, position: { type: 'integer', nullable: false },
|
|
9
|
+
...TASK_TARGET_COLUMNS, sender_id: { type: 'text', nullable: true }, creation: { type: 'text', nullable: true },
|
|
10
|
+
content: { type: 'text', nullable: false }, state: { type: 'text', length: 24, nullable: false },
|
|
11
|
+
created_at: { type: 'bigint', nullable: false }, next_run_at: { type: 'bigint', nullable: false },
|
|
12
|
+
interval_ms: { type: 'bigint', nullable: true }, claim_id: { type: 'text', nullable: true },
|
|
13
|
+
last_run_at: { type: 'bigint', nullable: true }, detail: { type: 'text', nullable: false },
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function codec(admin: boolean): RelationalStateCodec {
|
|
17
|
+
const table = admin ? 'admin_reminder_tasks' : 'reminder_tasks';
|
|
18
|
+
const receipts = 'admin_reminder_receipts';
|
|
19
|
+
return {
|
|
20
|
+
key: admin ? ADMIN_REMINDER_STATE_KEY : REMINDER_STATE_KEY,
|
|
21
|
+
header: { table: `${table}_book`, definition: {
|
|
22
|
+
version: { type: 'integer', nullable: true }, revision: { type: 'text', nullable: true },
|
|
23
|
+
} },
|
|
24
|
+
tables: { [table]: taskColumns, ...(admin ? { [receipts]: TASK_RECEIPT_COLUMNS } : {}) },
|
|
25
|
+
encode(value) {
|
|
26
|
+
const book = value as ReminderBook | AdminReminderBook;
|
|
27
|
+
if (book.version !== 1 || !Array.isArray(book.tasks)) throw new Error('Unsupported reminder book; original state was preserved');
|
|
28
|
+
return { header: { version: book.version, revision: 'revision' in book ? book.revision : null }, rows: {
|
|
29
|
+
[table]: book.tasks.map((task, position) => ({ id: task.id, position, ...encodeTaskTarget(task.target),
|
|
30
|
+
sender_id: 'senderId' in task ? encodeStorageIdentity(task.senderId) : null,
|
|
31
|
+
creation: 'creation' in task ? task.creation : null, content: encodeStorageIdentity(task.text),
|
|
32
|
+
state: 'status' in task ? task.status : task.state, created_at: task.createdAt, next_run_at: task.nextRunAt,
|
|
33
|
+
interval_ms: task.intervalMs, claim_id: task.claimId, last_run_at: task.lastRunAt, detail: encodeStorageIdentity(task.detail) })),
|
|
34
|
+
...(admin ? { [receipts]: encodeTaskReceipts((book as AdminReminderBook).receipts) } : {}),
|
|
35
|
+
} };
|
|
36
|
+
},
|
|
37
|
+
decode(header, rows) {
|
|
38
|
+
return { version: Number(header.version), ...(admin ? { revision: String(header.revision) } : {}),
|
|
39
|
+
tasks: rows[table]!.map(row => ({ id: String(row.id), target: decodeTaskTarget(row), text: decodeStorageIdentity(row.content),
|
|
40
|
+
createdAt: Number(row.created_at), nextRunAt: Number(row.next_run_at), intervalMs: row.interval_ms == null ? null : Number(row.interval_ms),
|
|
41
|
+
claimId: row.claim_id == null ? null : String(row.claim_id), lastRunAt: row.last_run_at == null ? null : Number(row.last_run_at), detail: decodeStorageIdentity(row.detail),
|
|
42
|
+
...(admin ? { creation: String(row.creation), state: String(row.state) } : { senderId: decodeStorageIdentity(row.sender_id), status: String(row.state) }),
|
|
43
|
+
})), ...(admin ? { receipts: decodeTaskReceipts(rows[receipts]!) } : {}),
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Both pools keep their existing CAS API but persist independent rows atomically. */
|
|
50
|
+
export function createReminderState(database: PluginDatabaseHost) {
|
|
51
|
+
return createRelationalStateStore(database, [codec(false), codec(true)]);
|
|
52
|
+
}
|