@lark-apaas/fullstack-nestjs-core 1.1.34-alpha.61 → 1.1.34-alpha.63

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.cjs CHANGED
@@ -34423,7 +34423,8 @@ __export(index_exports, {
34423
34423
  UserContextMiddleware: () => UserContextMiddleware,
34424
34424
  ViewContextMiddleware: () => ViewContextMiddleware,
34425
34425
  configureApp: () => configureApp,
34426
- createLegacyPathRedirectMiddleware: () => createLegacyPathRedirectMiddleware
34426
+ createLegacyPathRedirectMiddleware: () => createLegacyPathRedirectMiddleware,
34427
+ registerOpenApiSpecEndpoint: () => registerOpenApiSpecEndpoint
34427
34428
  });
34428
34429
  module.exports = __toCommonJS(index_exports);
34429
34430
 
@@ -34627,32 +34628,31 @@ var ViewContextMiddleware = class _ViewContextMiddleware {
34627
34628
  constructor(client) {
34628
34629
  this.client = client;
34629
34630
  }
34630
- async getAppPublished(appId) {
34631
+ async getAppInfo(appId) {
34631
34632
  if (!appId) {
34632
- this.logger.warn(`appId is empty, skip get app published`);
34633
+ this.logger.warn(`appId is empty, skip get app info`);
34633
34634
  return null;
34634
34635
  }
34635
34636
  try {
34636
34637
  const resp = await this.client.get(`/b/${appId}/get_published_v2`);
34637
34638
  if (resp.status !== 200) {
34638
- throw new Error(`Failed to get app published, status: ${resp.status}`);
34639
+ throw new Error(`Failed to get app info, status: ${resp.status}`);
34639
34640
  }
34640
34641
  const data = await resp.json();
34641
34642
  if (data.status_code !== "0") {
34642
- throw new Error(`Failed to get app published, status_code: ${data.status_code}`);
34643
+ throw new Error(`Failed to get app info, status_code: ${data.status_code}`);
34643
34644
  }
34644
- return data.data ?? null;
34645
+ return data.data.app_info ?? {};
34645
34646
  } catch (err) {
34646
- this.logger.error(err, "Failed to get app published");
34647
+ this.logger.error(err, "Failed to get app info");
34647
34648
  return null;
34648
34649
  }
34649
34650
  }
34650
34651
  async use(req, res, next) {
34651
34652
  const { userId, tenantId, appId, loginUrl, userType } = req.userContext;
34652
34653
  const csrfToken = req.csrfToken;
34654
+ const appInfo = await this.getAppInfo(appId);
34653
34655
  const environment = mapToWindowEnvironment(process.env.FORCE_FRAMEWORK_ENVIRONMENT);
34654
- const appPublishedData = await this.getAppPublished(appId);
34655
- const appInfo = appPublishedData?.app_info ?? null;
34656
34656
  req.__platform_data__ = {
34657
34657
  csrfToken: csrfToken ?? "",
34658
34658
  userId: userId ?? "",
@@ -34663,9 +34663,7 @@ var ViewContextMiddleware = class _ViewContextMiddleware {
34663
34663
  loginUrl: loginUrl ?? "",
34664
34664
  userType: userType ?? "",
34665
34665
  tenantId,
34666
- environment,
34667
- showBadge: appInfo?.show_badge !== false,
34668
- appPublished: appPublishedData ?? null
34666
+ environment
34669
34667
  };
34670
34668
  res.locals = {
34671
34669
  ...res.locals ?? {},
@@ -34776,18 +34774,24 @@ function createApiNotFoundResponse(req) {
34776
34774
  };
34777
34775
  }
34778
34776
  __name(createApiNotFoundResponse, "createApiNotFoundResponse");
34779
- function getApiPathPrefix() {
34777
+ function getApiPathPrefixes() {
34780
34778
  const globalPrefix = process.env.CLIENT_BASE_PATH ?? "";
34781
34779
  if (!globalPrefix) {
34782
- return "/api/";
34780
+ return [
34781
+ "/api/",
34782
+ "/openapi/"
34783
+ ];
34783
34784
  }
34784
34785
  const normalizedPrefix = globalPrefix.replace(/\/+$/, "");
34785
- return `${normalizedPrefix}/api/`;
34786
+ return [
34787
+ `${normalizedPrefix}/api/`,
34788
+ `${normalizedPrefix}/openapi/`
34789
+ ];
34786
34790
  }
34787
- __name(getApiPathPrefix, "getApiPathPrefix");
34791
+ __name(getApiPathPrefixes, "getApiPathPrefixes");
34788
34792
  function apiResponseInterceptor(req, res, next) {
34789
- const apiPrefix = getApiPathPrefix();
34790
- if (!req.baseUrl.startsWith(apiPrefix)) {
34793
+ const apiPrefixes = getApiPathPrefixes();
34794
+ if (!apiPrefixes.some((prefix) => req.baseUrl.startsWith(prefix))) {
34791
34795
  return next();
34792
34796
  }
34793
34797
  res.render = function() {
@@ -36440,16 +36444,18 @@ var PlatformModule = class _PlatformModule {
36440
36444
  */
36441
36445
  configure(consumer) {
36442
36446
  const options = _PlatformModule.moduleOptions;
36443
- consumer.apply(apiResponseInterceptor).forRoutes("/api/*");
36447
+ consumer.apply(apiResponseInterceptor).forRoutes("/api/*", "/openapi/*");
36444
36448
  if (process.env.NODE_ENV === "development") {
36445
36449
  consumer.apply(FrameworkDebugMiddleware).forRoutes("/api/__framework__/debug");
36446
36450
  }
36447
36451
  consumer.apply(UserContextMiddleware, RequestContextMiddleware, import_nestjs_logger2.LoggerContextMiddleware, import_nestjs_observable.ObservableTraceMiddleware, ...DISABLE_DATAPASS ? [] : [
36448
36452
  import_nestjs_datapaas.SqlExecutionContextMiddleware
36449
36453
  ]).forRoutes("/*");
36450
- consumer.apply(CsrfTokenMiddleware, ViewContextMiddleware, HtmlHotUpdateViewMiddleware).exclude("/api/(.*)", "/static/(.*)").forRoutes("*");
36454
+ consumer.apply(CsrfTokenMiddleware, ViewContextMiddleware, HtmlHotUpdateViewMiddleware).exclude("/api/(.*)", "/openapi/(.*)", "/static/(.*)").forRoutes("*");
36451
36455
  if (options.enableCsrf !== false) {
36452
- const csrfRoutes = options.csrfRoutes || "/api/*";
36456
+ const csrfRoutes = options.csrfRoutes || [
36457
+ "/api/*"
36458
+ ];
36453
36459
  if (Array.isArray(csrfRoutes)) {
36454
36460
  csrfRoutes.forEach((route) => {
36455
36461
  consumer.apply(CsrfMiddleware).forRoutes(route);
@@ -36506,6 +36512,108 @@ function createLegacyPathRedirectMiddleware() {
36506
36512
  }
36507
36513
  __name(createLegacyPathRedirectMiddleware, "createLegacyPathRedirectMiddleware");
36508
36514
 
36515
+ // src/middlewares/openapi-spec/index.ts
36516
+ var import_swagger3 = require("@nestjs/swagger");
36517
+ function registerOpenApiSpecEndpoint(app) {
36518
+ const globalPrefix = process.env.CLIENT_BASE_PATH ?? "";
36519
+ let cachedResult = null;
36520
+ const httpAdapter = app.getHttpAdapter();
36521
+ httpAdapter.get(`${globalPrefix}/api/__framework__/openapi-spec`, (_req, res) => {
36522
+ try {
36523
+ if (!cachedResult) {
36524
+ const config = new import_swagger3.DocumentBuilder().setTitle("OpenAPI Spec").setVersion("1.0").build();
36525
+ const spec = import_swagger3.SwaggerModule.createDocument(app, config);
36526
+ cachedResult = buildFilteredSpec(spec, globalPrefix);
36527
+ }
36528
+ res.json(cachedResult);
36529
+ } catch (err) {
36530
+ console.error("[openapi-spec] Failed to generate spec:", err);
36531
+ res.json({
36532
+ openapi: "3.0.0",
36533
+ paths: {},
36534
+ components: {
36535
+ schemas: {}
36536
+ }
36537
+ });
36538
+ }
36539
+ });
36540
+ console.log(`[OpenAPI] Registered GET ${globalPrefix}/api/__framework__/openapi-spec`);
36541
+ }
36542
+ __name(registerOpenApiSpecEndpoint, "registerOpenApiSpecEndpoint");
36543
+ function buildFilteredSpec(spec, globalPrefix) {
36544
+ const schemas = spec.components?.schemas ?? {};
36545
+ const paths = spec.paths ?? {};
36546
+ const filteredPaths = {};
36547
+ for (const [pathKey, methods] of Object.entries(paths)) {
36548
+ const cleanPath = stripPrefix(pathKey, globalPrefix);
36549
+ if (!cleanPath.startsWith("/openapi")) continue;
36550
+ filteredPaths[cleanPath] = {};
36551
+ for (const [method, operation] of Object.entries(methods)) {
36552
+ if ([
36553
+ "parameters",
36554
+ "summary",
36555
+ "description",
36556
+ "servers"
36557
+ ].includes(method)) continue;
36558
+ filteredPaths[cleanPath][method] = resolveRefsDeep(structuredClone(operation), schemas);
36559
+ }
36560
+ }
36561
+ return {
36562
+ openapi: spec.openapi,
36563
+ paths: filteredPaths,
36564
+ components: {
36565
+ schemas: resolveAllSchemaRefs(structuredClone(schemas))
36566
+ }
36567
+ };
36568
+ }
36569
+ __name(buildFilteredSpec, "buildFilteredSpec");
36570
+ function stripPrefix(path2, prefix) {
36571
+ if (prefix && path2.startsWith(prefix)) {
36572
+ return path2.slice(prefix.length);
36573
+ }
36574
+ return path2;
36575
+ }
36576
+ __name(stripPrefix, "stripPrefix");
36577
+ var MAX_REF_DEPTH = 5;
36578
+ function resolveRefsDeep(obj, schemas, depth = 0) {
36579
+ if (depth > MAX_REF_DEPTH || obj === null || obj === void 0) return obj;
36580
+ if (typeof obj !== "object") return obj;
36581
+ if (Array.isArray(obj)) {
36582
+ return obj.map((item) => resolveRefsDeep(item, schemas, depth));
36583
+ }
36584
+ const record = obj;
36585
+ if (typeof record["$ref"] === "string") {
36586
+ const resolved = resolveRef(record["$ref"], schemas);
36587
+ if (resolved !== void 0) {
36588
+ return resolveRefsDeep(structuredClone(resolved), schemas, depth + 1);
36589
+ }
36590
+ return record;
36591
+ }
36592
+ const result = {};
36593
+ for (const [key, value] of Object.entries(record)) {
36594
+ result[key] = resolveRefsDeep(value, schemas, depth);
36595
+ }
36596
+ return result;
36597
+ }
36598
+ __name(resolveRefsDeep, "resolveRefsDeep");
36599
+ function resolveRef(ref, schemas) {
36600
+ const prefix = "#/components/schemas/";
36601
+ if (ref.startsWith(prefix)) {
36602
+ const name = ref.slice(prefix.length);
36603
+ return schemas[name];
36604
+ }
36605
+ return void 0;
36606
+ }
36607
+ __name(resolveRef, "resolveRef");
36608
+ function resolveAllSchemaRefs(schemas) {
36609
+ const result = {};
36610
+ for (const [name, schema] of Object.entries(schemas)) {
36611
+ result[name] = resolveRefsDeep(schema, schemas);
36612
+ }
36613
+ return result;
36614
+ }
36615
+ __name(resolveAllSchemaRefs, "resolveAllSchemaRefs");
36616
+
36509
36617
  // src/setup.ts
36510
36618
  var DEFAULT_BODY_LIMIT = "1mb";
36511
36619
  var defaultPerms = {
@@ -36538,6 +36646,9 @@ async function configureApp(app, perms = defaultPerms) {
36538
36646
  console.error("[OpenAPI] OpenAPI \u751F\u6210\u5931\u8D25:", err);
36539
36647
  }
36540
36648
  }
36649
+ if (process.env.NODE_ENV !== "production") {
36650
+ registerOpenApiSpecEndpoint(app);
36651
+ }
36541
36652
  console.log("App Started Successfully.");
36542
36653
  }
36543
36654
  __name(configureApp, "configureApp");
@@ -36574,6 +36685,7 @@ var import_nestjs_authzpaas2 = require("@lark-apaas/nestjs-authzpaas");
36574
36685
  ViewContextMiddleware,
36575
36686
  configureApp,
36576
36687
  createLegacyPathRedirectMiddleware,
36688
+ registerOpenApiSpecEndpoint,
36577
36689
  ...require("@lark-apaas/nestjs-authnpaas"),
36578
36690
  ...require("@lark-apaas/nestjs-capability"),
36579
36691
  ...require("@lark-apaas/nestjs-datapaas"),
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { NestModule, DynamicModule, MiddlewareConsumer, OnModuleInit, NestMiddleware } from '@nestjs/common';
1
+ import { NestModule, DynamicModule, MiddlewareConsumer, OnModuleInit, NestMiddleware, INestApplication } from '@nestjs/common';
2
2
  import { HttpClientConfig, PlatformPluginOptions, HttpClient } from '@lark-apaas/http-client';
3
3
  import { AuthZPaasModuleOptions } from '@lark-apaas/nestjs-authzpaas';
4
4
  export { AddMembersParams, AuthZPaasModule, AuthorizationSDK, Can, CanRole, ChatSimpleDTO, CommonParam, CreateRoleParams, CreateRoleResponse, DepartmentDTO, DepartmentEntity, DepartmentSimpleDTO, FilterParams, ForceRoleDTO, I18nText, IPermissionResolver, ListMembersParams, ListMembersResponse, ListRolesParams, MemberMutationData, MemberType, PERMISSION_RESOLVER_TOKEN, PermissionPoint, PermissionRequirement, PresetGroupDTO, RemoveMembersParams, RoleMemberDTO, SearchChatEntity, SearchParams, SearchResponse, SearchResult, SearchUserEntity, UpdateRoleParams, UserSimpleDTO } from '@lark-apaas/nestjs-authzpaas';
@@ -201,7 +201,7 @@ declare class ViewContextMiddleware implements NestMiddleware {
201
201
  private readonly client;
202
202
  private readonly logger;
203
203
  constructor(client: PlatformHttpClient);
204
- private getAppPublished;
204
+ private getAppInfo;
205
205
  use(req: Request, res: Response, next: NextFunction): Promise<void>;
206
206
  }
207
207
 
@@ -221,6 +221,14 @@ declare class ViewContextMiddleware implements NestMiddleware {
221
221
  */
222
222
  declare function createLegacyPathRedirectMiddleware(): (req: Request, res: Response, next: NextFunction) => void;
223
223
 
224
+ /**
225
+ * 注册 OpenAPI spec 端点(仅开发环境)
226
+ *
227
+ * 在 NestJS 进程中注册 GET /api/__framework__/openapi-spec,
228
+ * 返回过滤后的 OpenAPI 3.0 子集(仅 /openapi/** 路由,$ref 已解引用)。
229
+ */
230
+ declare function registerOpenApiSpecEndpoint(app: INestApplication): void;
231
+
224
232
  /**
225
233
  * API 404 响应格式
226
234
  */
@@ -401,4 +409,4 @@ declare class PlatformHttpClientService {
401
409
  private registerInterceptorsForClient;
402
410
  }
403
411
 
404
- export { type ApiNotFoundResponse, CsrfMiddleware, CsrfTokenMiddleware, FileService, HtmlHotUpdateModule, HtmlHotUpdateService, type PlatformHttpClientOptions, PlatformHttpClientService, PlatformModule, type PlatformModuleOptions, StaticModule, UserContextMiddleware, ViewContextMiddleware, configureApp, createLegacyPathRedirectMiddleware };
412
+ export { type ApiNotFoundResponse, CsrfMiddleware, CsrfTokenMiddleware, FileService, HtmlHotUpdateModule, HtmlHotUpdateService, type PlatformHttpClientOptions, PlatformHttpClientService, PlatformModule, type PlatformModuleOptions, StaticModule, UserContextMiddleware, ViewContextMiddleware, configureApp, createLegacyPathRedirectMiddleware, registerOpenApiSpecEndpoint };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { NestModule, DynamicModule, MiddlewareConsumer, OnModuleInit, NestMiddleware } from '@nestjs/common';
1
+ import { NestModule, DynamicModule, MiddlewareConsumer, OnModuleInit, NestMiddleware, INestApplication } from '@nestjs/common';
2
2
  import { HttpClientConfig, PlatformPluginOptions, HttpClient } from '@lark-apaas/http-client';
3
3
  import { AuthZPaasModuleOptions } from '@lark-apaas/nestjs-authzpaas';
4
4
  export { AddMembersParams, AuthZPaasModule, AuthorizationSDK, Can, CanRole, ChatSimpleDTO, CommonParam, CreateRoleParams, CreateRoleResponse, DepartmentDTO, DepartmentEntity, DepartmentSimpleDTO, FilterParams, ForceRoleDTO, I18nText, IPermissionResolver, ListMembersParams, ListMembersResponse, ListRolesParams, MemberMutationData, MemberType, PERMISSION_RESOLVER_TOKEN, PermissionPoint, PermissionRequirement, PresetGroupDTO, RemoveMembersParams, RoleMemberDTO, SearchChatEntity, SearchParams, SearchResponse, SearchResult, SearchUserEntity, UpdateRoleParams, UserSimpleDTO } from '@lark-apaas/nestjs-authzpaas';
@@ -201,7 +201,7 @@ declare class ViewContextMiddleware implements NestMiddleware {
201
201
  private readonly client;
202
202
  private readonly logger;
203
203
  constructor(client: PlatformHttpClient);
204
- private getAppPublished;
204
+ private getAppInfo;
205
205
  use(req: Request, res: Response, next: NextFunction): Promise<void>;
206
206
  }
207
207
 
@@ -221,6 +221,14 @@ declare class ViewContextMiddleware implements NestMiddleware {
221
221
  */
222
222
  declare function createLegacyPathRedirectMiddleware(): (req: Request, res: Response, next: NextFunction) => void;
223
223
 
224
+ /**
225
+ * 注册 OpenAPI spec 端点(仅开发环境)
226
+ *
227
+ * 在 NestJS 进程中注册 GET /api/__framework__/openapi-spec,
228
+ * 返回过滤后的 OpenAPI 3.0 子集(仅 /openapi/** 路由,$ref 已解引用)。
229
+ */
230
+ declare function registerOpenApiSpecEndpoint(app: INestApplication): void;
231
+
224
232
  /**
225
233
  * API 404 响应格式
226
234
  */
@@ -401,4 +409,4 @@ declare class PlatformHttpClientService {
401
409
  private registerInterceptorsForClient;
402
410
  }
403
411
 
404
- export { type ApiNotFoundResponse, CsrfMiddleware, CsrfTokenMiddleware, FileService, HtmlHotUpdateModule, HtmlHotUpdateService, type PlatformHttpClientOptions, PlatformHttpClientService, PlatformModule, type PlatformModuleOptions, StaticModule, UserContextMiddleware, ViewContextMiddleware, configureApp, createLegacyPathRedirectMiddleware };
412
+ export { type ApiNotFoundResponse, CsrfMiddleware, CsrfTokenMiddleware, FileService, HtmlHotUpdateModule, HtmlHotUpdateService, type PlatformHttpClientOptions, PlatformHttpClientService, PlatformModule, type PlatformModuleOptions, StaticModule, UserContextMiddleware, ViewContextMiddleware, configureApp, createLegacyPathRedirectMiddleware, registerOpenApiSpecEndpoint };
package/dist/index.js CHANGED
@@ -34600,32 +34600,31 @@ var ViewContextMiddleware = class _ViewContextMiddleware {
34600
34600
  constructor(client) {
34601
34601
  this.client = client;
34602
34602
  }
34603
- async getAppPublished(appId) {
34603
+ async getAppInfo(appId) {
34604
34604
  if (!appId) {
34605
- this.logger.warn(`appId is empty, skip get app published`);
34605
+ this.logger.warn(`appId is empty, skip get app info`);
34606
34606
  return null;
34607
34607
  }
34608
34608
  try {
34609
34609
  const resp = await this.client.get(`/b/${appId}/get_published_v2`);
34610
34610
  if (resp.status !== 200) {
34611
- throw new Error(`Failed to get app published, status: ${resp.status}`);
34611
+ throw new Error(`Failed to get app info, status: ${resp.status}`);
34612
34612
  }
34613
34613
  const data = await resp.json();
34614
34614
  if (data.status_code !== "0") {
34615
- throw new Error(`Failed to get app published, status_code: ${data.status_code}`);
34615
+ throw new Error(`Failed to get app info, status_code: ${data.status_code}`);
34616
34616
  }
34617
- return data.data ?? null;
34617
+ return data.data.app_info ?? {};
34618
34618
  } catch (err) {
34619
- this.logger.error(err, "Failed to get app published");
34619
+ this.logger.error(err, "Failed to get app info");
34620
34620
  return null;
34621
34621
  }
34622
34622
  }
34623
34623
  async use(req, res, next) {
34624
34624
  const { userId, tenantId, appId, loginUrl, userType } = req.userContext;
34625
34625
  const csrfToken = req.csrfToken;
34626
+ const appInfo = await this.getAppInfo(appId);
34626
34627
  const environment = mapToWindowEnvironment(process.env.FORCE_FRAMEWORK_ENVIRONMENT);
34627
- const appPublishedData = await this.getAppPublished(appId);
34628
- const appInfo = appPublishedData?.app_info ?? null;
34629
34628
  req.__platform_data__ = {
34630
34629
  csrfToken: csrfToken ?? "",
34631
34630
  userId: userId ?? "",
@@ -34636,9 +34635,7 @@ var ViewContextMiddleware = class _ViewContextMiddleware {
34636
34635
  loginUrl: loginUrl ?? "",
34637
34636
  userType: userType ?? "",
34638
34637
  tenantId,
34639
- environment,
34640
- showBadge: appInfo?.show_badge !== false,
34641
- appPublished: appPublishedData ?? null
34638
+ environment
34642
34639
  };
34643
34640
  res.locals = {
34644
34641
  ...res.locals ?? {},
@@ -34749,18 +34746,24 @@ function createApiNotFoundResponse(req) {
34749
34746
  };
34750
34747
  }
34751
34748
  __name(createApiNotFoundResponse, "createApiNotFoundResponse");
34752
- function getApiPathPrefix() {
34749
+ function getApiPathPrefixes() {
34753
34750
  const globalPrefix = process.env.CLIENT_BASE_PATH ?? "";
34754
34751
  if (!globalPrefix) {
34755
- return "/api/";
34752
+ return [
34753
+ "/api/",
34754
+ "/openapi/"
34755
+ ];
34756
34756
  }
34757
34757
  const normalizedPrefix = globalPrefix.replace(/\/+$/, "");
34758
- return `${normalizedPrefix}/api/`;
34758
+ return [
34759
+ `${normalizedPrefix}/api/`,
34760
+ `${normalizedPrefix}/openapi/`
34761
+ ];
34759
34762
  }
34760
- __name(getApiPathPrefix, "getApiPathPrefix");
34763
+ __name(getApiPathPrefixes, "getApiPathPrefixes");
34761
34764
  function apiResponseInterceptor(req, res, next) {
34762
- const apiPrefix = getApiPathPrefix();
34763
- if (!req.baseUrl.startsWith(apiPrefix)) {
34765
+ const apiPrefixes = getApiPathPrefixes();
34766
+ if (!apiPrefixes.some((prefix) => req.baseUrl.startsWith(prefix))) {
34764
34767
  return next();
34765
34768
  }
34766
34769
  res.render = function() {
@@ -36413,16 +36416,18 @@ var PlatformModule = class _PlatformModule {
36413
36416
  */
36414
36417
  configure(consumer) {
36415
36418
  const options = _PlatformModule.moduleOptions;
36416
- consumer.apply(apiResponseInterceptor).forRoutes("/api/*");
36419
+ consumer.apply(apiResponseInterceptor).forRoutes("/api/*", "/openapi/*");
36417
36420
  if (process.env.NODE_ENV === "development") {
36418
36421
  consumer.apply(FrameworkDebugMiddleware).forRoutes("/api/__framework__/debug");
36419
36422
  }
36420
36423
  consumer.apply(UserContextMiddleware, RequestContextMiddleware, LoggerContextMiddleware, ObservableTraceMiddleware, ...DISABLE_DATAPASS ? [] : [
36421
36424
  SqlExecutionContextMiddleware
36422
36425
  ]).forRoutes("/*");
36423
- consumer.apply(CsrfTokenMiddleware, ViewContextMiddleware, HtmlHotUpdateViewMiddleware).exclude("/api/(.*)", "/static/(.*)").forRoutes("*");
36426
+ consumer.apply(CsrfTokenMiddleware, ViewContextMiddleware, HtmlHotUpdateViewMiddleware).exclude("/api/(.*)", "/openapi/(.*)", "/static/(.*)").forRoutes("*");
36424
36427
  if (options.enableCsrf !== false) {
36425
- const csrfRoutes = options.csrfRoutes || "/api/*";
36428
+ const csrfRoutes = options.csrfRoutes || [
36429
+ "/api/*"
36430
+ ];
36426
36431
  if (Array.isArray(csrfRoutes)) {
36427
36432
  csrfRoutes.forEach((route) => {
36428
36433
  consumer.apply(CsrfMiddleware).forRoutes(route);
@@ -36479,6 +36484,108 @@ function createLegacyPathRedirectMiddleware() {
36479
36484
  }
36480
36485
  __name(createLegacyPathRedirectMiddleware, "createLegacyPathRedirectMiddleware");
36481
36486
 
36487
+ // src/middlewares/openapi-spec/index.ts
36488
+ import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
36489
+ function registerOpenApiSpecEndpoint(app) {
36490
+ const globalPrefix = process.env.CLIENT_BASE_PATH ?? "";
36491
+ let cachedResult = null;
36492
+ const httpAdapter = app.getHttpAdapter();
36493
+ httpAdapter.get(`${globalPrefix}/api/__framework__/openapi-spec`, (_req, res) => {
36494
+ try {
36495
+ if (!cachedResult) {
36496
+ const config = new DocumentBuilder().setTitle("OpenAPI Spec").setVersion("1.0").build();
36497
+ const spec = SwaggerModule.createDocument(app, config);
36498
+ cachedResult = buildFilteredSpec(spec, globalPrefix);
36499
+ }
36500
+ res.json(cachedResult);
36501
+ } catch (err) {
36502
+ console.error("[openapi-spec] Failed to generate spec:", err);
36503
+ res.json({
36504
+ openapi: "3.0.0",
36505
+ paths: {},
36506
+ components: {
36507
+ schemas: {}
36508
+ }
36509
+ });
36510
+ }
36511
+ });
36512
+ console.log(`[OpenAPI] Registered GET ${globalPrefix}/api/__framework__/openapi-spec`);
36513
+ }
36514
+ __name(registerOpenApiSpecEndpoint, "registerOpenApiSpecEndpoint");
36515
+ function buildFilteredSpec(spec, globalPrefix) {
36516
+ const schemas = spec.components?.schemas ?? {};
36517
+ const paths = spec.paths ?? {};
36518
+ const filteredPaths = {};
36519
+ for (const [pathKey, methods] of Object.entries(paths)) {
36520
+ const cleanPath = stripPrefix(pathKey, globalPrefix);
36521
+ if (!cleanPath.startsWith("/openapi")) continue;
36522
+ filteredPaths[cleanPath] = {};
36523
+ for (const [method, operation] of Object.entries(methods)) {
36524
+ if ([
36525
+ "parameters",
36526
+ "summary",
36527
+ "description",
36528
+ "servers"
36529
+ ].includes(method)) continue;
36530
+ filteredPaths[cleanPath][method] = resolveRefsDeep(structuredClone(operation), schemas);
36531
+ }
36532
+ }
36533
+ return {
36534
+ openapi: spec.openapi,
36535
+ paths: filteredPaths,
36536
+ components: {
36537
+ schemas: resolveAllSchemaRefs(structuredClone(schemas))
36538
+ }
36539
+ };
36540
+ }
36541
+ __name(buildFilteredSpec, "buildFilteredSpec");
36542
+ function stripPrefix(path2, prefix) {
36543
+ if (prefix && path2.startsWith(prefix)) {
36544
+ return path2.slice(prefix.length);
36545
+ }
36546
+ return path2;
36547
+ }
36548
+ __name(stripPrefix, "stripPrefix");
36549
+ var MAX_REF_DEPTH = 5;
36550
+ function resolveRefsDeep(obj, schemas, depth = 0) {
36551
+ if (depth > MAX_REF_DEPTH || obj === null || obj === void 0) return obj;
36552
+ if (typeof obj !== "object") return obj;
36553
+ if (Array.isArray(obj)) {
36554
+ return obj.map((item) => resolveRefsDeep(item, schemas, depth));
36555
+ }
36556
+ const record = obj;
36557
+ if (typeof record["$ref"] === "string") {
36558
+ const resolved = resolveRef(record["$ref"], schemas);
36559
+ if (resolved !== void 0) {
36560
+ return resolveRefsDeep(structuredClone(resolved), schemas, depth + 1);
36561
+ }
36562
+ return record;
36563
+ }
36564
+ const result = {};
36565
+ for (const [key, value] of Object.entries(record)) {
36566
+ result[key] = resolveRefsDeep(value, schemas, depth);
36567
+ }
36568
+ return result;
36569
+ }
36570
+ __name(resolveRefsDeep, "resolveRefsDeep");
36571
+ function resolveRef(ref, schemas) {
36572
+ const prefix = "#/components/schemas/";
36573
+ if (ref.startsWith(prefix)) {
36574
+ const name = ref.slice(prefix.length);
36575
+ return schemas[name];
36576
+ }
36577
+ return void 0;
36578
+ }
36579
+ __name(resolveRef, "resolveRef");
36580
+ function resolveAllSchemaRefs(schemas) {
36581
+ const result = {};
36582
+ for (const [name, schema] of Object.entries(schemas)) {
36583
+ result[name] = resolveRefsDeep(schema, schemas);
36584
+ }
36585
+ return result;
36586
+ }
36587
+ __name(resolveAllSchemaRefs, "resolveAllSchemaRefs");
36588
+
36482
36589
  // src/setup.ts
36483
36590
  var DEFAULT_BODY_LIMIT = "1mb";
36484
36591
  var defaultPerms = {
@@ -36511,6 +36618,9 @@ async function configureApp(app, perms = defaultPerms) {
36511
36618
  console.error("[OpenAPI] OpenAPI \u751F\u6210\u5931\u8D25:", err);
36512
36619
  }
36513
36620
  }
36621
+ if (process.env.NODE_ENV !== "production") {
36622
+ registerOpenApiSpecEndpoint(app);
36623
+ }
36514
36624
  console.log("App Started Successfully.");
36515
36625
  }
36516
36626
  __name(configureApp, "configureApp");
@@ -36545,7 +36655,8 @@ export {
36545
36655
  UserContextMiddleware,
36546
36656
  ViewContextMiddleware,
36547
36657
  configureApp,
36548
- createLegacyPathRedirectMiddleware
36658
+ createLegacyPathRedirectMiddleware,
36659
+ registerOpenApiSpecEndpoint
36549
36660
  };
36550
36661
  /*! Bundled license information:
36551
36662
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-nestjs-core",
3
- "version": "1.1.34-alpha.61",
3
+ "version": "1.1.34-alpha.63",
4
4
  "description": "FullStack Nestjs Core",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -45,7 +45,7 @@
45
45
  "@lark-apaas/nestjs-authzpaas": "^0.1.8",
46
46
  "@lark-apaas/nestjs-capability": "^0.1.11",
47
47
  "@lark-apaas/nestjs-common": "^0.1.8",
48
- "@lark-apaas/nestjs-datapaas": "^1.0.19",
48
+ "@lark-apaas/nestjs-datapaas": "^1.0.18",
49
49
  "@lark-apaas/nestjs-logger": "^1.0.16",
50
50
  "@lark-apaas/nestjs-observable": "^0.0.11",
51
51
  "@lark-apaas/nestjs-openapi-devtools": "^1.0.10",