@faapi/faapi 6.21.0 → 6.22.0

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/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { F as FaapiMiddleware, A as AppRegistries, R as RouteManifest, a as FaapiContext, C as CorsOptions, T as TaskClient, H as HelmetOptions, L as LogConfig, I as InjectorMap, b as TaskFailedHandler, W as WsRouteManifest, c as TaskQueueDeps, d as TaskQueue, e as TaskDriver, f as TaskRegistry, g as TaskManifest, h as ToolMetadata, i as AgentCore, j as AgentMetadata, k as CreateLoggerOptions, l as Logger } from './routeTypes-gyz4PMh7.js';
2
- export { m as AgentHandleFactory, n as AgentHandleStore, o as AgentPathMeta, p as AgentRegistry, q as AgentToolDescriptor, r as FaapiContextConfig, s as FaapiTaskMeta, t as FailOptions, u as Injector, v as LogEntry, w as LogLevel, x as LogSink, y as RouteInfo, z as RouteInputSchema, B as RouteOutputSchema, D as RouteParamSchema, S as SkillRegistry, E as SseEvent, G as SseWriter, J as TaskContext, K as TaskDriverJob, M as TaskDriverProcess, N as TaskDriverRecord, O as TaskFailedInfo, P as TaskJob, Q as TaskJobStatus, U as TaskMetadata, V as TaskModule, X as TaskRegistriesSnapshot, Y as TaskRegistriesView, Z as ToolCore, _ as ToolPathMeta, $ as ToolRegistry, a0 as cors, a1 as createAppRegistries, a2 as createTaskRegistriesView, a3 as createTaskRegistry, a4 as helmet } from './routeTypes-gyz4PMh7.js';
1
+ import { F as FaapiMiddleware, A as AppRegistries, R as RouteManifest, a as FaapiContext, C as CorsOptions, T as TaskClient, H as HelmetOptions, L as LogConfig, I as InjectorMap, b as TaskFailedHandler, W as WsRouteManifest, c as TaskQueueDeps, d as TaskQueue, e as TaskDriver, f as TaskRegistry, g as TaskManifest, h as ToolMetadata, i as AgentCore, j as AgentMetadata, k as CreateLoggerOptions, l as Logger } from './routeTypes-CXWkRx4W.js';
2
+ export { m as AgentHandleFactory, n as AgentHandleStore, o as AgentPathMeta, p as AgentRegistry, q as AgentToolDescriptor, r as FaapiContextConfig, s as FaapiTaskMeta, t as FailOptions, u as Injector, v as LogEntry, w as LogLevel, x as LogSink, y as RouteInfo, z as RouteInputSchema, B as RouteOutputSchema, D as RouteParamSchema, S as SkillRegistry, E as SseEvent, G as SseOptions, J as SseWriter, K as TaskContext, M as TaskDriverJob, N as TaskDriverProcess, O as TaskDriverRecord, P as TaskFailedInfo, Q as TaskJob, U as TaskJobStatus, V as TaskMetadata, X as TaskModule, Y as TaskRegistriesSnapshot, Z as TaskRegistriesView, _ as ToolCore, $ as ToolPathMeta, a0 as ToolRegistry, a1 as cors, a2 as createAppRegistries, a3 as createTaskRegistriesView, a4 as createTaskRegistry, a5 as helmet } from './routeTypes-CXWkRx4W.js';
3
3
  import * as node_http from 'node:http';
4
4
  import { Server, IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Socket } from 'node:net';
package/dist/index.js CHANGED
@@ -4782,13 +4782,28 @@ function encodeSseEvent(event) {
4782
4782
  return out;
4783
4783
  }
