nesties 1.1.1 → 1.1.3

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../index.ts", "../src/insert-field.ts", "../src/merge.ts", "../src/return-message.ts", "../src/openapi.ts", "../src/pipe.ts", "../src/token.guard.ts", "../src/abort-utils.ts", "../src/abort-http-signal.ts", "../src/abortable-module/abortable.token.ts", "../src/abortable-module/abort-signal.provider.ts", "../src/abortable-module/abortable.module.ts"],
4
+ "sourcesContent": ["export * from './src/insert-field';\nexport * from './src/merge';\nexport * from './src/return-message';\nexport * from './src/openapi';\nexport * from './src/pipe';\nexport * from './src/token.guard';\nexport * from './src/abort-utils';\nexport * from './src/abortable-module';\n", "import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';\n\nexport type AnyClass = new (...args: any[]) => any;\nexport type ClassOrArray = AnyClass | [AnyClass];\nexport type ClassType<T> = new (...args: any[]) => T;\nexport type TypeFromClass<T> = T extends new (...args: any[]) => infer U\n ? U\n : never;\nexport type ParamsFromClass<T> = T extends new (...args: infer U) => any\n ? U\n : never;\nexport type ParseType<IC extends ClassOrArray> = IC extends [infer U]\n ? TypeFromClass<U>[]\n : TypeFromClass<IC>;\n\nexport function getClassFromClassOrArray(o: ClassOrArray) {\n return o instanceof Array ? o[0] : o;\n}\n\nexport interface InsertOptions<C extends ClassOrArray = ClassOrArray> {\n type: C;\n options?: ApiPropertyOptions;\n}\n\ntype TypeFromInsertOptions<O extends InsertOptions> =\n O extends InsertOptions<infer C>\n ?\n | ParseType<C>\n | (O extends { options: { required: true } } ? never : undefined)\n : never;\n\ntype Merge<T, U> = {\n [K in keyof T | keyof U]: K extends keyof T\n ? T[K]\n : K extends keyof U\n ? U[K]\n : never;\n};\n\nexport function InsertField<\n C extends AnyClass,\n M extends Record<string, InsertOptions>,\n>(\n cl: C,\n map: M,\n newName?: string,\n): new (...args: ParamsFromClass<C>) => Merge<\n {\n [F in keyof M]: TypeFromInsertOptions<M[F]>;\n },\n TypeFromClass<C>\n> {\n const extendedCl = class extends cl {};\n for (const key in map) {\n ApiProperty({\n type: map[key].type,\n ...(map[key].options || {}),\n })(extendedCl.prototype, key);\n }\n Object.defineProperty(extendedCl, 'name', {\n value: newName || cl.name,\n });\n return extendedCl;\n}\n", "export function MergePropertyDecorators(\n decs: PropertyDecorator[],\n): PropertyDecorator {\n return (obj, key) => {\n for (const dec of decs) {\n dec(obj, key);\n }\n };\n}\n\nexport function MergeMethodDecorators(\n decs: MethodDecorator[],\n): MethodDecorator {\n return (obj, key, descriptor) => {\n for (const dec of decs) {\n dec(obj, key, descriptor);\n }\n };\n}\n\nexport function MergeClassDecorators(decs: ClassDecorator[]): ClassDecorator {\n return (obj) => {\n for (const dec of decs) {\n dec(obj);\n }\n };\n}\n\nexport function MergeParameterDecorators(\n decs: ParameterDecorator[],\n): ParameterDecorator {\n return (obj, key, index) => {\n for (const dec of decs) {\n dec(obj, key, index);\n }\n };\n}\n\nexport function MergeClassOrMethodDecorators(\n decs: (ClassDecorator & MethodDecorator)[],\n): ClassDecorator & MethodDecorator {\n return (obj, key?, descriptor?) => {\n if (descriptor) {\n for (const dec of decs) {\n dec(obj, key, descriptor);\n }\n } else {\n for (const dec of decs) {\n dec(obj);\n }\n }\n };\n}\n", "import { ApiProperty } from '@nestjs/swagger';\nimport { HttpException } from '@nestjs/common';\nimport {\n AnyClass,\n ClassOrArray,\n getClassFromClassOrArray,\n InsertField,\n ParseType,\n} from './insert-field';\n\nexport interface PageSettingsWise {\n pageCount: number;\n recordsPerPage: number;\n}\n\nexport interface BlankReturnMessage {\n statusCode: number;\n message: string;\n success: boolean;\n timestamp: Date;\n}\n\nexport interface ReturnMessage<T> extends BlankReturnMessage {\n data?: T;\n}\n\nexport class BlankReturnMessageDto implements BlankReturnMessage {\n @ApiProperty({ description: 'Return code', type: Number })\n statusCode: number;\n @ApiProperty({ description: 'Return message', type: String })\n message: string;\n @ApiProperty({ description: 'Whether success.', type: Boolean })\n success: boolean;\n @ApiProperty({ description: 'Return timestamp', type: Date })\n timestamp: Date;\n constructor(statusCode: number, message?: string) {\n this.statusCode = statusCode;\n this.message = message || 'success';\n this.success = statusCode < 400;\n this.timestamp = new Date();\n }\n\n toException() {\n return new HttpException(this, this.statusCode);\n }\n}\n\nexport class BlankPaginatedReturnMessageDto\n extends BlankReturnMessageDto\n implements PageSettingsWise\n{\n @ApiProperty({ description: 'Total record count.', type: Number })\n total: number;\n @ApiProperty({ description: 'Total page count.', type: Number })\n totalPages: number;\n @ApiProperty({ description: 'Current page.', type: Number })\n pageCount: number;\n @ApiProperty({ description: 'Records per page.', type: Number })\n recordsPerPage: number;\n constructor(\n statusCode: number,\n message: string,\n total: number,\n pageSettings: PageSettingsWise,\n ) {\n super(statusCode, message);\n this.total = total;\n this.pageCount = pageSettings.pageCount;\n this.recordsPerPage = pageSettings.recordsPerPage;\n this.totalPages = Math.ceil(total / pageSettings.recordsPerPage);\n }\n}\n\nexport class GenericReturnMessageDto<T>\n extends BlankReturnMessageDto\n implements ReturnMessage<T>\n{\n data?: T;\n constructor(statusCode: number, message?: string, data?: T) {\n super(statusCode, message);\n this.data = data;\n }\n}\n\nexport function ReturnMessageDto<T extends ClassOrArray>(\n type: T,\n): new (\n statusCode: number,\n message: string,\n data: ParseType<T>,\n) => GenericReturnMessageDto<ParseType<T>> {\n return InsertField(\n GenericReturnMessageDto,\n {\n data: {\n type,\n options: {\n required: false,\n description: 'Return data.',\n },\n },\n },\n `${getClassFromClassOrArray(type).name}${Array.isArray(type) ? 'Array' : ''}ReturnMessageDto`,\n );\n}\n\nexport class GenericPaginatedReturnMessageDto<T>\n extends BlankPaginatedReturnMessageDto\n implements PageSettingsWise, ReturnMessage<T[]>\n{\n data: T[];\n constructor(\n statusCode: number,\n message: string,\n data: T[],\n total: number,\n pageSettings: PageSettingsWise,\n ) {\n super(statusCode, message, total, pageSettings);\n this.data = data;\n }\n}\n\nexport function PaginatedReturnMessageDto<T extends AnyClass>(\n type: T,\n): new (\n statusCode: number,\n message: string,\n data: InstanceType<T>[],\n total: number,\n pageSettings: PageSettingsWise,\n) => GenericPaginatedReturnMessageDto<InstanceType<T>> {\n return InsertField(\n GenericPaginatedReturnMessageDto,\n {\n data: {\n type: [type],\n options: {\n required: false,\n description: 'Return data.',\n },\n },\n },\n `${getClassFromClassOrArray(type).name}PaginatedReturnMessageDto`,\n );\n}\n\nexport class StringReturnMessageDto extends GenericReturnMessageDto<string> {\n @ApiProperty({ description: 'Return data.', type: String, required: false })\n data: string;\n}\n", "import { BlankReturnMessageDto, ReturnMessageDto } from './return-message';\nimport { ApiResponse, ApiResponseOptions } from '@nestjs/swagger';\nimport { ClassOrArray } from './insert-field';\n\nexport const ApiTypeResponse = (\n // eslint-disable-next-line @typescript-eslint/ban-types\n type: ClassOrArray,\n options: ApiResponseOptions = {},\n) =>\n ApiResponse({\n status: 200,\n type: ReturnMessageDto(type),\n ...options,\n });\n\nexport const ApiBlankResponse = (options: ApiResponseOptions = {}) =>\n ApiResponse({\n status: 200,\n type: BlankReturnMessageDto,\n ...options,\n });\n\nexport const ApiError = (status: number, description: string) =>\n ApiBlankResponse({ status, description });\n\nexport const ApiErrorTyped = (\n status: number,\n description: string,\n type: ClassOrArray,\n) =>\n ApiTypeResponse(type, {\n status,\n description,\n });\n", "import {\n Body,\n PipeTransform,\n Query,\n Type,\n ValidationPipe,\n} from '@nestjs/common';\n\nexport const DataPipe = () =>\n new ValidationPipe({\n transform: true,\n transformOptions: { enableImplicitConversion: true },\n });\n\nconst createDataPipeDec =\n (\n nestFieldDec: (\n ...pipes: (Type<PipeTransform> | PipeTransform)[]\n ) => ParameterDecorator,\n ) =>\n (...extraPipes: (Type<PipeTransform> | PipeTransform)[]) =>\n nestFieldDec(DataPipe(), ...extraPipes);\n\nexport const DataQuery = createDataPipeDec(Query);\nexport const DataBody = createDataPipeDec(Body);\n", "import {\n CanActivate,\n ExecutionContext,\n Injectable,\n UseGuards,\n} from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { ApiHeader } from '@nestjs/swagger';\nimport { BlankReturnMessageDto } from './return-message';\nimport { MergeClassOrMethodDecorators } from './merge';\nimport { ApiError } from './openapi';\n\n@Injectable()\nexport class TokenGuard implements CanActivate {\n private token = this.config.get<string>('SERVER_TOKEN');\n constructor(private config: ConfigService) {}\n\n async canActivate(context: ExecutionContext) {\n const request = context.switchToHttp().getRequest();\n const token = request.headers['x-server-token'];\n if (this.token && token !== this.token) {\n throw new BlankReturnMessageDto(401, 'Unauthorized').toException();\n }\n return true;\n }\n}\n\nexport const RequireToken = () =>\n MergeClassOrMethodDecorators([\n UseGuards(TokenGuard),\n ApiHeader({\n name: 'x-server-token',\n description: 'Server token',\n required: false,\n }),\n ApiError(401, 'Incorrect server token provided'),\n ]);\n", "import { Observable, takeUntil } from 'rxjs';\nimport { createParamDecorator, ExecutionContext } from '@nestjs/common';\nimport { IncomingMessage } from 'node:http';\nimport { BlankReturnMessageDto } from './return-message';\nimport type { Request, Response } from 'express';\nimport { createAbortSignalFromHttp } from './abort-http-signal';\n\nexport type AbortableFn<T> = (ac: AbortController) => Promise<T>;\n\nexport const fromAbortable = <T>(fn: AbortableFn<T>): Observable<T> => {\n return new Observable<T>((subscriber) => {\n const ac = new AbortController();\n\n fn(ac).then(\n (value) => {\n if (!ac.signal.aborted && !subscriber.closed) {\n subscriber.next(value);\n subscriber.complete();\n }\n },\n (err) => {\n if (ac.signal.aborted) {\n if (!subscriber.closed) subscriber.complete();\n return;\n }\n if (!subscriber.closed) subscriber.error(err);\n },\n );\n\n return () => {\n if (!ac.signal.aborted) ac.abort();\n };\n });\n};\n\nexport const takeUntilAbort = <T>(signal: AbortSignal) => {\n return (source: Observable<T>) => {\n return source.pipe(\n takeUntil(\n new Observable<void>((subscriber) => {\n const onAbort = () => subscriber.next();\n if (signal.aborted) {\n subscriber.next();\n } else {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n return () => signal.removeEventListener('abort', onAbort);\n }),\n ),\n );\n };\n};\n\nexport const As = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext) => {\n const req = ctx.switchToHttp().getRequest<Request>();\n return createAbortSignalFromHttp(req);\n },\n);\n", "// abort-http-signal.ts\nimport type { IncomingMessage } from 'http';\nimport type { Request as ExpressReq } from 'express';\nimport type { FastifyRequest } from 'fastify';\nimport { BlankReturnMessageDto } from './return-message';\n\ntype AnyReq = ExpressReq | FastifyRequest | IncomingMessage;\n\nfunction toRawReq(req: AnyReq): IncomingMessage {\n // Fastify: req.raw \u662F IncomingMessage\uFF1BExpress: req \u672C\u8EAB\u5C31\u662F IncomingMessage\n if ((req as any)?.raw?.socket) return (req as any).raw as IncomingMessage;\n return req as IncomingMessage;\n}\n\n/**\n * \u4EC5\u901A\u8FC7 req \u81EA\u52A8\u9002\u914D Express/Fastify\uFF0C\u7ED1\u5B9A HTTP \u53D6\u6D88\u5230 AbortSignal\u3002\n * - \u4F18\u5148\u76D1\u542C 'aborted'\uFF08\u5BA2\u6237\u7AEF\u4E2D\u65AD\u6700\u53EF\u9760\u7684\u4FE1\u53F7\uFF09\n * - \u53EF\u9009\u515C\u5E95\uFF1A\u5728 socket 'close' \u65F6\uFF0C\u4EC5\u5F53\u8BF7\u6C42\u672A\u5B8C\u6574\u63A5\u6536/\u6216\u5DF2\u6807\u8BB0 aborted \u65F6\uFF0C\u624D\u89E6\u53D1 abort\uFF0C\u907F\u514D\u6B63\u5E38\u5B8C\u6210\u7684\u8BEF\u4F24\n * - reason \u56FA\u5B9A\u4E3A 499 HttpException\n *\n * \u6CE8\u610F\uFF1A\u82E5\u4F60\u7684 abortable() \u5728 signal.reason \u662F Error \u65F6\u4F1A\u201C\u539F\u6837 throw reason\u201D\uFF0C\n * \u90A3\u4E48\u4E0A\u5C42\u4F1A\u6536\u5230 HttpException(499)\u3002\u82E5\u4ECD\u60F3\u7EDF\u4E00\u629B AbortedError\uFF0C\u53EF\u6539\u4E3A\uFF1A\n * const reason = new AbortedError('Request aborted', httpErr);\n * \u5E76\u8BA9 throwIfAborted \u5148\u629B AbortedError\uFF08\u4FDD\u7559 cause\uFF09\u3002\n */\nexport function createAbortSignalFromHttp(req: AnyReq): AbortSignal {\n const rawReq = toRawReq(req);\n const ac = new AbortController();\n\n const makeReason = () =>\n new BlankReturnMessageDto(499, 'Request aborted').toException();\n\n const abortOnce = () => {\n if (!ac.signal.aborted) ac.abort(makeReason());\n cleanup();\n };\n\n const onClose = () => {\n abortOnce();\n };\n\n const cleanup = () => {\n rawReq.off?.('close', onClose);\n };\n\n rawReq.once?.('close', onClose);\n\n return ac.signal;\n}\n", "import { Inject, Provider, Scope } from '@nestjs/common';\nimport { abortable, AbortableOpts } from 'nfkit';\nimport { ABORT_SIGNAL } from './abort-signal.provider';\nimport { ContextIdFactory, ModuleRef, REQUEST } from '@nestjs/core';\n\nexport type ProviderToken<T = any> =\n | string\n | symbol\n | (new (...args: any[]) => T);\n\nconst tokenMemo = new Map<any, symbol>();\nexport const abortableToken = (token: ProviderToken) => {\n if (tokenMemo.has(token)) return tokenMemo.get(token)!;\n const name = typeof token === 'function' ? token.name : String(token);\n const sym = Symbol.for(`Abortable(${name})`);\n tokenMemo.set(token, sym);\n return sym;\n};\n\n/**\n * \u652F\u6301\u4E24\u79CD\u7528\u6CD5\uFF1A\n * @InjectAbortable(SomeService)\n * @InjectAbortable() // \u81EA\u52A8\u63A8\u65AD\u7C7B\u578B\n */\nexport function InjectAbortable(token?: ProviderToken): ParameterDecorator {\n return (target, propertyKey, parameterIndex) => {\n let actualToken = token;\n\n if (!actualToken) {\n // \u5229\u7528 reflect-metadata \u83B7\u53D6\u53C2\u6570\u7C7B\u578B\n const paramTypes: any[] =\n Reflect.getMetadata('design:paramtypes', target, propertyKey) || [];\n actualToken = paramTypes[parameterIndex];\n if (!actualToken) {\n throw new Error(\n `@InjectAbortable() cannot infer type from metadata: ${target.constructor?.name}[${parameterIndex}]`,\n );\n }\n }\n\n Inject(abortableToken(actualToken))(target, propertyKey, parameterIndex);\n };\n}\n\nexport function createAbortableProvider<T>(\n token: ProviderToken<T>,\n opts?: AbortableOpts,\n): Provider {\n const provide = abortableToken(token);\n\n return {\n provide,\n scope: Scope.REQUEST,\n inject: [ModuleRef, REQUEST, ABORT_SIGNAL],\n // \u26A0\uFE0F \u6CE8\u610F\uFF1A\u7528 async + resolve + contextId + strict:false\n useFactory: async (\n moduleRef: ModuleRef,\n req: Request,\n signal: AbortSignal,\n ) => {\n // \u8BA9\u89E3\u6790\u4E0E\u5F53\u524D\u8BF7\u6C42\u4E0A\u4E0B\u6587\u7ED1\u5B9A\uFF08\u652F\u6301 request/transient \u4F5C\u7528\u57DF\uFF09\n const ctxId = ContextIdFactory.getByRequest(req);\n // \u4E25\u683C\u6A21\u5F0F\u5173\u95ED\uFF0C\u5141\u8BB8\u8DE8\u6A21\u5757\u8FB9\u754C\u89E3\u6790\uFF08\u89E3\u51B3\u6D4B\u8BD5\u91CC forFeature \u5B50\u6A21\u5757\u770B\u4E0D\u5230 DemoService \u7684\u60C5\u51B5\uFF09\n const svc = await moduleRef.resolve<T>(token, ctxId, { strict: false });\n if (svc == null) {\n throw new Error(\n `Abortable: provider \"${String(\n (token as any).name ?? token,\n )}\" not found in container (even with strict:false)`,\n );\n }\n return abortable<T>(svc, signal, opts);\n },\n };\n}\n", "import { Inject, Provider, Scope } from '@nestjs/common';\nimport { REQUEST } from '@nestjs/core';\nimport type { Request as ExpressReq } from 'express';\nimport { createAbortSignalFromHttp } from '../abort-http-signal';\n\nexport const ABORT_SIGNAL = Symbol('ABORT_SIGNAL');\nexport const AbortSignalProvider: Provider = {\n provide: ABORT_SIGNAL,\n scope: Scope.REQUEST,\n inject: [REQUEST],\n useFactory: (req: ExpressReq) => {\n return createAbortSignalFromHttp(req);\n },\n};\n\nexport const InjectAbortSignal = () => Inject(ABORT_SIGNAL);\n", "import { DynamicModule, Module, Provider } from '@nestjs/common';\nimport { ProviderToken, createAbortableProvider } from './abortable.token';\nimport { AbortableOpts } from 'nfkit';\nimport { AbortSignalProvider } from './abort-signal.provider';\n\nexport interface AbortableModuleOptions {\n abortableOptions?: AbortableOpts;\n}\n\n@Module({})\nexport class AbortableModule {\n static forRoot(): DynamicModule {\n return {\n module: AbortableModule,\n providers: [AbortSignalProvider],\n exports: [AbortSignalProvider],\n global: true,\n };\n }\n\n static forFeature(\n tokens: ProviderToken[],\n options?: AbortableModuleOptions,\n ): DynamicModule {\n const providers: Provider[] = tokens.map((token) =>\n createAbortableProvider(token, options?.abortableOptions),\n );\n\n return {\n module: AbortableModule,\n providers: [...providers],\n exports: [...providers],\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["import_swagger", "import_swagger", "import_common", "import_common", "import_swagger", "import_common", "import_common", "import_common", "import_core", "import_common"]
7
+ }
package/dist/index.d.ts CHANGED
@@ -4,3 +4,5 @@ export * from './src/return-message';
4
4
  export * from './src/openapi';
