diff --git a/.dockerignore b/.dockerignore index ecd919cd5..efac14f5e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -31,4 +31,5 @@ dist migrations/ config/ build.ts -tsconfig.json \ No newline at end of file +tsconfig.json +drizzle.config.ts diff --git a/.github/workflows/dev-image.yml b/.github/workflows/dev-image.yml new file mode 100644 index 000000000..48880cb6d --- /dev/null +++ b/.github/workflows/dev-image.yml @@ -0,0 +1,166 @@ +name: Create Dev-Image + +on: + pull_request_target: + branches: + - main + - dev + types: + - opened + - synchronize + - reopened + +concurrency: + group: pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + +env: + TAG_URL: https://hub.docker.com/r/${{ vars.DOCKER_HUB_REPO }}/tags + TAG: ${{ vars.DOCKER_HUB_REPO }}:dev-pr${{ github.event.pull_request.number }} + TAG_PG: ${{ vars.DOCKER_HUB_REPO }}:postgresql-dev-pr${{ github.event.pull_request.number }} + +jobs: + build-w: + if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + runs-on: ubuntu-latest + environment: build-dev + + steps: + - name: Checkout PR code + uses: actions/checkout@v6 + with: + ref: refs/pull/${{github.event.pull_request.number}}/merge + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image SQLITE + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64 + push: true + tags: ${{ env.TAG }} + build-args: | + DATABASE=sqlite + BUILD=enterprise + cache-from: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache + cache-to: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache,mode=max + + - name: Build and push Docker image PG + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64 + push: true + tags: ${{ env.TAG_PG }} + build-args: | + DATABASE=sqlite + BUILD=enterprise + cache-from: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache-pg + cache-to: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache-pg,mode=max + + - uses: actions/github-script@v8 + with: + script: | + const repoUrl = process.env.TAG_URL; + const tag = process.env.TAG; + const tagPg = process.env.TAG_PG; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `> [!WARNING] + > This image may contain unchecked and breaking changes. Only use on own risk. + + 👋 Thanks for your PR! + Dev images for this PR are now available on [docker hub](${repoUrl}): + + **SQLITE Image:** + \`\`\` + ${tag} + \`\`\` + + **Postgresql Image:** + \`\`\` + ${tagPg} + \`\`\`` + }) + build-wo: + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + runs-on: ubuntu-latest + + steps: + - name: Checkout PR code + uses: actions/checkout@v6 + with: + ref: refs/pull/${{github.event.pull_request.number}}/merge + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USERNAME }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build and push Docker image SQLITE + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64 + push: true + tags: ${{ env.TAG }} + build-args: | + DATABASE=sqlite + BUILD=enterprise + cache-from: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache + cache-to: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache,mode=max + + - name: Build and push Docker image PG + uses: docker/build-push-action@v6 + with: + context: . + platforms: linux/amd64 + push: true + tags: ${{ env.TAG_PG }} + build-args: | + DATABASE=sqlite + BUILD=enterprise + cache-from: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache-pg + cache-to: type=registry,ref=${{ vars.DOCKER_HUB_REPO }}:buildcache-pg,mode=max + + - uses: actions/github-script@v8 + with: + script: | + const repoUrl = process.env.TAG_URL; + const tag = process.env.TAG; + const tagPg = process.env.TAG_PG; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `> [!WARNING] + > This image may contain unchecked and breaking changes. Only use on own risk. + + 👋 Thanks for your PR! + Dev images for this PR are now available on [docker hub](${repoUrl}): + + **SQLITE Image:** + \`\`\` + ${tag} + \`\`\` + + **Postgresql Image:** + \`\`\` + ${tagPg} + \`\`\`` + }) + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 58b4662ce..3bb232a4d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: - name: Install Node uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0 with: - node-version: '22' + node-version: '24' - name: Copy config file run: cp config/config.example.yml config/config.yml @@ -34,10 +34,10 @@ jobs: run: npm run set:oss - name: Generate database migrations - run: npm run db:sqlite:generate + run: npm run db:generate - name: Apply database migrations - run: npm run db:sqlite:push + run: npm run db:sqlite - name: Test with tsc run: npx tsc --noEmit @@ -64,9 +64,6 @@ jobs: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Copy config file - run: cp config/config.example.yml config/config.yml - - name: Build Docker image sqlite run: make dev-build-sqlite @@ -76,8 +73,5 @@ jobs: - name: Checkout repository uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - - name: Copy config file - run: cp config/config.example.yml config/config.yml - - name: Build Docker image pg run: make dev-build-pg diff --git a/.gitignore b/.gitignore index df9179a43..1067dc2ce 100644 --- a/.gitignore +++ b/.gitignore @@ -51,4 +51,5 @@ dynamic/ scratch/ tsconfig.json hydrateSaas.ts -CLAUDE.md \ No newline at end of file +CLAUDE.md +drizzle.config.ts diff --git a/Dockerfile b/Dockerfile index 487fa0336..215884e48 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,67 +1,76 @@ -FROM node:24-alpine AS builder +FROM dhi.io/node:24-alpine3.23-dev AS builder WORKDIR /app ARG BUILD=oss ARG DATABASE=sqlite -RUN apk add --no-cache python3 make g++ +# Install build dependencies +RUN apk add --no-cache \ + g++ \ + make \ + python3 -# COPY package.json package-lock.json ./ +# Copy dependency files first for better caching COPY package*.json ./ RUN npm ci +# Copy source files COPY . . +# Build application RUN if [ "$BUILD" = "oss" ]; then rm -rf server/private; fi && \ npm run set:$DATABASE && \ npm run set:$BUILD && \ - npm run db:$DATABASE:generate && \ - npm run build:$DATABASE && \ - npm run build:cli + npm run db:generate && \ + npm run build && \ + npm run build:cli && \ + test -f dist/server.mjs -# test to make sure the build output is there and error if not -RUN test -f dist/server.mjs +FROM dhi.io/node:24-alpine3.23-dev AS runner -# Prune dev dependencies and clean up to prepare for copy to runner -RUN npm prune --omit=dev && npm cache clean --force +WORKDIR /app + +# Install runtime dependencies and install production node_modules +RUN apk add --no-cache \ + g++ \ + make \ + python3 \ + tzdata + +COPY package*.json ./ +RUN npm ci --omit=dev && \ + npm cache clean --force -FROM node:24-alpine AS runner +FROM dhi.io/node:24-alpine3.23 # OCI Image Labels - Build Args for dynamic values ARG VERSION="dev" ARG REVISION="" ARG CREATED="" ARG LICENSE="AGPL-3.0" - -# Derive title and description based on BUILD type ARG IMAGE_TITLE="Pangolin" ARG IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" WORKDIR /app -# Only curl and tzdata needed at runtime - no build tools! -RUN apk add --no-cache curl tzdata - -# Copy pre-built node_modules from builder (already pruned to production only) -# This includes the compiled native modules like better-sqlite3 -COPY --from=builder /app/node_modules ./node_modules -COPY --from=builder /app/.next/standalone ./ -COPY --from=builder /app/.next/static ./.next/static -COPY --from=builder /app/dist ./dist -COPY --from=builder /app/server/migrations ./dist/init -COPY --from=builder /app/package.json ./package.json +# Copy pre-built node_modules and timezone data from runner stage +COPY --from=runner /app/node_modules ./node_modules +COPY --from=runner /usr/share/zoneinfo /usr/share/zoneinfo -COPY ./cli/wrapper.sh /usr/local/bin/pangctl -RUN chmod +x /usr/local/bin/pangctl ./dist/cli.mjs +# Copy built artifacts from builder stage +COPY --chown=node:node --from=builder /app/.next/standalone ./ +COPY --chown=node:node --from=builder /app/.next/static ./.next/static +COPY --chown=node:node --from=builder /app/dist ./dist +COPY --chown=node:node --from=builder /app/server/migrations ./dist/init -COPY server/db/names.json ./dist/names.json -COPY server/db/ios_models.json ./dist/ios_models.json -COPY server/db/mac_models.json ./dist/mac_models.json -COPY public ./public +COPY --chown=node:node --chmod=+x ./cli/wrapper.sh /usr/local/bin/pangctl +COPY --chown=node:node server/db/names.json server/db/*_models.json ./dist/ +COPY --chown=node:node public ./public +COPY --chown=node:node --chmod=+x entrypoint.mjs /entrypoint.mjs +COPY --chown=node:node --chmod=+x healthcheck.mjs /healthcheck.mjs # OCI Image Labels -# https://github.com/opencontainers/image-spec/blob/main/annotations.md LABEL org.opencontainers.image.source="https://github.com/fosrl/pangolin" \ org.opencontainers.image.url="https://github.com/fosrl/pangolin" \ org.opencontainers.image.documentation="https://docs.pangolin.net" \ @@ -73,4 +82,7 @@ LABEL org.opencontainers.image.source="https://github.com/fosrl/pangolin" \ org.opencontainers.image.revision="${REVISION}" \ org.opencontainers.image.created="${CREATED}" -CMD ["npm", "run", "start"] +# Run as non-root user +USER node + +ENTRYPOINT ["node", "/entrypoint.mjs"] diff --git a/Dockerfile.bak b/Dockerfile.bak new file mode 100644 index 000000000..219ef95b4 --- /dev/null +++ b/Dockerfile.bak @@ -0,0 +1,73 @@ +FROM dhi.io/node:24-alpine3.23-dev AS builder + +WORKDIR /app + +ARG BUILD=oss +ARG DATABASE=sqlite + +RUN apk add --no-cache python3 make g++ + +# COPY package.json package-lock.json ./ +COPY package*.json ./ +RUN npm ci + +COPY . . + +RUN if [ "$BUILD" = "oss" ]; then rm -rf server/private; fi && \ + npm run set:$DATABASE && \ + npm run set:$BUILD && \ + npm run db:$DATABASE:generate && \ + npm run build:$DATABASE && \ + npm run build:cli && \ + test -f dist/server.mjs + +FROM dhi.io/node:24-alpine3.23-dev AS runner + +RUN apk add --no-cache python3 make g++ tzdata + +COPY package*.json ./ +RUN npm ci --omit=dev && npm cache clean --force + +FROM dhi.io/node:24-alpine3.23 + +# OCI Image Labels - Build Args for dynamic values +ARG VERSION="dev" +ARG REVISION="" +ARG CREATED="" +ARG LICENSE="AGPL-3.0" + +# Derive title and description based on BUILD type +ARG IMAGE_TITLE="Pangolin" +ARG IMAGE_DESCRIPTION="Identity-aware VPN and proxy for remote access to anything, anywhere" + +WORKDIR /app + +# Copy pre-built node_modules from builder (already pruned to production only) +# This includes the compiled native modules like better-sqlite3 +COPY --from=runner /app/node_modules ./node_modules +COPY --from=runner /usr/share/zoneinfo /usr/share/zoneinfo + +COPY --chown=node:node --from=builder /app/.next/standalone ./ +COPY --chown=node:node --from=builder /app/.next/static ./.next/static +COPY --chown=node:node --from=builder --chmod=+x /app/dist ./dist +COPY --chown=node:node --from=builder /app/server/migrations ./dist/init + +COPY --chown=node:node --chmod=+x ./cli/wrapper.sh /usr/local/bin/pangctl + +COPY --chown=node:node server/db/names.json server/db/*_models.json ./dist/ +COPY --chown=node:node public ./public + +# OCI Image Labels +# https://github.com/opencontainers/image-spec/blob/main/annotations.md +LABEL org.opencontainers.image.source="https://github.com/fosrl/pangolin" \ + org.opencontainers.image.url="https://github.com/fosrl/pangolin" \ + org.opencontainers.image.documentation="https://docs.pangolin.net" \ + org.opencontainers.image.vendor="Fossorial" \ + org.opencontainers.image.licenses="${LICENSE}" \ + org.opencontainers.image.title="${IMAGE_TITLE}" \ + org.opencontainers.image.description="${IMAGE_DESCRIPTION}" \ + org.opencontainers.image.version="${VERSION}" \ + org.opencontainers.image.revision="${REVISION}" \ + org.opencontainers.image.created="${CREATED}" + +CMD ["npm", "run", "start"] diff --git a/Makefile b/Makefile index da31b6e27..c6edc7305 100644 --- a/Makefile +++ b/Makefile @@ -521,3 +521,17 @@ test: clean: docker rmi pangolin + +test-local: + cp config/config.example.yml config/config.yml + npm run set:oss + npm run set:sqlite + npm run db:sqlite:generate + npm run db:sqlite:push + - npx tsc --noEmit + - docker build --build-arg DATABASE=pg -t fosrl/pangolin:postgresql-latest . + - docker build --build-arg DATABASE=sqlite -t fosrl/pangolin:latest . + npm run set:saas + - npx tsc --noEmit + - docker build --build-arg DATABASE=pg -t fosrl/pangolin:postgresql-saas-latest . + - docker build --build-arg DATABASE=sqlite -t fosrl/pangolin:saas-latest . diff --git a/entrypoint.mjs b/entrypoint.mjs new file mode 100644 index 000000000..63ac84683 --- /dev/null +++ b/entrypoint.mjs @@ -0,0 +1,62 @@ +import { spawn } from 'child_process'; + +// Set environment variables for the application +process.env.ENVIRONMENT = 'prod'; + +async function runMigrations() { + return new Promise((resolve, reject) => { + console.log('Running migrations...'); + const migrations = spawn('node', ['/app/dist/migrations.mjs']); + + migrations.on('exit', (code) => { + if (code === 0) { + console.log('Migrations completed successfully'); + resolve(); + } else { + console.error(`Migrations failed with exit code ${code}`); + reject(new Error(`Migrations exited with code ${code}`)); + } + }); + + migrations.on('error', (err) => { + console.error(`Failed to start migrations: ${err}`); + reject(err); + }); + }); +} + +process.env.NODE_ENV = 'development'; + +async function startServer() { + return new Promise((resolve, reject) => { + console.log('Starting server with source maps enabled...'); + const server = spawn('node', ['--enable-source-maps', '/app/dist/server.mjs'], { + stdio: 'inherit' + }); + + server.on('exit', (code) => { + if (code === 0) { + resolve(); + } else { + reject(new Error(`Server exited with code ${code}`)); + } + }); + + server.on('error', (err) => { + console.error(`Failed to start server: ${err}`); + reject(err); + }); + }); +} + +async function main() { + try { + await runMigrations(); + await startServer(); + } catch (error) { + console.error('Fatal error:', error.message); + process.exit(1); + } +} + +main(); \ No newline at end of file diff --git a/esbuild.mjs b/esbuild.mjs index 0157c34ac..ce613bd96 100644 --- a/esbuild.mjs +++ b/esbuild.mjs @@ -6,6 +6,16 @@ import path from "path"; import fs from "fs"; // import { glob } from "glob"; +// Read default build type from server/build.ts (TypeScript file won't import under ESM) +let build = "oss"; +try { + const buildFile = fs.readFileSync(path.resolve("server/build.ts"), "utf8"); + const m = buildFile.match(/export\s+const\s+build\s*=\s*["'](oss|saas|enterprise)["']/); + if (m) build = m[1]; +} catch (err) { + // fallback to "oss" if file missing or unreadable +} + const banner = ` // patch __dirname // import { fileURLToPath } from "url"; @@ -37,7 +47,7 @@ const argv = yargs(hideBin(process.argv)) describe: "Build type (oss, saas, enterprise)", type: "string", choices: ["oss", "saas", "enterprise"], - default: "oss" + default: build }) .help() .alias("help", "h").argv; @@ -275,7 +285,7 @@ esbuild }) ], sourcemap: "inline", - target: "node22" + target: "node24" }) .then((result) => { // Check if there were any errors in the build result diff --git a/healthcheck.mjs b/healthcheck.mjs new file mode 100644 index 000000000..7f97d14fa --- /dev/null +++ b/healthcheck.mjs @@ -0,0 +1,5 @@ +import http from 'http'; +const req = http.get('http://localhost:3001/api/v1/', (res) => { + process.exit(res.statusCode === 200 ? 0 : 1); +}); +req.on('error', () => process.exit(1)); diff --git a/messages/de-DE.json b/messages/de-DE.json index e0c85879d..cbf8b4d3f 100644 --- a/messages/de-DE.json +++ b/messages/de-DE.json @@ -97,7 +97,7 @@ "siteGeneralDescription": "Allgemeine Einstellungen für diesen Standort konfigurieren", "siteSettingDescription": "Standorteinstellungen konfigurieren", "siteSetting": "{siteName} Einstellungen", - "siteNewtTunnel": "Neuer Standort (empfohlen)", + "siteNewtTunnel": "Newt Standort (empfohlen)", "siteNewtTunnelDescription": "Einfachster Weg, einen Einstiegspunkt in jedes Netzwerk zu erstellen. Keine zusätzliche Einrichtung.", "siteWg": "Einfacher WireGuard Tunnel", "siteWgDescription": "Verwende jeden WireGuard-Client, um einen Tunnel einzurichten. Manuelles NAT-Setup erforderlich.", @@ -107,7 +107,7 @@ "siteSeeAll": "Alle Standorte anzeigen", "siteTunnelDescription": "Legen Sie fest, wie Sie sich mit dem Standort verbinden möchten", "siteNewtCredentials": "Zugangsdaten", - "siteNewtCredentialsDescription": "So wird sich die Seite mit dem Server authentifizieren", + "siteNewtCredentialsDescription": "So wird sich der Standort mit dem Server authentifizieren", "remoteNodeCredentialsDescription": "So wird sich der entfernte Node mit dem Server authentifizieren", "siteCredentialsSave": "Anmeldedaten speichern", "siteCredentialsSaveDescription": "Du kannst das nur einmal sehen. Stelle sicher, dass du es an einen sicheren Ort kopierst.", @@ -2503,7 +2503,7 @@ "deviceModel": "Gerätemodell", "serialNumber": "Seriennummer", "hostname": "Hostname", - "firstSeen": "Erster Blick", + "firstSeen": "Zuerst gesehen", "lastSeen": "Zuletzt gesehen", "biometricsEnabled": "Biometrie aktiviert", "diskEncrypted": "Festplatte verschlüsselt", diff --git a/package.json b/package.json index 70c9ab321..2458616cb 100644 --- a/package.json +++ b/package.json @@ -13,22 +13,19 @@ "scripts": { "dev": "NODE_ENV=development ENVIRONMENT=dev tsx watch server/index.ts", "dev:check": "npx tsc --noEmit && npm run format:check", - "dev:setup": "cp config/config.example.yml config/config.yml && npm run set:oss && npm run set:sqlite && npm run db:sqlite:generate && npm run db:sqlite:push", - "db:pg:generate": "drizzle-kit generate --config=./drizzle.pg.config.ts", - "db:sqlite:generate": "drizzle-kit generate --config=./drizzle.sqlite.config.ts", - "db:pg:push": "npx tsx server/db/pg/migrate.ts", - "db:sqlite:push": "npx tsx server/db/sqlite/migrate.ts", - "db:sqlite:studio": "drizzle-kit studio --config=./drizzle.sqlite.config.ts", - "db:pg:studio": "drizzle-kit studio --config=./drizzle.pg.config.ts", + "dev:setup": "cp config/config.example.yml config/config.yml && npm run set:oss && npm run set:sqlite && npm run db:generate && npm run db:sqlite", + "db:generate": "drizzle-kit generate --config=./drizzle.config.ts", + "db:pg": "npx tsx server/db/pg/migrate.ts", + "db:sqlite": "npx tsx server/db/sqlite/migrate.ts", + "db:studio": "drizzle-kit studio --config=./drizzle.config.ts", "db:clear-migrations": "rm -rf server/migrations", "set:oss": "echo 'export const build = \"oss\" as \"saas\" | \"enterprise\" | \"oss\";' > server/build.ts && cp tsconfig.oss.json tsconfig.json", "set:saas": "echo 'export const build = \"saas\" as \"saas\" | \"enterprise\" | \"oss\";' > server/build.ts && cp tsconfig.saas.json tsconfig.json", "set:enterprise": "echo 'export const build = \"enterprise\" as \"saas\" | \"enterprise\" | \"oss\";' > server/build.ts && cp tsconfig.enterprise.json tsconfig.json", - "set:sqlite": "echo 'export * from \"./sqlite\";\nexport const driver: \"pg\" | \"sqlite\" = \"sqlite\";' > server/db/index.ts", - "set:pg": "echo 'export * from \"./pg\";\nexport const driver: \"pg\" | \"sqlite\" = \"pg\";' > server/db/index.ts", - "build:next": "next build", - "build:sqlite": "mkdir -p dist && next build && node esbuild.mjs -e server/index.ts -o dist/server.mjs && node esbuild.mjs -e server/setup/migrationsSqlite.ts -o dist/migrations.mjs", - "build:pg": "mkdir -p dist && next build && node esbuild.mjs -e server/index.ts -o dist/server.mjs && node esbuild.mjs -e server/setup/migrationsPg.ts -o dist/migrations.mjs", + "set:sqlite": "echo 'export * from \"./sqlite\";\nexport const driver: \"pg\" | \"sqlite\" = \"sqlite\";' > server/db/index.ts && cp drizzle.sqlite.config.ts drizzle.config.ts && cp server/setup/migrationsSqlite.ts server/setup/migrations.ts", + "set:pg": "echo 'export * from \"./pg\";\nexport const driver: \"pg\" | \"sqlite\" = \"pg\";' > server/db/index.ts && cp drizzle.pg.config.ts drizzle.config.ts && cp server/setup/migrationsPg.ts server/setup/migrations.ts", + "next:build": "next build", + "build": "mkdir -p dist && next build && node esbuild.mjs -e server/index.ts -o dist/server.mjs && node esbuild.mjs -e server/setup/migrations.ts -o dist/migrations.mjs", "start": "ENVIRONMENT=prod node dist/migrations.mjs && ENVIRONMENT=prod NODE_ENV=development node --enable-source-maps dist/server.mjs", "email": "email dev --dir server/emails/templates --port 3005", "build:cli": "node esbuild.mjs -e cli/index.ts -o dist/cli.mjs", diff --git a/tsconfig.enterprise.json b/tsconfig.enterprise.json index 0b856fe08..60ed7c09b 100644 --- a/tsconfig.enterprise.json +++ b/tsconfig.enterprise.json @@ -29,7 +29,7 @@ "name": "next" } ], - "target": "ES2022" + "target": "ES2024" }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] diff --git a/tsconfig.oss.json b/tsconfig.oss.json index e32eabd3b..f2157b29c 100644 --- a/tsconfig.oss.json +++ b/tsconfig.oss.json @@ -29,7 +29,7 @@ "name": "next" } ], - "target": "ES2022" + "target": "ES2024" }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"] diff --git a/tsconfig.saas.json b/tsconfig.saas.json index 0b856fe08..60ed7c09b 100644 --- a/tsconfig.saas.json +++ b/tsconfig.saas.json @@ -29,7 +29,7 @@ "name": "next" } ], - "target": "ES2022" + "target": "ES2024" }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"]