diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 7547e5d..db61623 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -17,9 +17,7 @@ "Bash(git reset:*)", "Bash(git checkout:*)", "WebFetch(domain:cheatingchelsea.com)", - "Bash(npm install:*)", - "Bash(npm run typecheck:*)", - "Bash(rm:*)" + "Bash(npm install:*)" ], "deny": [] } diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index f445e68..5c7ee16 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -6,10 +6,6 @@ on: pull_request: branches: [ main, master ] -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: test: runs-on: self-hosted @@ -17,24 +13,33 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Cache Next.js build + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/.next/cache + key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.[jt]s', '**/*.[jt]sx') }} + restore-keys: | + ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}- + - name: Install dependencies - run: npm ci --prefer-offline --no-audit --no-fund - env: - NODE_OPTIONS: '--max-old-space-size=4096' - UV_THREADPOOL_SIZE: 16 + run: npm ci - - name: Run linting and type checking in parallel - run: | - npm run lint & - npm run typecheck & - wait - env: - NODE_OPTIONS: '--max-old-space-size=4096' + - name: Run linting + run: npm run lint + + - name: Run type checking + run: npm run typecheck - name: Build application run: npm run build env: # Use empty string for YOUTUBE_API_KEY during CI build - YOUTUBE_API_KEY: "" - NODE_OPTIONS: '--max-old-space-size=4096' - NEXT_TELEMETRY_DISABLED: 1 \ No newline at end of file + YOUTUBE_API_KEY: "" \ No newline at end of file diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml index 1e92609..1dc61d8 100644 --- a/.forgejo/workflows/deploy.yml +++ b/.forgejo/workflows/deploy.yml @@ -5,10 +5,6 @@ on: branches: [ main, master ] workflow_dispatch: -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: deploy: runs-on: self-hosted @@ -16,19 +12,30 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Cache Next.js build + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/.next/cache + key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.[jt]s', '**/*.[jt]sx') }} + restore-keys: | + ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}- + - name: Install dependencies - run: npm ci --prefer-offline --no-audit --no-fund - env: - NODE_OPTIONS: '--max-old-space-size=4096' - UV_THREADPOOL_SIZE: 16 + run: npm ci - name: Build application run: npm run build env: # Access YouTube API key from repository secrets YOUTUBE_API_KEY: ${{ secrets.YOUTUBE_API_KEY }} - NODE_OPTIONS: '--max-old-space-size=4096' - NEXT_TELEMETRY_DISABLED: 1 - name: Deploy to S3 (if configured) run: | diff --git a/CLAUDE.md b/CLAUDE.md index f8246d7..e6c79c9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -This is a Next.js 15.3.3 application with TypeScript, React 18, and multiple deployment options. The app exposes harmful activities and supports Kristen Jacobs through a GoFundMe campaign. +This is a Next.js 15.3.3 application with TypeScript, React 18, and Firebase hosting. The app exposes harmful activities and supports Kristen Jacobs through a GoFundMe campaign. ## Essential Commands @@ -15,8 +15,7 @@ npm run genkit:dev # Start Genkit AI development server npm run genkit:watch # Start Genkit with file watching # Production -npm run build # Build with git commit hash injection -npm run build:static # Standard Next.js build +npm run build # Build the Next.js application npm run start # Start production server # Quality Checks @@ -24,8 +23,8 @@ npm run lint # Run Next.js linting npm run typecheck # Run TypeScript type checking # Deployment -npm run deploy:s3 # Deploy to AWS S3 bucket (requires S3_BUCKET_NAME env var) -npm run create-s3-bucket # Interactive S3 bucket setup +npm run deploy:s3 # Deploy to AWS S3 bucket +npm run create-s3-bucket # Create S3 bucket for deployment ``` ## Architecture Overview @@ -33,71 +32,24 @@ npm run create-s3-bucket # Interactive S3 bucket setup ### App Structure - **App Router**: Uses Next.js App Router in `src/app/` - **Pages**: Homepage, Gallery (YouTube videos), Dadvocate (curated videos), Long Story -- **Static Export**: Configured with `output: 'export'` for static hosting -- **Deployment**: AWS S3 static hosting +- **Static Generation**: Pages use static generation with ISR for external data +- **Deployment**: Supports Static hosting (S3), Firebase App Hosting, and Vercel ### Key Patterns 1. **UI Components**: Full shadcn/ui component library in `src/components/ui/` 2. **Styling**: Tailwind CSS with custom theme, use `cn()` utility for class merging -3. **Data Fetching**: Server-side fetching with fallback data, 1-hour cache for YouTube API -4. **Environment Variables**: `YOUTUBE_API_KEY` (required), `S3_BUCKET_NAME` (for deployment) +3. **Data Fetching**: Server-side fetching in page components with fallback data +4. **Environment Variables**: Only `YOUTUBE_API_KEY` is used 5. **Path Alias**: Use `@/` for imports from `src/` directory -### Build & Deployment Details -- **Version Tracking**: Build process injects git commit hash into footer via `scripts/set-git-commit.js` -- **Static Files**: Build outputs to `out/` directory for S3 deployment -- **Build Errors**: TypeScript and ESLint errors are ignored (configured in next.config.ts) -- **S3 Deployment**: Uses dotenv-cli to load environment variables from `.env.local` -- **Pre-commit Hooks**: Husky installed for running lint checks before commits - ### Development Notes -- **No Testing Framework**: Project currently has no test setup -- **AI Integration**: Genkit configured with Google AI (Gemini 2.0 Flash) but minimally implemented +- **Build Configuration**: TypeScript and ESLint errors are ignored during builds +- **YouTube API**: Gallery and Dadvocate pages fetch video data with 1-hour cache +- **AI Integration**: Genkit setup exists but is minimally implemented - **Theme**: Dark/light mode support via next-themes -- **Image Optimization**: Configured for YouTube thumbnails and placeholder images +- **Pre-commit**: Husky runs linting before commits ### Adding Features -- New pages: Create directory in `src/app/` with `page.tsx` and export metadata +- New pages: Create directory in `src/app/` with `page.tsx` and metadata export - New components: Add to `src/components/` or use existing shadcn/ui components -- YouTube videos: Update video IDs in gallery/page.tsx or dadvocate/page.tsx, then rebuild - -## Git Workflow & Pull Requests - -### Creating Pull Requests with tea -Use the `tea` command instead of `gh` for all Git operations. When creating PRs: - -```bash -# Create PR with title only (description must be added via web UI) -tea pr create --title "Your PR title" - -# With additional options -tea pr create --title "Your PR title" --base main --head feature-branch - -# Note: tea does not support setting PR description via CLI -# You must add the description through the web interface after creation -``` - -### PR Description Template -After creating a PR with tea, add this description format via the web UI: - -```markdown -## Summary -- Brief bullet points of what this PR does - -## Changes -- Detailed list of changes made -- Files modified/added/deleted -- Implementation details - -## Test plan -- [ ] Steps to test the changes -- [ ] What to verify - -🤖 Generated with [Claude Code](https://claude.ai/code) -``` - -## Code Style Guidelines -- Always use 'tea' instead of 'gh' for Git operations -- Follow existing code patterns and conventions -- Use TypeScript strict mode practices -- Maintain consistent formatting with Prettier/ESLint \ No newline at end of file +- API integration: Use server components with async/await and error handling \ No newline at end of file diff --git a/README.md b/README.md index 0f0fcc6..ac01785 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ A Next.js application built to expose harmful activities and support Kristen Jac - **Language**: TypeScript - **UI Components**: shadcn/ui component library - **Styling**: Tailwind CSS with custom theming -- **Hosting**: AWS S3 static hosting +- **Hosting**: Supports Static hosting (S3), Firebase App Hosting, and Vercel - **AI Integration**: Google Genkit (minimal implementation) ## 📋 Prerequisites @@ -89,6 +89,14 @@ This application supports multiple deployment platforms: ### Static Hosting (AWS S3) The project includes CI/CD workflow for automatic deployment to AWS S3. +### Firebase App Hosting +Deploy using Firebase CLI: +```bash +firebase deploy +``` + +### Vercel +Deploy directly from Git repository through Vercel dashboard or CLI. ## 📁 Project Structure diff --git a/apphosting.yaml b/apphosting.yaml new file mode 100644 index 0000000..a55af7b --- /dev/null +++ b/apphosting.yaml @@ -0,0 +1,7 @@ +# Settings to manage and configure a Firebase App Hosting backend. +# https://firebase.google.com/docs/app-hosting/configure + +runConfig: + # Increase this value if you'd like to automatically spin up + # more instances in response to increased traffic. + maxInstances: 1 diff --git a/package-lock.json b/package-lock.json index 9af84c1..08d33db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "date-fns": "^3.6.0", "dotenv": "^16.5.0", "embla-carousel-react": "^8.6.0", + "firebase": "^11.9.1", "genkit": "^1.13.0", "lucide-react": "^0.475.0", "next": "15.3.3", @@ -58,7 +59,6 @@ "aws-cdk-lib": "^2.189.1", "constructs": "^10.4.2", "cross-env": "^7.0.3", - "dotenv-cli": "^8.0.0", "esbuild": "^0.25.5", "eslint": "^9.30.0", "eslint-config-next": "15.3.4", @@ -163,6 +163,21 @@ "kuler": "^2.0.0" } }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.5", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "dev": true, @@ -366,6 +381,538 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@firebase/ai": { + "version": "1.4.0", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.16", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/installations": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.22", + "license": "Apache-2.0", + "dependencies": { + "@firebase/analytics": "0.10.16", + "@firebase/analytics-types": "0.8.3", + "@firebase/component": "0.6.17", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.3", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app": { + "version": "0.13.1", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.10.0", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.25", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check": "0.10.0", + "@firebase/app-check-types": "0.5.3", + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.3", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.3", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app-compat": { + "version": "0.4.1", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app": "0.13.1", + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.3", + "license": "Apache-2.0" + }, + "node_modules/@firebase/app/node_modules/idb": { + "version": "7.1.1", + "license": "ISC" + }, + "node_modules/@firebase/auth-compat": { + "version": "0.5.27", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth": "1.10.7", + "@firebase/auth-types": "0.13.0", + "@firebase/component": "0.6.17", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-compat/node_modules/@firebase/auth": { + "version": "1.10.7", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.4", + "license": "Apache-2.0" + }, + "node_modules/@firebase/auth-types": { + "version": "0.13.0", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.17", + "license": "Apache-2.0", + "dependencies": { + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/data-connect": { + "version": "0.3.9", + "license": "Apache-2.0", + "dependencies": { + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/database": { + "version": "1.0.19", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "2.0.10", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/database": "1.0.19", + "@firebase/database-types": "1.0.14", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.14", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-types": "0.9.3", + "@firebase/util": "1.12.0" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.7.17", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "@firebase/webchannel-wrapper": "1.0.3", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.52", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/firestore": "4.7.17", + "@firebase/firestore-types": "3.0.3", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.3", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.12.8", + "license": "Apache-2.0", + "dependencies": { + "@firebase/app-check-interop-types": "0.3.3", + "@firebase/auth-interop-types": "0.2.4", + "@firebase/component": "0.6.17", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.25", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/functions": "0.12.8", + "@firebase/functions-types": "0.6.3", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.3", + "license": "Apache-2.0" + }, + "node_modules/@firebase/installations": { + "version": "0.6.17", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/util": "1.12.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.17", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/installations": "0.6.17", + "@firebase/installations-types": "0.5.3", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.3", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/installations/node_modules/idb": { + "version": "7.1.1", + "license": "ISC" + }, + "node_modules/@firebase/logger": { + "version": "0.4.4", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.21", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/installations": "0.6.17", + "@firebase/messaging-interop-types": "0.2.3", + "@firebase/util": "1.12.0", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.21", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/messaging": "0.12.21", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.3", + "license": "Apache-2.0" + }, + "node_modules/@firebase/messaging/node_modules/idb": { + "version": "7.1.1", + "license": "ISC" + }, + "node_modules/@firebase/performance": { + "version": "0.7.6", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/installations": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0", + "web-vitals": "^4.2.4" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.19", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/performance": "0.7.6", + "@firebase/performance-types": "0.2.3", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.3", + "license": "Apache-2.0" + }, + "node_modules/@firebase/remote-config": { + "version": "0.6.4", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/installations": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.17", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/remote-config": "0.6.4", + "@firebase/remote-config-types": "0.4.0", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.4.0", + "license": "Apache-2.0" + }, + "node_modules/@firebase/storage": { + "version": "0.13.13", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.23", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/storage": "0.13.13", + "@firebase/storage-types": "0.8.3", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.3", + "license": "Apache-2.0", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.12.0", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "1.0.3", + "license": "Apache-2.0" + }, "node_modules/@floating-ui/core": { "version": "1.7.1", "license": "MIT", @@ -848,6 +1395,74 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.1.0", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.1.0", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.2", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.1.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.2", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "license": "ISC", @@ -1332,11 +1947,10 @@ }, "node_modules/@next/swc-linux-x64-gnu": { "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.3.tgz", - "integrity": "sha512-jJ8HRiF3N8Zw6hGlytCj5BiHyG/K+fnTKVDEKvUCyiQ/0r5tgwO7OgaRiOjjRoIx2vwLR+Rz8hQoPrnmFbJdfw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1347,11 +1961,10 @@ }, "node_modules/@next/swc-linux-x64-musl": { "version": "15.3.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.3.tgz", - "integrity": "sha512-HrUcTr4N+RgiiGn3jjeT6Oo208UT/7BuTr7K0mdKRBtTbT4v9zJqCDKO97DUqqoBK1qyzP1RwvrWTvU6EPh/Cw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -3733,6 +4346,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.9.2", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "license": "BSD-2-Clause" @@ -5386,32 +6011,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/dotenv-cli": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-8.0.0.tgz", - "integrity": "sha512-aLqYbK7xKOiTMIRf1lDPbI+Y+Ip/wo5k3eyp6ePysVaSqbyxjyK3dK35BTxG+rmd7djf5q2UPs4noPNH+cj0Qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6", - "dotenv": "^16.3.0", - "dotenv-expand": "^10.0.0", - "minimist": "^1.2.6" - }, - "bin": { - "dotenv": "cli.js" - } - }, - "node_modules/dotenv-expand": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", - "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - } - }, "node_modules/dotprompt": { "version": "1.1.1", "license": "ISC", @@ -6571,6 +7170,16 @@ "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "dev": true, @@ -6660,6 +7269,62 @@ "micromatch": "^4.0.2" } }, + "node_modules/firebase": { + "version": "11.9.1", + "license": "Apache-2.0", + "dependencies": { + "@firebase/ai": "1.4.0", + "@firebase/analytics": "0.10.16", + "@firebase/analytics-compat": "0.2.22", + "@firebase/app": "0.13.1", + "@firebase/app-check": "0.10.0", + "@firebase/app-check-compat": "0.3.25", + "@firebase/app-compat": "0.4.1", + "@firebase/app-types": "0.9.3", + "@firebase/auth": "1.10.7", + "@firebase/auth-compat": "0.5.27", + "@firebase/data-connect": "0.3.9", + "@firebase/database": "1.0.19", + "@firebase/database-compat": "2.0.10", + "@firebase/firestore": "4.7.17", + "@firebase/firestore-compat": "0.3.52", + "@firebase/functions": "0.12.8", + "@firebase/functions-compat": "0.3.25", + "@firebase/installations": "0.6.17", + "@firebase/installations-compat": "0.2.17", + "@firebase/messaging": "0.12.21", + "@firebase/messaging-compat": "0.2.21", + "@firebase/performance": "0.7.6", + "@firebase/performance-compat": "0.2.19", + "@firebase/remote-config": "0.6.4", + "@firebase/remote-config-compat": "0.2.17", + "@firebase/storage": "0.13.13", + "@firebase/storage-compat": "0.3.23", + "@firebase/util": "1.12.0" + } + }, + "node_modules/firebase/node_modules/@firebase/auth": { + "version": "1.10.7", + "license": "Apache-2.0", + "dependencies": { + "@firebase/component": "0.6.17", + "@firebase/logger": "0.4.4", + "@firebase/util": "1.12.0", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, "node_modules/flat-cache": { "version": "4.0.1", "dev": true, @@ -7363,6 +8028,10 @@ "node": ">= 0.8" } }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "license": "MIT" + }, "node_modules/http-proxy-agent": { "version": "5.0.0", "dev": true, @@ -11254,10 +11923,33 @@ "node": ">= 8" } }, + "node_modules/web-vitals": { + "version": "4.2.4", + "license": "Apache-2.0" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "license": "BSD-2-Clause" }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "license": "MIT", diff --git a/package.json b/package.json index c918fea..0f57edf 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "start": "next start", "lint": "next lint", "typecheck": "tsc --noEmit", - "deploy:s3": "npm run build && dotenv -e .env.local -- aws s3 sync out/ s3://$S3_BUCKET_NAME --delete", + "deploy:s3": "npm run build && aws s3 sync out/ s3://$S3_BUCKET_NAME --delete", "create-s3-bucket": "node scripts/create-s3-bucket.js", "prepare": "husky install" }, @@ -45,6 +45,7 @@ "date-fns": "^3.6.0", "dotenv": "^16.5.0", "embla-carousel-react": "^8.6.0", + "firebase": "^11.9.1", "genkit": "^1.13.0", "lucide-react": "^0.475.0", "next": "15.3.3", @@ -66,7 +67,6 @@ "aws-cdk-lib": "^2.189.1", "constructs": "^10.4.2", "cross-env": "^7.0.3", - "dotenv-cli": "^8.0.0", "esbuild": "^0.25.5", "eslint": "^9.30.0", "eslint-config-next": "15.3.4", diff --git a/tsconfig.json b/tsconfig.json index 9aed7fb..c133409 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2017", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, @@ -13,7 +13,6 @@ "isolatedModules": true, "jsx": "preserve", "incremental": true, - "tsBuildInfoFile": ".next/types/tsbuildinfo", "plugins": [ { "name": "next"