- Redesign website homepage & product-center per Figma (fonts, logos, hero/footer/customer cases) - Add API upload module (multer) with static serving for uploads/public assets - Add OriginGood.delisted flag and SDS request retry logic - Add admin ImageUpload component and goods import/upload flows - Add vitest suite for website components and composables (32 tests) - Add skills, docs, plans and PRODUCT.md
83 lines
2.6 KiB
TypeScript
83 lines
2.6 KiB
TypeScript
import { NestFactory } from '@nestjs/core';
|
|
import { NestExpressApplication } from '@nestjs/platform-express';
|
|
import { ValidationPipe } from '@nestjs/common';
|
|
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
|
import { json } from 'express';
|
|
import { join } from 'path';
|
|
import { AppModule } from './app.module';
|
|
import { HttpExceptionFilter } from './common/filters/http-exception.filter';
|
|
import { TransformInterceptor } from './common/interceptors/transform.interceptor';
|
|
|
|
async function bootstrap() {
|
|
const app = await NestFactory.create<NestExpressApplication>(AppModule, { bodyParser: false });
|
|
|
|
// Replace Express's JSON parser with one that stringifies BigInt.
|
|
// Express's default `json()` throws "Do not know how to serialize a BigInt".
|
|
app.use(
|
|
json({
|
|
limit: '2mb',
|
|
reviver: (_key: string, value: unknown) => {
|
|
// If a numeric string would overflow the JS number range we keep
|
|
// it as a string; the JWT strategy / services expect bigints.
|
|
if (typeof value === 'string' && /^-?\d{16,}$/.test(value)) {
|
|
// Leave as string — services parse with BigInt().
|
|
return value;
|
|
}
|
|
return value;
|
|
},
|
|
}),
|
|
);
|
|
|
|
// CORS
|
|
app.enableCors({
|
|
origin: true,
|
|
credentials: true,
|
|
});
|
|
|
|
// Serve uploaded files
|
|
app.useStaticAssets(join(process.cwd(), 'uploads'), {
|
|
prefix: '/uploads/',
|
|
});
|
|
app.useStaticAssets(join(process.cwd(), 'public'), {
|
|
prefix: '/assets/',
|
|
});
|
|
|
|
// Global pipes
|
|
app.useGlobalPipes(
|
|
new ValidationPipe({
|
|
whitelist: true,
|
|
transform: true,
|
|
forbidNonWhitelisted: true,
|
|
}),
|
|
);
|
|
|
|
// Global filters and interceptors
|
|
app.useGlobalFilters(new HttpExceptionFilter());
|
|
app.useGlobalInterceptors(new TransformInterceptor());
|
|
|
|
// Swagger
|
|
const config = new DocumentBuilder()
|
|
.setTitle('InkReach Product Center API')
|
|
.setDescription('Backend API for InkReach Product Center')
|
|
.setVersion('1.0')
|
|
.addBearerAuth()
|
|
.build();
|
|
|
|
const document = SwaggerModule.createDocument(app, config);
|
|
SwaggerModule.setup('api/docs', app, document);
|
|
|
|
const port = process.env.PORT ?? 3001;
|
|
await app.listen(port, '0.0.0.0');
|
|
console.log(`🚀 Application is running on: http://0.0.0.0:${port}`);
|
|
console.log(`📚 Swagger documentation: http://0.0.0.0:${port}/api/docs`);
|
|
}
|
|
|
|
// Make JSON.stringify aware of BigInt so outgoing responses containing
|
|
// primary keys (`BigInt` columns) don't blow up. BigInts are serialized
|
|
// as their decimal string — clients should parse them with BigInt().
|
|
(BigInt.prototype as unknown as { toJSON: () => string }).toJSON = function () {
|
|
return this.toString();
|
|
};
|
|
|
|
bootstrap();
|