@lark-apaas/fullstack-nestjs-core 0.1.0-alpha.10 → 0.1.0-alpha.11

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
@@ -5,11 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
9
- var __typeError = (msg) => {
10
- throw TypeError(msg);
11
- };
12
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
8
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
14
9
  var __export = (target, all) => {
15
10
  for (var name in all)
@@ -32,44 +27,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
27
  mod
33
28
  ));
34
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
- var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
36
- var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
37
- var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
38
- var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
39
- var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
40
- var __runInitializers = (array, flags, self, value) => {
41
- for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
42
- return value;
43
- };
44
- var __decorateElement = (array, flags, name, decorators, target, extra) => {
45
- var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
46
- var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
47
- var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
48
- var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name]() {
49
- return __privateGet(this, extra);
50
- }, set [name](x) {
51
- return __privateSet(this, extra, x);
52
- } }, name));
53
- k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
54
- for (var i = decorators.length - 1; i >= 0; i--) {
55
- ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
56
- if (k) {
57
- ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
58
- if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
59
- if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
60
- }
61
- it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
62
- if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
63
- else if (typeof it !== "object" || it === null) __typeError("Object expected");
64
- else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
65
- }
66
- return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
67
- };
68
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
69
- var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
70
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
71
- var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
72
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
73
30
 
74
31
  // src/index.ts
75
32
  var index_exports = {};
@@ -93,6 +50,7 @@ function normalizeBasePath(rawBasePath) {
93
50
  const normalizedBasePath = rawBasePath.startsWith("/") ? rawBasePath : `/${rawBasePath}`;
94
51
  return normalizedBasePath.endsWith("/") ? normalizedBasePath.slice(0, -1) : normalizedBasePath;
95
52
  }
53
+ __name(normalizeBasePath, "normalizeBasePath");
96
54
  function resolveOptsWithDefaultValue(options) {
97
55
  const basePath = normalizeBasePath(options.basePath || "/");
98
56
  const docsPath = normalizeBasePath(options.docsPath || `api/docs`);
@@ -112,26 +70,35 @@ function resolveOptsWithDefaultValue(options) {
112
70
  }
113
71
  };
114
72
  }
73
+ __name(resolveOptsWithDefaultValue, "resolveOptsWithDefaultValue");
115
74
  function ensureDirAndWrite(filePath, content) {
116
75
  const dir = (0, import_node_path.dirname)(filePath);
117
- (0, import_node_fs.mkdirSync)(dir, { recursive: true });
76
+ (0, import_node_fs.mkdirSync)(dir, {
77
+ recursive: true
78
+ });
118
79
  (0, import_node_fs.writeFileSync)(filePath, content);
119
80
  }
81
+ __name(ensureDirAndWrite, "ensureDirAndWrite");
120
82
 
121
83
  // src/modules/devtool/index.ts
