@xfilecom/core-sdk
v1.4.5
Published
Core SDK for NestJS microservices - 통합 개발 키트
Readme
@xfilecom/core-sdk
NestJS 마이크로서비스용 Core SDK — DB, 인증, 로깅, 공통 응답, 설정 로드, 해시 검증 등을 하나의 패키지로 제공합니다.
목차
- 설치
- 설정 파일 위치 (표준)
- 설정 소스 (.env vs YAML)
- 사용 범위 요약
- CoreModule
- 설정 파일 (application.yml)
- 설정 루트·Config 로더
- Crypto (비밀번호·조회용 해시)
- Hash verification
- 기능 옵션
- Database
- Controller / Service 예시
- Guards · Decorators · Interceptors · Filters
- 기타 유틸
- Database 연결 실패 시
- 수정 사항
- 라이선스
설치
npm install @xfilecom/core-sdk설정 파일 위치 (표준)
다른 서비스/팀과 동일한 방식으로 사용하려면 설정 파일 위치를 아래 규칙으로 통일합니다.
| 항목 | 규칙 |
|------|------|
| 파일 경로 | {프로젝트 루트}/application.yml 또는 application.yaml |
| 프로젝트 루트 | 기본값 process.cwd(). 필요 시 loadApplicationYaml({ rootDir }) 로 지정 |
| 파일명 우선순위 | application.yml → application.yaml (먼저 찾은 것 사용) |
| 환경별 병합 | 같은 루트에 application-{env}.yml (예: application-development.yml) 있으면 base 위에 deep merge |
코드에서 루트만 맞추면 항상 같은 위치에서 설정을 읽습니다.
import { loadApplicationYaml, DEFAULT_CONFIG_FILENAMES } from '@xfilecom/core-sdk';
// 기본: process.cwd() 에서 application.yml / application.yaml 탐색
const config = await loadApplicationYaml();
// 루트 지정 (예: 패키지 루트)
const config = await loadApplicationYaml({ rootDir: path.join(__dirname, '..') });
// 환경별 설정 병합
const config = await loadApplicationYaml({ env: process.env.NODE_ENV });- 파일이 없으면 예외 없이 빈 객체
{}반환. - 상수:
DEFAULT_CONFIG_FILENAMES,ENV_CONFIG_FILENAME_PATTERN(index에서 export).
설정 소스 (.env vs YAML)
YAML을 쓸지, 환경 변수(.env)만 쓸지, 또는 둘 다 쓸지를 설정할 수 있습니다.
옵션 (configSource)
| 값 | 동작 |
|----|------|
| yaml | application.yml만 읽음 (기본값) |
| env | YAML을 읽지 않고, process.env(DB_, JWT_, HASH_* 등)로 config 객체 생성 |
| yamlWithEnvOverrides | YAML 로드 후, 같은 키가 환경 변수에 있으면 그 값으로 덮어씀 |
어디에 설정하나요?
1) 코드에서 지정 (권장)
loadApplicationYaml() 호출 시 옵션으로 넘깁니다.
import { loadApplicationYaml, type ConfigSource } from '@xfilecom/core-sdk';
// YAML만 사용 (기본)
const config = await loadApplicationYaml();
// .env(환경 변수)만 사용 — application.yml 없이 DB_*, JWT_* 등으로 config 구성
const config = await loadApplicationYaml({ configSource: 'env' });
// YAML 먼저 로드하고, 환경 변수로 덮어쓰기
const config = await loadApplicationYaml({ configSource: 'yamlWithEnvOverrides', env: process.env.NODE_ENV });2) 환경 변수로 지정
코드는 그대로 두고, 실행 환경 또는 .env 파일에 다음 키로 소스를 정합니다.
| 설정 위치 | 예시 |
|-----------|------|
| .env 파일 | CONFIG_SOURCE=env 또는 CONFIG_SOURCE=yamlWithEnvOverrides |
| 쉘/실행 시 | CONFIG_SOURCE=env node dist/main.js |
CONFIG_SOURCE가 없으면 기본값yaml로 동작합니다.- 상수 이름:
CONFIG_SOURCE_ENV_KEY('CONFIG_SOURCE') — index에서 export.
# .env
CONFIG_SOURCE=env
DB_HOST=localhost
JWT_SECRET=my-secret이렇게 하면 loadApplicationYaml() 호출 시 옵션에 configSource를 안 넘겨도, process.env.CONFIG_SOURCE를 읽어서 동일하게 동작합니다. (앱에서 dotenv 등으로 .env를 먼저 로드해야 함)
configSource: 'env' 일 때 매핑
환경 변수만 쓸 때 아래 키들이 config 객체로 매핑됩니다.
- database:
DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAME(또는DB_DATABASE),DB_SSL,DB_CONNECTION_LIMIT - jwt:
JWT_SECRET,JWT_EXPIRES_IN - hashVerification.default:
HASH_VERIFICATION_SECRET - hashVerification.profiles.email:
EMAIL_HASH_SECRET(없으면HASH_VERIFICATION_SECRET)
사용 범위 요약
| 구분 | 내용 |
|------|------|
| 모듈 | CoreModule.forRoot(), forMicroservice(), forHttpApi(), forHybrid() |
| 설정 | loadApplicationYaml() / loadApplicationYamlSync() — 표준 경로 application.yml 또는 configSource: 'env' 로 환경 변수만 사용 |
| 설정 루트·로더 | resolveConfigRootDir() (모노레포 등 설정 디렉터리 탐색), createConfigLoader() (한 번 로드 + 캐시 + getFullConfig / getServiceConfig) |
| Crypto | pbkdf2HashPassword / pbkdf2VerifyPassword (saltHex:hashHex), lookupHash / compareLookupHash (키 파생 옵션), deriveKeySha256 |
| 해시/검증 | hashValue, compareValue, hashByKey, compareByKey, hashEmail, compareEmail, lookupHash, compareLookupHash (YAML hashVerification + keyDerivation 연동) |
| DB | Drizzle ORM + MySQL, DatabaseQuery, ServiceHelpers (getDb, withTransaction, createPaginationResult 등) |
| 컨트롤러 | ControllerHelpers (parsePagination, parseSort, parseFilters, success, error) |
| 인증 | JwtAuthGuard, RolesGuard, AuthHelpers, @Public(), @User(), @Roles() |
| 인터셉터 | Logging, ErrorHandling, ResponseTransform, DatabaseCheck |
| 필터 | AllExceptionsFilter |
| 기타 | ErrorUtils, LoggerHelpers, ConfigValidator, getLoggingConfigFromEnv |
CoreModule
마이크로서비스
import { Module } from '@nestjs/common';
import { CoreModule } from '@xfilecom/core-sdk';
@Module({
imports: [CoreModule.forMicroservice()],
})
export class AppModule {}HTTP API
import { Module } from '@nestjs/common';
import { CoreModule } from '@xfilecom/core-sdk';
import { schema } from './database/schema';
@Module({
imports: [
CoreModule.forHttpApi({
database: { schema },
}),
],
})
export class AppModule {}하이브리드 (HTTP + TCP)
import { Module } from '@nestjs/common';
import { CoreModule } from '@xfilecom/core-sdk';
@Module({
imports: [CoreModule.forHybrid()],
})
export class AppModule {}커스텀 설정 (forRoot)
import { Module } from '@nestjs/common';
import { CoreModule } from '@xfilecom/core-sdk';
import { mySchema } from './database/schema';
@Module({
imports: [
CoreModule.forRoot({
database: { schema: mySchema },
jwt: { secret: process.env.JWT_SECRET, expiresIn: '7d' },
response: { commonResponse: true },
interceptors: { logging: true, databaseCheck: true },
guards: { jwt: true },
filters: { exception: true },
}),
],
})
export class AppModule {}설정 파일 (application.yml)
- 위치: 설정 파일 위치 (표준) 참고.
- 소스 선택: 설정 소스 (.env vs YAML) 참고 —
configSource또는CONFIG_SOURCE로 YAML / .env 선택 가능. - 비동기:
loadApplicationYaml(options?) - 동기:
loadApplicationYamlSync(options?)(bootstrap 전 등) - syncEnvKeys: YAML 로드 후 config 일부를
process.env에 채울 수 있음. ConfigValidator / JwtAuthGuard 등이 env를 참조할 때 YAML만 써도 연동 가능.
import { loadApplicationYaml, loadApplicationYamlSync } from '@xfilecom/core-sdk';
const config = await loadApplicationYaml();
const dbHost = config?.database?.host ?? process.env.DB_HOST;
const configWithEnv = await loadApplicationYaml({ env: process.env.NODE_ENV });
const configSync = loadApplicationYamlSync({ rootDir: path.join(__dirname, '..') });
// YAML 로드 후 JWT 등을 process.env에 동기화 (Guard/ConfigValidator와 연동)
const config = await loadApplicationYaml({
env: process.env.NODE_ENV,
syncEnvKeys: {
JWT_SECRET: 'jwt.secret',
JWT_EXPIRES_IN: 'jwt.expiresIn',
HASH_VERIFICATION_SECRET: 'hashVerification.default.secret',
},
});설정 파일 안에는 DB, JWT, hashVerification 등 자유롭게 정의하고, 코드에서 config?.database, config?.hashVerification 등으로 접근하면 됩니다. JWT는 CoreModule.forHttpApi({ jwt: config?.jwt }) 로 넘기면 ConfigValidator.validateJwtConfig 시 env 검사를 건너뜁니다.
설정 루트·Config 로더
모노레포·실행 위치와 관계없이 설정 디렉터리를 찾고, 한 번 로드 → env 동기화 → 전역 캐시 → getFullConfig / getServiceConfig 패턴을 쓰려면 아래 API를 사용합니다.
resolveConfigRootDir(options?)
application.yml / application.yaml 이 있는 디렉터리를 후보 순서대로 탐색해 반환합니다. 기본 후보는 모노레포 패턴(libs/config/config, ../../libs/config/config, ../libs/config/config, cwd)입니다.
import { resolveConfigRootDir, loadApplicationYamlSync, DEFAULT_CONFIG_ROOT_CANDIDATES } from '@xfilecom/core-sdk';
// 기본 (process.cwd() 기준 후보 탐색)
const rootDir = resolveConfigRootDir();
// 후보·파일명 지정
const rootDir2 = resolveConfigRootDir({
cwd: process.cwd(),
candidates: ['libs/config/config', 'config', '.'],
configFilenames: ['application.yml', 'application.yaml'],
});
const config = loadApplicationYamlSync({ rootDir, env: process.env.NODE_ENV });createConfigLoader(options)
한 번 로드한 config를 캐시하고, getFullConfig() / getServiceConfig(serviceKey, overrides?) 를 반환합니다. auth-service, mail-service, chat-service 등에서 동일한 패턴으로 사용할 수 있습니다.
- getFullConfig(): 이미 로드된 full config 반환 (최초 호출 시 1회 로드 후 저장).
- getServiceConfig(serviceKey, overrides?):
full.common+full[serviceKey]병합.overrides.portEnvKey가 있으면process.env[portEnvKey]로server.port덮어씀.
import { createConfigLoader, resolveConfigRootDir } from '@xfilecom/core-sdk';
const { getFullConfig, getServiceConfig } = createConfigLoader({
rootDir: resolveConfigRootDir(),
env: process.env.APP_PROFILE ?? (process.env.NODE_ENV === 'production' ? 'prod' : 'dev'),
syncEnvKeys: {
JWT_SECRET: 'auth-service.jwt.secret',
JWT_EXPIRES_IN: 'auth-service.jwt.expiresIn',
},
globalKey: 'auth-service',
});
// 서비스별 config (common + auth-service 병합, 포트는 AUTH_SERVICE_PORT 로 덮어쓰기)
export const getAuthServiceConfig = () =>
getServiceConfig('auth-service', { portEnvKey: 'AUTH_SERVICE_PORT' });
export { getFullConfig };- rootDir 없으면
resolveConfigRootDir()로 자동 해석. - globalKey: 동일 키로 캐시해 두어 재호출 시 같은 객체 반환.
- YAML 구조 예:
common: { ... }, auth-service: { server: { port: 3001 }, jwt: { ... } }, mail-service: { ... }.
Crypto (비밀번호·조회용 해시)
PBKDF2 비밀번호 (usdt3·기존 DB 호환)
저장 형식 saltHex:hashHex, 기본 pbkdf2-sha512 100_000회·64바이트. bcrypt와 형식이 달라 기존 usdt3 DB와 호환하려면 아래 API 사용.
import {
pbkdf2HashPassword,
pbkdf2VerifyPassword,
PBKDF2_DEFAULT_ITERATIONS,
PBKDF2_DEFAULT_KEYLEN,
PBKDF2_DEFAULT_DIGEST,
type Pbkdf2Options,
} from '@xfilecom/core-sdk';
// 해시 (salt 미지정 시 랜덤 salt 자동 생성)
const stored = pbkdf2HashPassword('myPassword');
// 옵션 지정 시
const stored2 = pbkdf2HashPassword('myPassword', undefined, {
iterations: 100_000,
keylen: 64,
digest: 'sha512',
});
// 검증
const ok = pbkdf2VerifyPassword('myPassword', stored);
const ok2 = pbkdf2VerifyPassword('myPassword', stored2, { iterations: 100_000, keylen: 64, digest: 'sha512' });조회용 해시 (키 파생 — usdt3·기존 DB 호환)
기존 DB가 HMAC 키 = sha256(secret) 방식이면 keyDerivation: 'sha256' 사용. YAML 프로필 또는 lookupHash/compareLookupHash 로 동일한 해시 생성.
import { lookupHash, compareLookupHash, emailNormalizer, digitsNormalizer } from '@xfilecom/core-sdk';
// secret을 sha256(secret)으로 파생해 HMAC (usdt3 호환)
const emailHash = lookupHash('[email protected]', process.env.EMAIL_HASH_SECRET, {
keyDerivation: 'sha256',
normalizer: emailNormalizer,
});
const match = compareLookupHash('[email protected]', row.email_hash, process.env.EMAIL_HASH_SECRET, {
keyDerivation: 'sha256',
normalizer: emailNormalizer,
});YAML에서 프로필별로 지정할 때는 hashVerification.profiles.email 에 keyDerivation: sha256 추가 후 hashByKey('email', ...) 사용하면 동일한 결과.
Hash verification
이메일·전화번호·식별자 등 문자열을 YAML 설정 기반으로 HMAC 해시 후 저장/비교할 수 있습니다. 설정은 표준 위치의 application.yml 에 두면 됩니다.
YAML 구조 (application.yml 에 추가)
hashVerification:
default:
algorithm: sha256
secret: ${HASH_VERIFICATION_SECRET}
encoding: hex
keyDerivation: sha256 # usdt3 등 기존 DB 호환 시: HMAC 키 = sha256(secret)
profiles:
email:
secret: ${EMAIL_HASH_SECRET}
normalizer: email
keyDerivation: sha256
phone:
secret: ${PHONE_HASH_SECRET}
normalizer: digits
keyDerivation: sha256
userId:
secret: ${USER_ID_HASH_SECRET}
tenantId:
secret: ${TENANT_HASH_SECRET}- default: 해당 키가 없을 때 사용하는 공통 설정.
- profiles: 키별 설정. 새 키만 YAML에 추가하면 코드 수정 없이
hashByKey(key, value, hv)로 처리 가능. - normalizer:
email(trim+소문자),digits(숫자만). 생략 시 입력 그대로 해시. - keyDerivation:
none(기본)=secret 그대로 HMAC 키로 사용.sha256=sha256(secret)을 HMAC 키로 사용(usdt3·기존 DB 호환).
동적 키로 해시/비교 (권장)
import { loadApplicationYaml, hashByKey, compareByKey } from '@xfilecom/core-sdk';
const config = await loadApplicationYaml({ env: process.env.NODE_ENV });
const hv = config?.hashVerification;
const emailHash = hashByKey('email', '[email protected]', hv);
const phoneHash = hashByKey('phone', '010-1234-5678', hv);
const userIdHash = hashByKey('userId', uid, hv);
const match = compareByKey('email', plainEmail, row.email_hash, hv);공통 API (config 직접 전달)
import { hashValue, compareValue } from '@xfilecom/core-sdk';
const hv = config?.hashVerification;
const emailHash = hashValue('[email protected]', hv?.profiles?.email ?? hv?.email);
const match = compareValue('[email protected]', row.email_hash, hv?.profiles?.email ?? hv?.email);이메일 전용
import { hashEmail, compareEmail } from '@xfilecom/core-sdk';
const emailHash = hashEmail('[email protected]', config?.hashVerification?.profiles?.email);
const match = compareEmail('[email protected]', row.email_hash, config?.hashVerification?.profiles?.email);- secret 없으면
HASH_VERIFICATION_SECRET(이메일 키는EMAIL_HASH_SECRET) env 사용. - 내장 normalizer:
email,digits.BUILT_IN_NORMALIZERS,getProfileConfig,emailNormalizer,digitsNormalizerexport 됨. - usdt3·기존 DB 호환: 프로필에
keyDerivation: sha256지정하거나, YAML 없이lookupHash/compareLookupHash(..., { keyDerivation: 'sha256' })사용.
기능 옵션
CoreModule 옵션으로 기능별 on/off 가능. 미설정 시 기본값 true.
| 옵션 | 설명 | 기본값 |
|------|------|--------|
| database.auto | DB 모듈 사용 | true |
| response.commonResponse | { code, data, meta, error } 형식 적용 | true |
| interceptors.logging | 요청/응답 로깅 | true |
| interceptors.errorHandling | 에러 인터셉터 | true |
| interceptors.responseTransform | 응답 변환(CommonResponse) | true |
| interceptors.databaseCheck | DB 연결 체크 | true |
| guards.jwt | JWT 인증 가드 (forHttpApi/forHybrid 기본 true) | context별 |
| filters.exception | AllExceptionsFilter | true |
예: CommonResponse 끄기, 로깅/DB체크 끄기
CoreModule.forHttpApi({
database: { schema },
response: { commonResponse: false },
interceptors: { logging: false, databaseCheck: false },
})Database
스키마 정의 및 주입
// database/schema.ts
import { mysqlTable, int, varchar, timestamp } from 'drizzle-orm/mysql-core';
export const users = mysqlTable('users', {
id: int('id').primaryKey().autoincrement(),
email: varchar('email', { length: 255 }).notNull().unique(),
password: varchar('password', { length: 255 }).notNull(),
createdAt: timestamp('created_at').defaultNow(),
});
export const schema = { users };환경 변수
DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME, DB_SSL, DB_CONNECTION_LIMIT
DatabaseQuery
where는 Drizzle SQL 또는 plain object(eq 조합) 지원.
// select(options)
const result = await this.dbQuery.select({
table: 'users',
fields: ['id', 'name', 'email'],
where: { email: '[email protected]' },
});
// query() — pagination, sort, search
const result = await this.dbQuery.query({
table: 'users',
fields: ['id', 'email'],
sort: [{ field: 'createdAt', order: 'desc' }],
pagination: { page: 1, limit: 10 },
search: [{ keyword: 'test', fields: ['email', 'name'] }],
where: { status: 'active' },
});
// insert / update / delete
await this.dbQuery.insertOne({ table: 'users', fields: ['email', 'name'], values: data });
await this.dbQuery.updateOne({ table: 'users', values: data, where: eq(users.id, id) });
await this.dbQuery.deleteOne({ table: 'users', where: eq(users.id, id) });
// findOne / findById / count / exists
const user = await this.dbQuery.findOne('users', { where: { email: '[email protected]' }, fields: ['id', 'email'] });
const user = await this.dbQuery.findById('users', 1);
const n = await this.dbQuery.count('users', { where: { status: 'active' } });
const ok = await this.dbQuery.exists('users', { where: { email: '[email protected]' } });ServiceHelpers (Drizzle 직접 사용)
const db = this.helpers.getDb();
const [user] = await db.select().from(users).where(eq(users.email, email)).limit(1);
await this.helpers.withTransaction(async (tx) => {
await tx.insert(users).values({ email: '[email protected]' });
await tx.insert(posts).values({ userId: 1, title: 'Hello' });
});
const paginationResult = this.helpers.createPaginationResult(items, total, page, limit);Controller / Service 예시
// Controller
import { Controller, Get, Request, UseGuards } from '@nestjs/common';
import { ControllerHelpers, Public, User, JwtUser, Roles, JwtAuthGuard, RolesGuard } from '@xfilecom/core-sdk';
@Controller('users')
export class UsersController {
constructor(private readonly helpers: ControllerHelpers) {}
@Public()
@Get()
async findAll(@Request() req: any) {
const { page, limit } = this.helpers.parsePagination(req.query);
const users = await this.userService.findAll(page, limit);
return this.helpers.success(users, 'Users retrieved');
}
@UseGuards(JwtAuthGuard)
@Get('me')
getMe(@User() user: JwtUser) {
return user;
}
@UseGuards(JwtAuthGuard)
@Get('my-id')
getMyId(@User('sub') userId: string | number) {
return { userId };
}
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin')
@Get('admin')
adminOnly() {
return { message: 'admin only' };
}
}
// Service
@Injectable()
export class UsersService {
constructor(
private readonly helpers: ServiceHelpers,
private readonly dbQuery: DatabaseQuery,
) {}
async findAll(page: number, limit: number) {
return this.dbQuery.query({
table: 'users',
fields: ['id', 'email', 'name'],
pagination: { page, limit },
sort: [{ field: 'id', order: 'desc' }],
});
}
}Guards · Decorators · Interceptors · Filters
- Guards:
JwtAuthGuard,RolesGuard - Decorators:
@Public(),@User(),@User('sub'),@Roles('admin', 'user') - Interceptors: LoggingInterceptor, ErrorHandlingInterceptor, ResponseTransformInterceptor, DatabaseCheckInterceptor
- Filters: AllExceptionsFilter
- 응답 타입:
CommonResponseDto,CommonErrorDto,PaginationMeta,ResponseMeta
JWT 인증: JwtAuthGuard는 process.env.JWT_SECRET을 참조합니다. YAML만 쓸 경우 loadApplicationYaml({ syncEnvKeys: { JWT_SECRET: 'jwt.secret' } }) 로 config 값을 env에 채우면 Guard와 자연스럽게 연동됩니다. CoreModule.forHttpApi({ jwt: { secret, expiresIn } }) 로 넘기면 ConfigValidator는 env 검사를 건너뜁니다. passport-jwt / @nestjs/passport는 선택 의존성이며, 없으면 경고 후 인증을 스킵합니다 (개발용). 프로덕션에서는 설치 권장.
기타 유틸
- ErrorUtils: 에러 메시지/코드 처리
- LoggerHelpers, ILogWriter, ConsoleLogWriter, FileLogWriter, getLoggingConfigFromEnv: 로깅
- ConfigValidator: JWT/DB 설정 검증 (
validateJwtConfig(throwOnMissing?, jwtOptions?)—jwtOptions.secret이 있으면 env 검사 생략), parseBoolean, parseNumber, parseArray (쉼표 구분 문자열 → 배열) - Env:
getAppEnv(),isDevelopment(),isProduction(),isStaging(),currentAppEnv,isDev,isProd(APP_ENV / NODE_ENV 기반)
Database 연결 실패 시
- 연결 실패해도 서버는 기동됩니다 (Graceful Degradation).
.env에DB_HOST,DB_PORT,DB_USER,DB_PASSWORD,DB_NAME설정 후 재시도.- Config 직접 주입:
CoreModule.forHttpApi({ database: { config: { ... }, schema } }).
수정 사항
JWT 설정 검증 (ConfigValidator)
validateJwtConfig(throwOnMissing?, jwtOptions?)두 번째 인자 추가.options.jwt?.secret이 있으면process.env.JWT_SECRET검사를 건너뛰어 불필요한 경고를 내지 않음.CoreModule에서 JWT Guard 등록 시options.jwt를 넘기도록 변경 → YAML/옵션만으로 JWT 설정 시 경고 제거.
설정 로드 시 env 동기화 (syncEnvKeys)
loadApplicationYaml/loadApplicationYamlSync옵션에syncEnvKeys?: Record<string, string>추가.- 로드한 config의 dot 경로(예:
jwt.secret) 값을 지정한 환경 변수명(예:JWT_SECRET)으로process.env에 채움. - YAML만 사용해도 ConfigValidator, JwtAuthGuard 등이
process.env를 참조할 때 자연스럽게 연동 가능.
설정 루트·Config 로더 (resolveConfigRootDir, createConfigLoader)
- resolveConfigRootDir(options?): application.yml 이 있는 디렉터리 탐색. 기본 후보:
libs/config/config,../../libs/config/config,../libs/config/config, cwd. 모노레포·실행 위치 무관하게 동일 규칙 사용 가능. - createConfigLoader(options): 한 번 로드 → env 동기화 → 전역 캐시(globalKey) →
getFullConfig()/getServiceConfig(serviceKey, { portEnvKey? })제공. auth-service, mail-service 등에서 config-root.ts·load-config.ts 대신 core-sdk만으로 동일 패턴 사용 가능.
설정 소스 (configSource)
configSource: 'yaml' | 'env' | 'yamlWithEnvOverrides'옵션 및CONFIG_SOURCE환경 변수로 .env vs YAML 선택 가능.configSource: 'env'시 YAML 없이process.env기반 config 객체 생성.
환경 유틸 (Env)
getAppEnv(),isDevelopment(),isProduction(),isStaging(),currentAppEnv,isDev,isProd추가 (APP_ENV / NODE_ENV 기반).
Crypto (비밀번호·조회용 해시)
- PBKDF2 비밀번호:
pbkdf2HashPassword,pbkdf2VerifyPassword— 저장 형식saltHex:hashHex, 기본 100_000회·sha512·64바이트 (usdt3·기존 DB 호환). - 조회용 해시 키 파생:
HashVerificationConfig.keyDerivation: 'none' | 'sha256'—sha256이면 HMAC 키로 sha256(secret) 사용 (usdt3·기존 email_hash 등과 동일). - lookupHash / compareLookupHash: YAML 없이 secret + keyDerivation 만으로 조회용 해시 생성/비교.
deriveKeySha256export.
Hash verification
hashVerification.profiles+hashByKey/compareByKey로 동적 키별 해시/비교 지원.keyDerivation: 'sha256'로 기존 DB와 동일한 해시 생성 가능.ConfigValidator.parseArray추가 (쉼표 구분 문자열 → 배열).
문서
- JWT 인증:
process.env참조,syncEnvKeys연동,passport-jwt선택 의존성 안내. - Auth 클라이언트: auth 모듈이 패키지에 포함되면
index에서 export 예정.
라이선스
ISC
