@rei-standard/amsg-server 2.6.0-next.33 → 2.6.0-next.35

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 CHANGED
@@ -1014,3 +1014,18 @@ async function executeToolCalls(calls, ctx) {
1014
1014
  取消收尾使用 `onFireSettled({ status: 'cancelled', willRetry: false, error, ... })`,不是生成失败。应用应在这里释放资源、结算已发生的用量,避免发出失败提示或把未送达内容记为已回复。取消时已经开始写入的 outbox 批次会在写完后检查信号并撤掉未投递部分;已经发到客户端的消息仍由客户端处理。应用需要记录停止的任务身份,拦住迟到推送、补收以及尚未显示的本地内容。已完成的外部副作用无法撤销;不支持 AbortSignal 的工具也需要自己在执行步骤之间检查取消。
1015
1015
 
1016
1016
  执行阶段的 `ctx.writeState`、`scheduleTask`、`cancelTask`、`renewTask` 和 `emitResult` 会拒绝取消后新发起的操作。`onFireSettled` 的 `info.writeState` 特意仍可用,供宿主释放锁、保存账单等收尾;它不能用于继续生成阶段的业务动作。已经开始的数据库写入不支持回滚,宿主仍需处理并发状态版本。
1017
+
1018
+ ### Cloud data inventory and cleanup (D1)
1019
+
1020
+ Single-user D1 deployments expose `cloud-data-management` in `/capabilities`.
1021
+ The management API lists actual cloud resources, including acknowledged outbox
1022
+ rows, orphan state chunks and resources missing a local character. Cleanup uses
1023
+ server previews, persistent operations and cron continuation. Owner retirement
1024
+ fences future writes and in-flight task outputs; restoration is explicit and
1025
+ returns the generation required on subsequent writes.
1026
+
1027
+ See the repository [cloud data management contract](../../../docs/cloud-data-management.md)
1028
+ for routes, encrypted metadata, host `cloudData.resolveOwner` configuration,
1029
+ retention, and upgrade requirements. Other adapters do not advertise this
1030
+ capability. Use the matching client SDK management methods rather than composing
1031
+ bulk deletes from the browser's local resource list.
@@ -49,6 +49,104 @@ export class D1Adapter {
49
49
  * @returns {Promise<number>} 各批影响行数之和
50
50
  */
51
51
  private _runInClauseWrite;
52
+ /** A complete management implementation needs real transactional batches. */
53
+ get cloudDataManagement(): boolean;
54
+ _cloudGuardPredicate(userId: any, guard: any): {
55
+ sql: string;
56
+ args: any[];
57
+ };
58
+ _cloudBatch(statements: any, userId: any, guards?: any[], metadata?: Map<any, any>): Promise<any[]>;
59
+ getCloudResourceMetadata(userId: any, resourceKey: any): Promise<any>;
60
+ listCloudResourceRows(userId: any): Promise<{
61
+ gaps: any[];
62
+ }>;
63
+ _cloudRecord(row: any): Promise<{
64
+ id: any;
65
+ userId: any;
66
+ kind: any;
67
+ data: any;
68
+ updatedAt: any;
69
+ }>;
70
+ putCloudDataRecord(userId: any, kind: any, id: any, data: any, { idempotencyKey, createOnly, leaseToken, work }?: {
71
+ idempotencyKey?: any;
72
+ createOnly?: boolean;
73
+ }): Promise<{
74
+ id: any;
75
+ userId: any;
76
+ kind: any;
77
+ data: any;
78
+ updatedAt: any;
79
+ }>;
80
+ getCloudDataRecord(userId: any, kind: any, id: any): Promise<{
81
+ id: any;
82
+ userId: any;
83
+ kind: any;
84
+ data: any;
85
+ updatedAt: any;
86
+ }>;
87
+ getCloudDataRecordByIdempotency(userId: any, kind: any, idempotencyKey: any): Promise<{
88
+ id: any;
89
+ userId: any;
90
+ kind: any;
91
+ data: any;
92
+ updatedAt: any;
93
+ }>;
94
+ _cloudRecordForList(row: any): Promise<{
95
+ id: any;
96
+ userId: any;
97
+ kind: any;
98
+ data: any;
99
+ updatedAt: any;
100
+ }>;
101
+ listCloudDataRecords(userId: any, kind: any): Promise<any[]>;
102
+ listCloudDataRecordsAcrossUsers(kind: any): Promise<any[]>;
103
+ claimCloudDataRecord(userId: any, kind: any, id: any, leaseMs: any, leaseToken?: any): Promise<boolean>;
104
+ releaseCloudDataRecord(userId: any, kind: any, id: any, leaseToken: any): Promise<void>;
105
+ renewCloudDataRecordLease(userId: any, kind: any, id: any, leaseMs: any, leaseToken: any): Promise<boolean>;
106
+ deleteCloudDataRecord(userId: any, kind: any, id: any): Promise<boolean>;
107
+ cleanupCloudDataRecords(kind: any, beforeMs: any): Promise<any>;
108
+ listDueCloudDataOperations(now?: number, limit?: number): Promise<any[]>;
109
+ cleanupExpiredCloudDataRecords(now?: number, limit?: number): Promise<any>;
110
+ getCloudMaintenanceBatch(name: any, table: any, limit?: number): Promise<{
111
+ rows: any[];
112
+ completed: boolean;
113
+ upperBound?: undefined;
114
+ cursor?: undefined;
115
+ } | {
116
+ rows: any;
117
+ upperBound: any;
118
+ cursor: any;
119
+ completed: boolean;
120
+ }>;
121
+ finishCloudMaintenanceBatch(name: any, cursor: any, completed: any): Promise<void>;
122
+ indexCloudDataRecordWork(userId: any, kind: any, id: any, work: any, expectedWriteToken?: any): Promise<void>;
123
+ readCloudMaintenanceRecord(row: any): Promise<{
124
+ id: any;
125
+ userId: any;
126
+ kind: any;
127
+ data: any;
128
+ updatedAt: any;
129
+ }>;
130
+ repairCloudResourceMetadata(limit?: number): Promise<void>;
131
+ /** One explicit repair, or a bounded upgrade batch; never called as a recurring sweep. */
132
+ cleanupCloudResourceMetadata(userId?: any, range?: any): Promise<any>;
133
+ listCloudOwners(userId: any): Promise<any>;
134
+ getCloudOwner(userId: any, owner: any): Promise<{
135
+ active: boolean;
136
+ generation: any;
137
+ updatedAt: any;
138
+ }>;
139
+ setCloudOwnerActive(userId: any, owner: any, active: any, expectedGeneration: any): Promise<{
140
+ active: boolean;
141
+ generation: any;
142
+ updatedAt: any;
143
+ }>;
144
+ isCloudOwnerGuardValid(userId: any, guard: any): Promise<boolean>;
145
+ /** Delete only the exact physical snapshot; no untrusted SQL identifiers. */
146
+ deleteCloudResourceRows(userId: any, locators: any, { operationId, leaseToken }?: {}): Promise<{
147
+ deleted: number;
148
+ changed: number;
149
+ }>;
52
150
  initSchema(): Promise<{
53
151
  columnsCreated: number;
54
152
  indexesCreated: number;
@@ -76,14 +174,15 @@ export class D1Adapter {
76
174
  * 构变了而老部署没跑过 initSchema 时,cron 会每分钟静默挂在缺的那一列上,
77
175
  * 界面上一切正常——这个方法就是让宿主查得出来。
78
176
  *
79
- * @returns {Promise<{ tables: Record<string, string[]>, indexes: string[] }>}
177
+ * @returns {Promise<{ tables: Record<string, string[]>, indexes: string[], triggers: string[] }>}
80
178
  */
81
179
  describeSchema(): Promise<{
82
180
  tables: Record<string, string[]>;
83
181
  indexes: string[];
182
+ triggers: string[];
84
183
  }>;
85
184
  dropSchema(): Promise<void>;
86
- createTask(params: any): Promise<any>;
185
+ createTask(params: any, cloudGuard?: any): Promise<any>;
87
186
  /**
88
187
  * 建新任务的同时取消旧的那条(`POST /schedule-message` 的 supersedesUuid)。
89
188
  *
@@ -96,7 +195,7 @@ export class D1Adapter {
96
195
  * @returns {Promise<Object>} createTask 的返回行 + `superseded`(旧行是否
97
196
  * 真的被删掉;false = 旧行本就不存在)
98
197
  */
99
- createTaskSuperseding(params: import("./interface.js").InsertTaskParams, supersedesUuid: string): Promise<any>;
198
+ createTaskSuperseding(params: import("./interface.js").InsertTaskParams, supersedesUuid: string, cloudGuard?: any): Promise<any>;
100
199
  getTaskByUuid(uuid: any, userId: any): Promise<any>;
101
200
  getTaskByUuidOnly(uuid: any): Promise<any>;
102
201
  /**
@@ -109,7 +208,7 @@ export class D1Adapter {
109
208
  getTaskStatusByUuidOnly(uuid: string): Promise<{
110
209
  status: string;
111
210
  } | null>;
112
- updateTaskById(taskId: any, updates: any): Promise<any>;
211
+ updateTaskById(taskId: any, updates: any, cloudGuard?: any): Promise<any>;
113
212
  /**
114
213
  * 按 uuid 改一条 pending 任务(PUT /update-message、fire hook 的 renewTask)。
115
214
  *
@@ -119,7 +218,7 @@ export class D1Adapter {
119
218
  * ——用户以为改期生效了,实际什么都没留下。正文这类字段不受这道门约束:它们
120
219
  * 只影响以后的触发,收尾那边本来就不会覆盖(见 run-tick 的收尾守卫)。
121
220
  */
122
- updateTaskByUuid(uuid: any, userId: any, encryptedPayload: any, extraFields: any): Promise<{
221
+ updateTaskByUuid(uuid: any, userId: any, encryptedPayload: any, extraFields: any, cloudGuard?: any): Promise<{
123
222
  uuid: any;
124
223
  updated_at: string;
125
224
  }>;
@@ -160,7 +259,7 @@ export class D1Adapter {
160
259
  * @returns {Promise<boolean>} true = 领到了;false = 别人正拿着租约、同分组
161
260
  * 有任务正在跑、排期被改过、或行已不是 pending
162
261
  */
163
- claimTask(taskId: number, expectedNextSendAt: string, leaseUntil: string | Date, serializeGroup?: string | null): Promise<boolean>;
262
+ claimTask(taskId: number, expectedNextSendAt: string, leaseUntil: string | Date, serializeGroup?: string | null, cloudGuard?: any): Promise<boolean>;
164
263
  /**
165
264
  * 投递期间的租约续期(run-tick 的心跳用)。只在行仍是 pending 且确实持有
166
265
  * 租约(lease_until 非空)时生效——收尾把租约放掉之后,迟到的心跳不会把
@@ -170,7 +269,7 @@ export class D1Adapter {
170
269
  * @param {string|Date} leaseUntil - 新的租期末尾
171
270
  * @returns {Promise<boolean>} true = 续上了
172
271
  */
173
- renewTaskLease(taskId: number, leaseUntil: string | Date): Promise<boolean>;
272
+ renewTaskLease(taskId: number, leaseUntil: string | Date, cloudGuard?: any): Promise<boolean>;
174
273
  listTasks(userId: any, opts?: {}): Promise<{
175
274
  tasks: any;
176
275
  total: number;
@@ -241,7 +340,7 @@ export class D1Adapter {
241
340
  key?: string;
242
341
  keyPrefix?: string;
243
342
  updatedAt: number;
244
- }>, now?: number): Promise<{
343
+ }>, now?: number, cloudGuard?: any): Promise<{
245
344
  upserted: number;
246
345
  skipped: number;
247
346
  outcomes: boolean[];
@@ -377,7 +476,7 @@ export class D1Adapter {
377
476
  upsertLlmCredentials(userId: string, entries: Array<{
378
477
  credId: string;
379
478
  encryptedValue: string;
380
- }>): Promise<number>;
479
+ }>, cloudGuard?: any): Promise<number>;
381
480
  /**
382
481
  * 按 cred_id 批量读这个用户的凭据行(`encrypted_value` 是密文,解密在上
383
482
  * 层)。排程时的存在性检查和 fire 时的解析共用这一个口。
@@ -456,7 +555,7 @@ export class D1Adapter {
456
555
  total_messages?: number | null;
457
556
  payload: string;
458
557
  created_at: number;
459
- }>): Promise<number>;
558
+ }>, cloudGuard?: any): Promise<number>;
460
559
  /**
461
560
  * 把这一批标记为「Web Push 已发出」。发送失败的段不标——delivered_at 为
462
561
  * null 的行正是客户端最需要拉的那部分。
@@ -49,6 +49,7 @@ export type DbAdapter = {
49
49
  describeSchema?: () => Promise<{
50
50
  tables: Record<string, string[]>;
51
51
  indexes: string[];
52
+ triggers?: string[];
52
53
  }>;
53
54
  /**
54
55
  * Drop the scheduled_messages table (CASCADE).
@@ -53,15 +53,28 @@ export const SQLITE_ALL_INDEXES: {
53
53
  description: string;
54
54
  critical: boolean;
55
55
  }[];
56
+ export const CLOUD_DATA_TABLES_SQL: string[];
57
+ export const CLOUD_DATA_WORK_TABLES_SQL: string[];
58
+ export const CLOUD_DATA_WORK_INDEXES: {
59
+ name: string;
60
+ sql: string;
61
+ description: string;
62
+ critical: boolean;
63
+ }[];
64
+ export const CLOUD_DATA_DELETE_TRIGGERS: {
65
+ name: string;
66
+ sql: string;
67
+ }[];
56
68
  /**
57
69
  * 这一版代码跑起来需要的表 / 列 / 索引。
58
70
  *
59
71
  * 索引只列 critical 的那几个(uidx_uuid 之类):其余索引缺了只是慢,缺了它则
60
72
  * 是正确性问题。
61
73
  *
62
- * @type {{ tables: Record<string, string[]>, indexes: string[] }}
74
+ * @type {{ tables: Record<string, string[]>, indexes: string[], triggers: string[] }}
63
75
  */
64
76
  export const SQLITE_REQUIRED_SCHEMA: {
65
77
  tables: Record<string, string[]>;
66
78
  indexes: string[];
79
+ triggers: string[];
67
80
  };