@faapi/faapi 1.3.1 → 1.5.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
@@ -1451,6 +1451,31 @@ interface InjectResponse {
1451
1451
  headers: Headers;
1452
1452
  body: unknown;
1453
1453
  }
1454
+ /**
1455
+ * 获取当前 faapi app 单例
1456
+ *
1457
+ * 用于在无法直接拿到 app 引用的场景(如 Next.js Server Component)中访问 app。
1458
+ *
1459
+ * @returns 当前 app 实例
1460
+ * @throws 未初始化时抛错(需先调 `createProdApp()` / `createDevApp()`,或 `faapi dev` / `node dist/main` 启动)
1461
+ *
1462
+ * @example
1463
+ * ```ts
1464
+ * // Next.js RSC 中调用 faapi API(同进程,跳过 HTTP loopback)
1465
+ * import { getApp } from '@faapi/faapi';
1466
+ * import { headers } from 'next/headers';
1467
+ *
1468
+ * const app = getApp();
1469
+ * const h = await headers();
1470
+ * const res = await app.inject({
1471
+ * method: 'GET',
1472
+ * path: '/api/user',
1473
+ * headers: { cookie: h.get('cookie') ?? '', authorization: h.get('authorization') ?? '' },
1474
+ * });
1475
+ * const data = res.body; // 已解析
1476
+ * ```
1477
+ */
1478
+ declare function getApp(): AppBase;
1454
1479
  interface CreateAppOptions {
1455
1480
  /** 项目根目录,默认 process.cwd() */
1456
1481
  rootDir?: string;
@@ -1476,8 +1501,11 @@ interface AppBase {
1476
1501
  /**
1477
1502
  * 无服务器测试注入
1478
1503
  *
1479
- * 构建一个模拟请求直接走完整请求链路,不绑定端口。
1480
- * 需要在 listen() 之前调用(server 未启动时)。
1504
+ * 构建一个模拟请求直接走完整请求链路(CORS / helmet / logger / 全局中间件 / 路由匹配 /
1505
+ * schema 校验 / 目录中间件 / handler),不绑定端口,返回已解析的 `{ status, headers, body }`。
1506
+ *
1507
+ * `listen()` 前后均可调用——`listen()` 后调用常用于 Next.js Server Component 等同进程场景
1508
+ * (配合 `getApp()` 拿到 app 实例)。
1481
1509
  */
1482
1510
  inject(options?: InjectOptions): Promise<InjectResponse>;
1483
1511
  }
@@ -1532,4 +1560,4 @@ type ProdApp = AppBase;
1532
1560
  */
1533
1561
  declare function createProdApp(options?: CreateAppOptions): Promise<ProdApp>;
1534
1562
 
1535
- export { type ProdApp as App, type CorsOptions, type CreateAppOptions, type DevApp, type FaapiConfig, type FaapiContext, type FaapiContextConfig, FaapiError, type FaapiMiddleware, type FaapiPlugin, type FailOptions, type HandlerTypeInfo, type HelmetOptions, type InjectOptions, type InjectResponse, type Injector, type InjectorMap, InternalError, type LifecycleContext, type LifecycleHooks, type LoggerOptions, MessageQueue, MethodNotAllowedError, ModuleLoadError, type PluginContext, type PluginDeclaration, type ProdApp, type PropertyType, type RequestHandler, type ResponseConfig, type RouteInfo, type RouteInputSchema, type RouteManifest, RouteNotFoundError, type RouteOutputSchema, type RouteParamSchema, type RouteSchemaSource, type RuntimeType, SchemaExtractionError, type SseEvent, type SseWriter, type TestServer, type TestServerOptions, type TypeConstraint, type UpgradeHandler, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, type WsTestClient, type WsTestClientOptions, collectRouteSchemaSources, connectWs, cors, createProdApp as createApp, createContext, createDevApp, createProdApp, createProgram, createTestServer, extractTypeInfo, getInputTypeForMethod, helmet, invalidateProgramCache, invokeHandler, loadConfig, loadEnv, logger, resolveTypeNode, waitForWsOpen };
1563
+ export { type ProdApp as App, type CorsOptions, type CreateAppOptions, type DevApp, type FaapiConfig, type FaapiContext, type FaapiContextConfig, FaapiError, type FaapiMiddleware, type FaapiPlugin, type FailOptions, type HandlerTypeInfo, type HelmetOptions, type InjectOptions, type InjectResponse, type Injector, type InjectorMap, InternalError, type LifecycleContext, type LifecycleHooks, type LoggerOptions, MessageQueue, MethodNotAllowedError, ModuleLoadError, type PluginContext, type PluginDeclaration, type ProdApp, type PropertyType, type RequestHandler, type ResponseConfig, type RouteInfo, type RouteInputSchema, type RouteManifest, RouteNotFoundError, type RouteOutputSchema, type RouteParamSchema, type RouteSchemaSource, type RuntimeType, SchemaExtractionError, type SseEvent, type SseWriter, type TestServer, type TestServerOptions, type TypeConstraint, type UpgradeHandler, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, type WsTestClient, type WsTestClientOptions, collectRouteSchemaSources, connectWs, cors, createProdApp as createApp, createContext, createDevApp, createProdApp, createProgram, createTestServer, extractTypeInfo, getApp, getInputTypeForMethod, helmet, invalidateProgramCache, invokeHandler, loadConfig, loadEnv, logger, resolveTypeNode, waitForWsOpen };
package/dist/index.js CHANGED
@@ -3786,7 +3786,7 @@ async function connectWs(baseUrl, pathname, options = {}) {
3786
3786
  // src/cli/createAppCore.ts
3787
3787
  import fs13 from "fs";
3788
3788
  import path14 from "path";
3789
- import { PassThrough } from "stream";
3789
+ import { PassThrough, Readable as Readable3 } from "stream";
3790
3790
 
3791
3791
  // src/router/detectRouteConflicts.ts
3792
3792
  function detectRouteConflicts(routes) {
@@ -3931,6 +3931,15 @@ var DEFAULT_DIST = "dist";
3931
3931
  var DEFAULT_PORT = 3e3;
3932
3932
  var ROUTES_FILE = "faapi-routes.js";
3933
3933
  var PATTERNS = ["src/api/**/*.ts"];
3934
+ var currentApp = null;
3935
+ function getApp() {
3936
+ if (!currentApp) {
3937
+ throw new Error(
3938
+ "[faapi] No app instance. Call createProdApp() / createDevApp() first, or run `faapi dev` / `node dist/main`."
3939
+ );
3940
+ }
3941
+ return currentApp;
3942
+ }
3934
3943
  var FAAPI_CONFIG_KEYS = /* @__PURE__ */ new Set([
3935
3944
  "cors",
3936
3945
  "lifecycle",
@@ -4088,11 +4097,7 @@ async function createAppBase(options) {
4088
4097
  reject(new Error("No request handler found"));
4089
4098
  return;
4090
4099
  }
4091
- const mockReq = new PassThrough({
4092
- read() {
4093
- this.push(null);
4094
- }
4095
- });
4100
+ const mockReq = Readable3.from(body !== void 0 ? [Buffer.from(JSON.stringify(body))] : []);
4096
4101
  mockReq.method = method;
4097
4102
  mockReq.url = `${reqPath}${queryStr}`;
4098
4103
  mockReq.headers = {
@@ -4101,9 +4106,6 @@ async function createAppBase(options) {
4101
4106
  "content-type": body !== void 0 ? "application/json" : void 0
4102
4107
  };
4103
4108
  mockReq.socket = { remoteAddress: "127.0.0.1" };
4104
- if (body !== void 0) {
4105
- mockReq.push(JSON.stringify(body));
4106
- }
4107
4109
  handler(
4108
4110
  mockReq,
4109
4111
  mockRes
@@ -4125,17 +4127,20 @@ async function createAppBase(options) {
4125
4127
  }
4126
4128
  if (!server.listening) {
4127
4129
  app.server = null;
4130
+ if (currentApp === app) currentApp = null;
4128
4131
  return;
4129
4132
  }
4130
4133
  return new Promise((resolve) => {
4131
4134
  server.close((err) => {
4132
4135
  if (err) console.error("Error closing server:", err);
4133
4136
  app.server = null;
4137
+ if (currentApp === app) currentApp = null;
4134
4138
  resolve();
4135
4139
  });
4136
4140
  });
4137
4141
  }
4138
4142
  };
4143
+ currentApp = app;
4139
4144
  const ctx = {
4140
4145
  rootDir,
4141
4146
  dist,
@@ -4204,6 +4209,7 @@ export {
4204
4209
  createProgram,
4205
4210
  createTestServer,
4206
4211
  extractTypeInfo,
4212
+ getApp,
4207
4213
  getInputTypeForMethod,
4208
4214
  helmet,
4209
4215
  invalidateProgramCache,