brave-real-launcher 1.2.32 → 1.2.33

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.
@@ -0,0 +1,333 @@
1
+ /**
2
+ * @license Copyright 2024 Brave Real Launcher Contributors.
3
+ * Licensed under the Apache License, Version 2.0
4
+ *
5
+ * Extension Manager for Brave Real Launcher
6
+ * Handles downloading, caching, and loading browser extensions
7
+ */
8
+ 'use strict';
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || function (mod) {
26
+ if (mod && mod.__esModule) return mod;
27
+ var result = {};
28
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
29
+ __setModuleDefault(result, mod);
30
+ return result;
31
+ };
32
+ var __importDefault = (this && this.__importDefault) || function (mod) {
33
+ return (mod && mod.__esModule) ? mod : { "default": mod };
34
+ };
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ExtensionManager = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const https = __importStar(require("https"));
40
+ const http = __importStar(require("http"));
41
+ const child_process_1 = require("child_process");
42
+ const os_1 = require("os");
43
+ const logger_js_1 = __importDefault(require("./logger.js"));
44
+ const UBLOCK_GITHUB_API = 'https://api.github.com/repos/gorhill/uBlock/releases/latest';
45
+ const UBLOCK_DOWNLOAD_BASE = 'https://github.com/gorhill/uBlock/releases/download';
46
+ class ExtensionManager {
47
+ constructor(options = {}) {
48
+ this.cacheDir = options.cacheDir || this.getDefaultCacheDir();
49
+ this.autoUpdate = options.autoUpdate !== false;
50
+ this.silent = options.silent || false;
51
+ // Ensure cache directory exists
52
+ if (!fs.existsSync(this.cacheDir)) {
53
+ fs.mkdirSync(this.cacheDir, { recursive: true });
54
+ }
55
+ }
56
+ getDefaultCacheDir() {
57
+ const homeDir = (0, os_1.homedir)();
58
+ return path.join(homeDir, '.brave-real-launcher', 'extensions');
59
+ }
60
+ /**
61
+ * Get uBlock Origin extension, downloading if necessary
62
+ */
63
+ async getUBlockOrigin() {
64
+ try {
65
+ const extensionDir = path.join(this.cacheDir, 'ublock-origin');
66
+ const versionFile = path.join(extensionDir, 'version.json');
67
+ // Check if we need to update
68
+ let needsUpdate = !fs.existsSync(extensionDir);
69
+ let currentVersion = '0.0.0';
70
+ if (fs.existsSync(versionFile)) {
71
+ try {
72
+ const versionData = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
73
+ currentVersion = versionData.version;
74
+ }
75
+ catch (e) {
76
+ needsUpdate = true;
77
+ }
78
+ }
79
+ else {
80
+ needsUpdate = true;
81
+ }
82
+ // Get latest version info
83
+ const latestInfo = await this.getLatestUBlockVersion();
84
+ if (latestInfo && this.autoUpdate) {
85
+ if (this.compareVersions(latestInfo.version, currentVersion) > 0) {
86
+ needsUpdate = true;
87
+ if (!this.silent) {
88
+ logger_js_1.default.log('ExtensionManager', `uBlock Origin update available: ${currentVersion} → ${latestInfo.version}`);
89
+ }
90
+ }
91
+ }
92
+ if (needsUpdate && latestInfo) {
93
+ await this.downloadAndExtractUBlock(latestInfo.downloadUrl, extensionDir, latestInfo.version);
94
+ }
95
+ // Find the extension manifest
96
+ const manifestPath = this.findManifest(extensionDir);
97
+ if (manifestPath) {
98
+ const manifestDir = path.dirname(manifestPath);
99
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
100
+ return {
101
+ name: 'uBlock Origin',
102
+ version: manifest.version || currentVersion,
103
+ path: manifestDir
104
+ };
105
+ }
106
+ return null;
107
+ }
108
+ catch (error) {
109
+ if (!this.silent) {
110
+ logger_js_1.default.error('ExtensionManager', `Failed to get uBlock Origin: ${error.message}`);
111
+ }
112
+ return null;
113
+ }
114
+ }
115
+ /**
116
+ * Get latest uBlock Origin version from GitHub
117
+ */
118
+ async getLatestUBlockVersion() {
119
+ return new Promise((resolve) => {
120
+ const options = {
121
+ hostname: 'api.github.com',
122
+ path: '/repos/gorhill/uBlock/releases/latest',
123
+ method: 'GET',
124
+ headers: {
125
+ 'User-Agent': 'brave-real-launcher',
126
+ 'Accept': 'application/vnd.github.v3+json'
127
+ }
128
+ };
129
+ const req = https.request(options, (res) => {
130
+ let data = '';
131
+ res.on('data', chunk => data += chunk);
132
+ res.on('end', () => {
133
+ var _a, _b;
134
+ try {
135
+ const release = JSON.parse(data);
136
+ const version = ((_a = release.tag_name) === null || _a === void 0 ? void 0 : _a.replace('v', '')) || release.name;
137
+ // Find chromium zip asset
138
+ const chromiumAsset = (_b = release.assets) === null || _b === void 0 ? void 0 : _b.find((asset) => asset.name.includes('chromium') && asset.name.endsWith('.zip'));
139
+ if (chromiumAsset) {
140
+ resolve({
141
+ version,
142
+ downloadUrl: chromiumAsset.browser_download_url
143
+ });
144
+ }
145
+ else {
146
+ // Fallback to constructed URL
147
+ resolve({
148
+ version,
149
+ downloadUrl: `${UBLOCK_DOWNLOAD_BASE}/${release.tag_name}/uBlock0_${version}.chromium.zip`
150
+ });
151
+ }
152
+ }
153
+ catch (e) {
154
+ resolve(null);
155
+ }
156
+ });
157
+ });
158
+ req.on('error', () => resolve(null));
159
+ req.setTimeout(10000, () => {
160
+ req.destroy();
161
+ resolve(null);
162
+ });
163
+ req.end();
164
+ });
165
+ }
166
+ /**
167
+ * Download and extract uBlock Origin
168
+ */
169
+ async downloadAndExtractUBlock(url, targetDir, version) {
170
+ if (!this.silent) {
171
+ logger_js_1.default.log('ExtensionManager', `Downloading uBlock Origin v${version}...`);
172
+ }
173
+ const zipPath = path.join(this.cacheDir, 'ublock-temp.zip');
174
+ // Download the file
175
+ await this.downloadFile(url, zipPath);
176
+ // Clean target directory
177
+ if (fs.existsSync(targetDir)) {
178
+ this.removeDir(targetDir);
179
+ }
180
+ fs.mkdirSync(targetDir, { recursive: true });
181
+ // Extract the zip
182
+ await this.extractZip(zipPath, targetDir);
183
+ // Save version info
184
+ const versionFile = path.join(targetDir, 'version.json');
185
+ fs.writeFileSync(versionFile, JSON.stringify({ version, downloadedAt: new Date().toISOString() }));
186
+ // Cleanup zip
187
+ try {
188
+ fs.unlinkSync(zipPath);
189
+ }
190
+ catch (e) { }
191
+ if (!this.silent) {
192
+ logger_js_1.default.log('ExtensionManager', `uBlock Origin v${version} installed successfully`);
193
+ }
194
+ }
195
+ /**
196
+ * Download a file from URL
197
+ */
198
+ downloadFile(url, destPath) {
199
+ return new Promise((resolve, reject) => {
200
+ const followRedirect = (url, redirectCount = 0) => {
201
+ if (redirectCount > 5) {
202
+ reject(new Error('Too many redirects'));
203
+ return;
204
+ }
205
+ const protocol = url.startsWith('https') ? https : http;
206
+ protocol.get(url, {
207
+ headers: { 'User-Agent': 'brave-real-launcher' }
208
+ }, (response) => {
209
+ // Handle redirects
210
+ if (response.statusCode === 301 || response.statusCode === 302) {
211
+ const redirectUrl = response.headers.location;
212
+ if (redirectUrl) {
213
+ followRedirect(redirectUrl, redirectCount + 1);
214
+ return;
215
+ }
216
+ }
217
+ if (response.statusCode !== 200) {
218
+ reject(new Error(`Download failed with status ${response.statusCode}`));
219
+ return;
220
+ }
221
+ const file = fs.createWriteStream(destPath);
222
+ response.pipe(file);
223
+ file.on('finish', () => {
224
+ file.close();
225
+ resolve();
226
+ });
227
+ file.on('error', (err) => {
228
+ fs.unlinkSync(destPath);
229
+ reject(err);
230
+ });
231
+ }).on('error', reject);
232
+ };
233
+ followRedirect(url);
234
+ });
235
+ }
236
+ /**
237
+ * Extract zip file
238
+ */
239
+ async extractZip(zipPath, targetDir) {
240
+ const platform = process.platform;
241
+ try {
242
+ if (platform === 'win32') {
243
+ // Use PowerShell on Windows
244
+ (0, child_process_1.execSync)(`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${targetDir}' -Force"`, {
245
+ stdio: 'ignore'
246
+ });
247
+ }
248
+ else {
249
+ // Use unzip on Linux/macOS
250
+ (0, child_process_1.execSync)(`unzip -o "${zipPath}" -d "${targetDir}"`, {
251
+ stdio: 'ignore'
252
+ });
253
+ }
254
+ }
255
+ catch (error) {
256
+ throw new Error(`Failed to extract zip: ${error.message}`);
257
+ }
258
+ }
259
+ /**
260
+ * Find manifest.json in extension directory
261
+ */
262
+ findManifest(dir) {
263
+ if (!fs.existsSync(dir))
264
+ return null;
265
+ // Check current directory
266
+ const directManifest = path.join(dir, 'manifest.json');
267
+ if (fs.existsSync(directManifest)) {
268
+ return directManifest;
269
+ }
270
+ // Check subdirectories (zip might have a nested folder)
271
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
272
+ for (const entry of entries) {
273
+ if (entry.isDirectory()) {
274
+ const nestedManifest = path.join(dir, entry.name, 'manifest.json');
275
+ if (fs.existsSync(nestedManifest)) {
276
+ return nestedManifest;
277
+ }
278
+ }
279
+ }
280
+ return null;
281
+ }
282
+ /**
283
+ * Compare semantic versions
284
+ */
285
+ compareVersions(a, b) {
286
+ const partsA = a.replace(/[^\d.]/g, '').split('.').map(Number);
287
+ const partsB = b.replace(/[^\d.]/g, '').split('.').map(Number);
288
+ for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
289
+ const numA = partsA[i] || 0;
290
+ const numB = partsB[i] || 0;
291
+ if (numA > numB)
292
+ return 1;
293
+ if (numA < numB)
294
+ return -1;
295
+ }
296
+ return 0;
297
+ }
298
+ /**
299
+ * Remove directory recursively
300
+ */
301
+ removeDir(dir) {
302
+ const rmSync = fs.rmSync || fs.rmdirSync;
303
+ try {
304
+ rmSync(dir, { recursive: true, force: true });
305
+ }
306
+ catch (e) { }
307
+ }
308
+ /**
309
+ * Get extension load flags for browser
310
+ */
311
+ getExtensionFlags(extensionPaths) {
312
+ if (extensionPaths.length === 0)
313
+ return [];
314
+ return [
315
+ `--load-extension=${extensionPaths.join(',')}`,
316
+ '--enable-extensions'
317
+ ];
318
+ }
319
+ /**
320
+ * Clean extension cache
321
+ */
322
+ cleanCache() {
323
+ if (fs.existsSync(this.cacheDir)) {
324
+ this.removeDir(this.cacheDir);
325
+ if (!this.silent) {
326
+ logger_js_1.default.log('ExtensionManager', 'Extension cache cleaned');
327
+ }
328
+ }
329
+ }
330
+ }
331
+ exports.ExtensionManager = ExtensionManager;
332
+ exports.default = ExtensionManager;
333
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXh0ZW5zaW9uLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZXh0ZW5zaW9uLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBQ0gsWUFBWSxDQUFDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUViLHVDQUF5QjtBQUN6QiwyQ0FBNkI7QUFDN0IsNkNBQStCO0FBQy9CLDJDQUE2QjtBQUM3QixpREFBeUM7QUFDekMsMkJBQTZCO0FBQzdCLDREQUE4QjtBQWM5QixNQUFNLGlCQUFpQixHQUFHLDZEQUE2RCxDQUFDO0FBQ3hGLE1BQU0sb0JBQW9CLEdBQUcscURBQXFELENBQUM7QUFFbkYsTUFBYSxnQkFBZ0I7SUFLekIsWUFBWSxVQUFtQyxFQUFFO1FBQzdDLElBQUksQ0FBQyxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUM5RCxJQUFJLENBQUMsVUFBVSxHQUFHLE9BQU8sQ0FBQyxVQUFVLEtBQUssS0FBSyxDQUFDO1FBQy9DLElBQUksQ0FBQyxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxLQUFLLENBQUM7UUFFdEMsZ0NBQWdDO1FBQ2hDLElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRTtZQUMvQixFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztTQUNwRDtJQUNMLENBQUM7SUFFTyxrQkFBa0I7UUFDdEIsTUFBTSxPQUFPLEdBQUcsSUFBQSxZQUFPLEdBQUUsQ0FBQztRQUMxQixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLHNCQUFzQixFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQ3BFLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxlQUFl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
@@ -0,0 +1,304 @@
1
+ /**
2
+ * @license Copyright 2024 Brave Real Launcher Contributors.
3
+ * Licensed under the Apache License, Version 2.0
4
+ *
5
+ * Extension Manager for Brave Real Launcher
6
+ * Handles downloading, caching, and loading browser extensions
7
+ */
8
+ 'use strict';
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ import * as https from 'https';
12
+ import * as http from 'http';
13
+ import { execSync } from 'child_process';
14
+ import { homedir } from 'os';
15
+ import log from './logger.mjs';
16
+ const UBLOCK_GITHUB_API = 'https://api.github.com/repos/gorhill/uBlock/releases/latest';
17
+ const UBLOCK_DOWNLOAD_BASE = 'https://github.com/gorhill/uBlock/releases/download';
18
+ export class ExtensionManager {
19
+ constructor(options = {}) {
20
+ this.cacheDir = options.cacheDir || this.getDefaultCacheDir();
21
+ this.autoUpdate = options.autoUpdate !== false;
22
+ this.silent = options.silent || false;
23
+ // Ensure cache directory exists
24
+ if (!fs.existsSync(this.cacheDir)) {
25
+ fs.mkdirSync(this.cacheDir, { recursive: true });
26
+ }
27
+ }
28
+ getDefaultCacheDir() {
29
+ const homeDir = homedir();
30
+ return path.join(homeDir, '.brave-real-launcher', 'extensions');
31
+ }
32
+ /**
33
+ * Get uBlock Origin extension, downloading if necessary
34
+ */
35
+ async getUBlockOrigin() {
36
+ try {
37
+ const extensionDir = path.join(this.cacheDir, 'ublock-origin');
38
+ const versionFile = path.join(extensionDir, 'version.json');
39
+ // Check if we need to update
40
+ let needsUpdate = !fs.existsSync(extensionDir);
41
+ let currentVersion = '0.0.0';
42
+ if (fs.existsSync(versionFile)) {
43
+ try {
44
+ const versionData = JSON.parse(fs.readFileSync(versionFile, 'utf-8'));
45
+ currentVersion = versionData.version;
46
+ }
47
+ catch (e) {
48
+ needsUpdate = true;
49
+ }
50
+ }
51
+ else {
52
+ needsUpdate = true;
53
+ }
54
+ // Get latest version info
55
+ const latestInfo = await this.getLatestUBlockVersion();
56
+ if (latestInfo && this.autoUpdate) {
57
+ if (this.compareVersions(latestInfo.version, currentVersion) > 0) {
58
+ needsUpdate = true;
59
+ if (!this.silent) {
60
+ log.log('ExtensionManager', `uBlock Origin update available: ${currentVersion} → ${latestInfo.version}`);
61
+ }
62
+ }
63
+ }
64
+ if (needsUpdate && latestInfo) {
65
+ await this.downloadAndExtractUBlock(latestInfo.downloadUrl, extensionDir, latestInfo.version);
66
+ }
67
+ // Find the extension manifest
68
+ const manifestPath = this.findManifest(extensionDir);
69
+ if (manifestPath) {
70
+ const manifestDir = path.dirname(manifestPath);
71
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
72
+ return {
73
+ name: 'uBlock Origin',
74
+ version: manifest.version || currentVersion,
75
+ path: manifestDir
76
+ };
77
+ }
78
+ return null;
79
+ }
80
+ catch (error) {
81
+ if (!this.silent) {
82
+ log.error('ExtensionManager', `Failed to get uBlock Origin: ${error.message}`);
83
+ }
84
+ return null;
85
+ }
86
+ }
87
+ /**
88
+ * Get latest uBlock Origin version from GitHub
89
+ */
90
+ async getLatestUBlockVersion() {
91
+ return new Promise((resolve) => {
92
+ const options = {
93
+ hostname: 'api.github.com',
94
+ path: '/repos/gorhill/uBlock/releases/latest',
95
+ method: 'GET',
96
+ headers: {
97
+ 'User-Agent': 'brave-real-launcher',
98
+ 'Accept': 'application/vnd.github.v3+json'
99
+ }
100
+ };
101
+ const req = https.request(options, (res) => {
102
+ let data = '';
103
+ res.on('data', chunk => data += chunk);
104
+ res.on('end', () => {
105
+ var _a, _b;
106
+ try {
107
+ const release = JSON.parse(data);
108
+ const version = ((_a = release.tag_name) === null || _a === void 0 ? void 0 : _a.replace('v', '')) || release.name;
109
+ // Find chromium zip asset
110
+ const chromiumAsset = (_b = release.assets) === null || _b === void 0 ? void 0 : _b.find((asset) => asset.name.includes('chromium') && asset.name.endsWith('.zip'));
111
+ if (chromiumAsset) {
112
+ resolve({
113
+ version,
114
+ downloadUrl: chromiumAsset.browser_download_url
115
+ });
116
+ }
117
+ else {
118
+ // Fallback to constructed URL
119
+ resolve({
120
+ version,
121
+ downloadUrl: `${UBLOCK_DOWNLOAD_BASE}/${release.tag_name}/uBlock0_${version}.chromium.zip`
122
+ });
123
+ }
124
+ }
125
+ catch (e) {
126
+ resolve(null);
127
+ }
128
+ });
129
+ });
130
+ req.on('error', () => resolve(null));
131
+ req.setTimeout(10000, () => {
132
+ req.destroy();
133
+ resolve(null);
134
+ });
135
+ req.end();
136
+ });
137
+ }
138
+ /**
139
+ * Download and extract uBlock Origin
140
+ */
141
+ async downloadAndExtractUBlock(url, targetDir, version) {
142
+ if (!this.silent) {
143
+ log.log('ExtensionManager', `Downloading uBlock Origin v${version}...`);
144
+ }
145
+ const zipPath = path.join(this.cacheDir, 'ublock-temp.zip');
146
+ // Download the file
147
+ await this.downloadFile(url, zipPath);
148
+ // Clean target directory
149
+ if (fs.existsSync(targetDir)) {
150
+ this.removeDir(targetDir);
151
+ }
152
+ fs.mkdirSync(targetDir, { recursive: true });
153
+ // Extract the zip
154
+ await this.extractZip(zipPath, targetDir);
155
+ // Save version info
156
+ const versionFile = path.join(targetDir, 'version.json');
157
+ fs.writeFileSync(versionFile, JSON.stringify({ version, downloadedAt: new Date().toISOString() }));
158
+ // Cleanup zip
159
+ try {
160
+ fs.unlinkSync(zipPath);
161
+ }
162
+ catch (e) { }
163
+ if (!this.silent) {
164
+ log.log('ExtensionManager', `uBlock Origin v${version} installed successfully`);
165
+ }
166
+ }
167
+ /**
168
+ * Download a file from URL
169
+ */
170
+ downloadFile(url, destPath) {
171
+ return new Promise((resolve, reject) => {
172
+ const followRedirect = (url, redirectCount = 0) => {
173
+ if (redirectCount > 5) {
174
+ reject(new Error('Too many redirects'));
175
+ return;
176
+ }
177
+ const protocol = url.startsWith('https') ? https : http;
178
+ protocol.get(url, {
179
+ headers: { 'User-Agent': 'brave-real-launcher' }
180
+ }, (response) => {
181
+ // Handle redirects
182
+ if (response.statusCode === 301 || response.statusCode === 302) {
183
+ const redirectUrl = response.headers.location;
184
+ if (redirectUrl) {
185
+ followRedirect(redirectUrl, redirectCount + 1);
186
+ return;
187
+ }
188
+ }
189
+ if (response.statusCode !== 200) {
190
+ reject(new Error(`Download failed with status ${response.statusCode}`));
191
+ return;
192
+ }
193
+ const file = fs.createWriteStream(destPath);
194
+ response.pipe(file);
195
+ file.on('finish', () => {
196
+ file.close();
197
+ resolve();
198
+ });
199
+ file.on('error', (err) => {
200
+ fs.unlinkSync(destPath);
201
+ reject(err);
202
+ });
203
+ }).on('error', reject);
204
+ };
205
+ followRedirect(url);
206
+ });
207
+ }
208
+ /**
209
+ * Extract zip file
210
+ */
211
+ async extractZip(zipPath, targetDir) {
212
+ const platform = process.platform;
213
+ try {
214
+ if (platform === 'win32') {
215
+ // Use PowerShell on Windows
216
+ execSync(`powershell -Command "Expand-Archive -Path '${zipPath}' -DestinationPath '${targetDir}' -Force"`, {
217
+ stdio: 'ignore'
218
+ });
219
+ }
220
+ else {
221
+ // Use unzip on Linux/macOS
222
+ execSync(`unzip -o "${zipPath}" -d "${targetDir}"`, {
223
+ stdio: 'ignore'
224
+ });
225
+ }
226
+ }
227
+ catch (error) {
228
+ throw new Error(`Failed to extract zip: ${error.message}`);
229
+ }
230
+ }
231
+ /**
232
+ * Find manifest.json in extension directory
233
+ */
234
+ findManifest(dir) {
235
+ if (!fs.existsSync(dir))
236
+ return null;
237
+ // Check current directory
238
+ const directManifest = path.join(dir, 'manifest.json');
239
+ if (fs.existsSync(directManifest)) {
240
+ return directManifest;
241
+ }
242
+ // Check subdirectories (zip might have a nested folder)
243
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
244
+ for (const entry of entries) {
245
+ if (entry.isDirectory()) {
246
+ const nestedManifest = path.join(dir, entry.name, 'manifest.json');
247
+ if (fs.existsSync(nestedManifest)) {
248
+ return nestedManifest;
249
+ }
250
+ }
251
+ }
252
+ return null;
253
+ }
254
+ /**
255
+ * Compare semantic versions
256
+ */
257
+ compareVersions(a, b) {
258
+ const partsA = a.replace(/[^\d.]/g, '').split('.').map(Number);
259
+ const partsB = b.replace(/[^\d.]/g, '').split('.').map(Number);
260
+ for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
261
+ const numA = partsA[i] || 0;
262
+ const numB = partsB[i] || 0;
263
+ if (numA > numB)
264
+ return 1;
265
+ if (numA < numB)
266
+ return -1;
267
+ }
268
+ return 0;
269
+ }
270
+ /**
271
+ * Remove directory recursively
272
+ */
273
+ removeDir(dir) {
274
+ const rmSync = fs.rmSync || fs.rmdirSync;
275
+ try {
276
+ rmSync(dir, { recursive: true, force: true });
277
+ }
278
+ catch (e) { }
279
+ }
280
+ /**
281
+ * Get extension load flags for browser
282
+ */
283
+ getExtensionFlags(extensionPaths) {
284
+ if (extensionPaths.length === 0)
285
+ return [];
286
+ return [
287
+ `--load-extension=${extensionPaths.join(',')}`,
288
+ '--enable-extensions'
289
+ ];
290
+ }
291
+ /**
292
+ * Clean extension cache
293
+ */
294
+ cleanCache() {
295
+ if (fs.existsSync(this.cacheDir)) {
296
+ this.removeDir(this.cacheDir);
297
+ if (!this.silent) {
298
+ log.log('ExtensionManager', 'Extension cache cleaned');
299
+ }
300
+ }
301
+ }
302
+ }
303
+ export default ExtensionManager;
304
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXh0ZW5zaW9uLW1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZXh0ZW5zaW9uLW1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7OztHQU1HO0FBQ0gsWUFBWSxDQUFDO0FBRWIsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxLQUFLLEtBQUssTUFBTSxPQUFPLENBQUM7QUFDL0IsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzdCLE9BQU8sR0FBRyxNQUFNLGFBQWEsQ0FBQztBQWM5QixNQUFNLGlCQUFpQixHQUFHLDZEQUE2RCxDQUFDO0FBQ3hGLE1BQU0sb0JBQW9CLEdBQUcscURBQXFELENBQUM7QUFFbkYsTUFBTSxPQUFPLGdCQUFnQjtJQUt6QixZQUFZLFVBQW1DLEVBQUU7UUFDN0MsSUFBSSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1FBQzlELElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFDLFVBQVUsS0FBSyxLQUFLLENBQUM7UUFDL0MsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQztRQUV0QyxnQ0FBZ0M7UUFDaEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQy9CLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1NBQ3BEO0lBQ0wsQ0FBQztJQUVPLGtCQUFrQjtRQUN0QixN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