@rei-standard/amsg-server 2.6.0-next.21 → 2.6.0-next.23

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
@@ -15,7 +15,46 @@ npm install @neondatabase/serverless
15
15
  npm install pg
16
16
  ```
17
17
 
18
- ## 快速使用
18
+ ## 两条部署线
19
+
20
+ | | 单用户线(推荐) | 多租户线 |
21
+ |---|---|---|
22
+ | 入口 | `createSingleUserCloudflareWorker` / `createSingleUserServer` | `createReiServer` |
23
+ | 数据库 | D1 | pg / neon |
24
+ | 一个部署 | 服务一个用户 | 服务多个租户(Blob 存租户配置 + token 鉴权) |
25
+ | 服务端收件箱(`GET /outbox` 补拉) | ✅ | ❌ |
26
+ | `client_state` 云端镜像 | ✅ | ❌ |
27
+ | 推送订阅、LLM 凭据、定时 / 周期任务 | ✅ | ✅ |
28
+
29
+ **新接入走单用户线。** 收件箱是这套 SDK 的到达保证:每条 payload 发出去之前先落一行 `message_outbox`,客户端上线 `GET /outbox?since=` 一条不少地补得回来。有了它,到了客户端不会弹通知的 payload(思考过程、工具请求、错误)就不必占用推送通道——这是[哪些 payload 会发推送](#哪些-payload-会发推送)那一节的前提,也是不去赌 iOS 订阅宽限期的唯一办法。
30
+
31
+ 多租户线继续维护,任务、推送、凭据这些照常能用——但它的 pg / neon 适配器还没有 `message_outbox` 和 `client_state`,收件箱相关的端点返回 501,不会弹通知的 payload 也只能照旧推送。
32
+
33
+ > **TODO**:给 pg / neon 适配器补 `message_outbox` 那组方法(D1 的实现见 `src/server/adapters/d1.js`,建表 SQL 见 `adapters/schema.sqlite.js`)。补上之前,多租户线省不掉那些不会弹通知的推送。
34
+
35
+ ## 快速使用(单用户线)
36
+
37
+ 一个 Cloudflare Worker 装完两个入口:`fetch` 收客户端请求,`scheduled` 跑 cron 投递。
38
+
39
+ ```js
40
+ import { createSingleUserCloudflareWorker, createD1Adapter } from '@rei-standard/amsg-server';
41
+
42
+ export default createSingleUserCloudflareWorker((env) => ({
43
+ db: createD1Adapter(env.DB),
44
+ masterKey: env.MASTER_KEY,
45
+ vapid: {
46
+ email: env.VAPID_EMAIL,
47
+ publicKey: env.VAPID_PUBLIC_KEY,
48
+ privateKey: env.VAPID_PRIVATE_KEY,
49
+ },
50
+ }));
51
+ ```
52
+
53
+ 建表、绑定、cron 配置和 fire-time hook 的完整走法见 [`examples/cloudflare-single-user`](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/server/examples/cloudflare-single-user/README.md)。
54
+
55
+ 客户端那侧还差一步:**应用启动时拉一次收件箱**。不会弹通知的内容(思考过程、工具请求、错误)只落收件箱、不发推送,不补拉就等于没有——做法见 [`@rei-standard/amsg-client` README 的「上线补一次收件箱」](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/client/README.md#上线补一次收件箱)。
56
+
57
+ ## 快速使用(多租户线)
19
58
 
20
59
  ```js
21
60
  import { createReiServer } from '@rei-standard/amsg-server';
