n8n-nodes-nvk-browser 1.0.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.
Files changed (55) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +76 -0
  3. package/dist/nodes/PageInteraction/MoveAndClick/MoveAndClick.description.d.ts +2 -0
  4. package/dist/nodes/PageInteraction/MoveAndClick/MoveAndClick.description.js +132 -0
  5. package/dist/nodes/PageInteraction/MoveAndClick/MoveAndClick.node.d.ts +5 -0
  6. package/dist/nodes/PageInteraction/MoveAndClick/MoveAndClick.node.js +176 -0
  7. package/dist/nodes/PageInteraction/MoveAndClick/click.svg +5 -0
  8. package/dist/nodes/PageInteraction/MoveAndClick/code.svg +5 -0
  9. package/dist/nodes/PageInteraction/MoveAndClick/profile.svg +5 -0
  10. package/dist/nodes/PageInteraction/RunJavaScript/RunJavaScript.description.d.ts +2 -0
  11. package/dist/nodes/PageInteraction/RunJavaScript/RunJavaScript.description.js +62 -0
  12. package/dist/nodes/PageInteraction/RunJavaScript/RunJavaScript.node.d.ts +5 -0
  13. package/dist/nodes/PageInteraction/RunJavaScript/RunJavaScript.node.js +126 -0
  14. package/dist/nodes/PageInteraction/RunJavaScript/click.svg +5 -0
  15. package/dist/nodes/PageInteraction/RunJavaScript/code.svg +5 -0
  16. package/dist/nodes/PageInteraction/RunJavaScript/profile.svg +5 -0
  17. package/dist/nodes/ProfileManagement/CreateProfile/CreateProfile.description.d.ts +2 -0
  18. package/dist/nodes/ProfileManagement/CreateProfile/CreateProfile.description.js +61 -0
  19. package/dist/nodes/ProfileManagement/CreateProfile/CreateProfile.node.d.ts +5 -0
  20. package/dist/nodes/ProfileManagement/CreateProfile/CreateProfile.node.js +124 -0
  21. package/dist/nodes/ProfileManagement/CreateProfile/click.svg +5 -0
  22. package/dist/nodes/ProfileManagement/CreateProfile/code.svg +5 -0
  23. package/dist/nodes/ProfileManagement/CreateProfile/profile.svg +5 -0
  24. package/dist/nodes/ProfileManagement/DeleteProfile/DeleteProfile.description.d.ts +2 -0
  25. package/dist/nodes/ProfileManagement/DeleteProfile/DeleteProfile.description.js +19 -0
  26. package/dist/nodes/ProfileManagement/DeleteProfile/DeleteProfile.node.d.ts +5 -0
  27. package/dist/nodes/ProfileManagement/DeleteProfile/DeleteProfile.node.js +123 -0
  28. package/dist/nodes/ProfileManagement/DeleteProfile/click.svg +5 -0
  29. package/dist/nodes/ProfileManagement/DeleteProfile/code.svg +5 -0
  30. package/dist/nodes/ProfileManagement/DeleteProfile/profile.svg +5 -0
  31. package/dist/nodes/ProfileManagement/StartProfile/StartProfile.description.d.ts +2 -0
  32. package/dist/nodes/ProfileManagement/StartProfile/StartProfile.description.js +122 -0
  33. package/dist/nodes/ProfileManagement/StartProfile/StartProfile.node.d.ts +5 -0
  34. package/dist/nodes/ProfileManagement/StartProfile/StartProfile.node.js +140 -0
  35. package/dist/nodes/ProfileManagement/StartProfile/click.svg +5 -0
  36. package/dist/nodes/ProfileManagement/StartProfile/code.svg +5 -0
  37. package/dist/nodes/ProfileManagement/StartProfile/profile.svg +5 -0
  38. package/dist/nodes/ProfileManagement/StopProfile/StopProfile.description.d.ts +2 -0
  39. package/dist/nodes/ProfileManagement/StopProfile/StopProfile.description.js +19 -0
  40. package/dist/nodes/ProfileManagement/StopProfile/StopProfile.node.d.ts +5 -0
  41. package/dist/nodes/ProfileManagement/StopProfile/StopProfile.node.js +115 -0
  42. package/dist/nodes/ProfileManagement/StopProfile/click.svg +5 -0
  43. package/dist/nodes/ProfileManagement/StopProfile/code.svg +5 -0
  44. package/dist/nodes/ProfileManagement/StopProfile/profile.svg +5 -0
  45. package/dist/utils/BrowserManager.d.ts +18 -0
  46. package/dist/utils/BrowserManager.js +174 -0
  47. package/dist/utils/ExtensionHandler.d.ts +9 -0
  48. package/dist/utils/ExtensionHandler.js +86 -0
  49. package/dist/utils/ProfileManager.d.ts +14 -0
  50. package/dist/utils/ProfileManager.js +128 -0
  51. package/dist/utils/ProxyHandler.d.ts +5 -0
  52. package/dist/utils/ProxyHandler.js +50 -0
  53. package/dist/utils/types.d.ts +47 -0
  54. package/dist/utils/types.js +2 -0
  55. package/package.json +66 -0
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <polyline points="16 18 22 12 16 6"></polyline>
3
+ <polyline points="8 6 2 12 8 18"></polyline>
4
+ </svg>
5
+
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
3
+ <circle cx="12" cy="7" r="4"></circle>
4
+ </svg>
5
+
@@ -0,0 +1,2 @@
1
+ import { INodeProperties } from 'n8n-workflow';
2
+ export declare const stopProfileFields: INodeProperties[];
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stopProfileFields = void 0;
4
+ exports.stopProfileFields = [
5
+ {
6
+ displayName: 'Profile ID',
7
+ name: 'profileId',
8
+ type: 'string',
9
+ required: true,
10
+ default: '',
11
+ description: 'ID of the profile to stop',
12
+ displayOptions: {
13
+ show: {
14
+ resource: ['profile'],
15
+ operation: ['stop'],
16
+ },
17
+ },
18
+ },
19
+ ];
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class StopProfile implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.StopProfile = void 0;
27
+ const BrowserManager_1 = require("../../../utils/BrowserManager");
28
+ const StopProfile_description_1 = require("./StopProfile.description");
29
+ const path = __importStar(require("path"));
30
+ class StopProfile {
31
+ constructor() {
32
+ this.description = {
33
+ displayName: 'Stop Profile',
34
+ name: 'stopProfile',
35
+ icon: 'file:profile.svg',
36
+ group: ['transform'],
37
+ version: 1,
38
+ description: 'Stop a running browser profile',
39
+ defaults: {
40
+ name: 'Stop Profile',
41
+ },
42
+ inputs: ['main'],
43
+ outputs: ['main'],
44
+ properties: [
45
+ {
46
+ displayName: 'Resource',
47
+ name: 'resource',
48
+ type: 'options',
49
+ noDataExpression: true,
50
+ options: [
51
+ {
52
+ name: 'Profile',
53
+ value: 'profile',
54
+ },
55
+ ],
56
+ default: 'profile',
57
+ },
58
+ {
59
+ displayName: 'Operation',
60
+ name: 'operation',
61
+ type: 'options',
62
+ noDataExpression: true,
63
+ options: [
64
+ {
65
+ name: 'Stop',
66
+ value: 'stop',
67
+ description: 'Stop a profile',
68
+ action: 'Stop a profile',
69
+ },
70
+ ],
71
+ default: 'stop',
72
+ },
73
+ ...StopProfile_description_1.stopProfileFields,
74
+ ],
75
+ };
76
+ }
77
+ async execute() {
78
+ const items = this.getInputData();
79
+ const returnData = [];
80
+ const workspacePath = process.cwd();
81
+ const profilesDir = process.env.NVK_PROFILES_DIR || path.join(workspacePath, 'profiles');
82
+ const browserPath = process.env.NVK_BROWSER_PATH || path.join(workspacePath, 'browser-142', 'chrome.exe');
83
+ const resolvedBrowserPath = path.isAbsolute(browserPath)
84
+ ? browserPath
85
+ : path.resolve(workspacePath, browserPath);
86
+ const resolvedProfilesDir = path.isAbsolute(profilesDir)
87
+ ? profilesDir
88
+ : path.resolve(workspacePath, profilesDir);
89
+ BrowserManager_1.BrowserManager.resetInstance(); // Reset để đảm bảo dùng đúng paths
90
+ const browserManager = BrowserManager_1.BrowserManager.getInstance(resolvedBrowserPath, resolvedProfilesDir);
91
+ for (let i = 0; i < items.length; i++) {
92
+ try {
93
+ const profileId = this.getNodeParameter('profileId', i);
94
+ const stopped = await browserManager.stopProfile(profileId);
95
+ returnData.push({
96
+ json: {
97
+ success: stopped,
98
+ profileId,
99
+ message: stopped ? 'Profile stopped successfully' : 'Profile not running',
100
+ },
101
+ });
102
+ }
103
+ catch (error) {
104
+ returnData.push({
105
+ json: {
106
+ success: false,
107
+ error: error instanceof Error ? error.message : String(error),
108
+ },
109
+ });
110
+ }
111
+ }
112
+ return [returnData];
113
+ }
114
+ }
115
+ exports.StopProfile = StopProfile;
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M9 9l5 12 1.774-5.226L21 14 9 9z"></path>
3
+ <path d="M21 3l-3.5 3.5"></path>
4
+ </svg>
5
+
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <polyline points="16 18 22 12 16 6"></polyline>
3
+ <polyline points="8 6 2 12 8 18"></polyline>
4
+ </svg>
5
+
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
3
+ <circle cx="12" cy="7" r="4"></circle>
4
+ </svg>
5
+
@@ -0,0 +1,18 @@
1
+ import { Page } from 'puppeteer-core';
2
+ import { BrowserInstance, WindowConfig } from './types';
3
+ export declare class BrowserManager {
4
+ private static instance;
5
+ private instances;
6
+ private browserPath;
7
+ private profilesManager;
8
+ private constructor();
9
+ static getInstance(browserPath?: string, profilesDir?: string): BrowserManager;
10
+ static resetInstance(): void;
11
+ startProfile(profileId: string, windowConfig?: WindowConfig): Promise<BrowserInstance>;
12
+ stopProfile(profileId: string): Promise<boolean>;
13
+ getInstance(profileId: string): BrowserInstance | undefined;
14
+ getAllInstances(): BrowserInstance[];
15
+ private getDebugPort;
16
+ private setWindowPosition;
17
+ getPage(profileId: string, tabIndex?: number): Promise<Page | null>;
18
+ }
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BrowserManager = void 0;
7
+ const puppeteer_core_1 = __importDefault(require("puppeteer-core"));
8
+ const ProxyHandler_1 = require("./ProxyHandler");
9
+ const ExtensionHandler_1 = require("./ExtensionHandler");
10
+ const ProfileManager_1 = require("./ProfileManager");
11
+ class BrowserManager {
12
+ constructor(browserPath, profilesDir) {
13
+ this.instances = new Map();
14
+ this.browserPath = browserPath;
15
+ this.profilesManager = new ProfileManager_1.ProfileManager(profilesDir);
16
+ }
17
+ static getInstance(browserPath, profilesDir) {
18
+ if (!BrowserManager.instance) {
19
+ if (!browserPath || !profilesDir) {
20
+ throw new Error('BrowserManager must be initialized with browserPath and profilesDir');
21
+ }
22
+ BrowserManager.instance = new BrowserManager(browserPath, profilesDir);
23
+ }
24
+ return BrowserManager.instance;
25
+ }
26
+ static resetInstance() {
27
+ BrowserManager.instance = null;
28
+ }
29
+ async startProfile(profileId, windowConfig) {
30
+ // Kiểm tra xem profile đã đang chạy chưa
31
+ if (this.instances.has(profileId)) {
32
+ throw new Error(`Profile ${profileId} is already running`);
33
+ }
34
+ // Lấy thông tin profile
35
+ const profile = this.profilesManager.getProfile(profileId);
36
+ if (!profile) {
37
+ throw new Error(`Profile ${profileId} not found`);
38
+ }
39
+ const profilePath = this.profilesManager.getProfilePath(profileId);
40
+ // Chuẩn bị Chrome arguments
41
+ const args = [
42
+ `--user-data-dir=${profilePath}`,
43
+ '--remote-debugging-port=0',
44
+ '--disable-blink-features=AutomationControlled',
45
+ '--disable-dev-shm-usage',
46
+ '--no-sandbox',
47
+ '--disable-setuid-sandbox',
48
+ ];
49
+ // Proxy configuration
50
+ if (profile.proxy) {
51
+ const proxyConfig = ProxyHandler_1.ProxyHandler.parseProxyString(profile.proxy);
52
+ if (proxyConfig) {
53
+ args.push(...ProxyHandler_1.ProxyHandler.getChromeProxyArgs(proxyConfig));
54
+ }
55
+ }
56
+ // Extension configuration
57
+ if (profile.extensions && profile.extensions.length > 0) {
58
+ args.push(...ExtensionHandler_1.ExtensionHandler.getExtensionArgs(profile.extensions));
59
+ }
60
+ // Window configuration
61
+ if (windowConfig) {
62
+ if (windowConfig.scale) {
63
+ args.push(`--force-device-scale-factor=${windowConfig.scale}`);
64
+ }
65
+ if (windowConfig.headless) {
66
+ args.push('--headless=new');
67
+ }
68
+ }
69
+ // Khởi động Chrome
70
+ const browser = await puppeteer_core_1.default.launch({
71
+ executablePath: this.browserPath,
72
+ args,
73
+ headless: windowConfig?.headless || false,
74
+ defaultViewport: windowConfig?.size
75
+ ? {
76
+ width: windowConfig.size.width,
77
+ height: windowConfig.size.height,
78
+ }
79
+ : null,
80
+ });
81
+ // Lấy debug port từ browser
82
+ const targets = browser.targets();
83
+ const debugPort = await this.getDebugPort(browser);
84
+ // Tạo instance
85
+ const instance = {
86
+ profileId,
87
+ process: browser.process(),
88
+ browser,
89
+ pages: new Map(),
90
+ debugPort,
91
+ };
92
+ // Lưu instance
93
+ this.instances.set(profileId, instance);
94
+ // Set window position nếu có
95
+ if (windowConfig?.position && !windowConfig.headless) {
96
+ await this.setWindowPosition(browser, windowConfig.position);
97
+ }
98
+ return instance;
99
+ }
100
+ async stopProfile(profileId) {
101
+ const instance = this.instances.get(profileId);
102
+ if (!instance) {
103
+ return false;
104
+ }
105
+ try {
106
+ await instance.browser.close();
107
+ this.instances.delete(profileId);
108
+ return true;
109
+ }
110
+ catch (error) {
111
+ this.instances.delete(profileId);
112
+ return false;
113
+ }
114
+ }
115
+ getInstance(profileId) {
116
+ return this.instances.get(profileId);
117
+ }
118
+ getAllInstances() {
119
+ return Array.from(this.instances.values());
120
+ }
121
+ async getDebugPort(browser) {
122
+ try {
123
+ const endpoint = browser.wsEndpoint();
124
+ const match = endpoint.match(/localhost:(\d+)/);
125
+ if (match) {
126
+ return parseInt(match[1], 10);
127
+ }
128
+ }
129
+ catch (error) {
130
+ // Ignore
131
+ }
132
+ return 0;
133
+ }
134
+ async setWindowPosition(browser, position) {
135
+ try {
136
+ // Window position được set thông qua Chrome DevTools Protocol
137
+ const pages = await browser.pages();
138
+ if (pages.length > 0) {
139
+ const target = pages[0].target();
140
+ const client = await target.createCDPSession();
141
+ // Note: Window position setting via CDP may require additional setup
142
+ // For now, we'll rely on Chrome's default behavior
143
+ // The position parameter is stored but not actively used
144
+ await client.detach();
145
+ }
146
+ }
147
+ catch (error) {
148
+ // Ignore if not supported - window position is optional
149
+ }
150
+ }
151
+ async getPage(profileId, tabIndex = 0) {
152
+ const instance = this.instances.get(profileId);
153
+ if (!instance) {
154
+ return null;
155
+ }
156
+ // Kiểm tra cache
157
+ if (instance.pages.has(tabIndex)) {
158
+ return instance.pages.get(tabIndex);
159
+ }
160
+ // Lấy pages từ browser
161
+ const pages = await instance.browser.pages();
162
+ if (pages.length > tabIndex) {
163
+ const page = pages[tabIndex];
164
+ instance.pages.set(tabIndex, page);
165
+ return page;
166
+ }
167
+ // Tạo page mới nếu không có
168
+ const newPage = await instance.browser.newPage();
169
+ instance.pages.set(tabIndex, newPage);
170
+ return newPage;
171
+ }
172
+ }
173
+ BrowserManager.instance = null;
174
+ exports.BrowserManager = BrowserManager;
@@ -0,0 +1,9 @@
1
+ export declare class ExtensionHandler {
2
+ static parseExtensions(extensionInput: string): string[];
3
+ static validateExtension(extension: string): {
4
+ valid: boolean;
5
+ path?: string;
6
+ error?: string;
7
+ };
8
+ static getExtensionArgs(extensions: string[]): string[];
9
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ExtensionHandler = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ class ExtensionHandler {
30
+ static parseExtensions(extensionInput) {
31
+ if (!extensionInput || !extensionInput.trim()) {
32
+ return [];
33
+ }
34
+ // Mỗi extension một dòng
35
+ const lines = extensionInput
36
+ .split('\n')
37
+ .map(line => line.trim())
38
+ .filter(line => line.length > 0);
39
+ return lines;
40
+ }
41
+ static validateExtension(extension) {
42
+ // Nếu là ID từ Chrome Store (thường là 32 ký tự alphanumeric)
43
+ if (/^[a-z]{32}$/i.test(extension)) {
44
+ return { valid: true };
45
+ }
46
+ // Nếu là đường dẫn local
47
+ if (path.isAbsolute(extension) || extension.startsWith('./') || extension.startsWith('../')) {
48
+ const resolvedPath = path.resolve(extension);
49
+ if (fs.existsSync(resolvedPath)) {
50
+ // Kiểm tra xem có phải là extension directory không
51
+ const manifestPath = path.join(resolvedPath, 'manifest.json');
52
+ if (fs.existsSync(manifestPath)) {
53
+ return { valid: true, path: resolvedPath };
54
+ }
55
+ return { valid: false, error: 'Extension directory does not contain manifest.json' };
56
+ }
57
+ return { valid: false, error: 'Extension path does not exist' };
58
+ }
59
+ // Nếu là relative path từ workspace
60
+ const workspacePath = path.resolve(__dirname, '..', extension);
61
+ if (fs.existsSync(workspacePath)) {
62
+ const manifestPath = path.join(workspacePath, 'manifest.json');
63
+ if (fs.existsSync(manifestPath)) {
64
+ return { valid: true, path: workspacePath };
65
+ }
66
+ return { valid: false, error: 'Extension directory does not contain manifest.json' };
67
+ }
68
+ return { valid: false, error: 'Invalid extension format. Must be Chrome Store ID or valid path' };
69
+ }
70
+ static getExtensionArgs(extensions) {
71
+ const args = [];
72
+ const validPaths = [];
73
+ for (const ext of extensions) {
74
+ const validation = this.validateExtension(ext);
75
+ if (validation.valid && validation.path) {
76
+ validPaths.push(validation.path);
77
+ }
78
+ // Chrome Store IDs sẽ được load sau khi browser khởi động
79
+ }
80
+ if (validPaths.length > 0) {
81
+ args.push(`--load-extension=${validPaths.join(',')}`);
82
+ }
83
+ return args;
84
+ }
85
+ }
86
+ exports.ExtensionHandler = ExtensionHandler;
@@ -0,0 +1,14 @@
1
+ import { ProfileData } from './types';
2
+ export declare class ProfileManager {
3
+ private profilesDir;
4
+ constructor(profilesDir: string);
5
+ private ensureProfilesDir;
6
+ private getProfileMetadataPath;
7
+ private getProfileDir;
8
+ createProfile(name: string, proxy?: string, note?: string, extensions?: string[]): ProfileData;
9
+ getProfile(profileId: string): ProfileData | null;
10
+ getAllProfiles(): ProfileData[];
11
+ updateProfile(profileId: string, updates: Partial<ProfileData>): ProfileData | null;
12
+ deleteProfile(profileId: string): boolean;
13
+ getProfilePath(profileId: string): string;
14
+ }
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.ProfileManager = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ const uuid_1 = require("uuid");
30
+ class ProfileManager {
31
+ constructor(profilesDir) {
32
+ this.profilesDir = profilesDir;
33
+ this.ensureProfilesDir();
34
+ }
35
+ ensureProfilesDir() {
36
+ if (!fs.existsSync(this.profilesDir)) {
37
+ fs.mkdirSync(this.profilesDir, { recursive: true });
38
+ }
39
+ }
40
+ getProfileMetadataPath(profileId) {
41
+ return path.join(this.profilesDir, profileId, 'profile.metadata.json');
42
+ }
43
+ getProfileDir(profileId) {
44
+ return path.join(this.profilesDir, profileId);
45
+ }
46
+ createProfile(name, proxy, note, extensions) {
47
+ const profileId = (0, uuid_1.v4)();
48
+ const profileDir = this.getProfileDir(profileId);
49
+ // Tạo thư mục profile
50
+ fs.mkdirSync(profileDir, { recursive: true });
51
+ const profileData = {
52
+ id: profileId,
53
+ name,
54
+ proxy,
55
+ note,
56
+ extensions: extensions || [],
57
+ createdAt: new Date().toISOString(),
58
+ updatedAt: new Date().toISOString(),
59
+ };
60
+ // Lưu metadata
61
+ const metadataPath = this.getProfileMetadataPath(profileId);
62
+ fs.writeFileSync(metadataPath, JSON.stringify(profileData, null, 2), 'utf-8');
63
+ return profileData;
64
+ }
65
+ getProfile(profileId) {
66
+ const metadataPath = this.getProfileMetadataPath(profileId);
67
+ if (!fs.existsSync(metadataPath)) {
68
+ return null;
69
+ }
70
+ try {
71
+ const content = fs.readFileSync(metadataPath, 'utf-8');
72
+ return JSON.parse(content);
73
+ }
74
+ catch (error) {
75
+ return null;
76
+ }
77
+ }
78
+ getAllProfiles() {
79
+ const profiles = [];
80
+ if (!fs.existsSync(this.profilesDir)) {
81
+ return profiles;
82
+ }
83
+ const dirs = fs.readdirSync(this.profilesDir);
84
+ for (const dir of dirs) {
85
+ const profilePath = path.join(this.profilesDir, dir);
86
+ if (fs.statSync(profilePath).isDirectory()) {
87
+ const profile = this.getProfile(dir);
88
+ if (profile) {
89
+ profiles.push(profile);
90
+ }
91
+ }
92
+ }
93
+ return profiles;
94
+ }
95
+ updateProfile(profileId, updates) {
96
+ const profile = this.getProfile(profileId);
97
+ if (!profile) {
98
+ return null;
99
+ }
100
+ const updatedProfile = {
101
+ ...profile,
102
+ ...updates,
103
+ id: profileId,
104
+ updatedAt: new Date().toISOString(),
105
+ };
106
+ const metadataPath = this.getProfileMetadataPath(profileId);
107
+ fs.writeFileSync(metadataPath, JSON.stringify(updatedProfile, null, 2), 'utf-8');
108
+ return updatedProfile;
109
+ }
110
+ deleteProfile(profileId) {
111
+ const profileDir = this.getProfileDir(profileId);
112
+ if (!fs.existsSync(profileDir)) {
113
+ return false;
114
+ }
115
+ try {
116
+ // Xóa toàn bộ thư mục profile
117
+ fs.rmSync(profileDir, { recursive: true, force: true });
118
+ return true;
119
+ }
120
+ catch (error) {
121
+ return false;
122
+ }
123
+ }
124
+ getProfilePath(profileId) {
125
+ return this.getProfileDir(profileId);
126
+ }
127
+ }
128
+ exports.ProfileManager = ProfileManager;
@@ -0,0 +1,5 @@
1
+ import { ProxyConfig } from './types';
2
+ export declare class ProxyHandler {
3
+ static parseProxyString(proxyString: string): ProxyConfig | null;
4
+ static getChromeProxyArgs(proxyConfig: ProxyConfig | null): string[];
5
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProxyHandler = void 0;
4
+ class ProxyHandler {
5
+ static parseProxyString(proxyString) {
6
+ if (!proxyString || !proxyString.trim()) {
7
+ return null;
8
+ }
9
+ // Format: http:127.0.0.1:8080:user:pass hoặc socks5:127.0.0.1:1080:user:pass
10
+ const parts = proxyString.split(':');
11
+ if (parts.length < 3) {
12
+ return null;
13
+ }
14
+ const type = parts[0].toLowerCase();
15
+ if (type !== 'http' && type !== 'socks5') {
16
+ return null;
17
+ }
18
+ const host = parts[1];
19
+ const port = parseInt(parts[2], 10);
20
+ if (isNaN(port)) {
21
+ return null;
22
+ }
23
+ const config = {
24
+ type,
25
+ host,
26
+ port,
27
+ };
28
+ if (parts.length >= 4) {
29
+ config.username = parts[3];
30
+ }
31
+ if (parts.length >= 5) {
32
+ config.password = parts[4];
33
+ }
34
+ return config;
35
+ }
36
+ static getChromeProxyArgs(proxyConfig) {
37
+ if (!proxyConfig) {
38
+ return [];
39
+ }
40
+ const args = [];
41
+ if (proxyConfig.type === 'http') {
42
+ args.push(`--proxy-server=http://${proxyConfig.host}:${proxyConfig.port}`);
43
+ }
44
+ else if (proxyConfig.type === 'socks5') {
45
+ args.push(`--proxy-server=socks5://${proxyConfig.host}:${proxyConfig.port}`);
46
+ }
47
+ return args;
48
+ }
49
+ }
50
+ exports.ProxyHandler = ProxyHandler;