@faapi/faapi 1.2.1 → 1.3.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
@@ -4574,6 +4574,41 @@ function createContext(request, params, config = {}, ip = "") {
4574
4574
  ctxWithSse.__sseResponse = writer.response;
4575
4575
  ctxWithSse.__sseWriter = writer;
4576
4576
  return writer;
4577
+ },
4578
+ /**
4579
+ * 显式包装成功响应(返回 Response,不会被自动包裹再次包装)
4580
+ *
4581
+ * 用 config.response.ok(或默认 (data) => ({ data })) 包裹 data 并返回 JSON Response。
4582
+ * handler 也可直接 return data,框架会自动用 ok 包裹,两者等价。
4583
+ */
4584
+ ok(data) {
4585
+ const responseConfig = config.response;
4586
+ const okFn = responseConfig?.ok ?? ((d) => ({ data: d }));
4587
+ const body = okFn(data);
4588
+ return ctx.json(body);
4589
+ },
4590
+ /**
4591
+ * 返回错误响应(对象形式参数,status 和 code 均可省略)
4592
+ *
4593
+ * - status 省略时 HTTP 状态码默认 500
4594
+ * - code 省略时响应 body 里不含 code 字段(默认 fail 函数只放非 undefined 的字段)
4595
+ * - status 和 code 独立无关联
4596
+ *
4597
+ * body 用 config.response.fail(或默认实现)包装。
4598
+ */
4599
+ fail(options) {
4600
+ const responseConfig = config.response;
4601
+ const failFn = responseConfig?.fail ?? ((e) => {
4602
+ const error = { message: e.message };
4603
+ if (e.code !== void 0) error.code = e.code;
4604
+ return { error };
4605
+ });
4606
+ const body = failFn({
4607
+ status: options.status,
4608
+ code: options.code,
4609
+ message: options.message
4610
+ });
4611
+ return ctx.json(body, options.status ?? 500);
4577
4612
  }
4578
4613
  };
4579
4614
  const extend = config?.extendContext;
@@ -4938,6 +4973,12 @@ var init_injectParams = __esm({
4938
4973
  });
4939
4974
 
4940
4975
  // src/runtime/invokeHandler.ts
4976
+ function wrapResult(result, ctx) {
4977
+ if (result instanceof Response) return result;
4978
+ const responseConfig = ctx.config.response;
4979
+ const okFn = responseConfig?.ok ?? ((d) => ({ data: d }));
4980
+ return okFn(result);
4981
+ }
4941
4982
  function mergeMeta(response, meta) {
4942
4983
  const hasMeta = meta.status !== void 0 || Object.keys(meta.headers).length > 0 || meta.setCookies.length > 0;
4943
4984
  if (!hasMeta) return response;
@@ -5002,7 +5043,7 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
5002
5043
  const result = await injectParamsAsync(handler, ctx, body, injectors);
5003
5044
  const sseResponse = pickSseAndAutoClose();
5004
5045
  if (sseResponse) return sseResponse;
5005
- return toResponse(result, meta);
5046
+ return toResponse(wrapResult(result, ctx), meta);
5006
5047
  } catch (err) {
5007
5048
  autoCloseSseOnError();
5008
5049
  throw err;
@@ -5013,7 +5054,7 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
5013
5054
  const result = await injectParamsAsync(handler, ctx, body, injectors);
5014
5055
  const sseResponse = pickSseAndAutoClose();
5015
5056
  if (sseResponse) return sseResponse;
5016
- return toResponse(result, meta);
5057
+ return toResponse(wrapResult(result, ctx), meta);
5017
5058
  } catch (err) {
5018
5059
  autoCloseSseOnError();
5019
5060
  throw err;
@@ -6058,41 +6099,40 @@ async function createAppBase(options) {
6058
6099
  } = injectOpts ?? {};
6059
6100
  const queryStr = query ? "?" + new URLSearchParams(Object.entries(query).map(([k, v]) => [k, String(v)])).toString() : "";
6060
6101
  return new Promise((resolve3, reject) => {
6061
- const mockRes = {
6062
- statusCode: 200,
6063
- _headers: {},
6064
- _body: Buffer.alloc(0),
6065
- setHeader(name, value) {
6066
- this._headers[name.toLowerCase()] = value;
6067
- },
6068
- appendHeader(name, value) {
6069
- const key = name.toLowerCase();
6070
- const existing = this._headers[key];
6071
- this._headers[key] = existing ? `${existing}, ${value}` : value;
6072
- },
6073
- writeHead(status, headers) {
6074
- this.statusCode = status;
6075
- if (headers) {
6076
- Object.assign(this._headers, headers);
6077
- }
6078
- },
6079
- end(data) {
6080
- const buf = Buffer.isBuffer(data) ? data : Buffer.from(data ?? "");
6081
- this._body = buf;
6082
- resolve3({
6083
- status: this.statusCode,
6084
- headers: new Headers(this._headers),
6085
- body: this.parseBody()
6086
- });
6087
- },
6088
- parseBody() {
6089
- try {
6090
- return JSON.parse(this._body.toString());
6091
- } catch {
6092
- return this._body.toString();
6093
- }
6102
+ const chunks = [];
6103
+ const mockRes = new PassThrough();
6104
+ mockRes.statusCode = 200;
6105
+ mockRes._headers = {};
6106
+ mockRes.setHeader = function(name, value) {
6107
+ this._headers[name.toLowerCase()] = value;
6108
+ };
6109
+ mockRes.appendHeader = function(name, value) {
6110
+ const key = name.toLowerCase();
6111
+ const existing = this._headers[key];
6112
+ this._headers[key] = existing ? `${existing}, ${value}` : value;
6113
+ };
6114
+ mockRes.writeHead = function(status, headers) {
6115
+ this.statusCode = status;
6116
+ if (headers) {
6117
+ Object.assign(this._headers, headers);
6094
6118
  }
6095
6119
  };
6120
+ mockRes.on("data", (chunk) => chunks.push(chunk));
6121
+ mockRes.on("error", reject);
6122
+ mockRes.on("finish", () => {
6123
+ const body2 = Buffer.concat(chunks);
6124
+ let parsed;
6125
+ try {
6126
+ parsed = JSON.parse(body2.toString());
6127
+ } catch {
6128
+ parsed = body2.toString();
6129
+ }
6130
+ resolve3({
6131
+ status: mockRes.statusCode,
6132
+ headers: new Headers(mockRes._headers),
6133
+ body: parsed
6134
+ });
6135
+ });
6096
6136
  const listeners = server.listeners("request");
6097
6137
  const handler = listeners[listeners.length - 1];
6098
6138
  if (typeof handler !== "function") {
@@ -6191,7 +6231,8 @@ var init_createAppCore = __esm({
6191
6231
  "helmet",
6192
6232
  "bodyLimit",
6193
6233
  "logger",
6194
- "http2"
6234
+ "http2",
6235
+ "response"
6195
6236
  ]);
6196
6237
  }
6197
6238
  });