From 44aa34d1ff39399ae6b314439cfb2607f89fc426 Mon Sep 17 00:00:00 2001 From: hzhang Date: Fri, 15 May 2026 18:47:35 +0100 Subject: [PATCH] refactor: migrate to ES modules package.json type=module, tsconfig module/moduleResolution=NodeNext, target es2022, explicit .js on all relative imports. Center: jsonwebtoken & bcryptjs switched to default imports (ESM/CJS interop). Verified: builds, boots, full auth + plugin round-trip work under ESM. Co-Authored-By: Claude Opus 4.7 (1M context) --- package.json | 1 + src/app.module.ts | 18 +++++++++--------- src/audit/audit.module.ts | 4 ++-- src/audit/audit.service.ts | 2 +- src/auth/auth.controller.ts | 10 +++++----- src/auth/auth.module.ts | 12 ++++++------ src/auth/auth.service.ts | 20 ++++++++++---------- src/auth/token.util.spec.ts | 2 +- src/cli.ts | 6 +++--- src/common/center-api-key.guard.ts | 4 ++-- src/common/metrics.controller.ts | 2 +- src/common/request-context.middleware.ts | 2 +- src/data-source.ts | 2 +- src/database.config.ts | 10 +++++----- src/health.integration.spec.ts | 2 +- src/main.ts | 6 +++--- src/nodes/node-admin.service.ts | 6 +++--- src/nodes/nodes.controller.ts | 6 +++--- src/nodes/nodes.module.ts | 6 +++--- tsconfig.json | 5 +++-- 20 files changed, 64 insertions(+), 62 deletions(-) diff --git a/package.json b/package.json index bcdf698..bbfa5f4 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "fabric-backend-center", "version": "0.1.0", "private": true, + "type": "module", "description": "Fabric Identity Hub (Center service)", "scripts": { "build": "tsc -p tsconfig.build.json", diff --git a/src/app.module.ts b/src/app.module.ts index 56b53c3..f24d1c8 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,15 +1,15 @@ import { Module } from '@nestjs/common'; import { APP_GUARD } from '@nestjs/core'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { buildTypeOrmConfig } from './database.config'; -import { HealthController } from './common/health.controller'; -import { MetricsController } from './common/metrics.controller'; -import { MetricsService } from './common/metrics.service'; -import { AuthModule } from './auth/auth.module'; -import { NodesModule } from './nodes/nodes.module'; -import { AuditModule } from './audit/audit.module'; -import { CenterApiKeyGuard } from './common/center-api-key.guard'; -import { GuildNode } from './entities/guild-node.entity'; +import { buildTypeOrmConfig } from './database.config.js'; +import { HealthController } from './common/health.controller.js'; +import { MetricsController } from './common/metrics.controller.js'; +import { MetricsService } from './common/metrics.service.js'; +import { AuthModule } from './auth/auth.module.js'; +import { NodesModule } from './nodes/nodes.module.js'; +import { AuditModule } from './audit/audit.module.js'; +import { CenterApiKeyGuard } from './common/center-api-key.guard.js'; +import { GuildNode } from './entities/guild-node.entity.js'; @Module({ imports: [ diff --git a/src/audit/audit.module.ts b/src/audit/audit.module.ts index d87290a..353d25f 100644 --- a/src/audit/audit.module.ts +++ b/src/audit/audit.module.ts @@ -1,7 +1,7 @@ import { Global, Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { AuditLog } from '../entities/audit-log.entity'; -import { AuditService } from './audit.service'; +import { AuditLog } from '../entities/audit-log.entity.js'; +import { AuditService } from './audit.service.js'; @Global() @Module({ diff --git a/src/audit/audit.service.ts b/src/audit/audit.service.ts index c90d0e9..20f81af 100644 --- a/src/audit/audit.service.ts +++ b/src/audit/audit.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { AuditLog } from '../entities/audit-log.entity'; +import { AuditLog } from '../entities/audit-log.entity.js'; export type AuditWriteInput = { action: string; diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 29878c6..9337e89 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -1,9 +1,9 @@ import { Body, Controller, Get, Headers, Param, Patch, Post, UnauthorizedException } from '@nestjs/common'; -import { AuthService } from './auth.service'; -import { LoginDto } from './dto.login.dto'; -import { RefreshDto } from './dto.refresh.dto'; -import { LogoutDto } from './dto.logout.dto'; -import { UpdateMeDto } from './dto.update-me.dto'; +import { AuthService } from './auth.service.js'; +import { LoginDto } from './dto.login.dto.js'; +import { RefreshDto } from './dto.refresh.dto.js'; +import { LogoutDto } from './dto.logout.dto.js'; +import { UpdateMeDto } from './dto.update-me.dto.js'; function bearer(authorization?: string): string { return authorization?.startsWith('Bearer ') ? authorization.slice(7) : ''; diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 5527f47..d582944 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -1,11 +1,11 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { AuthController } from './auth.controller'; -import { AuthService } from './auth.service'; -import { User } from '../entities/user.entity'; -import { GuildNode } from '../entities/guild-node.entity'; -import { GuildUser } from '../entities/guild-user.entity'; -import { UserApiKey } from '../entities/user-api-key.entity'; +import { AuthController } from './auth.controller.js'; +import { AuthService } from './auth.service.js'; +import { User } from '../entities/user.entity.js'; +import { GuildNode } from '../entities/guild-node.entity.js'; +import { GuildUser } from '../entities/guild-user.entity.js'; +import { UserApiKey } from '../entities/user-api-key.entity.js'; @Module({ imports: [TypeOrmModule.forFeature([User, GuildNode, GuildUser, UserApiKey])], diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 655299f..5018bf1 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -5,17 +5,17 @@ import { } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import * as bcrypt from 'bcryptjs'; -import * as jwt from 'jsonwebtoken'; +import bcrypt from 'bcryptjs'; +import jwt from 'jsonwebtoken'; import { randomBytes } from 'crypto'; -import { User } from '../entities/user.entity'; -import { GuildNode } from '../entities/guild-node.entity'; -import { GuildUser } from '../entities/guild-user.entity'; -import { UserApiKey } from '../entities/user-api-key.entity'; -import { RegisterDto } from './dto.register.dto'; -import { LoginDto } from './dto.login.dto'; -import { AuditService } from '../audit/audit.service'; -import { parseDurationToSeconds } from './token.util'; +import { User } from '../entities/user.entity.js'; +import { GuildNode } from '../entities/guild-node.entity.js'; +import { GuildUser } from '../entities/guild-user.entity.js'; +import { UserApiKey } from '../entities/user-api-key.entity.js'; +import { RegisterDto } from './dto.register.dto.js'; +import { LoginDto } from './dto.login.dto.js'; +import { AuditService } from '../audit/audit.service.js'; +import { parseDurationToSeconds } from './token.util.js'; function signAccessToken(userId: string, email: string): string { const secret = process.env.FABRIC_BACKEND_CENTER_JWT_ACCESS_SECRET as string; diff --git a/src/auth/token.util.spec.ts b/src/auth/token.util.spec.ts index 5399290..680e04d 100644 --- a/src/auth/token.util.spec.ts +++ b/src/auth/token.util.spec.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { parseDurationToSeconds } from './token.util'; +import { parseDurationToSeconds } from './token.util.js'; describe('parseDurationToSeconds', () => { it('parses time units', () => { diff --git a/src/cli.ts b/src/cli.ts index 71b57ea..f9157d3 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,8 +1,8 @@ import 'reflect-metadata'; import { NestFactory } from '@nestjs/core'; -import { AppModule } from './app.module'; -import { AuthService } from './auth/auth.service'; -import { NodeAdminService } from './nodes/node-admin.service'; +import { AppModule } from './app.module.js'; +import { AuthService } from './auth/auth.service.js'; +import { NodeAdminService } from './nodes/node-admin.service.js'; function getArg(flag: string): string | null { const idx = process.argv.indexOf(flag); diff --git a/src/common/center-api-key.guard.ts b/src/common/center-api-key.guard.ts index 5ffa43f..88f9380 100644 --- a/src/common/center-api-key.guard.ts +++ b/src/common/center-api-key.guard.ts @@ -1,8 +1,8 @@ import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import * as bcrypt from 'bcryptjs'; -import { GuildNode } from '../entities/guild-node.entity'; +import bcrypt from 'bcryptjs'; +import { GuildNode } from '../entities/guild-node.entity.js'; @Injectable() export class CenterApiKeyGuard implements CanActivate { diff --git a/src/common/metrics.controller.ts b/src/common/metrics.controller.ts index 0054d6b..61510d1 100644 --- a/src/common/metrics.controller.ts +++ b/src/common/metrics.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get } from '@nestjs/common'; -import { MetricsService } from './metrics.service'; +import { MetricsService } from './metrics.service.js'; @Controller('metrics') export class MetricsController { diff --git a/src/common/request-context.middleware.ts b/src/common/request-context.middleware.ts index d5d63eb..a232a30 100644 --- a/src/common/request-context.middleware.ts +++ b/src/common/request-context.middleware.ts @@ -1,6 +1,6 @@ import { randomUUID } from 'crypto'; import { NextFunction, Request, Response } from 'express'; -import { MetricsService } from './metrics.service'; +import { MetricsService } from './metrics.service.js'; type ReqWithId = Request & { requestId?: string }; diff --git a/src/data-source.ts b/src/data-source.ts index 521bcdd..17f8669 100644 --- a/src/data-source.ts +++ b/src/data-source.ts @@ -1,6 +1,6 @@ import 'reflect-metadata'; import { DataSource, DataSourceOptions } from 'typeorm'; -import { buildTypeOrmConfig } from './database.config'; +import { buildTypeOrmConfig } from './database.config.js'; const cfg = buildTypeOrmConfig(); diff --git a/src/database.config.ts b/src/database.config.ts index 10a4bec..9c8b47e 100644 --- a/src/database.config.ts +++ b/src/database.config.ts @@ -1,9 +1,9 @@ import { TypeOrmModuleOptions } from '@nestjs/typeorm'; -import { User } from './entities/user.entity'; -import { GuildNode } from './entities/guild-node.entity'; -import { AuditLog } from './entities/audit-log.entity'; -import { GuildUser } from './entities/guild-user.entity'; -import { UserApiKey } from './entities/user-api-key.entity'; +import { User } from './entities/user.entity.js'; +import { GuildNode } from './entities/guild-node.entity.js'; +import { AuditLog } from './entities/audit-log.entity.js'; +import { GuildUser } from './entities/guild-user.entity.js'; +import { UserApiKey } from './entities/user-api-key.entity.js'; export const buildTypeOrmConfig = (): TypeOrmModuleOptions => ({ type: 'mysql', diff --git a/src/health.integration.spec.ts b/src/health.integration.spec.ts index 1b8586d..b91959f 100644 --- a/src/health.integration.spec.ts +++ b/src/health.integration.spec.ts @@ -18,7 +18,7 @@ describe('center integration (mysql + api)', () => { let app: INestApplication; beforeAll(async () => { - const { AppModule } = await import('./app.module'); + const { AppModule } = await import('./app.module.js'); const moduleRef = await Test.createTestingModule({ imports: [AppModule], }).compile(); diff --git a/src/main.ts b/src/main.ts index 31c35fc..8c119ba 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,9 +2,9 @@ import 'reflect-metadata'; import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; -import { AppModule } from './app.module'; -import { createRequestContextMiddleware } from './common/request-context.middleware'; -import { MetricsService } from './common/metrics.service'; +import { AppModule } from './app.module.js'; +import { createRequestContextMiddleware } from './common/request-context.middleware.js'; +import { MetricsService } from './common/metrics.service.js'; function requireEnv(name: string): string { const value = process.env[name]; diff --git a/src/nodes/node-admin.service.ts b/src/nodes/node-admin.service.ts index 6b05a72..49c9b57 100644 --- a/src/nodes/node-admin.service.ts +++ b/src/nodes/node-admin.service.ts @@ -1,10 +1,10 @@ import { ConflictException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import * as bcrypt from 'bcryptjs'; +import bcrypt from 'bcryptjs'; import { randomBytes } from 'crypto'; -import { GuildNode } from '../entities/guild-node.entity'; -import { AuditService } from '../audit/audit.service'; +import { GuildNode } from '../entities/guild-node.entity.js'; +import { AuditService } from '../audit/audit.service.js'; @Injectable() export class NodeAdminService { diff --git a/src/nodes/nodes.controller.ts b/src/nodes/nodes.controller.ts index be8051b..6f1160a 100644 --- a/src/nodes/nodes.controller.ts +++ b/src/nodes/nodes.controller.ts @@ -12,9 +12,9 @@ import { } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { GuildNode } from '../entities/guild-node.entity'; -import { AuditService } from '../audit/audit.service'; -import { UpdateNodeStatusDto } from './dto.update-node-status.dto'; +import { GuildNode } from '../entities/guild-node.entity.js'; +import { AuditService } from '../audit/audit.service.js'; +import { UpdateNodeStatusDto } from './dto.update-node-status.dto.js'; @Controller('nodes') export class NodesController { diff --git a/src/nodes/nodes.module.ts b/src/nodes/nodes.module.ts index 809e324..b7729ba 100644 --- a/src/nodes/nodes.module.ts +++ b/src/nodes/nodes.module.ts @@ -1,8 +1,8 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { NodesController } from './nodes.controller'; -import { GuildNode } from '../entities/guild-node.entity'; -import { NodeAdminService } from './node-admin.service'; +import { NodesController } from './nodes.controller.js'; +import { GuildNode } from '../entities/guild-node.entity.js'; +import { NodeAdminService } from './node-admin.service.js'; @Module({ imports: [TypeOrmModule.forFeature([GuildNode])], diff --git a/tsconfig.json b/tsconfig.json index fc317e0..1558f9e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,8 @@ { "compilerOptions": { - "module": "commonjs", - "target": "es2020", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "es2022", "strict": true, "esModuleInterop": true, "experimentalDecorators": true,