@rei-standard/amsg-server 2.6.0-next.31 → 2.6.0-next.32

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
@@ -940,3 +940,30 @@ VERCEL_PROTECTION_BYPASS=YOUR_BYPASS_KEY
940
940
  - [SW 包 README](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/sw/README.md)
941
941
  - [API 技术规范](https://github.com/Tosd0/ReiStandard/blob/main/standards/active-messaging-api.md)
942
942
  - [Service Worker 规范](https://github.com/Tosd0/ReiStandard/blob/main/standards/service-worker-specification.md)
943
+
944
+
945
+ ## 取消正在执行的生成与工具
946
+
947
+ 任务被 `DELETE /cancel-message` 取消或被新任务顶替后,租约心跳发现任务已经失效,会中断正在等待的模型请求,阻止新的模型轮次、工具阶段和推送。`leaseHeartbeatMs` 默认仍为 30000;需要及时停止的交互应用可配置为 1000(每个正在执行的任务每秒续租一次)。这是跨请求的数据库检测,延迟取决于心跳和数据库响应,不承诺瞬时中断。自定义适配器需要支持 `claimTask` / `renewTaskLease`;关掉心跳时也关掉了这条主动检测路径。
948
+
949
+ `onBeforeFire`、`onLLMOutput`、`executeToolCalls` 的 context 以及 `onFireSettled` 回执新增:
950
+
951
+ - `signal: AbortSignal`:传给工具内部的 `fetch`,与工具自己的超时信号合并。
952
+ - `isCancelled(): boolean`:当前是否已收到取消信号。
953
+ - `throwIfCancelled(): void`:已取消时抛出 `code: 'TASK_CANCELLED'` 的错误。每个副作用开始前检查,工具 catch 中也要先调用它,以免取消被转成普通工具失败后继续执行。
954
+
955
+ ```js
956
+ async function executeToolCalls(calls, ctx) {
957
+ const results = [];
958
+ for (const call of calls) {
959
+ ctx.throwIfCancelled();
960
+ const response = await fetch(toolUrl(call), { signal: ctx.signal });
961
+ results.push({ tool_call_id: call.id, role: 'tool', content: await response.text() });
962
+ }
963
+ return results;
964
+ }
965
+ ```
966
+
967
+ 取消收尾使用 `onFireSettled({ status: 'cancelled', willRetry: false, error, ... })`,不是生成失败。应用应在这里释放资源、结算已发生的用量,避免发出失败提示或把未送达内容记为已回复。取消时已经开始写入的 outbox 批次会在写完后检查信号并撤掉未投递部分;已经发到客户端的消息仍由客户端处理。应用需要记录停止的任务身份,拦住迟到推送、补收以及尚未显示的本地内容。已完成的外部副作用无法撤销;不支持 AbortSignal 的工具也需要自己在执行步骤之间检查取消。
968
+
969
+ 执行阶段的 `ctx.writeState`、`scheduleTask`、`cancelTask`、`renewTask` 和 `emitResult` 会拒绝取消后新发起的操作。`onFireSettled` 的 `info.writeState` 特意仍可用,供宿主释放锁、保存账单等收尾;它不能用于继续生成阶段的业务动作。已经开始的数据库写入不支持回滚,宿主仍需处理并发状态版本。
@@ -1707,6 +1707,17 @@ function firstPositiveNumber(values, fallback) {
1707
1707
  }
1708
1708
  async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1709
1709
  const hooks = ctx.hooks;
1710
+ const signal = ctx.signal || new AbortController().signal;
1711
+ const isCancelled = () => signal.aborted || ctx.isTaskCancelled?.() === true;
1712
+ const throwIfCancelled = () => {
1713
+ if (!isCancelled()) return;
1714
+ if (isTaskCancelledError(signal.reason)) throw signal.reason;
1715
+ const error = new Error("Task was cancelled or superseded");
1716
+ error.code = "TASK_CANCELLED";
1717
+ throw error;
1718
+ };
1719
+ const cancellation = { signal, isCancelled, throwIfCancelled };
1720
+ ctx = { ...ctx, ...cancellation };
1710
1721
  if (typeof hooks.onLLMOutput !== "function") {
1711
1722
  throw new DeploymentConfigError(
1712
1723
  "AGENTIC_CONFIG_ERROR: hooks.onBeforeFire requires hooks.onLLMOutput to classify LLM rounds",
@@ -1715,13 +1726,17 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1715
1726
  }
1716
1727
  const nowFn = typeof ctx._agenticNow === "function" ? ctx._agenticNow : Date.now;
1717
1728
  const sleep = typeof ctx._agenticSleep === "function" ? ctx._agenticSleep : defaultSleep;
1718
- const { readState, writeState } = createStateAccessors({
1729
+ const { readState, writeState: writeSettledState } = createStateAccessors({
1719
1730
  db: ctx.db,
1720
1731
  userId: task.user_id,
1721
1732
  userKey,
1722
1733
  maxStateValueBytes: ctx.maxStateValueBytes,
1723
1734
  now: nowFn
1724
1735
  });
1736
+ const writeState = async (namespace, entries) => {
1737
+ throwIfCancelled();
1738
+ return writeSettledState(namespace, entries);
1739
+ };
1725
1740
  const sessionId = task.id != null ? `sess_task_${task.id}${occurrenceSuffix(task)}` : `sess_${randomUUID()}`;
1726
1741
  const messageIdBase = task.id != null ? `msg_task_${task.id}${occurrenceSuffix(task)}` : `msg_${randomUUID()}`;
1727
1742
  const occurrenceMs = occurrenceMsOf(task);
@@ -1737,7 +1752,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1737
1752
  now: nowFn,
1738
1753
  // run-tick 在投递 ctx 上挂的取消信号(与 guardWebpushWithLease 读的是同一
1739
1754
  // 个租约状态),emitResult 不发推送的那条路要靠它拦下已取消任务的落行。
1740
- isCancelled: typeof ctx.isTaskCancelled === "function" ? ctx.isTaskCancelled : null
1755
+ isCancelled
1741
1756
  });
1742
1757
  const maxScheduledTasksPerFire = Number.isInteger(ctx.maxScheduledTasksPerFire) && ctx.maxScheduledTasksPerFire >= 0 ? ctx.maxScheduledTasksPerFire : DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE;
1743
1758
  let scheduledTaskCount = 0;
@@ -1754,6 +1769,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1754
1769
  }
1755
1770
  }
1756
1771
  const scheduleTask = async (options) => {
1772
+ throwIfCancelled();
1757
1773
  if (!options || typeof options !== "object" || Array.isArray(options)) {
1758
1774
  throw new TypeError("scheduleTask(options) \u9700\u8981\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u81F3\u5C11\u5305\u542B { firstSendTime }");
1759
1775
  }
@@ -1874,6 +1890,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1874
1890
  }
1875
1891
  scheduledTaskCount++;
1876
1892
  const encryptedPayload = await encryptForStorage(serializedTaskData, userKey);
1893
+ throwIfCancelled();
1877
1894
  let created;
1878
1895
  try {
1879
1896
  created = await ctx.db.createTask({
@@ -1908,6 +1925,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1908
1925
  };
1909
1926
  };
1910
1927
  const cancelTask = async (uuid) => {
1928
+ throwIfCancelled();
1911
1929
  if (typeof uuid !== "string" || !uuid.trim()) {
1912
1930
  throw new TypeError("cancelTask(uuid) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
1913
1931
  }
@@ -1922,6 +1940,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1922
1940
  { code: "AGENTIC_CANCEL_UNSUPPORTED" }
1923
1941
  );
1924
1942
  }
1943
+ throwIfCancelled();
1925
1944
  const cancelled = await ctx.db.deleteTaskByUuid(uuid, task.user_id);
1926
1945
  if (cancelled) {
1927
1946
  await discardUndeliveredPushesForTask({ db: ctx.db, userId: task.user_id, taskUuid: uuid });
@@ -1929,6 +1948,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1929
1948
  return { cancelled: !!cancelled };
1930
1949
  };
1931
1950
  const renewTask = async (uuid, nextSendAt) => {
1951
+ throwIfCancelled();
1932
1952
  if (typeof uuid !== "string" || !uuid.trim()) {
1933
1953
  throw new TypeError("renewTask(uuid, nextSendAt) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
1934
1954
  }
@@ -1959,6 +1979,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1959
1979
  const payload = JSON.parse(await decryptFromStorage(row.encrypted_payload, userKey));
1960
1980
  const nextSendAtIso = sendAt.toISOString();
1961
1981
  const encrypted = await encryptForStorage(JSON.stringify({ ...payload, firstSendTime: nextSendAtIso }), userKey);
1982
+ throwIfCancelled();
1962
1983
  const updated = await ctx.db.updateTaskByUuid(uuid, task.user_id, encrypted, {
1963
1984
  next_send_at: nextSendAtIso,
1964
1985
  retry_count: 0,
@@ -1979,6 +2000,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1979
2000
  };
1980
2001
  const scratch = {};
1981
2002
  const fireCtx = Object.freeze({
2003
+ ...cancellation,
1982
2004
  task: buildHookTask(task, decryptedPayload),
1983
2005
  userId: task.user_id,
1984
2006
  readState,
@@ -2027,16 +2049,26 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
2027
2049
  messageIdBase,
2028
2050
  occurrenceMs
2029
2051
  });
2052
+ throwIfCancelled();
2030
2053
  settledStatus = !outcome.handled ? "not-handled" : outcome.result.status === "skipped" ? "skipped" : "sent";
2031
2054
  return outcome;
2032
2055
  } catch (error) {
2056
+ if (isCancelled() && !isTaskCancelledError(error)) {
2057
+ try {
2058
+ throwIfCancelled();
2059
+ } catch (cancelled) {
2060
+ error = cancelled;
2061
+ }
2062
+ }
2063
+ if (isTaskCancelledError(error)) settledStatus = "cancelled";
2033
2064
  settledError = error;
2034
2065
  throw error;
2035
2066
  } finally {
2036
2067
  await notifyFireSettled(ctx, {
2037
2068
  task,
2069
+ ...cancellation,
2038
2070
  status: settledStatus,
2039
- ...settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
2071
+ ...settledStatus === "cancelled" ? { willRetry: false, failureStage: null } : settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
2040
2072
  skipReason: settledStatus === "skipped" ? progress.skipReason : null,
2041
2073
  sentCount: progress.sentCount,
2042
2074
  pushedCount: progress.pushedCount,
@@ -2060,7 +2092,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
2060
2092
  outboxed: progress.outboxed,
2061
2093
  scratch,
2062
2094
  readState,
2063
- writeState,
2095
+ writeState: writeSettledState,
2064
2096
  emitResult
2065
2097
  });
2066
2098
  }
@@ -2087,7 +2119,9 @@ async function runFireChain({
2087
2119
  messageIdBase,
2088
2120
  occurrenceMs
2089
2121
  }) {
2122
+ ctx.throwIfCancelled();
2090
2123
  const before = await hooks.onBeforeFire(fireCtx);
2124
+ ctx.throwIfCancelled();
2091
2125
  if (before == null) return { handled: false };
2092
2126
  if (typeof before === "object" && before.skip === true) {
2093
2127
  progress.skipReason = "before-fire";
@@ -2111,6 +2145,7 @@ async function runFireChain({
2111
2145
  decryptedPayload
2112
2146
  });
2113
2147
  for (let iteration = 0; iteration < maxToolIterations; iteration++) {
2148
+ ctx.throwIfCancelled();
2114
2149
  if (nowFn() >= deadline) {
2115
2150
  throw new Error(`AGENTIC_TOTAL_TIMEOUT: fire chain exceeded ${totalTimeoutMs}ms after ${iteration} LLM round(s)`);
2116
2151
  }
@@ -2124,13 +2159,17 @@ async function runFireChain({
2124
2159
  messages,
2125
2160
  ...normalized.tools ? { tools: normalized.tools, toolChoice: normalized.toolChoice } : {}
2126
2161
  },
2127
- { requireContent: false, timeoutMs: roundTimeoutMs }
2162
+ { requireContent: false, timeoutMs: roundTimeoutMs, signal: ctx.signal }
2128
2163
  );
2129
2164
  const assistantMessage = extractAssistantMessage(llmResponse);
2130
2165
  messages = [...messages, assistantMessage];
2131
2166
  progress.usage = llmResponse && typeof llmResponse === "object" && llmResponse.usage || null;
2132
2167
  progress.usageTotal = accumulateUsage(progress.usageTotal, progress.usage);
2168
+ ctx.throwIfCancelled();
2133
2169
  const sessionCtx = Object.freeze({
2170
+ signal: ctx.signal,
2171
+ isCancelled: ctx.isCancelled,
2172
+ throwIfCancelled: ctx.throwIfCancelled,
2134
2173
  ...buildSessionContext({
2135
2174
  sessionId,
2136
2175
  messages,
@@ -2154,6 +2193,7 @@ async function runFireChain({
2154
2193
  resolveLlmCredential: resolveLlmCredential2
2155
2194
  });
2156
2195
  const decision = await hooks.onLLMOutput(sessionCtx);
2196
+ ctx.throwIfCancelled();
2157
2197
  try {
2158
2198
  assertValidDecision(decision, { inlineToolCalls: true });
2159
2199
  } catch (error) {
@@ -2204,11 +2244,15 @@ async function runFireChain({
2204
2244
  }
2205
2245
  let toolResults;
2206
2246
  try {
2247
+ ctx.throwIfCancelled();
2207
2248
  toolResults = await hooks.executeToolCalls(toolCalls, sessionCtx);
2249
+ ctx.throwIfCancelled();
2208
2250
  if (!Array.isArray(toolResults)) {
2209
2251
  throw new TypeError('executeToolCalls must resolve to an array of { tool_call_id, role: "tool", content }');
2210
2252
  }
2211
2253
  } catch (error) {
2254
+ ctx.throwIfCancelled();
2255
+ if (isTaskCancelledError(error)) throw error;
2212
2256
  toolResults = toolCalls.map((toolCall) => ({
2213
2257
  tool_call_id: toolCall && typeof toolCall === "object" && typeof toolCall.id === "string" ? toolCall.id : "",
2214
2258
  role: "tool",
@@ -2298,9 +2342,11 @@ async function sendHookPushPayloads({
2298
2342
  stampTaskIdentity(push, task, decryptedPayload, occurrenceMs);
2299
2343
  finalized.push(push);
2300
2344
  }
2345
+ ctx.throwIfCancelled();
2301
2346
  outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
2302
2347
  progress.outboxed = outboxed;
2303
2348
  if (ctx._deliveryState) ctx._deliveryState.outboxed = outboxed;
2349
+ ctx.throwIfCancelled();
2304
2350
  if (!ctx.vapid || !ctx.vapid.email || !ctx.vapid.publicKey || !ctx.vapid.privateKey) {
2305
2351
  throw new Error("VAPID configuration missing - push notifications cannot be sent");
2306
2352
  }
@@ -2314,6 +2360,7 @@ async function sendHookPushPayloads({
2314
2360
  const willPush = finalized.map((push) => shouldSendPush(push, pushGate));
2315
2361
  const lastPushIndex = willPush.lastIndexOf(true);
2316
2362
  for (let i = 0; i < total; i++) {
2363
+ ctx.throwIfCancelled();
2317
2364
  if (willPush[i]) {
2318
2365
  await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
2319
2366
  pushedCount++;
@@ -2577,7 +2624,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2577
2624
  const hasChatSource = hasChatCredRef(decryptedPayload) || !!(decryptedPayload.apiUrl && decryptedPayload.apiKey && decryptedPayload.primaryModel);
2578
2625
  if (hasPrompt && hasChatSource) {
2579
2626
  const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
2580
- const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
2627
+ const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
2581
2628
  messageContent = aiResult.content;
2582
2629
  llmResponse = aiResult.response;
2583
2630
  } else if (decryptedPayload.userMessage) {
@@ -2587,7 +2634,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2587
2634
  }
2588
2635
  } else if (decryptedPayload.messageType === "prompted" || decryptedPayload.messageType === "auto") {
2589
2636
  const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
2590
- const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
2637
+ const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
2591
2638
  messageContent = aiResult.content;
2592
2639
  llmResponse = aiResult.response;
2593
2640
  } else {
@@ -3208,7 +3255,8 @@ async function deliverTasks(ctx, tasks) {
3208
3255
  return !!await db.claimTask(task.id, task.next_send_at, leaseUntil, serializeGroup);
3209
3256
  }
3210
3257
  function startLeaseHeartbeat(task) {
3211
- const lease = { lost: false, released: false, stop: () => {
3258
+ const controller = new AbortController();
3259
+ const lease = { lost: false, released: false, signal: controller.signal, stop: () => {
3212
3260
  } };
3213
3261
  if (!heartbeatEnabled) return lease;
3214
3262
  let stopped = false;
@@ -3224,6 +3272,9 @@ async function deliverTasks(ctx, tasks) {
3224
3272
  if (renewed === false) {
3225
3273
  if (stopped || lease.released) return;
3226
3274
  lease.lost = true;
3275
+ const error = new Error("Task was cancelled or superseded");
3276
+ error.code = TASK_CANCELLED_CODE;
3277
+ controller.abort(error);
3227
3278
  console.warn(`[amsg-server] \u4EFB\u52A1 ${task.id} \u7684\u79DF\u7EA6\u5DF2\u5931\u6548\uFF08\u884C\u88AB\u53D6\u6D88\u6216\u9876\u66FF\uFF09\uFF0C\u5269\u4F59\u63A8\u9001\u5C06\u4E2D\u6B62`);
3228
3279
  return;
3229
3280
  }
@@ -3553,7 +3604,8 @@ async function deliverTasks(ctx, tasks) {
3553
3604
  db,
3554
3605
  masterKey,
3555
3606
  webpush: guardWebpushWithLease(ctx.webpush, lease),
3556
- isTaskCancelled: () => lease.lost
3607
+ isTaskCancelled: () => lease.lost,
3608
+ signal: lease.signal
3557
3609
  },
3558
3610
  masterKey,
3559
3611
  { userKey, payload: decryptedPayload }
@@ -5960,7 +6012,7 @@ function createClientStateNamespacesHandler(ctx) {
5960
6012
  }
5961
6013
 
5962
6014
  // src/server/lib/version.js
5963
- var SERVER_VERSION = true ? "2.6.0-next.31" : "0.0.0-dev";
6015
+ var SERVER_VERSION = true ? "2.6.0-next.32" : "0.0.0-dev";
5964
6016
 
5965
6017
  // src/server/handlers/capabilities.js
5966
6018
  var SERVER_FEATURES = Object.freeze([
@@ -1707,6 +1707,17 @@ function firstPositiveNumber(values, fallback) {
1707
1707
  }
1708
1708
  async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1709
1709
  const hooks = ctx.hooks;
1710
+ const signal = ctx.signal || new AbortController().signal;
1711
+ const isCancelled = () => signal.aborted || _optionalChain([ctx, 'access', _5 => _5.isTaskCancelled, 'optionalCall', _6 => _6()]) === true;
1712
+ const throwIfCancelled = () => {
1713
+ if (!isCancelled()) return;
1714
+ if (isTaskCancelledError(signal.reason)) throw signal.reason;
1715
+ const error = new Error("Task was cancelled or superseded");
1716
+ error.code = "TASK_CANCELLED";
1717
+ throw error;
1718
+ };
1719
+ const cancellation = { signal, isCancelled, throwIfCancelled };
1720
+ ctx = { ...ctx, ...cancellation };
1710
1721
  if (typeof hooks.onLLMOutput !== "function") {
1711
1722
  throw new DeploymentConfigError(
1712
1723
  "AGENTIC_CONFIG_ERROR: hooks.onBeforeFire requires hooks.onLLMOutput to classify LLM rounds",
@@ -1715,13 +1726,17 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1715
1726
  }
1716
1727
  const nowFn = typeof ctx._agenticNow === "function" ? ctx._agenticNow : Date.now;
1717
1728
  const sleep = typeof ctx._agenticSleep === "function" ? ctx._agenticSleep : defaultSleep;
1718
- const { readState, writeState } = createStateAccessors({
1729
+ const { readState, writeState: writeSettledState } = createStateAccessors({
1719
1730
  db: ctx.db,
1720
1731
  userId: task.user_id,
1721
1732
  userKey,
1722
1733
  maxStateValueBytes: ctx.maxStateValueBytes,
1723
1734
  now: nowFn
1724
1735
  });
1736
+ const writeState = async (namespace, entries) => {
1737
+ throwIfCancelled();
1738
+ return writeSettledState(namespace, entries);
1739
+ };
1725
1740
  const sessionId = task.id != null ? `sess_task_${task.id}${occurrenceSuffix(task)}` : `sess_${_amsgshared.randomUUID.call(void 0, )}`;
1726
1741
  const messageIdBase = task.id != null ? `msg_task_${task.id}${occurrenceSuffix(task)}` : `msg_${_amsgshared.randomUUID.call(void 0, )}`;
1727
1742
  const occurrenceMs = occurrenceMsOf(task);
@@ -1737,7 +1752,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1737
1752
  now: nowFn,
1738
1753
  // run-tick 在投递 ctx 上挂的取消信号(与 guardWebpushWithLease 读的是同一
1739
1754
  // 个租约状态),emitResult 不发推送的那条路要靠它拦下已取消任务的落行。
1740
- isCancelled: typeof ctx.isTaskCancelled === "function" ? ctx.isTaskCancelled : null
1755
+ isCancelled
1741
1756
  });
1742
1757
  const maxScheduledTasksPerFire = Number.isInteger(ctx.maxScheduledTasksPerFire) && ctx.maxScheduledTasksPerFire >= 0 ? ctx.maxScheduledTasksPerFire : DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE;
1743
1758
  let scheduledTaskCount = 0;
@@ -1754,6 +1769,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1754
1769
  }
1755
1770
  }
1756
1771
  const scheduleTask = async (options) => {
1772
+ throwIfCancelled();
1757
1773
  if (!options || typeof options !== "object" || Array.isArray(options)) {
1758
1774
  throw new TypeError("scheduleTask(options) \u9700\u8981\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u81F3\u5C11\u5305\u542B { firstSendTime }");
1759
1775
  }
@@ -1874,6 +1890,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1874
1890
  }
1875
1891
  scheduledTaskCount++;
1876
1892
  const encryptedPayload = await encryptForStorage(serializedTaskData, userKey);
1893
+ throwIfCancelled();
1877
1894
  let created;
1878
1895
  try {
1879
1896
  created = await ctx.db.createTask({
@@ -1908,6 +1925,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1908
1925
  };
1909
1926
  };
1910
1927
  const cancelTask = async (uuid) => {
1928
+ throwIfCancelled();
1911
1929
  if (typeof uuid !== "string" || !uuid.trim()) {
1912
1930
  throw new TypeError("cancelTask(uuid) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
1913
1931
  }
@@ -1922,6 +1940,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1922
1940
  { code: "AGENTIC_CANCEL_UNSUPPORTED" }
1923
1941
  );
1924
1942
  }
1943
+ throwIfCancelled();
1925
1944
  const cancelled = await ctx.db.deleteTaskByUuid(uuid, task.user_id);
1926
1945
  if (cancelled) {
1927
1946
  await discardUndeliveredPushesForTask({ db: ctx.db, userId: task.user_id, taskUuid: uuid });
@@ -1929,6 +1948,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1929
1948
  return { cancelled: !!cancelled };
1930
1949
  };
1931
1950
  const renewTask = async (uuid, nextSendAt) => {
1951
+ throwIfCancelled();
1932
1952
  if (typeof uuid !== "string" || !uuid.trim()) {
1933
1953
  throw new TypeError("renewTask(uuid, nextSendAt) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
1934
1954
  }
@@ -1959,6 +1979,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1959
1979
  const payload = JSON.parse(await decryptFromStorage(row.encrypted_payload, userKey));
1960
1980
  const nextSendAtIso = sendAt.toISOString();
1961
1981
  const encrypted = await encryptForStorage(JSON.stringify({ ...payload, firstSendTime: nextSendAtIso }), userKey);
1982
+ throwIfCancelled();
1962
1983
  const updated = await ctx.db.updateTaskByUuid(uuid, task.user_id, encrypted, {
1963
1984
  next_send_at: nextSendAtIso,
1964
1985
  retry_count: 0,
@@ -1979,6 +2000,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
1979
2000
  };
1980
2001
  const scratch = {};
1981
2002
  const fireCtx = Object.freeze({
2003
+ ...cancellation,
1982
2004
  task: buildHookTask(task, decryptedPayload),
1983
2005
  userId: task.user_id,
1984
2006
  readState,
@@ -2027,16 +2049,26 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
2027
2049
  messageIdBase,
2028
2050
  occurrenceMs
2029
2051
  });
2052
+ throwIfCancelled();
2030
2053
  settledStatus = !outcome.handled ? "not-handled" : outcome.result.status === "skipped" ? "skipped" : "sent";
2031
2054
  return outcome;
2032
2055
  } catch (error) {
2056
+ if (isCancelled() && !isTaskCancelledError(error)) {
2057
+ try {
2058
+ throwIfCancelled();
2059
+ } catch (cancelled) {
2060
+ error = cancelled;
2061
+ }
2062
+ }
2063
+ if (isTaskCancelledError(error)) settledStatus = "cancelled";
2033
2064
  settledError = error;
2034
2065
  throw error;
2035
2066
  } finally {
2036
2067
  await notifyFireSettled(ctx, {
2037
2068
  task,
2069
+ ...cancellation,
2038
2070
  status: settledStatus,
2039
- ...settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
2071
+ ...settledStatus === "cancelled" ? { willRetry: false, failureStage: null } : settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
2040
2072
  skipReason: settledStatus === "skipped" ? progress.skipReason : null,
2041
2073
  sentCount: progress.sentCount,
2042
2074
  pushedCount: progress.pushedCount,
@@ -2060,7 +2092,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
2060
2092
  outboxed: progress.outboxed,
2061
2093
  scratch,
2062
2094
  readState,
2063
- writeState,
2095
+ writeState: writeSettledState,
2064
2096
  emitResult
2065
2097
  });
2066
2098
  }
@@ -2087,7 +2119,9 @@ async function runFireChain({
2087
2119
  messageIdBase,
2088
2120
  occurrenceMs
2089
2121
  }) {
2122
+ ctx.throwIfCancelled();
2090
2123
  const before = await hooks.onBeforeFire(fireCtx);
2124
+ ctx.throwIfCancelled();
2091
2125
  if (before == null) return { handled: false };
2092
2126
  if (typeof before === "object" && before.skip === true) {
2093
2127
  progress.skipReason = "before-fire";
@@ -2111,6 +2145,7 @@ async function runFireChain({
2111
2145
  decryptedPayload
2112
2146
  });
2113
2147
  for (let iteration = 0; iteration < maxToolIterations; iteration++) {
2148
+ ctx.throwIfCancelled();
2114
2149
  if (nowFn() >= deadline) {
2115
2150
  throw new Error(`AGENTIC_TOTAL_TIMEOUT: fire chain exceeded ${totalTimeoutMs}ms after ${iteration} LLM round(s)`);
2116
2151
  }
@@ -2124,13 +2159,17 @@ async function runFireChain({
2124
2159
  messages,
2125
2160
  ...normalized.tools ? { tools: normalized.tools, toolChoice: normalized.toolChoice } : {}
2126
2161
  },
2127
- { requireContent: false, timeoutMs: roundTimeoutMs }
2162
+ { requireContent: false, timeoutMs: roundTimeoutMs, signal: ctx.signal }
2128
2163
  );
2129
2164
  const assistantMessage = _amsgshared.extractAssistantMessage.call(void 0, llmResponse);
2130
2165
  messages = [...messages, assistantMessage];
2131
2166
  progress.usage = llmResponse && typeof llmResponse === "object" && llmResponse.usage || null;
2132
2167
  progress.usageTotal = accumulateUsage(progress.usageTotal, progress.usage);
2168
+ ctx.throwIfCancelled();
2133
2169
  const sessionCtx = Object.freeze({
2170
+ signal: ctx.signal,
2171
+ isCancelled: ctx.isCancelled,
2172
+ throwIfCancelled: ctx.throwIfCancelled,
2134
2173
  ..._amsgshared.buildSessionContext.call(void 0, {
2135
2174
  sessionId,
2136
2175
  messages,
@@ -2154,6 +2193,7 @@ async function runFireChain({
2154
2193
  resolveLlmCredential: resolveLlmCredential2
2155
2194
  });
2156
2195
  const decision = await hooks.onLLMOutput(sessionCtx);
2196
+ ctx.throwIfCancelled();
2157
2197
  try {
2158
2198
  _amsgshared.assertValidDecision.call(void 0, decision, { inlineToolCalls: true });
2159
2199
  } catch (error) {
@@ -2204,15 +2244,19 @@ async function runFireChain({
2204
2244
  }
2205
2245
  let toolResults;
2206
2246
  try {
2247
+ ctx.throwIfCancelled();
2207
2248
  toolResults = await hooks.executeToolCalls(toolCalls, sessionCtx);
2249
+ ctx.throwIfCancelled();
2208
2250
  if (!Array.isArray(toolResults)) {
2209
2251
  throw new TypeError('executeToolCalls must resolve to an array of { tool_call_id, role: "tool", content }');
2210
2252
  }
2211
2253
  } catch (error) {
2254
+ ctx.throwIfCancelled();
2255
+ if (isTaskCancelledError(error)) throw error;
2212
2256
  toolResults = toolCalls.map((toolCall) => ({
2213
2257
  tool_call_id: toolCall && typeof toolCall === "object" && typeof toolCall.id === "string" ? toolCall.id : "",
2214
2258
  role: "tool",
2215
- content: `Tool execution failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _5 => _5.message]), () => ( String(error)))}`
2259
+ content: `Tool execution failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _7 => _7.message]), () => ( String(error)))}`
2216
2260
  }));
2217
2261
  }
2218
2262
  const nativeCalls = Array.isArray(assistantMessage.tool_calls) ? assistantMessage.tool_calls : [];
@@ -2298,9 +2342,11 @@ async function sendHookPushPayloads({
2298
2342
  stampTaskIdentity(push, task, decryptedPayload, occurrenceMs);
2299
2343
  finalized.push(push);
2300
2344
  }
2345
+ ctx.throwIfCancelled();
2301
2346
  outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
2302
2347
  progress.outboxed = outboxed;
2303
2348
  if (ctx._deliveryState) ctx._deliveryState.outboxed = outboxed;
2349
+ ctx.throwIfCancelled();
2304
2350
  if (!ctx.vapid || !ctx.vapid.email || !ctx.vapid.publicKey || !ctx.vapid.privateKey) {
2305
2351
  throw new Error("VAPID configuration missing - push notifications cannot be sent");
2306
2352
  }
@@ -2314,6 +2360,7 @@ async function sendHookPushPayloads({
2314
2360
  const willPush = finalized.map((push) => shouldSendPush(push, pushGate));
2315
2361
  const lastPushIndex = willPush.lastIndexOf(true);
2316
2362
  for (let i = 0; i < total; i++) {
2363
+ ctx.throwIfCancelled();
2317
2364
  if (willPush[i]) {
2318
2365
  await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
2319
2366
  pushedCount++;
@@ -2577,7 +2624,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2577
2624
  const hasChatSource = hasChatCredRef(decryptedPayload) || !!(decryptedPayload.apiUrl && decryptedPayload.apiKey && decryptedPayload.primaryModel);
2578
2625
  if (hasPrompt && hasChatSource) {
2579
2626
  const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
2580
- const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
2627
+ const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
2581
2628
  messageContent = aiResult.content;
2582
2629
  llmResponse = aiResult.response;
2583
2630
  } else if (decryptedPayload.userMessage) {
@@ -2587,7 +2634,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
2587
2634
  }
2588
2635
  } else if (decryptedPayload.messageType === "prompted" || decryptedPayload.messageType === "auto") {
2589
2636
  const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
2590
- const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
2637
+ const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
2591
2638
  messageContent = aiResult.content;
2592
2639
  llmResponse = aiResult.response;
2593
2640
  } else {
@@ -3208,7 +3255,8 @@ async function deliverTasks(ctx, tasks) {
3208
3255
  return !!await db.claimTask(task.id, task.next_send_at, leaseUntil, serializeGroup);
3209
3256
  }
3210
3257
  function startLeaseHeartbeat(task) {
3211
- const lease = { lost: false, released: false, stop: () => {
3258
+ const controller = new AbortController();
3259
+ const lease = { lost: false, released: false, signal: controller.signal, stop: () => {
3212
3260
  } };
3213
3261
  if (!heartbeatEnabled) return lease;
3214
3262
  let stopped = false;
@@ -3224,6 +3272,9 @@ async function deliverTasks(ctx, tasks) {
3224
3272
  if (renewed === false) {
3225
3273
  if (stopped || lease.released) return;
3226
3274
  lease.lost = true;
3275
+ const error = new Error("Task was cancelled or superseded");
3276
+ error.code = TASK_CANCELLED_CODE;
3277
+ controller.abort(error);
3227
3278
  console.warn(`[amsg-server] \u4EFB\u52A1 ${task.id} \u7684\u79DF\u7EA6\u5DF2\u5931\u6548\uFF08\u884C\u88AB\u53D6\u6D88\u6216\u9876\u66FF\uFF09\uFF0C\u5269\u4F59\u63A8\u9001\u5C06\u4E2D\u6B62`);
3228
3279
  return;
3229
3280
  }
@@ -3553,7 +3604,8 @@ async function deliverTasks(ctx, tasks) {
3553
3604
  db,
3554
3605
  masterKey,
3555
3606
  webpush: guardWebpushWithLease(ctx.webpush, lease),
3556
- isTaskCancelled: () => lease.lost
3607
+ isTaskCancelled: () => lease.lost,
3608
+ signal: lease.signal
3557
3609
  },
3558
3610
  masterKey,
3559
3611
  { userKey, payload: decryptedPayload }
@@ -5099,7 +5151,7 @@ var D1Adapter = class {
5099
5151
  result.cleanupOutcomes = probeIndexes.map((probeAt) => {
5100
5152
  if (probeAt === null) return null;
5101
5153
  const row = results[probeAt] && Array.isArray(results[probeAt].results) ? results[probeAt].results[0] : null;
5102
- return Number(_nullishCoalesce(_optionalChain([row, 'optionalAccess', _6 => _6.n]), () => ( 0))) === 0;
5154
+ return Number(_nullishCoalesce(_optionalChain([row, 'optionalAccess', _8 => _8.n]), () => ( 0))) === 0;
5103
5155
  });
5104
5156
  }
5105
5157
  return result;
@@ -5960,7 +6012,7 @@ function createClientStateNamespacesHandler(ctx) {
5960
6012
  }
5961
6013
 
5962
6014
  // src/server/lib/version.js
5963
- var SERVER_VERSION = true ? "2.6.0-next.31" : "0.0.0-dev";
6015
+ var SERVER_VERSION = true ? "2.6.0-next.32" : "0.0.0-dev";
5964
6016
 
5965
6017
  // src/server/handlers/capabilities.js
5966
6018
  var SERVER_FEATURES = Object.freeze([
@@ -27,7 +27,7 @@
27
27
 
28
28
 
29
29
 
30
- var _chunk7TM3MH3Qcjs = require('./chunk-7TM3MH3Q.cjs');
30
+ var _chunkKZT3YC62cjs = require('./chunk-KZT3YC62.cjs');
31
31
  require('./chunk-7NMQFTDJ.cjs');
32
32
 
33
33
 
@@ -58,4 +58,4 @@ require('./chunk-7NMQFTDJ.cjs');
58
58
 
59
59
 
60
60
 
61
- exports.DEFAULT_MAX_DELIVERY_RETRIES = _chunk7TM3MH3Qcjs.DEFAULT_MAX_DELIVERY_RETRIES; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunk7TM3MH3Qcjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.MAX_PUSH_PAYLOAD_BYTES = _chunk7TM3MH3Qcjs.MAX_PUSH_PAYLOAD_BYTES; exports.NonRetryableError = _chunk7TM3MH3Qcjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunk7TM3MH3Qcjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunk7TM3MH3Qcjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunk7TM3MH3Qcjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunk7TM3MH3Qcjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunk7TM3MH3Qcjs.advanceOccurrence; exports.createD1Adapter = _chunk7TM3MH3Qcjs.createD1Adapter; exports.createSingleUserCloudflareWorker = _chunk7TM3MH3Qcjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunk7TM3MH3Qcjs.createSingleUserServer; exports.createWebCryptoWebPush = _chunk7TM3MH3Qcjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunk7TM3MH3Qcjs.decryptFromStorage; exports.decryptPayload = _chunk7TM3MH3Qcjs.decryptPayload; exports.deriveUserEncryptionKey = _chunk7TM3MH3Qcjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunk7TM3MH3Qcjs.encryptForStorage; exports.ensureSchema = _chunk7TM3MH3Qcjs.ensureSchema; exports.getSchemaVersion = _chunk7TM3MH3Qcjs.getSchemaVersion; exports.isNonRetryableError = _chunk7TM3MH3Qcjs.isNonRetryableError; exports.isValidTimeZoneId = _chunk7TM3MH3Qcjs.isValidTimeZoneId; exports.measurePushPayload = _chunk7TM3MH3Qcjs.measurePushPayload; exports.nextFutureOccurrence = _chunk7TM3MH3Qcjs.nextFutureOccurrence; exports.planNextOccurrence = _chunk7TM3MH3Qcjs.planNextOccurrence; exports.readRequestBody = _chunk7TM3MH3Qcjs.readRequestBody; exports.runScheduledTick = _chunk7TM3MH3Qcjs.runScheduledTick; exports.runTask = _chunk7TM3MH3Qcjs.runTask; exports.summarizeErrorCause = _chunk7TM3MH3Qcjs.summarizeErrorCause;
61
+ exports.DEFAULT_MAX_DELIVERY_RETRIES = _chunkKZT3YC62cjs.DEFAULT_MAX_DELIVERY_RETRIES; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkKZT3YC62cjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkKZT3YC62cjs.MAX_PUSH_PAYLOAD_BYTES; exports.NonRetryableError = _chunkKZT3YC62cjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkKZT3YC62cjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkKZT3YC62cjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkKZT3YC62cjs.advanceOccurrence; exports.createD1Adapter = _chunkKZT3YC62cjs.createD1Adapter; exports.createSingleUserCloudflareWorker = _chunkKZT3YC62cjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkKZT3YC62cjs.createSingleUserServer; exports.createWebCryptoWebPush = _chunkKZT3YC62cjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkKZT3YC62cjs.decryptFromStorage; exports.decryptPayload = _chunkKZT3YC62cjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkKZT3YC62cjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkKZT3YC62cjs.encryptForStorage; exports.ensureSchema = _chunkKZT3YC62cjs.ensureSchema; exports.getSchemaVersion = _chunkKZT3YC62cjs.getSchemaVersion; exports.isNonRetryableError = _chunkKZT3YC62cjs.isNonRetryableError; exports.isValidTimeZoneId = _chunkKZT3YC62cjs.isValidTimeZoneId; exports.measurePushPayload = _chunkKZT3YC62cjs.measurePushPayload; exports.nextFutureOccurrence = _chunkKZT3YC62cjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkKZT3YC62cjs.planNextOccurrence; exports.readRequestBody = _chunkKZT3YC62cjs.readRequestBody; exports.runScheduledTick = _chunkKZT3YC62cjs.runScheduledTick; exports.runTask = _chunkKZT3YC62cjs.runTask; exports.summarizeErrorCause = _chunkKZT3YC62cjs.summarizeErrorCause;
@@ -27,7 +27,7 @@ import {
27
27
  runScheduledTick,
28
28
  runTask,
29
29
  summarizeErrorCause
30
- } from "./chunk-PG54W6B5.mjs";
30
+ } from "./chunk-INNZZFGJ.mjs";
31
31
  import "./chunk-GN44PST5.mjs";
32
32
  export {
33
33
  DEFAULT_MAX_DELIVERY_RETRIES,
package/dist/index.cjs CHANGED
@@ -72,7 +72,7 @@
72
72
 
73
73
 
74
74
 
75
- var _chunk7TM3MH3Qcjs = require('./chunk-7TM3MH3Q.cjs');
75
+ var _chunkKZT3YC62cjs = require('./chunk-KZT3YC62.cjs');
76
76
  require('./chunk-7NMQFTDJ.cjs');
77
77
 
78
78
  // src/server/adapters/factory.js
@@ -106,7 +106,7 @@ async function createAdapter(config) {
106
106
  // src/server/handlers/init-tenant.js
107
107
  function createInitTenantHandler(ctx) {
108
108
  async function POST(headers, body) {
109
- const initSecret = _chunk7TM3MH3Qcjs.getHeader.call(void 0, headers, "x-init-secret");
109
+ const initSecret = _chunkKZT3YC62cjs.getHeader.call(void 0, headers, "x-init-secret");
110
110
  if (ctx.tenant.initSecret && initSecret !== ctx.tenant.initSecret) {
111
111
  return {
112
112
  status: 401,
@@ -119,7 +119,7 @@ function createInitTenantHandler(ctx) {
119
119
  }
120
120
  };
121
121
  }
122
- const parsed = _chunk7TM3MH3Qcjs.parseJsonBody.call(void 0, body);
122
+ const parsed = _chunkKZT3YC62cjs.parseJsonBody.call(void 0, body);
123
123
  if (!parsed.ok) {
124
124
  return {
125
125
  status: 400,
@@ -133,7 +133,7 @@ function createInitTenantHandler(ctx) {
133
133
  const tenantId = payload.tenantId || void 0;
134
134
  const driver = payload.driver;
135
135
  const databaseUrl = payload.databaseUrl || payload.connectionString;
136
- if (tenantId && !_chunk7TM3MH3Qcjs.isValidUUIDv4.call(void 0, tenantId)) {
136
+ if (tenantId && !_chunkKZT3YC62cjs.isValidUUIDv4.call(void 0, tenantId)) {
137
137
  return {
138
138
  status: 400,
139
139
  body: {
@@ -253,7 +253,7 @@ function createSendNotificationsHandler(ctx) {
253
253
  }
254
254
  };
255
255
  }
256
- const data = await _chunk7TM3MH3Qcjs.runScheduledTick.call(void 0, { ...ctx, db, masterKey });
256
+ const data = await _chunkKZT3YC62cjs.runScheduledTick.call(void 0, { ...ctx, db, masterKey });
257
257
  return { status: 200, body: { success: true, data } };
258
258
  }
259
259
  return { POST };
@@ -275,16 +275,16 @@ function encryptConfig(config, kekBuffer) {
275
275
  const plaintext = Buffer.from(JSON.stringify(config), "utf8");
276
276
  const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
277
277
  const authTag = cipher.getAuthTag();
278
- return `v1.${_chunk7TM3MH3Qcjs.bytesToBase64Url.call(void 0, iv)}.${_chunk7TM3MH3Qcjs.bytesToBase64Url.call(void 0, authTag)}.${_chunk7TM3MH3Qcjs.bytesToBase64Url.call(void 0, ciphertext)}`;
278
+ return `v1.${_chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, iv)}.${_chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, authTag)}.${_chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, ciphertext)}`;
279
279
  }
280
280
  function decryptConfig(encrypted, kekBuffer) {
281
281
  const parts = String(encrypted || "").split(".");
282
282
  if (parts.length !== 4 || parts[0] !== "v1") {
283
283
  throw new Error("INVALID_TENANT_CONFIG");
284
284
  }
285
- const iv = _chunk7TM3MH3Qcjs.base64UrlToBytes.call(void 0, parts[1]);
286
- const authTag = _chunk7TM3MH3Qcjs.base64UrlToBytes.call(void 0, parts[2]);
287
- const ciphertext = _chunk7TM3MH3Qcjs.base64UrlToBytes.call(void 0, parts[3]);
285
+ const iv = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, parts[1]);
286
+ const authTag = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, parts[2]);
287
+ const ciphertext = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, parts[3]);
288
288
  const decipher = _crypto.createDecipheriv.call(void 0, "aes-256-gcm", kekBuffer, iv);
289
289
  decipher.setAuthTag(authTag);
290
290
  const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
@@ -352,7 +352,7 @@ function createTenantBlobStore(options) {
352
352
  // src/server/tenant/token.js
353
353
 
354
354
  function sign(input, secret) {
355
- return _chunk7TM3MH3Qcjs.bytesToBase64Url.call(void 0, _crypto.createHmac.call(void 0, "sha256", secret).update(input).digest());
355
+ return _chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, _crypto.createHmac.call(void 0, "sha256", secret).update(input).digest());
356
356
  }
357
357
  function nowEpochSeconds() {
358
358
  return Math.floor(Date.now() / 1e3);
@@ -368,8 +368,8 @@ function createTenantToken(params, secret) {
368
368
  v: 1
369
369
  };
370
370
  const header = { alg: "HS256", typ: "JWT" };
371
- const encodedHeader = _chunk7TM3MH3Qcjs.bytesToBase64Url.call(void 0, _chunk7TM3MH3Qcjs.utf8.call(void 0, JSON.stringify(header)));
372
- const encodedPayload = _chunk7TM3MH3Qcjs.bytesToBase64Url.call(void 0, _chunk7TM3MH3Qcjs.utf8.call(void 0, JSON.stringify(payload)));
371
+ const encodedHeader = _chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, _chunkKZT3YC62cjs.utf8.call(void 0, JSON.stringify(header)));
372
+ const encodedPayload = _chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, _chunkKZT3YC62cjs.utf8.call(void 0, JSON.stringify(payload)));
373
373
  const signingInput = `${encodedHeader}.${encodedPayload}`;
374
374
  const signature = sign(signingInput, secret);
375
375
  return `${signingInput}.${signature}`;
@@ -388,17 +388,17 @@ function verifyTenantToken(token, secret, options = {}) {
388
388
  let receivedBytes;
389
389
  let expectedBytes;
390
390
  try {
391
- receivedBytes = _chunk7TM3MH3Qcjs.base64UrlToBytes.call(void 0, receivedSignature);
392
- expectedBytes = _chunk7TM3MH3Qcjs.base64UrlToBytes.call(void 0, expectedSignature);
391
+ receivedBytes = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, receivedSignature);
392
+ expectedBytes = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, expectedSignature);
393
393
  } catch (e) {
394
394
  throw new Error("INVALID_TENANT_AUTH");
395
395
  }
396
- if (!_chunk7TM3MH3Qcjs.timingSafeEqualBytes.call(void 0, receivedBytes, expectedBytes)) {
396
+ if (!_chunkKZT3YC62cjs.timingSafeEqualBytes.call(void 0, receivedBytes, expectedBytes)) {
397
397
  throw new Error("INVALID_TENANT_AUTH");
398
398
  }
399
399
  let payload;
400
400
  try {
401
- payload = JSON.parse(_chunk7TM3MH3Qcjs.utf8Decode.call(void 0, _chunk7TM3MH3Qcjs.base64UrlToBytes.call(void 0, encodedPayload)));
401
+ payload = JSON.parse(_chunkKZT3YC62cjs.utf8Decode.call(void 0, _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, encodedPayload)));
402
402
  } catch (e2) {
403
403
  throw new Error("INVALID_TENANT_AUTH");
404
404
  }
@@ -626,15 +626,15 @@ async function createReiServer(config) {
626
626
  return {
627
627
  handlers: {
628
628
  initTenant: createInitTenantHandler(ctx),
629
- getUserKey: _chunk7TM3MH3Qcjs.createGetUserKeyHandler.call(void 0, ctx),
630
- scheduleMessage: _chunk7TM3MH3Qcjs.createScheduleMessageHandler.call(void 0, ctx),
629
+ getUserKey: _chunkKZT3YC62cjs.createGetUserKeyHandler.call(void 0, ctx),
630
+ scheduleMessage: _chunkKZT3YC62cjs.createScheduleMessageHandler.call(void 0, ctx),
631
631
  sendNotifications: createSendNotificationsHandler(ctx),
632
- updateMessage: _chunk7TM3MH3Qcjs.createUpdateMessageHandler.call(void 0, ctx),
633
- cancelMessage: _chunk7TM3MH3Qcjs.createCancelMessageHandler.call(void 0, ctx),
634
- messages: _chunk7TM3MH3Qcjs.createMessagesHandler.call(void 0, ctx),
635
- getMessage: _chunk7TM3MH3Qcjs.createGetMessageHandler.call(void 0, ctx),
636
- pushSubscription: _chunk7TM3MH3Qcjs.createPushSubscriptionHandler.call(void 0, ctx),
637
- llmCredentials: _chunk7TM3MH3Qcjs.createLlmCredentialsHandler.call(void 0, ctx)
632
+ updateMessage: _chunkKZT3YC62cjs.createUpdateMessageHandler.call(void 0, ctx),
633
+ cancelMessage: _chunkKZT3YC62cjs.createCancelMessageHandler.call(void 0, ctx),
634
+ messages: _chunkKZT3YC62cjs.createMessagesHandler.call(void 0, ctx),
635
+ getMessage: _chunkKZT3YC62cjs.createGetMessageHandler.call(void 0, ctx),
636
+ pushSubscription: _chunkKZT3YC62cjs.createPushSubscriptionHandler.call(void 0, ctx),
637
+ llmCredentials: _chunkKZT3YC62cjs.createLlmCredentialsHandler.call(void 0, ctx)
638
638
  }
639
639
  };
640
640
  }
@@ -701,4 +701,4 @@ async function createReiServer(config) {
701
701
 
702
702
 
703
703
 
704
- exports.CORS_ALLOW_HEADERS = _chunk7TM3MH3Qcjs.CORS_ALLOW_HEADERS; exports.CORS_ALLOW_METHODS = _chunk7TM3MH3Qcjs.CORS_ALLOW_METHODS; exports.CRED_ID_MAX_LENGTH = _chunk7TM3MH3Qcjs.CRED_ID_MAX_LENGTH; exports.CRED_PUT_BATCH_MAX = _chunk7TM3MH3Qcjs.CRED_PUT_BATCH_MAX; exports.CRED_REFS_MAX_ENTRIES = _chunk7TM3MH3Qcjs.CRED_REFS_MAX_ENTRIES; exports.CRED_ROWS_PER_USER_MAX = _chunk7TM3MH3Qcjs.CRED_ROWS_PER_USER_MAX; exports.DEFAULT_CLAIM_LEASE_MS = _chunk7TM3MH3Qcjs.DEFAULT_CLAIM_LEASE_MS; exports.DEFAULT_HEARTBEAT_LEASE_TTL_MS = _chunk7TM3MH3Qcjs.DEFAULT_HEARTBEAT_LEASE_TTL_MS; exports.DEFAULT_LEASE_HEARTBEAT_MS = _chunk7TM3MH3Qcjs.DEFAULT_LEASE_HEARTBEAT_MS; exports.DEFAULT_MAX_DELIVERY_RETRIES = _chunk7TM3MH3Qcjs.DEFAULT_MAX_DELIVERY_RETRIES; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunk7TM3MH3Qcjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE = _chunk7TM3MH3Qcjs.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE; exports.DEFAULT_MAX_TOOL_ITERATIONS = _chunk7TM3MH3Qcjs.DEFAULT_MAX_TOOL_ITERATIONS; exports.DEFAULT_TOTAL_TIMEOUT_MS = _chunk7TM3MH3Qcjs.DEFAULT_TOTAL_TIMEOUT_MS; exports.DeploymentConfigError = _chunk7TM3MH3Qcjs.DeploymentConfigError; exports.MAX_PUSH_PAYLOAD_BYTES = _chunk7TM3MH3Qcjs.MAX_PUSH_PAYLOAD_BYTES; exports.MAX_TASK_PAYLOAD_BYTES = _chunk7TM3MH3Qcjs.MAX_TASK_PAYLOAD_BYTES; exports.MIN_SCHEDULE_LEAD_MS = _chunk7TM3MH3Qcjs.MIN_SCHEDULE_LEAD_MS; exports.NonRetryableError = _chunk7TM3MH3Qcjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunk7TM3MH3Qcjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunk7TM3MH3Qcjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunk7TM3MH3Qcjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunk7TM3MH3Qcjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunk7TM3MH3Qcjs.advanceOccurrence; exports.createAdapter = createAdapter; exports.createD1Adapter = _chunk7TM3MH3Qcjs.createD1Adapter; exports.createReiServer = createReiServer; exports.createSingleUserCloudflareWorker = _chunk7TM3MH3Qcjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunk7TM3MH3Qcjs.createSingleUserServer; exports.createTenantToken = createTenantToken; exports.createWebCryptoWebPush = _chunk7TM3MH3Qcjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunk7TM3MH3Qcjs.decryptFromStorage; exports.decryptPayload = _chunk7TM3MH3Qcjs.decryptPayload; exports.deriveUserEncryptionKey = _chunk7TM3MH3Qcjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunk7TM3MH3Qcjs.encryptForStorage; exports.ensureSchema = _chunk7TM3MH3Qcjs.ensureSchema; exports.getSchemaVersion = _chunk7TM3MH3Qcjs.getSchemaVersion; exports.hasChatCredRef = _chunk7TM3MH3Qcjs.hasChatCredRef; exports.isNonRetryableError = _chunk7TM3MH3Qcjs.isNonRetryableError; exports.isValidCredId = _chunk7TM3MH3Qcjs.isValidCredId; exports.isValidISO8601 = _chunk7TM3MH3Qcjs.isValidISO8601; exports.isValidTimeZoneId = _chunk7TM3MH3Qcjs.isValidTimeZoneId; exports.isValidUUID = _chunk7TM3MH3Qcjs.isValidUUID; exports.isValidUUIDv4 = _chunk7TM3MH3Qcjs.isValidUUIDv4; exports.isValidUrl = _chunk7TM3MH3Qcjs.isValidUrl; exports.measurePushPayload = _chunk7TM3MH3Qcjs.measurePushPayload; exports.nextFutureOccurrence = _chunk7TM3MH3Qcjs.nextFutureOccurrence; exports.planNextOccurrence = _chunk7TM3MH3Qcjs.planNextOccurrence; exports.readRequestBody = _chunk7TM3MH3Qcjs.readRequestBody; exports.resolveLlmCredential = _chunk7TM3MH3Qcjs.resolveLlmCredential; exports.runScheduledTick = _chunk7TM3MH3Qcjs.runScheduledTick; exports.runTask = _chunk7TM3MH3Qcjs.runTask; exports.sanitizeErrorSummary = _chunk7TM3MH3Qcjs.sanitizeErrorSummary; exports.summarizeErrorCause = _chunk7TM3MH3Qcjs.summarizeErrorCause; exports.supportsLlmCredentialsStore = _chunk7TM3MH3Qcjs.supportsLlmCredentialsStore; exports.validateAvatarUrl = _chunk7TM3MH3Qcjs.validateAvatarUrl; exports.validateCredRefs = _chunk7TM3MH3Qcjs.validateCredRefs; exports.validateCredValue = _chunk7TM3MH3Qcjs.validateCredValue; exports.validateLlmMessagesArray = _chunk7TM3MH3Qcjs.validateLlmMessagesArray; exports.validateScheduleMessagePayload = _chunk7TM3MH3Qcjs.validateScheduleMessagePayload; exports.validateSplitPattern = _chunk7TM3MH3Qcjs.validateSplitPattern; exports.verifyTenantToken = verifyTenantToken;
704
+ exports.CORS_ALLOW_HEADERS = _chunkKZT3YC62cjs.CORS_ALLOW_HEADERS; exports.CORS_ALLOW_METHODS = _chunkKZT3YC62cjs.CORS_ALLOW_METHODS; exports.CRED_ID_MAX_LENGTH = _chunkKZT3YC62cjs.CRED_ID_MAX_LENGTH; exports.CRED_PUT_BATCH_MAX = _chunkKZT3YC62cjs.CRED_PUT_BATCH_MAX; exports.CRED_REFS_MAX_ENTRIES = _chunkKZT3YC62cjs.CRED_REFS_MAX_ENTRIES; exports.CRED_ROWS_PER_USER_MAX = _chunkKZT3YC62cjs.CRED_ROWS_PER_USER_MAX; exports.DEFAULT_CLAIM_LEASE_MS = _chunkKZT3YC62cjs.DEFAULT_CLAIM_LEASE_MS; exports.DEFAULT_HEARTBEAT_LEASE_TTL_MS = _chunkKZT3YC62cjs.DEFAULT_HEARTBEAT_LEASE_TTL_MS; exports.DEFAULT_LEASE_HEARTBEAT_MS = _chunkKZT3YC62cjs.DEFAULT_LEASE_HEARTBEAT_MS; exports.DEFAULT_MAX_DELIVERY_RETRIES = _chunkKZT3YC62cjs.DEFAULT_MAX_DELIVERY_RETRIES; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkKZT3YC62cjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE = _chunkKZT3YC62cjs.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE; exports.DEFAULT_MAX_TOOL_ITERATIONS = _chunkKZT3YC62cjs.DEFAULT_MAX_TOOL_ITERATIONS; exports.DEFAULT_TOTAL_TIMEOUT_MS = _chunkKZT3YC62cjs.DEFAULT_TOTAL_TIMEOUT_MS; exports.DeploymentConfigError = _chunkKZT3YC62cjs.DeploymentConfigError; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkKZT3YC62cjs.MAX_PUSH_PAYLOAD_BYTES; exports.MAX_TASK_PAYLOAD_BYTES = _chunkKZT3YC62cjs.MAX_TASK_PAYLOAD_BYTES; exports.MIN_SCHEDULE_LEAD_MS = _chunkKZT3YC62cjs.MIN_SCHEDULE_LEAD_MS; exports.NonRetryableError = _chunkKZT3YC62cjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkKZT3YC62cjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkKZT3YC62cjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkKZT3YC62cjs.advanceOccurrence; exports.createAdapter = createAdapter; exports.createD1Adapter = _chunkKZT3YC62cjs.createD1Adapter; exports.createReiServer = createReiServer; exports.createSingleUserCloudflareWorker = _chunkKZT3YC62cjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkKZT3YC62cjs.createSingleUserServer; exports.createTenantToken = createTenantToken; exports.createWebCryptoWebPush = _chunkKZT3YC62cjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkKZT3YC62cjs.decryptFromStorage; exports.decryptPayload = _chunkKZT3YC62cjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkKZT3YC62cjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkKZT3YC62cjs.encryptForStorage; exports.ensureSchema = _chunkKZT3YC62cjs.ensureSchema; exports.getSchemaVersion = _chunkKZT3YC62cjs.getSchemaVersion; exports.hasChatCredRef = _chunkKZT3YC62cjs.hasChatCredRef; exports.isNonRetryableError = _chunkKZT3YC62cjs.isNonRetryableError; exports.isValidCredId = _chunkKZT3YC62cjs.isValidCredId; exports.isValidISO8601 = _chunkKZT3YC62cjs.isValidISO8601; exports.isValidTimeZoneId = _chunkKZT3YC62cjs.isValidTimeZoneId; exports.isValidUUID = _chunkKZT3YC62cjs.isValidUUID; exports.isValidUUIDv4 = _chunkKZT3YC62cjs.isValidUUIDv4; exports.isValidUrl = _chunkKZT3YC62cjs.isValidUrl; exports.measurePushPayload = _chunkKZT3YC62cjs.measurePushPayload; exports.nextFutureOccurrence = _chunkKZT3YC62cjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkKZT3YC62cjs.planNextOccurrence; exports.readRequestBody = _chunkKZT3YC62cjs.readRequestBody; exports.resolveLlmCredential = _chunkKZT3YC62cjs.resolveLlmCredential; exports.runScheduledTick = _chunkKZT3YC62cjs.runScheduledTick; exports.runTask = _chunkKZT3YC62cjs.runTask; exports.sanitizeErrorSummary = _chunkKZT3YC62cjs.sanitizeErrorSummary; exports.summarizeErrorCause = _chunkKZT3YC62cjs.summarizeErrorCause; exports.supportsLlmCredentialsStore = _chunkKZT3YC62cjs.supportsLlmCredentialsStore; exports.validateAvatarUrl = _chunkKZT3YC62cjs.validateAvatarUrl; exports.validateCredRefs = _chunkKZT3YC62cjs.validateCredRefs; exports.validateCredValue = _chunkKZT3YC62cjs.validateCredValue; exports.validateLlmMessagesArray = _chunkKZT3YC62cjs.validateLlmMessagesArray; exports.validateScheduleMessagePayload = _chunkKZT3YC62cjs.validateScheduleMessagePayload; exports.validateSplitPattern = _chunkKZT3YC62cjs.validateSplitPattern; exports.verifyTenantToken = verifyTenantToken;
package/dist/index.mjs CHANGED
@@ -72,7 +72,7 @@ import {
72
72
  validateLlmMessagesArray,
73
73
  validateScheduleMessagePayload,
74
74
  validateSplitPattern
75
- } from "./chunk-PG54W6B5.mjs";
75
+ } from "./chunk-INNZZFGJ.mjs";
76
76
  import "./chunk-GN44PST5.mjs";
77
77
 
78
78
  // src/server/adapters/factory.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rei-standard/amsg-server",
3
- "version": "2.6.0-next.31",
3
+ "version": "2.6.0-next.32",
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.10",
42
+ "@rei-standard/amsg-shared": "^0.4.0-next.11",
43
43
  "web-push": "^3.6.7"
44
44
  },
45
45
  "peerDependencies": {