@@ -54,9 +93,9 @@ const rei = await createReiServer({
54
93
 
55
94
  ## 关于 `messageType: 'instant'`
56
95
 
57
- > **两条 instant 路径,按各自特点选一条(都是正式支持路径):**
58
- > - **本端点的 `messageType: 'instant'`**(create task → process by UUID → delete task):任务先写进数据库再处理,投递不绑在请求连接上——客户端断开也没关系,任务行还在,能继续跑、能重试,想跑多久跑多久。适合**有数据库、需要长时间生成或保证消息零丢失**的场景。
59
- > - **[@rei-standard/amsg-instant](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/instant/README.md)**:纯 SSE 流 + Web Push backup,不需要数据库,适合无状态边缘运行时(如 Cloudflare Workers)。它的处理挂在响应连接上,客户端一断开就只剩平台给的那点宽限期把活干完(Deno Deploy 实测 ≈20-30s),所以适合**能快速跑完的短即时消息**。
96
+ > **两条 instant 路径:**
97
+ > - **本端点的 `messageType: 'instant'`**(create task → process by UUID → delete task):任务先写进数据库再处理,投递不绑在请求连接上——客户端断开也没关系,任务行还在,能继续跑、能重试,想跑多久跑多久。落进收件箱的那份客户端上线也补得回来。有数据库就走这条。
98
+ > - **[@rei-standard/amsg-instant](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/instant/README.md)**:纯 SSE 流 + Web Push backup,不需要数据库,跑得动无状态边缘运行时。处理挂在响应连接上,客户端一断开就只剩平台给的那点宽限期把活干完(Deno Deploy 实测 ≈20-30s);它也没有服务端收件箱,push 漏了的内容补不回来。这个包现在是维护态,新接入不从它起步。
60
99
 
61
100
  ## AI 接口 `apiUrl` 约束
62
101
 
@@ -142,9 +181,30 @@ const message = body.length <= remainingBytes ? body : body.slice(0, remainingBy
142
181
 
143
182
  用比 64 字符更长的 uuid(`scheduleTask` 允许传任意字符串)就自己再多留一点。
144
183
 
184
+ ### 哪些 payload 会发推送
185
+
186
+ 一条 payload 出门有两条腿:**落进 `message_outbox`**(到达的保证,客户端上线 `GET /outbox?since=` 补拉)和**发一条 Web Push**(及时性,当场叫人回来看)。收件箱那条腿每条 payload 都走,推送这条腿只留给「到了客户端会弹通知」的那些。
187
+
188
+ | payload | 落收件箱 | 发推送 |
189
+ | --- | --- | --- |
190
+ | `content` / `result` | ✅ | ✅ |
191
+ | `reasoning` / `tool_request` / `error` | ✅ | ❌ |
192
+ | 任意 kind + `notification: { show: false }` | ✅ | ❌ |
193
+ | 任意 kind + `notification: { show: 'always' \| 'when-hidden' }` | ✅ | ✅ |
194
+
195
+ 为什么这么分:订阅是按 `userVisibleOnly: true` 建的,每条 push 都欠用户一次可见反馈。`reasoning` / `tool_request` / `error` 在 Service Worker 那边是静默送给页面的,推过去不会有任何可见反馈,却要跟浏览器赊一次账——Firefox 对这类 push 有配额、超了退掉订阅,iOS 给新订阅几天宽限期、过后一条就吊销订阅,而且掉订阅是静默发生的,服务端只看得到后续推送返回 410。而这些内容在收件箱里一个字不少,客户端上线补拉就行(完整取舍见 `@rei-standard/amsg-sw` README 的「不展示通知的代价」一节)。
196
+
197
+ **想让某一条照样弹**,给它带上 `notification: { show: 'always' }`——判定读的是与 Service Worker 同一份规则(`@rei-standard/amsg-shared` 的 `notificationIntent`),宿主说了要弹,发送端就当它值得占用推送通道。逐条控制,不需要在服务端配开关。嫌打扰就配 `tag` 折叠加 `silent`,而不是不弹——只在用户看着页面时想安静的写 `silent: 'when-visible'`,静不静音由 Service Worker 收到时现算(发送端定不了这件事,它不知道用户此刻在不在前台)。`show: 'when-hidden'` 也照推(它到底弹不弹只有 Service Worker 当场知道),但那是给老部署留的兼容档,新代码在「一定弹」和「压根不推」里挑一个。
198
+
199
+ 跳过推送的那条不标 `delivered_at`,行留在收件箱里等客户端补收;这正是能跳过的前提。
200
+
201
+ **前提是这个部署有收件箱。** 内置适配器里只有 D1 实现了 `message_outbox`(见[两条部署线](#两条部署线))。落不进收件箱时——适配器没实现,或者这一批落行失败——推送是这条内容唯一的腿,所有 payload 照旧全推,包括不会弹通知的那些。宁可跟浏览器违约一次,也不能让内容凭空消失。
202
+
203
+ agentic 链路的 `onAfterSend` / `onFireSettled` 回执里,`sentCount` 是这批走完了几段,`pushedCount` 是其中真的占用了推送通道的有几条。`sentCount === total` 照旧表示整批都到位了。
204
+
145
205
  ### 装不下就切片:`multipart`
146
206
 
147
- 思考过程(reasoning)常常一条 push 装不下。装不下时服务端会把它切成分片逐条发,Service Worker 收齐后还原成原样再走正常派发。切多大一片、最多切几片、收齐前能等多久,都是接收端说了算——所以给 `installReiSW` 传了什么,就把同一份原样传给服务端:
207
+ 思考过程(reasoning)常常一条 push 装不下。真要把它推出去时(宿主给它配了 `notification.show`,或者这个部署没有收件箱),服务端会把它切成分片逐条发,Service Worker 收齐后还原成原样再走正常派发。切多大一片、最多切几片、收齐前能等多久,都是接收端说了算——所以给 `installReiSW` 传了什么,就把同一份原样传给服务端:
148
208
 
149
209
  ```js
150
210
  const multipart = { maxChunkBytes: 1800, maxChunks: 128, maxTotalBytes: 256_000, ttlMs: 60_000 };
@@ -168,6 +228,8 @@ createSingleUserCloudflareWorker((env) => ({ …, multipart })); // CF Worker
168
228
 
169
229
  ### 思考过程没送到时的可见性
170
230
 
231
+ > 这一节说的是**推送真的发出去过、但发挂了**的情况。有收件箱的部署上思考过程只落行、不推送(见[哪些 payload 会发推送](#哪些-payload-会发推送)),那条路上内容没丢,也就不会有下面这些信号。
232
+
171
233
  思考过程是正文之外的附赠内容:它没发出去不影响正文,任务照样算成功。这件事有三处看得见——
172
234
 
173
235
  - 定时任务的 tick 汇总多一个 `details.reasoningSkippedTasks`:`[{ taskId, reason }]`。这些任务同时计在 `successCount` 里。
@@ -324,14 +386,16 @@ hook 在 `pushPayloads` 里自己写了这几个字段的话会被库覆盖:
324
386
 
325
387
  | hook | 什么时候调 | 载荷 |
326
388
  |---|---|---|
327
- | `onAfterSend` | fire 的 pushPayloads 逐段发完,或中途发挂 | `{ task, sentCount, total, error, scratch, readState, writeState, emitResult }` |
328
- | `onFireSettled` | 一次 fire 收尾——只要 `onBeforeFire` 被调用过,什么结局都调一次 | `{ task, status, skipReason, sentCount, total, iterations, error, scratch, readState, writeState, emitResult }` |
389
+ | `onAfterSend` | fire 的 pushPayloads 逐段发完,或中途发挂 | `{ task, sentCount, pushedCount, total, error, scratch, readState, writeState, emitResult }` |
390
+ | `onFireSettled` | 一次 fire 收尾——只要 `onBeforeFire` 被调用过,什么结局都调一次 | `{ task, status, skipReason, sentCount, pushedCount, total, iterations, error, scratch, readState, writeState, emitResult }` |
329
391
  | `onStaleSkip` | 任务错过触发时刻超过 60 分钟、这一次(或这几次)不再补发 | `{ reason, action, metadata, recurrenceType, occurrenceMs, skippedCount, skippedOccurrences, skippedTruncated, nextSendAt, readState, writeState, emitResult }` |
330
392
 
331
393
  三个 hook 都自带 `readState` / `writeState` / `emitResult`,作用于当前用户,语义与 fire 级那套一致。`onStaleSkip` 尤其需要:服务停摆恢复后的第一跳里可能一次 fire 都没跑过,而那正是它要留痕迹的时候。
332
394
 
333
395
  `onAfterSend` 的 `scratch` 与本次 fire 的 `onBeforeFire` / `onLLMOutput` 是同一个引用——「这次生成了哪几段正文」之类的上下文直接从这里读,不用自建按任务分格的登记表。全部成功时 `error` 为 `null`;第 k 段失败时 `sentCount = k`、`error` 带原始错误,且在错误往上抛之前调用完。
334
396
 
397
+ `sentCount` 与 `pushedCount` 数的是两件事:`sentCount` 是这批走完了几段(只落收件箱、没占推送通道的那些也算走完),`pushedCount` 是其中真的发了 Web Push 的有几条。判整批跑完没有看 `sentCount === total`。
398
+
335
399
  `onFireSettled` 是「这次 fire 结束了」这一个信号,`status` 说明结局:
336
400
 
337
401
  | status | 什么时候 |
@@ -412,7 +476,9 @@ const { messageId, pushed } = await ctx.emitResult({
412
476
 
413
477
  **通知**默认弹(结果与聊天正文同待遇,其余 push 类型是静默送给页面)。标题正文在 `notification` 里自定义,字段与 SW 那套一致(`title` / `body` / `icon` / `tag` / …);不想弹就 `notification: { show: false }`。
414
478
 
415
- **返回值**里 `pushed` 是「这次推送有没有真的发出去」。`false` 只表示没能当场送达(订阅失效、推送服务抽风、payload 超过 4KB),行还在收件箱里等补收——所以这不算失败,`emitResult` 也不会因此抛错。
479
+ > 带 `show: false` 的结果不发推送、只落收件箱(见[哪些 payload 会发推送](#哪些-payload-会发推送)):订阅按 `userVisibleOnly: true` 建,收到 push 却不弹通知,Firefox 按配额退订,iOS 在订阅的宽限期过后直接吊销(完整取舍见 `@rei-standard/amsg-sw` README 的「不展示通知的代价」一节)。结果这条本来就有收件箱兜底,客户端上线补拉拿得到。
480
+
481
+ **返回值**里 `pushed` 是「这次推送有没有真的发出去」。两种情况会是 `false`:带 `notification: { show: false }` 的结果按策略压根不推(见[哪些 payload 会发推送](#哪些-payload-会发推送)),以及推了但没送出去(订阅失效、推送服务抽风、payload 超过 4KB)。两种都不算失败,行还在收件箱里等补收,`emitResult` 也不会因此抛错。
416
482
 
417
483
  **落行失败会抛**:收件箱是到达的保证,静默丢掉正是这个能力要修的病。适配器没有 `message_outbox`(自定义适配器)时同样抛,`code` 是 `OUTBOX_UNSUPPORTED`。
418
484
 
@@ -1293,6 +1293,13 @@ async function discardUndeliveredPushesForTask({ db, userId, taskUuid }) {
1293
1293
  await discardPushesFromOutbox({ db, userId, messageIds });
1294
1294
  }
1295
1295
 
1296
+ // src/server/lib/push-policy.js
1297
+ import { notificationIntent } from "@rei-standard/amsg-shared";
1298
+ function shouldSendPush(push, { outboxed }) {
1299
+ if (!outboxed) return true;
1300
+ return notificationIntent(push) !== "never";
1301
+ }
1302
+
1296
1303
  // src/server/lib/push-subscription-store.js
1297
1304
  function supportsPushSubscriptionStore(db) {
1298
1305
  return !!db && typeof db.getPushSubscription === "function" && typeof db.upsertPushSubscription === "function" && typeof db.deletePushSubscription === "function";
@@ -1379,7 +1386,7 @@ function createResultEmitter({
1379
1386
  await db.appendOutboxMessages(task.user_id, await toOutboxRows([push], userKey, nowFn()));
1380
1387
  let pushed;
1381
1388
  try {
1382
- pushed = await sendResultPush({ db, task, userKey, decryptedPayload, webpush, push });
1389
+ pushed = shouldSendPush(push, { outboxed: true }) ? await sendResultPush({ db, task, userKey, decryptedPayload, webpush, push }) : false;
1383
1390
  } catch (error) {
1384
1391
  await discardUndeliveredPushes({ db, userId: task.user_id, pushes: [push], sentIds: [] });
1385
1392
  throw error;
@@ -1826,7 +1833,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1826
1833
  now: new Date(nowFn()),
1827
1834
  scratch
1828
1835
  });
1829
- const progress = { sentCount: 0, total: 0, iterations: 0, skipReason: null, usage: null };
1836
+ const progress = { sentCount: 0, pushedCount: 0, total: 0, iterations: 0, skipReason: null, usage: null };
1830
1837
  let settledStatus = "failed";
1831
1838
  let settledError = null;
1832
1839
  try {
@@ -1863,6 +1870,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1863
1870
  status: settledStatus,
1864
1871
  skipReason: settledStatus === "skipped" ? progress.skipReason : null,
1865
1872
  sentCount: progress.sentCount,
1873
+ pushedCount: progress.pushedCount,
1866
1874
  total: progress.total,
1867
1875
  iterations: progress.iterations,
1868
1876
  error: settledError,
@@ -2085,6 +2093,7 @@ async function sendHookPushPayloads({
2085
2093
  }) {
2086
2094
  const total = pushPayloads.length;
2087
2095
  let sentCount = 0;
2096
+ let pushedCount = 0;
2088
2097
  progress.total = total;
2089
2098
  const afterSendBase = { task, total, scratch, readState, writeState, emitResult, usage: progress.usage };
2090
2099
  const sentIds = [];
@@ -2109,13 +2118,20 @@ async function sendHookPushPayloads({
2109
2118
  stampTaskIdentity(push, task, decryptedPayload, occurrenceMs);
2110
2119
  finalized.push(push);
2111
2120
  }
2112
- await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
2121
+ const outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
2122
+ const pushGate = { outboxed };
2123
+ const willPush = finalized.map((push) => shouldSendPush(push, pushGate));
2124
+ const lastPushIndex = willPush.lastIndexOf(true);
2113
2125
  for (let i = 0; i < total; i++) {
2114
- await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
2126
+ if (willPush[i]) {
2127
+ await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
2128
+ pushedCount++;
2129
+ progress.pushedCount = pushedCount;
2130
+ sentIds.push(finalized[i].messageId);
2131
+ }
2115
2132
  sentCount++;
2116
2133
  progress.sentCount = sentCount;
2117
- sentIds.push(finalized[i].messageId);
2118
- if (i < total - 1) await sleep(SLEEP_BETWEEN_MESSAGES_MS);
2134
+ if (willPush[i] && i < lastPushIndex) await sleep(SLEEP_BETWEEN_MESSAGES_MS);
2119
2135
  }
2120
2136
  } catch (error) {
2121
2137
  await markPushesDelivered({ db: ctx.db, userId: task.user_id, messageIds: sentIds });
@@ -2127,11 +2143,11 @@ async function sendHookPushPayloads({
2127
2143
  sentIds
2128
2144
  });
2129
2145
  }
2130
- await notifyAfterSend(ctx, { ...afterSendBase, sentCount, error });
2146
+ await notifyAfterSend(ctx, { ...afterSendBase, sentCount, pushedCount, error });
2131
2147
  throw error;
2132
2148
  }
2133
2149
  await markPushesDelivered({ db: ctx.db, userId: task.user_id, messageIds: sentIds });
2134
- await notifyAfterSend(ctx, { ...afterSendBase, sentCount, error: null });
2150
+ await notifyAfterSend(ctx, { ...afterSendBase, sentCount, pushedCount, error: null });
2135
2151
  return total;
2136
2152
  }
2137
2153
 
@@ -2334,12 +2350,14 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2334
2350
  contentPushes.push(contentPush);
2335
2351
  }
2336
2352
  const pushesToSend = reasoningPush ? [reasoningPush, ...contentPushes] : contentPushes;
2337
- await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: pushesToSend });
2353
+ const outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: pushesToSend });
2354
+ const pushGate = { outboxed };
2355
+ const contentToPush = contentPushes.filter((push) => shouldSendPush(push, pushGate));
2338
2356
  const sentIds = [];
2339
2357
  let cancelledMidBurst = false;
2340
2358
  let reasoningError;
2341
2359
  try {
2342
- if (reasoningPush) {
2360
+ if (reasoningPush && shouldSendPush(reasoningPush, pushGate)) {
2343
2361
  const reasoning2 = await deliverReasoningPush(ctx, pushSubscription, reasoningPush);
2344
2362
  if (reasoning2.shipped) {
2345
2363
  sentIds.push(reasoningPush.messageId);
@@ -2348,10 +2366,10 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2348
2366
  reasoningError = reasoning2.error;
2349
2367
  }
2350
2368
  }
2351
- for (let i = 0; i < contentPushes.length; i++) {
2352
- await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(contentPushes[i]));
2353
- sentIds.push(contentPushes[i].messageId);
2354
- if (i < contentPushes.length - 1) {
2369
+ for (let i = 0; i < contentToPush.length; i++) {
2370
+ await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(contentToPush[i]));
2371
+ sentIds.push(contentToPush[i].messageId);
2372
+ if (i < contentToPush.length - 1) {
2355
2373
  await sleepFor(ctx, SLEEP_BETWEEN_MESSAGES_MS2);
2356
2374
  }
2357
2375
  }
@@ -5195,7 +5213,7 @@ function createClientStateHandler(ctx) {
5195
5213
  }
5196
5214
 
5197
5215
  // src/server/lib/version.js
5198
- var SERVER_VERSION = true ? "2.6.0-next.21" : "0.0.0-dev";
5216
+ var SERVER_VERSION = true ? "2.6.0-next.23" : "0.0.0-dev";
5199
5217
 
5200
5218
  // src/server/handlers/capabilities.js
5201
5219
  var SERVER_FEATURES = Object.freeze([
@@ -1293,6 +1293,13 @@ async function discardUndeliveredPushesForTask({ db, userId, taskUuid }) {
1293
1293
  await discardPushesFromOutbox({ db, userId, messageIds });
1294
1294
  }
1295
1295
 
1296
+ // src/server/lib/push-policy.js
1297
+
1298
+ function shouldSendPush(push, { outboxed }) {
1299
+ if (!outboxed) return true;
1300
+ return _amsgshared.notificationIntent.call(void 0, push) !== "never";
1301
+ }
1302
+
1296
1303
  // src/server/lib/push-subscription-store.js
1297
1304
  function supportsPushSubscriptionStore(db) {
1298
1305
  return !!db && typeof db.getPushSubscription === "function" && typeof db.upsertPushSubscription === "function" && typeof db.deletePushSubscription === "function";
@@ -1379,7 +1386,7 @@ function createResultEmitter({
1379
1386
  await db.appendOutboxMessages(task.user_id, await toOutboxRows([push], userKey, nowFn()));
1380
1387
  let pushed;
1381
1388
  try {
1382
- pushed = await sendResultPush({ db, task, userKey, decryptedPayload, webpush, push });
1389
+ pushed = shouldSendPush(push, { outboxed: true }) ? await sendResultPush({ db, task, userKey, decryptedPayload, webpush, push }) : false;
1383
1390
  } catch (error) {
1384
1391
  await discardUndeliveredPushes({ db, userId: task.user_id, pushes: [push], sentIds: [] });
1385
1392
  throw error;
@@ -1826,7 +1833,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1826
1833
  now: new Date(nowFn()),
1827
1834
  scratch
1828
1835
  });
1829
- const progress = { sentCount: 0, total: 0, iterations: 0, skipReason: null, usage: null };
1836
+ const progress = { sentCount: 0, pushedCount: 0, total: 0, iterations: 0, skipReason: null, usage: null };
1830
1837
  let settledStatus = "failed";
1831
1838
  let settledError = null;
1832
1839
  try {
@@ -1863,6 +1870,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1863
1870
  status: settledStatus,
1864
1871
  skipReason: settledStatus === "skipped" ? progress.skipReason : null,
1865
1872
  sentCount: progress.sentCount,
1873
+ pushedCount: progress.pushedCount,
1866
1874
  total: progress.total,
1867
1875
  iterations: progress.iterations,
1868
1876
  error: settledError,
@@ -2085,6 +2093,7 @@ async function sendHookPushPayloads({
2085
2093
  }) {
2086
2094
  const total = pushPayloads.length;
2087
2095
  let sentCount = 0;
2096
+ let pushedCount = 0;
2088
2097
  progress.total = total;
2089
2098
  const afterSendBase = { task, total, scratch, readState, writeState, emitResult, usage: progress.usage };
2090
2099
  const sentIds = [];
@@ -2109,13 +2118,20 @@ async function sendHookPushPayloads({
2109
2118
  stampTaskIdentity(push, task, decryptedPayload, occurrenceMs);
2110
2119
  finalized.push(push);
2111
2120
  }
2112
- await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
2121
+ const outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
2122
+ const pushGate = { outboxed };
2123
+ const willPush = finalized.map((push) => shouldSendPush(push, pushGate));
2124
+ const lastPushIndex = willPush.lastIndexOf(true);
2113
2125
  for (let i = 0; i < total; i++) {
2114
- await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
2126
+ if (willPush[i]) {
2127
+ await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
2128
+ pushedCount++;
2129
+ progress.pushedCount = pushedCount;
2130
+ sentIds.push(finalized[i].messageId);
2131
+ }
2115
2132
  sentCount++;
2116
2133
  progress.sentCount = sentCount;
2117
- sentIds.push(finalized[i].messageId);
2118
- if (i < total - 1) await sleep(SLEEP_BETWEEN_MESSAGES_MS);
2134
+ if (willPush[i] && i < lastPushIndex) await sleep(SLEEP_BETWEEN_MESSAGES_MS);
2119
2135
  }
2120
2136
  } catch (error) {
2121
2137
  await markPushesDelivered({ db: ctx.db, userId: task.user_id, messageIds: sentIds });
@@ -2127,11 +2143,11 @@ async function sendHookPushPayloads({
2127
2143
  sentIds
2128
2144
  });
2129
2145
  }
2130
- await notifyAfterSend(ctx, { ...afterSendBase, sentCount, error });
2146
+ await notifyAfterSend(ctx, { ...afterSendBase, sentCount, pushedCount, error });
2131
2147
  throw error;
2132
2148
  }
2133
2149
  await markPushesDelivered({ db: ctx.db, userId: task.user_id, messageIds: sentIds });
2134
- await notifyAfterSend(ctx, { ...afterSendBase, sentCount, error: null });
2150
+ await notifyAfterSend(ctx, { ...afterSendBase, sentCount, pushedCount, error: null });
2135
2151
  return total;
2136
2152
  }
2137
2153
 
@@ -2334,12 +2350,14 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2334
2350
  contentPushes.push(contentPush);
2335
2351
  }
2336
2352
  const pushesToSend = reasoningPush ? [reasoningPush, ...contentPushes] : contentPushes;
2337
- await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: pushesToSend });
2353
+ const outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: pushesToSend });
2354
+ const pushGate = { outboxed };
2355
+ const contentToPush = contentPushes.filter((push) => shouldSendPush(push, pushGate));
2338
2356
  const sentIds = [];
2339
2357
  let cancelledMidBurst = false;
2340
2358
  let reasoningError;
2341
2359
  try {
2342
- if (reasoningPush) {
2360
+ if (reasoningPush && shouldSendPush(reasoningPush, pushGate)) {
2343
2361
  const reasoning2 = await deliverReasoningPush(ctx, pushSubscription, reasoningPush);
2344
2362
  if (reasoning2.shipped) {
2345
2363
  sentIds.push(reasoningPush.messageId);
@@ -2348,10 +2366,10 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2348
2366
  reasoningError = reasoning2.error;
2349
2367
  }
2350
2368
  }
2351
- for (let i = 0; i < contentPushes.length; i++) {
2352
- await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(contentPushes[i]));
2353
- sentIds.push(contentPushes[i].messageId);
2354
- if (i < contentPushes.length - 1) {
2369
+ for (let i = 0; i < contentToPush.length; i++) {
2370
+ await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(contentToPush[i]));
2371
+ sentIds.push(contentToPush[i].messageId);
2372
+ if (i < contentToPush.length - 1) {
2355
2373
  await sleepFor(ctx, SLEEP_BETWEEN_MESSAGES_MS2);
2356
2374
  }
2357
2375
  }
@@ -5195,7 +5213,7 @@ function createClientStateHandler(ctx) {
5195
5213
  }
5196
5214
 
5197
5215
  // src/server/lib/version.js
5198
- var SERVER_VERSION = true ? "2.6.0-next.21" : "0.0.0-dev";
5216
+ var SERVER_VERSION = true ? "2.6.0-next.23" : "0.0.0-dev";
5199
5217
 
5200
5218
  // src/server/handlers/capabilities.js
5201
5219
  var SERVER_FEATURES = Object.freeze([
@@ -26,7 +26,7 @@
26
26
 
27
27
 
28
28
 
29
- var _chunkQHVID3V2cjs = require('./chunk-QHVID3V2.cjs');
29
+ var _chunkBNZLICCIcjs = require('./chunk-BNZLICCI.cjs');
30
30
  require('./chunk-7NMQFTDJ.cjs');
31
31
 
32
32
 
@@ -56,4 +56,4 @@ require('./chunk-7NMQFTDJ.cjs');
56
56
 
57
57
 
58
58
 
59
- exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkQHVID3V2cjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkQHVID3V2cjs.MAX_PUSH_PAYLOAD_BYTES; exports.NonRetryableError = _chunkQHVID3V2cjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkQHVID3V2cjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkQHVID3V2cjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkQHVID3V2cjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkQHVID3V2cjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkQHVID3V2cjs.advanceOccurrence; exports.createD1Adapter = _chunkQHVID3V2cjs.createD1Adapter; exports.createSingleUserCloudflareWorker = _chunkQHVID3V2cjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkQHVID3V2cjs.createSingleUserServer; exports.createWebCryptoWebPush = _chunkQHVID3V2cjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkQHVID3V2cjs.decryptFromStorage; exports.decryptPayload = _chunkQHVID3V2cjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkQHVID3V2cjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkQHVID3V2cjs.encryptForStorage; exports.ensureSchema = _chunkQHVID3V2cjs.ensureSchema; exports.getSchemaVersion = _chunkQHVID3V2cjs.getSchemaVersion; exports.isNonRetryableError = _chunkQHVID3V2cjs.isNonRetryableError; exports.isValidTimeZoneId = _chunkQHVID3V2cjs.isValidTimeZoneId; exports.measurePushPayload = _chunkQHVID3V2cjs.measurePushPayload; exports.nextFutureOccurrence = _chunkQHVID3V2cjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkQHVID3V2cjs.planNextOccurrence; exports.readRequestBody = _chunkQHVID3V2cjs.readRequestBody; exports.runScheduledTick = _chunkQHVID3V2cjs.runScheduledTick; exports.runTask = _chunkQHVID3V2cjs.runTask; exports.summarizeErrorCause = _chunkQHVID3V2cjs.summarizeErrorCause;
59
+ exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkBNZLICCIcjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkBNZLICCIcjs.MAX_PUSH_PAYLOAD_BYTES; exports.NonRetryableError = _chunkBNZLICCIcjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkBNZLICCIcjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkBNZLICCIcjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkBNZLICCIcjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkBNZLICCIcjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkBNZLICCIcjs.advanceOccurrence; exports.createD1Adapter = _chunkBNZLICCIcjs.createD1Adapter; exports.createSingleUserCloudflareWorker = _chunkBNZLICCIcjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkBNZLICCIcjs.createSingleUserServer; exports.createWebCryptoWebPush = _chunkBNZLICCIcjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkBNZLICCIcjs.decryptFromStorage; exports.decryptPayload = _chunkBNZLICCIcjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkBNZLICCIcjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkBNZLICCIcjs.encryptForStorage; exports.ensureSchema = _chunkBNZLICCIcjs.ensureSchema; exports.getSchemaVersion = _chunkBNZLICCIcjs.getSchemaVersion; exports.isNonRetryableError = _chunkBNZLICCIcjs.isNonRetryableError; exports.isValidTimeZoneId = _chunkBNZLICCIcjs.isValidTimeZoneId; exports.measurePushPayload = _chunkBNZLICCIcjs.measurePushPayload; exports.nextFutureOccurrence = _chunkBNZLICCIcjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkBNZLICCIcjs.planNextOccurrence; exports.readRequestBody = _chunkBNZLICCIcjs.readRequestBody; exports.runScheduledTick = _chunkBNZLICCIcjs.runScheduledTick; exports.runTask = _chunkBNZLICCIcjs.runTask; exports.summarizeErrorCause = _chunkBNZLICCIcjs.summarizeErrorCause;
@@ -26,7 +26,7 @@ import {
26
26
  runScheduledTick,
27
27
  runTask,
28
28
  summarizeErrorCause
29
- } from "./chunk-KOJQVOYS.mjs";
29
+ } from "./chunk-3JEWYDM4.mjs";
30
30
  import "./chunk-GN44PST5.mjs";
31
31
  export {
32
32
  DEFAULT_MAX_REQUEST_BODY_BYTES,
package/dist/index.cjs CHANGED
@@ -71,7 +71,7 @@
71
71
 
72
72
 
73
73
 
74
- var _chunkQHVID3V2cjs = require('./chunk-QHVID3V2.cjs');
74
+ var _chunkBNZLICCIcjs = require('./chunk-BNZLICCI.cjs');
75
75
  require('./chunk-7NMQFTDJ.cjs');
76
76
 
77
77
  // src/server/adapters/factory.js
@@ -105,7 +105,7 @@ async function createAdapter(config) {
105
105
  // src/server/handlers/init-tenant.js
106
106
  function createInitTenantHandler(ctx) {
107
107
  async function POST(headers, body) {
108
- const initSecret = _chunkQHVID3V2cjs.getHeader.call(void 0, headers, "x-init-secret");
108
+ const initSecret = _chunkBNZLICCIcjs.getHeader.call(void 0, headers, "x-init-secret");
109
109
  if (ctx.tenant.initSecret && initSecret !== ctx.tenant.initSecret) {
110
110
  return {
111
111
  status: 401,
@@ -118,7 +118,7 @@ function createInitTenantHandler(ctx) {
118
118
  }
119
119
  };
120
120
  }
121
- const parsed = _chunkQHVID3V2cjs.parseJsonBody.call(void 0, body);
121
+ const parsed = _chunkBNZLICCIcjs.parseJsonBody.call(void 0, body);
122
122
  if (!parsed.ok) {
123
123
  return {
124
124
  status: 400,
@@ -132,7 +132,7 @@ function createInitTenantHandler(ctx) {
132
132
  const tenantId = payload.tenantId || void 0;
133
133
  const driver = payload.driver;
134
134
  const databaseUrl = payload.databaseUrl || payload.connectionString;
135
- if (tenantId && !_chunkQHVID3V2cjs.isValidUUIDv4.call(void 0, tenantId)) {
135
+ if (tenantId && !_chunkBNZLICCIcjs.isValidUUIDv4.call(void 0, tenantId)) {
136
136
  return {
137
137
  status: 400,
138
138
  body: {
@@ -252,7 +252,7 @@ function createSendNotificationsHandler(ctx) {
252
252
  }
253
253
  };
254
254
  }
255
- const data = await _chunkQHVID3V2cjs.runScheduledTick.call(void 0, { ...ctx, db, masterKey });
255
+ const data = await _chunkBNZLICCIcjs.runScheduledTick.call(void 0, { ...ctx, db, masterKey });
256
256
  return { status: 200, body: { success: true, data } };
257
257
  }
258
258
  return { POST };
@@ -274,16 +274,16 @@ function encryptConfig(config, kekBuffer) {
274
274
  const plaintext = Buffer.from(JSON.stringify(config), "utf8");
275
275
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
276
276
  const authTag = cipher.getAuthTag();
277
- return `v1.${_chunkQHVID3V2cjs.bytesToBase64Url.call(void 0, iv)}.${_chunkQHVID3V2cjs.bytesToBase64Url.call(void 0, authTag)}.${_chunkQHVID3V2cjs.bytesToBase64Url.call(void 0, ciphertext)}`;
277
+ return `v1.${_chunkBNZLICCIcjs.bytesToBase64Url.call(void 0, iv)}.${_chunkBNZLICCIcjs.bytesToBase64Url.call(void 0, authTag)}.${_chunkBNZLICCIcjs.bytesToBase64Url.call(void 0, ciphertext)}`;
278
278
  }
279
279
  function decryptConfig(encrypted, kekBuffer) {
280
280
  const parts = String(encrypted || "").split(".");
281
281
  if (parts.length !== 4 || parts[0] !== "v1") {
282
282
  throw new Error("INVALID_TENANT_CONFIG");
283
283
  }
284
- const iv = _chunkQHVID3V2cjs.base64UrlToBytes.call(void 0, parts[1]);
285
- const authTag = _chunkQHVID3V2cjs.base64UrlToBytes.call(void 0, parts[2]);
286
- const ciphertext = _chunkQHVID3V2cjs.base64UrlToBytes.call(void 0, parts[3]);
284
+ const iv = _chunkBNZLICCIcjs.base64UrlToBytes.call(void 0, parts[1]);
285
+ const authTag = _chunkBNZLICCIcjs.base64UrlToBytes.call(void 0, parts[2]);
286
+ const ciphertext = _chunkBNZLICCIcjs.base64UrlToBytes.call(void 0, parts[3]);
287
287
  const decipher = _crypto.createDecipheriv.call(void 0, "aes-256-gcm", kekBuffer, iv);
288
288
  decipher.setAuthTag(authTag);
289
289
  const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
@@ -351,7 +351,7 @@ function createTenantBlobStore(options) {
351
351
  // src/server/tenant/token.js
352
352
 
353
353
  function sign(input, secret) {
354
- return _chunkQHVID3V2cjs.bytesToBase64Url.call(void 0, _crypto.createHmac.call(void 0, "sha256", secret).update(input).digest());
354
+ return _chunkBNZLICCIcjs.bytesToBase64Url.call(void 0, _crypto.createHmac.call(void 0, "sha256", secret).update(input).digest());
355
355
  }
356
356
  function nowEpochSeconds() {
357
357
  return Math.floor(Date.now() / 1e3);
@@ -367,8 +367,8 @@ function createTenantToken(params, secret) {
367
367
  v: 1
368
368
  };
369
369
  const header = { alg: "HS256", typ: "JWT" };
370
- const encodedHeader = _chunkQHVID3V2cjs.bytesToBase64Url.call(void 0, _chunkQHVID3V2cjs.utf8.call(void 0, JSON.stringify(header)));
371
- const encodedPayload = _chunkQHVID3V2cjs.bytesToBase64Url.call(void 0, _chunkQHVID3V2cjs.utf8.call(void 0, JSON.stringify(payload)));
370
+ const encodedHeader = _chunkBNZLICCIcjs.bytesToBase64Url.call(void 0, _chunkBNZLICCIcjs.utf8.call(void 0, JSON.stringify(header)));
371
+ const encodedPayload = _chunkBNZLICCIcjs.bytesToBase64Url.call(void 0, _chunkBNZLICCIcjs.utf8.call(void 0, JSON.stringify(payload)));
372
372
  const signingInput = `${encodedHeader}.${encodedPayload}`;
373
373
  const signature = sign(signingInput, secret);
374
374
  return `${signingInput}.${signature}`;
@@ -387,17 +387,17 @@ function verifyTenantToken(token, secret, options = {}) {
387
387
  let receivedBytes;
388
388
  let expectedBytes;
389
389
  try {
390
- receivedBytes = _chunkQHVID3V2cjs.base64UrlToBytes.call(void 0, receivedSignature);
391
- expectedBytes = _chunkQHVID3V2cjs.base64UrlToBytes.call(void 0, expectedSignature);
390
+ receivedBytes = _chunkBNZLICCIcjs.base64UrlToBytes.call(void 0, receivedSignature);
391
+ expectedBytes = _chunkBNZLICCIcjs.base64UrlToBytes.call(void 0, expectedSignature);
392
392
  } catch (e) {
393
393
  throw new Error("INVALID_TENANT_AUTH");
394
394
  }
395
- if (!_chunkQHVID3V2cjs.timingSafeEqualBytes.call(void 0, receivedBytes, expectedBytes)) {
395
+ if (!_chunkBNZLICCIcjs.timingSafeEqualBytes.call(void 0, receivedBytes, expectedBytes)) {
396
396
  throw new Error("INVALID_TENANT_AUTH");
397
397
  }
398
398
  let payload;
399
399
  try {
400
- payload = JSON.parse(_chunkQHVID3V2cjs.utf8Decode.call(void 0, _chunkQHVID3V2cjs.base64UrlToBytes.call(void 0, encodedPayload)));
400
+ payload = JSON.parse(_chunkBNZLICCIcjs.utf8Decode.call(void 0, _chunkBNZLICCIcjs.base64UrlToBytes.call(void 0, encodedPayload)));
401
401
  } catch (e2) {
402
402
  throw new Error("INVALID_TENANT_AUTH");
403
403
  }
@@ -621,15 +621,15 @@ async function createReiServer(config) {
621
621
  return {
622
622
  handlers: {
623
623
  initTenant: createInitTenantHandler(ctx),
624
- getUserKey: _chunkQHVID3V2cjs.createGetUserKeyHandler.call(void 0, ctx),
625
- scheduleMessage: _chunkQHVID3V2cjs.createScheduleMessageHandler.call(void 0, ctx),
624
+ getUserKey: _chunkBNZLICCIcjs.createGetUserKeyHandler.call(void 0, ctx),
625
+ scheduleMessage: _chunkBNZLICCIcjs.createScheduleMessageHandler.call(void 0, ctx),
626
626
  sendNotifications: createSendNotificationsHandler(ctx),
627
- updateMessage: _chunkQHVID3V2cjs.createUpdateMessageHandler.call(void 0, ctx),
628
- cancelMessage: _chunkQHVID3V2cjs.createCancelMessageHandler.call(void 0, ctx),
629
- messages: _chunkQHVID3V2cjs.createMessagesHandler.call(void 0, ctx),
630
- getMessage: _chunkQHVID3V2cjs.createGetMessageHandler.call(void 0, ctx),
631
- pushSubscription: _chunkQHVID3V2cjs.createPushSubscriptionHandler.call(void 0, ctx),
632
- llmCredentials: _chunkQHVID3V2cjs.createLlmCredentialsHandler.call(void 0, ctx)
627
+ updateMessage: _chunkBNZLICCIcjs.createUpdateMessageHandler.call(void 0, ctx),
628
+ cancelMessage: _chunkBNZLICCIcjs.createCancelMessageHandler.call(void 0, ctx),
629
+ messages: _chunkBNZLICCIcjs.createMessagesHandler.call(void 0, ctx),
630
+ getMessage: _chunkBNZLICCIcjs.createGetMessageHandler.call(void 0, ctx),
631
+ pushSubscription: _chunkBNZLICCIcjs.createPushSubscriptionHandler.call(void 0, ctx),
632
+ llmCredentials: _chunkBNZLICCIcjs.createLlmCredentialsHandler.call(void 0, ctx)
633
633
  }
634
634
  };
635
635
  }
@@ -695,4 +695,4 @@ async function createReiServer(config) {
695
695
 
696
696
 
697
697
 
698
- exports.CORS_ALLOW_HEADERS = _chunkQHVID3V2cjs.CORS_ALLOW_HEADERS; exports.CORS_ALLOW_METHODS = _chunkQHVID3V2cjs.CORS_ALLOW_METHODS; exports.CRED_ID_MAX_LENGTH = _chunkQHVID3V2cjs.CRED_ID_MAX_LENGTH; exports.CRED_PUT_BATCH_MAX = _chunkQHVID3V2cjs.CRED_PUT_BATCH_MAX; exports.CRED_REFS_MAX_ENTRIES = _chunkQHVID3V2cjs.CRED_REFS_MAX_ENTRIES; exports.CRED_ROWS_PER_USER_MAX = _chunkQHVID3V2cjs.CRED_ROWS_PER_USER_MAX; exports.DEFAULT_CLAIM_LEASE_MS = _chunkQHVID3V2cjs.DEFAULT_CLAIM_LEASE_MS; exports.DEFAULT_HEARTBEAT_LEASE_TTL_MS = _chunkQHVID3V2cjs.DEFAULT_HEARTBEAT_LEASE_TTL_MS; exports.DEFAULT_LEASE_HEARTBEAT_MS = _chunkQHVID3V2cjs.DEFAULT_LEASE_HEARTBEAT_MS; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkQHVID3V2cjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE = _chunkQHVID3V2cjs.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE; exports.DEFAULT_MAX_TOOL_ITERATIONS = _chunkQHVID3V2cjs.DEFAULT_MAX_TOOL_ITERATIONS; exports.DEFAULT_TOTAL_TIMEOUT_MS = _chunkQHVID3V2cjs.DEFAULT_TOTAL_TIMEOUT_MS; exports.DeploymentConfigError = _chunkQHVID3V2cjs.DeploymentConfigError; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkQHVID3V2cjs.MAX_PUSH_PAYLOAD_BYTES; exports.MAX_TASK_PAYLOAD_BYTES = _chunkQHVID3V2cjs.MAX_TASK_PAYLOAD_BYTES; exports.MIN_SCHEDULE_LEAD_MS = _chunkQHVID3V2cjs.MIN_SCHEDULE_LEAD_MS; exports.NonRetryableError = _chunkQHVID3V2cjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkQHVID3V2cjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkQHVID3V2cjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkQHVID3V2cjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkQHVID3V2cjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkQHVID3V2cjs.advanceOccurrence; exports.createAdapter = createAdapter; exports.createD1Adapter = _chunkQHVID3V2cjs.createD1Adapter; exports.createReiServer = createReiServer; exports.createSingleUserCloudflareWorker = _chunkQHVID3V2cjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkQHVID3V2cjs.createSingleUserServer; exports.createTenantToken = createTenantToken; exports.createWebCryptoWebPush = _chunkQHVID3V2cjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkQHVID3V2cjs.decryptFromStorage; exports.decryptPayload = _chunkQHVID3V2cjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkQHVID3V2cjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkQHVID3V2cjs.encryptForStorage; exports.ensureSchema = _chunkQHVID3V2cjs.ensureSchema; exports.getSchemaVersion = _chunkQHVID3V2cjs.getSchemaVersion; exports.hasChatCredRef = _chunkQHVID3V2cjs.hasChatCredRef; exports.isNonRetryableError = _chunkQHVID3V2cjs.isNonRetryableError; exports.isValidCredId = _chunkQHVID3V2cjs.isValidCredId; exports.isValidISO8601 = _chunkQHVID3V2cjs.isValidISO8601; exports.isValidTimeZoneId = _chunkQHVID3V2cjs.isValidTimeZoneId; exports.isValidUUID = _chunkQHVID3V2cjs.isValidUUID; exports.isValidUUIDv4 = _chunkQHVID3V2cjs.isValidUUIDv4; exports.isValidUrl = _chunkQHVID3V2cjs.isValidUrl; exports.measurePushPayload = _chunkQHVID3V2cjs.measurePushPayload; exports.nextFutureOccurrence = _chunkQHVID3V2cjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkQHVID3V2cjs.planNextOccurrence; exports.readRequestBody = _chunkQHVID3V2cjs.readRequestBody; exports.resolveLlmCredential = _chunkQHVID3V2cjs.resolveLlmCredential; exports.runScheduledTick = _chunkQHVID3V2cjs.runScheduledTick; exports.runTask = _chunkQHVID3V2cjs.runTask; exports.sanitizeErrorSummary = _chunkQHVID3V2cjs.sanitizeErrorSummary; exports.summarizeErrorCause = _chunkQHVID3V2cjs.summarizeErrorCause; exports.supportsLlmCredentialsStore = _chunkQHVID3V2cjs.supportsLlmCredentialsStore; exports.validateAvatarUrl = _chunkQHVID3V2cjs.validateAvatarUrl; exports.validateCredRefs = _chunkQHVID3V2cjs.validateCredRefs; exports.validateCredValue = _chunkQHVID3V2cjs.validateCredValue; exports.validateLlmMessagesArray = _chunkQHVID3V2cjs.validateLlmMessagesArray; exports.validateScheduleMessagePayload = _chunkQHVID3V2cjs.validateScheduleMessagePayload; exports.validateSplitPattern = _chunkQHVID3V2cjs.validateSplitPattern; exports.verifyTenantToken = verifyTenantToken;
698
+ exports.CORS_ALLOW_HEADERS = _chunkBNZLICCIcjs.CORS_ALLOW_HEADERS; exports.CORS_ALLOW_METHODS = _chunkBNZLICCIcjs.CORS_ALLOW_METHODS; exports.CRED_ID_MAX_LENGTH = _chunkBNZLICCIcjs.CRED_ID_MAX_LENGTH; exports.CRED_PUT_BATCH_MAX = _chunkBNZLICCIcjs.CRED_PUT_BATCH_MAX; exports.CRED_REFS_MAX_ENTRIES = _chunkBNZLICCIcjs.CRED_REFS_MAX_ENTRIES; exports.CRED_ROWS_PER_USER_MAX = _chunkBNZLICCIcjs.CRED_ROWS_PER_USER_MAX; exports.DEFAULT_CLAIM_LEASE_MS = _chunkBNZLICCIcjs.DEFAULT_CLAIM_LEASE_MS; exports.DEFAULT_HEARTBEAT_LEASE_TTL_MS = _chunkBNZLICCIcjs.DEFAULT_HEARTBEAT_LEASE_TTL_MS; exports.DEFAULT_LEASE_HEARTBEAT_MS = _chunkBNZLICCIcjs.DEFAULT_LEASE_HEARTBEAT_MS; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkBNZLICCIcjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE = _chunkBNZLICCIcjs.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE; exports.DEFAULT_MAX_TOOL_ITERATIONS = _chunkBNZLICCIcjs.DEFAULT_MAX_TOOL_ITERATIONS; exports.DEFAULT_TOTAL_TIMEOUT_MS = _chunkBNZLICCIcjs.DEFAULT_TOTAL_TIMEOUT_MS; exports.DeploymentConfigError = _chunkBNZLICCIcjs.DeploymentConfigError; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkBNZLICCIcjs.MAX_PUSH_PAYLOAD_BYTES; exports.MAX_TASK_PAYLOAD_BYTES = _chunkBNZLICCIcjs.MAX_TASK_PAYLOAD_BYTES; exports.MIN_SCHEDULE_LEAD_MS = _chunkBNZLICCIcjs.MIN_SCHEDULE_LEAD_MS; exports.NonRetryableError = _chunkBNZLICCIcjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkBNZLICCIcjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkBNZLICCIcjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkBNZLICCIcjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkBNZLICCIcjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkBNZLICCIcjs.advanceOccurrence; exports.createAdapter = createAdapter; exports.createD1Adapter = _chunkBNZLICCIcjs.createD1Adapter; exports.createReiServer = createReiServer; exports.createSingleUserCloudflareWorker = _chunkBNZLICCIcjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkBNZLICCIcjs.createSingleUserServer; exports.createTenantToken = createTenantToken; exports.createWebCryptoWebPush = _chunkBNZLICCIcjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkBNZLICCIcjs.decryptFromStorage; exports.decryptPayload = _chunkBNZLICCIcjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkBNZLICCIcjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkBNZLICCIcjs.encryptForStorage; exports.ensureSchema = _chunkBNZLICCIcjs.ensureSchema; exports.getSchemaVersion = _chunkBNZLICCIcjs.getSchemaVersion; exports.hasChatCredRef = _chunkBNZLICCIcjs.hasChatCredRef; exports.isNonRetryableError = _chunkBNZLICCIcjs.isNonRetryableError; exports.isValidCredId = _chunkBNZLICCIcjs.isValidCredId; exports.isValidISO8601 = _chunkBNZLICCIcjs.isValidISO8601; exports.isValidTimeZoneId = _chunkBNZLICCIcjs.isValidTimeZoneId; exports.isValidUUID = _chunkBNZLICCIcjs.isValidUUID; exports.isValidUUIDv4 = _chunkBNZLICCIcjs.isValidUUIDv4; exports.isValidUrl = _chunkBNZLICCIcjs.isValidUrl; exports.measurePushPayload = _chunkBNZLICCIcjs.measurePushPayload; exports.nextFutureOccurrence = _chunkBNZLICCIcjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkBNZLICCIcjs.planNextOccurrence; exports.readRequestBody = _chunkBNZLICCIcjs.readRequestBody; exports.resolveLlmCredential = _chunkBNZLICCIcjs.resolveLlmCredential; exports.runScheduledTick = _chunkBNZLICCIcjs.runScheduledTick; exports.runTask = _chunkBNZLICCIcjs.runTask; exports.sanitizeErrorSummary = _chunkBNZLICCIcjs.sanitizeErrorSummary; exports.summarizeErrorCause = _chunkBNZLICCIcjs.summarizeErrorCause; exports.supportsLlmCredentialsStore = _chunkBNZLICCIcjs.supportsLlmCredentialsStore; exports.validateAvatarUrl = _chunkBNZLICCIcjs.validateAvatarUrl; exports.validateCredRefs = _chunkBNZLICCIcjs.validateCredRefs; exports.validateCredValue = _chunkBNZLICCIcjs.validateCredValue; exports.validateLlmMessagesArray = _chunkBNZLICCIcjs.validateLlmMessagesArray; exports.validateScheduleMessagePayload = _chunkBNZLICCIcjs.validateScheduleMessagePayload; exports.validateSplitPattern = _chunkBNZLICCIcjs.validateSplitPattern; exports.verifyTenantToken = verifyTenantToken;
package/dist/index.mjs CHANGED
@@ -71,7 +71,7 @@ import {
71
71
  validateLlmMessagesArray,
72
72
  validateScheduleMessagePayload,
73
73
  validateSplitPattern
74
- } from "./chunk-KOJQVOYS.mjs";
74
+ } from "./chunk-3JEWYDM4.mjs";
75
75
  import "./chunk-GN44PST5.mjs";
76
76
 
77
77
  // src/server/adapters/factory.js
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 这条 push 要不要真的发出去。
3
+ *
4
+ * @param {Record<string, unknown>} push - 定稿后的 push 对象
5
+ * @param {Object} options
6
+ * @param {boolean} options.outboxed - 这一批是否真的落进了 outbox
7
+ * @returns {boolean}
8
+ */
9
+ export function shouldSendPush(push: Record<string, unknown>, { outboxed }: {
10
+ outboxed: boolean;
11
+ }): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rei-standard/amsg-server",
3
- "version": "2.6.0-next.21",
3
+ "version": "2.6.0-next.23",
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",
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@netlify/blobs": "^8.1.0",
42
- "@rei-standard/amsg-shared": "^0.4.0-next.6",
42
+ "@rei-standard/amsg-shared": "^0.4.0-next.8",
43
43
  "web-push": "^3.6.7"
44
44
  },
45
45
  "peerDependencies": {