Enhance NestJS application with SWC builder configuration, add @nestjs/devtools-integration for development support, and refactor various components for improved readability. Update package dependencies and streamline import statements across multiple files.

This commit is contained in:
2024-11-26 04:26:55 +07:00
parent c4e302387f
commit a1ca5c62fb
12 changed files with 1646 additions and 235 deletions

View File

@@ -6,6 +6,14 @@
"compilerOptions": { "compilerOptions": {
"watchAssets": true, "watchAssets": true,
"deleteOutDir": true, "deleteOutDir": true,
"builder": {
"type": "swc",
"options": {
"copyFiles": true,
"includeDotfiles": true
}
},
"typeCheck": true,
"assets": [ "assets": [
{ {
"include": "**/*.pug", "include": "**/*.pug",

1561
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -44,6 +44,7 @@
"@nestjs/common": "^10.0.0", "@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.2.3", "@nestjs/config": "^3.2.3",
"@nestjs/core": "^10.0.0", "@nestjs/core": "^10.0.0",
"@nestjs/devtools-integration": "^0.1.6",
"@nestjs/event-emitter": "^2.1.1", "@nestjs/event-emitter": "^2.1.1",
"@nestjs/graphql": "^12.2.0", "@nestjs/graphql": "^12.2.0",
"@nestjs/jwt": "^10.2.0", "@nestjs/jwt": "^10.2.0",
@@ -141,19 +142,13 @@
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": ["js", "json", "ts"],
"js",
"json",
"ts"
],
"rootDir": "src", "rootDir": "src",
"testRegex": ".*\\.spec\\.ts$", "testRegex": ".*\\.spec\\.ts$",
"transform": { "transform": {
"^.+\\.(t|j)s$": "ts-jest" "^.+\\.(t|j)s$": "ts-jest"
}, },
"collectCoverageFrom": [ "collectCoverageFrom": ["**/*.(t|j)s"],
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage", "coverageDirectory": "../coverage",
"testEnvironment": "node" "testEnvironment": "node"
}, },

View File

@@ -1,13 +1,4 @@
import { import { Controller, Get, Post, Put, Delete, Param, Body, Headers } from '@nestjs/common'
Controller,
Get,
Post,
Put,
Delete,
Param,
Body,
Headers,
} from '@nestjs/common'
import { ClerkService } from './clerk.service' import { ClerkService } from './clerk.service'
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger' import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'
@ApiTags('Clerk') @ApiTags('Clerk')
@@ -18,7 +9,7 @@ export class ClerkController {
@Post('webhook') @Post('webhook')
@ApiOperation({ summary: 'Clerk Webhook' }) @ApiOperation({ summary: 'Clerk Webhook' })
@ApiResponse({ status: 200, description: 'Webhook created successfully' }) @ApiResponse({ status: 200, description: 'Webhook created successfully' })
webhook(@Headers() headers: Headers, @Body() body: any) { webhook(@Body() body: any) {
return this.clerkService.webhook(body) return this.clerkService.webhook(body)
} }
} }

View File

@@ -1,10 +1,8 @@
export enum DocumentEvent { export enum DocumentEvent {
CREATED = 'document_created',
CHANGED = 'document_changed', CHANGED = 'document_changed',
DELETED = 'document_deleted', DELETED = 'document_deleted',
SAVED = 'document_saved', SAVED = 'document_saved',
PAGE_CREATED = 'document_page_created', PAGE_CREATED = 'document_page_created',
PAGE_DELETED = 'document_page_deleted', PAGE_DELETED = 'document_page_deleted',
DOCUMENT_CREATED = 'document_created',
ACTIVE_DOCUMENT_ID_CHANGED = 'document_active_document_id_changed', ACTIVE_DOCUMENT_ID_CHANGED = 'document_active_document_id_changed',
} }

View File

@@ -1,10 +1,5 @@
import { Inject, Injectable, Logger } from '@nestjs/common' import { Inject, Injectable, Logger } from '@nestjs/common'
import { import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
Pothos,
PothosRef,
PothosSchema,
SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'
import { Builder, SchemaContext } from '../Graphql/graphql.builder' import { Builder, SchemaContext } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service' import { PrismaService } from '../Prisma/prisma.service'
import { DocumentEvent } from './document.event' import { DocumentEvent } from './document.event'
@@ -99,10 +94,7 @@ export class DocumentSchema extends PothosSchema {
...query, ...query,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: { where: {
OR: [ OR: [{ ownerId: ctx.http.me.id }, { collaborators: { some: { userId: ctx.http.me.id } } }],
{ ownerId: ctx.http.me.id },
{ collaborators: { some: { userId: ctx.http.me.id } } },
],
}, },
}) })
}, },
@@ -138,11 +130,7 @@ export class DocumentSchema extends PothosSchema {
if (ctx.isSubscription) throw new Error('Not allowed') if (ctx.isSubscription) throw new Error('Not allowed')
const userId = ctx.http?.me?.id const userId = ctx.http?.me?.id
if (!userId) throw new Error('User not found') if (!userId) throw new Error('User not found')
const fileUrl = await this.minio.getFileUrl( const fileUrl = await this.minio.getFileUrl('document', 'document', 'document')
'document',
'document',
'document',
)
if (!fileUrl) throw new Error('File not found') if (!fileUrl) throw new Error('File not found')
const document = await this.prisma.document.create({ const document = await this.prisma.document.create({
...query, ...query,
@@ -211,10 +199,7 @@ export class DocumentSchema extends PothosSchema {
delta, delta,
senderId: ctx.http?.me?.id, senderId: ctx.http?.me?.id,
} }
ctx.http.pubSub.publish( ctx.http.pubSub.publish(`${DocumentEvent.CHANGED}.${args.documentId}`, documentDelta)
`${DocumentEvent.CHANGED}.${args.documentId}`,
documentDelta,
)
return documentDelta return documentDelta
}, },
}), }),
@@ -275,9 +260,7 @@ export class DocumentSchema extends PothosSchema {
if ( if (
document.ownerId !== ctx.http?.me?.id && document.ownerId !== ctx.http?.me?.id &&
!document.isPublic && !document.isPublic &&
!document.collaborators.some( !document.collaborators.some((c) => c.userId === ctx.http?.me?.id && c.writable)
(c) => c.userId === ctx.http?.me?.id && c.writable,
)
) )
throw new Error('User is not owner or collaborator of document') throw new Error('User is not owner or collaborator of document')
return await this.prisma.document.update({ return await this.prisma.document.update({
@@ -302,8 +285,7 @@ export class DocumentSchema extends PothosSchema {
where: { id: args.documentId }, where: { id: args.documentId },
}) })
if (!document) throw new Error('Document not found') if (!document) throw new Error('Document not found')
if (document.ownerId !== ctx.http?.me?.id) if (document.ownerId !== ctx.http?.me?.id) throw new Error('User is not owner of document')
throw new Error('User is not owner of document')
return await this.prisma.documentCollaborator.create({ return await this.prisma.documentCollaborator.create({
data: { data: {
documentId: args.documentId, documentId: args.documentId,
@@ -342,17 +324,16 @@ export class DocumentSchema extends PothosSchema {
if (!document.isPublic) { if (!document.isPublic) {
if ( if (
document.ownerId !== ctx.websocket?.me?.id && document.ownerId !== ctx.websocket?.me?.id &&
!document.collaborators.some( !document.collaborators.some((c) => c.userId === ctx.websocket?.me?.id && c.writable)
(c) => c.userId === ctx.websocket?.me?.id && c.writable,
)
) )
throw new Error('User is not owner or collaborator of document') throw new Error('User is not owner or collaborator of document')
} }
return pubSub.asyncIterator([ return pubSub.asyncIterator([
`${DocumentEvent.CHANGED}.${documentId}`, `${DocumentEvent.CHANGED}.${documentId}`,
`${DocumentEvent.CREATED}.${documentId}`,
`${DocumentEvent.DELETED}.${documentId}`, `${DocumentEvent.DELETED}.${documentId}`,
`${DocumentEvent.SAVED}.${documentId}`, `${DocumentEvent.SAVED}.${documentId}`,
`${DocumentEvent.PAGE_CREATED}.${documentId}`,
`${DocumentEvent.PAGE_DELETED}.${documentId}`,
`${DocumentEvent.ACTIVE_DOCUMENT_ID_CHANGED}.${documentId}`, `${DocumentEvent.ACTIVE_DOCUMENT_ID_CHANGED}.${documentId}`,
]) as unknown as AsyncIterable<DocumentDelta> ]) as unknown as AsyncIterable<DocumentDelta>
}, },

View File

@@ -3,64 +3,12 @@ import { forwardRef, Inject, Injectable } from '@nestjs/common'
import Delta, { Op } from 'quill-delta' import Delta, { Op } from 'quill-delta'
import { MinioService } from '../Minio/minio.service' import { MinioService } from '../Minio/minio.service'
import { DocumentDelta } from './document.type' import { DocumentDelta } from './document.type'
import { JSDOM } from 'jsdom'
import { Logger } from '@nestjs/common' import { Logger } from '@nestjs/common'
import { PrismaService } from 'src/Prisma/prisma.service'
@Injectable() @Injectable()
export class DocumentService { export class DocumentService {
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
private quill: any
constructor( constructor(
private readonly prisma: PrismaService,
private readonly minio: MinioService, private readonly minio: MinioService,
public document: JSDOM, ) {}
) {
;(async () => {
await this.loadQuill()
})()
}
private async loadQuill() {
if (typeof window === 'undefined' || typeof document === 'undefined') {
const { window } = new JSDOM('<!doctype html><html><body></body></html>')
const { navigator } = window
const { Node } = window
global.window = window
global.document = window.document
global.navigator = navigator
global.Node = Node
}
const { default: Quill } = await import('quill')
this.quill = Quill
}
// TODO: maybe never do :)
async handleOnChange(documentId: string, delta: DocumentDelta) {}
async handleOnSave(documentId: string) {}
async handleOnSync(documentId: string) {}
async requestSync(documentId: string, page?: number) {
// using pubsub to broadcast to all clients
// this.pubSub.publish(`document:sync:${documentId}`, {
// documentId,
// page,
// })
}
async clientRequestSave(documentId: string) {
// using pubsub to broadcast to all clients
// this.pubSub.publish(`document:save:${documentId}`, {
// documentId,
// })
}
async serverRequestSave(documentId: string) {}
async generatePreviewImage(documentId: string) {}
async allPageToDelta(documentId: string) {}
async toDocx(documentId: string) {}
} }
// epess/documents/<id>/<page>

View File

@@ -36,10 +36,7 @@ export class MinioService {
} }
let url = null let url = null
// check if presignUrl is provided and not expired else get new presignUrl // check if presignUrl is provided and not expired else get new presignUrl
if ( if (presignUrl && !DateTimeUtils.isExpired(presignUrl.split('&X-Amz-Date=')[1])) {
presignUrl &&
!DateTimeUtils.isExpired(presignUrl.split('&X-Amz-Date=')[1])
) {
url = presignUrl url = presignUrl
} else { } else {
try { try {
@@ -81,14 +78,30 @@ export class MinioService {
} }
async deleteFile(id: string, category: string) { async deleteFile(id: string, category: string) {
return await this.minioClient.removeObject( return await this.minioClient.removeObject(this.configService.get('BUCKET_NAME') ?? 'epess', `${category}/${id}`)
this.configService.get('BUCKET_NAME') ?? 'epess', }
`${category}/${id}`, // create a folder for a document pattern epess/documents/<id>/<page>
) async createDocumentFolder(id: string) {
return await this.minioClient.putObject(this.configService.get('BUCKET_NAME') ?? 'epess', `documents/${id}`, '')
} }
async streamFile(id: string, category: string) {} async upsertDocumentFolder(id: string, page: string) {
return await this.minioClient.putObject(
this.configService.get('BUCKET_NAME') ?? 'epess',
`documents/${id}/${page}`,
'',
)
}
// export document to docx format by get all pages and convert to docx
async exportDocument(id: string) {
// get all pages
const pages = await this.minioClient.listObjects(
this.configService.get('BUCKET_NAME') ?? 'epess',
`documents/${id}`,
)
// convert to docx
// const docx = await this.convertToDocx(pages)
}
fileName() { fileName() {
// generate a unique file name using uuid // generate a unique file name using uuid
return uuidv4() return uuidv4()

View File

@@ -4,15 +4,10 @@ import { Injectable, Logger } from '@nestjs/common'
import { PrismaService } from 'src/Prisma/prisma.service' import { PrismaService } from 'src/Prisma/prisma.service'
import { AppConfigService } from 'src/AppConfig/appconfig.service' import { AppConfigService } from 'src/AppConfig/appconfig.service'
import { import { PreviewScheduleType, ScheduleConfigType, ScheduleConfigTypeForCenter, ScheduleSlotType } from './schedule.d'
PreviewScheduleType,
ScheduleConfigType,
ScheduleConfigTypeForCenter,
ScheduleSlotType,
} from './schedule.d'
import { Config, Schedule, ScheduleDate } from '@prisma/client' import { Config, Schedule, ScheduleDate } from '@prisma/client'
import { DateTime, Settings, Zone } from 'luxon' import { DateTime, Settings, Zone } from 'luxon'
import * as _ from 'lodash' import _ from 'lodash'
import { ScheduleDateInput } from './schedule' import { ScheduleDateInput } from './schedule'
@Injectable() @Injectable()
@@ -22,9 +17,7 @@ export class ScheduleService {
private readonly appConfigService: AppConfigService, private readonly appConfigService: AppConfigService,
) {} ) {}
async createSchedulePreviewForSingleDay( async createSchedulePreviewForSingleDay(scheduleConfig: ScheduleConfigType): Promise<PreviewScheduleType> {
scheduleConfig: ScheduleConfigType,
): Promise<PreviewScheduleType> {
// generate Slot By config // generate Slot By config
const slots = this.generateSlots(scheduleConfig) const slots = this.generateSlots(scheduleConfig)
@@ -35,12 +28,8 @@ export class ScheduleService {
} }
// create preview for center require scheduleConfigInput: { startDate: "2024-11-02T00:00:00.000Z", endDate: "2024-11-22T00:00:00.000Z", slots: [1, 3], days: [2, 5] } // create preview for center require scheduleConfigInput: { startDate: "2024-11-02T00:00:00.000Z", endDate: "2024-11-22T00:00:00.000Z", slots: [1, 3], days: [2, 5] }
async createSchedulePreviewForCenter( async createSchedulePreviewForCenter(scheduleConfig: ScheduleConfigTypeForCenter): Promise<PreviewScheduleType> {
scheduleConfig: ScheduleConfigTypeForCenter, const config: ScheduleConfigType = (await this.appConfigService.getVisibleConfigs()).reduce((acc, curr) => {
): Promise<PreviewScheduleType> {
const config: ScheduleConfigType = (
await this.appConfigService.getVisibleConfigs()
).reduce((acc, curr) => {
// @ts-ignore // @ts-ignore
acc[curr.key] = curr.value acc[curr.key] = curr.value
return acc return acc
@@ -54,9 +43,7 @@ export class ScheduleService {
async generateScheduleDates(schedule: Schedule): Promise<ScheduleDate[]> { async generateScheduleDates(schedule: Schedule): Promise<ScheduleDate[]> {
// generate schedule dates based on data and config // generate schedule dates based on data and config
const config: ScheduleConfigType = ( const config: ScheduleConfigType = (await this.appConfigService.getVisibleConfigs()).reduce((acc, curr) => {
await this.appConfigService.getVisibleConfigs()
).reduce((acc, curr) => {
// @ts-ignore // @ts-ignore
acc[curr.key] = curr.value acc[curr.key] = curr.value
return acc return acc
@@ -72,11 +59,7 @@ export class ScheduleService {
const scheduleDates: ScheduleDateInput[] = [] const scheduleDates: ScheduleDateInput[] = []
// loop each day from scheduleStart to scheduleEnd // loop each day from scheduleStart to scheduleEnd
for ( for (let date = scheduleStart; date <= scheduleEnd; date = date.plus({ days: 1 })) {
let date = scheduleStart;
date <= scheduleEnd;
date = date.plus({ days: 1 })
) {
// Check if the current date matches one of the specified days of the week // Check if the current date matches one of the specified days of the week
if (daysOfWeeks.includes(date.weekday)) { if (daysOfWeeks.includes(date.weekday)) {
// loop through slots // loop through slots
@@ -85,10 +68,7 @@ export class ScheduleService {
slot, slot,
slotDuration.toString(), slotDuration.toString(),
slotBreakDuration.toString(), slotBreakDuration.toString(),
DateTimeUtils.getATimeWithDateB( DateTimeUtils.getATimeWithDateB(DateTime.fromISO(config.dayStartTime), date).toISO() ?? '',
DateTime.fromISO(config.dayStartTime),
date,
).toISO() ?? '',
) )
scheduleDates.push({ scheduleDates.push({
scheduleId: schedule.id, scheduleId: schedule.id,
@@ -103,8 +83,7 @@ export class ScheduleService {
} }
} }
} }
const scheduleDatesCreated = const scheduleDatesCreated = await this.prisma.scheduleDate.createManyAndReturn({
await this.prisma.scheduleDate.createManyAndReturn({
data: scheduleDates, data: scheduleDates,
}) })
@@ -137,11 +116,7 @@ query CenterPreviewSchedule {
const scheduleStart = DateTime.fromISO(_scheduleConfig.startDate) const scheduleStart = DateTime.fromISO(_scheduleConfig.startDate)
const scheduleEnd = DateTime.fromISO(_scheduleConfig.endDate) const scheduleEnd = DateTime.fromISO(_scheduleConfig.endDate)
// loop each day from scheduleStart to scheduleEnd // loop each day from scheduleStart to scheduleEnd
for ( for (let date = scheduleStart; date <= scheduleEnd; date = date.plus({ days: 1 })) {
let date = scheduleStart;
date <= scheduleEnd;
date = date.plus({ days: 1 })
) {
// Check if the current date matches one of the specified days of the week // Check if the current date matches one of the specified days of the week
if (daysOfWeeks.includes(date.weekday)) { if (daysOfWeeks.includes(date.weekday)) {
// loop through slots // loop through slots
@@ -151,10 +126,7 @@ query CenterPreviewSchedule {
slot, slot,
_config.slotDuration, _config.slotDuration,
_config.slotBreakDuration, _config.slotBreakDuration,
DateTimeUtils.getATimeWithDateB( DateTimeUtils.getATimeWithDateB(DateTime.fromISO(_config.dayStartTime), date).toISO() ?? '',
DateTime.fromISO(_config.dayStartTime),
date,
).toISO() ?? '',
) )
// if the slot is not overlapping with mid day break time, add it to the slots // if the slot is not overlapping with mid day break time, add it to the slots
if ( if (
@@ -213,24 +185,11 @@ query CenterPreviewSchedule {
return slots return slots
} }
isOverLapping( isOverLapping(startTime1: DateTime, endTime1: DateTime, startTime2: DateTime, endTime2: DateTime) {
startTime1: DateTime, return Math.max(startTime1.toMillis(), startTime2.toMillis()) < Math.min(endTime1.toMillis(), endTime2.toMillis())
endTime1: DateTime,
startTime2: DateTime,
endTime2: DateTime,
) {
return (
Math.max(startTime1.toMillis(), startTime2.toMillis()) <
Math.min(endTime1.toMillis(), endTime2.toMillis())
)
} }
calculateNumberOfSlots( calculateNumberOfSlots(startTime: string, endTime: string, slotDuration: string, slotBreakDuration: string) {
startTime: string,
endTime: string,
slotDuration: string,
slotBreakDuration: string,
) {
const _startTime = DateTimeUtils.toTime(startTime) const _startTime = DateTimeUtils.toTime(startTime)
const _endTime = DateTimeUtils.toTime(endTime) const _endTime = DateTimeUtils.toTime(endTime)
const _slotDuration = parseInt(slotDuration) // minutes const _slotDuration = parseInt(slotDuration) // minutes
@@ -247,20 +206,12 @@ query CenterPreviewSchedule {
second: _endTime.second, second: _endTime.second,
}) })
const totalMinutes = const totalMinutes = (endDate.toMillis() - startDate.toMillis()) / (60 * 1000)
(endDate.toMillis() - startDate.toMillis()) / (60 * 1000) const numberOfSlots = Math.floor(totalMinutes / (_slotDuration + _slotBreakDuration))
const numberOfSlots = Math.floor(
totalMinutes / (_slotDuration + _slotBreakDuration),
)
return numberOfSlots return numberOfSlots
} }
getSlotStartAndEndTime( getSlotStartAndEndTime(slotNumber: number, slotDuration: string, slotBreakDuration: string, dayStartTime: string) {
slotNumber: number,
slotDuration: string,
slotBreakDuration: string,
dayStartTime: string,
) {
const durationInMinutes = parseInt(slotDuration) const durationInMinutes = parseInt(slotDuration)
const breakDurationInMinutes = parseInt(slotBreakDuration) const breakDurationInMinutes = parseInt(slotBreakDuration)
const initialStartTime = DateTime.fromISO(dayStartTime) const initialStartTime = DateTime.fromISO(dayStartTime)

View File

@@ -1,3 +1,4 @@
import { DevtoolsModule } from '@nestjs/devtools-integration'
import { ClerkModule } from './Clerk/clerk.module' import { ClerkModule } from './Clerk/clerk.module'
import { ConfigModule } from '@nestjs/config' import { ConfigModule } from '@nestjs/config'
import { GraphqlModule } from './Graphql/graphql.module' import { GraphqlModule } from './Graphql/graphql.module'
@@ -9,6 +10,10 @@ import { CronModule } from './Cron/cron.module'
@Module({ @Module({
imports: [ imports: [
DevtoolsModule.register({
http: process.env.NODE_ENV !== 'production',
port: 8000,
}),
ConfigModule.forRoot({ ConfigModule.forRoot({
isGlobal: true, isGlobal: true,
}), }),

View File

@@ -1,14 +1,6 @@
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
import * as _ from 'lodash' import _ from 'lodash'
import { import { DateTime, Settings, HourNumbers, MinuteNumbers, SecondNumbers, DayNumbers, WeekdayNumbers } from 'luxon'
DateTime,
Settings,
HourNumbers,
MinuteNumbers,
SecondNumbers,
DayNumbers,
WeekdayNumbers,
} from 'luxon'
Settings.defaultLocale = 'en-US' Settings.defaultLocale = 'en-US'
Settings.defaultZone = 'utc' Settings.defaultZone = 'utc'
@@ -52,22 +44,11 @@ export class DateTimeUtils {
return DateTime.fromISO(expires) < DateTime.now() return DateTime.fromISO(expires) < DateTime.now()
} }
static isOverlap( static isOverlap(startA: DateTime, endA: DateTime, startB: DateTime, endB: DateTime): boolean {
startA: DateTime, return this.getOverlapRange(startA, endA, startB, endB).start < this.getOverlapRange(startA, endA, startB, endB).end
endA: DateTime,
startB: DateTime,
endB: DateTime,
): boolean {
return (
this.getOverlapRange(startA, endA, startB, endB).start <
this.getOverlapRange(startA, endA, startB, endB).end
)
} }
static isOverlaps( static isOverlaps(listA: { start: DateTime; end: DateTime }[], listB: { start: DateTime; end: DateTime }[]): boolean {
listA: { start: DateTime; end: DateTime }[],
listB: { start: DateTime; end: DateTime }[],
): boolean {
for (const a of listA) { for (const a of listA) {
for (const b of listB) { for (const b of listB) {
if (this.isOverlap(a.start, a.end, b.start, b.end)) { if (this.isOverlap(a.start, a.end, b.start, b.end)) {

View File

@@ -10,39 +10,22 @@ import { readFileSync } from 'node:fs'
import { json } from 'express' import { json } from 'express'
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule) const app = await NestFactory.create(AppModule, {})
// load private key and public key // load private key and public key
const privateKey = readFileSync( const privateKey = readFileSync(path.join(__dirname, 'KeyStore', 'private_key.pem'), 'utf8')
path.join(__dirname, 'KeyStore', 'private_key.pem'), const publicKey = readFileSync(path.join(__dirname, 'KeyStore', 'public_key.pem'), 'utf8')
'utf8',
)
const publicKey = readFileSync(
path.join(__dirname, 'KeyStore', 'public_key.pem'),
'utf8',
)
// set private key and public key to env // set private key and public key to env
process.env.JWT_RS256_PRIVATE_KEY = privateKey process.env.JWT_RS256_PRIVATE_KEY = privateKey
process.env.JWT_RS256_PUBLIC_KEY = publicKey process.env.JWT_RS256_PUBLIC_KEY = publicKey
Logger.log( Logger.log(`Private key: ${privateKey.slice(0, 10).replace(/\n/g, '')}...`, 'Bootstrap')
`Private key: ${privateKey.slice(0, 10).replace(/\n/g, '')}...`, Logger.log(`Public key: ${publicKey.slice(0, 10).replace(/\n/g, '')}...`, 'Bootstrap')
'Bootstrap',
)
Logger.log(
`Public key: ${publicKey.slice(0, 10).replace(/\n/g, '')}...`,
'Bootstrap',
)
const corsOrigin = (process.env.CORS_ORIGIN ?? '').split(',') // split by comma to array const corsOrigin = (process.env.CORS_ORIGIN ?? '').split(',') // split by comma to array
app.enableCors({ app.enableCors({
origin: corsOrigin, origin: corsOrigin,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: [ allowedHeaders: ['Content-Type', '*', 'x-apollo-operation-name', 'x-session-id'],
'Content-Type',
'*',
'x-apollo-operation-name',
'x-session-id',
],
credentials: true, credentials: true,
}) })
@@ -63,8 +46,7 @@ async function bootstrap() {
get: { get: {
tags: ['GraphQL'], tags: ['GraphQL'],
summary: 'GraphQL Playground', summary: 'GraphQL Playground',
description: description: 'Access the GraphQL Playground to interact with the GraphQL API.',
'Access the GraphQL Playground to interact with the GraphQL API.',
responses: { responses: {
'200': { '200': {
description: 'GraphQL Playground', description: 'GraphQL Playground',
@@ -90,10 +72,7 @@ async function bootstrap() {
) )
// biome-ignore lint/suspicious/noExplicitAny: <explanation> // biome-ignore lint/suspicious/noExplicitAny: <explanation>
} catch (error: any) { } catch (error: any) {
Logger.error( Logger.error(`Error in file upload middleware: ${error.message}`, 'Bootstrap')
`Error in file upload middleware: ${error.message}`,
'Bootstrap',
)
// Optionally, you can handle the error further or rethrow it // Optionally, you can handle the error further or rethrow it
} }