From b8b51829118dbd6c7b04afe01f2441accf70d8c9 Mon Sep 17 00:00:00 2001 From: rafiarrafif Date: Fri, 23 May 2025 20:46:47 +0700 Subject: [PATCH] creating contenerization --- .dockerignore | 7 + .env.example | 36 + .gitignore | 8 +- Dockerfile | 24 + bun.lockb | Bin 63698 -> 81719 bytes docker-compose.yml | 28 + package.json | 9 +- .../20250523071439_initial/migration.sql | 758 ++++++++++++++++++ prisma/migrations/migration_lock.toml | 3 + scripts/create-example-env.ts | 52 ++ scripts/sync-routes.ts | 51 ++ src/index.ts | 2 +- src/routes.legacy.ts | 32 + src/routes.ts | 40 +- 14 files changed, 1013 insertions(+), 37 deletions(-) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 prisma/migrations/20250523071439_initial/migration.sql create mode 100644 prisma/migrations/migration_lock.toml create mode 100644 scripts/create-example-env.ts create mode 100644 scripts/sync-routes.ts create mode 100644 src/routes.legacy.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..84e935f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.git +.gitignore +Dockerfile* +docker-compose* +README.md \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..7449640 --- /dev/null +++ b/.env.example @@ -0,0 +1,36 @@ +APP_NAME=NounozCommunity +APP_ENV=development +PORT=3200 +API_KEY=nahidaa +ALLOWED_ORIGINS=www.nounoz.com,nounoz.com,localhost + +SALT_ROUNDS= +JWT_SECRET= +SESSION_EXPIRE= + +R2_ACCOUNT_ID= +R2_TOKEN_VALUE_ID= +R2_ACCESS_KEY_ID= +R2_SECRET_ACCESS_KEY= +R2_BUCKET_NAME= +R2_REGION= +R2_ENDPOINT= + +MAL_CLIENT_ID= +MAL_CLIENT_SECRET= + +SMTP_HOST= +SMTP_PORT= +SMTP_SECURE= +SMTP_USER= +SMTP_PASS= +SMTP_FROM= + +REDIS_HOST=localhost +REDIS_PORT=6379 +REDIS_PASSWORD= + +DATABASE_URL= +MONGODB_URI= + +# CREATE USER astofo WITH PASSWORD 'Nahidamylover*123'; \ No newline at end of file diff --git a/.gitignore b/.gitignore index d0624e2..f8ff2fe 100644 --- a/.gitignore +++ b/.gitignore @@ -8,11 +8,8 @@ # testing /coverage -# next.js -/.next/ -/out/ - # production +/dist /build # misc @@ -48,6 +45,9 @@ package-lock.json .env.test .env.production +# local docker compose files +docker-compose.override.yml + # compiled output server server.exe \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a355dee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +# --- Stage 1: Build --- +FROM oven/bun:1.1 AS builder + +WORKDIR /app + +COPY bun.lockb package.json ./ +RUN bun install + +COPY . . +RUN bunx prisma generate +RUN bun run build + + +# --- Stage 2: Production Runner --- +FROM oven/bun:1.1 AS runner + +WORKDIR /app + +COPY --from=builder /app ./ + +RUN bunx prisma migrate deploy +EXPOSE 3000 + +CMD [ "sh", "-c", "PORT=3000 ./dist/server" ] \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 53faf6ed546c964e53c5f5f39d7606bd9b7f6faa..f73c7b5d1b98a93918fc6f4cbcd585d79fa76588 100644 GIT binary patch delta 21538 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 KzYG^s-2Vr1ELmd! diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fac635c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +services: + app: + build: + context: . + dockerfile: Dockerfile + ports: + - "3003:3000" + depends_on: + - db + - redis + restart: unless-stopped + + db: + image: postgres:16-alpine + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: 868686 + POSTGRES_DB: nouzen + volumes: + - pgdata:/var/lib/postgresql/data + restart: unless-stopped + + redis: + image: redis:7.2-alpine + restart: unless-stopped + +volumes: + pgdata: diff --git a/package.json b/package.json index 3420871..c81d4df 100644 --- a/package.json +++ b/package.json @@ -3,19 +3,24 @@ "version": "1.0.50", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "build": "bun build ./src/app.ts --compile --target bun --minify-whitespace --minify-syntax --minify-identifiers --outfile server", - "dev": "bun run --watch src/index.ts" + "build": "bun build ./src/index.ts --compile --target bun --minify-whitespace --minify-syntax --minify-identifiers --outfile dist/server", + "dev": "bun run --watch src/index.ts", + "route:sync": "bun run ./scripts/sync-routes.ts", + "env:publish": "bun run ./scripts/create-example-env.ts" }, "dependencies": { "@prisma/client": "^6.7.0", "@types/bcrypt": "^5.0.2", "@types/jsonwebtoken": "^9.0.9", + "aws-sdk": "^2.1692.0", "bcrypt": "^5.1.1", "cookie": "^1.0.2", "elysia": "latest", "ioredis": "^5.6.1", "joi": "^17.13.3", "jsonwebtoken": "^9.0.2", + "mock-aws-s3": "^4.0.2", + "nock": "^14.0.4", "ua-parser-js": "^2.0.3" }, "devDependencies": { diff --git a/prisma/migrations/20250523071439_initial/migration.sql b/prisma/migrations/20250523071439_initial/migration.sql new file mode 100644 index 0000000..961e392 --- /dev/null +++ b/prisma/migrations/20250523071439_initial/migration.sql @@ -0,0 +1,758 @@ +-- CreateEnum +CREATE TYPE "AgeRating" AS ENUM ('G', 'PG', 'PG_13', 'R', 'R_plus', 'Rx'); + +-- CreateEnum +CREATE TYPE "MediaType" AS ENUM ('TV', 'ONA', 'OVA', 'Movie', 'Special', 'Music'); + +-- CreateEnum +CREATE TYPE "Source" AS ENUM ('original', 'manga', 'light_novel', 'game'); + +-- CreateEnum +CREATE TYPE "MediaOperation" AS ENUM ('create', 'update', 'delete'); + +-- CreateEnum +CREATE TYPE "UserGender" AS ENUM ('male', 'female'); + +-- CreateEnum +CREATE TYPE "AdultFiltering" AS ENUM ('hide', 'show', 'explicit'); + +-- CreateEnum +CREATE TYPE "AdultAlert" AS ENUM ('hide', 'show'); + +-- CreateEnum +CREATE TYPE "VideoQuality" AS ENUM ('Q2160', 'Q1440', 'Q1080', 'Q720', 'Q480', 'Q360', 'Q240', 'Q144'); + +-- CreateEnum +CREATE TYPE "UserNotificationState" AS ENUM ('info', 'warning', 'danger'); + +-- CreateEnum +CREATE TYPE "ReportStatus" AS ENUM ('pending', 'resolved', 'rejected'); + +-- CreateEnum +CREATE TYPE "ReportReason" AS ENUM ('sexualize', 'violent', 'explicit', 'hateful', 'political', 'racist', 'spam', 'other'); + +-- CreateEnum +CREATE TYPE "AccessStatus" AS ENUM ('private', 'selected', 'protected', 'public'); + +-- CreateEnum +CREATE TYPE "AccessScope" AS ENUM ('viewer', 'editor'); + +-- CreateEnum +CREATE TYPE "MediaReviewReaction" AS ENUM ('angry', 'sad', 'awesome', 'happy', 'sleepy', 'annoyed', 'disgusting', 'disappointed'); + +-- CreateEnum +CREATE TYPE "EmailPorpose" AS ENUM ('forgot_password', 'account_activation', 'account_notification', 'subscribtion'); + +-- CreateEnum +CREATE TYPE "TypeSystemNotification" AS ENUM ('component', 'popup', 'toast'); + +-- CreateTable +CREATE TABLE "medias" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "titleAlternative" JSONB NOT NULL, + "slug" TEXT NOT NULL, + "pictureMedium" TEXT NOT NULL, + "pictureLarge" TEXT NOT NULL, + "countryId" TEXT NOT NULL, + "isAiring" BOOLEAN NOT NULL DEFAULT false, + "isTba" BOOLEAN NOT NULL DEFAULT false, + "startAiring" TIMESTAMP(3) NOT NULL, + "endAiring" TIMESTAMP(3) NOT NULL, + "synopsis" TEXT NOT NULL, + "nfsw" BOOLEAN NOT NULL DEFAULT false, + "ageRating" "AgeRating" NOT NULL, + "mediaType" "MediaType" NOT NULL, + "source" "Source" NOT NULL, + "pendingUpload" BOOLEAN NOT NULL DEFAULT true, + "uploadedBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "medias_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "media_logs" ( + "id" TEXT NOT NULL, + "status" "MediaOperation" NOT NULL, + "approval" BOOLEAN NOT NULL DEFAULT false, + "proposedBy" TEXT NOT NULL, + "approvedBy" TEXT NOT NULL, + "mediaId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "media_logs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "genres" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "slug" VARCHAR(255) NOT NULL, + "malId" INTEGER NOT NULL, + "malUrl" VARCHAR(255) NOT NULL, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "genres_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "studios" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "slug" VARCHAR(255) NOT NULL, + "logoUrl" TEXT NOT NULL, + "colorHex" VARCHAR(10) NOT NULL, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "studios_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "countries" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "code" VARCHAR(5) NOT NULL, + "flag" VARCHAR(10) NOT NULL, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "countries_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "episodes" ( + "id" TEXT NOT NULL, + "mediaId" TEXT NOT NULL, + "episode" INTEGER NOT NULL, + "name" VARCHAR(255) NOT NULL, + "pictureThumbnail" TEXT NOT NULL, + "viewed" BIGINT NOT NULL DEFAULT 0, + "likes" BIGINT NOT NULL DEFAULT 0, + "dislikes" BIGINT NOT NULL DEFAULT 0, + "pendingUpload" BOOLEAN NOT NULL DEFAULT true, + "uploadedBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "episodes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "episode_likes" ( + "id" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "sessionId" TEXT NOT NULL, + "episodeId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "episode_likes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "videos" ( + "id" TEXT NOT NULL, + "episodeId" TEXT NOT NULL, + "serviceId" TEXT NOT NULL, + "code" VARCHAR(255) NOT NULL, + "pendingUpload" BOOLEAN NOT NULL DEFAULT true, + "uploadedBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "videos_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "video_services" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "domain" VARCHAR(255) NOT NULL, + "logo" TEXT, + "hexColor" VARCHAR(10) NOT NULL, + "endpointVideo" TEXT NOT NULL, + "endpointThumbnail" TEXT, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "video_services_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "users" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "username" VARCHAR(255) NOT NULL, + "email" TEXT NOT NULL, + "password" TEXT NOT NULL, + "birthDate" DATE, + "gender" "UserGender", + "phoneCC" INTEGER, + "phoneNumber" INTEGER, + "bioProfile" TEXT, + "profilePicture" TEXT, + "commentPicture" TEXT, + "preferenceId" TEXT, + "verifiedAt" TIMESTAMP(3), + "disabledAt" TIMESTAMP(3), + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "users_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "user_preferences" ( + "id" TEXT NOT NULL, + "langPreference" TEXT, + "adultFiltering" "AdultFiltering" NOT NULL DEFAULT 'hide', + "adultAlert" "AdultAlert" NOT NULL DEFAULT 'show', + "videoQuality" "VideoQuality" NOT NULL DEFAULT 'Q1080', + "serviceDefaultId" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "user_preferences_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "user_roles" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "primaryColor" VARCHAR(10), + "secondaryColor" VARCHAR(10), + "pictureImage" TEXT, + "badgeImage" TEXT, + "isSuperadmin" BOOLEAN NOT NULL DEFAULT false, + "canEditMedia" BOOLEAN NOT NULL DEFAULT false, + "canManageMedia" BOOLEAN NOT NULL DEFAULT false, + "canEditEpisodes" BOOLEAN NOT NULL DEFAULT false, + "canManageEpisodes" BOOLEAN NOT NULL DEFAULT false, + "canEditComment" BOOLEAN NOT NULL DEFAULT false, + "canManageComment" BOOLEAN NOT NULL DEFAULT false, + "canEditUser" BOOLEAN NOT NULL DEFAULT false, + "canManageUser" BOOLEAN NOT NULL DEFAULT false, + "canEditSystem" BOOLEAN NOT NULL DEFAULT false, + "canManageSystem" BOOLEAN NOT NULL DEFAULT false, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "user_roles_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "user_notifications" ( + "id" TEXT NOT NULL, + "title" VARCHAR(255) NOT NULL, + "content" TEXT NOT NULL, + "picture" TEXT NOT NULL, + "state" "UserNotificationState" NOT NULL, + "ctaLink" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "isReaded" BOOLEAN NOT NULL DEFAULT false, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "user_notifications_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "user_sessions" ( + "id" TEXT NOT NULL, + "isAuthenticated" BOOLEAN NOT NULL DEFAULT false, + "userId" TEXT NOT NULL, + "deviceType" VARCHAR(255) NOT NULL, + "deviceOs" VARCHAR(255) NOT NULL, + "deviceIp" VARCHAR(255) NOT NULL, + "isOnline" BOOLEAN NOT NULL DEFAULT false, + "lastOnline" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "validUntil" TIMESTAMP(3) NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "user_sessions_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "user_logs" ( + "id" TEXT NOT NULL, + "title" VARCHAR(255) NOT NULL, + "notes" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "sessionId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "user_logs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "collections" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "ownerId" TEXT NOT NULL, + "accessStatus" "AccessStatus" NOT NULL DEFAULT 'private', + "password" VARCHAR(255), + "accessScope" "AccessScope" NOT NULL DEFAULT 'viewer', + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "collections_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "watch_histories" ( + "id" TEXT NOT NULL, + "episodeId" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "sessionId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "watch_histories_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "movie_reviews" ( + "id" TEXT NOT NULL, + "mediaId" TEXT NOT NULL, + "rating" INTEGER NOT NULL, + "title" VARCHAR(255) NOT NULL, + "text" TEXT NOT NULL, + "reaction" "MediaReviewReaction" NOT NULL, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "movie_reviews_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "comments" ( + "id" TEXT NOT NULL, + "episodeId" TEXT NOT NULL, + "text" TEXT NOT NULL, + "isParent" BOOLEAN NOT NULL DEFAULT false, + "parentId" TEXT, + "userId" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "comments_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "comment_likes" ( + "id" TEXT NOT NULL, + "commentId" TEXT NOT NULL, + "userLiked" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "comment_likes_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "comment_reports" ( + "id" TEXT NOT NULL, + "userReporter" TEXT NOT NULL, + "commentReported" TEXT NOT NULL, + "isSupervisorReport" BOOLEAN NOT NULL DEFAULT false, + "reason" "ReportReason" NOT NULL, + "status" "ReportStatus" NOT NULL, + "description" VARCHAR(255) NOT NULL, + "approvedBy" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "comment_reports_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "languages" ( + "id" TEXT NOT NULL, + "name" VARCHAR(255) NOT NULL, + "code" VARCHAR(5) NOT NULL, + "countryFlag" VARCHAR(10) NOT NULL, + "fileLocation" TEXT NOT NULL, + "craetedBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "languages_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "email_system_accounts" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "host" VARCHAR(255) NOT NULL, + "port" INTEGER NOT NULL, + "secure" BOOLEAN NOT NULL, + "email" VARCHAR(255) NOT NULL, + "username" VARCHAR(255) NOT NULL, + "password" VARCHAR(255) NOT NULL, + "purpose" "EmailPorpose" NOT NULL, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "email_system_accounts_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "email_system_histories" ( + "id" TEXT NOT NULL, + "purpose" "EmailPorpose" NOT NULL, + "fromEmail" TEXT NOT NULL, + "toEmail" TEXT NOT NULL, + "userRelated" TEXT NOT NULL, + "title" VARCHAR(255) NOT NULL, + "htmlContent" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "email_system_histories_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "system_preferences" ( + "id" TEXT NOT NULL, + "key" VARCHAR(225) NOT NULL, + "value" VARCHAR(225) NOT NULL, + "description" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "system_preferences_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "system_notifications" ( + "id" TEXT NOT NULL, + "type" "TypeSystemNotification" NOT NULL, + "componentName" VARCHAR(255), + "popupImage" TEXT, + "titleToast" VARCHAR(255), + "contentToast" TEXT, + "createdBy" TEXT NOT NULL, + "deletedAt" TIMESTAMP(3), + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "system_notifications_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "system_logs" ( + "id" TEXT NOT NULL, + "title" VARCHAR(255) NOT NULL, + "notes" TEXT NOT NULL, + "relatedUser" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "system_logs_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_MediaStudios" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_MediaStudios_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateTable +CREATE TABLE "_MediaGenres" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_MediaGenres_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateTable +CREATE TABLE "_UserFavoriteGenres" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_UserFavoriteGenres_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateTable +CREATE TABLE "_UserShowContries" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_UserShowContries_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateTable +CREATE TABLE "_UserRoles" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_UserRoles_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateTable +CREATE TABLE "_MediaCollections" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_MediaCollections_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateTable +CREATE TABLE "_UserSelectedSharingCollention" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_UserSelectedSharingCollention_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateIndex +CREATE UNIQUE INDEX "video_services_name_key" ON "video_services"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "users_username_key" ON "users"("username"); + +-- CreateIndex +CREATE UNIQUE INDEX "users_email_key" ON "users"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "users_preferenceId_key" ON "users"("preferenceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "user_roles_name_key" ON "user_roles"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "languages_code_key" ON "languages"("code"); + +-- CreateIndex +CREATE UNIQUE INDEX "email_system_accounts_name_key" ON "email_system_accounts"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "email_system_accounts_email_key" ON "email_system_accounts"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "email_system_accounts_username_key" ON "email_system_accounts"("username"); + +-- CreateIndex +CREATE INDEX "_MediaStudios_B_index" ON "_MediaStudios"("B"); + +-- CreateIndex +CREATE INDEX "_MediaGenres_B_index" ON "_MediaGenres"("B"); + +-- CreateIndex +CREATE INDEX "_UserFavoriteGenres_B_index" ON "_UserFavoriteGenres"("B"); + +-- CreateIndex +CREATE INDEX "_UserShowContries_B_index" ON "_UserShowContries"("B"); + +-- CreateIndex +CREATE INDEX "_UserRoles_B_index" ON "_UserRoles"("B"); + +-- CreateIndex +CREATE INDEX "_MediaCollections_B_index" ON "_MediaCollections"("B"); + +-- CreateIndex +CREATE INDEX "_UserSelectedSharingCollention_B_index" ON "_UserSelectedSharingCollention"("B"); + +-- AddForeignKey +ALTER TABLE "medias" ADD CONSTRAINT "medias_countryId_fkey" FOREIGN KEY ("countryId") REFERENCES "countries"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "medias" ADD CONSTRAINT "medias_uploadedBy_fkey" FOREIGN KEY ("uploadedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_proposedBy_fkey" FOREIGN KEY ("proposedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_approvedBy_fkey" FOREIGN KEY ("approvedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "media_logs" ADD CONSTRAINT "media_logs_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "genres" ADD CONSTRAINT "genres_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "studios" ADD CONSTRAINT "studios_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "countries" ADD CONSTRAINT "countries_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "episodes" ADD CONSTRAINT "episodes_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "episodes" ADD CONSTRAINT "episodes_uploadedBy_fkey" FOREIGN KEY ("uploadedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "episode_likes" ADD CONSTRAINT "episode_likes_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "videos" ADD CONSTRAINT "videos_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "videos" ADD CONSTRAINT "videos_serviceId_fkey" FOREIGN KEY ("serviceId") REFERENCES "video_services"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "videos" ADD CONSTRAINT "videos_uploadedBy_fkey" FOREIGN KEY ("uploadedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "video_services" ADD CONSTRAINT "video_services_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "users" ADD CONSTRAINT "users_preferenceId_fkey" FOREIGN KEY ("preferenceId") REFERENCES "user_preferences"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_langPreference_fkey" FOREIGN KEY ("langPreference") REFERENCES "languages"("code") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_serviceDefaultId_fkey" FOREIGN KEY ("serviceDefaultId") REFERENCES "video_services"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_notifications" ADD CONSTRAINT "user_notifications_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_sessions" ADD CONSTRAINT "user_sessions_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_logs" ADD CONSTRAINT "user_logs_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "user_logs" ADD CONSTRAINT "user_logs_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "collections" ADD CONSTRAINT "collections_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_id_fkey" FOREIGN KEY ("id") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "watch_histories" ADD CONSTRAINT "watch_histories_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "user_sessions"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "movie_reviews" ADD CONSTRAINT "movie_reviews_mediaId_fkey" FOREIGN KEY ("mediaId") REFERENCES "medias"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "movie_reviews" ADD CONSTRAINT "movie_reviews_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comments" ADD CONSTRAINT "comments_episodeId_fkey" FOREIGN KEY ("episodeId") REFERENCES "episodes"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comments" ADD CONSTRAINT "comments_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "comments"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comments" ADD CONSTRAINT "comments_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comment_likes" ADD CONSTRAINT "comment_likes_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "comments"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comment_likes" ADD CONSTRAINT "comment_likes_userLiked_fkey" FOREIGN KEY ("userLiked") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_userReporter_fkey" FOREIGN KEY ("userReporter") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "comment_reports" ADD CONSTRAINT "comment_reports_approvedBy_fkey" FOREIGN KEY ("approvedBy") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "languages" ADD CONSTRAINT "languages_craetedBy_fkey" FOREIGN KEY ("craetedBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "email_system_accounts" ADD CONSTRAINT "email_system_accounts_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "email_system_histories" ADD CONSTRAINT "email_system_histories_userRelated_fkey" FOREIGN KEY ("userRelated") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "system_notifications" ADD CONSTRAINT "system_notifications_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "system_logs" ADD CONSTRAINT "system_logs_relatedUser_fkey" FOREIGN KEY ("relatedUser") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MediaStudios" ADD CONSTRAINT "_MediaStudios_A_fkey" FOREIGN KEY ("A") REFERENCES "medias"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MediaStudios" ADD CONSTRAINT "_MediaStudios_B_fkey" FOREIGN KEY ("B") REFERENCES "studios"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MediaGenres" ADD CONSTRAINT "_MediaGenres_A_fkey" FOREIGN KEY ("A") REFERENCES "genres"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MediaGenres" ADD CONSTRAINT "_MediaGenres_B_fkey" FOREIGN KEY ("B") REFERENCES "medias"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserFavoriteGenres" ADD CONSTRAINT "_UserFavoriteGenres_A_fkey" FOREIGN KEY ("A") REFERENCES "genres"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserFavoriteGenres" ADD CONSTRAINT "_UserFavoriteGenres_B_fkey" FOREIGN KEY ("B") REFERENCES "user_preferences"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserShowContries" ADD CONSTRAINT "_UserShowContries_A_fkey" FOREIGN KEY ("A") REFERENCES "countries"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserShowContries" ADD CONSTRAINT "_UserShowContries_B_fkey" FOREIGN KEY ("B") REFERENCES "user_preferences"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserRoles" ADD CONSTRAINT "_UserRoles_A_fkey" FOREIGN KEY ("A") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserRoles" ADD CONSTRAINT "_UserRoles_B_fkey" FOREIGN KEY ("B") REFERENCES "user_roles"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MediaCollections" ADD CONSTRAINT "_MediaCollections_A_fkey" FOREIGN KEY ("A") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_MediaCollections" ADD CONSTRAINT "_MediaCollections_B_fkey" FOREIGN KEY ("B") REFERENCES "medias"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserSelectedSharingCollention" ADD CONSTRAINT "_UserSelectedSharingCollention_A_fkey" FOREIGN KEY ("A") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_UserSelectedSharingCollention" ADD CONSTRAINT "_UserSelectedSharingCollention_B_fkey" FOREIGN KEY ("B") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml new file mode 100644 index 0000000..044d57c --- /dev/null +++ b/prisma/migrations/migration_lock.toml @@ -0,0 +1,3 @@ +# Please do not edit this file manually +# It should be added in your version-control system (e.g., Git) +provider = "postgresql" diff --git a/scripts/create-example-env.ts b/scripts/create-example-env.ts new file mode 100644 index 0000000..32e7423 --- /dev/null +++ b/scripts/create-example-env.ts @@ -0,0 +1,52 @@ +import fs from "fs"; +import path from "path"; + +const PRESERVED_KEYS = [ + "APP_NAME", + "APP_ENV", + "PORT", + "API_KEY", + "ALLOWED_ORIGINS", + "REDIS_HOST", + "REDIS_PORT", +]; + +try { + const envPath = path.join(process.cwd(), ".env"); + const envExamplePath = path.join(process.cwd(), ".env.example"); + + if (!fs.existsSync(envPath)) { + console.error(`.env file not found at ${envPath}`); + process.exit(1); + } + + const envContent = fs.readFileSync(envPath, "utf-8"); + + const lines = envContent.split("\n"); + const processedLines = lines.map((line) => { + const trimmedLine = line.trim(); + + if (trimmedLine.startsWith("#") || trimmedLine === "") { + return line; + } + + const delimeterIndex = line.indexOf("="); + if (delimeterIndex === -1) { + return line; + } + + const key = line.substring(0, delimeterIndex).trim(); + const value = line.substring(delimeterIndex + 1).trim(); + + if (PRESERVED_KEYS.includes(key)) { + return `${key}=${value}`; + } + return `${key}=`; + }); + + fs.writeFileSync(envExamplePath, processedLines.join("\n")); + console.log("File .env.example berhasil diperbarui!"); +} catch (error) { + console.error("Error while creating .env.example:", error); + process.exit(1); +} diff --git a/scripts/sync-routes.ts b/scripts/sync-routes.ts new file mode 100644 index 0000000..03aa674 --- /dev/null +++ b/scripts/sync-routes.ts @@ -0,0 +1,51 @@ +/** + * Dynamically aggregates Elysia sub-routes from modular directories into a central registry. + * + * @behavior + * 1. Scans `./src/modules` for valid Elysia modules + * 2. Generates imports and `.use()` calls for each module + * 3. Writes composed routes to `./src/routes.ts` + * + * @requirements + * - Module directories must contain an export named `[folderName]Module` + * (e.g., `userModule` for `/user` folder) + * - Modules must export an Elysia instance + * + * @outputfile ./src/routes.ts + * @examplegenerated + * ```ts + * import Elysia from "elysia"; + * import { userModule } from './modules/user'; + * import { authModule } from './modules/auth'; + * + * const routes = new Elysia() + * .use(userModule) + * .use(authModule); + * + * export { routes }; + * ``` + */ +import { writeFileSync, readdirSync } from "fs"; +import { join } from "path"; + +const modulesPath = "./src/modules"; +const importLines: string[] = []; +const useLines: string[] = []; + +for (const folder of readdirSync(modulesPath, { withFileTypes: true })) { + if (folder.isDirectory()) { + const varName = `${folder.name}Module`; + importLines.push(`import {${varName}} from './modules/${folder.name}';`); + useLines.push(`.use(${varName})`); + } +} + +const content = ` +import Elysia from "elysia"; +${importLines.join("\n")} +const routes = new Elysia() +${useLines.join("\n")}; +export { routes }; +`; + +writeFileSync(join(modulesPath, "../routes.ts"), content); diff --git a/src/index.ts b/src/index.ts index 4db0e8f..d25a260 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import { Elysia } from "elysia"; import { routes } from "./routes"; -const app = new Elysia().use(routes).listen(3200); +const app = new Elysia().use(routes).listen(process.env.PORT || 3000); console.log( `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` diff --git a/src/routes.legacy.ts b/src/routes.legacy.ts new file mode 100644 index 0000000..07f8565 --- /dev/null +++ b/src/routes.legacy.ts @@ -0,0 +1,32 @@ +import Elysia from "elysia"; +import { pathToFileURL } from "bun"; +import { readdirSync } from "fs"; +import { join } from "path"; + +const routes = new Elysia(); + +const modulesPath = join(__dirname, "./modules"); + +for (const folder of readdirSync(modulesPath, { withFileTypes: true })) { + if (folder.isDirectory()) { + const moduleIndex = join(modulesPath, folder.name, "index.ts"); + + try { + const module = await import(pathToFileURL(moduleIndex).href); + + const mod = Object.values(module).find( + (m): m is Elysia => m instanceof Elysia + ); + + if (mod) { + routes.use(mod); + } + } catch (error) { + console.warn( + `Module ${folder.name} not found. Please check the module path or name: ${error}` + ); + } + } +} + +export { routes }; diff --git a/src/routes.ts b/src/routes.ts index 07f8565..526fc3f 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -1,32 +1,12 @@ + import Elysia from "elysia"; -import { pathToFileURL } from "bun"; -import { readdirSync } from "fs"; -import { join } from "path"; - -const routes = new Elysia(); - -const modulesPath = join(__dirname, "./modules"); - -for (const folder of readdirSync(modulesPath, { withFileTypes: true })) { - if (folder.isDirectory()) { - const moduleIndex = join(modulesPath, folder.name, "index.ts"); - - try { - const module = await import(pathToFileURL(moduleIndex).href); - - const mod = Object.values(module).find( - (m): m is Elysia => m instanceof Elysia - ); - - if (mod) { - routes.use(mod); - } - } catch (error) { - console.warn( - `Module ${folder.name} not found. Please check the module path or name: ${error}` - ); - } - } -} - +import {authModule} from './modules/auth'; +import {userModule} from './modules/user'; +import {userRoleModule} from './modules/userRole'; +import {userSessionModule} from './modules/userSession'; +const routes = new Elysia() +.use(authModule) +.use(userModule) +.use(userRoleModule) +.use(userSessionModule); export { routes };