@faapi/faapi 6.21.1 → 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/cli/index.js CHANGED
@@ -6367,13 +6367,28 @@ function encodeSseEvent(event) {
6367
6367
  return out;
6368
6368
  }
6369
6369
  function createSseWriter(options = {}) {
6370
- const { onFirstWrite } = options;
6370
+ const { onFirstWrite, keepOpen = false } = options;
6371
6371
  const encoder = new TextEncoder();
6372
6372
  let controller = null;
6373
6373
  let closed = false;
6374
6374
  let aborted = false;
6375
6375
  let firstWriteTriggered = false;
6376
6376
  let drainWaiters = [];
6377
+ let closeCallbacks = [];
6378
+ let closeCallbacksFired = false;
6379
+ const safeRunCallback = (callback) => {
6380
+ try {
6381
+ callback();
6382
+ } catch {
6383
+ }
6384
+ };
6385
+ const runCloseCallbacks = () => {
6386
+ if (closeCallbacksFired) return;
6387
+ closeCallbacksFired = true;
6388
+ const callbacks = closeCallbacks;
6389
+ closeCallbacks = [];
6390
+ for (const callback of callbacks) safeRunCallback(callback);
6391
+ };
6377
6392
  const resolveDrainWaiters = () => {
6378
6393
  const waiters = drainWaiters;
6379
6394
  drainWaiters = [];
@@ -6397,6 +6412,7 @@ function createSseWriter(options = {}) {
6397
6412
  aborted = true;
6398
6413
  closed = true;
6399
6414
  controller = null;
6415
+ runCloseCallbacks();
6400
6416
  resolveDrainWaiters();
6401
6417
  }
6402
6418
  },
@@ -6439,6 +6455,7 @@ function createSseWriter(options = {}) {
6439
6455
  close() {
6440
6456
  if (closed) return;
6441
6457
  closed = true;
6458
+ runCloseCallbacks();
6442
6459
  resolveDrainWaiters();
6443
6460
  if (controller) {
6444
6461
  try {
@@ -6448,6 +6465,13 @@ function createSseWriter(options = {}) {
6448
6465
  controller = null;
6449
6466
  }
6450
6467
  },
6468
+ onClose(callback) {
6469
+ if (closeCallbacksFired) {
6470
+ safeRunCallback(callback);
6471
+ return;
6472
+ }
6473
+ closeCallbacks.push(callback);
6474
+ },
6451
6475
  get closed() {
6452
6476
  return closed;
6453
6477
  },
@@ -6464,6 +6488,9 @@ function createSseWriter(options = {}) {
6464
6488
  get aborted() {
6465
6489
  return aborted;
6466
6490
  },
6491
+ get keepOpen() {
6492
+ return keepOpen;
6493
+ },
6467
6494
  get response() {
6468
6495
  return response;
6469
6496
  }
@@ -7011,10 +7038,15 @@ function createContextFromUrl(request, url, params, config = {}, ip = "", regist
7011
7038
  * 接入底层连接——流式期间字节即产即达(见 createServer.md「SSE 提前接管」)。
7012
7039
  * 无钩子场景(app.inject / 测试直调 invokeHandler)回落为 handler 返回后交出。
7013
7040
  *
7041
+ * `{ keepOpen: true }` 声明流生命周期独立于 handler 返回:handler 返回后框架
7042
+ * 不自动 close(长连接订阅模式,清理推送源用 writer.onClose);handler 抛错
7043
+ * 的兜底 close 不受影响。详见 runtime/sse.md「长连接订阅模式」。
7044
+ *
7014
7045
  * 与 ctx.json / ctx.html 互斥:一个 handler 只能用一种响应方式。
7015
7046
  */
7016
- sse() {
7047
+ sse(options) {
7017
7048
  const writer = createSseWriter({
7049
+ keepOpen: options?.keepOpen,
7018
7050
  onFirstWrite: (response) => {
7019
7051
  ctx.__earlyRespond?.(response);
7020
7052
  }
@@ -7704,7 +7736,7 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
7704
7736
  const pickSseAndAutoClose = () => {
7705
7737
  const sseWriter = ctx.__sseWriter;
7706
7738
  if (!sseWriter) return null;
7707
- if (!sseWriter.closed && !sseWriter.aborted) {
7739
+ if (!sseWriter.keepOpen && !sseWriter.closed && !sseWriter.aborted) {
7708
7740
  sseWriter.close();
7709
7741
  }
7710
7742
  return mergeMeta(sseWriter.response, meta);