nesties 1.1.6 → 1.1.8

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,96 +801,30 @@ 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,
758
814
  Inject as Inject5,
759
815
  Injectable as Injectable3
760
816
  } from "@nestjs/common";
817
+ import { ModuleRef as ModuleRef4 } from "@nestjs/core";
761
818
  var LocalePipe = class {
762
- constructor(i18nService) {
819
+ constructor(i18nService, moduleRef) {
763
820
  this.i18nService = i18nService;
821
+ this.moduleRef = moduleRef;
764
822
  }
765
823
  async transform(ctx, metadata) {
766
824
  const resolver = ctx.resolver;
767
825
  if (resolver) {
768
- const _resolver = createDynamicResolverFromStatic(resolver);
769
- const locale = await _resolver(ctx.ctx, void 0);
826
+ const _resolver = createResolver(resolver);
827
+ const locale = await _resolver(ctx.ctx, this.moduleRef);
770
828
  return this.i18nService.getExactLocale(locale);
771
829
  } else {
772
830
  return this.i18nService.getExactLocaleFromRequest(ctx.ctx);
@@ -775,7 +833,8 @@ var LocalePipe = class {
775
833
  };
776
834
  LocalePipe = __decorateClass([
777
835
  Injectable3(),
778
- __decorateParam(0, Inject5(I18nService))
836
+ __decorateParam(0, Inject5(I18nService)),
837
+ __decorateParam(1, Inject5(ModuleRef4))
779
838
  ], LocalePipe);
780
839
  var _dec = createParamDecorator2((resolver, ctx) => {
781
840
  return { ctx, resolver };
@@ -788,17 +847,7 @@ var I18nModule = class extends ConfigurableModuleClass {
788
847
  I18nModule = __decorateClass([
789
848
  Global(),
790
849
  Module2({
791
- providers: [
792
- createProvider(
793
- {
794
- provide: I18nResolverToken,
795
- inject: [I18nModuleOptionsToken]
796
- },
797
- (o) => createDynamicResolverFromStatic(o.resolver)
798
- ),
799
- I18nService,
800
- LocalePipe
801
- ],
850
+ providers: [I18nService, LocalePipe],
802
851
  exports: [I18nService, LocalePipe]
803
852
  })
804
853
  ], I18nModule);
@@ -846,24 +895,15 @@ I18nInterceptor = __decorateClass([
846
895
  ], I18nInterceptor);
847
896
 
848
897
  // src/i18n-module/i18n-decorator.ts
849
- import {
850
- ApiHeader as ApiHeader2,
851
- ApiQuery
852
- } from "@nestjs/swagger";
853
898
  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
899
  return () => MergeClassOrMethodDecorators([
865
900
  UseInterceptors(I18nInterceptor),
866
- ...paramType ? [dec()] : []
901
+ ApiFromResolver(options.resolver, {
902
+ description: "Locale for internationalization",
903
+ required: false,
904
+ default: options.defaultLocale ?? options.locales[0],
905
+ enum: options.locales
906
+ })
867
907
  ]);
868
908
  };
869
909
 
@@ -881,7 +921,7 @@ var createI18n = (options) => {
881
921
  };
882
922
  };
883
923
 
884
- // src/i18n-module/middelewares/lookup.ts
924
+ // src/i18n-module/middlewares/lookup.ts
885
925
  var I18nLookupMiddleware = (dict, options) => {
886
926
  const matchType = options?.matchType ?? "exact";
887
927
  const dictFactory = typeof dict === "function" ? dict : () => dict;
@@ -919,7 +959,9 @@ var I18nLookupMiddleware = (dict, options) => {
919
959
  }
920
960
  if (dictionary && Object.prototype.hasOwnProperty.call(dictionary, key)) {
921
961
  const val = dictionary[key];
922
- if (val != null) return val;
962
+ if (val != null) {
963
+ return val;
964
+ }
923
965
  }
924
966
  return next();
925
967
  };
@@ -931,6 +973,7 @@ export {
931
973
  ApiBlankResponse,
932
974
  ApiError,
933
975
  ApiErrorTyped,
976
+ ApiFromResolver,
934
977
  ApiTypeResponse,
935
978
  As,
936
979
  BlankPaginatedReturnMessageDto,
@@ -964,6 +1007,7 @@ export {
964
1007
  createI18n,
965
1008
  createI18nDecorator,
966
1009
  createProvider,
1010
+ createResolver,
967
1011
  fromAbortable,
968
1012
  getClassFromClassOrArray,
969
1013
  takeUntilAbort