UNPKG

nestjs-cls

Version:

A continuation-local storage module compatible with NestJS's dependency injection.

136 lines 6.53 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProxyProvidersResolver = void 0; const unknown_dependencies_exception_1 = require("@nestjs/core/errors/exceptions/unknown-dependencies.exception"); const proxy_provider_functions_1 = require("./proxy-provider.functions"); const proxy_provider_exceptions_1 = require("./proxy-provider.exceptions"); const proxy_provider_constants_1 = require("./proxy-provider.constants"); const get_proxy_provider_symbol_1 = require("./get-proxy-provider-symbol"); const promise_with_resolvers_polyfill_1 = require("../../utils/promise-with-resolvers.polyfill"); const CLS_PROXY_PROVIDER_PROMISES_MAP = Symbol('CLS_PROVIDER_PROMISES_MAP'); class ProxyProvidersResolver { constructor(cls, proxyProviderMap) { this.cls = cls; this.proxyProviderMap = proxyProviderMap; this.proxyProviderDependenciesMap = new Map(); this.proxyProviderMap.forEach((provider) => { // find each Proxy Providers' dependencies that are also Proxy Providers // and store those in a separate map this.proxyProviderDependenciesMap.set(provider.symbol, provider.dependencies .map(get_proxy_provider_symbol_1.getProxyProviderSymbol) .filter((symbol) => !proxy_provider_constants_1.defaultProxyProviderTokens.has(symbol)) .filter((symbol) => proxyProviderMap.has(symbol))); }); } /** * Resolves all Proxy Providers that have been registered, * or only the ones that are passed as an argument and their dependencies. */ async resolve(providerSymbols) { const providerSymbolsToResolve = providerSymbols?.length ? providerSymbols : Array.from(this.proxyProviderMap.keys()); const resolutionPromisesMap = this.getOrCreateCurrentProxyPromisesMap(); const allNeededProviderSymbols = this.getAllNeededProviderSymbols(providerSymbolsToResolve); const promiseWithResolversMap = new Map(); for (const dep of allNeededProviderSymbols) { const isBeingResolved = resolutionPromisesMap.has(dep); if (!isBeingResolved) { const promiseWithResolvers = (0, promise_with_resolvers_polyfill_1.Promise_withResolvers)(); promiseWithResolversMap.set(dep, promiseWithResolvers); resolutionPromisesMap.set(dep, promiseWithResolvers.promise); } } for (const [dep, promiseWithResolvers] of promiseWithResolversMap) { void this.resolveProxyProvider(dep, promiseWithResolvers, resolutionPromisesMap); } const timeout = 10_000; const timeoutPromise = (0, promise_with_resolvers_polyfill_1.Promise_withResolvers)(); const timeoutHandle = setTimeout(() => { timeoutPromise.reject(proxy_provider_exceptions_1.ProxyProvidersResolutionTimeoutException.create(timeout)); }, timeout); try { await Promise.race([ timeoutPromise.promise, Promise.all(resolutionPromisesMap.values()), ]); } finally { clearTimeout(timeoutHandle); } } /** * ProxyProviderResolutionPromisesMap is a map scoped to the * current CLS context that holds reference to the Promises of * all Proxy Providers (those that have been resolved and those * that are being resolved) * * It is used to prevent multiple concurrent resolutions of the same * Proxy Provider and also to ensure that all Proxy Providers are * resolved in the correct order (dependencies first) */ getOrCreateCurrentProxyPromisesMap() { const resolutionPromisesMap = this.cls.get(CLS_PROXY_PROVIDER_PROMISES_MAP) ?? new Map(); this.cls.setIfUndefined(CLS_PROXY_PROVIDER_PROMISES_MAP, resolutionPromisesMap); return resolutionPromisesMap; } /** * Gets a set of all Proxy Provider symbols that need to be resolved * and symbols of their dependencies (that have not been resolved yet) */ getAllNeededProviderSymbols(providerSymbols) { return new Set(providerSymbols .filter((providerSymbol) => !this.cls.get(providerSymbol)) .map((providerSymbol) => { const deps = this.proxyProviderDependenciesMap.get(providerSymbol) ?? []; return [providerSymbol, ...deps]; }) .flat()); } async resolveProxyProvider(providerSymbol, ownPromise, dependencyPromises) { try { const providerDefinition = this.proxyProviderMap.get(providerSymbol); if (!providerDefinition) { throw proxy_provider_exceptions_1.ProxyProviderNotRegisteredException.create(providerSymbol); } const ownDependencySymbols = this.proxyProviderDependenciesMap.get(providerSymbol) ?? []; const ownDependencyPromises = ownDependencySymbols.map((dep) => dependencyPromises.get(dep)); await Promise.all(ownDependencyPromises); const providerInstance = await this.resolveProxyProviderInstance(providerDefinition); this.cls.set(providerSymbol, providerInstance); return ownPromise.resolve(); } catch (e) { return ownPromise.reject(e); } } resolveProxyProviderInstance(provider) { let resolution; if ((0, proxy_provider_functions_1.isProxyClassProvider)(provider)) { resolution = this.resolveProxyClassProviderInstance(provider); } else { resolution = this.resolveProxyFactoryProviderInstance(provider); } return resolution; } async resolveProxyClassProviderInstance(provider) { const moduleRef = provider.moduleRef; const Provider = provider.useClass; try { return await moduleRef.create(Provider); } catch (error) { if (!(error instanceof unknown_dependencies_exception_1.UnknownDependenciesException)) throw error; throw proxy_provider_exceptions_1.UnknownProxyDependenciesException.create(error, Provider); } } async resolveProxyFactoryProviderInstance(provider) { const injected = provider.injected; return await provider.useFactory.apply(null, injected); } } exports.ProxyProvidersResolver = ProxyProvidersResolver; //# sourceMappingURL=proxy-provider-resolver.js.map