Compare commits

...

2 Commits

7 changed files with 423 additions and 396 deletions

View File

@ -23,6 +23,24 @@
**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
### **Issue 4: Mock API Build Order & TypeScript Errors** ❌→✅
**Problem**:
- TypeScript compilation errors in mock API functions
- Build order issue: source files copied before mock API creation
- Server.ts file causing compilation errors
**Root Cause**:
- Mock API files created after source code copy
- TypeScript compilation happening before mock API is ready
- Server.ts file not needed for frontend demo
**Fix Applied**:
1. Reordered Dockerfile: create mock API structure BEFORE copying source code
2. Added `rm -f src/server.ts` to remove server file
3. Fixed function signatures in mock API (added missing parameters)
4. Fixed useCreateScript hook to properly handle userId parameter
5. Fixed server.ts createScript call to pass userId parameter
## 📋 Changes Made ## 📋 Changes Made
### **1. Updated Dockerfile (Lines 77, 89, 113)** ### **1. Updated Dockerfile (Lines 77, 89, 113)**
@ -42,9 +60,11 @@ CMD curl -f http://localhost/ || wget -q --spider http://localhost/ || exit 1
After these fixes: After these fixes:
1. **TypeScript Build**: ✅ Should compile `.tsx` files successfully 1. **TypeScript Build**: ✅ Should compile `.tsx` files successfully
2. **Health Check**: ✅ Should pass using either curl or wget 2. **Mock API**: ✅ Should compile without TypeScript errors
3. **Container Status**: ✅ Should show as healthy 3. **Health Check**: ✅ Should pass using either curl or wget
4. **Deployment**: ✅ Should complete without rollback 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 ## 🎯 Root Cause Analysis

View File

@ -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
View File

@ -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": {

View File

@ -55,7 +55,8 @@ export function useCreateScript() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: scriptsApi.createScript, mutationFn: ({ data, userId }: { data: scriptsApi.CreateScriptData; userId: string }) =>
scriptsApi.createScript({...data, authorId: userId, authorName: data.authorName || 'User'}, userId),
onSuccess: () => { onSuccess: () => {
queryClient.invalidateQueries({ queryKey: scriptKeys.lists() }); queryClient.invalidateQueries({ queryKey: scriptKeys.lists() });
showSuccess('Script created successfully!'); showSuccess('Script created successfully!');

View File

@ -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();

View File

@ -74,7 +74,12 @@ app.post('/api/scripts', async (req: Request, res: Response) => {
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
const scriptData = {
...req.body,
authorId: userId
};
const result = await createScript(scriptData, userId);
res.json(result); res.json(result);
} catch (error) { } catch (error) {
console.error('Create script error:', error); console.error('Create script error:', error);

View File

@ -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 */