Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
bdca42213d | |||
4e193ab1b2 |
@ -1,64 +1,84 @@
|
|||||||
# 🔧 Deployment Issue Fixes
|
# 🔧 Deployment Issue Fixes
|
||||||
|
|
||||||
## 🔍 Issues Identified from Latest Log
|
## 🔍 Issues Identified from Latest Log
|
||||||
|
|
||||||
### **Issue 1: TypeScript JSX Configuration Missing** ❌→✅
|
### **Issue 1: TypeScript JSX Configuration Missing** ❌→✅
|
||||||
**Problem**: TypeScript compilation failing with `error TS6142: '--jsx' is not set`
|
**Problem**: TypeScript compilation failing with `error TS6142: '--jsx' is not set`
|
||||||
**Root Cause**: Generated tsconfig.json in Docker was missing JSX configuration
|
**Root Cause**: Generated tsconfig.json in Docker was missing JSX configuration
|
||||||
**Fix Applied**: Added `"jsx":"react-jsx"` to the tsconfig.json generation in Dockerfile
|
**Fix Applied**: Added `"jsx":"react-jsx"` to the tsconfig.json generation in Dockerfile
|
||||||
**Line Fixed**: Line 77 in Dockerfile
|
**Line Fixed**: Line 77 in Dockerfile
|
||||||
|
|
||||||
### **Issue 2: Health Check Tool Mismatch** ❌→✅
|
### **Issue 2: Health Check Tool Mismatch** ❌→✅
|
||||||
**Problem**: Health checks failing with `wget: can't connect to remote host: Connection refused`
|
**Problem**: Health checks failing with `wget: can't connect to remote host: Connection refused`
|
||||||
**Root Cause**:
|
**Root Cause**:
|
||||||
- Dockerfile uses `curl` for health checks
|
- Dockerfile uses `curl` for health checks
|
||||||
- Coolify deployment system uses `wget` for health checks
|
- Coolify deployment system uses `wget` for health checks
|
||||||
- Tool mismatch causing health check failures
|
- Tool mismatch causing health check failures
|
||||||
|
|
||||||
**Fix Applied**:
|
**Fix Applied**:
|
||||||
1. Added `wget` installation alongside `curl`
|
1. Added `wget` installation alongside `curl`
|
||||||
2. Updated health check command to support both tools: `curl -f http://localhost/ || wget -q --spider http://localhost/ || exit 1`
|
2. Updated health check command to support both tools: `curl -f http://localhost/ || wget -q --spider http://localhost/ || exit 1`
|
||||||
|
|
||||||
### **Issue 3: Container Health Check Endpoint** ❌→✅
|
### **Issue 3: Container Health Check Endpoint** ❌→✅
|
||||||
**Problem**: Health check trying to access `/health` endpoint that doesn't exist
|
**Problem**: Health check trying to access `/health` endpoint that doesn't exist
|
||||||
**Fix Applied**: Changed health check to use root path `/` which always exists for Nginx
|
**Fix Applied**: Changed health check to use root path `/` which always exists for Nginx
|
||||||
|
|
||||||
## 📋 Changes Made
|
### **Issue 4: Mock API Build Order & TypeScript Errors** ❌→✅
|
||||||
|
**Problem**:
|
||||||
### **1. Updated Dockerfile (Lines 77, 89, 113)**
|
- TypeScript compilation errors in mock API functions
|
||||||
```dockerfile
|
- Build order issue: source files copied before mock API creation
|
||||||
# Fixed TypeScript JSX configuration
|
- Server.ts file causing compilation errors
|
||||||
RUN echo '{"compilerOptions":{..."jsx":"react-jsx"...}}' > tsconfig.json
|
|
||||||
|
**Root Cause**:
|
||||||
# Added wget for Coolify compatibility
|
- Mock API files created after source code copy
|
||||||
RUN apk add --no-cache curl wget
|
- TypeScript compilation happening before mock API is ready
|
||||||
|
- Server.ts file not needed for frontend demo
|
||||||
# Fixed health check with fallback
|
|
||||||
CMD curl -f http://localhost/ || wget -q --spider http://localhost/ || exit 1
|
**Fix Applied**:
|
||||||
```
|
1. Reordered Dockerfile: create mock API structure BEFORE copying source code
|
||||||
|
2. Added `rm -f src/server.ts` to remove server file
|
||||||
## ✅ Expected Results
|
3. Fixed function signatures in mock API (added missing parameters)
|
||||||
|
4. Fixed useCreateScript hook to properly handle userId parameter
|
||||||
After these fixes:
|
5. Fixed server.ts createScript call to pass userId parameter
|
||||||
|
|
||||||
1. **TypeScript Build**: ✅ Should compile `.tsx` files successfully
|
## 📋 Changes Made
|
||||||
2. **Health Check**: ✅ Should pass using either curl or wget
|
|
||||||
3. **Container Status**: ✅ Should show as healthy
|
### **1. Updated Dockerfile (Lines 77, 89, 113)**
|
||||||
4. **Deployment**: ✅ Should complete without rollback
|
```dockerfile
|
||||||
|
# Fixed TypeScript JSX configuration
|
||||||
## 🎯 Root Cause Analysis
|
RUN echo '{"compilerOptions":{..."jsx":"react-jsx"...}}' > tsconfig.json
|
||||||
|
|
||||||
The deployment failures were caused by:
|
# Added wget for Coolify compatibility
|
||||||
1. **Build Configuration**: Missing JSX support in generated TypeScript config
|
RUN apk add --no-cache curl wget
|
||||||
2. **Health Check Compatibility**: Tool mismatch between Docker image and deployment platform
|
|
||||||
3. **Endpoint Mismatch**: Health check looking for non-existent endpoint
|
# Fixed health check with fallback
|
||||||
|
CMD curl -f http://localhost/ || wget -q --spider http://localhost/ || exit 1
|
||||||
## 🚀 Next Deployment
|
```
|
||||||
|
|
||||||
The next deployment should:
|
## ✅ Expected Results
|
||||||
- ✅ Build successfully with JSX support
|
|
||||||
- ✅ Pass health checks with both curl and wget
|
After these fixes:
|
||||||
- ✅ Complete without rollbacks
|
|
||||||
- ✅ Result in a fully functional application
|
1. **TypeScript Build**: ✅ Should compile `.tsx` files successfully
|
||||||
|
2. **Mock API**: ✅ Should compile without TypeScript errors
|
||||||
**Status**: Ready for redeployment with fixes applied! 🎉
|
3. **Health Check**: ✅ Should pass using either curl or wget
|
||||||
|
4. **Container Status**: ✅ Should show as healthy
|
||||||
|
5. **Deployment**: ✅ Should complete without rollback
|
||||||
|
6. **Frontend**: ✅ Should load and function properly with mock API
|
||||||
|
|
||||||
|
## 🎯 Root Cause Analysis
|
||||||
|
|
||||||
|
The deployment failures were caused by:
|
||||||
|
1. **Build Configuration**: Missing JSX support in generated TypeScript config
|
||||||
|
2. **Health Check Compatibility**: Tool mismatch between Docker image and deployment platform
|
||||||
|
3. **Endpoint Mismatch**: Health check looking for non-existent endpoint
|
||||||
|
|
||||||
|
## 🚀 Next Deployment
|
||||||
|
|
||||||
|
The next deployment should:
|
||||||
|
- ✅ Build successfully with JSX support
|
||||||
|
- ✅ Pass health checks with both curl and wget
|
||||||
|
- ✅ Complete without rollbacks
|
||||||
|
- ✅ Result in a fully functional application
|
||||||
|
|
||||||
|
**Status**: Ready for redeployment with fixes applied! 🎉
|
||||||
|
11
Dockerfile
11
Dockerfile
@ -12,9 +12,6 @@ COPY package*.json ./
|
|||||||
# Install dependencies with proper npm cache handling
|
# Install dependencies with proper npm cache handling
|
||||||
RUN npm ci --only=production=false --silent
|
RUN npm ci --only=production=false --silent
|
||||||
|
|
||||||
# Copy source code
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Set build-time environment variables
|
# Set build-time environment variables
|
||||||
ARG VITE_APP_NAME="ScriptShare"
|
ARG VITE_APP_NAME="ScriptShare"
|
||||||
ARG VITE_APP_URL="https://scriptshare.example.com"
|
ARG VITE_APP_URL="https://scriptshare.example.com"
|
||||||
@ -39,10 +36,14 @@ RUN npm install
|
|||||||
# Remove problematic server-side API files for frontend-only build
|
# Remove problematic server-side API files for frontend-only build
|
||||||
RUN rm -rf src/lib/api || true
|
RUN rm -rf src/lib/api || true
|
||||||
RUN rm -rf src/lib/db || true
|
RUN rm -rf src/lib/db || true
|
||||||
|
RUN rm -f src/server.ts || true
|
||||||
|
|
||||||
# Create mock API layer for frontend demo
|
# Create mock API layer for frontend demo
|
||||||
RUN mkdir -p src/lib/api src/lib/db
|
RUN mkdir -p src/lib/api src/lib/db
|
||||||
|
|
||||||
|
# Copy source code AFTER creating mock API structure
|
||||||
|
COPY . .
|
||||||
|
|
||||||
# Create mock database files
|
# Create mock database files
|
||||||
RUN echo "export const db = {};" > src/lib/db/index.ts
|
RUN echo "export const db = {};" > src/lib/db/index.ts
|
||||||
RUN echo "export const users = {}; export const scripts = {}; export const ratings = {}; export const scriptVersions = {}; export const scriptAnalytics = {}; export const scriptCollections = {}; export const collectionScripts = {};" > src/lib/db/schema.ts
|
RUN echo "export const users = {}; export const scripts = {}; export const ratings = {}; export const scriptVersions = {}; export const scriptAnalytics = {}; export const scriptCollections = {}; export const collectionScripts = {};" > src/lib/db/schema.ts
|
||||||
@ -56,7 +57,7 @@ RUN printf 'import { nanoid } from "nanoid";\nexport const generateId = () => na
|
|||||||
RUN printf 'export interface LoginCredentials {\n email: string;\n password: string;\n}\nexport interface RegisterData {\n email: string;\n username: string;\n displayName: string;\n password: string;\n}\nexport interface AuthToken {\n token: string;\n user: any;\n}\nexport async function login(credentials: LoginCredentials): Promise<AuthToken> {\n return { token: "demo-token", user: { id: "1", username: "demo", email: "demo@example.com", displayName: "Demo User", isAdmin: false, isModerator: false } };\n}\nexport async function register(data: RegisterData): Promise<AuthToken> {\n return { token: "demo-token", user: { id: "1", username: data.username, email: data.email, displayName: data.displayName, isAdmin: false, isModerator: false } };\n}\nexport async function refreshToken(token: string): Promise<AuthToken> {\n return { token: "demo-token", user: { id: "1", username: "demo", email: "demo@example.com", displayName: "Demo User", isAdmin: false, isModerator: false } };\n}\nexport async function changePassword(userId: string, currentPassword: string, newPassword: string): Promise<boolean> {\n return true;\n}' > src/lib/api/auth.ts
|
RUN printf 'export interface LoginCredentials {\n email: string;\n password: string;\n}\nexport interface RegisterData {\n email: string;\n username: string;\n displayName: string;\n password: string;\n}\nexport interface AuthToken {\n token: string;\n user: any;\n}\nexport async function login(credentials: LoginCredentials): Promise<AuthToken> {\n return { token: "demo-token", user: { id: "1", username: "demo", email: "demo@example.com", displayName: "Demo User", isAdmin: false, isModerator: false } };\n}\nexport async function register(data: RegisterData): Promise<AuthToken> {\n return { token: "demo-token", user: { id: "1", username: data.username, email: data.email, displayName: data.displayName, isAdmin: false, isModerator: false } };\n}\nexport async function refreshToken(token: string): Promise<AuthToken> {\n return { token: "demo-token", user: { id: "1", username: "demo", email: "demo@example.com", displayName: "Demo User", isAdmin: false, isModerator: false } };\n}\nexport async function changePassword(userId: string, currentPassword: string, newPassword: string): Promise<boolean> {\n return true;\n}' > src/lib/api/auth.ts
|
||||||
|
|
||||||
# Mock scripts API with individual function exports
|
# Mock scripts API with individual function exports
|
||||||
RUN printf 'export interface ScriptFilters {\n search?: string;\n categories?: string[];\n compatibleOs?: string[];\n sortBy?: string;\n limit?: number;\n isApproved?: boolean;\n}\nexport interface UpdateScriptData {\n name?: string;\n description?: string;\n content?: string;\n}\nexport interface CreateScriptData {\n name: string;\n description: string;\n content: string;\n categories: string[];\n compatibleOs: string[];\n tags?: string[];\n}\nexport async function getScripts(filters?: ScriptFilters) {\n return { scripts: [], total: 0 };\n}\nexport async function getScriptById(id: string) {\n return null;\n}\nexport async function getPopularScripts() {\n return [];\n}\nexport async function getRecentScripts() {\n return [];\n}\nexport async function createScript(data: CreateScriptData, userId: string) {\n return { id: "mock-script-id", ...data, authorId: userId };\n}\nexport async function updateScript(id: string, data: UpdateScriptData, userId: string) {\n return { id, ...data };\n}\nexport async function deleteScript(id: string, userId: string) {\n return { success: true };\n}\nexport async function moderateScript(id: string, isApproved: boolean, moderatorId: string) {\n return { id, isApproved };\n}\nexport async function incrementViewCount(id: string) {\n return { success: true };\n}\nexport async function incrementDownloadCount(id: string) {\n return { success: true };\n}' > src/lib/api/scripts.ts
|
RUN printf 'export interface ScriptFilters {\n search?: string;\n categories?: string[];\n compatibleOs?: string[];\n sortBy?: string;\n limit?: number;\n isApproved?: boolean;\n}\nexport interface UpdateScriptData {\n name?: string;\n description?: string;\n content?: string;\n}\nexport interface CreateScriptData {\n name: string;\n description: string;\n content: string;\n categories: string[];\n compatibleOs: string[];\n tags?: string[];\n}\nexport async function getScripts(filters?: ScriptFilters) {\n return { scripts: [], total: 0 };\n}\nexport async function getScriptById(id: string) {\n return null;\n}\nexport async function getPopularScripts(limit?: number) {\n return [];\n}\nexport async function getRecentScripts(limit?: number) {\n return [];\n}\nexport async function createScript(data: CreateScriptData, userId: string) {\n return { id: "mock-script-id", ...data, authorId: userId };\n}\nexport async function updateScript(id: string, data: UpdateScriptData, userId: string) {\n return { id, ...data };\n}\nexport async function deleteScript(id: string, userId: string) {\n return { success: true };\n}\nexport async function moderateScript(id: string, isApproved: boolean, moderatorId: string) {\n return { id, isApproved };\n}\nexport async function incrementViewCount(id: string) {\n return { success: true };\n}\nexport async function incrementDownloadCount(id: string) {\n return { success: true };\n}' > src/lib/api/scripts.ts
|
||||||
|
|
||||||
# Mock ratings API with individual function exports
|
# Mock ratings API with individual function exports
|
||||||
RUN printf 'export interface CreateRatingData {\n scriptId: string;\n userId: string;\n rating: number;\n}\nexport async function rateScript(data: CreateRatingData) {\n return { id: "mock-rating-id", ...data, createdAt: new Date(), updatedAt: new Date() };\n}\nexport async function getUserRating(scriptId: string, userId: string) {\n return null;\n}\nexport async function getScriptRatings(scriptId: string) {\n return [];\n}\nexport async function getScriptRatingStats(scriptId: string) {\n return { averageRating: 0, totalRatings: 0, distribution: [] };\n}\nexport async function deleteRating(scriptId: string, userId: string) {\n return { success: true };\n}' > src/lib/api/ratings.ts
|
RUN printf 'export interface CreateRatingData {\n scriptId: string;\n userId: string;\n rating: number;\n}\nexport async function rateScript(data: CreateRatingData) {\n return { id: "mock-rating-id", ...data, createdAt: new Date(), updatedAt: new Date() };\n}\nexport async function getUserRating(scriptId: string, userId: string) {\n return null;\n}\nexport async function getScriptRatings(scriptId: string) {\n return [];\n}\nexport async function getScriptRatingStats(scriptId: string) {\n return { averageRating: 0, totalRatings: 0, distribution: [] };\n}\nexport async function deleteRating(scriptId: string, userId: string) {\n return { success: true };\n}' > src/lib/api/ratings.ts
|
||||||
@ -65,7 +66,7 @@ RUN printf 'export interface CreateRatingData {\n scriptId: string;\n userId:
|
|||||||
RUN printf 'export interface TrackEventData {\n scriptId: string;\n eventType: string;\n userId?: string;\n userAgent?: string;\n ipAddress?: string;\n referrer?: string;\n}\nexport interface AnalyticsFilters {\n scriptId?: string;\n eventType?: string;\n startDate?: Date;\n endDate?: Date;\n userId?: string;\n}\nexport async function trackEvent(data: TrackEventData) {\n return { success: true };\n}\nexport async function getAnalyticsEvents(filters?: AnalyticsFilters) {\n return [];\n}\nexport async function getScriptAnalytics(scriptId: string, days?: number) {\n return { eventCounts: [], dailyActivity: [], referrers: [], periodDays: days || 30 };\n}\nexport async function getPlatformAnalytics(days?: number) {\n return { totals: { totalScripts: 0, approvedScripts: 0, pendingScripts: 0 }, activityByType: [], popularScripts: [], dailyTrends: [], periodDays: days || 30 };\n}\nexport async function getUserAnalytics(userId: string, days?: number) {\n return { userScripts: [], recentActivity: [], periodDays: days || 30 };\n}' > src/lib/api/analytics.ts
|
RUN printf 'export interface TrackEventData {\n scriptId: string;\n eventType: string;\n userId?: string;\n userAgent?: string;\n ipAddress?: string;\n referrer?: string;\n}\nexport interface AnalyticsFilters {\n scriptId?: string;\n eventType?: string;\n startDate?: Date;\n endDate?: Date;\n userId?: string;\n}\nexport async function trackEvent(data: TrackEventData) {\n return { success: true };\n}\nexport async function getAnalyticsEvents(filters?: AnalyticsFilters) {\n return [];\n}\nexport async function getScriptAnalytics(scriptId: string, days?: number) {\n return { eventCounts: [], dailyActivity: [], referrers: [], periodDays: days || 30 };\n}\nexport async function getPlatformAnalytics(days?: number) {\n return { totals: { totalScripts: 0, approvedScripts: 0, pendingScripts: 0 }, activityByType: [], popularScripts: [], dailyTrends: [], periodDays: days || 30 };\n}\nexport async function getUserAnalytics(userId: string, days?: number) {\n return { userScripts: [], recentActivity: [], periodDays: days || 30 };\n}' > src/lib/api/analytics.ts
|
||||||
|
|
||||||
# Mock collections API with individual function exports
|
# Mock collections API with individual function exports
|
||||||
RUN printf 'export interface CreateCollectionData {\n name: string;\n description?: string;\n authorId: string;\n isPublic?: boolean;\n}\nexport interface UpdateCollectionData {\n name?: string;\n description?: string;\n isPublic?: boolean;\n}\nexport async function createCollection(data: CreateCollectionData) {\n return { id: "mock-collection-id", ...data, createdAt: new Date(), updatedAt: new Date() };\n}\nexport async function getCollectionById(id: string) {\n return null;\n}\nexport async function getUserCollections(userId: string) {\n return [];\n}\nexport async function getPublicCollections(limit?: number, offset?: number) {\n return [];\n}\nexport async function updateCollection(id: string, data: UpdateCollectionData, userId: string) {\n return { id, ...data, updatedAt: new Date() };\n}\nexport async function deleteCollection(id: string, userId: string) {\n return { success: true };\n}\nexport async function addScriptToCollection(collectionId: string, scriptId: string, userId: string) {\n return { id: "mock-collection-script-id", collectionId, scriptId, addedAt: new Date() };\n}\nexport async function removeScriptFromCollection(collectionId: string, scriptId: string, userId: string) {\n return { success: true };\n}\nexport async function isScriptInCollection(collectionId: string, scriptId: string) {\n return false;\n}' > src/lib/api/collections.ts
|
RUN printf 'export interface CreateCollectionData {\n name: string;\n description?: string;\n authorId: string;\n isPublic?: boolean;\n}\nexport interface UpdateCollectionData {\n name?: string;\n description?: string;\n isPublic?: boolean;\n}\nexport async function createCollection(data: CreateCollectionData) {\n return { id: "mock-collection-id", ...data, createdAt: new Date(), updatedAt: new Date() };\n}\nexport async function getCollectionById(id: string) {\n return null;\n}\nexport async function getUserCollections(userId: string) {\n return [];\n}\nexport async function getPublicCollections(limit?: number, offset?: number) {\n return [];\n}\nexport async function updateCollection(id: string, data: UpdateCollectionData, userId: string) {\n return { id, ...data, authorId: userId, updatedAt: new Date() };\n}\nexport async function deleteCollection(id: string, userId: string) {\n return { success: true };\n}\nexport async function addScriptToCollection(collectionId: string, scriptId: string, userId: string) {\n return { id: "mock-collection-script-id", collectionId, scriptId, addedAt: new Date() };\n}\nexport async function removeScriptFromCollection(collectionId: string, scriptId: string, userId: string) {\n return { success: true };\n}\nexport async function isScriptInCollection(collectionId: string, scriptId: string) {\n return false;\n}' > src/lib/api/collections.ts
|
||||||
|
|
||||||
# Mock users API with individual function exports
|
# Mock users API with individual function exports
|
||||||
RUN printf 'export interface CreateUserData {\n email: string;\n username: string;\n displayName: string;\n avatarUrl?: string;\n bio?: string;\n}\nexport interface UpdateUserData {\n username?: string;\n displayName?: string;\n avatarUrl?: string;\n bio?: string;\n}\nexport async function createUser(data: CreateUserData) {\n return { id: "mock-user-id", ...data, isAdmin: false, isModerator: false, createdAt: new Date(), updatedAt: new Date() };\n}\nexport async function getUserById(id: string) {\n return null;\n}\nexport async function getUserByEmail(email: string) {\n return null;\n}\nexport async function getUserByUsername(username: string) {\n return null;\n}\nexport async function updateUser(id: string, data: UpdateUserData) {\n return { id, ...data, updatedAt: new Date() };\n}\nexport async function updateUserPermissions(id: string, permissions: any) {\n return { id, ...permissions, updatedAt: new Date() };\n}\nexport async function searchUsers(query: string, limit?: number) {\n return [];\n}\nexport async function getAllUsers(limit?: number, offset?: number) {\n return [];\n}' > src/lib/api/users.ts
|
RUN printf 'export interface CreateUserData {\n email: string;\n username: string;\n displayName: string;\n avatarUrl?: string;\n bio?: string;\n}\nexport interface UpdateUserData {\n username?: string;\n displayName?: string;\n avatarUrl?: string;\n bio?: string;\n}\nexport async function createUser(data: CreateUserData) {\n return { id: "mock-user-id", ...data, isAdmin: false, isModerator: false, createdAt: new Date(), updatedAt: new Date() };\n}\nexport async function getUserById(id: string) {\n return null;\n}\nexport async function getUserByEmail(email: string) {\n return null;\n}\nexport async function getUserByUsername(username: string) {\n return null;\n}\nexport async function updateUser(id: string, data: UpdateUserData) {\n return { id, ...data, updatedAt: new Date() };\n}\nexport async function updateUserPermissions(id: string, permissions: any) {\n return { id, ...permissions, updatedAt: new Date() };\n}\nexport async function searchUsers(query: string, limit?: number) {\n return [];\n}\nexport async function getAllUsers(limit?: number, offset?: number) {\n return [];\n}' > src/lib/api/users.ts
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -8319,16 +8319,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-syntax-highlighter": {
|
"node_modules/react-syntax-highlighter": {
|
||||||
"version": "15.6.1",
|
"version": "15.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.3.tgz",
|
||||||
"integrity": "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==",
|
"integrity": "sha512-HebdyA9r20hgmA0q8RyRJ4c/vB4E6KL2HeWb5MNjU3iJEiT2w9jfU2RJsmI6f3Cy3SGE5tm0AIkBzM/E7e9/lQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.3.1",
|
"@babel/runtime": "^7.3.1",
|
||||||
"highlight.js": "^10.4.1",
|
"highlight.js": "^10.4.1",
|
||||||
"highlightjs-vue": "^1.0.0",
|
"highlightjs-vue": "^1.0.0",
|
||||||
"lowlight": "^1.17.0",
|
"lowlight": "^1.17.0",
|
||||||
"prismjs": "^1.27.0",
|
"prismjs": "^1.30.0",
|
||||||
"refractor": "^3.6.0"
|
"refractor": "^3.6.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
@ -1,139 +1,140 @@
|
|||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
import * as scriptsApi from '@/lib/api/scripts';
|
import * as scriptsApi from '@/lib/api/scripts';
|
||||||
import { showSuccess, showError } from '@/utils/toast';
|
import { showSuccess, showError } from '@/utils/toast';
|
||||||
|
|
||||||
// Query keys
|
// Query keys
|
||||||
export const scriptKeys = {
|
export const scriptKeys = {
|
||||||
all: ['scripts'] as const,
|
all: ['scripts'] as const,
|
||||||
lists: () => [...scriptKeys.all, 'list'] as const,
|
lists: () => [...scriptKeys.all, 'list'] as const,
|
||||||
list: (filters: scriptsApi.ScriptFilters) => [...scriptKeys.lists(), filters] as const,
|
list: (filters: scriptsApi.ScriptFilters) => [...scriptKeys.lists(), filters] as const,
|
||||||
details: () => [...scriptKeys.all, 'detail'] as const,
|
details: () => [...scriptKeys.all, 'detail'] as const,
|
||||||
detail: (id: string) => [...scriptKeys.details(), id] as const,
|
detail: (id: string) => [...scriptKeys.details(), id] as const,
|
||||||
popular: () => [...scriptKeys.all, 'popular'] as const,
|
popular: () => [...scriptKeys.all, 'popular'] as const,
|
||||||
recent: () => [...scriptKeys.all, 'recent'] as const,
|
recent: () => [...scriptKeys.all, 'recent'] as const,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get scripts with filters
|
// Get scripts with filters
|
||||||
export function useScripts(filters: scriptsApi.ScriptFilters = {}) {
|
export function useScripts(filters: scriptsApi.ScriptFilters = {}) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: scriptKeys.list(filters),
|
queryKey: scriptKeys.list(filters),
|
||||||
queryFn: () => scriptsApi.getScripts(filters),
|
queryFn: () => scriptsApi.getScripts(filters),
|
||||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get script by ID
|
// Get script by ID
|
||||||
export function useScript(id: string) {
|
export function useScript(id: string) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: scriptKeys.detail(id),
|
queryKey: scriptKeys.detail(id),
|
||||||
queryFn: () => scriptsApi.getScriptById(id),
|
queryFn: () => scriptsApi.getScriptById(id),
|
||||||
enabled: !!id,
|
enabled: !!id,
|
||||||
staleTime: 5 * 60 * 1000,
|
staleTime: 5 * 60 * 1000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get popular scripts
|
// Get popular scripts
|
||||||
export function usePopularScripts(limit?: number) {
|
export function usePopularScripts(limit?: number) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [...scriptKeys.popular(), limit],
|
queryKey: [...scriptKeys.popular(), limit],
|
||||||
queryFn: () => scriptsApi.getPopularScripts(limit),
|
queryFn: () => scriptsApi.getPopularScripts(limit),
|
||||||
staleTime: 10 * 60 * 1000, // 10 minutes
|
staleTime: 10 * 60 * 1000, // 10 minutes
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get recent scripts
|
// Get recent scripts
|
||||||
export function useRecentScripts(limit?: number) {
|
export function useRecentScripts(limit?: number) {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [...scriptKeys.recent(), limit],
|
queryKey: [...scriptKeys.recent(), limit],
|
||||||
queryFn: () => scriptsApi.getRecentScripts(limit),
|
queryFn: () => scriptsApi.getRecentScripts(limit),
|
||||||
staleTime: 5 * 60 * 1000,
|
staleTime: 5 * 60 * 1000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create script mutation
|
// Create script mutation
|
||||||
export function useCreateScript() {
|
export function useCreateScript() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: scriptsApi.createScript,
|
mutationFn: ({ data, userId }: { data: scriptsApi.CreateScriptData; userId: string }) =>
|
||||||
onSuccess: () => {
|
scriptsApi.createScript({...data, authorId: userId, authorName: data.authorName || 'User'}, userId),
|
||||||
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
onSuccess: () => {
|
||||||
showSuccess('Script created successfully!');
|
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
||||||
},
|
showSuccess('Script created successfully!');
|
||||||
onError: (error: any) => {
|
},
|
||||||
showError(error.message || 'Failed to create script');
|
onError: (error: any) => {
|
||||||
},
|
showError(error.message || 'Failed to create script');
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
}
|
||||||
// Update script mutation
|
|
||||||
export function useUpdateScript() {
|
// Update script mutation
|
||||||
const queryClient = useQueryClient();
|
export function useUpdateScript() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, data, userId }: { id: string; data: scriptsApi.UpdateScriptData; userId: string }) =>
|
return useMutation({
|
||||||
scriptsApi.updateScript(id, data, userId),
|
mutationFn: ({ id, data, userId }: { id: string; data: scriptsApi.UpdateScriptData; userId: string }) =>
|
||||||
onSuccess: (data: any) => {
|
scriptsApi.updateScript(id, data, userId),
|
||||||
queryClient.invalidateQueries({ queryKey: scriptKeys.detail(data.id) });
|
onSuccess: (data: any) => {
|
||||||
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
queryClient.invalidateQueries({ queryKey: scriptKeys.detail(data.id) });
|
||||||
showSuccess('Script updated successfully!');
|
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
||||||
},
|
showSuccess('Script updated successfully!');
|
||||||
onError: (error: any) => {
|
},
|
||||||
showError(error.message || 'Failed to update script');
|
onError: (error: any) => {
|
||||||
},
|
showError(error.message || 'Failed to update script');
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
}
|
||||||
// Delete script mutation
|
|
||||||
export function useDeleteScript() {
|
// Delete script mutation
|
||||||
const queryClient = useQueryClient();
|
export function useDeleteScript() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, userId }: { id: string; userId: string }) =>
|
return useMutation({
|
||||||
scriptsApi.deleteScript(id, userId),
|
mutationFn: ({ id, userId }: { id: string; userId: string }) =>
|
||||||
onSuccess: (_, variables) => {
|
scriptsApi.deleteScript(id, userId),
|
||||||
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
onSuccess: (_, variables) => {
|
||||||
queryClient.removeQueries({ queryKey: scriptKeys.detail(variables.id) });
|
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
||||||
showSuccess('Script deleted successfully!');
|
queryClient.removeQueries({ queryKey: scriptKeys.detail(variables.id) });
|
||||||
},
|
showSuccess('Script deleted successfully!');
|
||||||
onError: (error: any) => {
|
},
|
||||||
showError(error.message || 'Failed to delete script');
|
onError: (error: any) => {
|
||||||
},
|
showError(error.message || 'Failed to delete script');
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
}
|
||||||
// Moderate script mutation (admin only)
|
|
||||||
export function useModerateScript() {
|
// Moderate script mutation (admin only)
|
||||||
const queryClient = useQueryClient();
|
export function useModerateScript() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
return useMutation({
|
|
||||||
mutationFn: ({ id, isApproved, moderatorId }: { id: string; isApproved: boolean; moderatorId: string }) =>
|
return useMutation({
|
||||||
scriptsApi.moderateScript(id, isApproved, moderatorId),
|
mutationFn: ({ id, isApproved, moderatorId }: { id: string; isApproved: boolean; moderatorId: string }) =>
|
||||||
onSuccess: (data: any) => {
|
scriptsApi.moderateScript(id, isApproved, moderatorId),
|
||||||
queryClient.invalidateQueries({ queryKey: scriptKeys.detail(data.id) });
|
onSuccess: (data: any) => {
|
||||||
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
queryClient.invalidateQueries({ queryKey: scriptKeys.detail(data.id) });
|
||||||
showSuccess(`Script ${data.isApproved ? 'approved' : 'rejected'} successfully!`);
|
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
|
||||||
},
|
showSuccess(`Script ${data.isApproved ? 'approved' : 'rejected'} successfully!`);
|
||||||
onError: (error: any) => {
|
},
|
||||||
showError(error.message || 'Failed to moderate script');
|
onError: (error: any) => {
|
||||||
},
|
showError(error.message || 'Failed to moderate script');
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
}
|
||||||
// Track view mutation
|
|
||||||
export function useTrackView() {
|
// Track view mutation
|
||||||
return useMutation({
|
export function useTrackView() {
|
||||||
mutationFn: scriptsApi.incrementViewCount,
|
return useMutation({
|
||||||
// Don't show success/error messages for view tracking
|
mutationFn: scriptsApi.incrementViewCount,
|
||||||
});
|
// Don't show success/error messages for view tracking
|
||||||
}
|
});
|
||||||
|
}
|
||||||
// Track download mutation
|
|
||||||
export function useTrackDownload() {
|
// Track download mutation
|
||||||
return useMutation({
|
export function useTrackDownload() {
|
||||||
mutationFn: scriptsApi.incrementDownloadCount,
|
return useMutation({
|
||||||
onSuccess: () => {
|
mutationFn: scriptsApi.incrementDownloadCount,
|
||||||
showSuccess('Download started!');
|
onSuccess: () => {
|
||||||
},
|
showSuccess('Download started!');
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
@ -39,7 +39,7 @@ export interface ScriptFilters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new script
|
// Create a new script
|
||||||
export async function createScript(data: CreateScriptData) {
|
export async function createScript(data: CreateScriptData, userId?: string) {
|
||||||
try {
|
try {
|
||||||
const scriptId = generateId();
|
const scriptId = generateId();
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
363
src/server.ts
363
src/server.ts
@ -1,179 +1,184 @@
|
|||||||
import express, { Request, Response, NextFunction } from 'express';
|
import express, { Request, Response, NextFunction } from 'express';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import { getAllUsers, getUserById } from './lib/api/users.js';
|
import { getAllUsers, getUserById } from './lib/api/users.js';
|
||||||
import { getScripts, getScriptById, createScript } from './lib/api/scripts.js';
|
import { getScripts, getScriptById, createScript } from './lib/api/scripts.js';
|
||||||
import { login, register } from './lib/api/auth.js';
|
import { login, register } from './lib/api/auth.js';
|
||||||
import { rateScript, getScriptRatingStats } from './lib/api/ratings.js';
|
import { rateScript, getScriptRatingStats } from './lib/api/ratings.js';
|
||||||
import { getPlatformAnalytics, trackEvent } from './lib/api/analytics.js';
|
import { getPlatformAnalytics, trackEvent } from './lib/api/analytics.js';
|
||||||
import { getUserCollections, getPublicCollections } from './lib/api/collections.js';
|
import { getUserCollections, getPublicCollections } from './lib/api/collections.js';
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
origin: process.env.CORS_ORIGIN || '*',
|
origin: process.env.CORS_ORIGIN || '*',
|
||||||
credentials: true
|
credentials: true
|
||||||
}));
|
}));
|
||||||
app.use(express.json({ limit: '10mb' }));
|
app.use(express.json({ limit: '10mb' }));
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
|
|
||||||
// Health check endpoint
|
// Health check endpoint
|
||||||
app.get('/api/health', (_req: Request, res: Response) => {
|
app.get('/api/health', (_req: Request, res: Response) => {
|
||||||
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auth routes
|
// Auth routes
|
||||||
app.post('/api/auth/login', async (req: Request, res: Response) => {
|
app.post('/api/auth/login', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const result = await login(req.body);
|
const result = await login(req.body);
|
||||||
res.json(result);
|
res.json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Login error:', error);
|
console.error('Login error:', error);
|
||||||
res.status(401).json({ error: 'Invalid credentials' });
|
res.status(401).json({ error: 'Invalid credentials' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/auth/register', async (req: Request, res: Response) => {
|
app.post('/api/auth/register', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const result = await register(req.body);
|
const result = await register(req.body);
|
||||||
res.json(result);
|
res.json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Register error:', error);
|
console.error('Register error:', error);
|
||||||
res.status(400).json({ error: 'Registration failed' });
|
res.status(400).json({ error: 'Registration failed' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Scripts routes
|
// Scripts routes
|
||||||
app.get('/api/scripts', async (req: Request, res: Response) => {
|
app.get('/api/scripts', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const result = await getScripts(req.query);
|
const result = await getScripts(req.query);
|
||||||
res.json(result);
|
res.json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Get scripts error:', error);
|
console.error('Get scripts error:', error);
|
||||||
res.status(500).json({ error: 'Failed to fetch scripts' });
|
res.status(500).json({ error: 'Failed to fetch scripts' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/scripts/:id', async (req: Request, res: Response) => {
|
app.get('/api/scripts/:id', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const script = await getScriptById(req.params.id);
|
const script = await getScriptById(req.params.id);
|
||||||
if (!script) {
|
if (!script) {
|
||||||
return res.status(404).json({ error: 'Script not found' });
|
return res.status(404).json({ error: 'Script not found' });
|
||||||
}
|
}
|
||||||
res.json(script);
|
res.json(script);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Get script error:', error);
|
console.error('Get script error:', error);
|
||||||
res.status(500).json({ error: 'Failed to fetch script' });
|
res.status(500).json({ error: 'Failed to fetch script' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/scripts', async (req: Request, res: Response) => {
|
app.post('/api/scripts', async (req: Request, res: Response) => {
|
||||||
try {
|
try {
|
||||||
const userId = req.headers['x-user-id'] as string;
|
const userId = req.headers['x-user-id'] as string;
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
return res.status(401).json({ error: 'Unauthorized' });
|
return res.status(401).json({ error: 'Unauthorized' });
|
||||||
}
|
}
|
||||||
const result = await createScript(req.body);
|
// Make sure userId is included in the request body
|
||||||
res.json(result);
|
const scriptData = {
|
||||||
} catch (error) {
|
...req.body,
|
||||||
console.error('Create script error:', error);
|
authorId: userId
|
||||||
res.status(500).json({ error: 'Failed to create script' });
|
};
|
||||||
}
|
const result = await createScript(scriptData, userId);
|
||||||
});
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
// Users routes
|
console.error('Create script error:', error);
|
||||||
app.get('/api/users', async (_req: Request, res: Response) => {
|
res.status(500).json({ error: 'Failed to create script' });
|
||||||
try {
|
}
|
||||||
const result = await getAllUsers();
|
});
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
// Users routes
|
||||||
console.error('Get users error:', error);
|
app.get('/api/users', async (_req: Request, res: Response) => {
|
||||||
res.status(500).json({ error: 'Failed to fetch users' });
|
try {
|
||||||
}
|
const result = await getAllUsers();
|
||||||
});
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
app.get('/api/users/:id', async (req: Request, res: Response) => {
|
console.error('Get users error:', error);
|
||||||
try {
|
res.status(500).json({ error: 'Failed to fetch users' });
|
||||||
const user = await getUserById(req.params.id);
|
}
|
||||||
if (!user) {
|
});
|
||||||
return res.status(404).json({ error: 'User not found' });
|
|
||||||
}
|
app.get('/api/users/:id', async (req: Request, res: Response) => {
|
||||||
res.json(user);
|
try {
|
||||||
} catch (error) {
|
const user = await getUserById(req.params.id);
|
||||||
console.error('Get user error:', error);
|
if (!user) {
|
||||||
res.status(500).json({ error: 'Failed to fetch user' });
|
return res.status(404).json({ error: 'User not found' });
|
||||||
}
|
}
|
||||||
});
|
res.json(user);
|
||||||
|
} catch (error) {
|
||||||
// Analytics routes
|
console.error('Get user error:', error);
|
||||||
app.get('/api/analytics/platform', async (req: Request, res: Response) => {
|
res.status(500).json({ error: 'Failed to fetch user' });
|
||||||
try {
|
}
|
||||||
const days = parseInt(req.query.days as string) || 30;
|
});
|
||||||
const result = await getPlatformAnalytics(days);
|
|
||||||
res.json(result);
|
// Analytics routes
|
||||||
} catch (error) {
|
app.get('/api/analytics/platform', async (req: Request, res: Response) => {
|
||||||
console.error('Analytics error:', error);
|
try {
|
||||||
res.status(500).json({ error: 'Failed to fetch analytics' });
|
const days = parseInt(req.query.days as string) || 30;
|
||||||
}
|
const result = await getPlatformAnalytics(days);
|
||||||
});
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
app.post('/api/analytics/track', async (req: Request, res: Response) => {
|
console.error('Analytics error:', error);
|
||||||
try {
|
res.status(500).json({ error: 'Failed to fetch analytics' });
|
||||||
const result = await trackEvent(req.body);
|
}
|
||||||
res.json(result);
|
});
|
||||||
} catch (error) {
|
|
||||||
console.error('Track event error:', error);
|
app.post('/api/analytics/track', async (req: Request, res: Response) => {
|
||||||
res.status(500).json({ error: 'Failed to track event' });
|
try {
|
||||||
}
|
const result = await trackEvent(req.body);
|
||||||
});
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
// Collections routes
|
console.error('Track event error:', error);
|
||||||
app.get('/api/collections', async (req: Request, res: Response) => {
|
res.status(500).json({ error: 'Failed to track event' });
|
||||||
try {
|
}
|
||||||
const userId = req.headers['x-user-id'] as string;
|
});
|
||||||
const result = userId ? await getUserCollections(userId) : await getPublicCollections();
|
|
||||||
res.json(result);
|
// Collections routes
|
||||||
} catch (error) {
|
app.get('/api/collections', async (req: Request, res: Response) => {
|
||||||
console.error('Get collections error:', error);
|
try {
|
||||||
res.status(500).json({ error: 'Failed to fetch collections' });
|
const userId = req.headers['x-user-id'] as string;
|
||||||
}
|
const result = userId ? await getUserCollections(userId) : await getPublicCollections();
|
||||||
});
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
// Ratings routes
|
console.error('Get collections error:', error);
|
||||||
app.post('/api/ratings', async (req: Request, res: Response) => {
|
res.status(500).json({ error: 'Failed to fetch collections' });
|
||||||
try {
|
}
|
||||||
const result = await rateScript(req.body);
|
});
|
||||||
res.json(result);
|
|
||||||
} catch (error) {
|
// Ratings routes
|
||||||
console.error('Rate script error:', error);
|
app.post('/api/ratings', async (req: Request, res: Response) => {
|
||||||
res.status(500).json({ error: 'Failed to rate script' });
|
try {
|
||||||
}
|
const result = await rateScript(req.body);
|
||||||
});
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
app.get('/api/scripts/:id/ratings', async (req: Request, res: Response) => {
|
console.error('Rate script error:', error);
|
||||||
try {
|
res.status(500).json({ error: 'Failed to rate script' });
|
||||||
const result = await getScriptRatingStats(req.params.id);
|
}
|
||||||
res.json(result);
|
});
|
||||||
} catch (error) {
|
|
||||||
console.error('Get ratings error:', error);
|
app.get('/api/scripts/:id/ratings', async (req: Request, res: Response) => {
|
||||||
res.status(500).json({ error: 'Failed to fetch ratings' });
|
try {
|
||||||
}
|
const result = await getScriptRatingStats(req.params.id);
|
||||||
});
|
res.json(result);
|
||||||
|
} catch (error) {
|
||||||
// Error handling middleware
|
console.error('Get ratings error:', error);
|
||||||
app.use((error: any, _req: Request, res: Response, _next: NextFunction) => {
|
res.status(500).json({ error: 'Failed to fetch ratings' });
|
||||||
console.error('Unhandled error:', error);
|
}
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
});
|
||||||
});
|
|
||||||
|
// Error handling middleware
|
||||||
// 404 handler
|
app.use((error: any, _req: Request, res: Response, _next: NextFunction) => {
|
||||||
app.use('*', (_req: Request, res: Response) => {
|
console.error('Unhandled error:', error);
|
||||||
res.status(404).json({ error: 'Endpoint not found' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
// 404 handler
|
||||||
console.log(`ScriptShare API server running on port ${PORT}`);
|
app.use('*', (_req: Request, res: Response) => {
|
||||||
console.log(`Environment: ${process.env.NODE_ENV}`);
|
res.status(404).json({ error: 'Endpoint not found' });
|
||||||
console.log(`Database URL configured: ${!!process.env.DATABASE_URL}`);
|
});
|
||||||
});
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`ScriptShare API server running on port ${PORT}`);
|
||||||
|
console.log(`Environment: ${process.env.NODE_ENV}`);
|
||||||
|
console.log(`Database URL configured: ${!!process.env.DATABASE_URL}`);
|
||||||
|
});
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
/* Linting */
|
/* Linting */
|
||||||
"strict": false,
|
"strict": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": true,
|
||||||
"noUnusedLocals": false,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": false,
|
"noUnusedParameters": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
|
||||||
/* Path mapping */
|
/* Path mapping */
|
||||||
|
Reference in New Issue
Block a user