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.cjs +161 -118
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +160 -119
- package/dist/index.mjs.map +4 -4
- package/dist/src/i18n-module/i18n-factory.d.ts +3 -2
- package/dist/src/i18n-module/i18n-module.options.d.ts +2 -10
- package/dist/src/i18n-module/i18n.service.d.ts +3 -3
- package/dist/src/i18n-module/index.d.ts +1 -1
- package/dist/src/i18n-module/locale.pipe.d.ts +3 -3
- package/dist/src/resolver.d.ts +12 -0
- package/dist/src/token.guard.d.ts +10 -3
- package/index.ts +1 -0
- package/package.json +3 -2
- package/dist/src/i18n-module/i18n-resolver.d.ts +0 -2
- /package/dist/src/i18n-module/{middelewares → middlewares}/index.d.ts +0 -0
- /package/dist/src/i18n-module/{middelewares → middlewares}/lookup.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
ApiBlankResponse: () => ApiBlankResponse,
|
|
35
35
|
ApiError: () => ApiError,
|
|
36
36
|
ApiErrorTyped: () => ApiErrorTyped,
|
|
37
|
+
ApiFromResolver: () => ApiFromResolver,
|
|
37
38
|
ApiTypeResponse: () => ApiTypeResponse,
|
|
38
39
|
As: () => As,
|
|
39
40
|
BlankPaginatedReturnMessageDto: () => BlankPaginatedReturnMessageDto,
|
|
@@ -67,6 +68,7 @@ __export(index_exports, {
|
|
|
67
68
|
createI18n: () => createI18n,
|
|
68
69
|
createI18nDecorator: () => createI18nDecorator,
|
|
69
70
|
createProvider: () => createProvider,
|
|
71
|
+
createResolver: () => createResolver,
|
|
70
72
|
fromAbortable: () => fromAbortable,
|
|
71
73
|
getClassFromClassOrArray: () => getClassFromClassOrArray,
|
|
72
74
|
takeUntilAbort: () => takeUntilAbort
|
|
@@ -262,34 +264,155 @@ var DataBody = createDataPipeDec(import_common2.Body);
|
|
|
262
264
|
// src/token.guard.ts
|
|
263
265
|
var import_common3 = require("@nestjs/common");
|
|
264
266
|
var import_config = require("@nestjs/config");
|
|
267
|
+
var import_swagger5 = require("@nestjs/swagger");
|
|
268
|
+
|
|
269
|
+
// src/resolver.ts
|
|
265
270
|
var import_swagger4 = require("@nestjs/swagger");
|
|
271
|
+
var coerceToString = (v) => {
|
|
272
|
+
if (v == null) return void 0;
|
|
273
|
+
if (v === false) return void 0;
|
|
274
|
+
if (Array.isArray(v)) return v.length ? coerceToString(v[0]) : void 0;
|
|
275
|
+
if (typeof v === "string") return v;
|
|
276
|
+
if (typeof v === "number") return String(v);
|
|
277
|
+
return void 0;
|
|
278
|
+
};
|
|
279
|
+
var getHeader = (req, name) => {
|
|
280
|
+
const viaMethod = typeof req.getHeader === "function" && req.getHeader(name) || typeof req.header === "function" && req.header(name) || typeof req.get === "function" && req.get(name);
|
|
281
|
+
if (viaMethod) {
|
|
282
|
+
return coerceToString(viaMethod);
|
|
283
|
+
}
|
|
284
|
+
const n = name.toLowerCase();
|
|
285
|
+
const headers = req.headers ?? {};
|
|
286
|
+
if (n in headers) return coerceToString(headers[n]);
|
|
287
|
+
const hit = Object.entries(headers).find(([k]) => k.toLowerCase() === n)?.[1];
|
|
288
|
+
return coerceToString(hit);
|
|
289
|
+
};
|
|
290
|
+
var pickPrimaryFromAcceptLanguage = (v) => {
|
|
291
|
+
if (!v) return void 0;
|
|
292
|
+
const first = v.split(",")[0]?.trim();
|
|
293
|
+
return first?.split(";")[0]?.trim() || first;
|
|
294
|
+
};
|
|
295
|
+
function getQueryValue(req, key) {
|
|
296
|
+
const q = req.query;
|
|
297
|
+
if (q && typeof q === "object" && !("raw" in q)) {
|
|
298
|
+
const v = q[key];
|
|
299
|
+
if (v != null) return coerceToString(v);
|
|
300
|
+
}
|
|
301
|
+
const rawUrl = req.originalUrl ?? req.url;
|
|
302
|
+
if (typeof rawUrl === "string" && rawUrl.includes("?")) {
|
|
303
|
+
try {
|
|
304
|
+
const search = rawUrl.startsWith("http") ? new URL(rawUrl).search : new URL(rawUrl, "http://localhost").search;
|
|
305
|
+
if (search) {
|
|
306
|
+
const params = new URLSearchParams(search);
|
|
307
|
+
const val = params.get(key);
|
|
308
|
+
if (val != null) return val;
|
|
309
|
+
}
|
|
310
|
+
} catch {
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return void 0;
|
|
314
|
+
}
|
|
315
|
+
var createResolver = (_options) => {
|
|
316
|
+
if (typeof _options === "function") {
|
|
317
|
+
return _options;
|
|
318
|
+
}
|
|
319
|
+
const options = _options;
|
|
320
|
+
const field = options.paramType;
|
|
321
|
+
let name = options.paramName;
|
|
322
|
+
if (field === "header") name = name.toLowerCase();
|
|
323
|
+
return (ctx) => {
|
|
324
|
+
const req = ctx.switchToHttp().getRequest();
|
|
325
|
+
if (field === "header") {
|
|
326
|
+
let raw = getHeader(req, name);
|
|
327
|
+
if (name === "accept-language") raw = pickPrimaryFromAcceptLanguage(raw);
|
|
328
|
+
return raw;
|
|
329
|
+
}
|
|
330
|
+
if (field === "query") {
|
|
331
|
+
return getQueryValue(req, name);
|
|
332
|
+
}
|
|
333
|
+
throw new Error(`Unsupported paramType: ${field}`);
|
|
334
|
+
};
|
|
335
|
+
};
|
|
336
|
+
var ApiFromResolver = (_options, extras = {}) => {
|
|
337
|
+
if (typeof _options === "function") {
|
|
338
|
+
return () => {
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
const options = _options;
|
|
342
|
+
const paramType = options?.paramType;
|
|
343
|
+
const apiOptions = {
|
|
344
|
+
name: options.paramName,
|
|
345
|
+
...extras
|
|
346
|
+
};
|
|
347
|
+
return paramType === "header" ? (0, import_swagger4.ApiHeader)(apiOptions) : paramType === "query" ? (0, import_swagger4.ApiQuery)({ type: "string", ...apiOptions }) : () => {
|
|
348
|
+
};
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/token.guard.ts
|
|
352
|
+
var import_typed_reflector = require("typed-reflector");
|
|
353
|
+
var import_core = require("@nestjs/core");
|
|
354
|
+
var reflector = new import_typed_reflector.Reflector();
|
|
355
|
+
var Metadata = new import_typed_reflector.MetadataSetter();
|
|
356
|
+
var defaultHeaderName = "x-server-token";
|
|
357
|
+
var defaultConfigName = "SERVER_TOKEN";
|
|
358
|
+
var defaultErrorCode = 401;
|
|
266
359
|
var TokenGuard = class {
|
|
267
|
-
constructor(config) {
|
|
360
|
+
constructor(config, moduleRef) {
|
|
268
361
|
this.config = config;
|
|
269
|
-
this.
|
|
362
|
+
this.moduleRef = moduleRef;
|
|
270
363
|
}
|
|
271
364
|
async canActivate(context) {
|
|
272
|
-
const
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
365
|
+
const controller = context.getClass();
|
|
366
|
+
const handlerName = context.getHandler()?.name;
|
|
367
|
+
let config = {};
|
|
368
|
+
if (controller) {
|
|
369
|
+
if (handlerName) {
|
|
370
|
+
config = reflector.get("requireTokenOptions", controller, handlerName) || {};
|
|
371
|
+
} else {
|
|
372
|
+
config = reflector.get("requireTokenOptions", controller) || {};
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const resolver = createResolver(
|
|
376
|
+
config.resolver || { paramType: "header", paramName: defaultHeaderName }
|
|
377
|
+
);
|
|
378
|
+
const tokenSource = config.tokenSource || defaultConfigName;
|
|
379
|
+
const [tokenFromClient, tokenFromConfig] = await Promise.all([
|
|
380
|
+
resolver(context, this.moduleRef),
|
|
381
|
+
typeof tokenSource === "function" ? tokenSource(context, this.moduleRef) : this.config.get(tokenSource)
|
|
382
|
+
]);
|
|
383
|
+
if (tokenFromConfig && tokenFromConfig !== tokenFromClient) {
|
|
384
|
+
throw new BlankReturnMessageDto(
|
|
385
|
+
config.errorCode || defaultErrorCode,
|
|
386
|
+
"Unauthorized"
|
|
387
|
+
).toException();
|
|
276
388
|
}
|
|
277
389
|
return true;
|
|
278
390
|
}
|
|
279
391
|
};
|
|
280
392
|
TokenGuard = __decorateClass([
|
|
281
393
|
(0, import_common3.Injectable)(),
|
|
282
|
-
__decorateParam(0, (0, import_common3.Inject)(import_config.ConfigService))
|
|
394
|
+
__decorateParam(0, (0, import_common3.Inject)(import_config.ConfigService)),
|
|
395
|
+
__decorateParam(1, (0, import_common3.Inject)(import_core.ModuleRef))
|
|
283
396
|
], TokenGuard);
|
|
284
|
-
var RequireToken = () =>
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
397
|
+
var RequireToken = (options = {}) => {
|
|
398
|
+
const swaggerDec = options.resolver ? ApiFromResolver(options.resolver, {
|
|
399
|
+
description: "Server token",
|
|
400
|
+
required: false
|
|
401
|
+
}) : (0, import_swagger5.ApiHeader)({
|
|
402
|
+
name: defaultHeaderName,
|
|
288
403
|
description: "Server token",
|
|
289
404
|
required: false
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
|
|
405
|
+
});
|
|
406
|
+
return MergeClassOrMethodDecorators([
|
|
407
|
+
(0, import_common3.UseGuards)(TokenGuard),
|
|
408
|
+
swaggerDec,
|
|
409
|
+
ApiError(
|
|
410
|
+
options.errorCode || defaultErrorCode,
|
|
411
|
+
"Incorrect server token provided"
|
|
412
|
+
),
|
|
413
|
+
...options ? [Metadata.set("requireTokenOptions", options)] : []
|
|
414
|
+
]);
|
|
415
|
+
};
|
|
293
416
|
|
|
294
417
|
// src/abort-utils.ts
|
|
295
418
|
var import_rxjs = require("rxjs");
|
|
@@ -372,7 +495,7 @@ var import_nfkit = require("nfkit");
|
|
|
372
495
|
|
|
373
496
|
// src/abortable-module/abort-signal.provider.ts
|
|
374
497
|
var import_common5 = require("@nestjs/common");
|
|
375
|
-
var
|
|
498
|
+
var import_core2 = require("@nestjs/core");
|
|
376
499
|
|
|
377
500
|
// src/create-provider.ts
|
|
378
501
|
var createProvider = (options, factory) => {
|
|
@@ -390,14 +513,14 @@ var AbortSignalProvider = createProvider(
|
|
|
390
513
|
{
|
|
391
514
|
provide: ABORT_SIGNAL,
|
|
392
515
|
scope: import_common5.Scope.REQUEST,
|
|
393
|
-
inject: [
|
|
516
|
+
inject: [import_core2.REQUEST]
|
|
394
517
|
},
|
|
395
518
|
createAbortSignalFromHttp
|
|
396
519
|
);
|
|
397
520
|
var InjectAbortSignal = () => (0, import_common5.Inject)(ABORT_SIGNAL);
|
|
398
521
|
|
|
399
522
|
// src/abortable-module/abortable.token.ts
|
|
400
|
-
var
|
|
523
|
+
var import_core3 = require("@nestjs/core");
|
|
401
524
|
var tokenMemo = /* @__PURE__ */ new Map();
|
|
402
525
|
var abortableToken = (token) => {
|
|
403
526
|
if (tokenMemo.has(token)) return tokenMemo.get(token);
|
|
@@ -427,10 +550,10 @@ function createAbortableProvider(token, opts) {
|
|
|
427
550
|
{
|
|
428
551
|
provide,
|
|
429
552
|
scope: import_common6.Scope.REQUEST,
|
|
430
|
-
inject: [
|
|
553
|
+
inject: [import_core3.ModuleRef, import_core3.REQUEST, ABORT_SIGNAL]
|
|
431
554
|
},
|
|
432
555
|
async (moduleRef, req, signal) => {
|
|
433
|
-
const ctxId =
|
|
556
|
+
const ctxId = import_core3.ContextIdFactory.getByRequest(req);
|
|
434
557
|
const svc = await moduleRef.resolve(token, ctxId, { strict: false });
|
|
435
558
|
if (svc == null) {
|
|
436
559
|
throw new Error(
|
|
@@ -515,12 +638,12 @@ var parseI18n = (text) => {
|
|
|
515
638
|
};
|
|
516
639
|
|
|
517
640
|
// src/i18n-module/i18n.service.ts
|
|
518
|
-
var
|
|
641
|
+
var import_core4 = require("@nestjs/core");
|
|
519
642
|
var I18nService = class {
|
|
520
|
-
constructor(
|
|
521
|
-
this.resolver = resolver;
|
|
643
|
+
constructor(options, moduleRef) {
|
|
522
644
|
this.options = options;
|
|
523
645
|
this.moduleRef = moduleRef;
|
|
646
|
+
this.resolver = createResolver(this.options.resolver);
|
|
524
647
|
this.locales = new Set(this.options.locales);
|
|
525
648
|
this.defaultLocale = this.options.defaultLocale ?? this.options.locales[0];
|
|
526
649
|
this.middlewares = [];
|
|
@@ -727,81 +850,13 @@ var I18nService = class {
|
|
|
727
850
|
};
|
|
728
851
|
I18nService = __decorateClass([
|
|
729
852
|
(0, import_common9.Injectable)(),
|
|
730
|
-
__decorateParam(0, (0, import_common9.Inject)(
|
|
731
|
-
__decorateParam(1, (0, import_common9.Inject)(
|
|
732
|
-
__decorateParam(2, (0, import_common9.Inject)(import_core3.ModuleRef))
|
|
853
|
+
__decorateParam(0, (0, import_common9.Inject)(I18nModuleOptionsToken)),
|
|
854
|
+
__decorateParam(1, (0, import_common9.Inject)(import_core4.ModuleRef))
|
|
733
855
|
], I18nService);
|
|
734
856
|
|
|
735
857
|
// src/i18n-module/i18n.module.ts
|
|
736
858
|
var import_common11 = require("@nestjs/common");
|
|
737
859
|
|
|
738
|
-
// src/i18n-module/i18n-resolver.ts
|
|
739
|
-
var coerceToString = (v) => {
|
|
740
|
-
if (v == null) return void 0;
|
|
741
|
-
if (v === false) return void 0;
|
|
742
|
-
if (Array.isArray(v)) return v.length ? coerceToString(v[0]) : void 0;
|
|
743
|
-
if (typeof v === "string") return v;
|
|
744
|
-
if (typeof v === "number") return String(v);
|
|
745
|
-
return void 0;
|
|
746
|
-
};
|
|
747
|
-
var getHeader = (req, name) => {
|
|
748
|
-
const viaMethod = typeof req.getHeader === "function" && req.getHeader(name) || typeof req.header === "function" && req.header(name) || typeof req.get === "function" && req.get(name);
|
|
749
|
-
if (viaMethod) {
|
|
750
|
-
return coerceToString(viaMethod);
|
|
751
|
-
}
|
|
752
|
-
const n = name.toLowerCase();
|
|
753
|
-
const headers = req.headers ?? {};
|
|
754
|
-
if (n in headers) return coerceToString(headers[n]);
|
|
755
|
-
const hit = Object.entries(headers).find(([k]) => k.toLowerCase() === n)?.[1];
|
|
756
|
-
return coerceToString(hit);
|
|
757
|
-
};
|
|
758
|
-
var pickPrimaryFromAcceptLanguage = (v) => {
|
|
759
|
-
if (!v) return void 0;
|
|
760
|
-
const first = v.split(",")[0]?.trim();
|
|
761
|
-
return first?.split(";")[0]?.trim() || first;
|
|
762
|
-
};
|
|
763
|
-
function getQueryValue(req, key) {
|
|
764
|
-
const q = req.query;
|
|
765
|
-
if (q && typeof q === "object" && !("raw" in q)) {
|
|
766
|
-
const v = q[key];
|
|
767
|
-
if (v != null) return coerceToString(v);
|
|
768
|
-
}
|
|
769
|
-
const rawUrl = req.originalUrl ?? req.url;
|
|
770
|
-
if (typeof rawUrl === "string" && rawUrl.includes("?")) {
|
|
771
|
-
try {
|
|
772
|
-
const search = rawUrl.startsWith("http") ? new URL(rawUrl).search : new URL(rawUrl, "http://localhost").search;
|
|
773
|
-
if (search) {
|
|
774
|
-
const params = new URLSearchParams(search);
|
|
775
|
-
const val = params.get(key);
|
|
776
|
-
if (val != null) return val;
|
|
777
|
-
}
|
|
778
|
-
} catch {
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
return void 0;
|
|
782
|
-
}
|
|
783
|
-
var createDynamicResolverFromStatic = (_options) => {
|
|
784
|
-
if (typeof _options === "function") {
|
|
785
|
-
return _options;
|
|
786
|
-
}
|
|
787
|
-
const options = _options;
|
|
788
|
-
const field = options.paramType;
|
|
789
|
-
let name = options.paramName;
|
|
790
|
-
if (field === "header") name = name.toLowerCase();
|
|
791
|
-
return (ctx) => {
|
|
792
|
-
const req = ctx.switchToHttp().getRequest();
|
|
793
|
-
if (field === "header") {
|
|
794
|
-
let raw = getHeader(req, name);
|
|
795
|
-
if (name === "accept-language") raw = pickPrimaryFromAcceptLanguage(raw);
|
|
796
|
-
return raw;
|
|
797
|
-
}
|
|
798
|
-
if (field === "query") {
|
|
799
|
-
return getQueryValue(req, name);
|
|
800
|
-
}
|
|
801
|
-
throw new Error(`Unsupported paramType: ${field}`);
|
|
802
|
-
};
|
|
803
|
-
};
|
|
804
|
-
|
|
805
860
|
// src/i18n-module/locale.pipe.ts
|
|
806
861
|
var import_common10 = require("@nestjs/common");
|
|
807
862
|
var LocalePipe = class {
|
|
@@ -811,7 +866,7 @@ var LocalePipe = class {
|
|
|
811
866
|
async transform(ctx, metadata) {
|
|
812
867
|
const resolver = ctx.resolver;
|
|
813
868
|
if (resolver) {
|
|
814
|
-
const _resolver =
|
|
869
|
+
const _resolver = createResolver(resolver);
|
|
815
870
|
const locale = await _resolver(ctx.ctx, void 0);
|
|
816
871
|
return this.i18nService.getExactLocale(locale);
|
|
817
872
|
} else {
|
|
@@ -834,17 +889,7 @@ var I18nModule = class extends ConfigurableModuleClass {
|
|
|
834
889
|
I18nModule = __decorateClass([
|
|
835
890
|
(0, import_common11.Global)(),
|
|
836
891
|
(0, import_common11.Module)({
|
|
837
|
-
providers: [
|
|
838
|
-
createProvider(
|
|
839
|
-
{
|
|
840
|
-
provide: I18nResolverToken,
|
|
841
|
-
inject: [I18nModuleOptionsToken]
|
|
842
|
-
},
|
|
843
|
-
(o) => createDynamicResolverFromStatic(o.resolver)
|
|
844
|
-
),
|
|
845
|
-
I18nService,
|
|
846
|
-
LocalePipe
|
|
847
|
-
],
|
|
892
|
+
providers: [I18nService, LocalePipe],
|
|
848
893
|
exports: [I18nService, LocalePipe]
|
|
849
894
|
})
|
|
850
895
|
], I18nModule);
|
|
@@ -888,21 +933,15 @@ I18nInterceptor = __decorateClass([
|
|
|
888
933
|
], I18nInterceptor);
|
|
889
934
|
|
|
890
935
|
// src/i18n-module/i18n-decorator.ts
|
|
891
|
-
var import_swagger5 = require("@nestjs/swagger");
|
|
892
936
|
var createI18nDecorator = (options) => {
|
|
893
|
-
const paramType = options.resolver?.paramType;
|
|
894
|
-
const apiOptions = {
|
|
895
|
-
name: options.resolver.paramName,
|
|
896
|
-
description: "Locale for internationalization",
|
|
897
|
-
required: false,
|
|
898
|
-
default: options.defaultLocale ?? options.locales[0],
|
|
899
|
-
enum: options.locales
|
|
900
|
-
};
|
|
901
|
-
const dec = paramType === "header" ? () => (0, import_swagger5.ApiHeader)(apiOptions) : paramType === "query" ? () => (0, import_swagger5.ApiQuery)({ ...apiOptions, type: "string" }) : () => () => {
|
|
902
|
-
};
|
|
903
937
|
return () => MergeClassOrMethodDecorators([
|
|
904
938
|
(0, import_common13.UseInterceptors)(I18nInterceptor),
|
|
905
|
-
|
|
939
|
+
ApiFromResolver(options.resolver, {
|
|
940
|
+
description: "Locale for internationalization",
|
|
941
|
+
required: false,
|
|
942
|
+
default: options.defaultLocale ?? options.locales[0],
|
|
943
|
+
enum: options.locales
|
|
944
|
+
})
|
|
906
945
|
]);
|
|
907
946
|
};
|
|
908
947
|
|
|
@@ -920,7 +959,7 @@ var createI18n = (options) => {
|
|
|
920
959
|
};
|
|
921
960
|
};
|
|
922
961
|
|
|
923
|
-
// src/i18n-module/
|
|
962
|
+
// src/i18n-module/middlewares/lookup.ts
|
|
924
963
|
var I18nLookupMiddleware = (dict, options) => {
|
|
925
964
|
const matchType = options?.matchType ?? "exact";
|
|
926
965
|
const dictFactory = typeof dict === "function" ? dict : () => dict;
|
|
@@ -958,7 +997,9 @@ var I18nLookupMiddleware = (dict, options) => {
|
|
|
958
997
|
}
|
|
959
998
|
if (dictionary && Object.prototype.hasOwnProperty.call(dictionary, key)) {
|
|
960
999
|
const val = dictionary[key];
|
|
961
|
-
if (val != null)
|
|
1000
|
+
if (val != null) {
|
|
1001
|
+
return val;
|
|
1002
|
+
}
|
|
962
1003
|
}
|
|
963
1004
|
return next();
|
|
964
1005
|
};
|
|
@@ -971,6 +1012,7 @@ var I18nLookupMiddleware = (dict, options) => {
|
|
|
971
1012
|
ApiBlankResponse,
|
|
972
1013
|
ApiError,
|
|
973
1014
|
ApiErrorTyped,
|
|
1015
|
+
ApiFromResolver,
|
|
974
1016
|
ApiTypeResponse,
|
|
975
1017
|
As,
|
|
976
1018
|
BlankPaginatedReturnMessageDto,
|
|
@@ -1004,6 +1046,7 @@ var I18nLookupMiddleware = (dict, options) => {
|
|
|
1004
1046
|
createI18n,
|
|
1005
1047
|
createI18nDecorator,
|
|
1006
1048
|
createProvider,
|
|
1049
|
+
createResolver,
|
|
1007
1050
|
fromAbortable,
|
|
1008
1051
|
getClassFromClassOrArray,
|
|
1009
1052
|
takeUntilAbort
|