@lark-apaas/fullstack-nestjs-core 0.1.0-alpha.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +71 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +71 -76
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
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,11 +50,13 @@ 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`);
|
|
99
57
|
return {
|
|
100
58
|
...options,
|
|
59
|
+
needSetupServer: options.needSetupServer ?? false,
|
|
101
60
|
basePath,
|
|
102
61
|
docsPath: `${basePath}${docsPath}`,
|
|
103
62
|
openapiOut: options.openapiOut || "./client/src/api/gen/openapi.json",
|
|
@@ -111,31 +70,45 @@ function resolveOptsWithDefaultValue(options) {
|
|
|
111
70
|
}
|
|
112
71
|
};
|
|
113
72
|
}
|
|
73
|
+
__name(resolveOptsWithDefaultValue, "resolveOptsWithDefaultValue");
|
|
114
74
|
function ensureDirAndWrite(filePath, content) {
|
|
115
75
|
const dir = (0, import_node_path.dirname)(filePath);
|
|
116
|
-
(0, import_node_fs.mkdirSync)(dir, {
|
|
76
|
+
(0, import_node_fs.mkdirSync)(dir, {
|
|
77
|
+
recursive: true
|
|
78
|
+
});
|
|
117
79
|
(0, import_node_fs.writeFileSync)(filePath, content);
|
|
118
80
|
}
|
|
81
|
+
__name(ensureDirAndWrite, "ensureDirAndWrite");
|
|
119
82
|
|
|
120
83
|
// src/modules/devtool/index.ts
|
|
121
84
|
var DevToolsModule = class {
|
|
85
|
+
static {
|
|
86
|
+
__name(this, "DevToolsModule");
|
|
87
|
+
}
|
|
122
88
|
static async mount(app, opts = {}) {
|
|
123
89
|
const options = resolveOptsWithDefaultValue(opts);
|
|
124
90
|
const baseDirname = process.cwd();
|
|
125
91
|
const builder = new import_swagger.DocumentBuilder().setTitle(options.swaggerOptions.title).setVersion(options.swaggerOptions.version);
|
|
126
92
|
const document = import_swagger.SwaggerModule.createDocument(app, builder.build(), {
|
|
127
|
-
operationIdFactory: (_c, m) => m
|
|
128
|
-
});
|
|
129
|
-
import_swagger.SwaggerModule.setup(options.docsPath, app, document, {
|
|
130
|
-
customSiteTitle: options.swaggerOptions.customSiteTitle,
|
|
131
|
-
customCss: options.swaggerOptions.customCss,
|
|
132
|
-
swaggerOptions: { persistAuthorization: true }
|
|
93
|
+
operationIdFactory: /* @__PURE__ */ __name((_c, m) => m, "operationIdFactory")
|
|
133
94
|
});
|
|
95
|
+
if (options.needSetupServer) {
|
|
96
|
+
import_swagger.SwaggerModule.setup(options.docsPath, app, document, {
|
|
97
|
+
customSiteTitle: options.swaggerOptions.customSiteTitle,
|
|
98
|
+
customCss: options.swaggerOptions.customCss,
|
|
99
|
+
swaggerOptions: {
|
|
100
|
+
persistAuthorization: true
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
console.log(`[OpenAPI] Swagger UI \u5DF2\u6302\u8F7D\u81F3 ${options.docsPath}`);
|
|
104
|
+
}
|
|
134
105
|
const openapiPath = (0, import_node_path2.resolve)(baseDirname, options.openapiOut);
|
|
135
106
|
ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));
|
|
136
107
|
if (options.needGenerateClientSdk) {
|
|
137
108
|
const clientSdkOutPath = (0, import_node_path2.resolve)(baseDirname, options.clientSdkOut);
|
|
138
|
-
(0, import_node_fs2.mkdirSync)(clientSdkOutPath, {
|
|
109
|
+
(0, import_node_fs2.mkdirSync)(clientSdkOutPath, {
|
|
110
|
+
recursive: true
|
|
111
|
+
});
|
|
139
112
|
const { generate } = await import("openapi-typescript-codegen");
|
|
140
113
|
await generate({
|
|
141
114
|
input: openapiPath,
|
|
@@ -162,21 +135,29 @@ function resolveCsrfTokenOptions(options) {
|
|
|
162
135
|
cookiePath: options.cookiePath ?? "/"
|
|
163
136
|
};
|
|
164
137
|
}
|
|
138
|
+
__name(resolveCsrfTokenOptions, "resolveCsrfTokenOptions");
|
|
165
139
|
function genToken() {
|
|
166
140
|
const ts = Math.floor(Date.now() / 1e3);
|
|
167
|
-
const randInt64 = BigInt(
|
|
168
|
-
"0x" + import_crypto.default.randomBytes(8).toString("hex")
|
|
169
|
-
).toString();
|
|
141
|
+
const randInt64 = BigInt("0x" + import_crypto.default.randomBytes(8).toString("hex")).toString();
|
|
170
142
|
const s = `${randInt64}.${ts}`;
|
|
171
143
|
const sha1 = import_crypto.default.createHash("sha1");
|
|
172
144
|
sha1.update(s);
|
|
173
145
|
return `${sha1.digest("hex")}-${ts}`;
|
|
174
146
|
}
|
|
147
|
+
__name(genToken, "genToken");
|
|
175
148
|
|
|
176
149
|
// src/middlewares/csrf_token/index.ts
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
+
}
|
|
180
161
|
static options;
|
|
181
162
|
static configure(opts) {
|
|
182
163
|
this.options = resolveCsrfTokenOptions(opts);
|
|
@@ -197,16 +178,14 @@ var _CsrfTokenMiddleware = class _CsrfTokenMiddleware {
|
|
|
197
178
|
secure: true,
|
|
198
179
|
sameSite: "none",
|
|
199
180
|
partitioned: true
|
|
200
|
-
// 默认开启 Partitioned Cookie
|
|
201
181
|
});
|
|
202
182
|
next();
|
|
203
183
|
}
|
|
204
184
|
}
|
|
205
185
|
};
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
var CsrfTokenMiddleware = _CsrfTokenMiddleware;
|
|
186
|
+
CsrfTokenMiddleware = _ts_decorate([
|
|
187
|
+
(0, import_common.Injectable)()
|
|
188
|
+
], CsrfTokenMiddleware);
|
|
210
189
|
|
|
211
190
|
// src/middlewares/csrf/index.ts
|
|
212
191
|
var import_common2 = require("@nestjs/common");
|
|
@@ -219,14 +198,24 @@ function resolveCsrfOptions(options) {
|
|
|
219
198
|
cookieKey: options.cookieKey ?? "suda-csrf-token"
|
|
220
199
|
};
|
|
221
200
|
}
|
|
201
|
+
__name(resolveCsrfOptions, "resolveCsrfOptions");
|
|
222
202
|
function sendForbidden(res, message) {
|
|
223
203
|
res.status(403).send(`Forbidden\uFF0C${message}`);
|
|
224
204
|
}
|
|
205
|
+
__name(sendForbidden, "sendForbidden");
|
|
225
206
|
|
|
226
207
|
// src/middlewares/csrf/index.ts
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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
|
+
}
|
|
230
219
|
static options;
|
|
231
220
|
static configure(opts) {
|
|
232
221
|
this.options = resolveCsrfOptions(opts);
|
|
@@ -250,10 +239,9 @@ var _CsrfMiddleware = class _CsrfMiddleware {
|
|
|
250
239
|
next();
|
|
251
240
|
}
|
|
252
241
|
};
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
var CsrfMiddleware = _CsrfMiddleware;
|
|
242
|
+
CsrfMiddleware = _ts_decorate2([
|
|
243
|
+
(0, import_common2.Injectable)()
|
|
244
|
+
], CsrfMiddleware);
|
|
257
245
|
|
|
258
246
|
// src/middlewares/user-context/index.ts
|
|
259
247
|
var import_common3 = require("@nestjs/common");
|
|
@@ -275,11 +263,20 @@ function getWebUserFromHeader(req) {
|
|
|
275
263
|
}
|
|
276
264
|
return null;
|
|
277
265
|
}
|
|
266
|
+
__name(getWebUserFromHeader, "getWebUserFromHeader");
|
|
278
267
|
|
|
279
268
|
// src/middlewares/user-context/index.ts
|
|
280
|
-
|
|
281
|
-
|
|
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");
|
|
282
276
|
var UserContextMiddleware = class {
|
|
277
|
+
static {
|
|
278
|
+
__name(this, "UserContextMiddleware");
|
|
279
|
+
}
|
|
283
280
|
use(req, _res, next) {
|
|
284
281
|
const webUser = getWebUserFromHeader(req);
|
|
285
282
|
req.userContext = {
|
|
@@ -290,9 +287,9 @@ var UserContextMiddleware = class {
|
|
|
290
287
|
next();
|
|
291
288
|
}
|
|
292
289
|
};
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
290
|
+
UserContextMiddleware = _ts_decorate3([
|
|
291
|
+
(0, import_common3.Injectable)()
|
|
292
|
+
], UserContextMiddleware);
|
|
296
293
|
// Annotate the CommonJS export names for ESM import in node:
|
|
297
294
|
0 && (module.exports = {
|
|
298
295
|
CsrfMiddleware,
|
package/dist/index.cjs.map
CHANGED
|
@@ -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\n SwaggerModule.setup(options.docsPath, app, document, {\n customSiteTitle: options.swaggerOptions.customSiteTitle,\n customCss: options.swaggerOptions.customCss,\n swaggerOptions: { persistAuthorization: true },\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 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":"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","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.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
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,11 +13,13 @@ 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`);
|
|
64
20
|
return {
|
|
65
21
|
...options,
|
|
22
|
+
needSetupServer: options.needSetupServer ?? false,
|
|
66
23
|
basePath,
|
|
67
24
|
docsPath: `${basePath}${docsPath}`,
|
|
68
25
|
openapiOut: options.openapiOut || "./client/src/api/gen/openapi.json",
|
|
@@ -76,31 +33,45 @@ function resolveOptsWithDefaultValue(options) {
|
|
|
76
33
|
}
|
|
77
34
|
};
|
|
78
35
|
}
|
|
36
|
+
__name(resolveOptsWithDefaultValue, "resolveOptsWithDefaultValue");
|
|
79
37
|
function ensureDirAndWrite(filePath, content) {
|
|
80
38
|
const dir = dirname(filePath);
|
|
81
|
-
mkdirSync(dir, {
|
|
39
|
+
mkdirSync(dir, {
|
|
40
|
+
recursive: true
|
|
41
|
+
});
|
|
82
42
|
writeFileSync(filePath, content);
|
|
83
43
|
}
|
|
44
|
+
__name(ensureDirAndWrite, "ensureDirAndWrite");
|
|
84
45
|
|
|
85
46
|
// src/modules/devtool/index.ts
|
|
86
47
|
var DevToolsModule = class {
|
|
48
|
+
static {
|
|
49
|
+
__name(this, "DevToolsModule");
|
|
50
|
+
}
|
|
87
51
|
static async mount(app, opts = {}) {
|
|
88
52
|
const options = resolveOptsWithDefaultValue(opts);
|
|
89
53
|
const baseDirname = process.cwd();
|
|
90
54
|
const builder = new DocumentBuilder().setTitle(options.swaggerOptions.title).setVersion(options.swaggerOptions.version);
|
|
91
55
|
const document = SwaggerModule.createDocument(app, builder.build(), {
|
|
92
|
-
operationIdFactory: (_c, m) => m
|
|
93
|
-
});
|
|
94
|
-
SwaggerModule.setup(options.docsPath, app, document, {
|
|
95
|
-
customSiteTitle: options.swaggerOptions.customSiteTitle,
|
|
96
|
-
customCss: options.swaggerOptions.customCss,
|
|
97
|
-
swaggerOptions: { persistAuthorization: true }
|
|
56
|
+
operationIdFactory: /* @__PURE__ */ __name((_c, m) => m, "operationIdFactory")
|
|
98
57
|
});
|
|
58
|
+
if (options.needSetupServer) {
|
|
59
|
+
SwaggerModule.setup(options.docsPath, app, document, {
|
|
60
|
+
customSiteTitle: options.swaggerOptions.customSiteTitle,
|
|
61
|
+
customCss: options.swaggerOptions.customCss,
|
|
62
|
+
swaggerOptions: {
|
|
63
|
+
persistAuthorization: true
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
console.log(`[OpenAPI] Swagger UI \u5DF2\u6302\u8F7D\u81F3 ${options.docsPath}`);
|
|
67
|
+
}
|
|
99
68
|
const openapiPath = resolve(baseDirname, options.openapiOut);
|
|
100
69
|
ensureDirAndWrite(openapiPath, JSON.stringify(document, null, 2));
|
|
101
70
|
if (options.needGenerateClientSdk) {
|
|
102
71
|
const clientSdkOutPath = resolve(baseDirname, options.clientSdkOut);
|
|
103
|
-
mkdirSync2(clientSdkOutPath, {
|
|
72
|
+
mkdirSync2(clientSdkOutPath, {
|
|
73
|
+
recursive: true
|
|
74
|
+
});
|
|
104
75
|
const { generate } = await import("openapi-typescript-codegen");
|
|
105
76
|
await generate({
|
|
106
77
|
input: openapiPath,
|
|
@@ -127,21 +98,29 @@ function resolveCsrfTokenOptions(options) {
|
|
|
127
98
|
cookiePath: options.cookiePath ?? "/"
|
|
128
99
|
};
|
|
129
100
|
}
|
|
101
|
+
__name(resolveCsrfTokenOptions, "resolveCsrfTokenOptions");
|
|
130
102
|
function genToken() {
|
|
131
103
|
const ts = Math.floor(Date.now() / 1e3);
|
|
132
|
-
const randInt64 = BigInt(
|
|
133
|
-
"0x" + crypto.randomBytes(8).toString("hex")
|
|
134
|
-
).toString();
|
|
104
|
+
const randInt64 = BigInt("0x" + crypto.randomBytes(8).toString("hex")).toString();
|
|
135
105
|
const s = `${randInt64}.${ts}`;
|
|
136
106
|
const sha1 = crypto.createHash("sha1");
|
|
137
107
|
sha1.update(s);
|
|
138
108
|
return `${sha1.digest("hex")}-${ts}`;
|
|
139
109
|
}
|
|
110
|
+
__name(genToken, "genToken");
|
|
140
111
|
|
|
141
112
|
// src/middlewares/csrf_token/index.ts
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
+
}
|
|
145
124
|
static options;
|
|
146
125
|
static configure(opts) {
|
|
147
126
|
this.options = resolveCsrfTokenOptions(opts);
|
|
@@ -162,16 +141,14 @@ var _CsrfTokenMiddleware = class _CsrfTokenMiddleware {
|
|
|
162
141
|
secure: true,
|
|
163
142
|
sameSite: "none",
|
|
164
143
|
partitioned: true
|
|
165
|
-
// 默认开启 Partitioned Cookie
|
|
166
144
|
});
|
|
167
145
|
next();
|
|
168
146
|
}
|
|
169
147
|
}
|
|
170
148
|
};
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
var CsrfTokenMiddleware = _CsrfTokenMiddleware;
|
|
149
|
+
CsrfTokenMiddleware = _ts_decorate([
|
|
150
|
+
Injectable()
|
|
151
|
+
], CsrfTokenMiddleware);
|
|
175
152
|
|
|
176
153
|
// src/middlewares/csrf/index.ts
|
|
177
154
|
import { Injectable as Injectable2 } from "@nestjs/common";
|
|
@@ -184,14 +161,24 @@ function resolveCsrfOptions(options) {
|
|
|
184
161
|
cookieKey: options.cookieKey ?? "suda-csrf-token"
|
|
185
162
|
};
|
|
186
163
|
}
|
|
164
|
+
__name(resolveCsrfOptions, "resolveCsrfOptions");
|
|
187
165
|
function sendForbidden(res, message) {
|
|
188
166
|
res.status(403).send(`Forbidden\uFF0C${message}`);
|
|
189
167
|
}
|
|
168
|
+
__name(sendForbidden, "sendForbidden");
|
|
190
169
|
|
|
191
170
|
// src/middlewares/csrf/index.ts
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
+
}
|
|
195
182
|
static options;
|
|
196
183
|
static configure(opts) {
|
|
197
184
|
this.options = resolveCsrfOptions(opts);
|
|
@@ -215,10 +202,9 @@ var _CsrfMiddleware = class _CsrfMiddleware {
|
|
|
215
202
|
next();
|
|
216
203
|
}
|
|
217
204
|
};
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
var CsrfMiddleware = _CsrfMiddleware;
|
|
205
|
+
CsrfMiddleware = _ts_decorate2([
|
|
206
|
+
Injectable2()
|
|
207
|
+
], CsrfMiddleware);
|
|
222
208
|
|
|
223
209
|
// src/middlewares/user-context/index.ts
|
|
224
210
|
import { Injectable as Injectable3 } from "@nestjs/common";
|
|
@@ -240,11 +226,20 @@ function getWebUserFromHeader(req) {
|
|
|
240
226
|
}
|
|
241
227
|
return null;
|
|
242
228
|
}
|
|
229
|
+
__name(getWebUserFromHeader, "getWebUserFromHeader");
|
|
243
230
|
|
|
244
231
|
// src/middlewares/user-context/index.ts
|
|
245
|
-
|
|
246
|
-
|
|
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");
|
|
247
239
|
var UserContextMiddleware = class {
|
|
240
|
+
static {
|
|
241
|
+
__name(this, "UserContextMiddleware");
|
|
242
|
+
}
|
|
248
243
|
use(req, _res, next) {
|
|
249
244
|
const webUser = getWebUserFromHeader(req);
|
|
250
245
|
req.userContext = {
|
|
@@ -255,9 +250,9 @@ var UserContextMiddleware = class {
|
|
|
255
250
|
next();
|
|
256
251
|
}
|
|
257
252
|
};
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
253
|
+
UserContextMiddleware = _ts_decorate3([
|
|
254
|
+
Injectable3()
|
|
255
|
+
], UserContextMiddleware);
|
|
261
256
|
export {
|
|
262
257
|
CsrfMiddleware,
|
|
263
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\n SwaggerModule.setup(options.docsPath, app, document, {\n customSiteTitle: options.swaggerOptions.customSiteTitle,\n customCss: options.swaggerOptions.customCss,\n swaggerOptions: { persistAuthorization: true },\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 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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAS,eAAe,uBAAuB;AAC/C,SAAS,aAAAA,kBAAiB;AAC1B,SAAS,eAAe;;;ACJxB,SAAS,eAAe;AACxB,SAAS,eAAe,iBAAiB;AASlC,SAAS,kBAAkB,aAA6B;AAC7D,QAAM,qBAAqB,YAAY,WAAW,GAAG,IACjD,cACA,IAAI,WAAW;AACnB,SAAO,mBAAmB,SAAS,GAAG,IAClC,mBAAmB,MAAM,GAAG,EAAE,IAC9B;AACN;AAQO,SAAS,4BACd,SACyB;AACzB,QAAM,WAAW,kBAAkB,QAAQ,YAAY,GAAG;AAC1D,QAAM,WAAW,kBAAkB,QAAQ,YAAY,UAAU;AACjE,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA,UAAU,GAAG,QAAQ,GAAG,QAAQ;AAAA,IAChC,YAAY,QAAQ,cAAc;AAAA,IAClC,cAAc,QAAQ,gBAAgB;AAAA,IACtC,uBAAuB,QAAQ,yBAAyB;AAAA,IACxD,gBAAgB;AAAA,MACd,OAAO,QAAQ,gBAAgB,SAAS;AAAA,MACxC,SAAS,QAAQ,gBAAgB,WAAW;AAAA,MAC5C,iBACE,QAAQ,gBAAgB,mBAAmB;AAAA,MAC7C,WACE,QAAQ,gBAAgB,aACxB;AAAA,IACJ;AAAA,EACF;AACF;AAEO,SAAS,kBAAkB,UAAkB,SAAiB;AAEnE,QAAM,MAAM,QAAQ,QAAQ;AAG5B,YAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAGlC,gBAAc,UAAU,OAAO;AACjC;;;ADjDO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,aAAa,MAAM,KAAuB,OAAwB,CAAC,GAAG;AACpE,UAAM,UAAU,4BAA4B,IAAI;AAChD,UAAM,cAAc,QAAQ,IAAI;AAGhC,UAAM,UAAU,IAAI,gBAAgB,EACjC,SAAS,QAAQ,eAAe,KAAK,EACrC,WAAW,QAAQ,eAAe,OAAO;AAC5C,UAAM,WAAW,cAAc,eAAe,KAAK,QAAQ,MAAM,GAAG;AAAA,MAClE,oBAAoB,CAAC,IAAI,MAAM;AAAA,IACjC,CAAC;AAED,kBAAc,MAAM,QAAQ,UAAU,KAAK,UAAU;AAAA,MACnD,iBAAiB,QAAQ,eAAe;AAAA,MACxC,WAAW,QAAQ,eAAe;AAAA,MAClC,gBAAgB,EAAE,sBAAsB,KAAK;AAAA,IAC/C,CAAC;AAGD,UAAM,cAAc,QAAQ,aAAa,QAAQ,UAAU;AAC3D,sBAAkB,aAAa,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAGhE,QAAI,QAAQ,uBAAuB;AACjC,YAAM,mBAAmB,QAAQ,aAAa,QAAQ,YAAY;AAClE,MAAAC,WAAU,kBAAkB,EAAE,WAAW,KAAK,CAAC;AAC/C,YAAM,EAAE,SAAS,IAAI,MAAM,OAAO,4BAA4B;AAC9D,YAAM,SAAS;AAAA,QACb,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,gBAAgB;AAAA,MAClB,CAAC;AACD,cAAQ,IAAI,yEAA2C;AAAA,IACzD;AAAA,EACF;AACF;;;AE/CA,SAAS,kBAAkC;;;ACA3C,OAAO,YAAY;AAGZ,SAAS,wBACd,SAC0B;AAC1B,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW,QAAQ,aAAa;AAAA,IAChC,cAAc,QAAQ,gBAAgB,MAAM,KAAK,KAAK,KAAK;AAAA,IAC3D,YAAY,QAAQ,cAAc;AAAA,EACpC;AACF;AAGO,SAAS,WAAW;AAEzB,QAAM,KAAK,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAGvC,QAAM,YAAY;AAAA,IAChB,OAAO,OAAO,YAAY,CAAC,EAAE,SAAS,KAAK;AAAA,EAC7C,EAAE,SAAS;AAGX,QAAM,IAAI,GAAG,SAAS,IAAI,EAAE;AAG5B,QAAM,OAAO,OAAO,WAAW,MAAM;AACrC,OAAK,OAAO,CAAC;AAGb,SAAO,GAAG,KAAK,OAAO,KAAK,CAAC,IAAI,EAAE;AACpC;;;ADjCA;AAMA,mCAAC,WAAW;AACL,IAAM,uBAAN,MAAM,qBAA8C;AAAA,EACzD,OAAe;AAAA,EAEf,OAAc,UAAU,MAAwB;AAC9C,SAAK,UAAU,wBAAwB,IAAI;AAAA,EAC7C;AAAA,EAEO,IAAI,KAAc,KAAe,MAAoB;AAC1D,UAAM,EAAE,WAAW,cAAc,WAAW,IAAI,qBAAoB;AACpE,UAAM,cAAc,IAAI,QAAQ,UAAU,YAAY,CAAC;AAEvD,QAAI,aAAa;AACf,UAAI,YAAY;AAChB,WAAK;AAAA,IACP,OAAO;AAEL,YAAM,QAAQ,SAAS;AACvB,UAAI,YAAY;AAChB,UAAI,OAAO,WAAW,OAAO;AAAA,QAC3B,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,aAAa;AAAA;AAAA,MACf,CAAC;AACD,WAAK;AAAA,IACP;AAAA,EACF;AACF;AA7BO;AAAM,uBAAN,mDADP,iCACa;AAAN,4BAAM;AAAN,IAAM,sBAAN;;;AEPP,SAAS,cAAAC,mBAAkC;;;ACIpC,SAAS,mBAAmB,SAA2C;AAC5E,SAAO;AAAA,IACL,GAAG;AAAA,IACH,WAAW,QAAQ,aAAa;AAAA,IAChC,WAAW,QAAQ,aAAa;AAAA,EAClC;AACF;AAEO,SAAS,cAAc,KAAe,SAAiB;AAC5D,MAAI,OAAO,GAAG,EAAE,KAAK,kBAAa,OAAO,EAAE;AAC7C;;;ADdA,gCAAAC;AAMA,8BAACC,YAAW;AACL,IAAM,kBAAN,MAAM,gBAAyC;AAAA,EACpD,OAAe;AAAA,EAEf,OAAc,UAAU,MAAmB;AACzC,SAAK,UAAU,mBAAmB,IAAI;AAAA,EACxC;AAAA,EAEO,IAAI,KAAc,KAAe,MAAoB;AAC1D,UAAM,EAAE,WAAW,UAAU,IAAI,gBAAe;AAChD,UAAM,kBAAkB,IAAI,QAAQ,UAAU,YAAY,CAAC;AAC3D,QAAI,CAAC,iBAAiB;AACpB,oBAAc,KAAK,iCAAiC;AACpD;AAAA,IACF;AACA,UAAM,kBAAkB,IAAI,QAAQ,UAAU,YAAY,CAAC;AAC3D,QAAI,CAAC,iBAAiB;AACpB,oBAAc,KAAK,iCAAiC;AACpD;AAAA,IACF;AACA,QAAI,oBAAoB,iBAAiB;AACvC,oBAAc,KAAK,uBAAuB;AAC1C;AAAA,IACF;AACA,SAAK;AAAA,EACP;AACF;AAzBOD,SAAA;AAAM,kBAAN,kBAAAA,QAAA,qBADP,4BACa;AAAN,kBAAAA,QAAA,GAAM;AAAN,IAAM,iBAAN;;;AEPP,SAAS,cAAAE,mBAAkC;;;ACE3C,IAAM,uBAAuB;AAQtB,SAAS,qBAAqB,KAAkC;AACrE,QAAM,qBAAqB,IAAI,QAAQ,oBAAoB;AAG3D,MAAI,CAAC,oBAAoB;AACvB,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,qBAAqB,mBAAmB,kBAAkB;AAChE,UAAM,kBAAkB,KAAK,MAAM,kBAAkB;AACrD,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAQ,MAAM,iDAAiD,GAAG;AAClE,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;AD1BA,uCAAAC;AAIA,qCAACC,YAAW;AACL,IAAM,wBAAN,MAAsD;AAAA,EAEpD,IAAI,KAAc,MAAgB,MAAoB;AAC3D,UAAM,UAAU,qBAAqB,GAAG;AACxC,QAAI,cAAc;AAAA,MAChB,QAAQ,SAAS;AAAA,MACjB,UAAU,SAAS;AAAA,MACnB,OAAO,SAAS,UAAU;AAAA,IAC5B;AACA,SAAK;AAAA,EACP;AACF;AAXOD,SAAA;AAAM,wBAAN,kBAAAA,QAAA,4BADP,mCACa;AAAN,kBAAAA,QAAA,GAAM;","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": "
|
|
3
|
+
"version": "1.0.0",
|
|
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
|
},
|
|
@@ -38,20 +47,11 @@
|
|
|
38
47
|
"@types/cookie-parser": "^1.4.9",
|
|
39
48
|
"@types/express": "^5.0.3",
|
|
40
49
|
"tsup": "^8.0.0",
|
|
41
|
-
"typescript": "^5.
|
|
50
|
+
"typescript": "^5.0.0"
|
|
42
51
|
},
|
|
43
52
|
"peerDependencies": {
|
|
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
|
+
}
|