feat: add initial project configuration and smoke tests
- Created pnpm workspace configuration to manage packages. - Added a placeholder .gitkeep file in the scripts directory. - Implemented a smoke test script to validate core API and web endpoints. - Established TypeScript base configuration for consistent compilation settings. - Introduced Turbo configuration for task management and build processes.
This commit is contained in:
10
packages/api/nest-cli.json
Normal file
10
packages/api/nest-cli.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true,
|
||||
"webpack": false,
|
||||
"tsConfigPath": "tsconfig.build.json"
|
||||
}
|
||||
}
|
||||
51
packages/api/package.json
Normal file
51
packages/api/package.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "@davinci/api",
|
||||
"version": "0.1.0-alpha.0",
|
||||
"description": "Davinci Platform — NestJS API backend (Fastify adapter)",
|
||||
"author": "Galaxis",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"main": "dist/main.js",
|
||||
"scripts": {
|
||||
"build": "nest build",
|
||||
"start": "node dist/main.js",
|
||||
"start:dev": "nest start --watch",
|
||||
"test": "vitest run",
|
||||
"test:unit": "vitest run --config vitest.config.ts",
|
||||
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
||||
"test:cov": "vitest run --coverage",
|
||||
"lint": "eslint \"{src,test}/**/*.ts\"",
|
||||
"prisma:generate": "prisma generate",
|
||||
"prisma:migrate": "prisma migrate dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@davinci/shared": "workspace:*",
|
||||
"@nestjs/common": "^11.0.0",
|
||||
"@nestjs/config": "^4.0.0",
|
||||
"@nestjs/core": "^11.0.0",
|
||||
"@nestjs/platform-fastify": "^11.0.0",
|
||||
"@nestjs/swagger": "^11.2.6",
|
||||
"@prisma/adapter-pg": "^7.5.0",
|
||||
"@prisma/client": "^7.0.0",
|
||||
"@scalar/fastify-api-reference": "^1.48.5",
|
||||
"dotenv": "^16.4.0",
|
||||
"joi": "^17.13.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.0",
|
||||
"@swc/core": "^1.10.0",
|
||||
"@types/node": "^22.10.0",
|
||||
"pino-pretty": "^13.1.3",
|
||||
"prisma": "^7.0.0",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.7.0",
|
||||
"unplugin-swc": "^1.5.0",
|
||||
"vitest": "^3.0.0"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "npx tsx prisma/seed.ts"
|
||||
}
|
||||
}
|
||||
13
packages/api/prisma.config.ts
Normal file
13
packages/api/prisma.config.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'dotenv/config';
|
||||
import { defineConfig } from 'prisma/config';
|
||||
|
||||
export default defineConfig({
|
||||
schema: 'prisma/schema.prisma',
|
||||
migrations: {
|
||||
path: 'prisma/migrations',
|
||||
seed: 'npx tsx prisma/seed.ts',
|
||||
},
|
||||
datasource: {
|
||||
url: process.env['DATABASE_URL'],
|
||||
},
|
||||
});
|
||||
14
packages/api/prisma/schema.prisma
Normal file
14
packages/api/prisma/schema.prisma
Normal file
@@ -0,0 +1,14 @@
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
output = "../src/generated/prisma"
|
||||
moduleFormat = "cjs"
|
||||
}
|
||||
|
||||
// Placeholder model — removed when real models are added in feature plans
|
||||
model Placeholder {
|
||||
id String @id @default(uuid())
|
||||
}
|
||||
43
packages/api/prisma/seed.ts
Normal file
43
packages/api/prisma/seed.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Prisma seed script — creates deterministic test data for local development.
|
||||
*
|
||||
* Run: npx prisma db seed
|
||||
* make dev-seed
|
||||
*
|
||||
* This is idempotent — safe to run multiple times.
|
||||
*
|
||||
* Replace/extend with real seed data when feature models are added.
|
||||
*/
|
||||
import { PrismaClient } from '../src/generated/prisma/client';
|
||||
import { PrismaPg } from '@prisma/adapter-pg';
|
||||
|
||||
const adapter = new PrismaPg({ connectionString: process.env['DATABASE_URL']! });
|
||||
const prisma = new PrismaClient({ adapter });
|
||||
|
||||
async function main(): Promise<void> {
|
||||
console.log('');
|
||||
console.log('🌱 Seeding davinci-platform dev database...');
|
||||
console.log('');
|
||||
|
||||
// Placeholder — replace when real models exist
|
||||
const existing = await prisma.placeholder.findFirst();
|
||||
if (existing) {
|
||||
console.log(' ⏭ Placeholder record already exists');
|
||||
} else {
|
||||
await prisma.placeholder.create({ data: {} });
|
||||
console.log(' ✅ Placeholder record created');
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('✅ Seed complete');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('❌ Seed failed:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
23
packages/api/src/app.module.ts
Normal file
23
packages/api/src/app.module.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import * as Joi from 'joi';
|
||||
import { HealthModule } from './health/health.module.js';
|
||||
import { PrismaModule } from './prisma/prisma.module.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
validationSchema: Joi.object({
|
||||
DATABASE_URL: Joi.string().uri().required(),
|
||||
PORT: Joi.number().default(3001),
|
||||
NODE_ENV: Joi.string().valid('development', 'production', 'test').default('development'),
|
||||
DAVINCI_MODE: Joi.string().valid('mothership', 'community').default('mothership'),
|
||||
ENABLE_API_DOCS: Joi.string().valid('true', 'false', '1', '0').optional(),
|
||||
}),
|
||||
}),
|
||||
PrismaModule,
|
||||
HealthModule,
|
||||
],
|
||||
})
|
||||
export class AppModule {}
|
||||
52
packages/api/src/docs/__tests__/api-docs.setup.spec.ts
Normal file
52
packages/api/src/docs/__tests__/api-docs.setup.spec.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { afterEach, describe, it, expect } from 'vitest';
|
||||
import { resolveEnableApiDocs, API_VERSIONS } from '../api-docs.setup';
|
||||
|
||||
describe('resolveEnableApiDocs', () => {
|
||||
const originalEnv = process.env.ENABLE_API_DOCS;
|
||||
|
||||
afterEach(() => {
|
||||
if (originalEnv === undefined) {
|
||||
delete process.env.ENABLE_API_DOCS;
|
||||
} else {
|
||||
process.env.ENABLE_API_DOCS = originalEnv;
|
||||
}
|
||||
});
|
||||
|
||||
it('returns true when ENABLE_API_DOCS=true', () => {
|
||||
process.env.ENABLE_API_DOCS = 'true';
|
||||
expect(resolveEnableApiDocs('production')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns true when ENABLE_API_DOCS=1', () => {
|
||||
process.env.ENABLE_API_DOCS = '1';
|
||||
expect(resolveEnableApiDocs('production')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when ENABLE_API_DOCS=false', () => {
|
||||
process.env.ENABLE_API_DOCS = 'false';
|
||||
expect(resolveEnableApiDocs('development')).toBe(false);
|
||||
});
|
||||
|
||||
it('defaults to true in development when not set', () => {
|
||||
delete process.env.ENABLE_API_DOCS;
|
||||
expect(resolveEnableApiDocs('development')).toBe(true);
|
||||
});
|
||||
|
||||
it('defaults to false in production when not set', () => {
|
||||
delete process.env.ENABLE_API_DOCS;
|
||||
expect(resolveEnableApiDocs('production')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('API_VERSIONS', () => {
|
||||
it('has at least one version defined', () => {
|
||||
expect(API_VERSIONS.length).toBeGreaterThanOrEqual(1);
|
||||
});
|
||||
|
||||
it('has v1 as the default version', () => {
|
||||
const defaultVersion = API_VERSIONS.find((v) => v.default);
|
||||
expect(defaultVersion).toBeDefined();
|
||||
expect(defaultVersion!.version).toBe('1');
|
||||
expect(defaultVersion!.slug).toBe('v1');
|
||||
});
|
||||
});
|
||||
152
packages/api/src/docs/api-docs.setup.ts
Normal file
152
packages/api/src/docs/api-docs.setup.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import {
|
||||
DocumentBuilder,
|
||||
OpenAPIObject,
|
||||
SwaggerModule,
|
||||
SwaggerDocumentOptions,
|
||||
} from '@nestjs/swagger';
|
||||
|
||||
export interface ApiVersionDefinition {
|
||||
version: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
default?: boolean;
|
||||
documentOptions?: SwaggerDocumentOptions;
|
||||
}
|
||||
|
||||
export const API_VERSIONS: ApiVersionDefinition[] = [
|
||||
{
|
||||
version: '1',
|
||||
title: 'API v1',
|
||||
slug: 'v1',
|
||||
default: true,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Configure multi-version OpenAPI and Scalar API reference UI.
|
||||
*
|
||||
* Generates OpenAPI docs via @nestjs/swagger, serves per-version JSON at
|
||||
* `/api-reference/{slug}/openapi.json`, and registers Scalar UI at `/api-reference`.
|
||||
*
|
||||
* The `/api-reference` endpoint is operational (like `/health`) and is NOT
|
||||
* subject to `/api/v{major}` versioning.
|
||||
*/
|
||||
export async function setupApiDocs(
|
||||
app: NestFastifyApplication,
|
||||
configService: ConfigService,
|
||||
): Promise<void> {
|
||||
const enableDocs = resolveEnableApiDocs(
|
||||
configService.get<string>('NODE_ENV') || process.env.NODE_ENV || 'development',
|
||||
);
|
||||
|
||||
if (!enableDocs) {
|
||||
return;
|
||||
}
|
||||
|
||||
const versionDocs = buildVersionedDocuments(app);
|
||||
registerOpenApiEndpoints(app, versionDocs);
|
||||
await registerScalarReference(app, versionDocs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether API docs should be enabled.
|
||||
*
|
||||
* 1. ENABLE_API_DOCS env var (explicit override)
|
||||
* 2. Default: enabled in development/test, disabled in production
|
||||
*/
|
||||
export function resolveEnableApiDocs(nodeEnv: string): boolean {
|
||||
const explicit = process.env.ENABLE_API_DOCS;
|
||||
if (explicit !== undefined) {
|
||||
return explicit === 'true' || explicit === '1';
|
||||
}
|
||||
|
||||
return nodeEnv !== 'production';
|
||||
}
|
||||
|
||||
export function buildVersionedDocuments(app: NestFastifyApplication): Map<string, OpenAPIObject> {
|
||||
const docs = new Map<string, OpenAPIObject>();
|
||||
|
||||
for (const version of API_VERSIONS) {
|
||||
docs.set(version.slug, buildOpenApiDocument(app, version));
|
||||
}
|
||||
|
||||
return docs;
|
||||
}
|
||||
|
||||
export function buildOpenApiDocument(
|
||||
app: NestFastifyApplication,
|
||||
version?: ApiVersionDefinition,
|
||||
): OpenAPIObject {
|
||||
const v = version?.version ?? '1';
|
||||
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle('Davinci Platform API')
|
||||
.setDescription(
|
||||
'Unified API for the Davinci platform.\n\n' +
|
||||
'## Versioning\n\n' +
|
||||
`All business endpoints are served under \`/api/v${v}\`. ` +
|
||||
'Operational endpoints (`/health`, `/api-reference`) are unversioned.',
|
||||
)
|
||||
.setVersion('0.1.0')
|
||||
.setContact('Davinci', '', '')
|
||||
.setLicense('UNLICENSED', '')
|
||||
.addBearerAuth(
|
||||
{
|
||||
type: 'http',
|
||||
scheme: 'bearer',
|
||||
bearerFormat: 'JWT',
|
||||
description:
|
||||
'JWT access token. Obtain via POST /api/v1/auth/login or /api/v1/auth/register.',
|
||||
},
|
||||
'bearer',
|
||||
)
|
||||
.build();
|
||||
|
||||
return SwaggerModule.createDocument(app, config, version?.documentOptions);
|
||||
}
|
||||
|
||||
function registerOpenApiEndpoints(
|
||||
app: NestFastifyApplication,
|
||||
versionDocs: Map<string, OpenAPIObject>,
|
||||
): void {
|
||||
const fastify = app.getHttpAdapter().getInstance();
|
||||
|
||||
for (const [slug, doc] of versionDocs) {
|
||||
fastify.get(
|
||||
`/api-reference/${slug}/openapi.json`,
|
||||
{ schema: { hide: true } as Record<string, unknown> },
|
||||
async () => doc,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function registerScalarReference(
|
||||
app: NestFastifyApplication,
|
||||
versionDocs: Map<string, OpenAPIObject>,
|
||||
): Promise<void> {
|
||||
const fastify = app.getHttpAdapter().getInstance();
|
||||
|
||||
// Dynamic import — @scalar/fastify-api-reference is ESM-only
|
||||
const { default: scalarFastifyApiReference } = await import('@scalar/fastify-api-reference');
|
||||
|
||||
const sources = API_VERSIONS.filter((v) => versionDocs.has(v.slug)).map((v) => ({
|
||||
title: v.title,
|
||||
slug: v.slug,
|
||||
url: `/api-reference/${v.slug}/openapi.json`,
|
||||
...(v.default && { default: true }),
|
||||
}));
|
||||
|
||||
await fastify.register(scalarFastifyApiReference, {
|
||||
routePrefix: '/api-reference',
|
||||
configuration: {
|
||||
sources,
|
||||
theme: 'kepler',
|
||||
hideClientButton: true,
|
||||
showDeveloperTools: 'never',
|
||||
hideDownloadButton: true,
|
||||
agent: { disabled: true },
|
||||
} as Record<string, unknown>,
|
||||
});
|
||||
}
|
||||
22
packages/api/src/health/health.controller.spec.ts
Normal file
22
packages/api/src/health/health.controller.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { HealthController } from './health.controller.js';
|
||||
|
||||
describe('HealthController', () => {
|
||||
let controller: HealthController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [HealthController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<HealthController>(HealthController);
|
||||
});
|
||||
|
||||
it('should return ok status with timestamp', () => {
|
||||
const result = controller.check();
|
||||
expect(result.status).toBe('ok');
|
||||
expect(result.timestamp).toBeDefined();
|
||||
expect(typeof result.timestamp).toBe('string');
|
||||
});
|
||||
});
|
||||
12
packages/api/src/health/health.controller.ts
Normal file
12
packages/api/src/health/health.controller.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common';
|
||||
|
||||
@Controller({ path: 'health', version: VERSION_NEUTRAL })
|
||||
export class HealthController {
|
||||
@Get()
|
||||
check() {
|
||||
return {
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
7
packages/api/src/health/health.module.ts
Normal file
7
packages/api/src/health/health.module.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HealthController } from './health.controller.js';
|
||||
|
||||
@Module({
|
||||
controllers: [HealthController],
|
||||
})
|
||||
export class HealthModule {}
|
||||
57
packages/api/src/main.ts
Normal file
57
packages/api/src/main.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||
import { VersioningType, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { AppModule } from './app.module.js';
|
||||
import { setupApiDocs } from './docs/api-docs.setup.js';
|
||||
|
||||
async function bootstrap() {
|
||||
const logger = new Logger('Bootstrap');
|
||||
const isDev = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const app = await NestFactory.create<NestFastifyApplication>(
|
||||
AppModule,
|
||||
new FastifyAdapter({
|
||||
logger: {
|
||||
level: process.env.LOG_LEVEL || (isDev ? 'debug' : 'info'),
|
||||
...(isDev && {
|
||||
transport: {
|
||||
target: 'pino-pretty',
|
||||
options: { colorize: true, singleLine: true },
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
// Global prefix — all routes under /api, except operational endpoints
|
||||
app.setGlobalPrefix('api', {
|
||||
exclude: ['health', 'health/ready', 'api-reference', 'api-reference/{*path}'],
|
||||
});
|
||||
|
||||
// URI-based versioning: /api/v1/..., /api/v2/...
|
||||
app.enableVersioning({
|
||||
type: VersioningType.URI,
|
||||
defaultVersion: '1',
|
||||
});
|
||||
|
||||
// CORS — env-driven: permissive in dev, strict in production
|
||||
const corsOrigin = process.env.CORS_ORIGIN;
|
||||
app.enableCors({
|
||||
origin: corsOrigin ? corsOrigin.split(',').map((o) => o.trim()) : true,
|
||||
credentials: true,
|
||||
});
|
||||
|
||||
// Interactive API documentation (Scalar) — conditional on ENABLE_API_DOCS
|
||||
const configService = app.get(ConfigService);
|
||||
await setupApiDocs(app, configService);
|
||||
|
||||
// Graceful shutdown
|
||||
app.enableShutdownHooks();
|
||||
|
||||
const port = process.env.PORT ?? 3001;
|
||||
await app.listen(port, '0.0.0.0');
|
||||
logger.log(`API running on http://localhost:${port}`);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
33
packages/api/src/prisma/__tests__/prisma.service.spec.ts
Normal file
33
packages/api/src/prisma/__tests__/prisma.service.spec.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||
import { PrismaService } from '../prisma.service.js';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
|
||||
describe('PrismaService', () => {
|
||||
let service: PrismaService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
PrismaService,
|
||||
{
|
||||
provide: ConfigService,
|
||||
useValue: {
|
||||
getOrThrow: vi.fn().mockReturnValue('postgresql://test:test@localhost:5432/test'),
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<PrismaService>(PrismaService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
it('should expose PrismaClient methods directly (extends pattern)', () => {
|
||||
expect(typeof service.$connect).toBe('function');
|
||||
expect(typeof service.$disconnect).toBe('function');
|
||||
});
|
||||
});
|
||||
9
packages/api/src/prisma/prisma.module.ts
Normal file
9
packages/api/src/prisma/prisma.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { PrismaService } from './prisma.service.js';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [PrismaService],
|
||||
exports: [PrismaService],
|
||||
})
|
||||
export class PrismaModule {}
|
||||
33
packages/api/src/prisma/prisma.service.ts
Normal file
33
packages/api/src/prisma/prisma.service.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { PrismaClient } from '../generated/prisma/client';
|
||||
import { PrismaPg } from '@prisma/adapter-pg';
|
||||
|
||||
/**
|
||||
* NestJS-managed Prisma service for Prisma 7.
|
||||
*
|
||||
* Follows the official NestJS + Prisma 7 recipe:
|
||||
* - Uses `prisma-client` generator with `moduleFormat = "cjs"`
|
||||
* - Extends PrismaClient directly for full type-safe API access
|
||||
* - Uses PrismaPg driver adapter with connectionString
|
||||
*
|
||||
* Usage in feature modules:
|
||||
* constructor(private readonly prisma: PrismaService) {}
|
||||
* await this.prisma.placeholder.findMany();
|
||||
*/
|
||||
@Injectable()
|
||||
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
||||
constructor(configService: ConfigService) {
|
||||
const databaseUrl = configService.getOrThrow<string>('DATABASE_URL');
|
||||
const adapter = new PrismaPg({ connectionString: databaseUrl });
|
||||
super({ adapter });
|
||||
}
|
||||
|
||||
async onModuleInit(): Promise<void> {
|
||||
await this.$connect();
|
||||
}
|
||||
|
||||
async onModuleDestroy(): Promise<void> {
|
||||
await this.$disconnect();
|
||||
}
|
||||
}
|
||||
4
packages/api/tsconfig.build.json
Normal file
4
packages/api/tsconfig.build.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist", "node_modules", "**/*.spec.ts", "**/*.test.ts", "test"]
|
||||
}
|
||||
15
packages/api/tsconfig.json
Normal file
15
packages/api/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"declaration": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"paths": {
|
||||
"@davinci/shared": ["../shared/src/index.ts"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["dist", "node_modules"]
|
||||
}
|
||||
18
packages/api/vitest.config.ts
Normal file
18
packages/api/vitest.config.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import swc from 'unplugin-swc';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import path from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
include: ['src/**/*.spec.ts', 'src/**/*.test.ts'],
|
||||
exclude: ['src/**/*.e2e-spec.ts'],
|
||||
},
|
||||
plugins: [swc.vite()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@davinci/shared': path.resolve(__dirname, '../shared/src/index.ts'),
|
||||
},
|
||||
},
|
||||
});
|
||||
17
packages/api/vitest.e2e.config.ts
Normal file
17
packages/api/vitest.e2e.config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import swc from 'unplugin-swc';
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import path from 'path';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'node',
|
||||
include: ['test/**/*.e2e-spec.ts', 'src/**/*.e2e-spec.ts'],
|
||||
},
|
||||
plugins: [swc.vite()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@davinci/shared': path.resolve(__dirname, '../shared/src/index.ts'),
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user