-
Notifications
You must be signed in to change notification settings - Fork 90
Expand file tree
/
Copy pathpreload.js
More file actions
117 lines (95 loc) · 32.4 KB
/
Copy pathpreload.js
File metadata and controls
117 lines (95 loc) · 32.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/config/subscription-config.ts":
/*!*******************************************!*\
!*** ./src/config/subscription-config.ts ***!
\*******************************************/
/***/ ((__unused_webpack_module, exports) => {
eval("\n/**\n * Configuration for Jarvis subscription service\n */\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.config = void 0;\n// Safe environment variable access for both main and renderer processes\nconst getEnvVar = (key, defaultValue) => {\n try {\n // Check if process is available (Node.js environment)\n if (typeof process !== 'undefined' && process.env) {\n return process.env[key] || defaultValue;\n }\n // Fallback to default value in browser environment\n return defaultValue;\n }\n catch (error) {\n return defaultValue;\n }\n};\nexports.config = {\n // Firebase configuration\n firebase: {\n baseUrl: getEnvVar('FIREBASE_FUNCTIONS_URL', 'https://us-central1-jarvis-aa14d.cloudfunctions.net'),\n projectId: getEnvVar('FIREBASE_PROJECT_ID', 'jarvis-aa14d'),\n },\n // Subscription configuration\n subscription: {\n trialDurationDays: 7,\n maxRetries: 3,\n timeoutMs: 30000,\n },\n // Security configuration\n security: {\n enableLogging: getEnvVar('NODE_ENV', 'development') !== 'production',\n enableSensitiveDataLogging: false,\n rateLimitRequests: 100,\n rateLimitWindowMs: 60000, // 1 minute\n },\n // Validation configuration\n validation: {\n maxUserIdLength: 128,\n maxEmailLength: 254,\n emailRegex: /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/,\n },\n};\nexports[\"default\"] = exports.config;\n\n\n//# sourceURL=webpack://jarvis-ai-assistant/./src/config/subscription-config.ts?");
/***/ }),
/***/ "./src/preload.ts":
/*!************************!*\
!*** ./src/preload.ts ***!
\************************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
eval("\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || (function () {\n var ownKeys = function(o) {\n ownKeys = Object.getOwnPropertyNames || function (o) {\n var ar = [];\n for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;\n return ar;\n };\n return ownKeys(o);\n };\n return function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== \"default\") __createBinding(result, mod, k[i]);\n __setModuleDefault(result, mod);\n return result;\n };\n})();\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nconst electron_1 = __webpack_require__(/*! electron */ \"electron\");\nelectron_1.contextBridge.exposeInMainWorld('electronAPI', {\n getStats: () => electron_1.ipcRenderer.invoke('get-stats'),\n refreshAnalytics: () => electron_1.ipcRenderer.invoke('refresh-analytics'),\n onStatsUpdate: (callback) => {\n electron_1.ipcRenderer.on('stats-update', (_event, stats) => callback(stats));\n },\n pasteLastTranscription: () => electron_1.ipcRenderer.send('paste-last-transcription'),\n startDictation: () => electron_1.ipcRenderer.send('start-dictation'),\n closeApp: () => electron_1.ipcRenderer.send('close-app'),\n openExternal: (url) => electron_1.ipcRenderer.invoke('open-external', url),\n onOAuthCallback: (callback) => {\n electron_1.ipcRenderer.on('oauth-callback', (_event, data) => callback(data));\n },\n completeOnboarding: () => electron_1.ipcRenderer.invoke('complete-onboarding'),\n checkOnboardingStatus: () => electron_1.ipcRenderer.invoke('check-onboarding-status'),\n cleanupOnboarding: () => electron_1.ipcRenderer.invoke('cleanup-onboarding'),\n startFnKeyMonitor: () => electron_1.ipcRenderer.invoke('start-fn-key-monitor'),\n stopFnKeyMonitor: () => electron_1.ipcRenderer.invoke('stop-fn-key-monitor'),\n onFnKeyEvent: (event, callback) => {\n electron_1.ipcRenderer.on(`fn-key-${event}`, callback);\n },\n // User authentication\n logout: () => electron_1.ipcRenderer.invoke('logout'),\n // Auth state persistence\n saveAuthState: (authState) => electron_1.ipcRenderer.invoke('save-auth-state', authState),\n loadAuthState: () => electron_1.ipcRenderer.invoke('load-auth-state'),\n clearAuthState: () => electron_1.ipcRenderer.invoke('clear-auth-state'),\n validateAuthState: () => electron_1.ipcRenderer.invoke('validate-auth-state'),\n // Permission requests\n requestMicrophonePermission: () => electron_1.ipcRenderer.invoke('request-microphone-permission'),\n requestAccessibilityPermission: () => electron_1.ipcRenderer.invoke('request-accessibility-permission'),\n requestNotificationPermission: () => electron_1.ipcRenderer.invoke('request-notification-permission'),\n checkPermissionStatus: (permission) => electron_1.ipcRenderer.invoke('check-permission-status', permission),\n // Permission monitoring\n startPermissionMonitoring: () => electron_1.ipcRenderer.send('start-permission-monitoring'),\n stopPermissionMonitoring: () => electron_1.ipcRenderer.send('stop-permission-monitoring'),\n onPermissionStatusChange: (callback) => {\n electron_1.ipcRenderer.on('permission-status-changed', (_event, permission, status) => callback(permission, status));\n },\n // Dictionary methods\n getDictionary: () => electron_1.ipcRenderer.invoke('get-dictionary'),\n addDictionaryEntry: (word, pronunciation) => electron_1.ipcRenderer.invoke('add-dictionary-entry', word, pronunciation),\n removeDictionaryEntry: (id) => electron_1.ipcRenderer.invoke('remove-dictionary-entry', id),\n // Subscription methods\n getSubscriptionStatus: async (userId) => {\n // Access the subscription service directly from renderer context\n try {\n const { subscriptionService } = await Promise.resolve().then(() => __importStar(__webpack_require__(/*! ./services/subscription-service */ \"./src/services/subscription-service.ts\")));\n return await subscriptionService.getUserSubscription(userId);\n }\n catch (error) {\n console.error('Failed to get subscription status:', error);\n return null;\n }\n },\n getSubscriptionStatusViaIPC: (userId) => electron_1.ipcRenderer.invoke('get-subscription-status', userId),\n clearSubscriptionCache: () => {\n // This will be called from main process to clear cache\n console.log('✅ Clearing subscription cache from preload');\n // The actual cache clearing will happen in the refreshSubscription call\n return true;\n },\n // Stripe methods\n getStripeCheckoutUrl: () => electron_1.ipcRenderer.invoke('get-stripe-checkout-url'),\n upgradeToPro: () => electron_1.ipcRenderer.invoke('upgrade-to-pro'),\n // Testing methods\n getLogFilePath: () => electron_1.ipcRenderer.invoke('get-log-file-path'),\n // Nudge service methods\n nudgeRecordTyping: () => electron_1.ipcRenderer.invoke('nudge:record-typing'),\n nudgeRecordJarvisUsage: () => electron_1.ipcRenderer.invoke('nudge:record-jarvis-usage'),\n nudgeGetConfig: () => electron_1.ipcRenderer.invoke('nudge:get-config'),\n nudgeUpdateConfig: (config) => electron_1.ipcRenderer.invoke('nudge:update-config', config),\n nudgeSnooze: () => electron_1.ipcRenderer.invoke('nudge:snooze'),\n nudgeClose: () => electron_1.ipcRenderer.invoke('nudge:close'),\n nudgeEnableGlobalTyping: () => electron_1.ipcRenderer.invoke('nudge:enable-global-typing'),\n nudgeResetDaily: () => electron_1.ipcRenderer.invoke('nudge:reset-daily'),\n // Nudge settings methods\n nudgeGetSettings: () => electron_1.ipcRenderer.invoke('nudge:get-settings'),\n nudgeUpdateSettings: (settings) => electron_1.ipcRenderer.invoke('nudge:update-settings'),\n // App settings methods\n appGetSettings: () => electron_1.ipcRenderer.invoke('app:get-settings'),\n appUpdateSettings: (settings) => electron_1.ipcRenderer.invoke('app:update-settings', settings),\n appGetAutoLaunchStatus: () => electron_1.ipcRenderer.invoke('app-settings:get-auto-launch-status'),\n appSyncAutoLaunch: () => electron_1.ipcRenderer.invoke('app-settings:sync-auto-launch'),\n // Shell methods for opening URLs\n shell: {\n openExternal: (url) => electron_1.ipcRenderer.invoke('shell-open-external', url)\n },\n // Update methods\n downloadUpdate: (data) => electron_1.ipcRenderer.invoke('download-update', data),\n getAppVersion: () => electron_1.ipcRenderer.invoke('get-app-version'),\n restartApp: () => electron_1.ipcRenderer.invoke('restart-app'),\n // Trial expired overlay methods\n hideTrialExpiredOverlay: () => electron_1.ipcRenderer.invoke('hideTrialExpiredOverlay'),\n // Expose ipcRenderer for auth callbacks\n ipcRenderer: {\n on: (channel, callback) => {\n electron_1.ipcRenderer.on(channel, callback);\n },\n removeListener: (channel, callback) => {\n electron_1.ipcRenderer.removeListener(channel, callback);\n }\n }\n});\n\n\n//# sourceURL=webpack://jarvis-ai-assistant/./src/preload.ts?");
/***/ }),
/***/ "./src/services/stripe-subscription-service.ts":
/*!*****************************************************!*\
!*** ./src/services/stripe-subscription-service.ts ***!
\*****************************************************/
/***/ ((__unused_webpack_module, exports) => {
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.stripeSubscriptionService = exports.StripeSubscriptionService = void 0;\nclass StripeSubscriptionService {\n constructor() { }\n static getInstance() {\n if (!StripeSubscriptionService.instance) {\n StripeSubscriptionService.instance = new StripeSubscriptionService();\n }\n return StripeSubscriptionService.instance;\n }\n /**\n * Note: Dynamic pricing is no longer used - price is hardcoded in main.ts\n * This method is deprecated but kept for compatibility\n */\n async getPricingPlan(planId = 'pro') {\n console.warn('[Stripe] getPricingPlan is deprecated - pricing is now hardcoded in main.ts');\n return null;\n }\n /**\n * Note: Checkout session creation is now handled directly in main.ts\n * This method is deprecated but kept for compatibility\n */\n async createCheckoutSession(userId, userEmail) {\n throw new Error('Checkout session creation is now handled directly in main.ts via IPC');\n }\n /**\n * Initialize trial for new user\n */\n async initializeTrial(userId, userEmail) {\n try {\n console.log('[Stripe] Initializing trial for user:', userId);\n const response = await fetch('https://us-central1-jarvis-aa14d.cloudfunctions.net/initializeTrial', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n userId,\n userEmail\n })\n });\n if (!response.ok) {\n console.warn('[Stripe] Failed to initialize trial, using local fallback:', response.status);\n return this.getDefaultTrialSubscription();\n }\n const subscription = await response.json();\n // Don't log sensitive subscription data - just log status\n console.log('[Stripe] Trial initialized with status:', subscription?.status || 'unknown');\n return subscription;\n }\n catch (error) {\n console.error('[Stripe] Failed to initialize trial:', error);\n return this.getDefaultTrialSubscription();\n }\n }\n /**\n * Get user subscription - for now return trial status\n */\n async getUserSubscription(userId) {\n try {\n const response = await fetch(`https://us-central1-jarvis-aa14d.cloudfunctions.net/getSubscription?userId=${userId}`);\n if (!response.ok) {\n console.warn('[Stripe] Failed to get subscription, using trial fallback:', response.status);\n return this.getDefaultTrialSubscription();\n }\n const data = await response.json();\n // Don't log sensitive subscription data - just log status\n console.log('[Stripe] Got subscription status:', data?.status || 'unknown');\n return data;\n }\n catch (error) {\n console.error('[Stripe] Failed to get user subscription:', error);\n return this.getDefaultTrialSubscription();\n }\n }\n /**\n * Create customer portal session\n */\n async createPortalSession(userId) {\n try {\n const response = await fetch('https://us-central1-jarvis-aa14d.cloudfunctions.net/createPortalSession', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ userId })\n });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n const data = await response.json();\n // Don't log sensitive portal data - just log success\n console.log('[Stripe] Portal session created successfully');\n return data.url;\n }\n catch (error) {\n console.error('[Stripe] Failed to create portal session:', error);\n throw error;\n }\n }\n getDefaultTrialSubscription() {\n const trialEndDate = new Date();\n trialEndDate.setDate(trialEndDate.getDate() + 7);\n return {\n status: 'trial',\n trialStartDate: new Date().toISOString(),\n trialEndDate: trialEndDate.toISOString(),\n updatedAt: new Date().toISOString(),\n proExpiryDate: null,\n };\n }\n}\nexports.StripeSubscriptionService = StripeSubscriptionService;\nexports.stripeSubscriptionService = StripeSubscriptionService.getInstance();\n\n\n//# sourceURL=webpack://jarvis-ai-assistant/./src/services/stripe-subscription-service.ts?");
/***/ }),
/***/ "./src/services/subscription-service.ts":
/*!**********************************************!*\
!*** ./src/services/subscription-service.ts ***!
\**********************************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.subscriptionService = exports.SubscriptionService = void 0;\nconst subscription_1 = __webpack_require__(/*! ../types/subscription */ \"./src/types/subscription.ts\");\nconst stripe_subscription_service_1 = __webpack_require__(/*! ./stripe-subscription-service */ \"./src/services/stripe-subscription-service.ts\");\nconst validation_1 = __webpack_require__(/*! ../utils/validation */ \"./src/utils/validation.ts\");\nconst subscription_config_1 = __webpack_require__(/*! ../config/subscription-config */ \"./src/config/subscription-config.ts\");\nclass SubscriptionService {\n constructor() {\n this.cache = null;\n this.CACHE_DURATION = 60 * 60 * 1000; // 1 hour cache\n }\n static getInstance() {\n if (!SubscriptionService.instance) {\n SubscriptionService.instance = new SubscriptionService();\n }\n return SubscriptionService.instance;\n }\n /**\n * Check if cache is valid for the given user\n */\n isCacheValid(userId) {\n if (!this.cache)\n return false;\n if (this.cache.userId !== userId)\n return false;\n const age = Date.now() - this.cache.timestamp;\n return age < this.CACHE_DURATION;\n }\n async getUserSubscription(userId) {\n try {\n // Input validation using utility\n const sanitizedUserId = (0, validation_1.validateUserId)(userId);\n // Check cache first\n if (this.isCacheValid(sanitizedUserId)) {\n if (subscription_config_1.config.security.enableLogging) {\n console.log('[Subscription] Using cached subscription status:', this.cache.subscription.status);\n }\n return this.cache.subscription;\n }\n // Cache miss - fetch from API\n if (subscription_config_1.config.security.enableLogging) {\n console.log('[Subscription] Cache miss - fetching subscription from API');\n }\n const subscription = await stripe_subscription_service_1.stripeSubscriptionService.getUserSubscription(sanitizedUserId);\n // If subscription is null, return expired trial (don't auto-create)\n if (!subscription) {\n if (subscription_config_1.config.security.enableLogging) {\n console.log('[Subscription] No subscription found, returning expired trial');\n }\n const expiredTrial = this.getExpiredTrialSubscription();\n // Cache the result\n this.cache = {\n subscription: expiredTrial,\n timestamp: Date.now(),\n userId: sanitizedUserId\n };\n return expiredTrial;\n }\n // DEBUG: Log the actual subscription status received\n console.log('[Subscription] Received subscription status:', subscription.status);\n // For Pro subscriptions, return immediately without any trial logic\n if (subscription.status === 'pro') {\n if (subscription_config_1.config.security.enableLogging) {\n console.log('[Subscription] Pro subscription confirmed - returning pro status');\n }\n // Cache the result\n this.cache = {\n subscription,\n timestamp: Date.now(),\n userId: sanitizedUserId\n };\n return subscription;\n }\n // Check if trial expired (only for trial status)\n if (subscription.status === 'trial' && (0, subscription_1.isTrialExpired)(subscription)) {\n subscription.status = 'trial_expired';\n }\n // Cache the result\n this.cache = {\n subscription,\n timestamp: Date.now(),\n userId: sanitizedUserId\n };\n return subscription;\n }\n catch (error) {\n if (error instanceof validation_1.ValidationError) {\n console.error('[Subscription] Validation error:', error.message);\n throw error;\n }\n console.error('[Subscription] Failed to get subscription:', error);\n // Don't create new trials - return expired trial instead\n const expiredTrial = this.getExpiredTrialSubscription();\n // Cache the error result briefly (5 minutes) to avoid repeated failed API calls\n this.cache = {\n subscription: expiredTrial,\n timestamp: Date.now(),\n userId: (0, validation_1.validateUserId)(userId)\n };\n return expiredTrial;\n }\n }\n async initializeTrial(userId, userEmail) {\n try {\n // Input validation using utilities\n const sanitizedUserId = (0, validation_1.validateUserId)(userId);\n const sanitizedUserEmail = (0, validation_1.validateEmail)(userEmail);\n if (subscription_config_1.config.security.enableLogging) {\n console.log('[Subscription] Initializing trial for user:', sanitizedUserId);\n }\n const subscription = await stripe_subscription_service_1.stripeSubscriptionService.initializeTrial(sanitizedUserId, sanitizedUserEmail);\n return subscription;\n }\n catch (error) {\n if (error instanceof validation_1.ValidationError) {\n console.error('[Subscription] Validation error:', error.message);\n throw error;\n }\n console.error('[Subscription] Failed to initialize trial:', error);\n // Only return expired trial if initialization completely fails\n return this.getExpiredTrialSubscription();\n }\n }\n async upgradeToProWithStripe(userId, userEmail) {\n try {\n // Input validation using utilities\n const sanitizedUserId = (0, validation_1.validateUserId)(userId);\n const sanitizedUserEmail = (0, validation_1.validateEmail)(userEmail);\n return stripe_subscription_service_1.stripeSubscriptionService.createCheckoutSession(sanitizedUserId, sanitizedUserEmail);\n }\n catch (error) {\n if (error instanceof validation_1.ValidationError) {\n console.error('[Subscription] Validation error:', error.message);\n throw error;\n }\n throw error;\n }\n }\n async openCustomerPortal(userId) {\n try {\n // Input validation using utility\n const sanitizedUserId = (0, validation_1.validateUserId)(userId);\n return stripe_subscription_service_1.stripeSubscriptionService.createPortalSession(sanitizedUserId);\n }\n catch (error) {\n if (error instanceof validation_1.ValidationError) {\n console.error('[Subscription] Validation error:', error.message);\n throw error;\n }\n throw error;\n }\n }\n /**\n * Safely create a trial for a new user with proper validation\n */\n async createTrialForNewUser(userId, userEmail) {\n // Input validation\n if (!userId || typeof userId !== 'string' || userId.trim().length === 0) {\n throw new Error('Invalid userId provided');\n }\n if (!userEmail || typeof userEmail !== 'string' || !userEmail.includes('@')) {\n throw new Error('Invalid userEmail provided');\n }\n const sanitizedUserId = userId.trim();\n const sanitizedUserEmail = userEmail.trim().toLowerCase();\n try {\n // First check if user already has a subscription\n const existingSubscription = await stripe_subscription_service_1.stripeSubscriptionService.getUserSubscription(sanitizedUserId);\n if (existingSubscription) {\n console.log('[Subscription] User already has subscription, returning existing:', existingSubscription.status);\n return existingSubscription;\n }\n // Create new trial\n console.log('[Subscription] Creating new trial for user:', sanitizedUserId);\n return await this.initializeTrial(sanitizedUserId, sanitizedUserEmail);\n }\n catch (error) {\n console.error('[Subscription] Failed to create trial for new user:', error);\n return this.getExpiredTrialSubscription();\n }\n }\n async updateSubscriptionStatus(userId, subscription) {\n try {\n console.log('[Subscription] Updating subscription status for user:', userId, subscription);\n // This could be extended to update Firestore directly if needed\n // For now, we rely on Stripe webhooks to update the subscription\n }\n catch (error) {\n console.error('[Subscription] Failed to update subscription status:', error);\n throw error;\n }\n }\n clearCache() {\n this.cache = null;\n if (subscription_config_1.config.security.enableLogging) {\n console.log('[Subscription] Cache cleared');\n }\n }\n getDefaultTrialSubscription() {\n const trialEndDate = new Date();\n trialEndDate.setDate(trialEndDate.getDate() + 7);\n return {\n status: 'trial',\n trialStartDate: new Date().toISOString(),\n trialEndDate: trialEndDate.toISOString(),\n updatedAt: new Date().toISOString(),\n proExpiryDate: null,\n };\n }\n getExpiredTrialSubscription() {\n // Return an expired trial instead of creating new ones\n const yesterday = new Date();\n yesterday.setDate(yesterday.getDate() - 1);\n const weekAgo = new Date();\n weekAgo.setDate(weekAgo.getDate() - 7);\n return {\n status: 'trial_expired',\n trialStartDate: weekAgo.toISOString(),\n trialEndDate: yesterday.toISOString(),\n updatedAt: new Date().toISOString(),\n proExpiryDate: null,\n };\n }\n}\nexports.SubscriptionService = SubscriptionService;\nexports.subscriptionService = SubscriptionService.getInstance();\n\n\n//# sourceURL=webpack://jarvis-ai-assistant/./src/services/subscription-service.ts?");
/***/ }),
/***/ "./src/types/subscription.ts":
/*!***********************************!*\
!*** ./src/types/subscription.ts ***!
\***********************************/
/***/ ((__unused_webpack_module, exports) => {
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.isTrialExpired = isTrialExpired;\nexports.getTrialDaysRemaining = getTrialDaysRemaining;\nexports.getTrialProgress = getTrialProgress;\n// Helper function to check if trial is expired\nfunction isTrialExpired(subscription) {\n if (subscription.status !== 'trial' || !subscription.trialEndDate) {\n return false;\n }\n const now = new Date();\n const trialEnd = new Date(subscription.trialEndDate);\n return now > trialEnd;\n}\n// Helper function to get days remaining in trial\nfunction getTrialDaysRemaining(subscription) {\n if (subscription.status !== 'trial' || !subscription.trialEndDate) {\n return 0;\n }\n const now = new Date();\n const trialEnd = new Date(subscription.trialEndDate);\n const diffTime = trialEnd.getTime() - now.getTime();\n const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n return Math.max(0, diffDays);\n}\n// Helper function to get trial progress percentage\nfunction getTrialProgress(subscription) {\n if (subscription.status !== 'trial' || !subscription.trialStartDate || !subscription.trialEndDate) {\n return 0;\n }\n const now = new Date();\n const trialStart = new Date(subscription.trialStartDate);\n const trialEnd = new Date(subscription.trialEndDate);\n const totalDuration = trialEnd.getTime() - trialStart.getTime();\n const elapsed = now.getTime() - trialStart.getTime();\n const progress = (elapsed / totalDuration) * 100;\n return Math.min(100, Math.max(0, progress));\n}\n\n\n//# sourceURL=webpack://jarvis-ai-assistant/./src/types/subscription.ts?");
/***/ }),
/***/ "./src/utils/validation.ts":
/*!*********************************!*\
!*** ./src/utils/validation.ts ***!
\*********************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.isValidSubscriptionStatus = exports.sanitizeInput = exports.validateEmail = exports.validateUserId = exports.ValidationError = void 0;\nconst subscription_config_1 = __webpack_require__(/*! ../config/subscription-config */ \"./src/config/subscription-config.ts\");\n/**\n * Validation utilities for subscription service\n */\nclass ValidationError extends Error {\n constructor(message) {\n super(message);\n this.name = 'ValidationError';\n }\n}\nexports.ValidationError = ValidationError;\nconst validateUserId = (userId) => {\n if (!userId) {\n throw new ValidationError('UserId is required');\n }\n if (typeof userId !== 'string') {\n throw new ValidationError('UserId must be a string');\n }\n const trimmed = userId.trim();\n if (trimmed.length === 0) {\n throw new ValidationError('UserId cannot be empty');\n }\n if (trimmed.length > subscription_config_1.config.validation.maxUserIdLength) {\n throw new ValidationError(`UserId too long (max ${subscription_config_1.config.validation.maxUserIdLength} characters)`);\n }\n // Basic sanitization - remove potentially dangerous characters\n const sanitized = trimmed.replace(/[<>\\\"'&]/g, '');\n if (sanitized !== trimmed) {\n throw new ValidationError('UserId contains invalid characters');\n }\n return sanitized;\n};\nexports.validateUserId = validateUserId;\nconst validateEmail = (email) => {\n if (!email) {\n throw new ValidationError('Email is required');\n }\n if (typeof email !== 'string') {\n throw new ValidationError('Email must be a string');\n }\n const trimmed = email.trim().toLowerCase();\n if (trimmed.length === 0) {\n throw new ValidationError('Email cannot be empty');\n }\n if (trimmed.length > subscription_config_1.config.validation.maxEmailLength) {\n throw new ValidationError(`Email too long (max ${subscription_config_1.config.validation.maxEmailLength} characters)`);\n }\n if (!subscription_config_1.config.validation.emailRegex.test(trimmed)) {\n throw new ValidationError('Invalid email format');\n }\n return trimmed;\n};\nexports.validateEmail = validateEmail;\nconst sanitizeInput = (input) => {\n if (typeof input !== 'string') {\n return '';\n }\n return input.trim().replace(/[<>\\\"'&]/g, '');\n};\nexports.sanitizeInput = sanitizeInput;\nconst isValidSubscriptionStatus = (status) => {\n const validStatuses = ['trial', 'trial_expired', 'pro', 'expired'];\n return validStatuses.includes(status);\n};\nexports.isValidSubscriptionStatus = isValidSubscriptionStatus;\n\n\n//# sourceURL=webpack://jarvis-ai-assistant/./src/utils/validation.ts?");
/***/ }),
/***/ "electron":
/*!***************************!*\
!*** external "electron" ***!
\***************************/
/***/ ((module) => {
module.exports = require("electron");
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = __webpack_require__("./src/preload.ts");
/******/
/******/ })()
;