@nexica/nestjs-trpc
Version:
NestJS TRPC Bridge
241 lines • 13 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TRPCFactory = void 0;
const common_1 = require("@nestjs/common");
const nestjs_discovery_1 = require("@golevelup/nestjs-discovery");
const constants_1 = require("../constants");
const error_handler_1 = require("../utils/error-handler");
let TRPCFactory = class TRPCFactory {
constructor() {
Object.defineProperty(this, "discovery", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
}
createAppRouter() {
return __awaiter(this, arguments, void 0, function* (options = {}, routerFactory, procedureBuilder) {
var _a;
if (!this.discovery) {
error_handler_1.ErrorHandler.logWarning('TRPCFactory', 'DiscoveryService is not available - unable to discover routers automatically. Returning empty router.');
return routerFactory({});
}
try {
const routerProviders = yield this.discovery.providersWithMetaAtKey(constants_1.TRPC_ROUTER_METADATA);
if (!routerProviders.length) {
error_handler_1.ErrorHandler.logWarning('TRPCFactory', 'No router providers found, returning empty router');
return routerFactory({});
}
const routers = {};
for (const provider of routerProviders) {
try {
const discoveredClass = provider.discoveredClass;
const instance = discoveredClass === null || discoveredClass === void 0 ? void 0 : discoveredClass.instance;
const metatype = discoveredClass === null || discoveredClass === void 0 ? void 0 : discoveredClass.injectType;
const metadata = provider.meta;
if (!instance || !metatype) {
error_handler_1.ErrorHandler.logWarning('TRPCFactory', 'Skipping router - missing instance or metatype');
continue;
}
const typedInstance = instance;
const routerMiddlewareMetadata = Reflect.getMetadata(constants_1.TRPC_ROUTER_MIDDLEWARE_METADATA, metatype);
let routerProcedureBuilder = procedureBuilder;
if ((_a = routerMiddlewareMetadata === null || routerMiddlewareMetadata === void 0 ? void 0 : routerMiddlewareMetadata.middlewares) === null || _a === void 0 ? void 0 : _a.length) {
for (const middleware of routerMiddlewareMetadata.middlewares) {
if (typeof middleware === 'string') {
const middlewareMethod = typedInstance[middleware];
if (typeof middlewareMethod === 'function') {
const middlewareFn = middlewareMethod;
routerProcedureBuilder = routerProcedureBuilder.use((opts) => __awaiter(this, void 0, void 0, function* () {
yield middlewareFn.call(typedInstance, opts);
return opts.next();
}));
}
}
else if (typeof middleware === 'function') {
routerProcedureBuilder = routerProcedureBuilder.use(middleware);
}
}
}
const procedures = {};
const methods = this.getMethodsWithProcedureMetadata(metatype, instance);
for (const methodName of methods) {
const procedureResult = this.createProcedureFromMethod(metatype, methodName, typedInstance, routerProcedureBuilder);
if (procedureResult) {
procedures[procedureResult.path] = procedureResult.procedure;
}
}
if (Object.keys(procedures).length > 0) {
const routerName = (metadata === null || metadata === void 0 ? void 0 : metadata.path) || (typeof metatype === 'function' ? metatype.name : 'UnnamedRouter');
routers[routerName] = routerFactory(procedures);
}
}
catch (error) {
error_handler_1.ErrorHandler.logError('TRPCFactory', 'Error processing router', error);
}
}
return routerFactory(routers);
}
catch (error) {
error_handler_1.ErrorHandler.logError('TRPCFactory', 'Error creating app router', error);
return routerFactory({});
}
});
}
getMethodsWithProcedureMetadata(target, instance) {
const methods = [];
const prototype = Object.getPrototypeOf(instance);
const methodNames = Object.getOwnPropertyNames(prototype).filter((prop) => prop !== 'constructor' && typeof prototype[prop] === 'function');
for (const method of methodNames) {
const metadata = Reflect.getMetadata(constants_1.TRPC_PROCEDURE_METADATA, target, method);
if (metadata) {
methods.push(method);
}
}
return methods;
}
createProcedureFromMethod(target, methodName, instance, procedureBuilder) {
const procedureMetadata = this.getProcedureMetadata(target, methodName);
if (!procedureMetadata) {
return null;
}
const procedure = this.applyMiddleware(target, methodName, instance, procedureBuilder);
const configuredProcedure = this.configureInputOutput(procedure, procedureMetadata);
const handler = this.createProcedureHandler(target, methodName, instance);
const finalProcedure = this.createFinalProcedure(configuredProcedure, handler, procedureMetadata);
return {
procedure: finalProcedure,
path: methodName,
};
}
getProcedureMetadata(target, methodName) {
return Reflect.getMetadata(constants_1.TRPC_PROCEDURE_METADATA, target, methodName) || null;
}
applyMiddleware(target, methodName, instance, procedureBuilder) {
var _a;
const middlewareMetadata = Reflect.getMetadata(constants_1.TRPC_MIDDLEWARE_METADATA, target, methodName);
let procedure = procedureBuilder;
if ((_a = middlewareMetadata === null || middlewareMetadata === void 0 ? void 0 : middlewareMetadata.middlewares) === null || _a === void 0 ? void 0 : _a.length) {
for (const middleware of middlewareMetadata.middlewares) {
if (typeof middleware === 'string') {
const middlewareMethod = instance[middleware];
if (typeof middlewareMethod === 'function') {
const middlewareFn = middlewareMethod;
procedure = procedure.use((opts) => __awaiter(this, void 0, void 0, function* () {
yield middlewareFn.call(instance, opts);
return opts.next();
}));
}
}
else if (typeof middleware === 'function') {
procedure = procedure.use(middleware);
}
}
}
return procedure;
}
configureInputOutput(procedure, procedureMetadata) {
let configuredProcedure = procedure;
if (procedureMetadata.input) {
if (procedureMetadata.inputName) {
const inputWithName = procedureMetadata.input.describe(procedureMetadata.inputName);
configuredProcedure = configuredProcedure.input(inputWithName);
}
else {
configuredProcedure = configuredProcedure.input(procedureMetadata.input);
}
}
if (procedureMetadata.output && procedureMetadata.type !== 'subscription') {
if (procedureMetadata.outputName) {
const outputWithName = procedureMetadata.output.describe(procedureMetadata.outputName);
configuredProcedure = configuredProcedure.output(outputWithName);
}
else {
configuredProcedure = configuredProcedure.output(procedureMetadata.output);
}
}
return configuredProcedure;
}
createProcedureHandler(target, methodName, instance) {
const parameterMetadata = this.getParameterMetadata(target, methodName);
return (opts) => __awaiter(this, void 0, void 0, function* () {
const { input, ctx } = opts;
const args = this.buildMethodArguments(input, ctx, parameterMetadata);
const method = instance[methodName];
return yield method.apply(instance, args);
});
}
getParameterMetadata(target, methodName) {
const inputParamIndexes = Reflect.getMetadata(constants_1.TRPC_INPUT_PARAM_METADATA, target, methodName) || [];
const contextParamIndexes = Reflect.getMetadata(constants_1.TRPC_CONTEXT_PARAM_METADATA, target, methodName) || [];
return { inputParamIndexes, contextParamIndexes };
}
buildMethodArguments(input, ctx, parameterMetadata) {
const { inputParamIndexes, contextParamIndexes } = parameterMetadata;
const inputData = input || {};
const contextData = ctx || input;
if (inputParamIndexes.length === 0 && contextParamIndexes.length === 0) {
return [inputData];
}
const methodArgs = [];
for (const paramIndex of inputParamIndexes) {
methodArgs[paramIndex] = inputData;
}
for (const paramIndex of contextParamIndexes) {
methodArgs[paramIndex] = contextData;
}
return methodArgs;
}
createFinalProcedure(procedure, handler, procedureMetadata) {
const { type } = procedureMetadata;
let finalProcedure;
switch (type) {
case 'query':
finalProcedure = procedure.query(handler);
break;
case 'mutation':
finalProcedure = procedure.mutation(handler);
break;
case 'subscription':
finalProcedure = procedure.subscription(handler);
break;
default:
throw error_handler_1.ErrorHandler.createError('TRPCFactory', `Unknown procedure type: ${String(type)}`);
}
if (procedureMetadata.output || procedureMetadata.outputName) {
;
finalProcedure._def.output = procedureMetadata.output;
finalProcedure._def.outputName = procedureMetadata.outputName;
}
return finalProcedure;
}
};
exports.TRPCFactory = TRPCFactory;
__decorate([
(0, common_1.Inject)(nestjs_discovery_1.DiscoveryService),
(0, common_1.Optional)(),
__metadata("design:type", nestjs_discovery_1.DiscoveryService)
], TRPCFactory.prototype, "discovery", void 0);
exports.TRPCFactory = TRPCFactory = __decorate([
(0, common_1.Injectable)()
], TRPCFactory);
//# sourceMappingURL=trpc.factory.js.map