5
5
  export * from './src/pipe';
6
6
  export * from './src/token.guard';
7
+ export * from './src/abort-utils';
8
+ export * from './src/abortable-module';
package/dist/index.mjs ADDED
@@ -0,0 +1,435 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+
12
+ // src/insert-field.ts
13
+ import { ApiProperty } from "@nestjs/swagger";
14
+ function getClassFromClassOrArray(o) {
15
+ return o instanceof Array ? o[0] : o;
16
+ }
17
+ function InsertField(cl, map, newName) {
18
+ const extendedCl = class extends cl {
19
+ };
20
+ for (const key in map) {
21
+ ApiProperty({
22
+ type: map[key].type,
23
+ ...map[key].options || {}
24
+ })(extendedCl.prototype, key);
25
+ }
26
+ Object.defineProperty(extendedCl, "name", {
27
+ value: newName || cl.name
28
+ });
29
+ return extendedCl;
30
+ }
31
+
32
+ // src/merge.ts
33
+ function MergePropertyDecorators(decs) {
34
+ return (obj, key) => {
35
+ for (const dec of decs) {
36
+ dec(obj, key);
37
+ }
38
+ };
39
+ }
40
+ function MergeMethodDecorators(decs) {
41
+ return (obj, key, descriptor) => {
42
+ for (const dec of decs) {
43
+ dec(obj, key, descriptor);
44
+ }
45
+ };
46
+ }
47
+ function MergeClassDecorators(decs) {
48
+ return (obj) => {
49
+ for (const dec of decs) {
50
+ dec(obj);
51
+ }
52
+ };
53
+ }
54
+ function MergeParameterDecorators(decs) {
55
+ return (obj, key, index) => {
56
+ for (const dec of decs) {
57
+ dec(obj, key, index);
58
+ }
59
+ };
60
+ }
61
+ function MergeClassOrMethodDecorators(decs) {
62
+ return (obj, key, descriptor) => {
63
+ if (descriptor) {
64
+ for (const dec of decs) {
65
+ dec(obj, key, descriptor);
66
+ }
67
+ } else {
68
+ for (const dec of decs) {
69
+ dec(obj);
70
+ }
71
+ }
72
+ };
73
+ }
74
+
75
+ // src/return-message.ts
76
+ import { ApiProperty as ApiProperty2 } from "@nestjs/swagger";
77
+ import { HttpException } from "@nestjs/common";
78
+ var BlankReturnMessageDto = class {
79
+ constructor(statusCode, message) {
80
+ this.statusCode = statusCode;
81
+ this.message = message || "success";
82
+ this.success = statusCode < 400;
83
+ this.timestamp = /* @__PURE__ */ new Date();
84
+ }
85
+ toException() {
86
+ return new HttpException(this, this.statusCode);
87
+ }
88
+ };
89
+ __decorateClass([
90
+ ApiProperty2({ description: "Return code", type: Number })
91
+ ], BlankReturnMessageDto.prototype, "statusCode", 2);
92
+ __decorateClass([
93
+ ApiProperty2({ description: "Return message", type: String })
94
+ ], BlankReturnMessageDto.prototype, "message", 2);
95
+ __decorateClass([
96
+ ApiProperty2({ description: "Whether success.", type: Boolean })
97
+ ], BlankReturnMessageDto.prototype, "success", 2);
98
+ __decorateClass([
99
+ ApiProperty2({ description: "Return timestamp", type: Date })
100
+ ], BlankReturnMessageDto.prototype, "timestamp", 2);
101
+ var BlankPaginatedReturnMessageDto = class extends BlankReturnMessageDto {
102
+ constructor(statusCode, message, total, pageSettings) {
103
+ super(statusCode, message);
104
+ this.total = total;
105
+ this.pageCount = pageSettings.pageCount;
106
+ this.recordsPerPage = pageSettings.recordsPerPage;
107
+ this.totalPages = Math.ceil(total / pageSettings.recordsPerPage);
108
+ }
109
+ };
110
+ __decorateClass([
111
+ ApiProperty2({ description: "Total record count.", type: Number })
112
+ ], BlankPaginatedReturnMessageDto.prototype, "total", 2);
113
+ __decorateClass([
114
+ ApiProperty2({ description: "Total page count.", type: Number })
115
+ ], BlankPaginatedReturnMessageDto.prototype, "totalPages", 2);
116
+ __decorateClass([
117
+ ApiProperty2({ description: "Current page.", type: Number })
118
+ ], BlankPaginatedReturnMessageDto.prototype, "pageCount", 2);
119
+ __decorateClass([
120
+ ApiProperty2({ description: "Records per page.", type: Number })
121
+ ], BlankPaginatedReturnMessageDto.prototype, "recordsPerPage", 2);
122
+ var GenericReturnMessageDto = class extends BlankReturnMessageDto {
123
+ constructor(statusCode, message, data) {
124
+ super(statusCode, message);
125
+ this.data = data;
126
+ }
127
+ };
128
+ function ReturnMessageDto(type) {
129
+ return InsertField(
130
+ GenericReturnMessageDto,
131
+ {
132
+ data: {
133
+ type,
134
+ options: {
135
+ required: false,
136
+ description: "Return data."
137
+ }
138
+ }
139
+ },
140
+ `${getClassFromClassOrArray(type).name}${Array.isArray(type) ? "Array" : ""}ReturnMessageDto`
141
+ );
142
+ }
143
+ var GenericPaginatedReturnMessageDto = class extends BlankPaginatedReturnMessageDto {
144
+ constructor(statusCode, message, data, total, pageSettings) {
145
+ super(statusCode, message, total, pageSettings);
146
+ this.data = data;
147
+ }
148
+ };
149
+ function PaginatedReturnMessageDto(type) {
150
+ return InsertField(
151
+ GenericPaginatedReturnMessageDto,
152
+ {
153
+ data: {
154
+ type: [type],
155
+ options: {
156
+ required: false,
157
+ description: "Return data."
158
+ }
159
+ }
160
+ },
161
+ `${getClassFromClassOrArray(type).name}PaginatedReturnMessageDto`
162
+ );
163
+ }
164
+ var StringReturnMessageDto = class extends GenericReturnMessageDto {
165
+ };
166
+ __decorateClass([
167
+ ApiProperty2({ description: "Return data.", type: String, required: false })
168
+ ], StringReturnMessageDto.prototype, "data", 2);
169
+
170
+ // src/openapi.ts
171
+ import { ApiResponse } from "@nestjs/swagger";
172
+ var ApiTypeResponse = (type, options = {}) => ApiResponse({
173
+ status: 200,
174
+ type: ReturnMessageDto(type),
175
+ ...options
176
+ });
177
+ var ApiBlankResponse = (options = {}) => ApiResponse({
178
+ status: 200,
179
+ type: BlankReturnMessageDto,
180
+ ...options
181
+ });
182
+ var ApiError = (status, description) => ApiBlankResponse({ status, description });
183
+ var ApiErrorTyped = (status, description, type) => ApiTypeResponse(type, {
184
+ status,
185
+ description
186
+ });
187
+
188
+ // src/pipe.ts
189
+ import {
190
+ Body,
191
+ Query,
192
+ ValidationPipe
193
+ } from "@nestjs/common";
194
+ var DataPipe = () => new ValidationPipe({
195
+ transform: true,
196
+ transformOptions: { enableImplicitConversion: true }
197
+ });
198
+ var createDataPipeDec = (nestFieldDec) => (...extraPipes) => nestFieldDec(DataPipe(), ...extraPipes);
199
+ var DataQuery = createDataPipeDec(Query);
200
+ var DataBody = createDataPipeDec(Body);
201
+
202
+ // src/token.guard.ts
203
+ import {
204
+ Injectable,
205
+ UseGuards
206
+ } from "@nestjs/common";
207
+ import { ApiHeader } from "@nestjs/swagger";
208
+ var TokenGuard = class {
209
+ constructor(config) {
210
+ this.config = config;
211
+ this.token = this.config.get("SERVER_TOKEN");
212
+ }
213
+ async canActivate(context) {
214
+ const request = context.switchToHttp().getRequest();
215
+ const token = request.headers["x-server-token"];
216
+ if (this.token && token !== this.token) {
217
+ throw new BlankReturnMessageDto(401, "Unauthorized").toException();
218
+ }
219
+ return true;
220
+ }
221
+ };
222
+ TokenGuard = __decorateClass([
223
+ Injectable()
224
+ ], TokenGuard);
225
+ var RequireToken = () => MergeClassOrMethodDecorators([
226
+ UseGuards(TokenGuard),
227
+ ApiHeader({
228
+ name: "x-server-token",
229
+ description: "Server token",
230
+ required: false
231
+ }),
232
+ ApiError(401, "Incorrect server token provided")
233
+ ]);
234
+
235
+ // src/abort-utils.ts
236
+ import { Observable, takeUntil } from "rxjs";
237
+ import { createParamDecorator } from "@nestjs/common";
238
+
239
+ // src/abort-http-signal.ts
240
+ function toRawReq(req) {
241
+ if (req?.raw?.socket) return req.raw;
242
+ return req;
243
+ }
244
+ function createAbortSignalFromHttp(req) {
245
+ const rawReq = toRawReq(req);
246
+ const ac = new AbortController();
247
+ const makeReason = () => new BlankReturnMessageDto(499, "Request aborted").toException();
248
+ const abortOnce = () => {
249
+ if (!ac.signal.aborted) ac.abort(makeReason());
250
+ cleanup();
251
+ };
252
+ const onClose = () => {
253
+ abortOnce();
254
+ };
255
+ const cleanup = () => {
256
+ rawReq.off?.("close", onClose);
257
+ };
258
+ rawReq.once?.("close", onClose);
259
+ return ac.signal;
260
+ }
261
+
262
+ // src/abort-utils.ts
263
+ var fromAbortable = (fn) => {
264
+ return new Observable((subscriber) => {
265
+ const ac = new AbortController();
266
+ fn(ac).then(
267
+ (value) => {
268
+ if (!ac.signal.aborted && !subscriber.closed) {
269
+ subscriber.next(value);
270
+ subscriber.complete();
271
+ }
272
+ },
273
+ (err) => {
274
+ if (ac.signal.aborted) {
275
+ if (!subscriber.closed) subscriber.complete();
276
+ return;
277
+ }
278
+ if (!subscriber.closed) subscriber.error(err);
279
+ }
280
+ );
281
+ return () => {
282
+ if (!ac.signal.aborted) ac.abort();
283
+ };
284
+ });
285
+ };
286
+ var takeUntilAbort = (signal) => {
287
+ return (source) => {
288
+ return source.pipe(
289
+ takeUntil(
290
+ new Observable((subscriber) => {
291
+ const onAbort = () => subscriber.next();
292
+ if (signal.aborted) {
293
+ subscriber.next();
294
+ } else {
295
+ signal.addEventListener("abort", onAbort, { once: true });
296
+ }
297
+ return () => signal.removeEventListener("abort", onAbort);
298
+ })
299
+ )
300
+ );
301
+ };
302
+ };
303
+ var As = createParamDecorator(
304
+ (_data, ctx) => {
305
+ const req = ctx.switchToHttp().getRequest();
306
+ return createAbortSignalFromHttp(req);
307
+ }
308
+ );
309
+
310
+ // src/abortable-module/abortable.token.ts
311
+ import { Inject as Inject2, Scope as Scope2 } from "@nestjs/common";
312
+ import { abortable } from "nfkit";
313
+
314
+ // src/abortable-module/abort-signal.provider.ts
315
+ import { Inject, Scope } from "@nestjs/common";
316
+ import { REQUEST } from "@nestjs/core";
317
+ var ABORT_SIGNAL = Symbol("ABORT_SIGNAL");
318
+ var AbortSignalProvider = {
319
+ provide: ABORT_SIGNAL,
320
+ scope: Scope.REQUEST,
321
+ inject: [REQUEST],
322
+ useFactory: (req) => {
323
+ return createAbortSignalFromHttp(req);
324
+ }
325
+ };
326
+ var InjectAbortSignal = () => Inject(ABORT_SIGNAL);
327
+
328
+ // src/abortable-module/abortable.token.ts
329
+ import { ContextIdFactory, ModuleRef, REQUEST as REQUEST2 } from "@nestjs/core";
330
+ var tokenMemo = /* @__PURE__ */ new Map();
331
+ var abortableToken = (token) => {
332
+ if (tokenMemo.has(token)) return tokenMemo.get(token);
333
+ const name = typeof token === "function" ? token.name : String(token);
334
+ const sym = Symbol.for(`Abortable(${name})`);
335
+ tokenMemo.set(token, sym);
336
+ return sym;
337
+ };
338
+ function InjectAbortable(token) {
339
+ return (target, propertyKey, parameterIndex) => {
340
+ let actualToken = token;
341
+ if (!actualToken) {
342
+ const paramTypes = Reflect.getMetadata("design:paramtypes", target, propertyKey) || [];
343
+ actualToken = paramTypes[parameterIndex];
344
+ if (!actualToken) {
345
+ throw new Error(
346
+ `@InjectAbortable() cannot infer type from metadata: ${target.constructor?.name}[${parameterIndex}]`
347
+ );
348
+ }
349
+ }
350
+ Inject2(abortableToken(actualToken))(target, propertyKey, parameterIndex);
351
+ };
352
+ }
353
+ function createAbortableProvider(token, opts) {
354
+ const provide = abortableToken(token);
355
+ return {
356
+ provide,
357
+ scope: Scope2.REQUEST,
358
+ inject: [ModuleRef, REQUEST2, ABORT_SIGNAL],
359
+ // ⚠️ 注意:用 async + resolve + contextId + strict:false
360
+ useFactory: async (moduleRef, req, signal) => {
361
+ const ctxId = ContextIdFactory.getByRequest(req);
362
+ const svc = await moduleRef.resolve(token, ctxId, { strict: false });
363
+ if (svc == null) {
364
+ throw new Error(
365
+ `Abortable: provider "${String(
366
+ token.name ?? token
367
+ )}" not found in container (even with strict:false)`
368
+ );
369
+ }
370
+ return abortable(svc, signal, opts);
371
+ }
372
+ };
373
+ }
374
+
375
+ // src/abortable-module/abortable.module.ts
376
+ import { Module } from "@nestjs/common";
377
+ var AbortableModule = class {
378
+ static forRoot() {
379
+ return {
380
+ module: AbortableModule,
381
+ providers: [AbortSignalProvider],
382
+ exports: [AbortSignalProvider],
383
+ global: true
384
+ };
385
+ }
386
+ static forFeature(tokens, options) {
387
+ const providers = tokens.map(
388
+ (token) => createAbortableProvider(token, options?.abortableOptions)
389
+ );
390
+ return {
391
+ module: AbortableModule,
392
+ providers: [...providers],
393
+ exports: [...providers]
394
+ };
395
+ }
396
+ };
397
+ AbortableModule = __decorateClass([
398
+ Module({})
399
+ ], AbortableModule);
400
+ export {
401
+ ABORT_SIGNAL,
402
+ AbortSignalProvider,
403
+ AbortableModule,
404
+ ApiBlankResponse,
405
+ ApiError,
406
+ ApiErrorTyped,
407
+ ApiTypeResponse,
408
+ As,
409
+ BlankPaginatedReturnMessageDto,
410
+ BlankReturnMessageDto,
411
+ DataBody,
412
+ DataPipe,
413
+ DataQuery,
414
+ GenericPaginatedReturnMessageDto,
415
+ GenericReturnMessageDto,
416
+ InjectAbortSignal,
417
+ InjectAbortable,
418
+ InsertField,
419
+ MergeClassDecorators,
420
+ MergeClassOrMethodDecorators,
421
+ MergeMethodDecorators,
422
+ MergeParameterDecorators,
423
+ MergePropertyDecorators,
424
+ PaginatedReturnMessageDto,
425
+ RequireToken,
426
+ ReturnMessageDto,
427
+ StringReturnMessageDto,
428
+ TokenGuard,
429
+ abortableToken,
430
+ createAbortableProvider,
431
+ fromAbortable,
432
+ getClassFromClassOrArray,
433
+ takeUntilAbort
434
+ };
435
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/insert-field.ts", "../src/merge.ts", "../src/return-message.ts", "../src/openapi.ts", "../src/pipe.ts", "../src/token.guard.ts", "../src/abort-utils.ts", "../src/abort-http-signal.ts", "../src/abortable-module/abortable.token.ts", "../src/abortable-module/abort-signal.provider.ts", "../src/abortable-module/abortable.module.ts"],
4
+ "sourcesContent": ["import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';\n\nexport type AnyClass = new (...args: any[]) => any;\nexport type ClassOrArray = AnyClass | [AnyClass];\nexport type ClassType<T> = new (...args: any[]) => T;\nexport type TypeFromClass<T> = T extends new (...args: any[]) => infer U\n ? U\n : never;\nexport type ParamsFromClass<T> = T extends new (...args: infer U) => any\n ? U\n : never;\nexport type ParseType<IC extends ClassOrArray> = IC extends [infer U]\n ? TypeFromClass<U>[]\n : TypeFromClass<IC>;\n\nexport function getClassFromClassOrArray(o: ClassOrArray) {\n return o instanceof Array ? o[0] : o;\n}\n\nexport interface InsertOptions<C extends ClassOrArray = ClassOrArray> {\n type: C;\n options?: ApiPropertyOptions;\n}\n\ntype TypeFromInsertOptions<O extends InsertOptions> =\n O extends InsertOptions<infer C>\n ?\n | ParseType<C>\n | (O extends { options: { required: true } } ? never : undefined)\n : never;\n\ntype Merge<T, U> = {\n [K in keyof T | keyof U]: K extends keyof T\n ? T[K]\n : K extends keyof U\n ? U[K]\n : never;\n};\n\nexport function InsertField<\n C extends AnyClass,\n M extends Record<string, InsertOptions>,\n>(\n cl: C,\n map: M,\n newName?: string,\n): new (...args: ParamsFromClass<C>) => Merge<\n {\n [F in keyof M]: TypeFromInsertOptions<M[F]>;\n },\n TypeFromClass<C>\n> {\n const extendedCl = class extends cl {};\n for (const key in map) {\n ApiProperty({\n type: map[key].type,\n ...(map[key].options || {}),\n })(extendedCl.prototype, key);\n }\n Object.defineProperty(extendedCl, 'name', {\n value: newName || cl.name,\n });\n return extendedCl;\n}\n", "export function MergePropertyDecorators(\n decs: PropertyDecorator[],\n): PropertyDecorator {\n return (obj, key) => {\n for (const dec of decs) {\n dec(obj, key);\n }\n };\n}\n\nexport function MergeMethodDecorators(\n decs: MethodDecorator[],\n): MethodDecorator {\n return (obj, key, descriptor) => {\n for (const dec of decs) {\n dec(obj, key, descriptor);\n }\n };\n}\n\nexport function MergeClassDecorators(decs: ClassDecorator[]): ClassDecorator {\n return (obj) => {\n for (const dec of decs) {\n dec(obj);\n }\n };\n}\n\nexport function MergeParameterDecorators(\n decs: ParameterDecorator[],\n): ParameterDecorator {\n return (obj, key, index) => {\n for (const dec of decs) {\n dec(obj, key, index);\n }\n };\n}\n\nexport function MergeClassOrMethodDecorators(\n decs: (ClassDecorator & MethodDecorator)[],\n): ClassDecorator & MethodDecorator {\n return (obj, key?, descriptor?) => {\n if (descriptor) {\n for (const dec of decs) {\n dec(obj, key, descriptor);\n }\n } else {\n for (const dec of decs) {\n dec(obj);\n }\n }\n };\n}\n", "import { ApiProperty } from '@nestjs/swagger';\nimport { HttpException } from '@nestjs/common';\nimport {\n AnyClass,\n ClassOrArray,\n getClassFromClassOrArray,\n InsertField,\n ParseType,\n} from './insert-field';\n\nexport interface PageSettingsWise {\n pageCount: number;\n recordsPerPage: number;\n}\n\nexport interface BlankReturnMessage {\n statusCode: number;\n message: string;\n success: boolean;\n timestamp: Date;\n}\n\nexport interface ReturnMessage<T> extends BlankReturnMessage {\n data?: T;\n}\n\nexport class BlankReturnMessageDto implements BlankReturnMessage {\n @ApiProperty({ description: 'Return code', type: Number })\n statusCode: number;\n @ApiProperty({ description: 'Return message', type: String })\n message: string;\n @ApiProperty({ description: 'Whether success.', type: Boolean })\n success: boolean;\n @ApiProperty({ description: 'Return timestamp', type: Date })\n timestamp: Date;\n constructor(statusCode: number, message?: string) {\n this.statusCode = statusCode;\n this.message = message || 'success';\n this.success = statusCode < 400;\n this.timestamp = new Date();\n }\n\n toException() {\n return new HttpException(this, this.statusCode);\n }\n}\n\nexport class BlankPaginatedReturnMessageDto\n extends BlankReturnMessageDto\n implements PageSettingsWise\n{\n @ApiProperty({ description: 'Total record count.', type: Number })\n total: number;\n @ApiProperty({ description: 'Total page count.', type: Number })\n totalPages: number;\n @ApiProperty({ description: 'Current page.', type: Number })\n pageCount: number;\n @ApiProperty({ description: 'Records per page.', type: Number })\n recordsPerPage: number;\n constructor(\n statusCode: number,\n message: string,\n total: number,\n pageSettings: PageSettingsWise,\n ) {\n super(statusCode, message);\n this.total = total;\n this.pageCount = pageSettings.pageCount;\n this.recordsPerPage = pageSettings.recordsPerPage;\n this.totalPages = Math.ceil(total / pageSettings.recordsPerPage);\n }\n}\n\nexport class GenericReturnMessageDto<T>\n extends BlankReturnMessageDto\n implements ReturnMessage<T>\n{\n data?: T;\n constructor(statusCode: number, message?: string, data?: T) {\n super(statusCode, message);\n this.data = data;\n }\n}\n\nexport function ReturnMessageDto<T extends ClassOrArray>(\n type: T,\n): new (\n statusCode: number,\n message: string,\n data: ParseType<T>,\n) => GenericReturnMessageDto<ParseType<T>> {\n return InsertField(\n GenericReturnMessageDto,\n {\n data: {\n type,\n options: {\n required: false,\n description: 'Return data.',\n },\n },\n },\n `${getClassFromClassOrArray(type).name}${Array.isArray(type) ? 'Array' : ''}ReturnMessageDto`,\n );\n}\n\nexport class GenericPaginatedReturnMessageDto<T>\n extends BlankPaginatedReturnMessageDto\n implements PageSettingsWise, ReturnMessage<T[]>\n{\n data: T[];\n constructor(\n statusCode: number,\n message: string,\n data: T[],\n total: number,\n pageSettings: PageSettingsWise,\n ) {\n super(statusCode, message, total, pageSettings);\n this.data = data;\n }\n}\n\nexport function PaginatedReturnMessageDto<T extends AnyClass>(\n type: T,\n): new (\n statusCode: number,\n message: string,\n data: InstanceType<T>[],\n total: number,\n pageSettings: PageSettingsWise,\n) => GenericPaginatedReturnMessageDto<InstanceType<T>> {\n return InsertField(\n GenericPaginatedReturnMessageDto,\n {\n data: {\n type: [type],\n options: {\n required: false,\n description: 'Return data.',\n },\n },\n },\n `${getClassFromClassOrArray(type).name}PaginatedReturnMessageDto`,\n );\n}\n\nexport class StringReturnMessageDto extends GenericReturnMessageDto<string> {\n @ApiProperty({ description: 'Return data.', type: String, required: false })\n data: string;\n}\n", "import { BlankReturnMessageDto, ReturnMessageDto } from './return-message';\nimport { ApiResponse, ApiResponseOptions } from '@nestjs/swagger';\nimport { ClassOrArray } from './insert-field';\n\nexport const ApiTypeResponse = (\n // eslint-disable-next-line @typescript-eslint/ban-types\n type: ClassOrArray,\n options: ApiResponseOptions = {},\n) =>\n ApiResponse({\n status: 200,\n type: ReturnMessageDto(type),\n ...options,\n });\n\nexport const ApiBlankResponse = (options: ApiResponseOptions = {}) =>\n ApiResponse({\n status: 200,\n type: BlankReturnMessageDto,\n ...options,\n });\n\nexport const ApiError = (status: number, description: string) =>\n ApiBlankResponse({ status, description });\n\nexport const ApiErrorTyped = (\n status: number,\n description: string,\n type: ClassOrArray,\n) =>\n ApiTypeResponse(type, {\n status,\n description,\n });\n", "import {\n Body,\n PipeTransform,\n Query,\n Type,\n ValidationPipe,\n} from '@nestjs/common';\n\nexport const DataPipe = () =>\n new ValidationPipe({\n transform: true,\n transformOptions: { enableImplicitConversion: true },\n });\n\nconst createDataPipeDec =\n (\n nestFieldDec: (\n ...pipes: (Type<PipeTransform> | PipeTransform)[]\n ) => ParameterDecorator,\n ) =>\n (...extraPipes: (Type<PipeTransform> | PipeTransform)[]) =>\n nestFieldDec(DataPipe(), ...extraPipes);\n\nexport const DataQuery = createDataPipeDec(Query);\nexport const DataBody = createDataPipeDec(Body);\n", "import {\n CanActivate,\n ExecutionContext,\n Injectable,\n UseGuards,\n} from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport { ApiHeader } from '@nestjs/swagger';\nimport { BlankReturnMessageDto } from './return-message';\nimport { MergeClassOrMethodDecorators } from './merge';\nimport { ApiError } from './openapi';\n\n@Injectable()\nexport class TokenGuard implements CanActivate {\n private token = this.config.get<string>('SERVER_TOKEN');\n constructor(private config: ConfigService) {}\n\n async canActivate(context: ExecutionContext) {\n const request = context.switchToHttp().getRequest();\n const token = request.headers['x-server-token'];\n if (this.token && token !== this.token) {\n throw new BlankReturnMessageDto(401, 'Unauthorized').toException();\n }\n return true;\n }\n}\n\nexport const RequireToken = () =>\n MergeClassOrMethodDecorators([\n UseGuards(TokenGuard),\n ApiHeader({\n name: 'x-server-token',\n description: 'Server token',\n required: false,\n }),\n ApiError(401, 'Incorrect server token provided'),\n ]);\n", "import { Observable, takeUntil } from 'rxjs';\nimport { createParamDecorator, ExecutionContext } from '@nestjs/common';\nimport { IncomingMessage } from 'node:http';\nimport { BlankReturnMessageDto } from './return-message';\nimport type { Request, Response } from 'express';\nimport { createAbortSignalFromHttp } from './abort-http-signal';\n\nexport type AbortableFn<T> = (ac: AbortController) => Promise<T>;\n\nexport const fromAbortable = <T>(fn: AbortableFn<T>): Observable<T> => {\n return new Observable<T>((subscriber) => {\n const ac = new AbortController();\n\n fn(ac).then(\n (value) => {\n if (!ac.signal.aborted && !subscriber.closed) {\n subscriber.next(value);\n subscriber.complete();\n }\n },\n (err) => {\n if (ac.signal.aborted) {\n if (!subscriber.closed) subscriber.complete();\n return;\n }\n if (!subscriber.closed) subscriber.error(err);\n },\n );\n\n return () => {\n if (!ac.signal.aborted) ac.abort();\n };\n });\n};\n\nexport const takeUntilAbort = <T>(signal: AbortSignal) => {\n return (source: Observable<T>) => {\n return source.pipe(\n takeUntil(\n new Observable<void>((subscriber) => {\n const onAbort = () => subscriber.next();\n if (signal.aborted) {\n subscriber.next();\n } else {\n signal.addEventListener('abort', onAbort, { once: true });\n }\n return () => signal.removeEventListener('abort', onAbort);\n }),\n ),\n );\n };\n};\n\nexport const As = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext) => {\n const req = ctx.switchToHttp().getRequest<Request>();\n return createAbortSignalFromHttp(req);\n },\n);\n", "// abort-http-signal.ts\nimport type { IncomingMessage } from 'http';\nimport type { Request as ExpressReq } from 'express';\nimport type { FastifyRequest } from 'fastify';\nimport { BlankReturnMessageDto } from './return-message';\n\ntype AnyReq = ExpressReq | FastifyRequest | IncomingMessage;\n\nfunction toRawReq(req: AnyReq): IncomingMessage {\n // Fastify: req.raw \u662F IncomingMessage\uFF1BExpress: req \u672C\u8EAB\u5C31\u662F IncomingMessage\n if ((req as any)?.raw?.socket) return (req as any).raw as IncomingMessage;\n return req as IncomingMessage;\n}\n\n/**\n * \u4EC5\u901A\u8FC7 req \u81EA\u52A8\u9002\u914D Express/Fastify\uFF0C\u7ED1\u5B9A HTTP \u53D6\u6D88\u5230 AbortSignal\u3002\n * - \u4F18\u5148\u76D1\u542C 'aborted'\uFF08\u5BA2\u6237\u7AEF\u4E2D\u65AD\u6700\u53EF\u9760\u7684\u4FE1\u53F7\uFF09\n * - \u53EF\u9009\u515C\u5E95\uFF1A\u5728 socket 'close' \u65F6\uFF0C\u4EC5\u5F53\u8BF7\u6C42\u672A\u5B8C\u6574\u63A5\u6536/\u6216\u5DF2\u6807\u8BB0 aborted \u65F6\uFF0C\u624D\u89E6\u53D1 abort\uFF0C\u907F\u514D\u6B63\u5E38\u5B8C\u6210\u7684\u8BEF\u4F24\n * - reason \u56FA\u5B9A\u4E3A 499 HttpException\n *\n * \u6CE8\u610F\uFF1A\u82E5\u4F60\u7684 abortable() \u5728 signal.reason \u662F Error \u65F6\u4F1A\u201C\u539F\u6837 throw reason\u201D\uFF0C\n * \u90A3\u4E48\u4E0A\u5C42\u4F1A\u6536\u5230 HttpException(499)\u3002\u82E5\u4ECD\u60F3\u7EDF\u4E00\u629B AbortedError\uFF0C\u53EF\u6539\u4E3A\uFF1A\n * const reason = new AbortedError('Request aborted', httpErr);\n * \u5E76\u8BA9 throwIfAborted \u5148\u629B AbortedError\uFF08\u4FDD\u7559 cause\uFF09\u3002\n */\nexport function createAbortSignalFromHttp(req: AnyReq): AbortSignal {\n const rawReq = toRawReq(req);\n const ac = new AbortController();\n\n const makeReason = () =>\n new BlankReturnMessageDto(499, 'Request aborted').toException();\n\n const abortOnce = () => {\n if (!ac.signal.aborted) ac.abort(makeReason());\n cleanup();\n };\n\n const onClose = () => {\n abortOnce();\n };\n\n const cleanup = () => {\n rawReq.off?.('close', onClose);\n };\n\n rawReq.once?.('close', onClose);\n\n return ac.signal;\n}\n", "import { Inject, Provider, Scope } from '@nestjs/common';\nimport { abortable, AbortableOpts } from 'nfkit';\nimport { ABORT_SIGNAL } from './abort-signal.provider';\nimport { ContextIdFactory, ModuleRef, REQUEST } from '@nestjs/core';\n\nexport type ProviderToken<T = any> =\n | string\n | symbol\n | (new (...args: any[]) => T);\n\nconst tokenMemo = new Map<any, symbol>();\nexport const abortableToken = (token: ProviderToken) => {\n if (tokenMemo.has(token)) return tokenMemo.get(token)!;\n const name = typeof token === 'function' ? token.name : String(token);\n const sym = Symbol.for(`Abortable(${name})`);\n tokenMemo.set(token, sym);\n return sym;\n};\n\n/**\n * \u652F\u6301\u4E24\u79CD\u7528\u6CD5\uFF1A\n * @InjectAbortable(SomeService)\n * @InjectAbortable() // \u81EA\u52A8\u63A8\u65AD\u7C7B\u578B\n */\nexport function InjectAbortable(token?: ProviderToken): ParameterDecorator {\n return (target, propertyKey, parameterIndex) => {\n let actualToken = token;\n\n if (!actualToken) {\n // \u5229\u7528 reflect-metadata \u83B7\u53D6\u53C2\u6570\u7C7B\u578B\n const paramTypes: any[] =\n Reflect.getMetadata('design:paramtypes', target, propertyKey) || [];\n actualToken = paramTypes[parameterIndex];\n if (!actualToken) {\n throw new Error(\n `@InjectAbortable() cannot infer type from metadata: ${target.constructor?.name}[${parameterIndex}]`,\n );\n }\n }\n\n Inject(abortableToken(actualToken))(target, propertyKey, parameterIndex);\n };\n}\n\nexport function createAbortableProvider<T>(\n token: ProviderToken<T>,\n opts?: AbortableOpts,\n): Provider {\n const provide = abortableToken(token);\n\n return {\n provide,\n scope: Scope.REQUEST,\n inject: [ModuleRef, REQUEST, ABORT_SIGNAL],\n // \u26A0\uFE0F \u6CE8\u610F\uFF1A\u7528 async + resolve + contextId + strict:false\n useFactory: async (\n moduleRef: ModuleRef,\n req: Request,\n signal: AbortSignal,\n ) => {\n // \u8BA9\u89E3\u6790\u4E0E\u5F53\u524D\u8BF7\u6C42\u4E0A\u4E0B\u6587\u7ED1\u5B9A\uFF08\u652F\u6301 request/transient \u4F5C\u7528\u57DF\uFF09\n const ctxId = ContextIdFactory.getByRequest(req);\n // \u4E25\u683C\u6A21\u5F0F\u5173\u95ED\uFF0C\u5141\u8BB8\u8DE8\u6A21\u5757\u8FB9\u754C\u89E3\u6790\uFF08\u89E3\u51B3\u6D4B\u8BD5\u91CC forFeature \u5B50\u6A21\u5757\u770B\u4E0D\u5230 DemoService \u7684\u60C5\u51B5\uFF09\n const svc = await moduleRef.resolve<T>(token, ctxId, { strict: false });\n if (svc == null) {\n throw new Error(\n `Abortable: provider \"${String(\n (token as any).name ?? token,\n )}\" not found in container (even with strict:false)`,\n );\n }\n return abortable<T>(svc, signal, opts);\n },\n };\n}\n", "import { Inject, Provider, Scope } from '@nestjs/common';\nimport { REQUEST } from '@nestjs/core';\nimport type { Request as ExpressReq } from 'express';\nimport { createAbortSignalFromHttp } from '../abort-http-signal';\n\nexport const ABORT_SIGNAL = Symbol('ABORT_SIGNAL');\nexport const AbortSignalProvider: Provider = {\n provide: ABORT_SIGNAL,\n scope: Scope.REQUEST,\n inject: [REQUEST],\n useFactory: (req: ExpressReq) => {\n return createAbortSignalFromHttp(req);\n },\n};\n\nexport const InjectAbortSignal = () => Inject(ABORT_SIGNAL);\n", "import { DynamicModule, Module, Provider } from '@nestjs/common';\nimport { ProviderToken, createAbortableProvider } from './abortable.token';\nimport { AbortableOpts } from 'nfkit';\nimport { AbortSignalProvider } from './abort-signal.provider';\n\nexport interface AbortableModuleOptions {\n abortableOptions?: AbortableOpts;\n}\n\n@Module({})\nexport class AbortableModule {\n static forRoot(): DynamicModule {\n return {\n module: AbortableModule,\n providers: [AbortSignalProvider],\n exports: [AbortSignalProvider],\n global: true,\n };\n }\n\n static forFeature(\n tokens: ProviderToken[],\n options?: AbortableModuleOptions,\n ): DynamicModule {\n const providers: Provider[] = tokens.map((token) =>\n createAbortableProvider(token, options?.abortableOptions),\n );\n\n return {\n module: AbortableModule,\n providers: [...providers],\n exports: [...providers],\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["ApiProperty", "ApiProperty", "Inject", "Scope", "REQUEST", "Inject", "Scope"]
7
+ }
@@ -0,0 +1,17 @@
1
+ import type { IncomingMessage } from 'http';
2
+ import type { Request as ExpressReq } from 'express';
3
+ import type { FastifyRequest } from 'fastify';
4
+ type AnyReq = ExpressReq | FastifyRequest | IncomingMessage;
5
+ /**
6
+ * 仅通过 req 自动适配 Express/Fastify,绑定 HTTP 取消到 AbortSignal。
7
+ * - 优先监听 'aborted'(客户端中断最可靠的信号)
8
+ * - 可选兜底:在 socket 'close' 时,仅当请求未完整接收/或已标记 aborted 时,才触发 abort,避免正常完成的误伤
9
+ * - reason 固定为 499 HttpException
10
+ *
11
+ * 注意:若你的 abortable() 在 signal.reason 是 Error 时会“原样 throw reason”,
12
+ * 那么上层会收到 HttpException(499)。若仍想统一抛 AbortedError,可改为:
13
+ * const reason = new AbortedError('Request aborted', httpErr);
14
+ * 并让 throwIfAborted 先抛 AbortedError(保留 cause)。
15
+ */
16
+ export declare function createAbortSignalFromHttp(req: AnyReq): AbortSignal;
17
+ export {};
@@ -0,0 +1,5 @@
1
+ import { Observable } from 'rxjs';
2
+ export type AbortableFn<T> = (ac: AbortController) => Promise<T>;
3
+ export declare const fromAbortable: <T>(fn: AbortableFn<T>) => Observable<T>;
4
+ export declare const takeUntilAbort: <T>(signal: AbortSignal) => (source: Observable<T>) => Observable<T>;
5
+ export declare const As: (...dataOrPipes: unknown[]) => ParameterDecorator;
@@ -0,0 +1,4 @@
1
+ import { Provider } from '@nestjs/common';
2
+ export declare const ABORT_SIGNAL: unique symbol;
3
+ export declare const AbortSignalProvider: Provider;
4
+ export declare const InjectAbortSignal: () => PropertyDecorator & ParameterDecorator;
@@ -0,0 +1,10 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { ProviderToken } from './abortable.token';
3
+ import { AbortableOpts } from 'nfkit';
4
+ export interface AbortableModuleOptions {
5
+ abortableOptions?: AbortableOpts;
6
+ }
7
+ export declare class AbortableModule {
8
+ static forRoot(): DynamicModule;
9
+ static forFeature(tokens: ProviderToken[], options?: AbortableModuleOptions): DynamicModule;
10
+ }
@@ -0,0 +1,11 @@
1
+ import { Provider } from '@nestjs/common';
2
+ import { AbortableOpts } from 'nfkit';
3
+ export type ProviderToken<T = any> = string | symbol | (new (...args: any[]) => T);
4
+ export declare const abortableToken: (token: ProviderToken) => symbol;
5
+ /**
6
+ * 支持两种用法:
7
+ * @InjectAbortable(SomeService)
8
+ * @InjectAbortable() // 自动推断类型
9
+ */
10
+ export declare function InjectAbortable(token?: ProviderToken): ParameterDecorator;
11
+ export declare function createAbortableProvider<T>(token: ProviderToken<T>, opts?: AbortableOpts): Provider;
@@ -0,0 +1,3 @@
1
+ export * from './abortable.token';
2
+ export * from './abortable.module';
3
+ export * from './abort-signal.provider';
@@ -3,3 +3,4 @@ import { ClassOrArray } from './insert-field';
3
3
  export declare const ApiTypeResponse: (type: ClassOrArray, options?: ApiResponseOptions) => MethodDecorator & ClassDecorator;
4
4
  export declare const ApiBlankResponse: (options?: ApiResponseOptions) => MethodDecorator & ClassDecorator;
5
5
  export declare const ApiError: (status: number, description: string) => MethodDecorator & ClassDecorator;
6
+ export declare const ApiErrorTyped: (status: number, description: string, type: ClassOrArray) => MethodDecorator & ClassDecorator;
package/index.ts CHANGED
@@ -4,3 +4,5 @@ export * from './src/return-message';
4
4
  export * from './src/openapi';
5
5
  export * from './src/pipe';
6
6
  export * from './src/token.guard';
7
+ export * from './src/abort-utils';
8
+ export * from './src/abortable-module';