nesties 1.1.6 → 1.1.7

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.mjs CHANGED
@@ -207,34 +207,158 @@ import {
207
207
  UseGuards
208
208
  } from "@nestjs/common";
209
209
  import { ConfigService } from "@nestjs/config";
210
- import { ApiHeader } from "@nestjs/swagger";
210
+ import { ApiHeader as ApiHeader2 } from "@nestjs/swagger";
211
+
212
+ // src/resolver.ts
213
+ import {
214
+ ApiHeader,
215
+ ApiQuery
216
+ } from "@nestjs/swagger";
217
+ var coerceToString = (v) => {
218
+ if (v == null) return void 0;
219
+ if (v === false) return void 0;
220
+ if (Array.isArray(v)) return v.length ? coerceToString(v[0]) : void 0;
221
+ if (typeof v === "string") return v;
222
+ if (typeof v === "number") return String(v);
223
+ return void 0;
224
+ };
225
+ var getHeader = (req, name) => {
226
+ const viaMethod = typeof req.getHeader === "function" && req.getHeader(name) || typeof req.header === "function" && req.header(name) || typeof req.get === "function" && req.get(name);
227
+ if (viaMethod) {
228
+ return coerceToString(viaMethod);
229
+ }
230
+ const n = name.toLowerCase();
231
+ const headers = req.headers ?? {};
232
+ if (n in headers) return coerceToString(headers[n]);
233
+ const hit = Object.entries(headers).find(([k]) => k.toLowerCase() === n)?.[1];
234
+ return coerceToString(hit);
235
+ };
236
+ var pickPrimaryFromAcceptLanguage = (v) => {
237
+ if (!v) return void 0;
238
+ const first = v.split(",")[0]?.trim();
239
+ return first?.split(";")[0]?.trim() || first;
240
+ };
241
+ function getQueryValue(req, key) {
242
+ const q = req.query;
243
+ if (q && typeof q === "object" && !("raw" in q)) {
244
+ const v = q[key];
245
+ if (v != null) return coerceToString(v);
246
+ }
247
+ const rawUrl = req.originalUrl ?? req.url;
248
+ if (typeof rawUrl === "string" && rawUrl.includes("?")) {
249
+ try {
250
+ const search = rawUrl.startsWith("http") ? new URL(rawUrl).search : new URL(rawUrl, "http://localhost").search;
251
+ if (search) {
252
+ const params = new URLSearchParams(search);
253
+ const val = params.get(key);
254
+ if (val != null) return val;
255
+ }
256
+ } catch {
257
+ }
258
+ }
259
+ return void 0;
260
+ }
261
+ var createResolver = (_options) => {
262
+ if (typeof _options === "function") {
263
+ return _options;
264
+ }
265
+ const options = _options;
266
+ const field = options.paramType;
267
+ let name = options.paramName;
268
+ if (field === "header") name = name.toLowerCase();
269
+ return (ctx) => {
270
+ const req = ctx.switchToHttp().getRequest();
271
+ if (field === "header") {
272
+ let raw = getHeader(req, name);
273
+ if (name === "accept-language") raw = pickPrimaryFromAcceptLanguage(raw);
274
+ return raw;
275
+ }
276
+ if (field === "query") {
277
+ return getQueryValue(req, name);
278
+ }
279
+ throw new Error(`Unsupported paramType: ${field}`);
280
+ };
281
+ };
282
+ var ApiFromResolver = (_options, extras = {}) => {
283
+ if (typeof _options === "function") {
284
+ return () => {
285
+ };
286
+ }
287
+ const options = _options;
288
+ const paramType = options?.paramType;
289
+ const apiOptions = {
290
+ name: options.paramName,
291
+ ...extras
292
+ };
293
+ return paramType === "header" ? ApiHeader(apiOptions) : paramType === "query" ? ApiQuery({ type: "string", ...apiOptions }) : () => {
294
+ };
295
+ };
296
+
297
+ // src/token.guard.ts
298
+ import { MetadataSetter, Reflector } from "typed-reflector";
299
+ import { ModuleRef } from "@nestjs/core";
300
+ var reflector = new Reflector();
301
+ var Metadata = new MetadataSetter();
302
+ var defaultHeaderName = "x-server-token";
303
+ var defaultConfigName = "SERVER_TOKEN";
304
+ var defaultErrorCode = 401;
211
305
  var TokenGuard = class {
212
- constructor(config) {
306
+ constructor(config, moduleRef) {
213
307
  this.config = config;
214
- this.token = this.config.get("SERVER_TOKEN");
308
+ this.moduleRef = moduleRef;
215
309
  }
216
310
  async canActivate(context) {
217
- const request = context.switchToHttp().getRequest();
218
- const token = request.headers["x-server-token"];
219
- if (this.token && token !== this.token) {
220
- throw new BlankReturnMessageDto(401, "Unauthorized").toException();
311
+ const controller = context.getClass();
312
+ const handlerName = context.getHandler()?.name;
313
+ let config = {};
314
+ if (controller) {
315
+ if (handlerName) {
316
+ config = reflector.get("requireTokenOptions", controller, handlerName) || {};
317
+ } else {
318
+ config = reflector.get("requireTokenOptions", controller) || {};
319
+ }
320
+ }
321
+ const resolver = createResolver(
322
+ config.resolver || { paramType: "header", paramName: defaultHeaderName }
323
+ );
324
+ const tokenSource = config.tokenSource || defaultConfigName;
325
+ const [tokenFromClient, tokenFromConfig] = await Promise.all([
326
+ resolver(context, this.moduleRef),
327
+ typeof tokenSource === "function" ? tokenSource(context, this.moduleRef) : this.config.get(tokenSource)
328
+ ]);
329
+ if (tokenFromConfig && tokenFromConfig !== tokenFromClient) {
330
+ throw new BlankReturnMessageDto(
331
+ config.errorCode || defaultErrorCode,
332
+ "Unauthorized"
333
+ ).toException();
221
334
  }
222
335
  return true;
223
336
  }
224
337
  };
225
338
  TokenGuard = __decorateClass([
226
339
  Injectable(),
227
- __decorateParam(0, Inject(ConfigService))
340
+ __decorateParam(0, Inject(ConfigService)),
341
+ __decorateParam(1, Inject(ModuleRef))
228
342
  ], TokenGuard);
229
- var RequireToken = () => MergeClassOrMethodDecorators([
230
- UseGuards(TokenGuard),
231
- ApiHeader({
232
- name: "x-server-token",
343
+ var RequireToken = (options = {}) => {
344
+ const swaggerDec = options.resolver ? ApiFromResolver(options.resolver, {
345
+ description: "Server token",
346
+ required: false
347
+ }) : ApiHeader2({
348
+ name: defaultHeaderName,
233
349
  description: "Server token",
234
350
  required: false
235
- }),
236
- ApiError(401, "Incorrect server token provided")
237
- ]);
351
+ });
352
+ return MergeClassOrMethodDecorators([
353
+ UseGuards(TokenGuard),
354
+ swaggerDec,
355
+ ApiError(
356
+ options.errorCode || defaultErrorCode,
357
+ "Incorrect server token provided"
358
+ ),
359
+ ...options ? [Metadata.set("requireTokenOptions", options)] : []
360
+ ]);
361
+ };
238
362
 
239
363
  // src/abort-utils.ts
240
364
  import { Observable, takeUntil } from "rxjs";
@@ -342,7 +466,7 @@ var AbortSignalProvider = createProvider(
342
466
  var InjectAbortSignal = () => Inject2(ABORT_SIGNAL);
343
467
 
344
468
  // src/abortable-module/abortable.token.ts
345
- import { ContextIdFactory, ModuleRef, REQUEST as REQUEST2 } from "@nestjs/core";
469
+ import { ContextIdFactory, ModuleRef as ModuleRef2, REQUEST as REQUEST2 } from "@nestjs/core";
346
470
  var tokenMemo = /* @__PURE__ */ new Map();
347
471
  var abortableToken = (token) => {
348
472
  if (tokenMemo.has(token)) return tokenMemo.get(token);
@@ -372,7 +496,7 @@ function createAbortableProvider(token, opts) {
372
496
  {
373
497
  provide,
374
498
  scope: Scope2.REQUEST,
375
- inject: [ModuleRef, REQUEST2, ABORT_SIGNAL]
499
+ inject: [ModuleRef2, REQUEST2, ABORT_SIGNAL]
376
500
  },
377
501
  async (moduleRef, req, signal) => {
378
502
  const ctxId = ContextIdFactory.getByRequest(req);
@@ -465,12 +589,12 @@ var parseI18n = (text) => {
465
589
  };
466
590
 
467
591
  // src/i18n-module/i18n.service.ts
468
- import { ModuleRef as ModuleRef2 } from "@nestjs/core";
592
+ import { ModuleRef as ModuleRef3 } from "@nestjs/core";
469
593
  var I18nService = class {
470
- constructor(resolver, options, moduleRef) {
471
- this.resolver = resolver;
594
+ constructor(options, moduleRef) {
472
595
  this.options = options;
473
596
  this.moduleRef = moduleRef;
597
+ this.resolver = createResolver(this.options.resolver);
474
598
  this.locales = new Set(this.options.locales);
475
599
  this.defaultLocale = this.options.defaultLocale ?? this.options.locales[0];
476
600
  this.middlewares = [];
@@ -677,81 +801,13 @@ var I18nService = class {
677
801
  };
678
802
  I18nService = __decorateClass([
679
803
  Injectable2(),
680
- __decorateParam(0, Inject4(I18nResolverToken)),
681
- __decorateParam(1, Inject4(I18nModuleOptionsToken)),
682
- __decorateParam(2, Inject4(ModuleRef2))
804
+ __decorateParam(0, Inject4(I18nModuleOptionsToken)),
805
+ __decorateParam(1, Inject4(ModuleRef3))
683
806
  ], I18nService);
684
807
 
685
808
  // src/i18n-module/i18n.module.ts
686
809
  import { Global, Module as Module2 } from "@nestjs/common";
687
810
 
688
- // src/i18n-module/i18n-resolver.ts
689
- var coerceToString = (v) => {
690
- if (v == null) return void 0;
691
- if (v === false) return void 0;
692
- if (Array.isArray(v)) return v.length ? coerceToString(v[0]) : void 0;
693
- if (typeof v === "string") return v;
694
- if (typeof v === "number") return String(v);
695
- return void 0;
696
- };
697
- var getHeader = (req, name) => {
698
- const viaMethod = typeof req.getHeader === "function" && req.getHeader(name) || typeof req.header === "function" && req.header(name) || typeof req.get === "function" && req.get(name);
699
- if (viaMethod) {
700
- return coerceToString(viaMethod);
701
- }
702
- const n = name.toLowerCase();
703
- const headers = req.headers ?? {};
704
- if (n in headers) return coerceToString(headers[n]);
705
- const hit = Object.entries(headers).find(([k]) => k.toLowerCase() === n)?.[1];
706
- return coerceToString(hit);
707
- };
708
- var pickPrimaryFromAcceptLanguage = (v) => {
709
- if (!v) return void 0;
710
- const first = v.split(",")[0]?.trim();
711
- return first?.split(";")[0]?.trim() || first;
712
- };
713
- function getQueryValue(req, key) {
714
- const q = req.query;
715
- if (q && typeof q === "object" && !("raw" in q)) {
716
- const v = q[key];
717
- if (v != null) return coerceToString(v);
718
- }
719
- const rawUrl = req.originalUrl ?? req.url;
720
- if (typeof rawUrl === "string" && rawUrl.includes("?")) {
721
- try {
722
- const search = rawUrl.startsWith("http") ? new URL(rawUrl).search : new URL(rawUrl, "http://localhost").search;
723
- if (search) {
724
- const params = new URLSearchParams(search);
725
- const val = params.get(key);
726
- if (val != null) return val;
727
- }
728
- } catch {
729
- }
730
- }
731
- return void 0;
732
- }
733
- var createDynamicResolverFromStatic = (_options) => {
734
- if (typeof _options === "function") {
735
- return _options;
736
- }
737
- const options = _options;
738
- const field = options.paramType;
739
- let name = options.paramName;
740
- if (field === "header") name = name.toLowerCase();
741
- return (ctx) => {
742
- const req = ctx.switchToHttp().getRequest();
743
- if (field === "header") {
744
- let raw = getHeader(req, name);
745
- if (name === "accept-language") raw = pickPrimaryFromAcceptLanguage(raw);
746
- return raw;
747
- }
748
- if (field === "query") {
749
- return getQueryValue(req, name);
750
- }
751
- throw new Error(`Unsupported paramType: ${field}`);
752
- };
753
- };
754
-
755
811
  // src/i18n-module/locale.pipe.ts
756
812
  import {
757
813
  createParamDecorator as createParamDecorator2,
@@ -765,7 +821,7 @@ var LocalePipe = class {
765
821
  async transform(ctx, metadata) {
766
822
  const resolver = ctx.resolver;
767
823
  if (resolver) {
768
- const _resolver = createDynamicResolverFromStatic(resolver);
824
+ const _resolver = createResolver(resolver);
769
825
  const locale = await _resolver(ctx.ctx, void 0);
770
826
  return this.i18nService.getExactLocale(locale);
771
827
  } else {
@@ -788,17 +844,7 @@ var I18nModule = class extends ConfigurableModuleClass {
788
844
  I18nModule = __decorateClass([
789
845
  Global(),
790
846
  Module2({
791
- providers: [
792
- createProvider(
793
- {
794
- provide: I18nResolverToken,
795
- inject: [I18nModuleOptionsToken]
796
- },
797
- (o) => createDynamicResolverFromStatic(o.resolver)
798
- ),
799
- I18nService,
800
- LocalePipe
801
- ],
847
+ providers: [I18nService, LocalePipe],
802
848
  exports: [I18nService, LocalePipe]
803
849
  })
804
850
  ], I18nModule);
@@ -846,24 +892,15 @@ I18nInterceptor = __decorateClass([
846
892
  ], I18nInterceptor);
847
893
 
848
894
  // src/i18n-module/i18n-decorator.ts
849
- import {
850
- ApiHeader as ApiHeader2,
851
- ApiQuery
852
- } from "@nestjs/swagger";
853
895
  var createI18nDecorator = (options) => {
854
- const paramType = options.resolver?.paramType;
855
- const apiOptions = {
856
- name: options.resolver.paramName,
857
- description: "Locale for internationalization",
858
- required: false,
859
- default: options.defaultLocale ?? options.locales[0],
860
- enum: options.locales
861
- };
862
- const dec = paramType === "header" ? () => ApiHeader2(apiOptions) : paramType === "query" ? () => ApiQuery({ ...apiOptions, type: "string" }) : () => () => {
863
- };
864
896
  return () => MergeClassOrMethodDecorators([
865
897
  UseInterceptors(I18nInterceptor),
866
- ...paramType ? [dec()] : []
898
+ ApiFromResolver(options.resolver, {
899
+ description: "Locale for internationalization",
900
+ required: false,
901
+ default: options.defaultLocale ?? options.locales[0],
902
+ enum: options.locales
903
+ })
867
904
  ]);
868
905
  };
869
906
 
@@ -881,7 +918,7 @@ var createI18n = (options) => {
881
918
  };
882
919
  };
883
920
 
884
- // src/i18n-module/middelewares/lookup.ts
921
+ // src/i18n-module/middlewares/lookup.ts
885
922
  var I18nLookupMiddleware = (dict, options) => {
886
923
  const matchType = options?.matchType ?? "exact";
887
924
  const dictFactory = typeof dict === "function" ? dict : () => dict;
@@ -919,7 +956,9 @@ var I18nLookupMiddleware = (dict, options) => {
919
956
  }
920
957
  if (dictionary && Object.prototype.hasOwnProperty.call(dictionary, key)) {
921
958
  const val = dictionary[key];
922
- if (val != null) return val;
959
+ if (val != null) {
960
+ return val;
961
+ }
923
962
  }
924
963
  return next();
925
964
  };
@@ -931,6 +970,7 @@ export {
931
970
  ApiBlankResponse,
932
971
  ApiError,
933
972
  ApiErrorTyped,
973
+ ApiFromResolver,
934
974
  ApiTypeResponse,
935
975
  As,
936
976
  BlankPaginatedReturnMessageDto,
@@ -964,6 +1004,7 @@ export {
964
1004
  createI18n,
965
1005
  createI18nDecorator,
966
1006
  createProvider,
1007
+ createResolver,
967
1008
  fromAbortable,
968
1009
  getClassFromClassOrArray,
969
1010
  takeUntilAbort