@luxmargos/ensure-hosts 0.1.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/README.md +285 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +144 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.js +274 -0
- package/dist/config.js.map +1 -0
- package/dist/domain-map.d.ts +4 -0
- package/dist/domain-map.js +73 -0
- package/dist/domain-map.js.map +1 -0
- package/dist/hosts.d.ts +30 -0
- package/dist/hosts.js +220 -0
- package/dist/hosts.js.map +1 -0
- package/dist/platform.d.ts +30 -0
- package/dist/platform.js +212 -0
- package/dist/platform.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { delimiter, resolve } from 'node:path';
|
|
3
|
+
import { config as loadDotenv } from 'dotenv';
|
|
4
|
+
import { parse as parseYaml } from 'yaml';
|
|
5
|
+
const DEFAULT_ENV_FILE = '.env';
|
|
6
|
+
export function parseCliOptions(argv) {
|
|
7
|
+
const options = {
|
|
8
|
+
configPaths: [],
|
|
9
|
+
envFile: DEFAULT_ENV_FILE,
|
|
10
|
+
envFileExplicit: false,
|
|
11
|
+
dryRun: false,
|
|
12
|
+
printRecords: false,
|
|
13
|
+
remove: false,
|
|
14
|
+
removeForce: false,
|
|
15
|
+
noElevate: false,
|
|
16
|
+
elevated: false,
|
|
17
|
+
};
|
|
18
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
19
|
+
const arg = argv[index];
|
|
20
|
+
if (arg === '--help' || arg === '-h') {
|
|
21
|
+
printHelpAndExit(0);
|
|
22
|
+
}
|
|
23
|
+
if (arg === '--version' || arg === '-v') {
|
|
24
|
+
printVersionAndExit();
|
|
25
|
+
}
|
|
26
|
+
if (arg === '--config') {
|
|
27
|
+
options.configPaths.push(requireValue(argv, ++index, '--config'));
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (arg.startsWith('--config=')) {
|
|
31
|
+
options.configPaths.push(arg.slice('--config='.length));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (arg === '--env-file') {
|
|
35
|
+
options.envFile = requireValue(argv, ++index, '--env-file');
|
|
36
|
+
options.envFileExplicit = true;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (arg.startsWith('--env-file=')) {
|
|
40
|
+
options.envFile = arg.slice('--env-file='.length);
|
|
41
|
+
options.envFileExplicit = true;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (arg === '--hosts-file') {
|
|
45
|
+
options.hostsFile = requireValue(argv, ++index, '--hosts-file');
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (arg.startsWith('--hosts-file=')) {
|
|
49
|
+
options.hostsFile = arg.slice('--hosts-file='.length);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (arg === '--output-file') {
|
|
53
|
+
options.outputFile = requireValue(argv, ++index, '--output-file');
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (arg.startsWith('--output-file=')) {
|
|
57
|
+
options.outputFile = arg.slice('--output-file='.length);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (arg === '--dry-run') {
|
|
61
|
+
options.dryRun = true;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (arg === '--print-records') {
|
|
65
|
+
options.printRecords = true;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (arg === '--remove') {
|
|
69
|
+
options.remove = true;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (arg === '--remove-force') {
|
|
73
|
+
options.removeForce = true;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (arg === '--no-elevate') {
|
|
77
|
+
options.noElevate = true;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (arg === '--elevated') {
|
|
81
|
+
options.elevated = true;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`Unknown option: ${arg}\n\n${usage()}`);
|
|
85
|
+
}
|
|
86
|
+
assertCompatibleModes(options);
|
|
87
|
+
return options;
|
|
88
|
+
}
|
|
89
|
+
function assertCompatibleModes(options) {
|
|
90
|
+
if (options.remove && options.removeForce) {
|
|
91
|
+
throw new Error(`--remove and --remove-force cannot be used together.\n\n${usage()}`);
|
|
92
|
+
}
|
|
93
|
+
if ((options.remove || options.removeForce) && options.printRecords) {
|
|
94
|
+
throw new Error(`--print-records cannot be combined with --remove or --remove-force.\n\n${usage()}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
export function loadDefaultEnv(envFile) {
|
|
98
|
+
const resolved = resolve(envFile);
|
|
99
|
+
if (!existsSync(resolved)) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
loadDotenv({ path: resolved, override: false });
|
|
103
|
+
}
|
|
104
|
+
export function resolveConfigPaths(options, env = process.env) {
|
|
105
|
+
if (options.configPaths.length > 0) {
|
|
106
|
+
return options.configPaths.map(path => resolve(path));
|
|
107
|
+
}
|
|
108
|
+
const fromEnv = env.ENSURE_HOSTS_CONFIG?.trim();
|
|
109
|
+
if (!fromEnv) {
|
|
110
|
+
throw new Error(`No config file provided. Use --config <path> or set ENSURE_HOSTS_CONFIG.\n\n${usage()}`);
|
|
111
|
+
}
|
|
112
|
+
return splitPathList(fromEnv).map(path => resolve(path));
|
|
113
|
+
}
|
|
114
|
+
export function resolveHostsFileOverride(options, env = process.env) {
|
|
115
|
+
return options.hostsFile ?? env.ENSURE_HOSTS_HOSTS_FILE;
|
|
116
|
+
}
|
|
117
|
+
export function resolveNoElevate(options, env = process.env) {
|
|
118
|
+
return options.noElevate || parseBooleanEnv(env.ENSURE_HOSTS_NO_ELEVATE);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Rebuild the CLI args for an elevated child process from already-resolved
|
|
122
|
+
* (absolute) paths. The elevated re-spawn runs in a different working
|
|
123
|
+
* directory than the parent (osascript's `do shell script` starts in `/`),
|
|
124
|
+
* so any relative path the user passed would fail to resolve in the child.
|
|
125
|
+
* Passing absolute paths fixes that without changing the public CLI surface.
|
|
126
|
+
*
|
|
127
|
+
* Elevation-only flags (`--no-elevate`, `--elevated`) and `--output-file`
|
|
128
|
+
* (Windows elevated-output plumbing) are intentionally omitted: the child is
|
|
129
|
+
* re-elevated/redirected by the elevation layer itself, not by these flags.
|
|
130
|
+
*/
|
|
131
|
+
export function buildElevationArgs(options, configPaths) {
|
|
132
|
+
const args = [];
|
|
133
|
+
for (const configPath of configPaths) {
|
|
134
|
+
args.push('--config', resolve(configPath));
|
|
135
|
+
}
|
|
136
|
+
// Only forward --env-file when the user explicitly set it. Node 20.6+ treats
|
|
137
|
+
// --env-file as its own flag (even after the script path) and exits with an
|
|
138
|
+
// error if the file is missing, so emitting it unconditionally would crash
|
|
139
|
+
// the elevated child whenever the default .env is absent.
|
|
140
|
+
if (options.envFileExplicit) {
|
|
141
|
+
args.push('--env-file', resolve(options.envFile));
|
|
142
|
+
}
|
|
143
|
+
if (options.hostsFile) {
|
|
144
|
+
args.push('--hosts-file', resolve(options.hostsFile));
|
|
145
|
+
}
|
|
146
|
+
if (options.dryRun) {
|
|
147
|
+
args.push('--dry-run');
|
|
148
|
+
}
|
|
149
|
+
if (options.printRecords) {
|
|
150
|
+
args.push('--print-records');
|
|
151
|
+
}
|
|
152
|
+
if (options.remove) {
|
|
153
|
+
args.push('--remove');
|
|
154
|
+
}
|
|
155
|
+
if (options.removeForce) {
|
|
156
|
+
args.push('--remove-force');
|
|
157
|
+
}
|
|
158
|
+
return args;
|
|
159
|
+
}
|
|
160
|
+
export function loadProfiles(configPaths) {
|
|
161
|
+
return configPaths.map(loadProfile);
|
|
162
|
+
}
|
|
163
|
+
export function loadProfile(configPath) {
|
|
164
|
+
if (!/\.ya?ml$/i.test(configPath)) {
|
|
165
|
+
throw new Error(`Config file must be .yaml or .yml: ${configPath}`);
|
|
166
|
+
}
|
|
167
|
+
const content = readFileSync(configPath, 'utf8');
|
|
168
|
+
const parsed = parseYaml(content);
|
|
169
|
+
return normalizeProfile(parsed, configPath);
|
|
170
|
+
}
|
|
171
|
+
function normalizeProfile(value, configPath) {
|
|
172
|
+
if (!isRecord(value)) {
|
|
173
|
+
throw new Error(`Config must be a YAML object: ${configPath}`);
|
|
174
|
+
}
|
|
175
|
+
const profile = requireString(value.profile, 'profile', configPath);
|
|
176
|
+
const hostsValue = value.hosts;
|
|
177
|
+
if (!Array.isArray(hostsValue)) {
|
|
178
|
+
throw new Error(`Config field "hosts" must be an array: ${configPath}`);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
profile,
|
|
182
|
+
hosts: hostsValue.map((host, index) => normalizeHostNode(host, `${configPath}:hosts[${index}]`)),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function normalizeHostNode(value, location) {
|
|
186
|
+
if (typeof value === 'string') {
|
|
187
|
+
return { domain: value };
|
|
188
|
+
}
|
|
189
|
+
if (!isRecord(value)) {
|
|
190
|
+
throw new Error(`Host entry must be an object or string: ${location}`);
|
|
191
|
+
}
|
|
192
|
+
const domain = requireString(value.domain, 'domain', location);
|
|
193
|
+
const node = { domain };
|
|
194
|
+
if (value.address !== undefined) {
|
|
195
|
+
node.address = requireString(value.address, 'address', location);
|
|
196
|
+
}
|
|
197
|
+
if (value.rewrite !== undefined) {
|
|
198
|
+
node.rewrite = requireBoolean(value.rewrite, 'rewrite', location);
|
|
199
|
+
}
|
|
200
|
+
if (value.skipSelf !== undefined) {
|
|
201
|
+
node.skipSelf = requireBoolean(value.skipSelf, 'skipSelf', location);
|
|
202
|
+
}
|
|
203
|
+
if (value.children !== undefined) {
|
|
204
|
+
if (!Array.isArray(value.children)) {
|
|
205
|
+
throw new Error(`Field "children" must be an array: ${location}`);
|
|
206
|
+
}
|
|
207
|
+
node.children = value.children.map((child, index) => normalizeHostNode(child, `${location}.children[${index}]`));
|
|
208
|
+
}
|
|
209
|
+
return node;
|
|
210
|
+
}
|
|
211
|
+
function splitPathList(value) {
|
|
212
|
+
return value
|
|
213
|
+
.split(/[,\n]/g)
|
|
214
|
+
.flatMap(part => part.split(delimiter))
|
|
215
|
+
.map(part => part.trim())
|
|
216
|
+
.filter(Boolean);
|
|
217
|
+
}
|
|
218
|
+
function requireValue(argv, index, option) {
|
|
219
|
+
const value = argv[index];
|
|
220
|
+
if (!value || value.startsWith('--')) {
|
|
221
|
+
throw new Error(`${option} requires a value.`);
|
|
222
|
+
}
|
|
223
|
+
return value;
|
|
224
|
+
}
|
|
225
|
+
function requireString(value, field, location) {
|
|
226
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
227
|
+
throw new Error(`Field "${field}" must be a non-empty string: ${location}`);
|
|
228
|
+
}
|
|
229
|
+
return value.trim();
|
|
230
|
+
}
|
|
231
|
+
function requireBoolean(value, field, location) {
|
|
232
|
+
if (typeof value !== 'boolean') {
|
|
233
|
+
throw new Error(`Field "${field}" must be a boolean: ${location}`);
|
|
234
|
+
}
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
function parseBooleanEnv(value) {
|
|
238
|
+
if (!value) {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
|
242
|
+
}
|
|
243
|
+
function isRecord(value) {
|
|
244
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
245
|
+
}
|
|
246
|
+
function printHelpAndExit(code) {
|
|
247
|
+
console.log(usage());
|
|
248
|
+
process.exit(code);
|
|
249
|
+
}
|
|
250
|
+
function printVersionAndExit() {
|
|
251
|
+
console.log('0.1.0');
|
|
252
|
+
process.exit(0);
|
|
253
|
+
}
|
|
254
|
+
export function usage() {
|
|
255
|
+
return [
|
|
256
|
+
'Usage: ensure-hosts --config <path> [--config <path> ...] [options]',
|
|
257
|
+
'',
|
|
258
|
+
'Options:',
|
|
259
|
+
' --config <path> YAML/YML config file path (repeatable)',
|
|
260
|
+
' --env-file <path> dotenv file path (default: .env)',
|
|
261
|
+
' --hosts-file <path> override hosts file path',
|
|
262
|
+
' --dry-run print rewritten hosts content without writing',
|
|
263
|
+
' --print-records print expanded records and exit',
|
|
264
|
+
' --remove remove rewrite:true domains (respects rewrite:false)',
|
|
265
|
+
' --remove-force remove all listed domains, including rewrite:false',
|
|
266
|
+
' --no-elevate disable macOS/Windows privilege prompt',
|
|
267
|
+
' --help show help',
|
|
268
|
+
' --version show version',
|
|
269
|
+
'',
|
|
270
|
+
'--remove and --remove-force are mutually exclusive and cannot be combined',
|
|
271
|
+
'with --print-records.',
|
|
272
|
+
].join('\n');
|
|
273
|
+
}
|
|
274
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ExpandedProfile, ProfileConfig } from './types.js';
|
|
2
|
+
export declare function expandProfiles(profiles: ProfileConfig[]): ExpandedProfile[];
|
|
3
|
+
export declare function expandProfile(profile: ProfileConfig): ExpandedProfile;
|
|
4
|
+
export declare function composeDomain(domain: string, parentDomain?: string): string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { isIP } from 'node:net';
|
|
2
|
+
export function expandProfiles(profiles) {
|
|
3
|
+
return profiles.map(expandProfile);
|
|
4
|
+
}
|
|
5
|
+
export function expandProfile(profile) {
|
|
6
|
+
const output = {
|
|
7
|
+
profile: profile.profile,
|
|
8
|
+
records: [],
|
|
9
|
+
cleanupDomains: new Set(),
|
|
10
|
+
};
|
|
11
|
+
for (const host of profile.hosts) {
|
|
12
|
+
expandNode(host, {
|
|
13
|
+
profile: profile.profile,
|
|
14
|
+
parentRewrite: true,
|
|
15
|
+
}, output);
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
profile: output.profile,
|
|
19
|
+
records: output.records,
|
|
20
|
+
cleanupDomains: [...output.cleanupDomains],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function expandNode(node, context, output) {
|
|
24
|
+
const domain = composeDomain(node.domain, context.parentDomain);
|
|
25
|
+
const address = normalizeOptionalString(node.address) ?? context.parentAddress;
|
|
26
|
+
const rewrite = node.rewrite ?? context.parentRewrite ?? true;
|
|
27
|
+
const skipSelf = node.skipSelf ?? false;
|
|
28
|
+
if (rewrite) {
|
|
29
|
+
output.cleanupDomains.add(domain);
|
|
30
|
+
}
|
|
31
|
+
if (!skipSelf && address) {
|
|
32
|
+
assertIpAddress(address, domain);
|
|
33
|
+
output.records.push({
|
|
34
|
+
profile: context.profile,
|
|
35
|
+
domain,
|
|
36
|
+
address,
|
|
37
|
+
rewrite,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
for (const child of node.children ?? []) {
|
|
41
|
+
const childNode = typeof child === 'string' ? { domain: child } : child;
|
|
42
|
+
expandNode(childNode, {
|
|
43
|
+
profile: context.profile,
|
|
44
|
+
parentDomain: domain,
|
|
45
|
+
parentAddress: address,
|
|
46
|
+
parentRewrite: rewrite,
|
|
47
|
+
}, output);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function composeDomain(domain, parentDomain) {
|
|
51
|
+
const normalized = domain.trim().replace(/^\.+|\.+$/g, '').toLowerCase();
|
|
52
|
+
if (!normalized) {
|
|
53
|
+
throw new Error('Domain must not be empty.');
|
|
54
|
+
}
|
|
55
|
+
if (!parentDomain) {
|
|
56
|
+
return normalized;
|
|
57
|
+
}
|
|
58
|
+
const normalizedParent = parentDomain.trim().replace(/^\.+|\.+$/g, '').toLowerCase();
|
|
59
|
+
if (normalized === normalizedParent || normalized.endsWith(`.${normalizedParent}`)) {
|
|
60
|
+
return normalized;
|
|
61
|
+
}
|
|
62
|
+
return `${normalized}.${normalizedParent}`;
|
|
63
|
+
}
|
|
64
|
+
function normalizeOptionalString(value) {
|
|
65
|
+
const normalized = value?.trim();
|
|
66
|
+
return normalized ? normalized : undefined;
|
|
67
|
+
}
|
|
68
|
+
function assertIpAddress(address, domain) {
|
|
69
|
+
if (isIP(address) === 0) {
|
|
70
|
+
throw new Error(`Invalid IP address for ${domain}: ${address}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=domain-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-map.js","sourceRoot":"","sources":["../src/domain-map.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAgBhC,MAAM,UAAU,cAAc,CAAC,QAAyB;IACtD,OAAO,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAsB;IAClD,MAAM,MAAM,GAA2B;QACrC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,EAAE;QACX,cAAc,EAAE,IAAI,GAAG,EAAU;KAClC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACjC,UAAU,CAAC,IAAI,EAAE;YACf,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,aAAa,EAAE,IAAI;SACpB,EAAE,MAAM,CAAC,CAAC;IACb,CAAC;IAED,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,cAAc,EAAE,CAAC,GAAG,MAAM,CAAC,cAAc,CAAC;KAC3C,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CACjB,IAAoB,EACpB,OAAsB,EACtB,MAA8B;IAE9B,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,aAAa,CAAC;IAC/E,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,aAAa,IAAI,IAAI,CAAC;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;IAExC,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,OAAO,EAAE,CAAC;QACzB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACjC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;YAClB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,MAAM;YACN,OAAO;YACP,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACxE,UAAU,CACR,SAAS,EACT;YACE,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,YAAY,EAAE,MAAM;YACpB,aAAa,EAAE,OAAO;YACtB,aAAa,EAAE,OAAO;SACvB,EACD,MAAM,CACP,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,YAAqB;IACjE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACzE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,MAAM,gBAAgB,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACrF,IAAI,UAAU,KAAK,gBAAgB,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,gBAAgB,EAAE,CAAC,EAAE,CAAC;QACnF,OAAO,UAAU,CAAC;IACpB,CAAC;IACD,OAAO,GAAG,UAAU,IAAI,gBAAgB,EAAE,CAAC;AAC7C,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAyB;IACxD,MAAM,UAAU,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC;AAED,SAAS,eAAe,CAAC,OAAe,EAAE,MAAc;IACtD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
|
package/dist/hosts.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ExpandedProfile, HostRecord } from './types.js';
|
|
2
|
+
export interface RewriteResult {
|
|
3
|
+
content: string;
|
|
4
|
+
appended: HostRecord[];
|
|
5
|
+
removedDomains: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface RemoveResult {
|
|
8
|
+
content: string;
|
|
9
|
+
removedDomains: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare function rewriteHostsContent(content: string, profiles: ExpandedProfile[]): RewriteResult;
|
|
12
|
+
/**
|
|
13
|
+
* Remove the domains managed by the given profiles from the hosts content,
|
|
14
|
+
* without appending anything. This is the inverse of the default ensure
|
|
15
|
+
* action: run the cleanup phase only.
|
|
16
|
+
*
|
|
17
|
+
* `force: false` (the `--remove` flag) strips only `cleanupDomains` — the
|
|
18
|
+
* domains declared `rewrite: true`. Domains declared `rewrite: false` are
|
|
19
|
+
* left untouched, matching their "do not alter existing entries" contract.
|
|
20
|
+
*
|
|
21
|
+
* `force: true` (the `--remove-force` flag) additionally strips every domain
|
|
22
|
+
* the profiles would write (`record.domain`), including `rewrite: false`
|
|
23
|
+
* entries.
|
|
24
|
+
*/
|
|
25
|
+
export declare function removeHostsContent(content: string, profiles: ExpandedProfile[], options: {
|
|
26
|
+
force: boolean;
|
|
27
|
+
}): RemoveResult;
|
|
28
|
+
export declare function selectRecordsToAppend(lines: string[], profiles: ExpandedProfile[]): HostRecord[];
|
|
29
|
+
export declare function collectDomainsFromContent(content: string): Set<string>;
|
|
30
|
+
export declare function collectDomainsFromLines(lines: string[]): Set<string>;
|
package/dist/hosts.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
export function rewriteHostsContent(content, profiles) {
|
|
2
|
+
const eol = detectEol(content);
|
|
3
|
+
const hadFinalEol = content.endsWith('\n') || content.endsWith('\r\n');
|
|
4
|
+
const sourceLines = splitLines(content);
|
|
5
|
+
const cleanupDomains = new Set(profiles.flatMap(profile => profile.cleanupDomains));
|
|
6
|
+
const profileNames = new Set(profiles.map(profile => profile.profile));
|
|
7
|
+
const { lines: cleanedLines, removedDomains } = cleanupHostsLines(sourceLines, cleanupDomains, profileNames);
|
|
8
|
+
const compactedLines = compactBlankRuns(cleanedLines);
|
|
9
|
+
const appended = selectRecordsToAppend(compactedLines, profiles);
|
|
10
|
+
const nextLines = [...trimTrailingBlankLines(compactedLines)];
|
|
11
|
+
if (appended.length > 0) {
|
|
12
|
+
if (nextLines.length > 0) {
|
|
13
|
+
nextLines.push('');
|
|
14
|
+
}
|
|
15
|
+
for (const record of appended) {
|
|
16
|
+
nextLines.push(`# ${record.profile}`);
|
|
17
|
+
nextLines.push(`${record.address} ${record.domain}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const contentBody = nextLines.join(eol);
|
|
21
|
+
const nextContent = contentBody.length > 0 ? `${contentBody}${eol}` : hadFinalEol ? eol : '';
|
|
22
|
+
return {
|
|
23
|
+
content: nextContent,
|
|
24
|
+
appended,
|
|
25
|
+
removedDomains: [...removedDomains],
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Remove the domains managed by the given profiles from the hosts content,
|
|
30
|
+
* without appending anything. This is the inverse of the default ensure
|
|
31
|
+
* action: run the cleanup phase only.
|
|
32
|
+
*
|
|
33
|
+
* `force: false` (the `--remove` flag) strips only `cleanupDomains` — the
|
|
34
|
+
* domains declared `rewrite: true`. Domains declared `rewrite: false` are
|
|
35
|
+
* left untouched, matching their "do not alter existing entries" contract.
|
|
36
|
+
*
|
|
37
|
+
* `force: true` (the `--remove-force` flag) additionally strips every domain
|
|
38
|
+
* the profiles would write (`record.domain`), including `rewrite: false`
|
|
39
|
+
* entries.
|
|
40
|
+
*/
|
|
41
|
+
export function removeHostsContent(content, profiles, options) {
|
|
42
|
+
const eol = detectEol(content);
|
|
43
|
+
const hadFinalEol = content.endsWith('\n') || content.endsWith('\r\n');
|
|
44
|
+
const sourceLines = splitLines(content);
|
|
45
|
+
const removeDomains = new Set(profiles.flatMap(profile => profile.cleanupDomains));
|
|
46
|
+
if (options.force) {
|
|
47
|
+
for (const profile of profiles) {
|
|
48
|
+
for (const record of profile.records) {
|
|
49
|
+
removeDomains.add(record.domain);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const profileNames = new Set(profiles.map(profile => profile.profile));
|
|
54
|
+
const { lines: cleanedLines, removedDomains } = cleanupHostsLines(sourceLines, removeDomains, profileNames);
|
|
55
|
+
const compactedLines = compactBlankRuns(cleanedLines);
|
|
56
|
+
const nextLines = [...trimTrailingBlankLines(compactedLines)];
|
|
57
|
+
const contentBody = nextLines.join(eol);
|
|
58
|
+
const nextContent = contentBody.length > 0 ? `${contentBody}${eol}` : hadFinalEol ? eol : '';
|
|
59
|
+
return {
|
|
60
|
+
content: nextContent,
|
|
61
|
+
removedDomains: [...removedDomains],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Run the shared line-cleanup pass used by both ensure (rewrite) and remove.
|
|
66
|
+
* Strips tokens in `cleanupDomains` from each line via `cleanHostsLine`,
|
|
67
|
+
* drops orphaned `# <profile>` managed comments that precede a removed line,
|
|
68
|
+
* and returns the surviving lines plus the set of domains actually removed.
|
|
69
|
+
* Does not compact blank runs or append anything — callers do that.
|
|
70
|
+
*/
|
|
71
|
+
function cleanupHostsLines(sourceLines, cleanupDomains, profileNames) {
|
|
72
|
+
const cleanedLines = [];
|
|
73
|
+
const removedDomains = new Set();
|
|
74
|
+
let pendingManagedComments = [];
|
|
75
|
+
for (const line of sourceLines) {
|
|
76
|
+
if (isManagedProfileComment(line, profileNames)) {
|
|
77
|
+
pendingManagedComments.push(line);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const cleaned = cleanHostsLine(line, cleanupDomains);
|
|
81
|
+
for (const domain of cleaned.removedDomains) {
|
|
82
|
+
removedDomains.add(domain);
|
|
83
|
+
}
|
|
84
|
+
if (cleaned.changed) {
|
|
85
|
+
pendingManagedComments = [];
|
|
86
|
+
}
|
|
87
|
+
else if (pendingManagedComments.length > 0) {
|
|
88
|
+
cleanedLines.push(...pendingManagedComments);
|
|
89
|
+
pendingManagedComments = [];
|
|
90
|
+
}
|
|
91
|
+
if (cleaned.line !== null) {
|
|
92
|
+
cleanedLines.push(cleaned.line);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (pendingManagedComments.length > 0) {
|
|
96
|
+
cleanedLines.push(...pendingManagedComments);
|
|
97
|
+
}
|
|
98
|
+
return { lines: cleanedLines, removedDomains };
|
|
99
|
+
}
|
|
100
|
+
export function selectRecordsToAppend(lines, profiles) {
|
|
101
|
+
const existingDomains = collectDomainsFromLines(lines);
|
|
102
|
+
const records = profiles.flatMap(profile => profile.records);
|
|
103
|
+
const appended = [];
|
|
104
|
+
for (const record of records) {
|
|
105
|
+
if (!record.rewrite && existingDomains.has(record.domain)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
appended.push(record);
|
|
109
|
+
existingDomains.add(record.domain);
|
|
110
|
+
}
|
|
111
|
+
return appended;
|
|
112
|
+
}
|
|
113
|
+
export function collectDomainsFromContent(content) {
|
|
114
|
+
return collectDomainsFromLines(splitLines(content));
|
|
115
|
+
}
|
|
116
|
+
export function collectDomainsFromLines(lines) {
|
|
117
|
+
const domains = new Set();
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
const body = stripInlineComment(line).trim();
|
|
120
|
+
if (!body) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const [, ...hosts] = body.split(/\s+/);
|
|
124
|
+
for (const host of hosts) {
|
|
125
|
+
domains.add(host.toLowerCase());
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return domains;
|
|
129
|
+
}
|
|
130
|
+
function cleanHostsLine(line, cleanupDomains) {
|
|
131
|
+
if (cleanupDomains.size === 0) {
|
|
132
|
+
return { line, changed: false, removedDomains: [] };
|
|
133
|
+
}
|
|
134
|
+
const { body, comment } = splitInlineComment(line);
|
|
135
|
+
const leading = body.match(/^\s*/)?.[0] ?? '';
|
|
136
|
+
const tokens = body.trim().split(/\s+/).filter(Boolean);
|
|
137
|
+
if (tokens.length === 0) {
|
|
138
|
+
return { line, changed: false, removedDomains: [] };
|
|
139
|
+
}
|
|
140
|
+
const [address, ...hosts] = tokens;
|
|
141
|
+
if (hosts.length === 0) {
|
|
142
|
+
return { line, changed: false, removedDomains: [] };
|
|
143
|
+
}
|
|
144
|
+
const removedDomains = [];
|
|
145
|
+
const remainingHosts = hosts.filter(host => {
|
|
146
|
+
const shouldRemove = cleanupDomains.has(host.toLowerCase());
|
|
147
|
+
if (shouldRemove) {
|
|
148
|
+
removedDomains.push(host.toLowerCase());
|
|
149
|
+
}
|
|
150
|
+
return !shouldRemove;
|
|
151
|
+
});
|
|
152
|
+
if (removedDomains.length === 0) {
|
|
153
|
+
return { line, changed: false, removedDomains: [] };
|
|
154
|
+
}
|
|
155
|
+
if (remainingHosts.length === 0) {
|
|
156
|
+
const keptComment = comment.trim();
|
|
157
|
+
return {
|
|
158
|
+
line: keptComment ? keptComment : null,
|
|
159
|
+
changed: true,
|
|
160
|
+
removedDomains,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
const nextBody = `${leading}${[address, ...remainingHosts].join('\t')}`;
|
|
164
|
+
return {
|
|
165
|
+
line: comment ? `${nextBody} ${comment}` : nextBody,
|
|
166
|
+
changed: true,
|
|
167
|
+
removedDomains,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function isManagedProfileComment(line, profileNames) {
|
|
171
|
+
const trimmed = line.trim();
|
|
172
|
+
if (!trimmed.startsWith('#')) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const label = trimmed.slice(1).trim();
|
|
176
|
+
return profileNames.has(label);
|
|
177
|
+
}
|
|
178
|
+
function splitInlineComment(line) {
|
|
179
|
+
const index = line.indexOf('#');
|
|
180
|
+
if (index === -1) {
|
|
181
|
+
return { body: line, comment: '' };
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
body: line.slice(0, index),
|
|
185
|
+
comment: line.slice(index),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function stripInlineComment(line) {
|
|
189
|
+
return splitInlineComment(line).body;
|
|
190
|
+
}
|
|
191
|
+
function splitLines(content) {
|
|
192
|
+
if (content.length === 0) {
|
|
193
|
+
return [];
|
|
194
|
+
}
|
|
195
|
+
return content.replace(/\r?\n$/, '').split(/\r?\n/);
|
|
196
|
+
}
|
|
197
|
+
function trimTrailingBlankLines(lines) {
|
|
198
|
+
const output = [...lines];
|
|
199
|
+
while (output.length > 0 && output[output.length - 1]?.trim() === '') {
|
|
200
|
+
output.pop();
|
|
201
|
+
}
|
|
202
|
+
return output;
|
|
203
|
+
}
|
|
204
|
+
function compactBlankRuns(lines) {
|
|
205
|
+
const output = [];
|
|
206
|
+
let previousBlank = false;
|
|
207
|
+
for (const line of lines) {
|
|
208
|
+
const blank = line.trim() === '';
|
|
209
|
+
if (blank && previousBlank) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
output.push(line);
|
|
213
|
+
previousBlank = blank;
|
|
214
|
+
}
|
|
215
|
+
return output;
|
|
216
|
+
}
|
|
217
|
+
function detectEol(content) {
|
|
218
|
+
return content.includes('\r\n') ? '\r\n' : '\n';
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=hosts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hosts.js","sourceRoot":"","sources":["../src/hosts.ts"],"names":[],"mappings":"AAmBA,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,QAA2B;IAC9E,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,iBAAiB,CAAC,WAAW,EAAE,cAAc,EAAE,YAAY,CAAC,CAAC;IAC7G,MAAM,cAAc,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,CAAC,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC,CAAC;IAE9D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;QACD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC9B,SAAS,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YACtC,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAE7F,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,QAAQ;QACR,cAAc,EAAE,CAAC,GAAG,cAAc,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAe,EACf,QAA2B,EAC3B,OAA2B;IAE3B,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvE,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAExC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IACnF,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACrC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAEvE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,GAAG,iBAAiB,CAAC,WAAW,EAAE,aAAa,EAAE,YAAY,CAAC,CAAC;IAC5G,MAAM,cAAc,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,CAAC,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC,CAAC;IAE9D,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAE7F,OAAO;QACL,OAAO,EAAE,WAAW;QACpB,cAAc,EAAE,CAAC,GAAG,cAAc,CAAC;KACpC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CACxB,WAAqB,EACrB,cAA2B,EAC3B,YAAyB;IAEzB,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;IACzC,IAAI,sBAAsB,GAAa,EAAE,CAAC;IAE1C,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,uBAAuB,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,CAAC;YAChD,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QACrD,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;YAC5C,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;QAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,sBAAsB,GAAG,EAAE,CAAC;QAC9B,CAAC;aAAM,IAAI,sBAAsB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,YAAY,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,CAAC;YAC7C,sBAAsB,GAAG,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC1B,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,IAAI,sBAAsB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,YAAY,CAAC,IAAI,CAAC,GAAG,sBAAsB,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAe,EAAE,QAA2B;IAChF,MAAM,eAAe,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAElC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1D,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtB,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAe;IACvD,OAAO,uBAAuB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,KAAe;IACrD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,SAAS;QACX,CAAC;QACD,MAAM,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,cAA2B;IAC/D,IAAI,cAAc,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QACzC,MAAM,YAAY,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC5D,IAAI,YAAY,EAAE,CAAC;YACjB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,CAAC,YAAY,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;IACtD,CAAC;IAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO;YACL,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI;YACtC,OAAO,EAAE,IAAI;YACb,cAAc;SACf,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,OAAO,GAAG,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACxE,OAAO;QACL,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,QAAQ;QACnD,OAAO,EAAE,IAAI;QACb,cAAc;KACf,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAY,EAAE,YAAyB;IACtE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,OAAO,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACrC,CAAC;IACD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;QAC1B,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;KAC3B,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACtC,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;AACvC,CAAC;AAED,SAAS,UAAU,CAAC,OAAe;IACjC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAe;IAC7C,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1B,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACrE,MAAM,CAAC,GAAG,EAAE,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAe;IACvC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QACjC,IAAI,KAAK,IAAI,aAAa,EAAE,CAAC;YAC3B,SAAS;QACX,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,aAAa,GAAG,KAAK,CAAC;IACxB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,OAAe;IAChC,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare function resolveDefaultHostsPath(currentPlatform?: NodeJS.Platform, env?: NodeJS.ProcessEnv): string;
|
|
2
|
+
export type ElevationResult = false | 'written' | 'spawned';
|
|
3
|
+
export interface ElevationOptions {
|
|
4
|
+
scriptPath: string;
|
|
5
|
+
args: string[];
|
|
6
|
+
cwd: string;
|
|
7
|
+
noElevate: boolean;
|
|
8
|
+
elevated: boolean;
|
|
9
|
+
dryRun: boolean;
|
|
10
|
+
printRecords: boolean;
|
|
11
|
+
filePath: string;
|
|
12
|
+
content: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function tryElevate(options: ElevationOptions): ElevationResult;
|
|
15
|
+
/**
|
|
16
|
+
* Returns true when an elevation attempt succeeded and the caller should
|
|
17
|
+
* exit cleanly (no Permission denied error). Any truthy ElevationResult
|
|
18
|
+
* (`'written'` from sudo tee / already-root, or `'spawned'` from the
|
|
19
|
+
* osascript/Windows GUI re-spawn) counts as success. `false` means no
|
|
20
|
+
* elevation happened and the caller should throw the sudo hint.
|
|
21
|
+
*/
|
|
22
|
+
export declare function elevationHandled(elevated: ElevationResult): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Prints a notification when the process is running as root (uid 0),
|
|
25
|
+
* so the user knows the hosts file will be written directly without
|
|
26
|
+
* any elevation prompt. Called before the direct writeFileSync in cli.ts.
|
|
27
|
+
*/
|
|
28
|
+
export declare function notifyRootWrite(filePath: string): void;
|
|
29
|
+
export declare function elevatedCommandHint(command?: string): string;
|
|
30
|
+
export declare function withoutElevationArgs(args: string[]): string[];
|