| export type ProjectRuntime = 'static' | 'handlebars' | 'react' | 'preact' | 'svelte' | 'vue' | 'python' | 'lua'; |
|
|
| export interface Project { |
| id: string; |
| name: string; |
| description?: string; |
| createdAt: Date; |
| updatedAt: Date; |
| settings: { |
| runtime?: ProjectRuntime; |
| defaultTemplate?: string; |
| globalStyles?: string; |
| previewEntryPoint?: string; |
| githubRepo?: { |
| owner: string; |
| name: string; |
| html_url: string; |
| full_name: string; |
| }; |
| }; |
| lastSavedCheckpointId?: string | null; |
| lastSavedAt?: Date | null; |
| previewImage?: string; |
| previewUpdatedAt?: Date; |
| lastSyncedAt?: Date | null; |
| serverUpdatedAt?: Date | null; |
| syncStatus?: 'synced' | 'syncing' | 'error' | 'never-synced'; |
| costTracking?: { |
| totalCost: number; |
| providerBreakdown: Record<string, { |
| totalCost: number; |
| tokenUsage: { |
| input: number; |
| output: number; |
| reasoning?: number; |
| cached?: number; |
| }; |
| requestCount: number; |
| lastUpdated: Date; |
| }>; |
| sessionHistory?: Array<{ |
| sessionId: string; |
| cost: number; |
| provider: string; |
| timestamp: Date; |
| tokenUsage?: { |
| input: number; |
| output: number; |
| }; |
| correction?: boolean; |
| }>; |
| }; |
| } |
|
|
| |
| export interface Deployment { |
| |
| id: string; |
| projectId: string; |
| name: string; |
| slug?: string; |
| enabled: boolean; |
|
|
| |
| underConstruction: boolean; |
| customDomain?: string; |
| headScripts: ScriptConfig[]; |
| bodyScripts: ScriptConfig[]; |
| cdnLinks: CdnConfig[]; |
| analytics: AnalyticsConfig; |
| seo: SeoConfig; |
| compliance: ComplianceConfig; |
|
|
| |
| settingsVersion: number; |
| lastPublishedVersion?: number; |
|
|
| |
| previewImage?: string; |
| previewUpdatedAt?: Date; |
|
|
| |
| databaseEnabled?: boolean; |
|
|
| |
| createdAt: Date; |
| updatedAt: Date; |
| publishedAt?: Date | null; |
| } |
|
|
| |
| export interface PublishSettings { |
| |
| enabled: boolean; |
| underConstruction: boolean; |
| customDomain?: string; |
|
|
| |
| headScripts: ScriptConfig[]; |
| bodyScripts: ScriptConfig[]; |
| cdnLinks: CdnConfig[]; |
|
|
| |
| analytics: AnalyticsConfig; |
|
|
| |
| seo: SeoConfig; |
|
|
| |
| compliance: ComplianceConfig; |
|
|
| |
| settingsVersion: number; |
| lastPublishedVersion?: number; |
| } |
|
|
| export interface ScriptConfig { |
| id: string; |
| name: string; |
| content: string; |
| type: 'inline' | 'external'; |
| src?: string; |
| async?: boolean; |
| defer?: boolean; |
| enabled: boolean; |
| } |
|
|
| export interface CdnConfig { |
| id: string; |
| name: string; |
| url: string; |
| type: 'css' | 'js'; |
| integrity?: string; |
| crossorigin?: 'anonymous' | 'use-credentials'; |
| enabled: boolean; |
| } |
|
|
| export interface AnalyticsConfig { |
| enabled: boolean; |
| provider: 'builtin' | 'gtm' | 'ga4' | 'plausible' | 'custom'; |
| trackingId?: string; |
| customScript?: string; |
| privacyMode: boolean; |
|
|
| |
| features?: { |
| basicTracking?: boolean; |
| heatmaps?: boolean; |
| sessionRecording?: boolean; |
| performanceMetrics?: boolean; |
| engagementTracking?: boolean; |
| customEvents?: boolean; |
| }; |
|
|
| |
| retention?: { |
| pageviews?: number; |
| interactions?: number; |
| sessions?: number; |
| }; |
|
|
| |
| token?: string; |
| tokenGeneratedAt?: string; |
| } |
|
|
| export interface SeoConfig { |
| title?: string; |
| description?: string; |
| keywords?: string[]; |
| ogImage?: string; |
| ogTitle?: string; |
| ogDescription?: string; |
| twitterCard?: 'summary' | 'summary_large_image'; |
| canonical?: string; |
| noIndex?: boolean; |
| noFollow?: boolean; |
| } |
|
|
| export interface ComplianceConfig { |
| enabled: boolean; |
| bannerPosition: 'top' | 'bottom'; |
| bannerStyle: 'bar' | 'modal' | 'corner'; |
| message: string; |
| acceptButtonText: string; |
| declineButtonText: string; |
| privacyPolicyUrl?: string; |
| cookiePolicyUrl?: string; |
| mode: 'opt-in' | 'opt-out'; |
| blockAnalytics: boolean; |
| } |
|
|
| export interface VirtualFile { |
| id: string; |
| projectId: string; |
| path: string; |
| name: string; |
| type: 'html' | 'css' | 'js' | 'json' | 'text' | 'template' | 'image' | 'video' | 'binary'; |
| content: string | ArrayBuffer; |
| mimeType: string; |
| size: number; |
| createdAt: Date; |
| updatedAt: Date; |
| metadata: { |
| isEntry?: boolean; |
| dependencies?: string[]; |
| isTransient?: boolean; |
| isGenerated?: boolean; |
| isBuiltIn?: boolean; |
| isServerContext?: boolean; |
| isReadOnly?: boolean; |
| }; |
| } |
|
|
| export interface FileTreeNode { |
| id: string; |
| projectId: string; |
| path: string; |
| name: string; |
| type: 'directory' | 'file'; |
| parentPath: string | null; |
| isExpanded?: boolean; |
| children?: string[]; |
| metadata?: Record<string, unknown>; |
| } |
|
|
| export interface FileOperation { |
| projectId: string; |
| path: string; |
| content?: string | ArrayBuffer; |
| newPath?: string; |
| } |
|
|
| export type FileType = VirtualFile['type']; |
|
|
| export const MIME_TYPES: Record<FileType, string> = { |
| html: 'text/html', |
| css: 'text/css', |
| js: 'application/javascript', |
| json: 'application/json', |
| text: 'text/plain', |
| template: 'text/x-handlebars-template', |
| image: 'image/*', |
| video: 'video/*', |
| binary: 'application/octet-stream' |
| }; |
|
|
| export const SUPPORTED_EXTENSIONS = { |
| html: ['html', 'htm'], |
| css: ['css'], |
| js: ['js', 'mjs', 'jsx', 'ts', 'tsx', 'svelte', 'vue', 'py', 'lua'], |
| json: ['json'], |
| text: ['txt', 'md', 'xml', 'svg'], |
| template: ['hbs', 'handlebars'], |
| image: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'ico', 'bmp'], |
| video: ['mp4', 'webm', 'ogg'] |
| }; |
|
|
| export const FILE_SIZE_LIMITS = { |
| text: 5 * 1024 * 1024, |
| html: 5 * 1024 * 1024, |
| css: 5 * 1024 * 1024, |
| js: 5 * 1024 * 1024, |
| json: 5 * 1024 * 1024, |
| template: 5 * 1024 * 1024, |
| image: 10 * 1024 * 1024, |
| video: 50 * 1024 * 1024, |
| binary: 10 * 1024 * 1024 |
| }; |
|
|
| export function getFileTypeFromPath(path: string): FileType { |
| const ext = path.split('.').pop()?.toLowerCase(); |
| |
| for (const [type, extensions] of Object.entries(SUPPORTED_EXTENSIONS)) { |
| if (extensions.includes(ext || '')) { |
| return type as FileType; |
| } |
| } |
| |
| return 'text'; |
| } |
|
|
| export function getSpecificMimeType(path: string): string { |
| const ext = path.split('.').pop()?.toLowerCase(); |
| |
| const mimeMap: Record<string, string> = { |
| 'html': 'text/html', |
| 'htm': 'text/html', |
| |
| 'css': 'text/css', |
| |
| 'js': 'application/javascript', |
| 'mjs': 'application/javascript', |
| 'jsx': 'application/javascript', |
| 'ts': 'application/typescript', |
| 'tsx': 'application/typescript', |
| 'svelte': 'text/x-svelte', |
| 'vue': 'text/x-vue', |
| 'py': 'text/x-python', |
| 'lua': 'text/x-lua', |
|
|
| 'json': 'application/json', |
| |
| 'txt': 'text/plain', |
| 'md': 'text/markdown', |
| 'xml': 'application/xml', |
| 'svg': 'image/svg+xml', |
| |
| 'hbs': 'text/x-handlebars-template', |
| 'handlebars': 'text/x-handlebars-template', |
| |
| 'png': 'image/png', |
| 'jpg': 'image/jpeg', |
| 'jpeg': 'image/jpeg', |
| 'gif': 'image/gif', |
| 'webp': 'image/webp', |
| 'ico': 'image/x-icon', |
| 'bmp': 'image/bmp', |
| |
| 'mp4': 'video/mp4', |
| 'webm': 'video/webm', |
| 'ogg': 'video/ogg' |
| }; |
| |
| return mimeMap[ext || ''] || 'application/octet-stream'; |
| } |
|
|
| export function isFileSupported(fileName: string): boolean { |
| const ext = fileName.split('.').pop()?.toLowerCase(); |
| for (const extensions of Object.values(SUPPORTED_EXTENSIONS)) { |
| if (extensions.includes(ext || '')) { |
| return true; |
| } |
| } |
| return false; |
| } |
|
|
| export function getMimeType(type: FileType): string { |
| return MIME_TYPES[type]; |
| } |
|
|
| |
|
|
| export interface CustomTemplate { |
| id: string; |
| name: string; |
| description: string; |
| version: string; |
| files: Array<{path: string; content: string | ArrayBuffer}>; |
| directories: string[]; |
| assets?: Array<{ |
| filename: string; |
| path: string; |
| }>; |
| metadata: { |
| author?: string; |
| authorUrl?: string; |
| license: string; |
| licenseLabel?: string; |
| licenseDescription?: string; |
| tags?: string[]; |
| thumbnail?: string; |
| previewImages?: string[]; |
| downloadUrl?: string; |
| }; |
| runtime?: ProjectRuntime; |
| importedAt: Date; |
| updatedAt?: Date; |
| backendFeatures?: BackendFeatures; |
| } |
|
|
| export interface LicenseOption { |
| value: string; |
| label: string; |
| description: string; |
| } |
|
|
| |
| export interface EdgeFunction { |
| id: string; |
| projectId: string; |
| name: string; |
| description?: string; |
| code: string; |
| method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'ANY'; |
| enabled: boolean; |
| timeoutMs: number; |
| createdAt: Date; |
| updatedAt: Date; |
| } |
|
|
| export interface FunctionLog { |
| id: number; |
| functionId: string; |
| method: string; |
| path: string; |
| statusCode: number; |
| durationMs: number; |
| error?: string; |
| timestamp: Date; |
| } |
|
|
| |
| export interface TableInfo { |
| name: string; |
| columns: ColumnInfo[]; |
| rowCount: number; |
| isSystemTable: boolean; |
| } |
|
|
| export interface ColumnInfo { |
| name: string; |
| type: string; |
| nullable: boolean; |
| primaryKey: boolean; |
| defaultValue?: string; |
| } |
|
|
| |
| export interface ServerFunction { |
| id: string; |
| projectId: string; |
| name: string; |
| description?: string; |
| code: string; |
| enabled: boolean; |
| createdAt: Date; |
| updatedAt: Date; |
| } |
|
|
| |
| export interface Secret { |
| id: string; |
| projectId: string; |
| name: string; |
| description?: string; |
| hasValue: boolean; |
| value?: string; |
| createdAt: Date; |
| updatedAt: Date; |
| } |
|
|
| |
| export interface ScheduledFunction { |
| id: string; |
| projectId: string; |
| name: string; |
| description?: string; |
| functionId: string; |
| cronExpression: string; |
| timezone: string; |
| config: Record<string, unknown>; |
| enabled: boolean; |
| lastRunAt?: Date; |
| nextRunAt?: Date; |
| lastStatus?: 'success' | 'error'; |
| lastError?: string; |
| lastDurationMs?: number; |
| createdAt: Date; |
| updatedAt: Date; |
| } |
|
|
| |
| export interface BackendFeatures { |
| edgeFunctions?: Array<{ |
| name: string; |
| method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'ANY'; |
| code: string; |
| description?: string; |
| enabled?: boolean; |
| timeoutMs?: number; |
| }>; |
| serverFunctions?: Array<{ |
| name: string; |
| code: string; |
| description?: string; |
| enabled?: boolean; |
| }>; |
| secrets?: Array<{ |
| name: string; |
| description?: string; |
| }>; |
| scheduledFunctions?: Array<{ |
| name: string; |
| functionName: string; |
| cronExpression: string; |
| timezone?: string; |
| description?: string; |
| config?: Record<string, unknown>; |
| enabled?: boolean; |
| }>; |
| databaseSchema?: string; |
| deploymentSettings?: Record<string, unknown>; |
| } |
|
|
| export const LICENSE_OPTIONS: LicenseOption[] = [ |
| { |
| value: 'personal', |
| label: 'Personal Use Only', |
| description: 'Cannot be resold or used commercially' |
| }, |
| { |
| value: 'commercial', |
| label: 'Commercial Use', |
| description: 'Can be used in commercial projects, cannot resell template' |
| }, |
| { |
| value: 'mit', |
| label: 'MIT License', |
| description: 'Use freely, must include copyright notice' |
| }, |
| { |
| value: 'apache-2.0', |
| label: 'Apache 2.0', |
| description: 'Similar to MIT, with patent protection' |
| }, |
| { |
| value: 'gpl-3.0', |
| label: 'GPL 3.0', |
| description: 'Open source, derivatives must also be GPL' |
| }, |
| { |
| value: 'bsd-3-clause', |
| label: 'BSD 3-Clause', |
| description: 'Permissive, cannot use author name for promotion' |
| }, |
| { |
| value: 'cc-by-4.0', |
| label: 'CC BY 4.0', |
| description: 'Free use with attribution' |
| }, |
| { |
| value: 'cc-by-sa-4.0', |
| label: 'CC BY-SA 4.0', |
| description: 'Free use with attribution, share-alike' |
| }, |
| { |
| value: 'cc-by-nc-4.0', |
| label: 'CC BY-NC 4.0', |
| description: 'Free for non-commercial use with attribution' |
| }, |
| { |
| value: 'unlicense', |
| label: 'Unlicense (Public Domain)', |
| description: 'No restrictions, completely free to use' |
| }, |
| { |
| value: 'all-rights-reserved', |
| label: 'All Rights Reserved', |
| description: 'Most restrictive, requires explicit permission' |
| }, |
| { |
| value: 'custom', |
| label: 'Custom License', |
| description: 'Specify your own terms' |
| } |
| ]; |
|
|