@dynamicu/chromedebug-mcp 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +344 -0
- package/LICENSE +21 -0
- package/README.md +250 -0
- package/chrome-extension/README.md +41 -0
- package/chrome-extension/background.js +3917 -0
- package/chrome-extension/chrome-session-manager.js +706 -0
- package/chrome-extension/content.css +181 -0
- package/chrome-extension/content.js +3022 -0
- package/chrome-extension/data-buffer.js +435 -0
- package/chrome-extension/dom-tracker.js +411 -0
- package/chrome-extension/extension-config.js +78 -0
- package/chrome-extension/firebase-client.js +278 -0
- package/chrome-extension/firebase-config.js +32 -0
- package/chrome-extension/firebase-config.module.js +22 -0
- package/chrome-extension/firebase-config.module.template.js +27 -0
- package/chrome-extension/firebase-config.template.js +36 -0
- package/chrome-extension/frame-capture.js +407 -0
- package/chrome-extension/icon128.png +1 -0
- package/chrome-extension/icon16.png +1 -0
- package/chrome-extension/icon48.png +1 -0
- package/chrome-extension/license-helper.js +181 -0
- package/chrome-extension/logger.js +23 -0
- package/chrome-extension/manifest.json +73 -0
- package/chrome-extension/network-tracker.js +510 -0
- package/chrome-extension/offscreen.html +10 -0
- package/chrome-extension/options.html +203 -0
- package/chrome-extension/options.js +282 -0
- package/chrome-extension/pako.min.js +2 -0
- package/chrome-extension/performance-monitor.js +533 -0
- package/chrome-extension/pii-redactor.js +405 -0
- package/chrome-extension/popup.html +532 -0
- package/chrome-extension/popup.js +2446 -0
- package/chrome-extension/upload-manager.js +323 -0
- package/chrome-extension/web-vitals.iife.js +1 -0
- package/config/api-keys.json +11 -0
- package/config/chrome-pilot-config.json +45 -0
- package/package.json +126 -0
- package/scripts/cleanup-processes.js +109 -0
- package/scripts/config-manager.js +280 -0
- package/scripts/generate-extension-config.js +53 -0
- package/scripts/setup-security.js +64 -0
- package/src/capture/architecture.js +426 -0
- package/src/capture/error-handling-tests.md +38 -0
- package/src/capture/error-handling-types.ts +360 -0
- package/src/capture/index.js +508 -0
- package/src/capture/interfaces.js +625 -0
- package/src/capture/memory-manager.js +713 -0
- package/src/capture/types.js +342 -0
- package/src/chrome-controller.js +2658 -0
- package/src/cli.js +19 -0
- package/src/config-loader.js +303 -0
- package/src/database.js +2178 -0
- package/src/firebase-license-manager.js +462 -0
- package/src/firebase-privacy-guard.js +397 -0
- package/src/http-server.js +1516 -0
- package/src/index-direct.js +157 -0
- package/src/index-modular.js +219 -0
- package/src/index-monolithic-backup.js +2230 -0
- package/src/index.js +305 -0
- package/src/legacy/chrome-controller-old.js +1406 -0
- package/src/legacy/index-express.js +625 -0
- package/src/legacy/index-old.js +977 -0
- package/src/legacy/routes.js +260 -0
- package/src/legacy/shared-storage.js +101 -0
- package/src/logger.js +10 -0
- package/src/mcp/handlers/chrome-tool-handler.js +306 -0
- package/src/mcp/handlers/element-tool-handler.js +51 -0
- package/src/mcp/handlers/frame-tool-handler.js +957 -0
- package/src/mcp/handlers/request-handler.js +104 -0
- package/src/mcp/handlers/workflow-tool-handler.js +636 -0
- package/src/mcp/server.js +68 -0
- package/src/mcp/tools/index.js +701 -0
- package/src/middleware/auth.js +371 -0
- package/src/middleware/security.js +267 -0
- package/src/port-discovery.js +258 -0
- package/src/routes/admin.js +182 -0
- package/src/services/browser-daemon.js +494 -0
- package/src/services/chrome-service.js +375 -0
- package/src/services/failover-manager.js +412 -0
- package/src/services/git-safety-service.js +675 -0
- package/src/services/heartbeat-manager.js +200 -0
- package/src/services/http-client.js +195 -0
- package/src/services/process-manager.js +318 -0
- package/src/services/process-tracker.js +574 -0
- package/src/services/profile-manager.js +449 -0
- package/src/services/project-manager.js +415 -0
- package/src/services/session-manager.js +497 -0
- package/src/services/session-registry.js +491 -0
- package/src/services/unified-session-manager.js +678 -0
- package/src/shared-storage-old.js +267 -0
- package/src/standalone-server.js +53 -0
- package/src/utils/extension-path.js +145 -0
- package/src/utils.js +187 -0
- package/src/validation/log-transformer.js +125 -0
- package/src/validation/schemas.js +391 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { FUNCTIONS_URL } from './firebase-config.module.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Firebase License Client
|
|
5
|
+
* Handles license validation, usage tracking, and caching
|
|
6
|
+
*
|
|
7
|
+
* Privacy: Only transmits userId (anonymous UUID) and usage count
|
|
8
|
+
* NO recording data, NO PII, NO browsing history
|
|
9
|
+
*/
|
|
10
|
+
class FirebaseLicenseClient {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.functionsUrl = FUNCTIONS_URL;
|
|
13
|
+
this.cacheKey = 'chromedebug_license_cache';
|
|
14
|
+
this.instanceIdKey = 'chromedebug_instance_id';
|
|
15
|
+
console.log('[License] Initialized with FUNCTIONS_URL:', this.functionsUrl);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate unique instance ID (once per installation)
|
|
20
|
+
* Used for device-based license validation
|
|
21
|
+
* @returns {Promise<string>} Instance ID
|
|
22
|
+
*/
|
|
23
|
+
async generateInstanceId() {
|
|
24
|
+
const stored = await chrome.storage.local.get(this.instanceIdKey);
|
|
25
|
+
if (stored[this.instanceIdKey]) return stored[this.instanceIdKey];
|
|
26
|
+
|
|
27
|
+
const instanceId = crypto.randomUUID();
|
|
28
|
+
await chrome.storage.local.set({[this.instanceIdKey]: instanceId});
|
|
29
|
+
return instanceId;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Activate license with LemonSqueezy (first-time activation)
|
|
34
|
+
* @param {string} licenseKey - License key to activate
|
|
35
|
+
* @returns {Promise<{activated: boolean, instance?: object, error?: string}>}
|
|
36
|
+
*/
|
|
37
|
+
async activateLicense(licenseKey) {
|
|
38
|
+
const deviceId = await this.generateInstanceId();
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
console.log(`[License] Activating license ${licenseKey} with device ${deviceId}`);
|
|
42
|
+
|
|
43
|
+
const response = await fetch(`${this.functionsUrl}/activateLicense`, {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: {'Content-Type': 'application/json'},
|
|
46
|
+
body: JSON.stringify({
|
|
47
|
+
licenseKey: licenseKey.trim(),
|
|
48
|
+
instanceName: deviceId
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const errorData = await response.json();
|
|
54
|
+
throw new Error(errorData.error || `HTTP ${response.status}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
console.log('[License] Activation response:', data);
|
|
59
|
+
|
|
60
|
+
// If activation successful, save the LemonSqueezy instance ID
|
|
61
|
+
if (data.activated && data.instance) {
|
|
62
|
+
await chrome.storage.local.set({
|
|
63
|
+
'ls_instance_id': data.instance.id,
|
|
64
|
+
'ls_license_key': licenseKey.trim(),
|
|
65
|
+
'activated_at': Date.now()
|
|
66
|
+
});
|
|
67
|
+
console.log(`[License] Saved LS instance ID: ${data.instance.id}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return data;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('[License] Activation failed:', error);
|
|
73
|
+
return {
|
|
74
|
+
activated: false,
|
|
75
|
+
error: error.message
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Validate license with Cloud Function
|
|
82
|
+
* This should be called AFTER activateLicense() on first use
|
|
83
|
+
* @param {string} licenseKey - License key to validate
|
|
84
|
+
* @returns {Promise<{valid: boolean, tier?: string, error?: string}>}
|
|
85
|
+
*/
|
|
86
|
+
async validateLicense(licenseKey) {
|
|
87
|
+
try {
|
|
88
|
+
// Get LemonSqueezy instance ID (set during activation)
|
|
89
|
+
const stored = await chrome.storage.local.get(['ls_instance_id', 'ls_license_key']);
|
|
90
|
+
const instanceId = stored.ls_instance_id;
|
|
91
|
+
|
|
92
|
+
// If no instance ID yet, this license needs activation first
|
|
93
|
+
if (!instanceId) {
|
|
94
|
+
console.log('[License] No instance ID found - activating license first');
|
|
95
|
+
const activationResult = await this.activateLicense(licenseKey);
|
|
96
|
+
|
|
97
|
+
if (!activationResult.activated) {
|
|
98
|
+
return {
|
|
99
|
+
valid: false,
|
|
100
|
+
error: activationResult.error || 'Activation failed',
|
|
101
|
+
needsActivation: true
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Activation successful, get the new instance ID
|
|
106
|
+
const newStored = await chrome.storage.local.get('ls_instance_id');
|
|
107
|
+
const newInstanceId = newStored.ls_instance_id;
|
|
108
|
+
|
|
109
|
+
// Now validate with the new instance ID
|
|
110
|
+
return await this.validateWithInstanceId(licenseKey, newInstanceId);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Instance ID exists, just validate
|
|
114
|
+
return await this.validateWithInstanceId(licenseKey, instanceId);
|
|
115
|
+
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('License validation failed:', error);
|
|
118
|
+
// Check cache for offline grace period
|
|
119
|
+
return await this.getCachedLicenseStatus();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Validate license with LemonSqueezy API (via Firebase proxy)
|
|
125
|
+
* @param {string} licenseKey - License key
|
|
126
|
+
* @param {string} instanceId - LemonSqueezy instance ID
|
|
127
|
+
* @returns {Promise<{valid: boolean, tier?: string}>}
|
|
128
|
+
*/
|
|
129
|
+
async validateWithInstanceId(licenseKey, instanceId) {
|
|
130
|
+
console.log(`[License] Validating ${licenseKey} with instance ${instanceId}`);
|
|
131
|
+
|
|
132
|
+
const response = await fetch(`${this.functionsUrl}/validateLicense`, {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
headers: {'Content-Type': 'application/json'},
|
|
135
|
+
body: JSON.stringify({licenseKey, instanceId})
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
if (!response.ok) {
|
|
139
|
+
throw new Error(`HTTP ${response.status}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const data = await response.json();
|
|
143
|
+
console.log('[License] Validation response:', data);
|
|
144
|
+
|
|
145
|
+
// Map LemonSqueezy response to our format
|
|
146
|
+
const result = {
|
|
147
|
+
valid: data.valid === true && data.status === 'active',
|
|
148
|
+
tier: data.valid ? 'pro' : 'free',
|
|
149
|
+
status: data.status,
|
|
150
|
+
activationUsage: data.activationUsage,
|
|
151
|
+
activationLimit: data.activationLimit
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// Cache result for 24 hours with 30-day grace period
|
|
155
|
+
if (result.valid) {
|
|
156
|
+
await this.cacheLicenseStatus({
|
|
157
|
+
valid: true,
|
|
158
|
+
tier: result.tier,
|
|
159
|
+
licenseKey: licenseKey,
|
|
160
|
+
cachedAt: Date.now(),
|
|
161
|
+
graceUntil: Date.now() + (30 * 24 * 60 * 60 * 1000) // 30 days
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Check usage limit for user
|
|
170
|
+
* @param {string} userId - Anonymous user ID
|
|
171
|
+
* @returns {Promise<{allowed: boolean, count?: number, limit?: number, offline?: boolean}>}
|
|
172
|
+
*/
|
|
173
|
+
async checkUsageLimit(userId) {
|
|
174
|
+
// First check if user has valid pro license
|
|
175
|
+
const licenseStatus = await this.getCachedLicenseStatus();
|
|
176
|
+
if (licenseStatus.valid && licenseStatus.tier === 'pro') {
|
|
177
|
+
return {allowed: true, unlimited: true, tier: 'pro'};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const url = `${this.functionsUrl}/checkUsageLimit`;
|
|
181
|
+
try {
|
|
182
|
+
console.log('[License] Calling checkUsageLimit at:', url);
|
|
183
|
+
const response = await fetch(url, {
|
|
184
|
+
method: 'POST',
|
|
185
|
+
headers: {'Content-Type': 'application/json'},
|
|
186
|
+
body: JSON.stringify({userId})
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
throw new Error(`HTTP ${response.status}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return await response.json();
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error('[License] Full error details:');
|
|
196
|
+
console.error(' URL:', url);
|
|
197
|
+
console.error(' Error message:', error.message);
|
|
198
|
+
console.error(' Error name:', error.name);
|
|
199
|
+
console.error(' Error stack:', error.stack);
|
|
200
|
+
console.warn('[License] Cloud Functions not deployed yet - using offline mode:', error.message);
|
|
201
|
+
// Offline: allow limited usage (5 recordings/day default)
|
|
202
|
+
return {allowed: true, offline: true, count: 0, limit: 5};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Increment usage count (call AFTER recording completes)
|
|
208
|
+
* @param {string} userId - Anonymous user ID
|
|
209
|
+
* @returns {Promise<{success: boolean, count?: number, offline?: boolean}>}
|
|
210
|
+
*/
|
|
211
|
+
async incrementUsage(userId) {
|
|
212
|
+
// Don't increment for pro users
|
|
213
|
+
const licenseStatus = await this.getCachedLicenseStatus();
|
|
214
|
+
if (licenseStatus.valid && licenseStatus.tier === 'pro') {
|
|
215
|
+
return {success: true, tier: 'pro', skipped: true};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetch(`${this.functionsUrl}/incrementUsage`, {
|
|
220
|
+
method: 'POST',
|
|
221
|
+
headers: {'Content-Type': 'application/json'},
|
|
222
|
+
body: JSON.stringify({userId})
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
if (!response.ok) {
|
|
226
|
+
throw new Error(`HTTP ${response.status}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return await response.json();
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error('Failed to increment usage:', error);
|
|
232
|
+
return {success: false, offline: true};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Cache license status locally
|
|
238
|
+
* @param {{valid: boolean, tier: string, cachedAt: number, graceUntil: number}} status
|
|
239
|
+
*/
|
|
240
|
+
async cacheLicenseStatus(status) {
|
|
241
|
+
await chrome.storage.local.set({[this.cacheKey]: status});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Get cached license status with grace period handling
|
|
246
|
+
* @returns {Promise<{valid: boolean, tier?: string, offline?: boolean, expired?: boolean}>}
|
|
247
|
+
*/
|
|
248
|
+
async getCachedLicenseStatus() {
|
|
249
|
+
const result = await chrome.storage.local.get(this.cacheKey);
|
|
250
|
+
const cached = result[this.cacheKey];
|
|
251
|
+
|
|
252
|
+
if (!cached) return {valid: false};
|
|
253
|
+
|
|
254
|
+
// Check if cache is stale (>24 hours)
|
|
255
|
+
const cacheAge = Date.now() - cached.cachedAt;
|
|
256
|
+
const cacheExpired = cacheAge > (24 * 60 * 60 * 1000);
|
|
257
|
+
|
|
258
|
+
if (cacheExpired) {
|
|
259
|
+
// Check if within grace period
|
|
260
|
+
if (Date.now() < cached.graceUntil) {
|
|
261
|
+
return {valid: cached.valid, tier: cached.tier, offline: true, gracePeriod: true};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return {valid: false, expired: true};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return {valid: cached.valid, tier: cached.tier};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Clear cached license (for logout/deactivation)
|
|
272
|
+
*/
|
|
273
|
+
async clearLicenseCache() {
|
|
274
|
+
await chrome.storage.local.remove(this.cacheKey);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export { FirebaseLicenseClient };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Cloud Functions configuration
|
|
3
|
+
* Compatible with both service workers (importScripts) and ES6 modules
|
|
4
|
+
*
|
|
5
|
+
* SECURITY: This file is gitignored and contains your API key.
|
|
6
|
+
* The API key is restricted in Google Cloud Console.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Firebase configuration
|
|
10
|
+
const FIREBASE_CONFIG = {
|
|
11
|
+
projectId: 'chrome-debug-mcp',
|
|
12
|
+
apiKey: 'AIzaSyDu4r5k7J4gb76CVN9evBNg3DV6KjworCE',
|
|
13
|
+
authDomain: 'chromedebug.com'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Cloud Functions base URL
|
|
17
|
+
const FUNCTIONS_URL = `https://us-central1-${FIREBASE_CONFIG.projectId}.cloudfunctions.net`;
|
|
18
|
+
|
|
19
|
+
// LemonSqueezy checkout URL (Production)
|
|
20
|
+
const LEMONSQUEEZY_CHECKOUT_URL = 'https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
|
|
21
|
+
|
|
22
|
+
// Make available globally for service worker context
|
|
23
|
+
if (typeof self !== 'undefined') {
|
|
24
|
+
self.FIREBASE_CONFIG = FIREBASE_CONFIG;
|
|
25
|
+
self.FUNCTIONS_URL = FUNCTIONS_URL;
|
|
26
|
+
self.LEMONSQUEEZY_CHECKOUT_URL = LEMONSQUEEZY_CHECKOUT_URL;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// For ES6 module imports (popup.js)
|
|
30
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
31
|
+
module.exports = { FIREBASE_CONFIG, FUNCTIONS_URL, LEMONSQUEEZY_CHECKOUT_URL };
|
|
32
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Cloud Functions configuration
|
|
3
|
+
* ES6 module version for popup.js and firebase-client.js
|
|
4
|
+
*
|
|
5
|
+
* SECURITY: This file is gitignored and contains your API key.
|
|
6
|
+
* The API key is restricted in Google Cloud Console.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Firebase configuration
|
|
10
|
+
const FIREBASE_CONFIG = {
|
|
11
|
+
projectId: 'chrome-debug-mcp',
|
|
12
|
+
apiKey: 'AIzaSyDu4r5k7J4gb76CVN9evBNg3DV6KjworCE',
|
|
13
|
+
authDomain: 'chromedebug.com'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Cloud Functions base URL
|
|
17
|
+
const FUNCTIONS_URL = `https://us-central1-${FIREBASE_CONFIG.projectId}.cloudfunctions.net`;
|
|
18
|
+
|
|
19
|
+
// LemonSqueezy checkout URL (Production)
|
|
20
|
+
const LEMONSQUEEZY_CHECKOUT_URL = 'https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967';
|
|
21
|
+
|
|
22
|
+
export { FIREBASE_CONFIG, FUNCTIONS_URL, LEMONSQUEEZY_CHECKOUT_URL };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Cloud Functions configuration TEMPLATE
|
|
3
|
+
* ES6 module version for popup.js and firebase-client.js
|
|
4
|
+
*
|
|
5
|
+
* IMPORTANT: This is a template file. Do NOT commit actual API keys.
|
|
6
|
+
*
|
|
7
|
+
* Setup Instructions:
|
|
8
|
+
* 1. Copy this file to firebase-config.module.js
|
|
9
|
+
* 2. Replace placeholder values with your actual Firebase configuration
|
|
10
|
+
* 3. Ensure firebase-config.module.js is in .gitignore
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// Firebase configuration (populate after Firebase project creation)
|
|
14
|
+
const FIREBASE_CONFIG = {
|
|
15
|
+
projectId: 'YOUR_PROJECT_ID',
|
|
16
|
+
apiKey: 'YOUR_API_KEY_HERE',
|
|
17
|
+
authDomain: 'your-domain.com'
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Cloud Functions base URL (update after deployment)
|
|
21
|
+
const FUNCTIONS_URL = `https://us-central1-${FIREBASE_CONFIG.projectId}.cloudfunctions.net`;
|
|
22
|
+
|
|
23
|
+
// LemonSqueezy checkout URL
|
|
24
|
+
// Production example: https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967
|
|
25
|
+
const LEMONSQUEEZY_CHECKOUT_URL = 'https://your-store.lemonsqueezy.com/checkout';
|
|
26
|
+
|
|
27
|
+
export { FIREBASE_CONFIG, FUNCTIONS_URL, LEMONSQUEEZY_CHECKOUT_URL };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Cloud Functions configuration TEMPLATE
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: This is a template file. Do NOT commit actual API keys.
|
|
5
|
+
*
|
|
6
|
+
* Setup Instructions:
|
|
7
|
+
* 1. Copy this file to firebase-config.js
|
|
8
|
+
* 2. Replace placeholder values with your actual Firebase configuration
|
|
9
|
+
* 3. Ensure firebase-config.js is in .gitignore
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Firebase configuration (populate after Firebase project creation)
|
|
13
|
+
const FIREBASE_CONFIG = {
|
|
14
|
+
projectId: 'YOUR_PROJECT_ID',
|
|
15
|
+
apiKey: 'YOUR_API_KEY_HERE',
|
|
16
|
+
authDomain: 'your-domain.com'
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Cloud Functions base URL (update after deployment)
|
|
20
|
+
const FUNCTIONS_URL = `https://us-central1-${FIREBASE_CONFIG.projectId}.cloudfunctions.net`;
|
|
21
|
+
|
|
22
|
+
// LemonSqueezy checkout URL
|
|
23
|
+
// Production example: https://chromedebug.com/buy/996773cb-682b-430f-b9e3-9ce2130bd967
|
|
24
|
+
const LEMONSQUEEZY_CHECKOUT_URL = 'https://your-store.lemonsqueezy.com/checkout';
|
|
25
|
+
|
|
26
|
+
// Make available globally for service worker context
|
|
27
|
+
if (typeof self !== 'undefined') {
|
|
28
|
+
self.FIREBASE_CONFIG = FIREBASE_CONFIG;
|
|
29
|
+
self.FUNCTIONS_URL = FUNCTIONS_URL;
|
|
30
|
+
self.LEMONSQUEEZY_CHECKOUT_URL = LEMONSQUEEZY_CHECKOUT_URL;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// For ES6 module imports (popup.js)
|
|
34
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
35
|
+
module.exports = { FIREBASE_CONFIG, FUNCTIONS_URL, LEMONSQUEEZY_CHECKOUT_URL };
|
|
36
|
+
}
|