nport 2.0.7 → 2.1.1
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/CHANGELOG.md +173 -0
- package/README.md +42 -32
- package/dist/analytics.d.ts +59 -0
- package/dist/analytics.js +193 -0
- package/dist/analytics.js.map +1 -0
- package/dist/api.d.ts +20 -0
- package/dist/api.js +85 -0
- package/dist/api.js.map +1 -0
- package/dist/args.d.ts +44 -0
- package/dist/args.js +127 -0
- package/dist/args.js.map +1 -0
- package/dist/bin-manager.d.ts +1 -0
- package/dist/bin-manager.js +209 -0
- package/dist/bin-manager.js.map +1 -0
- package/dist/binary.d.ts +42 -0
- package/dist/binary.js +119 -0
- package/dist/binary.js.map +1 -0
- package/dist/config-manager.d.ts +54 -0
- package/dist/config-manager.js +129 -0
- package/dist/config-manager.js.map +1 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.js +59 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +61 -0
- package/dist/constants.js +86 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/lang.d.ts +38 -0
- package/dist/lang.js +217 -0
- package/dist/lang.js.map +1 -0
- package/dist/state.d.ts +82 -0
- package/dist/state.js +139 -0
- package/dist/state.js.map +1 -0
- package/dist/tunnel.d.ts +16 -0
- package/dist/tunnel.js +101 -0
- package/dist/tunnel.js.map +1 -0
- package/dist/types/analytics.d.ts +91 -0
- package/dist/types/analytics.js +8 -0
- package/dist/types/analytics.js.map +1 -0
- package/dist/types/config.d.ts +89 -0
- package/dist/types/config.js +8 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/i18n.d.ts +75 -0
- package/dist/types/i18n.js +5 -0
- package/dist/types/i18n.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/tunnel.d.ts +74 -0
- package/dist/types/tunnel.js +8 -0
- package/dist/types/tunnel.js.map +1 -0
- package/dist/types/version.d.ts +25 -0
- package/dist/types/version.js +5 -0
- package/dist/types/version.js.map +1 -0
- package/dist/ui.d.ts +54 -0
- package/dist/ui.js +120 -0
- package/dist/ui.js.map +1 -0
- package/dist/version.d.ts +16 -0
- package/dist/version.js +49 -0
- package/dist/version.js.map +1 -0
- package/package.json +18 -7
- package/scripts/postinstall.js +25 -0
- package/index.js +0 -110
- package/src/analytics.js +0 -265
- package/src/api.js +0 -104
- package/src/args.js +0 -122
- package/src/bin-manager.js +0 -379
- package/src/binary.js +0 -126
- package/src/config-manager.js +0 -139
- package/src/config.js +0 -88
- package/src/lang.js +0 -293
- package/src/state.js +0 -115
- package/src/tunnel.js +0 -116
- package/src/ui.js +0 -103
- package/src/version.js +0 -56
package/src/bin-manager.js
DELETED
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import https from "https";
|
|
4
|
-
import os from "os";
|
|
5
|
-
import { execSync } from "child_process";
|
|
6
|
-
import { fileURLToPath } from "url";
|
|
7
|
-
|
|
8
|
-
// ============================================================================
|
|
9
|
-
// Configuration & Constants
|
|
10
|
-
// ============================================================================
|
|
11
|
-
|
|
12
|
-
// Fix for __dirname in ES modules
|
|
13
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
-
const __dirname = path.dirname(path.dirname(__filename));
|
|
15
|
-
|
|
16
|
-
// Binary configuration
|
|
17
|
-
const BIN_DIR = path.join(__dirname, "bin");
|
|
18
|
-
const BINARY_NAME = "cloudflared";
|
|
19
|
-
const COMPRESSED_SUFFIX = ".tgz";
|
|
20
|
-
const TEMP_ARCHIVE_NAME = "cloudflared.tgz";
|
|
21
|
-
|
|
22
|
-
// Platform detection
|
|
23
|
-
const PLATFORM = os.platform();
|
|
24
|
-
const ARCH = os.arch();
|
|
25
|
-
const IS_WINDOWS = PLATFORM === "win32";
|
|
26
|
-
const IS_MACOS = PLATFORM === "darwin";
|
|
27
|
-
const IS_LINUX = PLATFORM === "linux";
|
|
28
|
-
|
|
29
|
-
// Binary paths
|
|
30
|
-
const BIN_NAME = IS_WINDOWS ? `${BINARY_NAME}.exe` : BINARY_NAME;
|
|
31
|
-
const BIN_PATH = path.join(BIN_DIR, BIN_NAME);
|
|
32
|
-
|
|
33
|
-
// Download configuration
|
|
34
|
-
const GITHUB_BASE_URL = "https://github.com/cloudflare/cloudflared/releases/latest/download";
|
|
35
|
-
const REDIRECT_CODES = [301, 302];
|
|
36
|
-
const SUCCESS_CODE = 200;
|
|
37
|
-
const UNIX_EXECUTABLE_MODE = "755";
|
|
38
|
-
|
|
39
|
-
// ============================================================================
|
|
40
|
-
// Platform Detection
|
|
41
|
-
// ============================================================================
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Platform and architecture mapping for cloudflared releases
|
|
45
|
-
*/
|
|
46
|
-
const PLATFORM_MAPPINGS = {
|
|
47
|
-
darwin: {
|
|
48
|
-
amd64: "cloudflared-darwin-amd64.tgz",
|
|
49
|
-
arm64: "cloudflared-darwin-amd64.tgz", // macOS uses universal binary
|
|
50
|
-
},
|
|
51
|
-
win32: {
|
|
52
|
-
x64: "cloudflared-windows-amd64.exe",
|
|
53
|
-
ia32: "cloudflared-windows-386.exe",
|
|
54
|
-
},
|
|
55
|
-
linux: {
|
|
56
|
-
x64: "cloudflared-linux-amd64",
|
|
57
|
-
arm64: "cloudflared-linux-arm64",
|
|
58
|
-
arm: "cloudflared-linux-arm",
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Normalizes architecture name for mapping lookup
|
|
64
|
-
* @param {string} arch - Raw architecture from os.arch()
|
|
65
|
-
* @returns {string} Normalized architecture name
|
|
66
|
-
*/
|
|
67
|
-
function normalizeArch(arch) {
|
|
68
|
-
const archMap = {
|
|
69
|
-
x64: "x64",
|
|
70
|
-
amd64: "amd64",
|
|
71
|
-
arm64: "arm64",
|
|
72
|
-
ia32: "ia32",
|
|
73
|
-
arm: "arm",
|
|
74
|
-
};
|
|
75
|
-
return archMap[arch] || arch;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Determines the download URL based on current platform and architecture
|
|
80
|
-
* @returns {string} Download URL for cloudflared binary
|
|
81
|
-
* @throws {Error} If platform/architecture combination is not supported
|
|
82
|
-
*/
|
|
83
|
-
function getDownloadUrl() {
|
|
84
|
-
const normalizedArch = normalizeArch(ARCH);
|
|
85
|
-
const platformMapping = PLATFORM_MAPPINGS[PLATFORM];
|
|
86
|
-
|
|
87
|
-
if (!platformMapping) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
`Unsupported platform: ${PLATFORM}. Supported platforms: darwin, win32, linux`
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const binaryName = platformMapping[normalizedArch];
|
|
94
|
-
|
|
95
|
-
if (!binaryName) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`Unsupported architecture: ${ARCH} for platform ${PLATFORM}. ` +
|
|
98
|
-
`Supported architectures: ${Object.keys(platformMapping).join(", ")}`
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return `${GITHUB_BASE_URL}/${binaryName}`;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Checks if the download URL points to a compressed archive
|
|
107
|
-
* @param {string} url - Download URL
|
|
108
|
-
* @returns {boolean} True if URL is for a compressed file
|
|
109
|
-
*/
|
|
110
|
-
function isCompressedArchive(url) {
|
|
111
|
-
return url.endsWith(COMPRESSED_SUFFIX);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ============================================================================
|
|
115
|
-
// File System Utilities
|
|
116
|
-
// ============================================================================
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Ensures directory exists, creates it if it doesn't
|
|
120
|
-
* @param {string} dirPath - Directory path to ensure
|
|
121
|
-
*/
|
|
122
|
-
function ensureDirectory(dirPath) {
|
|
123
|
-
if (!fs.existsSync(dirPath)) {
|
|
124
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Safely removes a file if it exists
|
|
130
|
-
* @param {string} filePath - Path to file to remove
|
|
131
|
-
*/
|
|
132
|
-
function safeUnlink(filePath) {
|
|
133
|
-
try {
|
|
134
|
-
if (fs.existsSync(filePath)) {
|
|
135
|
-
fs.unlinkSync(filePath);
|
|
136
|
-
}
|
|
137
|
-
} catch (err) {
|
|
138
|
-
// Ignore errors during cleanup
|
|
139
|
-
console.warn(`Warning: Could not remove ${filePath}:`, err.message);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Sets executable permissions on Unix-like systems
|
|
145
|
-
* @param {string} filePath - Path to file
|
|
146
|
-
* @param {string} mode - Permission mode (e.g., "755")
|
|
147
|
-
*/
|
|
148
|
-
function setExecutablePermissions(filePath, mode = UNIX_EXECUTABLE_MODE) {
|
|
149
|
-
if (!IS_WINDOWS) {
|
|
150
|
-
fs.chmodSync(filePath, mode);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Validates that a file exists at the given path
|
|
156
|
-
* @param {string} filePath - Path to validate
|
|
157
|
-
* @param {string} errorMessage - Error message if file doesn't exist
|
|
158
|
-
* @throws {Error} If file doesn't exist
|
|
159
|
-
*/
|
|
160
|
-
function validateFileExists(filePath, errorMessage) {
|
|
161
|
-
if (!fs.existsSync(filePath)) {
|
|
162
|
-
throw new Error(errorMessage || `File not found: ${filePath}`);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// ============================================================================
|
|
167
|
-
// Download Utilities
|
|
168
|
-
// ============================================================================
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Downloads a file from a URL with automatic redirect handling
|
|
172
|
-
* @param {string} url - URL to download from
|
|
173
|
-
* @param {string} dest - Destination file path
|
|
174
|
-
* @returns {Promise<string>} Resolves with destination path on success
|
|
175
|
-
*/
|
|
176
|
-
async function downloadFile(url, dest) {
|
|
177
|
-
return new Promise((resolve, reject) => {
|
|
178
|
-
const file = fs.createWriteStream(dest);
|
|
179
|
-
|
|
180
|
-
https
|
|
181
|
-
.get(url, (response) => {
|
|
182
|
-
// Handle redirects
|
|
183
|
-
if (REDIRECT_CODES.includes(response.statusCode)) {
|
|
184
|
-
file.close();
|
|
185
|
-
safeUnlink(dest);
|
|
186
|
-
downloadFile(response.headers.location, dest)
|
|
187
|
-
.then(resolve)
|
|
188
|
-
.catch(reject);
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Handle non-success status codes
|
|
193
|
-
if (response.statusCode !== SUCCESS_CODE) {
|
|
194
|
-
file.close();
|
|
195
|
-
safeUnlink(dest);
|
|
196
|
-
reject(
|
|
197
|
-
new Error(
|
|
198
|
-
`Download failed with status code ${response.statusCode} from ${url}`
|
|
199
|
-
)
|
|
200
|
-
);
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Stream response to file
|
|
205
|
-
response.pipe(file);
|
|
206
|
-
|
|
207
|
-
file.on("finish", () => {
|
|
208
|
-
file.close(() => resolve(dest));
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
file.on("error", (err) => {
|
|
212
|
-
file.close();
|
|
213
|
-
safeUnlink(dest);
|
|
214
|
-
reject(err);
|
|
215
|
-
});
|
|
216
|
-
})
|
|
217
|
-
.on("error", (err) => {
|
|
218
|
-
file.close();
|
|
219
|
-
safeUnlink(dest);
|
|
220
|
-
reject(new Error(`Network error: ${err.message}`));
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// ============================================================================
|
|
226
|
-
// Archive Extraction
|
|
227
|
-
// ============================================================================
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Extracts a .tgz archive to a directory
|
|
231
|
-
* @param {string} archivePath - Path to .tgz file
|
|
232
|
-
* @param {string} targetDir - Directory to extract to
|
|
233
|
-
* @throws {Error} If extraction fails
|
|
234
|
-
*/
|
|
235
|
-
function extractTarGz(archivePath, targetDir) {
|
|
236
|
-
try {
|
|
237
|
-
execSync(`tar -xzf "${archivePath}" -C "${targetDir}"`, {
|
|
238
|
-
stdio: "pipe", // Suppress output
|
|
239
|
-
});
|
|
240
|
-
} catch (err) {
|
|
241
|
-
throw new Error(`Extraction failed: ${err.message}`);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// ============================================================================
|
|
246
|
-
// Logging Utilities
|
|
247
|
-
// ============================================================================
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* Console logging with consistent formatting
|
|
251
|
-
*/
|
|
252
|
-
const logger = {
|
|
253
|
-
info: (msg) => console.log(`ℹ️ ${msg}`),
|
|
254
|
-
success: (msg) => console.log(`✅ ${msg}`),
|
|
255
|
-
warn: (msg) => console.warn(`⚠️ ${msg}`),
|
|
256
|
-
error: (msg) => console.error(`❌ ${msg}`),
|
|
257
|
-
progress: (msg) => console.log(`🚧 ${msg}`),
|
|
258
|
-
extract: (msg) => console.log(`📦 ${msg}`),
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
// ============================================================================
|
|
262
|
-
// Core Binary Management
|
|
263
|
-
// ============================================================================
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Downloads and installs the cloudflared binary
|
|
267
|
-
* @returns {Promise<string>} Path to installed binary
|
|
268
|
-
*/
|
|
269
|
-
async function installBinary() {
|
|
270
|
-
logger.progress(
|
|
271
|
-
"Cloudflared binary not found. Downloading... (This happens only once)"
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
const url = getDownloadUrl();
|
|
275
|
-
const isArchive = isCompressedArchive(url);
|
|
276
|
-
const downloadDest = isArchive
|
|
277
|
-
? path.join(BIN_DIR, TEMP_ARCHIVE_NAME)
|
|
278
|
-
: BIN_PATH;
|
|
279
|
-
|
|
280
|
-
try {
|
|
281
|
-
// Download binary or archive
|
|
282
|
-
await downloadFile(url, downloadDest);
|
|
283
|
-
|
|
284
|
-
// Extract if it's an archive (macOS)
|
|
285
|
-
if (isArchive) {
|
|
286
|
-
logger.extract("Extracting binary...");
|
|
287
|
-
extractTarGz(downloadDest, BIN_DIR);
|
|
288
|
-
|
|
289
|
-
// Clean up archive
|
|
290
|
-
safeUnlink(downloadDest);
|
|
291
|
-
|
|
292
|
-
// Validate extraction succeeded
|
|
293
|
-
validateFileExists(
|
|
294
|
-
BIN_PATH,
|
|
295
|
-
"Extraction failed: Binary not found after extraction"
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Set executable permissions (Unix-like systems)
|
|
300
|
-
setExecutablePermissions(BIN_PATH);
|
|
301
|
-
|
|
302
|
-
logger.success("Download complete.");
|
|
303
|
-
return BIN_PATH;
|
|
304
|
-
} catch (error) {
|
|
305
|
-
// Clean up any partial downloads
|
|
306
|
-
safeUnlink(downloadDest);
|
|
307
|
-
safeUnlink(BIN_PATH);
|
|
308
|
-
throw error;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Ensures cloudflared binary is available, downloading if necessary
|
|
314
|
-
* @returns {Promise<string>} Path to cloudflared binary
|
|
315
|
-
*/
|
|
316
|
-
export async function ensureCloudflared() {
|
|
317
|
-
// Ensure bin directory exists
|
|
318
|
-
ensureDirectory(BIN_DIR);
|
|
319
|
-
|
|
320
|
-
// Check if binary already exists
|
|
321
|
-
if (fs.existsSync(BIN_PATH)) {
|
|
322
|
-
// Always ensure permissions are set correctly (in case they were lost)
|
|
323
|
-
setExecutablePermissions(BIN_PATH);
|
|
324
|
-
return BIN_PATH;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Download and install
|
|
328
|
-
try {
|
|
329
|
-
return await installBinary();
|
|
330
|
-
} catch (error) {
|
|
331
|
-
logger.error(`Installation failed: ${error.message}`);
|
|
332
|
-
process.exit(1);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// ============================================================================
|
|
337
|
-
// CLI Entry Point
|
|
338
|
-
// ============================================================================
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Checks if we're running in a CI environment
|
|
342
|
-
* @returns {boolean} True if in CI environment
|
|
343
|
-
*/
|
|
344
|
-
function isCI() {
|
|
345
|
-
return !!(
|
|
346
|
-
process.env.CI || // Generic CI flag
|
|
347
|
-
process.env.GITHUB_ACTIONS || // GitHub Actions
|
|
348
|
-
process.env.GITLAB_CI || // GitLab CI
|
|
349
|
-
process.env.CIRCLECI || // CircleCI
|
|
350
|
-
process.env.TRAVIS || // Travis CI
|
|
351
|
-
process.env.JENKINS_URL || // Jenkins
|
|
352
|
-
process.env.BUILDKITE // Buildkite
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Main function when run directly from command line
|
|
358
|
-
*/
|
|
359
|
-
async function main() {
|
|
360
|
-
// Skip binary download in CI environments to keep package lightweight
|
|
361
|
-
if (isCI()) {
|
|
362
|
-
logger.info("Running in CI environment - skipping binary download");
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
try {
|
|
367
|
-
const binaryPath = await ensureCloudflared();
|
|
368
|
-
logger.success(`Cloudflared binary is ready at: ${binaryPath}`);
|
|
369
|
-
} catch (error) {
|
|
370
|
-
logger.error(error.message);
|
|
371
|
-
process.exit(1);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Run if executed directly
|
|
376
|
-
if (process.argv[1] === __filename) {
|
|
377
|
-
main();
|
|
378
|
-
}
|
|
379
|
-
|
package/src/binary.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import { spawn } from "child_process";
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import fs from "fs";
|
|
4
|
-
import { LOG_PATTERNS, NETWORK_CONFIG } from "./config.js";
|
|
5
|
-
import { state } from "./state.js";
|
|
6
|
-
import { UI } from "./ui.js";
|
|
7
|
-
import { lang } from "./lang.js";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Binary Manager
|
|
11
|
-
* Handles cloudflared binary validation, spawning, and process management
|
|
12
|
-
*/
|
|
13
|
-
export class BinaryManager {
|
|
14
|
-
static validate(binaryPath) {
|
|
15
|
-
if (fs.existsSync(binaryPath)) {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
console.error(
|
|
20
|
-
chalk.red(`\n❌ Error: Cloudflared binary not found at: ${binaryPath}`)
|
|
21
|
-
);
|
|
22
|
-
console.error(
|
|
23
|
-
chalk.yellow(
|
|
24
|
-
"👉 Please run 'npm install' again to download the binary.\n"
|
|
25
|
-
)
|
|
26
|
-
);
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
static spawn(binaryPath, token, port) {
|
|
31
|
-
return spawn(binaryPath, [
|
|
32
|
-
"tunnel",
|
|
33
|
-
"run",
|
|
34
|
-
"--token",
|
|
35
|
-
token,
|
|
36
|
-
"--url",
|
|
37
|
-
`http://localhost:${port}`,
|
|
38
|
-
]);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
static attachHandlers(process, spinner = null) {
|
|
42
|
-
process.stderr.on("data", (chunk) => this.handleStderr(chunk));
|
|
43
|
-
process.on("error", (err) => this.handleError(err, spinner));
|
|
44
|
-
process.on("close", (code) => this.handleClose(code));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
static handleStderr(chunk) {
|
|
48
|
-
const msg = chunk.toString();
|
|
49
|
-
|
|
50
|
-
// Skip harmless warnings
|
|
51
|
-
if (LOG_PATTERNS.IGNORE.some((pattern) => msg.includes(pattern))) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Check for network warnings (QUIC/connectivity issues)
|
|
56
|
-
if (LOG_PATTERNS.NETWORK_WARNING.some((pattern) => msg.includes(pattern))) {
|
|
57
|
-
this.handleNetworkWarning(msg);
|
|
58
|
-
return; // Don't show the raw error to user
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Show success messages with connection count
|
|
62
|
-
if (LOG_PATTERNS.SUCCESS.some((pattern) => msg.includes(pattern))) {
|
|
63
|
-
const count = state.incrementConnection();
|
|
64
|
-
|
|
65
|
-
// Reset network issue count when connection succeeds
|
|
66
|
-
if (count === 1) {
|
|
67
|
-
state.resetNetworkIssues();
|
|
68
|
-
console.log(chalk.green(lang.t("connection1")));
|
|
69
|
-
} else if (count === 4) {
|
|
70
|
-
console.log(chalk.green(lang.t("connection2")));
|
|
71
|
-
// Display footer after tunnel is fully active
|
|
72
|
-
UI.displayFooter(state.updateInfo);
|
|
73
|
-
}
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Show critical errors only
|
|
78
|
-
if (LOG_PATTERNS.ERROR.some((pattern) => msg.includes(pattern))) {
|
|
79
|
-
console.error(chalk.red(`[Cloudflared] ${msg.trim()}`));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
static handleNetworkWarning(msg) {
|
|
84
|
-
const count = state.incrementNetworkIssue();
|
|
85
|
-
|
|
86
|
-
// Show user-friendly warning after threshold is reached
|
|
87
|
-
if (
|
|
88
|
-
state.shouldShowNetworkWarning(
|
|
89
|
-
NETWORK_CONFIG.WARNING_THRESHOLD,
|
|
90
|
-
NETWORK_CONFIG.WARNING_COOLDOWN
|
|
91
|
-
)
|
|
92
|
-
) {
|
|
93
|
-
this.displayNetworkWarning();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
static displayNetworkWarning() {
|
|
98
|
-
console.log(chalk.yellow(lang.t("networkIssueTitle")));
|
|
99
|
-
console.log(chalk.gray(lang.t("networkIssueDesc")));
|
|
100
|
-
console.log(chalk.cyan(lang.t("networkIssueTunnel")));
|
|
101
|
-
console.log(chalk.yellow(lang.t("networkIssueReasons")));
|
|
102
|
-
console.log(chalk.gray(lang.t("networkIssueReason1")));
|
|
103
|
-
console.log(chalk.gray(lang.t("networkIssueReason2")));
|
|
104
|
-
console.log(chalk.gray(lang.t("networkIssueReason3")));
|
|
105
|
-
console.log(chalk.yellow(lang.t("networkIssueFix")));
|
|
106
|
-
console.log(chalk.gray(lang.t("networkIssueFix1")));
|
|
107
|
-
console.log(chalk.gray(lang.t("networkIssueFix2")));
|
|
108
|
-
console.log(chalk.gray(lang.t("networkIssueFix3")));
|
|
109
|
-
console.log(chalk.gray(lang.t("networkIssueFix4")));
|
|
110
|
-
console.log(chalk.blue(lang.t("networkIssueIgnore")));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
static handleError(err, spinner) {
|
|
114
|
-
if (spinner) {
|
|
115
|
-
spinner.fail("Failed to spawn cloudflared process.");
|
|
116
|
-
}
|
|
117
|
-
console.error(chalk.red(`Process Error: ${err.message}`));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
static handleClose(code) {
|
|
121
|
-
if (code !== 0 && code !== null) {
|
|
122
|
-
console.log(chalk.red(`Tunnel process exited with code ${code}`));
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
package/src/config-manager.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import os from "os";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Configuration Manager
|
|
7
|
-
* Handles persistent storage of user preferences (backend URL, language, etc.)
|
|
8
|
-
*/
|
|
9
|
-
class ConfigManager {
|
|
10
|
-
constructor() {
|
|
11
|
-
this.configDir = path.join(os.homedir(), ".nport");
|
|
12
|
-
this.configFile = path.join(this.configDir, "config.json");
|
|
13
|
-
this.oldLangFile = path.join(this.configDir, "lang"); // For migration
|
|
14
|
-
this.config = this.loadConfig();
|
|
15
|
-
this.migrateOldConfig();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Load configuration from file
|
|
20
|
-
* @returns {object} Configuration object
|
|
21
|
-
*/
|
|
22
|
-
loadConfig() {
|
|
23
|
-
try {
|
|
24
|
-
if (fs.existsSync(this.configFile)) {
|
|
25
|
-
const data = fs.readFileSync(this.configFile, "utf8");
|
|
26
|
-
return JSON.parse(data);
|
|
27
|
-
}
|
|
28
|
-
} catch (error) {
|
|
29
|
-
// If config is corrupted or invalid, return default
|
|
30
|
-
console.warn("Warning: Could not load config file, using defaults");
|
|
31
|
-
}
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Migrate old configuration files to new unified format from version 2.0.5
|
|
37
|
-
*/
|
|
38
|
-
migrateOldConfig() {
|
|
39
|
-
try {
|
|
40
|
-
// Migrate old language file if it exists and no language in config
|
|
41
|
-
if (!this.config.language && fs.existsSync(this.oldLangFile)) {
|
|
42
|
-
const oldLang = fs.readFileSync(this.oldLangFile, "utf8").trim();
|
|
43
|
-
if (oldLang && ["en", "vi"].includes(oldLang)) {
|
|
44
|
-
this.config.language = oldLang;
|
|
45
|
-
this.saveConfig();
|
|
46
|
-
// Optionally delete old file
|
|
47
|
-
try {
|
|
48
|
-
fs.unlinkSync(this.oldLangFile);
|
|
49
|
-
} catch (err) {
|
|
50
|
-
// Ignore if can't delete
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
} catch (error) {
|
|
55
|
-
// Ignore migration errors
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Save configuration to file
|
|
61
|
-
*/
|
|
62
|
-
saveConfig() {
|
|
63
|
-
try {
|
|
64
|
-
// Ensure .nport directory exists
|
|
65
|
-
if (!fs.existsSync(this.configDir)) {
|
|
66
|
-
fs.mkdirSync(this.configDir, { recursive: true });
|
|
67
|
-
}
|
|
68
|
-
fs.writeFileSync(this.configFile, JSON.stringify(this.config, null, 2), "utf8");
|
|
69
|
-
return true;
|
|
70
|
-
} catch (error) {
|
|
71
|
-
console.warn("Warning: Could not save configuration");
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Get backend URL from config
|
|
78
|
-
* @returns {string|null} Saved backend URL or null
|
|
79
|
-
*/
|
|
80
|
-
getBackendUrl() {
|
|
81
|
-
return this.config.backendUrl || null;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Set backend URL in config
|
|
86
|
-
* @param {string} url - Backend URL to save
|
|
87
|
-
* @returns {boolean} Success status
|
|
88
|
-
*/
|
|
89
|
-
setBackendUrl(url) {
|
|
90
|
-
if (!url) {
|
|
91
|
-
delete this.config.backendUrl;
|
|
92
|
-
} else {
|
|
93
|
-
this.config.backendUrl = url;
|
|
94
|
-
}
|
|
95
|
-
return this.saveConfig();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Get language from config
|
|
100
|
-
* @returns {string|null} Saved language code or null
|
|
101
|
-
*/
|
|
102
|
-
getLanguage() {
|
|
103
|
-
return this.config.language || null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Set language in config
|
|
108
|
-
* @param {string} lang - Language code to save (e.g., 'en', 'vi')
|
|
109
|
-
* @returns {boolean} Success status
|
|
110
|
-
*/
|
|
111
|
-
setLanguage(lang) {
|
|
112
|
-
if (!lang) {
|
|
113
|
-
delete this.config.language;
|
|
114
|
-
} else {
|
|
115
|
-
this.config.language = lang;
|
|
116
|
-
}
|
|
117
|
-
return this.saveConfig();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Get all configuration
|
|
122
|
-
* @returns {object} All configuration
|
|
123
|
-
*/
|
|
124
|
-
getAll() {
|
|
125
|
-
return { ...this.config };
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Clear all configuration
|
|
130
|
-
* @returns {boolean} Success status
|
|
131
|
-
*/
|
|
132
|
-
clear() {
|
|
133
|
-
this.config = {};
|
|
134
|
-
return this.saveConfig();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Export singleton instance
|
|
139
|
-
export const configManager = new ConfigManager();
|