Files
scriptshare-cursor/Dockerfile

208 lines
7.0 KiB
Docker

# Build stage
FROM node:18-alpine AS builder
# Install build dependencies for native modules (bcrypt, etc.)
RUN apk add --no-cache python3 make g++ libc6-compat
WORKDIR /app
# Copy package files first for better Docker layer caching
COPY package*.json ./
# Install dependencies with proper npm cache handling
RUN npm ci --only=production=false --silent
# Copy source code
COPY . .
# Set build-time environment variables
ARG VITE_APP_NAME="ScriptShare"
ARG VITE_APP_URL="https://scriptshare.example.com"
ARG VITE_ANALYTICS_ENABLED="false"
# Export as environment variables for Vite build
ENV VITE_APP_NAME=$VITE_APP_NAME
ENV VITE_APP_URL=$VITE_APP_URL
ENV VITE_ANALYTICS_ENABLED=$VITE_ANALYTICS_ENABLED
# Remove problematic packages from package.json to prevent them from being bundled
RUN sed -i '/"mysql2"/d' package.json
RUN sed -i '/"drizzle-orm"/d' package.json
RUN sed -i '/"bcrypt"/d' package.json
RUN sed -i '/"jsonwebtoken"/d' package.json
RUN sed -i '/"@types\/bcrypt"/d' package.json
RUN sed -i '/"@types\/jsonwebtoken"/d' package.json
RUN sed -i '/"nanoid"/d' package.json
# Reinstall dependencies without server packages
RUN npm install
# Remove problematic server-side API files for frontend-only build
RUN rm -rf src/lib/api || true
RUN rm -rf src/lib/db || true
# Create mock API layer for frontend demo
RUN mkdir -p src/lib/api src/lib/db
# Create mock database files
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
# Create comprehensive mock API files with proper TypeScript support
# Mock API index with proper types
RUN cat > src/lib/api/index.ts << 'EOFILE'
export const generateId = () => Math.random().toString(36).substr(2, 9);
export class ApiError extends Error {
constructor(message: string, public status: number) {
super(message);
this.status = status;
}
}
EOFILE
# Mock auth API with complete interface
RUN cat > src/lib/api/auth.ts << 'EOFILE'
export const authApi = {
login: async (data: any) => ({ token: 'demo', user: { id: '1', username: 'demo' } }),
register: async (data: any) => ({ token: 'demo', user: { id: '1', username: 'demo' } }),
changePassword: async (data: any) => ({}),
refreshToken: async () => ({ token: 'demo' })
};
EOFILE
# Mock scripts API with all required methods
RUN cat > src/lib/api/scripts.ts << 'EOFILE'
export interface ScriptFilters {
search?: string;
categories?: string[];
compatibleOs?: string[];
sortBy?: string;
limit?: number;
isApproved?: boolean;
}
export interface UpdateScriptData {
name?: string;
description?: string;
content?: string;
}
export const scriptsApi = {
getScripts: async (filters?: ScriptFilters) => ({ scripts: [], total: 0 }),
getScriptById: async (id: string) => null,
getPopularScripts: async () => [],
getRecentScripts: async () => [],
createScript: async (data: any) => ({ id: 'mock' }),
updateScript: async (id: string, data: UpdateScriptData, userId: string) => ({ id }),
deleteScript: async (id: string, userId: string) => ({}),
moderateScript: async (id: string, isApproved: boolean, moderatorId: string) => ({ id, isApproved }),
incrementViewCount: async (id: string) => ({}),
incrementDownloadCount: async (id: string) => ({})
};
EOFILE
# Mock ratings API with complete interface
RUN cat > src/lib/api/ratings.ts << 'EOFILE'
export const ratingsApi = {
submitRating: async (data: any) => ({ scriptId: data.scriptId }),
rateScript: async (data: any) => ({ scriptId: data.scriptId }),
getUserRating: async (scriptId: string, userId?: string) => null,
getScriptRatings: async (scriptId: string) => [],
getScriptRatingStats: async (scriptId: string) => ({ averageRating: 0, totalRatings: 0, distribution: {} }),
deleteRating: async (scriptId: string, userId: string) => ({})
};
EOFILE
# Mock analytics API with complete interface
RUN cat > src/lib/api/analytics.ts << 'EOFILE'
export interface AnalyticsFilters {
startDate?: Date;
endDate?: Date;
}
export const analyticsApi = {
trackEvent: async (data: any) => ({}),
getAnalytics: async () => ({ views: [], downloads: [], topScripts: [], userGrowth: [] }),
getAnalyticsEvents: async (filters?: AnalyticsFilters) => [],
getScriptAnalytics: async (scriptId: string) => ({ views: [], downloads: [] }),
getPlatformAnalytics: async () => ({ totalUsers: 0, totalScripts: 0 }),
getUserAnalytics: async (userId: string) => ({ views: [], downloads: [] })
};
EOFILE
# Mock collections API with complete interface
RUN cat > src/lib/api/collections.ts << 'EOFILE'
export interface UpdateCollectionData {
name?: string;
description?: string;
}
export const collectionsApi = {
getCollections: async () => [],
getCollectionById: async (id: string) => null,
getUserCollections: async (userId: string) => [],
getPublicCollections: async () => [],
createCollection: async (data: any) => ({ id: 'mock' }),
updateCollection: async (id: string, data: UpdateCollectionData) => ({ id }),
deleteCollection: async (id: string) => ({}),
addScriptToCollection: async (collectionId: string, scriptId: string) => ({}),
removeScriptFromCollection: async (collectionId: string, scriptId: string) => ({}),
isScriptInCollection: async (collectionId: string, scriptId: string) => false
};
EOFILE
# Mock users API with complete interface
RUN cat > src/lib/api/users.ts << 'EOFILE'
export interface UpdateUserData {
username?: string;
displayName?: string;
bio?: string;
}
export const usersApi = {
getUser: async (id: string) => null,
getUserById: async (id: string) => null,
getAllUsers: async () => [],
searchUsers: async (query: string) => [],
createUser: async (data: any) => ({ id: 'mock' }),
updateUser: async (id: string, data: UpdateUserData) => ({ id }),
updateUserPermissions: async (id: string, permissions: any) => ({ id })
};
EOFILE
# Build the application (frontend only with mocks)
RUN npm run build
# Verify build output exists
RUN ls -la /app/dist
# Production stage
FROM nginx:alpine
# Install curl for health checks
RUN apk add --no-cache curl
# Copy built files from builder stage
COPY --from=builder /app/dist /usr/share/nginx/html
# Copy nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf
# Create nginx pid directory
RUN mkdir -p /var/run/nginx
# Set proper permissions
RUN chown -R nginx:nginx /usr/share/nginx/html
RUN chown -R nginx:nginx /var/cache/nginx
RUN chown -R nginx:nginx /var/log/nginx
RUN chown -R nginx:nginx /var/run/nginx
# Switch to non-root user for security
USER nginx
# Expose port 80
EXPOSE 80
# Add healthcheck
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost/health || exit 1
# Start nginx
CMD ["nginx", "-g", "daemon off;"]