Kord/packages/grpc-contracts/src/index.js

93 lines
2.8 KiB
JavaScript

const path = require('path');
const protoLoader = require('@grpc/proto-loader');
const grpc = require('@grpc/grpc-js');
const fs = require('fs');
/**
* gRPC proto 로딩 결과를 캐싱하기 위한 변수
*/
let _cache = null;
const findProtoPath = () => {
const attemptedPaths = [];
// 1. Try explicit environment variable
if (process.env.KORD_PROTO_PATH) {
if (fs.existsSync(process.env.KORD_PROTO_PATH)) return process.env.KORD_PROTO_PATH;
attemptedPaths.push(`Env: ${process.env.KORD_PROTO_PATH}`);
}
// 2. Try standard __dirname (most reliable for direct node/tsx runs)
const dirnamePath = path.resolve(__dirname, 'kord.proto');
if (fs.existsSync(dirnamePath)) return dirnamePath;
attemptedPaths.push(`Dirname: ${dirnamePath}`);
// 3. Try monorepo root via process.cwd()
const rootPath = path.resolve(process.cwd(), 'packages/grpc-contracts/src/kord.proto');
if (fs.existsSync(rootPath)) return rootPath;
attemptedPaths.push(`CWD Root: ${rootPath}`);
// 4. Try relative from apps/ (Next.js context)
const relativePath = path.resolve(process.cwd(), '../../packages/grpc-contracts/src/kord.proto');
if (fs.existsSync(relativePath)) return relativePath;
attemptedPaths.push(`Relative: ${relativePath}`);
// 5. Try shared node_modules depth (monorepo artifacts)
const nmPath = path.resolve(process.cwd(), 'node_modules/@kord/grpc-contracts/src/kord.proto');
if (fs.existsSync(nmPath)) return nmPath;
attemptedPaths.push(`NodeModules: ${nmPath}`);
return { error: true, attemptedPaths };
};
const initialize = () => {
if (_cache) return _cache;
// browser환경이나 분석 단계에서 fs가 없을 경우를 대비하여 체크 (Turbopack 대응)
if (!fs || !fs.existsSync) {
return { kordProto: null, protoPath: null };
}
const result = findProtoPath();
if (result.error) {
// 런타임에 에러가 발생하도록 경고를 출력하되, 빌드/분석 단계에서는 치명적 에러가 되지 않도록 함
console.warn('⚠️ [grpc-contracts] Failed to locate kord.proto during initialization.');
return { kordProto: null, protoPath: null };
}
const PROTO_PATH = result;
let packageDefinition;
try {
packageDefinition = protoLoader.loadSync(PROTO_PATH, {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true,
});
} catch (error) {
console.error(`Failed to load gRPC proto from: ${PROTO_PATH}`);
throw error;
}
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
_cache = {
kordProto: protoDescriptor.kord,
protoPath: PROTO_PATH
};
return _cache;
};
module.exports = {
// getter를 사용하여 실제 접근 시점에 로딩되도록 함 (Lazy Initialization)
get kordProto() {
return initialize().kordProto;
},
get protoPath() {
return initialize().protoPath;
}
};