4784
4784
  function createSseWriter(options = {}) {
4785
- const { onFirstWrite } = options;
4785
+ const { onFirstWrite, keepOpen = false } = options;
4786
4786
  const encoder = new TextEncoder();
4787
4787
  let controller = null;
4788
4788
  let closed = false;
4789
4789
  let aborted = false;
4790
4790
  let firstWriteTriggered = false;
4791
4791
  let drainWaiters = [];
4792
+ let closeCallbacks = [];
4793
+ let closeCallbacksFired = false;
4794
+ const safeRunCallback = (callback) => {
4795
+ try {
4796
+ callback();
4797
+ } catch {
4798
+ }
4799
+ };
4800
+ const runCloseCallbacks = () => {
4801
+ if (closeCallbacksFired) return;
4802
+ closeCallbacksFired = true;
4803
+ const callbacks = closeCallbacks;
4804
+ closeCallbacks = [];
4805
+ for (const callback of callbacks) safeRunCallback(callback);
4806
+ };
4792
4807
  const resolveDrainWaiters = () => {
4793
4808
  const waiters = drainWaiters;
4794
4809
  drainWaiters = [];
@@ -4812,6 +4827,7 @@ function createSseWriter(options = {}) {
4812
4827
  aborted = true;
4813
4828
  closed = true;
4814
4829
  controller = null;
4830
+ runCloseCallbacks();
4815
4831
  resolveDrainWaiters();
4816
4832
  }
4817
4833
  },
@@ -4854,6 +4870,7 @@ function createSseWriter(options = {}) {
4854
4870
  close() {
4855
4871
  if (closed) return;
4856
4872
  closed = true;
4873
+ runCloseCallbacks();
4857
4874
  resolveDrainWaiters();
4858
4875
  if (controller) {
4859
4876
  try {
@@ -4863,6 +4880,13 @@ function createSseWriter(options = {}) {
4863
4880
  controller = null;
4864
4881
  }
4865
4882
  },
4883
+ onClose(callback) {
4884
+ if (closeCallbacksFired) {
4885
+ safeRunCallback(callback);
4886
+ return;
4887
+ }
4888
+ closeCallbacks.push(callback);
4889
+ },
4866
4890
  get closed() {
4867
4891
  return closed;
4868
4892
  },
@@ -4879,6 +4903,9 @@ function createSseWriter(options = {}) {
4879
4903
  get aborted() {
4880
4904
  return aborted;
4881
4905
  },
4906
+ get keepOpen() {
4907
+ return keepOpen;
4908
+ },
4882
4909
  get response() {
4883
4910
  return response;
4884
4911
  }
@@ -5088,10 +5115,15 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
5088
5115
  * 接入底层连接——流式期间字节即产即达(见 createServer.md「SSE 提前接管」)。
5089
5116
  * 无钩子场景(app.inject / 测试直调 invokeHandler)回落为 handler 返回后交出。
5090
5117
  *
5118
+ * `{ keepOpen: true }` 声明流生命周期独立于 handler 返回:handler 返回后框架
5119
+ * 不自动 close(长连接订阅模式,清理推送源用 writer.onClose);handler 抛错
5120
+ * 的兜底 close 不受影响。详见 runtime/sse.md「长连接订阅模式」。
5121
+ *
5091
5122
  * 与 ctx.json / ctx.html 互斥:一个 handler 只能用一种响应方式。
5092
5123
  */
5093
- sse() {
5124
+ sse(options) {
5094
5125
  const writer = createSseWriter({
5126
+ keepOpen: options?.keepOpen,
5095
5127
  onFirstWrite: (response) => {
5096
5128
  ctx.__earlyRespond?.(response);
5097
5129
  }
@@ -5491,7 +5523,7 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
5491
5523
  const pickSseAndAutoClose = () => {
5492
5524
  const sseWriter = ctx.__sseWriter;
5493
5525
  if (!sseWriter) return null;
5494
- if (!sseWriter.closed && !sseWriter.aborted) {
5526
+ if (!sseWriter.keepOpen && !sseWriter.closed && !sseWriter.aborted) {
5495
5527
  sseWriter.close();
5496
5528
  }
5497
5529
  return mergeMeta(sseWriter.response, meta);