122
84
  var DevToolsModule = class {
85
+ static {
86
+ __name(this, "DevToolsModule");
87
+ }
123
88
  static async mount(app, opts = {}) {
124
89
  const options = resolveOptsWithDefaultValue(opts);
125
90
  const baseDirname = process.cwd();
126
91
  const builder = new import_swagger.DocumentBuilder().setTitle(options.swaggerOptions.title).setVersion(options.swaggerOptions.version);
127
92
  const document = import_swagger.SwaggerModule.createDocument(app, builder.build(), {
128
- operationIdFactory: (_c, m) => m
93
+ operationIdFactory: /* @__PURE__ */ __name((_c, m) => m, "operationIdFactory")
129
94
  });
130
95
  if (options.needSetupServer) {
131
96
  import_swagger.SwaggerModule.setup(options.docsPath, app, document, {
132
97
  customSiteTitle: options.swaggerOptions.customSiteTitle,
133
98
  customCss: options.swaggerOptions.customCss,
134
- swaggerOptions: { persistAuthorization: true }
99
+ swaggerOptions: {
100
+ persistAuthorization: true
101
+ }
135
102
  });
136
103
  console.log(`[OpenAPI] Swagger UI \u5DF2\u6302\u8F7D\u81F3 ${options.docsPath}`);
137
104
  }
@@ -139,7 +106,9 @@ var DevToolsModule = class {
139
106
  ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));
140
107
  if (options.needGenerateClientSdk) {
141
108
  const clientSdkOutPath = (0, import_node_path2.resolve)(baseDirname, options.clientSdkOut);
142
- (0, import_node_fs2.mkdirSync)(clientSdkOutPath, { recursive: true });
109
+ (0, import_node_fs2.mkdirSync)(clientSdkOutPath, {
110
+ recursive: true
111
+ });
143
112
  const { generate } = await import("openapi-typescript-codegen");
144
113
  await generate({
145
114
  input: openapiPath,
@@ -166,21 +135,29 @@ function resolveCsrfTokenOptions(options) {
166
135
  cookiePath: options.cookiePath ?? "/"
167
136
  };
168
137
  }
138
+ __name(resolveCsrfTokenOptions, "resolveCsrfTokenOptions");
169
139
  function genToken() {
170
140
  const ts = Math.floor(Date.now() / 1e3);
171
- const randInt64 = BigInt(
172
- "0x" + import_crypto.default.randomBytes(8).toString("hex")
173
- ).toString();
141
+ const randInt64 = BigInt("0x" + import_crypto.default.randomBytes(8).toString("hex")).toString();
174
142
  const s = `${randInt64}.${ts}`;
175
143
  const sha1 = import_crypto.default.createHash("sha1");
176
144
  sha1.update(s);
177
145
  return `${sha1.digest("hex")}-${ts}`;
178
146
  }
147
+ __name(genToken, "genToken");
179
148
 
180
149
  // src/middlewares/csrf_token/index.ts
181
- var _CsrfTokenMiddleware_decorators, _init;
182
- _CsrfTokenMiddleware_decorators = [(0, import_common.Injectable)()];
183
- var _CsrfTokenMiddleware = class _CsrfTokenMiddleware {
150
+ function _ts_decorate(decorators, target, key, desc) {
151
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
152
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
153
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
154
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
155
+ }
156
+ __name(_ts_decorate, "_ts_decorate");
157
+ var CsrfTokenMiddleware = class _CsrfTokenMiddleware {
158
+ static {
159
+ __name(this, "CsrfTokenMiddleware");
160
+ }
184
161
  static options;
185
162
  static configure(opts) {
186
163
  this.options = resolveCsrfTokenOptions(opts);
@@ -201,16 +178,14 @@ var _CsrfTokenMiddleware = class _CsrfTokenMiddleware {
201
178
  secure: true,
202
179
  sameSite: "none",
203
180
  partitioned: true
204
- // 默认开启 Partitioned Cookie
205
181
  });
206
182
  next();
207
183
  }
208
184
  }
209
185
  };
210
- _init = __decoratorStart(null);
211
- _CsrfTokenMiddleware = __decorateElement(_init, 0, "CsrfTokenMiddleware", _CsrfTokenMiddleware_decorators, _CsrfTokenMiddleware);
212
- __runInitializers(_init, 1, _CsrfTokenMiddleware);
213
- var CsrfTokenMiddleware = _CsrfTokenMiddleware;
186
+ CsrfTokenMiddleware = _ts_decorate([
187
+ (0, import_common.Injectable)()
188
+ ], CsrfTokenMiddleware);
214
189
 
215
190
  // src/middlewares/csrf/index.ts
216
191
  var import_common2 = require("@nestjs/common");
@@ -223,14 +198,24 @@ function resolveCsrfOptions(options) {
223
198
  cookieKey: options.cookieKey ?? "suda-csrf-token"
224
199
  };
225
200
  }
201
+ __name(resolveCsrfOptions, "resolveCsrfOptions");
226
202
  function sendForbidden(res, message) {
227
203
  res.status(403).send(`Forbidden\uFF0C${message}`);
228
204
  }
205
+ __name(sendForbidden, "sendForbidden");
229
206
 
230
207
  // src/middlewares/csrf/index.ts
231
- var _CsrfMiddleware_decorators, _init2;
232
- _CsrfMiddleware_decorators = [(0, import_common2.Injectable)()];
233
- var _CsrfMiddleware = class _CsrfMiddleware {
208
+ function _ts_decorate2(decorators, target, key, desc) {
209
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
210
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
211
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
212
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
213
+ }
214
+ __name(_ts_decorate2, "_ts_decorate");
215
+ var CsrfMiddleware = class _CsrfMiddleware {
216
+ static {
217
+ __name(this, "CsrfMiddleware");
218
+ }
234
219
  static options;
235
220
  static configure(opts) {
236
221
  this.options = resolveCsrfOptions(opts);
@@ -254,10 +239,9 @@ var _CsrfMiddleware = class _CsrfMiddleware {
254
239
  next();
255
240
  }
256
241
  };
257
- _init2 = __decoratorStart(null);
258
- _CsrfMiddleware = __decorateElement(_init2, 0, "CsrfMiddleware", _CsrfMiddleware_decorators, _CsrfMiddleware);
259
- __runInitializers(_init2, 1, _CsrfMiddleware);
260
- var CsrfMiddleware = _CsrfMiddleware;
242
+ CsrfMiddleware = _ts_decorate2([
243
+ (0, import_common2.Injectable)()
244
+ ], CsrfMiddleware);
261
245
 
262
246
  // src/middlewares/user-context/index.ts
263
247
  var import_common3 = require("@nestjs/common");
@@ -279,11 +263,20 @@ function getWebUserFromHeader(req) {
279
263
  }
280
264
  return null;
281
265
  }
266
+ __name(getWebUserFromHeader, "getWebUserFromHeader");
282
267
 
283
268
  // src/middlewares/user-context/index.ts
284
- var _UserContextMiddleware_decorators, _init3;
285
- _UserContextMiddleware_decorators = [(0, import_common3.Injectable)()];
269
+ function _ts_decorate3(decorators, target, key, desc) {
270
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
271
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
272
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
273
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
274
+ }
275
+ __name(_ts_decorate3, "_ts_decorate");
286
276
  var UserContextMiddleware = class {
277
+ static {
278
+ __name(this, "UserContextMiddleware");
279
+ }
287
280
  use(req, _res, next) {
288
281
  const webUser = getWebUserFromHeader(req);
289
282
  req.userContext = {
@@ -294,9 +287,9 @@ var UserContextMiddleware = class {
294
287
  next();
295
288
  }
296
289
  };
297
- _init3 = __decoratorStart(null);
298
- UserContextMiddleware = __decorateElement(_init3, 0, "UserContextMiddleware", _UserContextMiddleware_decorators, UserContextMiddleware);
299
- __runInitializers(_init3, 1, UserContextMiddleware);
290
+ UserContextMiddleware = _ts_decorate3([
291
+ (0, import_common3.Injectable)()
292
+ ], UserContextMiddleware);
300
293
  // Annotate the CommonJS export names for ESM import in node:
301
294
  0 && (module.exports = {
302
295
  CsrfMiddleware,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/modules/devtool/index.ts","../src/modules/devtool/helper.ts","../src/middlewares/csrf_token/index.ts","../src/middlewares/csrf_token/helper.ts","../src/middlewares/csrf/index.ts","../src/middlewares/csrf/helper.ts","../src/middlewares/user-context/index.ts","../src/middlewares/user-context/helper.ts"],"sourcesContent":["import './types/express.d';\n\nexport { DevToolsModule } from './modules/devtool';\n\n// Middlewares\nexport { CsrfTokenMiddleware } from './middlewares/csrf_token';\nexport { CsrfMiddleware } from './middlewares/csrf';\nexport { UserContextMiddleware } from './middlewares/user-context';\n","import type { INestApplication } from '@nestjs/common';\n\nimport { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';\nimport { mkdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { resolveOptsWithDefaultValue, ensureDirAndWrite } from './helper';\nimport { DevToolsOptions } from './type';\n\nexport class DevToolsModule {\n static async mount(app: INestApplication, opts: DevToolsOptions = {}) {\n const options = resolveOptsWithDefaultValue(opts);\n const baseDirname = process.cwd(); // 跟随命令的根目录\n\n // 1) 生成 Swagger 文档\n const builder = new DocumentBuilder()\n .setTitle(options.swaggerOptions.title)\n .setVersion(options.swaggerOptions.version);\n const document = SwaggerModule.createDocument(app, builder.build(), {\n operationIdFactory: (_c, m) => m,\n });\n // 1.1) 挂载 Swagger UI(可关)\n if(options.needSetupServer){\n SwaggerModule.setup(options.docsPath, app, document, {\n customSiteTitle: options.swaggerOptions.customSiteTitle,\n customCss: options.swaggerOptions.customCss,\n swaggerOptions: { persistAuthorization: true },\n });\n console.log(`[OpenAPI] Swagger UI 已挂载至 ${options.docsPath}`);\n }\n\n // 2) 导出 openapi.json\n const openapiPath = resolve(baseDirname, options.openapiOut);\n ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));\n\n // 3) 生成 axios SDK(可关)\n if (options.needGenerateClientSdk) {\n const clientSdkOutPath = resolve(baseDirname, options.clientSdkOut);\n mkdirSync(clientSdkOutPath, { recursive: true });\n const { generate } = await import('openapi-typescript-codegen');\n await generate({\n input: openapiPath,\n output: clientSdkOutPath,\n httpClient: 'axios',\n useOptions: false,\n exportServices: true,\n });\n console.log('[OpenAPI] 导出 openapi.json 并生成 axios SDK ✅');\n }\n }\n}\n","import { dirname } from 'node:path';\nimport { writeFileSync, mkdirSync } from 'node:fs';\n\nimport { DevToolsOptions } from './type';\n/**\n * 标准化基础路径,确保以 '/' 开头且以 '/' 结尾\n *\n * @param rawBasePath 原始的基础路径,可能以 '/' 开头或结尾\n * @returns 标准化后的基础路径,确保以 '/' 开头且不以 '/' 结尾\n */\nexport function normalizeBasePath(rawBasePath: string): string {\n const normalizedBasePath = rawBasePath.startsWith('/')\n ? rawBasePath\n : `/${rawBasePath}`;\n return normalizedBasePath.endsWith('/')\n ? normalizedBasePath.slice(0, -1)\n : normalizedBasePath;\n}\n\ntype ResolvedDevToolsOptions = Required<\n Omit<DevToolsOptions, 'swaggerOptions'>\n> & {\n swaggerOptions: Required<NonNullable<DevToolsOptions['swaggerOptions']>>;\n};\n\nexport function resolveOptsWithDefaultValue(\n options: DevToolsOptions,\n): ResolvedDevToolsOptions {\n const basePath = normalizeBasePath(options.basePath || '/');\n const docsPath = normalizeBasePath(options.docsPath || `api/docs`);\n return {\n ...options,\n needSetupServer: options.needSetupServer ?? false,\n basePath,\n docsPath: `${basePath}${docsPath}`,\n openapiOut: options.openapiOut || './client/src/api/gen/openapi.json',\n clientSdkOut: options.clientSdkOut || './client/src/api/gen',\n needGenerateClientSdk: options.needGenerateClientSdk ?? true,\n swaggerOptions: {\n title: options.swaggerOptions?.title ?? 'NestJS Fullstack API',\n version: options.swaggerOptions?.version ?? '1.0.0',\n customSiteTitle:\n options.swaggerOptions?.customSiteTitle ?? 'API Documentation',\n customCss:\n options.swaggerOptions?.customCss ??\n '.swagger-ui .topbar { display: none }',\n },\n };\n}\n\nexport function ensureDirAndWrite(filePath: string, content: string) {\n // 1. 拿到文件的上级目录\n const dir = dirname(filePath);\n\n // 2. 确保目录存在,不存在就递归创建\n mkdirSync(dir, { recursive: true });\n\n // 3. 写文件\n writeFileSync(filePath, content);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\nimport { resolveCsrfTokenOptions, genToken } from './helper';\n\n@Injectable()\nexport class CsrfTokenMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfTokenOptions;\n\n public static configure(opts: CsrfTokenOptions) {\n this.options = resolveCsrfTokenOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { cookieKey, cookieMaxAge, cookiePath } = CsrfTokenMiddleware.options;\n const originToken = req.cookies[cookieKey.toLowerCase()];\n // 如果存在 Cookie,则直接消费,无需生成\n if (originToken) {\n req.csrfToken = originToken;\n next();\n } else {\n // 如果不存在 token,则生成新的 csrfToken,并 setCookie\n const token = genToken();\n req.csrfToken = token;\n res.cookie(cookieKey, token, {\n maxAge: cookieMaxAge,\n path: cookiePath,\n httpOnly: true,\n secure: true,\n sameSite: 'none',\n partitioned: true, // 默认开启 Partitioned Cookie\n });\n next();\n }\n }\n}\n","import crypto from 'crypto';\nimport { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\n\nexport function resolveCsrfTokenOptions(\n options: CsrfTokenOptions,\n): ResolvedCsrfTokenOptions {\n return {\n ...options,\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n cookieMaxAge: options.cookieMaxAge ?? 1000 *60 * 60 * 24 * 30,\n cookiePath: options.cookiePath ?? '/',\n };\n}\n\n// 生成 CsrfToken\nexport function genToken() {\n // 时间戳(秒级,和 Go 一致)\n const ts = Math.floor(Date.now() / 1000);\n\n // 随机 int64 模拟:生成 8 字节随机数并转成十进制字符串\n const randInt64 = BigInt(\n '0x' + crypto.randomBytes(8).toString('hex'),\n ).toString();\n\n // 拼接 \"<rand>.<timestamp>\"\n const s = `${randInt64}.${ts}`;\n\n // 计算 sha1\n const sha1 = crypto.createHash('sha1');\n sha1.update(s);\n\n // 返回 \"<sha1Hex>-<timestamp>\"\n return `${sha1.digest('hex')}-${ts}`;\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfOptions, ResolvedCsrfOptions } from './type';\nimport { resolveCsrfOptions, sendForbidden } from './helper';\n\n@Injectable()\nexport class CsrfMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfOptions;\n\n public static configure(opts: CsrfOptions) {\n this.options = resolveCsrfOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { headerKey, cookieKey } = CsrfMiddleware.options;\n const cookieCsrfToken = req.cookies[cookieKey.toLowerCase()];\n if (!cookieCsrfToken) {\n sendForbidden(res, 'csrf token not found in cookie.');\n return;\n }\n const headerCsrfToken = req.headers[headerKey.toLowerCase()];\n if (!headerCsrfToken) {\n sendForbidden(res, 'csrf token not found in header.');\n return;\n }\n if (cookieCsrfToken !== headerCsrfToken) {\n sendForbidden(res, 'csrf token not match.');\n return;\n }\n next();\n }\n}\n","import type { Response } from 'express';\n\nimport { CsrfOptions, ResolvedCsrfOptions } from './type';\n\nexport function resolveCsrfOptions(options: CsrfOptions): ResolvedCsrfOptions {\n return {\n ...options,\n headerKey: options.headerKey ?? 'x-suda-csrf-token',\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n };\n}\n\nexport function sendForbidden(res: Response, message: string) {\n res.status(403).send(`Forbidden,${message}`);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\nimport { getWebUserFromHeader } from './helper';\n\n@Injectable()\nexport class UserContextMiddleware implements NestMiddleware {\n\n public use(req: Request, _res: Response, next: NextFunction) {\n const webUser = getWebUserFromHeader(req);\n req.userContext = {\n userId: webUser?.user_id,\n tenantId: webUser?.tenant_id,\n appId: webUser?.app_id ?? '',\n }\n next();\n }\n}\n","import type { Request } from 'express';\n\nconst sudaWebUserHeaderKey = 'x-larkgw-suda-webuser';\n\ninterface SudaWebUser {\n user_id: string;\n tenant_id: number;\n app_id: string;\n}\n\nexport function getWebUserFromHeader(req: Request): SudaWebUser | null {\n const sudaWebUserContent = req.headers[sudaWebUserHeaderKey] as\n | string\n | undefined;\n if (!sudaWebUserContent) {\n return null;\n }\n try {\n const sudaWebUserJsonStr = decodeURIComponent(sudaWebUserContent);\n const sudaWebUserJson = JSON.parse(sudaWebUserJsonStr) as SudaWebUser;\n return sudaWebUserJson;\n } catch (err) {\n console.error('parse suda webuser from header failed, err=%o', err);\n return null;\n }\n return null;\n}\n"],"mappings":"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","names":["import_node_fs","import_node_path","crypto","import_common","_init","import_common","_init"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/modules/devtool/index.ts","../src/modules/devtool/helper.ts","../src/middlewares/csrf_token/index.ts","../src/middlewares/csrf_token/helper.ts","../src/middlewares/csrf/index.ts","../src/middlewares/csrf/helper.ts","../src/middlewares/user-context/index.ts","../src/middlewares/user-context/helper.ts"],"sourcesContent":["import './types/express.d';\n\nexport { DevToolsModule } from './modules/devtool';\n\n// Middlewares\nexport { CsrfTokenMiddleware } from './middlewares/csrf_token';\nexport { CsrfMiddleware } from './middlewares/csrf';\nexport { UserContextMiddleware } from './middlewares/user-context';\n","import type { INestApplication } from '@nestjs/common';\n\nimport { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';\nimport { mkdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { resolveOptsWithDefaultValue, ensureDirAndWrite } from './helper';\nimport { DevToolsOptions } from './type';\n\nexport class DevToolsModule {\n static async mount(app: INestApplication, opts: DevToolsOptions = {}) {\n const options = resolveOptsWithDefaultValue(opts);\n const baseDirname = process.cwd(); // 跟随命令的根目录\n\n // 1) 生成 Swagger 文档\n const builder = new DocumentBuilder()\n .setTitle(options.swaggerOptions.title)\n .setVersion(options.swaggerOptions.version);\n const document = SwaggerModule.createDocument(app, builder.build(), {\n operationIdFactory: (_c, m) => m,\n });\n // 1.1) 挂载 Swagger UI(可关)\n if(options.needSetupServer){\n SwaggerModule.setup(options.docsPath, app, document, {\n customSiteTitle: options.swaggerOptions.customSiteTitle,\n customCss: options.swaggerOptions.customCss,\n swaggerOptions: { persistAuthorization: true },\n });\n console.log(`[OpenAPI] Swagger UI 已挂载至 ${options.docsPath}`);\n }\n\n // 2) 导出 openapi.json\n const openapiPath = resolve(baseDirname, options.openapiOut);\n ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));\n\n // 3) 生成 axios SDK(可关)\n if (options.needGenerateClientSdk) {\n const clientSdkOutPath = resolve(baseDirname, options.clientSdkOut);\n mkdirSync(clientSdkOutPath, { recursive: true });\n const { generate } = await import('openapi-typescript-codegen');\n await generate({\n input: openapiPath,\n output: clientSdkOutPath,\n httpClient: 'axios',\n useOptions: false,\n exportServices: true,\n });\n console.log('[OpenAPI] 导出 openapi.json 并生成 axios SDK ✅');\n }\n }\n}\n","import { dirname } from 'node:path';\nimport { writeFileSync, mkdirSync } from 'node:fs';\n\nimport { DevToolsOptions } from './type';\n/**\n * 标准化基础路径,确保以 '/' 开头且以 '/' 结尾\n *\n * @param rawBasePath 原始的基础路径,可能以 '/' 开头或结尾\n * @returns 标准化后的基础路径,确保以 '/' 开头且不以 '/' 结尾\n */\nexport function normalizeBasePath(rawBasePath: string): string {\n const normalizedBasePath = rawBasePath.startsWith('/')\n ? rawBasePath\n : `/${rawBasePath}`;\n return normalizedBasePath.endsWith('/')\n ? normalizedBasePath.slice(0, -1)\n : normalizedBasePath;\n}\n\ntype ResolvedDevToolsOptions = Required<\n Omit<DevToolsOptions, 'swaggerOptions'>\n> & {\n swaggerOptions: Required<NonNullable<DevToolsOptions['swaggerOptions']>>;\n};\n\nexport function resolveOptsWithDefaultValue(\n options: DevToolsOptions,\n): ResolvedDevToolsOptions {\n const basePath = normalizeBasePath(options.basePath || '/');\n const docsPath = normalizeBasePath(options.docsPath || `api/docs`);\n return {\n ...options,\n needSetupServer: options.needSetupServer ?? false,\n basePath,\n docsPath: `${basePath}${docsPath}`,\n openapiOut: options.openapiOut || './client/src/api/gen/openapi.json',\n clientSdkOut: options.clientSdkOut || './client/src/api/gen',\n needGenerateClientSdk: options.needGenerateClientSdk ?? true,\n swaggerOptions: {\n title: options.swaggerOptions?.title ?? 'NestJS Fullstack API',\n version: options.swaggerOptions?.version ?? '1.0.0',\n customSiteTitle:\n options.swaggerOptions?.customSiteTitle ?? 'API Documentation',\n customCss:\n options.swaggerOptions?.customCss ??\n '.swagger-ui .topbar { display: none }',\n },\n };\n}\n\nexport function ensureDirAndWrite(filePath: string, content: string) {\n // 1. 拿到文件的上级目录\n const dir = dirname(filePath);\n\n // 2. 确保目录存在,不存在就递归创建\n mkdirSync(dir, { recursive: true });\n\n // 3. 写文件\n writeFileSync(filePath, content);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\nimport { resolveCsrfTokenOptions, genToken } from './helper';\n\n@Injectable()\nexport class CsrfTokenMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfTokenOptions;\n\n public static configure(opts: CsrfTokenOptions) {\n this.options = resolveCsrfTokenOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { cookieKey, cookieMaxAge, cookiePath } = CsrfTokenMiddleware.options;\n const originToken = req.cookies[cookieKey.toLowerCase()];\n // 如果存在 Cookie,则直接消费,无需生成\n if (originToken) {\n req.csrfToken = originToken;\n next();\n } else {\n // 如果不存在 token,则生成新的 csrfToken,并 setCookie\n const token = genToken();\n req.csrfToken = token;\n res.cookie(cookieKey, token, {\n maxAge: cookieMaxAge,\n path: cookiePath,\n httpOnly: true,\n secure: true,\n sameSite: 'none',\n partitioned: true, // 默认开启 Partitioned Cookie\n });\n next();\n }\n }\n}\n","import crypto from 'crypto';\nimport { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\n\nexport function resolveCsrfTokenOptions(\n options: CsrfTokenOptions,\n): ResolvedCsrfTokenOptions {\n return {\n ...options,\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n cookieMaxAge: options.cookieMaxAge ?? 1000 *60 * 60 * 24 * 30,\n cookiePath: options.cookiePath ?? '/',\n };\n}\n\n// 生成 CsrfToken\nexport function genToken() {\n // 时间戳(秒级,和 Go 一致)\n const ts = Math.floor(Date.now() / 1000);\n\n // 随机 int64 模拟:生成 8 字节随机数并转成十进制字符串\n const randInt64 = BigInt(\n '0x' + crypto.randomBytes(8).toString('hex'),\n ).toString();\n\n // 拼接 \"<rand>.<timestamp>\"\n const s = `${randInt64}.${ts}`;\n\n // 计算 sha1\n const sha1 = crypto.createHash('sha1');\n sha1.update(s);\n\n // 返回 \"<sha1Hex>-<timestamp>\"\n return `${sha1.digest('hex')}-${ts}`;\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfOptions, ResolvedCsrfOptions } from './type';\nimport { resolveCsrfOptions, sendForbidden } from './helper';\n\n@Injectable()\nexport class CsrfMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfOptions;\n\n public static configure(opts: CsrfOptions) {\n this.options = resolveCsrfOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { headerKey, cookieKey } = CsrfMiddleware.options;\n const cookieCsrfToken = req.cookies[cookieKey.toLowerCase()];\n if (!cookieCsrfToken) {\n sendForbidden(res, 'csrf token not found in cookie.');\n return;\n }\n const headerCsrfToken = req.headers[headerKey.toLowerCase()];\n if (!headerCsrfToken) {\n sendForbidden(res, 'csrf token not found in header.');\n return;\n }\n if (cookieCsrfToken !== headerCsrfToken) {\n sendForbidden(res, 'csrf token not match.');\n return;\n }\n next();\n }\n}\n","import type { Response } from 'express';\n\nimport { CsrfOptions, ResolvedCsrfOptions } from './type';\n\nexport function resolveCsrfOptions(options: CsrfOptions): ResolvedCsrfOptions {\n return {\n ...options,\n headerKey: options.headerKey ?? 'x-suda-csrf-token',\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n };\n}\n\nexport function sendForbidden(res: Response, message: string) {\n res.status(403).send(`Forbidden,${message}`);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\nimport { getWebUserFromHeader } from './helper';\n\n@Injectable()\nexport class UserContextMiddleware implements NestMiddleware {\n\n public use(req: Request, _res: Response, next: NextFunction) {\n const webUser = getWebUserFromHeader(req);\n req.userContext = {\n userId: webUser?.user_id,\n tenantId: webUser?.tenant_id,\n appId: webUser?.app_id ?? '',\n }\n next();\n }\n}\n","import type { Request } from 'express';\n\nconst sudaWebUserHeaderKey = 'x-larkgw-suda-webuser';\n\ninterface SudaWebUser {\n user_id: string;\n tenant_id: number;\n app_id: string;\n}\n\nexport function getWebUserFromHeader(req: Request): SudaWebUser | null {\n const sudaWebUserContent = req.headers[sudaWebUserHeaderKey] as\n | string\n | undefined;\n if (!sudaWebUserContent) {\n return null;\n }\n try {\n const sudaWebUserJsonStr = decodeURIComponent(sudaWebUserContent);\n const sudaWebUserJson = JSON.parse(sudaWebUserJsonStr) as SudaWebUser;\n return sudaWebUserJson;\n } catch (err) {\n console.error('parse suda webuser from header failed, err=%o', err);\n return null;\n }\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;ACEA,qBAA+C;AAC/C,IAAAA,kBAA0B;AAC1B,IAAAC,oBAAwB;;;ACJxB,uBAAwB;AACxB,qBAAyC;AASlC,SAASC,kBAAkBC,aAAmB;AACnD,QAAMC,qBAAqBD,YAAYE,WAAW,GAAA,IAC9CF,cACA,IAAIA,WAAAA;AACR,SAAOC,mBAAmBE,SAAS,GAAA,IAC/BF,mBAAmBG,MAAM,GAAG,EAAC,IAC7BH;AACN;AAPgBF;AAeT,SAASM,4BACdC,SAAwB;AAExB,QAAMC,WAAWR,kBAAkBO,QAAQC,YAAY,GAAA;AACvD,QAAMC,WAAWT,kBAAkBO,QAAQE,YAAY,UAAU;AACjE,SAAO;IACL,GAAGF;IACHG,iBAAiBH,QAAQG,mBAAmB;IAC5CF;IACAC,UAAU,GAAGD,QAAAA,GAAWC,QAAAA;IACxBE,YAAYJ,QAAQI,cAAc;IAClCC,cAAcL,QAAQK,gBAAgB;IACtCC,uBAAuBN,QAAQM,yBAAyB;IACxDC,gBAAgB;MACdC,OAAOR,QAAQO,gBAAgBC,SAAS;MACxCC,SAAST,QAAQO,gBAAgBE,WAAW;MAC5CC,iBACEV,QAAQO,gBAAgBG,mBAAmB;MAC7CC,WACEX,QAAQO,gBAAgBI,aACxB;IACJ;EACF;AACF;AAvBgBZ;AAyBT,SAASa,kBAAkBC,UAAkBC,SAAe;AAEjE,QAAMC,UAAMC,0BAAQH,QAAAA;AAGpBI,gCAAUF,KAAK;IAAEG,WAAW;EAAK,CAAA;AAGjCC,oCAAcN,UAAUC,OAAAA;AAC1B;AATgBF;;;ADzCT,IAAMQ,iBAAN,MAAMA;EAPb,OAOaA;;;EACX,aAAaC,MAAMC,KAAuBC,OAAwB,CAAC,GAAG;AACpE,UAAMC,UAAUC,4BAA4BF,IAAAA;AAC5C,UAAMG,cAAcC,QAAQC,IAAG;AAG/B,UAAMC,UAAU,IAAIC,+BAAAA,EACjBC,SAASP,QAAQQ,eAAeC,KAAK,EACrCC,WAAWV,QAAQQ,eAAeG,OAAO;AAC5C,UAAMC,WAAWC,6BAAcC,eAAehB,KAAKO,QAAQU,MAAK,GAAI;MAClEC,oBAAoB,wBAACC,IAAIC,MAAMA,GAAX;IACtB,CAAA;AAEA,QAAGlB,QAAQmB,iBAAgB;AACzBN,mCAAcO,MAAMpB,QAAQqB,UAAUvB,KAAKc,UAAU;QACnDU,iBAAiBtB,QAAQQ,eAAec;QACxCC,WAAWvB,QAAQQ,eAAee;QAClCf,gBAAgB;UAAEgB,sBAAsB;QAAK;MAC/C,CAAA;AACAC,cAAQC,IAAI,iDAA6B1B,QAAQqB,QAAQ,EAAE;IAC7D;AAGA,UAAMM,kBAAcC,2BAAQ1B,aAAaF,QAAQ6B,UAAU;AAC3DC,sBAAkBH,aAAaI,KAAKC,UAAUpB,UAAU,MAAM,CAAA,CAAA;AAG9D,QAAIZ,QAAQiC,uBAAuB;AACjC,YAAMC,uBAAmBN,2BAAQ1B,aAAaF,QAAQmC,YAAY;AAClEC,qCAAUF,kBAAkB;QAAEG,WAAW;MAAK,CAAA;AAC9C,YAAM,EAAEC,SAAQ,IAAK,MAAM,OAAO,4BAAA;AAClC,YAAMA,SAAS;QACbC,OAAOZ;QACPa,QAAQN;QACRO,YAAY;QACZC,YAAY;QACZC,gBAAgB;MAClB,CAAA;AACAlB,cAAQC,IAAI,yEAAA;IACd;EACF;AACF;;;AElDA,oBAA2C;;;ACA3C,oBAAmB;AAGZ,SAASkB,wBACdC,SAAyB;AAEzB,SAAO;IACL,GAAGA;IACHC,WAAWD,QAAQC,aAAa;IAChCC,cAAcF,QAAQE,gBAAgB,MAAM,KAAK,KAAK,KAAK;IAC3DC,YAAYH,QAAQG,cAAc;EACpC;AACF;AATgBJ;AAYT,SAASK,WAAAA;AAEd,QAAMC,KAAKC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,GAAA;AAGnC,QAAMC,YAAYC,OAChB,OAAOC,cAAAA,QAAOC,YAAY,CAAA,EAAGC,SAAS,KAAA,CAAA,EACtCA,SAAQ;AAGV,QAAMC,IAAI,GAAGL,SAAAA,IAAaL,EAAAA;AAG1B,QAAMW,OAAOJ,cAAAA,QAAOK,WAAW,MAAA;AAC/BD,OAAKE,OAAOH,CAAAA;AAGZ,SAAO,GAAGC,KAAKG,OAAO,KAAA,CAAA,IAAUd,EAAAA;AAClC;AAlBgBD;;;;;;;;;;ADRT,IAAMgB,sBAAN,MAAMA,qBAAAA;SAAAA;;;EACX,OAAeC;EAEf,OAAcC,UAAUC,MAAwB;AAC9C,SAAKF,UAAUG,wBAAwBD,IAAAA;EACzC;EAEOE,IAAIC,KAAcC,KAAeC,MAAoB;AAC1D,UAAM,EAAEC,WAAWC,cAAcC,WAAU,IAAKX,qBAAoBC;AACpE,UAAMW,cAAcN,IAAIO,QAAQJ,UAAUK,YAAW,CAAA;AAErD,QAAIF,aAAa;AACfN,UAAIS,YAAYH;AAChBJ,WAAAA;IACF,OAAO;AAEL,YAAMQ,QAAQC,SAAAA;AACdX,UAAIS,YAAYC;AAChBT,UAAIW,OAAOT,WAAWO,OAAO;QAC3BG,QAAQT;QACRU,MAAMT;QACNU,UAAU;QACVC,QAAQ;QACRC,UAAU;QACVC,aAAa;MACf,CAAA;AACAhB,WAAAA;IACF;EACF;AACF;;;;;;AEpCA,IAAAiB,iBAA2C;;;ACIpC,SAASC,mBAAmBC,SAAoB;AACrD,SAAO;IACL,GAAGA;IACHC,WAAWD,QAAQC,aAAa;IAChCC,WAAWF,QAAQE,aAAa;EAClC;AACF;AANgBH;AAQT,SAASI,cAAcC,KAAeC,SAAe;AAC1DD,MAAIE,OAAO,GAAA,EAAKC,KAAK,kBAAaF,OAAAA,EAAS;AAC7C;AAFgBF;;;;;;;;;;ADLT,IAAMK,iBAAN,MAAMA,gBAAAA;SAAAA;;;EACX,OAAeC;EAEf,OAAcC,UAAUC,MAAmB;AACzC,SAAKF,UAAUG,mBAAmBD,IAAAA;EACpC;EAEOE,IAAIC,KAAcC,KAAeC,MAAoB;AAC1D,UAAM,EAAEC,WAAWC,UAAS,IAAKV,gBAAeC;AAChD,UAAMU,kBAAkBL,IAAIM,QAAQF,UAAUG,YAAW,CAAA;AACzD,QAAI,CAACF,iBAAiB;AACpBG,oBAAcP,KAAK,iCAAA;AACnB;IACF;AACA,UAAMQ,kBAAkBT,IAAIU,QAAQP,UAAUI,YAAW,CAAA;AACzD,QAAI,CAACE,iBAAiB;AACpBD,oBAAcP,KAAK,iCAAA;AACnB;IACF;AACA,QAAII,oBAAoBI,iBAAiB;AACvCD,oBAAcP,KAAK,uBAAA;AACnB;IACF;AACAC,SAAAA;EACF;AACF;;;;;;AEhCA,IAAAS,iBAA2C;;;ACE3C,IAAMC,uBAAuB;AAQtB,SAASC,qBAAqBC,KAAY;AAC/C,QAAMC,qBAAqBD,IAAIE,QAAQJ,oBAAAA;AAGvC,MAAI,CAACG,oBAAoB;AACvB,WAAO;EACT;AACA,MAAI;AACF,UAAME,qBAAqBC,mBAAmBH,kBAAAA;AAC9C,UAAMI,kBAAkBC,KAAKC,MAAMJ,kBAAAA;AACnC,WAAOE;EACT,SAASG,KAAK;AACZC,YAAQC,MAAM,iDAAiDF,GAAAA;AAC/D,WAAO;EACT;AACA,SAAO;AACT;AAhBgBT;;;;;;;;;;ADLT,IAAMY,wBAAN,MAAMA;SAAAA;;;EAEJC,IAAIC,KAAcC,MAAgBC,MAAoB;AAC3D,UAAMC,UAAUC,qBAAqBJ,GAAAA;AACrCA,QAAIK,cAAc;MAChBC,QAAQH,SAASI;MACjBC,UAAUL,SAASM;MACnBC,OAAOP,SAASQ,UAAU;IAC5B;AACAT,SAAAA;EACF;AACF;;;;","names":["import_node_fs","import_node_path","normalizeBasePath","rawBasePath","normalizedBasePath","startsWith","endsWith","slice","resolveOptsWithDefaultValue","options","basePath","docsPath","needSetupServer","openapiOut","clientSdkOut","needGenerateClientSdk","swaggerOptions","title","version","customSiteTitle","customCss","ensureDirAndWrite","filePath","content","dir","dirname","mkdirSync","recursive","writeFileSync","DevToolsModule","mount","app","opts","options","resolveOptsWithDefaultValue","baseDirname","process","cwd","builder","DocumentBuilder","setTitle","swaggerOptions","title","setVersion","version","document","SwaggerModule","createDocument","build","operationIdFactory","_c","m","needSetupServer","setup","docsPath","customSiteTitle","customCss","persistAuthorization","console","log","openapiPath","resolve","openapiOut","ensureDirAndWrite","JSON","stringify","needGenerateClientSdk","clientSdkOutPath","clientSdkOut","mkdirSync","recursive","generate","input","output","httpClient","useOptions","exportServices","resolveCsrfTokenOptions","options","cookieKey","cookieMaxAge","cookiePath","genToken","ts","Math","floor","Date","now","randInt64","BigInt","crypto","randomBytes","toString","s","sha1","createHash","update","digest","CsrfTokenMiddleware","options","configure","opts","resolveCsrfTokenOptions","use","req","res","next","cookieKey","cookieMaxAge","cookiePath","originToken","cookies","toLowerCase","csrfToken","token","genToken","cookie","maxAge","path","httpOnly","secure","sameSite","partitioned","import_common","resolveCsrfOptions","options","headerKey","cookieKey","sendForbidden","res","message","status","send","CsrfMiddleware","options","configure","opts","resolveCsrfOptions","use","req","res","next","headerKey","cookieKey","cookieCsrfToken","cookies","toLowerCase","sendForbidden","headerCsrfToken","headers","import_common","sudaWebUserHeaderKey","getWebUserFromHeader","req","sudaWebUserContent","headers","sudaWebUserJsonStr","decodeURIComponent","sudaWebUserJson","JSON","parse","err","console","error","UserContextMiddleware","use","req","_res","next","webUser","getWebUserFromHeader","userContext","userId","user_id","tenantId","tenant_id","appId","app_id"]}
package/dist/index.js CHANGED
@@ -1,50 +1,5 @@
1
- var __create = Object.create;
2
1
  var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
5
- var __typeError = (msg) => {
6
- throw TypeError(msg);
7
- };
8
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
- var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
11
- var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
12
- var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
13
- var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
14
- var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
15
- var __runInitializers = (array, flags, self, value) => {
16
- for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
17
- return value;
18
- };
19
- var __decorateElement = (array, flags, name, decorators, target, extra) => {
20
- var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
21
- var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
22
- var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
23
- var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name]() {
24
- return __privateGet(this, extra);
25
- }, set [name](x) {
26
- return __privateSet(this, extra, x);
27
- } }, name));
28
- k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
29
- for (var i = decorators.length - 1; i >= 0; i--) {
30
- ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
31
- if (k) {
32
- ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
33
- if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
34
- if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
35
- }
36
- it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
37
- if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
38
- else if (typeof it !== "object" || it === null) __typeError("Object expected");
39
- else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
40
- }
41
- return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
42
- };
43
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
44
- var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
45
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
46
- var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
47
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
48
3
 
49
4
  // src/modules/devtool/index.ts
50
5
  import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
@@ -58,6 +13,7 @@ function normalizeBasePath(rawBasePath) {
58
13
  const normalizedBasePath = rawBasePath.startsWith("/") ? rawBasePath : `/${rawBasePath}`;
59
14
  return normalizedBasePath.endsWith("/") ? normalizedBasePath.slice(0, -1) : normalizedBasePath;
60
15
  }
16
+ __name(normalizeBasePath, "normalizeBasePath");
61
17
  function resolveOptsWithDefaultValue(options) {
62
18
  const basePath = normalizeBasePath(options.basePath || "/");
63
19
  const docsPath = normalizeBasePath(options.docsPath || `api/docs`);
@@ -77,26 +33,35 @@ function resolveOptsWithDefaultValue(options) {
77
33
  }
78
34
  };
79
35
  }
36
+ __name(resolveOptsWithDefaultValue, "resolveOptsWithDefaultValue");
80
37
  function ensureDirAndWrite(filePath, content) {
81
38
  const dir = dirname(filePath);
82
- mkdirSync(dir, { recursive: true });
39
+ mkdirSync(dir, {
40
+ recursive: true
41
+ });
83
42
  writeFileSync(filePath, content);
84
43
  }
44
+ __name(ensureDirAndWrite, "ensureDirAndWrite");
85
45
 
86
46
  // src/modules/devtool/index.ts
87
47
  var DevToolsModule = class {
48
+ static {
49
+ __name(this, "DevToolsModule");
50
+ }
88
51
  static async mount(app, opts = {}) {
89
52
  const options = resolveOptsWithDefaultValue(opts);
90
53
  const baseDirname = process.cwd();
91
54
  const builder = new DocumentBuilder().setTitle(options.swaggerOptions.title).setVersion(options.swaggerOptions.version);
92
55
  const document = SwaggerModule.createDocument(app, builder.build(), {
93
- operationIdFactory: (_c, m) => m
56
+ operationIdFactory: /* @__PURE__ */ __name((_c, m) => m, "operationIdFactory")
94
57
  });
95
58
  if (options.needSetupServer) {
96
59
  SwaggerModule.setup(options.docsPath, app, document, {
97
60
  customSiteTitle: options.swaggerOptions.customSiteTitle,
98
61
  customCss: options.swaggerOptions.customCss,
99
- swaggerOptions: { persistAuthorization: true }
62
+ swaggerOptions: {
63
+ persistAuthorization: true
64
+ }
100
65
  });
101
66
  console.log(`[OpenAPI] Swagger UI \u5DF2\u6302\u8F7D\u81F3 ${options.docsPath}`);
102
67
  }
@@ -104,7 +69,9 @@ var DevToolsModule = class {
104
69
  ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));
105
70
  if (options.needGenerateClientSdk) {
106
71
  const clientSdkOutPath = resolve(baseDirname, options.clientSdkOut);
107
- mkdirSync2(clientSdkOutPath, { recursive: true });
72
+ mkdirSync2(clientSdkOutPath, {
73
+ recursive: true
74
+ });
108
75
  const { generate } = await import("openapi-typescript-codegen");
109
76
  await generate({
110
77
  input: openapiPath,
@@ -131,21 +98,29 @@ function resolveCsrfTokenOptions(options) {
131
98
  cookiePath: options.cookiePath ?? "/"
132
99
  };
133
100
  }
101
+ __name(resolveCsrfTokenOptions, "resolveCsrfTokenOptions");
134
102
  function genToken() {
135
103
  const ts = Math.floor(Date.now() / 1e3);
136
- const randInt64 = BigInt(
137
- "0x" + crypto.randomBytes(8).toString("hex")
138
- ).toString();
104
+ const randInt64 = BigInt("0x" + crypto.randomBytes(8).toString("hex")).toString();
139
105
  const s = `${randInt64}.${ts}`;
140
106
  const sha1 = crypto.createHash("sha1");
141
107
  sha1.update(s);
142
108
  return `${sha1.digest("hex")}-${ts}`;
143
109
  }
110
+ __name(genToken, "genToken");
144
111
 
145
112
  // src/middlewares/csrf_token/index.ts
146
- var _CsrfTokenMiddleware_decorators, _init;
147
- _CsrfTokenMiddleware_decorators = [Injectable()];
148
- var _CsrfTokenMiddleware = class _CsrfTokenMiddleware {
113
+ function _ts_decorate(decorators, target, key, desc) {
114
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
115
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
116
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
117
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
118
+ }
119
+ __name(_ts_decorate, "_ts_decorate");
120
+ var CsrfTokenMiddleware = class _CsrfTokenMiddleware {
121
+ static {
122
+ __name(this, "CsrfTokenMiddleware");
123
+ }
149
124
  static options;
150
125
  static configure(opts) {
151
126
  this.options = resolveCsrfTokenOptions(opts);
@@ -166,16 +141,14 @@ var _CsrfTokenMiddleware = class _CsrfTokenMiddleware {
166
141
  secure: true,
167
142
  sameSite: "none",
168
143
  partitioned: true
169
- // 默认开启 Partitioned Cookie
170
144
  });
171
145
  next();
172
146
  }
173
147
  }
174
148
  };
175
- _init = __decoratorStart(null);
176
- _CsrfTokenMiddleware = __decorateElement(_init, 0, "CsrfTokenMiddleware", _CsrfTokenMiddleware_decorators, _CsrfTokenMiddleware);
177
- __runInitializers(_init, 1, _CsrfTokenMiddleware);
178
- var CsrfTokenMiddleware = _CsrfTokenMiddleware;
149
+ CsrfTokenMiddleware = _ts_decorate([
150
+ Injectable()
151
+ ], CsrfTokenMiddleware);
179
152
 
180
153
  // src/middlewares/csrf/index.ts
181
154
  import { Injectable as Injectable2 } from "@nestjs/common";
@@ -188,14 +161,24 @@ function resolveCsrfOptions(options) {
188
161
  cookieKey: options.cookieKey ?? "suda-csrf-token"
189
162
  };
190
163
  }
164
+ __name(resolveCsrfOptions, "resolveCsrfOptions");
191
165
  function sendForbidden(res, message) {
192
166
  res.status(403).send(`Forbidden\uFF0C${message}`);
193
167
  }
168
+ __name(sendForbidden, "sendForbidden");
194
169
 
195
170
  // src/middlewares/csrf/index.ts
196
- var _CsrfMiddleware_decorators, _init2;
197
- _CsrfMiddleware_decorators = [Injectable2()];
198
- var _CsrfMiddleware = class _CsrfMiddleware {
171
+ function _ts_decorate2(decorators, target, key, desc) {
172
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
173
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
174
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
175
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
176
+ }
177
+ __name(_ts_decorate2, "_ts_decorate");
178
+ var CsrfMiddleware = class _CsrfMiddleware {
179
+ static {
180
+ __name(this, "CsrfMiddleware");
181
+ }
199
182
  static options;
200
183
  static configure(opts) {
201
184
  this.options = resolveCsrfOptions(opts);
@@ -219,10 +202,9 @@ var _CsrfMiddleware = class _CsrfMiddleware {
219
202
  next();
220
203
  }
221
204
  };
222
- _init2 = __decoratorStart(null);
223
- _CsrfMiddleware = __decorateElement(_init2, 0, "CsrfMiddleware", _CsrfMiddleware_decorators, _CsrfMiddleware);
224
- __runInitializers(_init2, 1, _CsrfMiddleware);
225
- var CsrfMiddleware = _CsrfMiddleware;
205
+ CsrfMiddleware = _ts_decorate2([
206
+ Injectable2()
207
+ ], CsrfMiddleware);
226
208
 
227
209
  // src/middlewares/user-context/index.ts
228
210
  import { Injectable as Injectable3 } from "@nestjs/common";
@@ -244,11 +226,20 @@ function getWebUserFromHeader(req) {
244
226
  }
245
227
  return null;
246
228
  }
229
+ __name(getWebUserFromHeader, "getWebUserFromHeader");
247
230
 
248
231
  // src/middlewares/user-context/index.ts
249
- var _UserContextMiddleware_decorators, _init3;
250
- _UserContextMiddleware_decorators = [Injectable3()];
232
+ function _ts_decorate3(decorators, target, key, desc) {
233
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
234
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
235
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
236
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
237
+ }
238
+ __name(_ts_decorate3, "_ts_decorate");
251
239
  var UserContextMiddleware = class {
240
+ static {
241
+ __name(this, "UserContextMiddleware");
242
+ }
252
243
  use(req, _res, next) {
253
244
  const webUser = getWebUserFromHeader(req);
254
245
  req.userContext = {
@@ -259,9 +250,9 @@ var UserContextMiddleware = class {
259
250
  next();
260
251
  }
261
252
  };
262
- _init3 = __decoratorStart(null);
263
- UserContextMiddleware = __decorateElement(_init3, 0, "UserContextMiddleware", _UserContextMiddleware_decorators, UserContextMiddleware);
264
- __runInitializers(_init3, 1, UserContextMiddleware);
253
+ UserContextMiddleware = _ts_decorate3([
254
+ Injectable3()
255
+ ], UserContextMiddleware);
265
256
  export {
266
257
  CsrfMiddleware,
267
258
  CsrfTokenMiddleware,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/modules/devtool/index.ts","../src/modules/devtool/helper.ts","../src/middlewares/csrf_token/index.ts","../src/middlewares/csrf_token/helper.ts","../src/middlewares/csrf/index.ts","../src/middlewares/csrf/helper.ts","../src/middlewares/user-context/index.ts","../src/middlewares/user-context/helper.ts"],"sourcesContent":["import type { INestApplication } from '@nestjs/common';\n\nimport { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';\nimport { mkdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { resolveOptsWithDefaultValue, ensureDirAndWrite } from './helper';\nimport { DevToolsOptions } from './type';\n\nexport class DevToolsModule {\n static async mount(app: INestApplication, opts: DevToolsOptions = {}) {\n const options = resolveOptsWithDefaultValue(opts);\n const baseDirname = process.cwd(); // 跟随命令的根目录\n\n // 1) 生成 Swagger 文档\n const builder = new DocumentBuilder()\n .setTitle(options.swaggerOptions.title)\n .setVersion(options.swaggerOptions.version);\n const document = SwaggerModule.createDocument(app, builder.build(), {\n operationIdFactory: (_c, m) => m,\n });\n // 1.1) 挂载 Swagger UI(可关)\n if(options.needSetupServer){\n SwaggerModule.setup(options.docsPath, app, document, {\n customSiteTitle: options.swaggerOptions.customSiteTitle,\n customCss: options.swaggerOptions.customCss,\n swaggerOptions: { persistAuthorization: true },\n });\n console.log(`[OpenAPI] Swagger UI 已挂载至 ${options.docsPath}`);\n }\n\n // 2) 导出 openapi.json\n const openapiPath = resolve(baseDirname, options.openapiOut);\n ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));\n\n // 3) 生成 axios SDK(可关)\n if (options.needGenerateClientSdk) {\n const clientSdkOutPath = resolve(baseDirname, options.clientSdkOut);\n mkdirSync(clientSdkOutPath, { recursive: true });\n const { generate } = await import('openapi-typescript-codegen');\n await generate({\n input: openapiPath,\n output: clientSdkOutPath,\n httpClient: 'axios',\n useOptions: false,\n exportServices: true,\n });\n console.log('[OpenAPI] 导出 openapi.json 并生成 axios SDK ✅');\n }\n }\n}\n","import { dirname } from 'node:path';\nimport { writeFileSync, mkdirSync } from 'node:fs';\n\nimport { DevToolsOptions } from './type';\n/**\n * 标准化基础路径,确保以 '/' 开头且以 '/' 结尾\n *\n * @param rawBasePath 原始的基础路径,可能以 '/' 开头或结尾\n * @returns 标准化后的基础路径,确保以 '/' 开头且不以 '/' 结尾\n */\nexport function normalizeBasePath(rawBasePath: string): string {\n const normalizedBasePath = rawBasePath.startsWith('/')\n ? rawBasePath\n : `/${rawBasePath}`;\n return normalizedBasePath.endsWith('/')\n ? normalizedBasePath.slice(0, -1)\n : normalizedBasePath;\n}\n\ntype ResolvedDevToolsOptions = Required<\n Omit<DevToolsOptions, 'swaggerOptions'>\n> & {\n swaggerOptions: Required<NonNullable<DevToolsOptions['swaggerOptions']>>;\n};\n\nexport function resolveOptsWithDefaultValue(\n options: DevToolsOptions,\n): ResolvedDevToolsOptions {\n const basePath = normalizeBasePath(options.basePath || '/');\n const docsPath = normalizeBasePath(options.docsPath || `api/docs`);\n return {\n ...options,\n needSetupServer: options.needSetupServer ?? false,\n basePath,\n docsPath: `${basePath}${docsPath}`,\n openapiOut: options.openapiOut || './client/src/api/gen/openapi.json',\n clientSdkOut: options.clientSdkOut || './client/src/api/gen',\n needGenerateClientSdk: options.needGenerateClientSdk ?? true,\n swaggerOptions: {\n title: options.swaggerOptions?.title ?? 'NestJS Fullstack API',\n version: options.swaggerOptions?.version ?? '1.0.0',\n customSiteTitle:\n options.swaggerOptions?.customSiteTitle ?? 'API Documentation',\n customCss:\n options.swaggerOptions?.customCss ??\n '.swagger-ui .topbar { display: none }',\n },\n };\n}\n\nexport function ensureDirAndWrite(filePath: string, content: string) {\n // 1. 拿到文件的上级目录\n const dir = dirname(filePath);\n\n // 2. 确保目录存在,不存在就递归创建\n mkdirSync(dir, { recursive: true });\n\n // 3. 写文件\n writeFileSync(filePath, content);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\nimport { resolveCsrfTokenOptions, genToken } from './helper';\n\n@Injectable()\nexport class CsrfTokenMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfTokenOptions;\n\n public static configure(opts: CsrfTokenOptions) {\n this.options = resolveCsrfTokenOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { cookieKey, cookieMaxAge, cookiePath } = CsrfTokenMiddleware.options;\n const originToken = req.cookies[cookieKey.toLowerCase()];\n // 如果存在 Cookie,则直接消费,无需生成\n if (originToken) {\n req.csrfToken = originToken;\n next();\n } else {\n // 如果不存在 token,则生成新的 csrfToken,并 setCookie\n const token = genToken();\n req.csrfToken = token;\n res.cookie(cookieKey, token, {\n maxAge: cookieMaxAge,\n path: cookiePath,\n httpOnly: true,\n secure: true,\n sameSite: 'none',\n partitioned: true, // 默认开启 Partitioned Cookie\n });\n next();\n }\n }\n}\n","import crypto from 'crypto';\nimport { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\n\nexport function resolveCsrfTokenOptions(\n options: CsrfTokenOptions,\n): ResolvedCsrfTokenOptions {\n return {\n ...options,\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n cookieMaxAge: options.cookieMaxAge ?? 1000 *60 * 60 * 24 * 30,\n cookiePath: options.cookiePath ?? '/',\n };\n}\n\n// 生成 CsrfToken\nexport function genToken() {\n // 时间戳(秒级,和 Go 一致)\n const ts = Math.floor(Date.now() / 1000);\n\n // 随机 int64 模拟:生成 8 字节随机数并转成十进制字符串\n const randInt64 = BigInt(\n '0x' + crypto.randomBytes(8).toString('hex'),\n ).toString();\n\n // 拼接 \"<rand>.<timestamp>\"\n const s = `${randInt64}.${ts}`;\n\n // 计算 sha1\n const sha1 = crypto.createHash('sha1');\n sha1.update(s);\n\n // 返回 \"<sha1Hex>-<timestamp>\"\n return `${sha1.digest('hex')}-${ts}`;\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfOptions, ResolvedCsrfOptions } from './type';\nimport { resolveCsrfOptions, sendForbidden } from './helper';\n\n@Injectable()\nexport class CsrfMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfOptions;\n\n public static configure(opts: CsrfOptions) {\n this.options = resolveCsrfOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { headerKey, cookieKey } = CsrfMiddleware.options;\n const cookieCsrfToken = req.cookies[cookieKey.toLowerCase()];\n if (!cookieCsrfToken) {\n sendForbidden(res, 'csrf token not found in cookie.');\n return;\n }\n const headerCsrfToken = req.headers[headerKey.toLowerCase()];\n if (!headerCsrfToken) {\n sendForbidden(res, 'csrf token not found in header.');\n return;\n }\n if (cookieCsrfToken !== headerCsrfToken) {\n sendForbidden(res, 'csrf token not match.');\n return;\n }\n next();\n }\n}\n","import type { Response } from 'express';\n\nimport { CsrfOptions, ResolvedCsrfOptions } from './type';\n\nexport function resolveCsrfOptions(options: CsrfOptions): ResolvedCsrfOptions {\n return {\n ...options,\n headerKey: options.headerKey ?? 'x-suda-csrf-token',\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n };\n}\n\nexport function sendForbidden(res: Response, message: string) {\n res.status(403).send(`Forbidden,${message}`);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\nimport { getWebUserFromHeader } from './helper';\n\n@Injectable()\nexport class UserContextMiddleware implements NestMiddleware {\n\n public use(req: Request, _res: Response, next: NextFunction) {\n const webUser = getWebUserFromHeader(req);\n req.userContext = {\n userId: webUser?.user_id,\n tenantId: webUser?.tenant_id,\n appId: webUser?.app_id ?? '',\n }\n next();\n }\n}\n","import type { Request } from 'express';\n\nconst sudaWebUserHeaderKey = 'x-larkgw-suda-webuser';\n\ninterface SudaWebUser {\n user_id: string;\n tenant_id: number;\n app_id: string;\n}\n\nexport function getWebUserFromHeader(req: Request): SudaWebUser | null {\n const sudaWebUserContent = req.headers[sudaWebUserHeaderKey] as\n | string\n | undefined;\n if (!sudaWebUserContent) {\n return null;\n }\n try {\n const sudaWebUserJsonStr = decodeURIComponent(sudaWebUserContent);\n const sudaWebUserJson = JSON.parse(sudaWebUserJsonStr) as SudaWebUser;\n return sudaWebUserJson;\n } catch (err) {\n console.error('parse suda webuser from header failed, err=%o', err);\n return null;\n }\n return null;\n}\n"],"mappings":"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","names":["mkdirSync","mkdirSync","Injectable","_init","Injectable","Injectable","_init","Injectable"]}
1
+ {"version":3,"sources":["../src/modules/devtool/index.ts","../src/modules/devtool/helper.ts","../src/middlewares/csrf_token/index.ts","../src/middlewares/csrf_token/helper.ts","../src/middlewares/csrf/index.ts","../src/middlewares/csrf/helper.ts","../src/middlewares/user-context/index.ts","../src/middlewares/user-context/helper.ts"],"sourcesContent":["import type { INestApplication } from '@nestjs/common';\n\nimport { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';\nimport { mkdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { resolveOptsWithDefaultValue, ensureDirAndWrite } from './helper';\nimport { DevToolsOptions } from './type';\n\nexport class DevToolsModule {\n static async mount(app: INestApplication, opts: DevToolsOptions = {}) {\n const options = resolveOptsWithDefaultValue(opts);\n const baseDirname = process.cwd(); // 跟随命令的根目录\n\n // 1) 生成 Swagger 文档\n const builder = new DocumentBuilder()\n .setTitle(options.swaggerOptions.title)\n .setVersion(options.swaggerOptions.version);\n const document = SwaggerModule.createDocument(app, builder.build(), {\n operationIdFactory: (_c, m) => m,\n });\n // 1.1) 挂载 Swagger UI(可关)\n if(options.needSetupServer){\n SwaggerModule.setup(options.docsPath, app, document, {\n customSiteTitle: options.swaggerOptions.customSiteTitle,\n customCss: options.swaggerOptions.customCss,\n swaggerOptions: { persistAuthorization: true },\n });\n console.log(`[OpenAPI] Swagger UI 已挂载至 ${options.docsPath}`);\n }\n\n // 2) 导出 openapi.json\n const openapiPath = resolve(baseDirname, options.openapiOut);\n ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));\n\n // 3) 生成 axios SDK(可关)\n if (options.needGenerateClientSdk) {\n const clientSdkOutPath = resolve(baseDirname, options.clientSdkOut);\n mkdirSync(clientSdkOutPath, { recursive: true });\n const { generate } = await import('openapi-typescript-codegen');\n await generate({\n input: openapiPath,\n output: clientSdkOutPath,\n httpClient: 'axios',\n useOptions: false,\n exportServices: true,\n });\n console.log('[OpenAPI] 导出 openapi.json 并生成 axios SDK ✅');\n }\n }\n}\n","import { dirname } from 'node:path';\nimport { writeFileSync, mkdirSync } from 'node:fs';\n\nimport { DevToolsOptions } from './type';\n/**\n * 标准化基础路径,确保以 '/' 开头且以 '/' 结尾\n *\n * @param rawBasePath 原始的基础路径,可能以 '/' 开头或结尾\n * @returns 标准化后的基础路径,确保以 '/' 开头且不以 '/' 结尾\n */\nexport function normalizeBasePath(rawBasePath: string): string {\n const normalizedBasePath = rawBasePath.startsWith('/')\n ? rawBasePath\n : `/${rawBasePath}`;\n return normalizedBasePath.endsWith('/')\n ? normalizedBasePath.slice(0, -1)\n : normalizedBasePath;\n}\n\ntype ResolvedDevToolsOptions = Required<\n Omit<DevToolsOptions, 'swaggerOptions'>\n> & {\n swaggerOptions: Required<NonNullable<DevToolsOptions['swaggerOptions']>>;\n};\n\nexport function resolveOptsWithDefaultValue(\n options: DevToolsOptions,\n): ResolvedDevToolsOptions {\n const basePath = normalizeBasePath(options.basePath || '/');\n const docsPath = normalizeBasePath(options.docsPath || `api/docs`);\n return {\n ...options,\n needSetupServer: options.needSetupServer ?? false,\n basePath,\n docsPath: `${basePath}${docsPath}`,\n openapiOut: options.openapiOut || './client/src/api/gen/openapi.json',\n clientSdkOut: options.clientSdkOut || './client/src/api/gen',\n needGenerateClientSdk: options.needGenerateClientSdk ?? true,\n swaggerOptions: {\n title: options.swaggerOptions?.title ?? 'NestJS Fullstack API',\n version: options.swaggerOptions?.version ?? '1.0.0',\n customSiteTitle:\n options.swaggerOptions?.customSiteTitle ?? 'API Documentation',\n customCss:\n options.swaggerOptions?.customCss ??\n '.swagger-ui .topbar { display: none }',\n },\n };\n}\n\nexport function ensureDirAndWrite(filePath: string, content: string) {\n // 1. 拿到文件的上级目录\n const dir = dirname(filePath);\n\n // 2. 确保目录存在,不存在就递归创建\n mkdirSync(dir, { recursive: true });\n\n // 3. 写文件\n writeFileSync(filePath, content);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\nimport { resolveCsrfTokenOptions, genToken } from './helper';\n\n@Injectable()\nexport class CsrfTokenMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfTokenOptions;\n\n public static configure(opts: CsrfTokenOptions) {\n this.options = resolveCsrfTokenOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { cookieKey, cookieMaxAge, cookiePath } = CsrfTokenMiddleware.options;\n const originToken = req.cookies[cookieKey.toLowerCase()];\n // 如果存在 Cookie,则直接消费,无需生成\n if (originToken) {\n req.csrfToken = originToken;\n next();\n } else {\n // 如果不存在 token,则生成新的 csrfToken,并 setCookie\n const token = genToken();\n req.csrfToken = token;\n res.cookie(cookieKey, token, {\n maxAge: cookieMaxAge,\n path: cookiePath,\n httpOnly: true,\n secure: true,\n sameSite: 'none',\n partitioned: true, // 默认开启 Partitioned Cookie\n });\n next();\n }\n }\n}\n","import crypto from 'crypto';\nimport { CsrfTokenOptions, ResolvedCsrfTokenOptions } from './type';\n\nexport function resolveCsrfTokenOptions(\n options: CsrfTokenOptions,\n): ResolvedCsrfTokenOptions {\n return {\n ...options,\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n cookieMaxAge: options.cookieMaxAge ?? 1000 *60 * 60 * 24 * 30,\n cookiePath: options.cookiePath ?? '/',\n };\n}\n\n// 生成 CsrfToken\nexport function genToken() {\n // 时间戳(秒级,和 Go 一致)\n const ts = Math.floor(Date.now() / 1000);\n\n // 随机 int64 模拟:生成 8 字节随机数并转成十进制字符串\n const randInt64 = BigInt(\n '0x' + crypto.randomBytes(8).toString('hex'),\n ).toString();\n\n // 拼接 \"<rand>.<timestamp>\"\n const s = `${randInt64}.${ts}`;\n\n // 计算 sha1\n const sha1 = crypto.createHash('sha1');\n sha1.update(s);\n\n // 返回 \"<sha1Hex>-<timestamp>\"\n return `${sha1.digest('hex')}-${ts}`;\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\n\nimport type { CsrfOptions, ResolvedCsrfOptions } from './type';\nimport { resolveCsrfOptions, sendForbidden } from './helper';\n\n@Injectable()\nexport class CsrfMiddleware implements NestMiddleware {\n private static options: ResolvedCsrfOptions;\n\n public static configure(opts: CsrfOptions) {\n this.options = resolveCsrfOptions(opts);\n }\n\n public use(req: Request, res: Response, next: NextFunction) {\n const { headerKey, cookieKey } = CsrfMiddleware.options;\n const cookieCsrfToken = req.cookies[cookieKey.toLowerCase()];\n if (!cookieCsrfToken) {\n sendForbidden(res, 'csrf token not found in cookie.');\n return;\n }\n const headerCsrfToken = req.headers[headerKey.toLowerCase()];\n if (!headerCsrfToken) {\n sendForbidden(res, 'csrf token not found in header.');\n return;\n }\n if (cookieCsrfToken !== headerCsrfToken) {\n sendForbidden(res, 'csrf token not match.');\n return;\n }\n next();\n }\n}\n","import type { Response } from 'express';\n\nimport { CsrfOptions, ResolvedCsrfOptions } from './type';\n\nexport function resolveCsrfOptions(options: CsrfOptions): ResolvedCsrfOptions {\n return {\n ...options,\n headerKey: options.headerKey ?? 'x-suda-csrf-token',\n cookieKey: options.cookieKey ?? 'suda-csrf-token',\n };\n}\n\nexport function sendForbidden(res: Response, message: string) {\n res.status(403).send(`Forbidden,${message}`);\n}\n","import { Injectable, NestMiddleware } from '@nestjs/common';\nimport type { Request, Response, NextFunction } from 'express';\nimport { getWebUserFromHeader } from './helper';\n\n@Injectable()\nexport class UserContextMiddleware implements NestMiddleware {\n\n public use(req: Request, _res: Response, next: NextFunction) {\n const webUser = getWebUserFromHeader(req);\n req.userContext = {\n userId: webUser?.user_id,\n tenantId: webUser?.tenant_id,\n appId: webUser?.app_id ?? '',\n }\n next();\n }\n}\n","import type { Request } from 'express';\n\nconst sudaWebUserHeaderKey = 'x-larkgw-suda-webuser';\n\ninterface SudaWebUser {\n user_id: string;\n tenant_id: number;\n app_id: string;\n}\n\nexport function getWebUserFromHeader(req: Request): SudaWebUser | null {\n const sudaWebUserContent = req.headers[sudaWebUserHeaderKey] as\n | string\n | undefined;\n if (!sudaWebUserContent) {\n return null;\n }\n try {\n const sudaWebUserJsonStr = decodeURIComponent(sudaWebUserContent);\n const sudaWebUserJson = JSON.parse(sudaWebUserJsonStr) as SudaWebUser;\n return sudaWebUserJson;\n } catch (err) {\n console.error('parse suda webuser from header failed, err=%o', err);\n return null;\n }\n return null;\n}\n"],"mappings":"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","names":["SwaggerModule","DocumentBuilder","mkdirSync","resolve","dirname","writeFileSync","mkdirSync","normalizeBasePath","rawBasePath","normalizedBasePath","startsWith","endsWith","slice","resolveOptsWithDefaultValue","options","basePath","docsPath","needSetupServer","openapiOut","clientSdkOut","needGenerateClientSdk","swaggerOptions","title","version","customSiteTitle","customCss","ensureDirAndWrite","filePath","content","dir","dirname","mkdirSync","recursive","writeFileSync","DevToolsModule","mount","app","opts","options","resolveOptsWithDefaultValue","baseDirname","process","cwd","builder","DocumentBuilder","setTitle","swaggerOptions","title","setVersion","version","document","SwaggerModule","createDocument","build","operationIdFactory","_c","m","needSetupServer","setup","docsPath","customSiteTitle","customCss","persistAuthorization","console","log","openapiPath","resolve","openapiOut","ensureDirAndWrite","JSON","stringify","needGenerateClientSdk","clientSdkOutPath","clientSdkOut","mkdirSync","recursive","generate","input","output","httpClient","useOptions","exportServices","Injectable","crypto","resolveCsrfTokenOptions","options","cookieKey","cookieMaxAge","cookiePath","genToken","ts","Math","floor","Date","now","randInt64","BigInt","crypto","randomBytes","toString","s","sha1","createHash","update","digest","CsrfTokenMiddleware","options","configure","opts","resolveCsrfTokenOptions","use","req","res","next","cookieKey","cookieMaxAge","cookiePath","originToken","cookies","toLowerCase","csrfToken","token","genToken","cookie","maxAge","path","httpOnly","secure","sameSite","partitioned","Injectable","resolveCsrfOptions","options","headerKey","cookieKey","sendForbidden","res","message","status","send","CsrfMiddleware","options","configure","opts","resolveCsrfOptions","use","req","res","next","headerKey","cookieKey","cookieCsrfToken","cookies","toLowerCase","sendForbidden","headerCsrfToken","headers","Injectable","sudaWebUserHeaderKey","getWebUserFromHeader","req","sudaWebUserContent","headers","sudaWebUserJsonStr","decodeURIComponent","sudaWebUserJson","JSON","parse","err","console","error","UserContextMiddleware","use","req","_res","next","webUser","getWebUserFromHeader","userContext","userId","user_id","tenantId","tenant_id","appId","app_id"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-nestjs-core",
3
- "version": "0.1.0-alpha.10",
3
+ "version": "0.1.0-alpha.11",
4
4
  "description": "FullStack Nestjs Core",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,6 +28,15 @@
28
28
  "require": "./dist/index.cjs"
29
29
  }
30
30
  },
31
+ "scripts": {
32
+ "build": "tsup",
33
+ "dev": "tsup --watch",
34
+ "typecheck": "tsc --noEmit",
35
+ "test": "vitest run",
36
+ "test:watch": "vitest",
37
+ "lint": "echo 'ESLint skipped for TypeScript files'",
38
+ "lint:fix": "eslint src --ext .ts --fix"
39
+ },
31
40
  "dependencies": {
32
41
  "openapi-typescript-codegen": "^0.29.0"
33
42
  },
@@ -44,14 +53,5 @@
44
53
  "@nestjs/common": "^10.4.20",
45
54
  "@nestjs/platform-express": "^10.4.20",
46
55
  "@nestjs/swagger": "^7.4.2"
47
- },
48
- "scripts": {
49
- "build": "tsup",
50
- "dev": "tsup --watch",
51
- "typecheck": "tsc --noEmit",
52
- "test": "vitest run",
53
- "test:watch": "vitest",
54
- "lint": "echo 'ESLint skipped for TypeScript files'",
55
- "lint:fix": "eslint src --ext .ts --fix"
56
56
  }
57
- }
57
+ }