ntfy-reverse-proxy 0.0.0 → 2.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.
- package/README.md +48 -0
- package/build/src/cli/commands/config-io.d.ts +5 -0
- package/build/src/cli/commands/config-io.d.ts.map +1 -0
- package/build/src/cli/commands/config-io.js +19 -0
- package/build/src/cli/commands/config-io.js.map +1 -0
- package/build/src/cli/commands/context.d.ts +9 -0
- package/build/src/cli/commands/context.d.ts.map +1 -0
- package/build/src/cli/commands/context.js +108 -0
- package/build/src/cli/commands/context.js.map +1 -0
- package/build/src/cli/commands/deploy.d.ts +4 -0
- package/build/src/cli/commands/deploy.d.ts.map +1 -0
- package/build/src/cli/commands/deploy.js +496 -0
- package/build/src/cli/commands/deploy.js.map +1 -0
- package/build/src/cli/commands/generate.d.ts +4 -0
- package/build/src/cli/commands/generate.d.ts.map +1 -0
- package/build/src/cli/commands/generate.js +68 -0
- package/build/src/cli/commands/generate.js.map +1 -0
- package/build/src/cli/commands/server.d.ts +7 -0
- package/build/src/cli/commands/server.d.ts.map +1 -0
- package/build/src/cli/commands/server.js +43 -0
- package/build/src/cli/commands/server.js.map +1 -0
- package/build/src/cli/commands/settings.d.ts +5 -0
- package/build/src/cli/commands/settings.d.ts.map +1 -0
- package/build/src/cli/commands/settings.js +16 -0
- package/build/src/cli/commands/settings.js.map +1 -0
- package/build/src/cli/commands/validate.d.ts +4 -0
- package/build/src/cli/commands/validate.d.ts.map +1 -0
- package/build/src/cli/commands/validate.js +45 -0
- package/build/src/cli/commands/validate.js.map +1 -0
- package/build/src/cli/index.d.ts +5 -0
- package/build/src/cli/index.d.ts.map +1 -0
- package/build/src/cli/index.js +118 -0
- package/build/src/cli/index.js.map +1 -0
- package/build/src/cli/menu/interactive.d.ts +4 -0
- package/build/src/cli/menu/interactive.d.ts.map +1 -0
- package/build/src/cli/menu/interactive.js +902 -0
- package/build/src/cli/menu/interactive.js.map +1 -0
- package/build/src/lib/item.d.ts +3 -0
- package/build/src/lib/item.d.ts.map +1 -0
- package/build/src/lib/item.js +3 -0
- package/build/src/lib/item.js.map +1 -0
- package/build/src/lib/regex.d.ts +30 -0
- package/build/src/lib/regex.d.ts.map +1 -0
- package/build/src/lib/regex.js +30 -0
- package/build/src/lib/regex.js.map +1 -0
- package/build/src/lib/schema.d.ts +167 -0
- package/build/src/lib/schema.d.ts.map +1 -0
- package/build/src/lib/schema.js +70 -0
- package/build/src/lib/schema.js.map +1 -0
- package/build/src/lib/utility.d.ts +4 -0
- package/build/src/lib/utility.d.ts.map +1 -0
- package/build/src/lib/utility.js +14 -0
- package/build/src/lib/utility.js.map +1 -0
- package/build/src/types/cli/commands/config-io.d.ts +38 -0
- package/build/src/types/cli/commands/context.d.ts +131 -0
- package/build/src/types/cli/commands/deploy.d.ts +622 -0
- package/build/src/types/cli/commands/generate.d.ts +51 -0
- package/build/src/types/cli/commands/server.d.ts +65 -0
- package/build/src/types/cli/commands/settings.d.ts +25 -0
- package/build/src/types/cli/commands/validate.d.ts +37 -0
- package/build/src/types/cli/index.d.ts +55 -0
- package/build/src/types/cli/menu/interactive.d.ts +381 -0
- package/build/src/types/fetch-response.d.ts +11 -0
- package/build/src/types/lib/schema.d.ts +134 -0
- package/build/src/types/lib/utility.d.ts +8 -0
- package/build/src/types/tests/cli/commands/context.test.d.ts +57 -0
- package/build/src/types/tests/cli/commands/generate.test.d.ts +12 -0
- package/build/src/types/tests/cli/commands/server.test.d.ts +45 -0
- package/build/src/types/tests/cli/commands/settings.test.d.ts +40 -0
- package/build/src/types/tests/cli/commands/validate.test.d.ts +19 -0
- package/build/src/types/tests/cli/menu/interactive.test.d.ts +6 -0
- package/build/src/types/tests/lib/schema.test.d.ts +10 -0
- package/build/src/types/tests/type-declarations.test.d.ts +173 -0
- package/build/src/types/tests/worker/index.test.d.ts +20 -0
- package/build/src/types/tests/worker/interpreters/ntfy-json.test.d.ts +19 -0
- package/build/src/types/tests/worker/interpreters/pfsense.test.d.ts +10 -0
- package/build/src/types/tests/worker/interpreters/plain-text.test.d.ts +10 -0
- package/build/src/types/tests/worker/interpreters/seerr.test.d.ts +8 -0
- package/build/src/types/tests/worker/interpreters/statuspage.test.d.ts +58 -0
- package/build/src/types/tests/worker/interpreters/synology.test.d.ts +8 -0
- package/build/src/types/tests/worker/interpreters/unifi.test.d.ts +8 -0
- package/build/src/types/tests/worker/landing/page.test.d.ts +55 -0
- package/build/src/types/tests/worker/pipeline/accumulate.test.d.ts +28 -0
- package/build/src/types/tests/worker/pipeline/authenticate.test.d.ts +9 -0
- package/build/src/types/tests/worker/pipeline/email.test.d.ts +15 -0
- package/build/src/types/tests/worker/pipeline/format.test.d.ts +38 -0
- package/build/src/types/tests/worker/pipeline/interpret.test.d.ts +43 -0
- package/build/src/types/tests/worker/pipeline/parse.test.d.ts +17 -0
- package/build/src/types/tests/worker/pipeline/receive.test.d.ts +23 -0
- package/build/src/types/tests/worker/pipeline/respond.test.d.ts +20 -0
- package/build/src/types/tests/worker/pipeline/route.test.d.ts +80 -0
- package/build/src/types/tests/worker/pipeline/send.test.d.ts +37 -0
- package/build/src/types/tests/worker/pipeline/split.test.d.ts +17 -0
- package/build/src/types/worker/index.d.ts +232 -0
- package/build/src/types/worker/interpreters/ntfy-json.d.ts +28 -0
- package/build/src/types/worker/interpreters/pfsense.d.ts +97 -0
- package/build/src/types/worker/interpreters/plain-text.d.ts +24 -0
- package/build/src/types/worker/interpreters/seerr.d.ts +124 -0
- package/build/src/types/worker/interpreters/statuspage.d.ts +239 -0
- package/build/src/types/worker/interpreters/synology.d.ts +99 -0
- package/build/src/types/worker/interpreters/unifi.d.ts +111 -0
- package/build/src/types/worker/landing/page.d.ts +44 -0
- package/build/src/types/worker/pipeline/accumulate.d.ts +79 -0
- package/build/src/types/worker/pipeline/authenticate.d.ts +68 -0
- package/build/src/types/worker/pipeline/email.d.ts +108 -0
- package/build/src/types/worker/pipeline/format.d.ts +47 -0
- package/build/src/types/worker/pipeline/interpret.d.ts +63 -0
- package/build/src/types/worker/pipeline/parse.d.ts +39 -0
- package/build/src/types/worker/pipeline/receive.d.ts +64 -0
- package/build/src/types/worker/pipeline/respond.d.ts +113 -0
- package/build/src/types/worker/pipeline/route.d.ts +34 -0
- package/build/src/types/worker/pipeline/send.d.ts +143 -0
- package/build/src/types/worker/pipeline/shared.d.ts +85 -0
- package/build/src/types/worker/pipeline/split.d.ts +35 -0
- package/build/src/worker/handlers.d.ts +5 -0
- package/build/src/worker/handlers.d.ts.map +1 -0
- package/build/src/worker/handlers.js +360 -0
- package/build/src/worker/handlers.js.map +1 -0
- package/build/src/worker/index.d.ts +4 -0
- package/build/src/worker/index.d.ts.map +1 -0
- package/build/src/worker/index.js +52 -0
- package/build/src/worker/index.js.map +1 -0
- package/build/src/worker/interpreters/ntfy-json.d.ts +4 -0
- package/build/src/worker/interpreters/ntfy-json.d.ts.map +1 -0
- package/build/src/worker/interpreters/ntfy-json.js +49 -0
- package/build/src/worker/interpreters/ntfy-json.js.map +1 -0
- package/build/src/worker/interpreters/pfsense.d.ts +4 -0
- package/build/src/worker/interpreters/pfsense.d.ts.map +1 -0
- package/build/src/worker/interpreters/pfsense.js +150 -0
- package/build/src/worker/interpreters/pfsense.js.map +1 -0
- package/build/src/worker/interpreters/plain-text.d.ts +4 -0
- package/build/src/worker/interpreters/plain-text.d.ts.map +1 -0
- package/build/src/worker/interpreters/plain-text.js +18 -0
- package/build/src/worker/interpreters/plain-text.js.map +1 -0
- package/build/src/worker/interpreters/seerr.d.ts +4 -0
- package/build/src/worker/interpreters/seerr.d.ts.map +1 -0
- package/build/src/worker/interpreters/seerr.js +173 -0
- package/build/src/worker/interpreters/seerr.js.map +1 -0
- package/build/src/worker/interpreters/statuspage.d.ts +4 -0
- package/build/src/worker/interpreters/statuspage.d.ts.map +1 -0
- package/build/src/worker/interpreters/statuspage.js +266 -0
- package/build/src/worker/interpreters/statuspage.js.map +1 -0
- package/build/src/worker/interpreters/synology.d.ts +4 -0
- package/build/src/worker/interpreters/synology.d.ts.map +1 -0
- package/build/src/worker/interpreters/synology.js +177 -0
- package/build/src/worker/interpreters/synology.js.map +1 -0
- package/build/src/worker/interpreters/unifi.d.ts +4 -0
- package/build/src/worker/interpreters/unifi.d.ts.map +1 -0
- package/build/src/worker/interpreters/unifi.js +152 -0
- package/build/src/worker/interpreters/unifi.js.map +1 -0
- package/build/src/worker/landing/page.d.ts +4 -0
- package/build/src/worker/landing/page.d.ts.map +1 -0
- package/build/src/worker/landing/page.js +260 -0
- package/build/src/worker/landing/page.js.map +1 -0
- package/build/src/worker/pipeline/accumulate.d.ts +7 -0
- package/build/src/worker/pipeline/accumulate.d.ts.map +1 -0
- package/build/src/worker/pipeline/accumulate.js +53 -0
- package/build/src/worker/pipeline/accumulate.js.map +1 -0
- package/build/src/worker/pipeline/authenticate.d.ts +4 -0
- package/build/src/worker/pipeline/authenticate.d.ts.map +1 -0
- package/build/src/worker/pipeline/authenticate.js +53 -0
- package/build/src/worker/pipeline/authenticate.js.map +1 -0
- package/build/src/worker/pipeline/email.d.ts +4 -0
- package/build/src/worker/pipeline/email.d.ts.map +1 -0
- package/build/src/worker/pipeline/email.js +149 -0
- package/build/src/worker/pipeline/email.js.map +1 -0
- package/build/src/worker/pipeline/format.d.ts +5 -0
- package/build/src/worker/pipeline/format.d.ts.map +1 -0
- package/build/src/worker/pipeline/format.js +48 -0
- package/build/src/worker/pipeline/format.js.map +1 -0
- package/build/src/worker/pipeline/interpret.d.ts +4 -0
- package/build/src/worker/pipeline/interpret.d.ts.map +1 -0
- package/build/src/worker/pipeline/interpret.js +30 -0
- package/build/src/worker/pipeline/interpret.js.map +1 -0
- package/build/src/worker/pipeline/parse.d.ts +4 -0
- package/build/src/worker/pipeline/parse.d.ts.map +1 -0
- package/build/src/worker/pipeline/parse.js +59 -0
- package/build/src/worker/pipeline/parse.js.map +1 -0
- package/build/src/worker/pipeline/receive.d.ts +4 -0
- package/build/src/worker/pipeline/receive.d.ts.map +1 -0
- package/build/src/worker/pipeline/receive.js +52 -0
- package/build/src/worker/pipeline/receive.js.map +1 -0
- package/build/src/worker/pipeline/respond.d.ts +4 -0
- package/build/src/worker/pipeline/respond.d.ts.map +1 -0
- package/build/src/worker/pipeline/respond.js +48 -0
- package/build/src/worker/pipeline/respond.js.map +1 -0
- package/build/src/worker/pipeline/route.d.ts +5 -0
- package/build/src/worker/pipeline/route.d.ts.map +1 -0
- package/build/src/worker/pipeline/route.js +23 -0
- package/build/src/worker/pipeline/route.js.map +1 -0
- package/build/src/worker/pipeline/send.d.ts +4 -0
- package/build/src/worker/pipeline/send.d.ts.map +1 -0
- package/build/src/worker/pipeline/send.js +156 -0
- package/build/src/worker/pipeline/send.js.map +1 -0
- package/build/src/worker/pipeline/split.d.ts +4 -0
- package/build/src/worker/pipeline/split.d.ts.map +1 -0
- package/build/src/worker/pipeline/split.js +40 -0
- package/build/src/worker/pipeline/split.js.map +1 -0
- package/package.json +95 -2
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { Bootstrap, CLIHeader, Logger } from '@cbnventures/nova/toolkit';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import prompts from 'prompts';
|
|
7
|
+
import { LIB_REGEX_NON_ALPHANUMERIC_ID } from '../../lib/regex.js';
|
|
8
|
+
import { addContext, generateId, generateToken, listContexts, removeContext, } from '../commands/context.js';
|
|
9
|
+
import { deploy } from '../commands/deploy.js';
|
|
10
|
+
import { addServer, listServers, removeServer } from '../commands/server.js';
|
|
11
|
+
import { getSettings, updateSettings } from '../commands/settings.js';
|
|
12
|
+
async function interactiveMenu(configDirs) {
|
|
13
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
14
|
+
let dir = dirname(currentFilePath);
|
|
15
|
+
let version = '0.0.0';
|
|
16
|
+
while (dir !== dirname(dir)) {
|
|
17
|
+
const packageJsonPath = join(dir, 'package.json');
|
|
18
|
+
if (existsSync(packageJsonPath) === true) {
|
|
19
|
+
const packageJsonRaw = readFileSync(packageJsonPath, 'utf-8');
|
|
20
|
+
const packageJsonParsed = JSON.parse(packageJsonRaw);
|
|
21
|
+
version = packageJsonParsed['version'];
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
const parent = dirname(dir);
|
|
25
|
+
dir = parent;
|
|
26
|
+
}
|
|
27
|
+
const header = CLIHeader.render([
|
|
28
|
+
chalk.magentaBright(`Reverse Proxy for ntfy v${version}`),
|
|
29
|
+
chalk.dim('A CBN Ventures Creation'),
|
|
30
|
+
], {
|
|
31
|
+
style: 'round',
|
|
32
|
+
width: 50,
|
|
33
|
+
marginBottom: 1,
|
|
34
|
+
});
|
|
35
|
+
process.stdout.write(`${header}\n`);
|
|
36
|
+
let configPath = undefined;
|
|
37
|
+
if (configDirs['length'] > 1) {
|
|
38
|
+
const configDirResponse = await prompts({
|
|
39
|
+
type: 'select',
|
|
40
|
+
name: 'dir',
|
|
41
|
+
message: chalk.cyan('Multiple config files found. Which one?'),
|
|
42
|
+
choices: configDirs.map((configDir) => ({
|
|
43
|
+
title: join(configDir, 'config.json'),
|
|
44
|
+
value: configDir,
|
|
45
|
+
})),
|
|
46
|
+
});
|
|
47
|
+
if (configDirResponse['dir'] === undefined) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
configPath = join(configDirResponse['dir'], 'config.json');
|
|
51
|
+
}
|
|
52
|
+
else if (configDirs['length'] === 1) {
|
|
53
|
+
configPath = join(configDirs[0], 'config.json');
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
const defaultConfigDir = Bootstrap.getConfigDir('ntfy-reverse-proxy');
|
|
57
|
+
configPath = join(defaultConfigDir, 'config.json');
|
|
58
|
+
}
|
|
59
|
+
let running = true;
|
|
60
|
+
while (running === true) {
|
|
61
|
+
const response = await prompts({
|
|
62
|
+
type: 'select',
|
|
63
|
+
name: 'action',
|
|
64
|
+
message: chalk.cyan('What would you like to do?'),
|
|
65
|
+
choices: [
|
|
66
|
+
{
|
|
67
|
+
title: 'Manage Servers', value: 'servers',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
title: 'Manage Contexts', value: 'contexts',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
title: 'Settings', value: 'settings',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
title: 'Deploy', value: 'deploy',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
title: 'Exit', value: 'exit',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
});
|
|
83
|
+
const action = response['action'];
|
|
84
|
+
if (action === undefined || action === 'exit') {
|
|
85
|
+
running = false;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
if (action === 'servers') {
|
|
89
|
+
await serverMenu(configPath);
|
|
90
|
+
}
|
|
91
|
+
else if (action === 'contexts') {
|
|
92
|
+
await contextMenu(configPath);
|
|
93
|
+
}
|
|
94
|
+
else if (action === 'settings') {
|
|
95
|
+
await settingsFlow(configPath);
|
|
96
|
+
}
|
|
97
|
+
else if (action === 'deploy') {
|
|
98
|
+
try {
|
|
99
|
+
await deploy(configPath, true);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
103
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
async function serverMenu(configPath) {
|
|
110
|
+
let inMenu = true;
|
|
111
|
+
while (inMenu === true) {
|
|
112
|
+
const response = await prompts({
|
|
113
|
+
type: 'select',
|
|
114
|
+
name: 'action',
|
|
115
|
+
message: chalk.cyan('Manage Servers'),
|
|
116
|
+
choices: [
|
|
117
|
+
{
|
|
118
|
+
title: 'Add', value: 'add',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
title: 'Edit', value: 'edit',
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
title: 'Remove', value: 'remove',
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
title: 'Back', value: 'back',
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
const action = response['action'];
|
|
132
|
+
if (action === undefined || action === 'back') {
|
|
133
|
+
inMenu = false;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
if (action === 'add') {
|
|
137
|
+
const answers = await prompts([
|
|
138
|
+
{
|
|
139
|
+
type: 'text',
|
|
140
|
+
name: 'name',
|
|
141
|
+
message: 'Server name:',
|
|
142
|
+
validate: (value) => value.trim()['length'] > 0 || 'Name is required',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'text',
|
|
146
|
+
name: 'server',
|
|
147
|
+
message: 'Server URL:',
|
|
148
|
+
validate: (value) => {
|
|
149
|
+
if (value.startsWith('https://') === false) {
|
|
150
|
+
return 'URL must start with https://';
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const urlInstance = new URL(value);
|
|
154
|
+
void urlInstance;
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return 'Invalid URL';
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'password',
|
|
164
|
+
name: 'token',
|
|
165
|
+
message: 'Server token:',
|
|
166
|
+
validate: (value) => value.startsWith('tk_') || 'Token must start with tk_',
|
|
167
|
+
},
|
|
168
|
+
]);
|
|
169
|
+
const answersName = answers['name'];
|
|
170
|
+
const answersServer = answers['server'];
|
|
171
|
+
const answersToken = answers['token'];
|
|
172
|
+
if (answersName !== undefined
|
|
173
|
+
&& answersServer !== undefined
|
|
174
|
+
&& answersToken !== undefined) {
|
|
175
|
+
try {
|
|
176
|
+
addServer(configPath, {
|
|
177
|
+
name: answersName,
|
|
178
|
+
server: answersServer,
|
|
179
|
+
token: answersToken,
|
|
180
|
+
});
|
|
181
|
+
Logger.info(`Server "${answersName}" added.`);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
185
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else if (action === 'edit') {
|
|
190
|
+
try {
|
|
191
|
+
const servers = listServers(configPath);
|
|
192
|
+
servers.sort((a, b) => a['name'].localeCompare(b['name']));
|
|
193
|
+
if (servers['length'] === 0) {
|
|
194
|
+
Logger.warn('No servers to edit.');
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
const selectResponse = await prompts({
|
|
198
|
+
type: 'select',
|
|
199
|
+
name: 'name',
|
|
200
|
+
message: 'Select server to edit:',
|
|
201
|
+
choices: servers.map((server) => ({
|
|
202
|
+
title: server['name'], value: server['name'],
|
|
203
|
+
})),
|
|
204
|
+
});
|
|
205
|
+
const name = selectResponse['name'];
|
|
206
|
+
if (name !== undefined) {
|
|
207
|
+
const current = servers.find((server) => server['name'] === name);
|
|
208
|
+
const currentServer = (current !== undefined) ? current['server'] : undefined;
|
|
209
|
+
const updates = await prompts([
|
|
210
|
+
{
|
|
211
|
+
type: 'text',
|
|
212
|
+
name: 'server',
|
|
213
|
+
message: 'Server URL:',
|
|
214
|
+
initial: currentServer,
|
|
215
|
+
validate: (value) => {
|
|
216
|
+
if (value.startsWith('https://') === false) {
|
|
217
|
+
return 'URL must start with https://';
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
const urlInstance = new URL(value);
|
|
221
|
+
void urlInstance;
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return 'Invalid URL';
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
type: 'password',
|
|
231
|
+
name: 'token',
|
|
232
|
+
message: 'Server token (leave blank to keep current):',
|
|
233
|
+
validate: (value) => {
|
|
234
|
+
const trimmedEmpty = (value.trim() === '');
|
|
235
|
+
const startsWithTk = value.startsWith('tk_');
|
|
236
|
+
if (trimmedEmpty === true) {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
return startsWithTk || 'Token must start with tk_';
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
]);
|
|
243
|
+
const editImport = await import('../commands/server.js');
|
|
244
|
+
const updatesServerString = updates['server'];
|
|
245
|
+
const serverUrlTrimmed = updatesServerString.trim();
|
|
246
|
+
const serverUrl = (serverUrlTrimmed !== '') ? updatesServerString : undefined;
|
|
247
|
+
const updatesTokenString = updates['token'];
|
|
248
|
+
const tokenTrimmed = updatesTokenString.trim();
|
|
249
|
+
const tokenValue = (tokenTrimmed !== '') ? updatesTokenString : undefined;
|
|
250
|
+
if (serverUrl !== undefined || tokenValue !== undefined) {
|
|
251
|
+
const editUpdates = {};
|
|
252
|
+
if (serverUrl !== undefined) {
|
|
253
|
+
Reflect.set(editUpdates, 'server', serverUrl);
|
|
254
|
+
}
|
|
255
|
+
if (tokenValue !== undefined) {
|
|
256
|
+
Reflect.set(editUpdates, 'token', tokenValue);
|
|
257
|
+
}
|
|
258
|
+
editImport.editServer(configPath, name, editUpdates);
|
|
259
|
+
Logger.info(`Server "${name}" updated.`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
266
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else if (action === 'remove') {
|
|
270
|
+
try {
|
|
271
|
+
const servers = listServers(configPath);
|
|
272
|
+
servers.sort((a, b) => a['name'].localeCompare(b['name']));
|
|
273
|
+
if (servers['length'] === 0) {
|
|
274
|
+
Logger.warn('No servers to remove.');
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const selectResponse = await prompts({
|
|
278
|
+
type: 'select',
|
|
279
|
+
name: 'name',
|
|
280
|
+
message: 'Select server to remove:',
|
|
281
|
+
choices: servers.map((server) => ({
|
|
282
|
+
title: server['name'], value: server['name'],
|
|
283
|
+
})),
|
|
284
|
+
});
|
|
285
|
+
const name = selectResponse['name'];
|
|
286
|
+
if (name !== undefined) {
|
|
287
|
+
const confirmResponse = await prompts({
|
|
288
|
+
type: 'confirm',
|
|
289
|
+
name: 'confirmed',
|
|
290
|
+
message: chalk.yellow(`Remove "${name}"?`),
|
|
291
|
+
initial: false,
|
|
292
|
+
});
|
|
293
|
+
const confirmed = confirmResponse['confirmed'];
|
|
294
|
+
if (confirmed === true) {
|
|
295
|
+
removeServer(configPath, name);
|
|
296
|
+
Logger.info(`Server "${name}" removed.`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
303
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
async function contextMenu(configPath) {
|
|
310
|
+
let inMenu = true;
|
|
311
|
+
while (inMenu === true) {
|
|
312
|
+
const response = await prompts({
|
|
313
|
+
type: 'select',
|
|
314
|
+
name: 'action',
|
|
315
|
+
message: chalk.cyan('Manage Contexts'),
|
|
316
|
+
choices: [
|
|
317
|
+
{
|
|
318
|
+
title: 'Add', value: 'add',
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
title: 'Edit', value: 'edit',
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
title: 'Remove', value: 'remove',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
title: 'Back', value: 'back',
|
|
328
|
+
},
|
|
329
|
+
],
|
|
330
|
+
});
|
|
331
|
+
const action = response['action'];
|
|
332
|
+
if (action === undefined || action === 'back') {
|
|
333
|
+
inMenu = false;
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
if (action === 'add') {
|
|
337
|
+
try {
|
|
338
|
+
const servers = listServers(configPath);
|
|
339
|
+
if (servers['length'] === 0) {
|
|
340
|
+
Logger.warn('Add a server first.');
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
await addContextFlow(configPath, servers);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
348
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else if (action === 'edit') {
|
|
352
|
+
try {
|
|
353
|
+
const contexts = listContexts(configPath);
|
|
354
|
+
contexts.sort((a, b) => a['name'].localeCompare(b['name']));
|
|
355
|
+
if (contexts['length'] === 0) {
|
|
356
|
+
Logger.warn('No contexts to edit.');
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
const selectResponse = await prompts({
|
|
360
|
+
type: 'select',
|
|
361
|
+
name: 'name',
|
|
362
|
+
message: 'Select context to edit:',
|
|
363
|
+
choices: contexts.map((context) => ({
|
|
364
|
+
title: context['name'], value: context['name'],
|
|
365
|
+
})),
|
|
366
|
+
});
|
|
367
|
+
const name = selectResponse['name'];
|
|
368
|
+
if (name !== undefined) {
|
|
369
|
+
const current = contexts.find((context) => context['name'] === name);
|
|
370
|
+
if (current !== undefined) {
|
|
371
|
+
const servers = listServers(configPath);
|
|
372
|
+
const serverChoices = servers.map((server) => ({
|
|
373
|
+
title: server['name'], value: server['name'],
|
|
374
|
+
}));
|
|
375
|
+
const keepIdResponse = await prompts({
|
|
376
|
+
type: 'confirm',
|
|
377
|
+
name: 'keepId',
|
|
378
|
+
message: `Keep current ID (${current['id']})?`,
|
|
379
|
+
initial: true,
|
|
380
|
+
});
|
|
381
|
+
const keepId = keepIdResponse['keepId'];
|
|
382
|
+
let id = undefined;
|
|
383
|
+
if (keepId === false) {
|
|
384
|
+
id = generateId();
|
|
385
|
+
Logger.info(` New ID: ${id}`);
|
|
386
|
+
}
|
|
387
|
+
const httpChoices = [
|
|
388
|
+
{
|
|
389
|
+
title: 'Plain Text', value: 'plain-text',
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
title: 'ntfy JSON', value: 'ntfy-json',
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
title: 'Seerr', value: 'seerr',
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
title: 'Synology DSM', value: 'synology',
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
title: 'Statuspage.io', value: 'statuspage',
|
|
402
|
+
},
|
|
403
|
+
];
|
|
404
|
+
const emailChoices = [
|
|
405
|
+
{
|
|
406
|
+
title: 'Plain Text', value: 'plain-text',
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
title: 'pfSense', value: 'pfsense',
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
title: 'UniFi', value: 'unifi',
|
|
413
|
+
},
|
|
414
|
+
];
|
|
415
|
+
const knownChoices = (current['type'] === 'http') ? httpChoices : emailChoices;
|
|
416
|
+
const exists = knownChoices.some((c) => c['value'] === current['interpreter']);
|
|
417
|
+
if (exists === false) {
|
|
418
|
+
knownChoices.unshift({
|
|
419
|
+
title: `${current['interpreter']} (current, unknown)`, value: current['interpreter'],
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
const httpValues = [
|
|
423
|
+
'plain-text',
|
|
424
|
+
'ntfy-json',
|
|
425
|
+
'seerr',
|
|
426
|
+
'synology',
|
|
427
|
+
'statuspage',
|
|
428
|
+
];
|
|
429
|
+
const emailValues = [
|
|
430
|
+
'plain-text',
|
|
431
|
+
'pfsense',
|
|
432
|
+
'unifi',
|
|
433
|
+
];
|
|
434
|
+
const knownValues = (current['type'] === 'http') ? httpValues : emailValues;
|
|
435
|
+
const interpreterIdx = knownValues.indexOf(current['interpreter']);
|
|
436
|
+
const interpreterInitial = (interpreterIdx >= 0) ? interpreterIdx : 0;
|
|
437
|
+
const interpreterResponse = await prompts({
|
|
438
|
+
type: 'select',
|
|
439
|
+
name: 'interpreter',
|
|
440
|
+
message: 'Interpreter:',
|
|
441
|
+
choices: knownChoices,
|
|
442
|
+
initial: interpreterInitial,
|
|
443
|
+
});
|
|
444
|
+
const interpreter = interpreterResponse['interpreter'];
|
|
445
|
+
const topicResponse = await prompts({
|
|
446
|
+
type: 'text',
|
|
447
|
+
name: 'topic',
|
|
448
|
+
message: 'ntfy topic:',
|
|
449
|
+
initial: current['topic'],
|
|
450
|
+
validate: (value) => value.trim()['length'] > 0 || 'Topic is required',
|
|
451
|
+
});
|
|
452
|
+
const topic = topicResponse['topic'];
|
|
453
|
+
const currentErrorTopic = (current['error_topic'] !== undefined) ? current['error_topic'] : '';
|
|
454
|
+
const errorTopicResponse = await prompts({
|
|
455
|
+
type: 'text',
|
|
456
|
+
name: 'error_topic',
|
|
457
|
+
message: 'ntfy error topic (blank to skip):',
|
|
458
|
+
initial: currentErrorTopic,
|
|
459
|
+
});
|
|
460
|
+
const errorTopic = errorTopicResponse['error_topic'];
|
|
461
|
+
const modeInitial = (current['mode'] === 'send-all') ? 1 : 0;
|
|
462
|
+
const modeResponse = await prompts({
|
|
463
|
+
type: 'select',
|
|
464
|
+
name: 'mode',
|
|
465
|
+
message: 'Mode:',
|
|
466
|
+
choices: [
|
|
467
|
+
{
|
|
468
|
+
title: 'Send to one server only', value: 'send-once',
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
title: 'Send to all servers', value: 'send-all',
|
|
472
|
+
},
|
|
473
|
+
],
|
|
474
|
+
initial: modeInitial,
|
|
475
|
+
});
|
|
476
|
+
const mode = modeResponse['mode'];
|
|
477
|
+
const showVisitorInfoResponse = await prompts({
|
|
478
|
+
type: 'confirm',
|
|
479
|
+
name: 'show_visitor_info',
|
|
480
|
+
message: 'Show visitor info?',
|
|
481
|
+
initial: current['show_visitor_info'],
|
|
482
|
+
});
|
|
483
|
+
const showVisitorInfo = showVisitorInfoResponse['show_visitor_info'];
|
|
484
|
+
const primaryServerIdx = serverChoices.findIndex((s) => s['value'] === current['primary_server']);
|
|
485
|
+
if (primaryServerIdx < 0) {
|
|
486
|
+
serverChoices.unshift({
|
|
487
|
+
title: `${current['primary_server']} (current, not found)`, value: current['primary_server'],
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
const primaryServerInitial = (primaryServerIdx >= 0) ? primaryServerIdx : 0;
|
|
491
|
+
const primaryServerResponse = await prompts({
|
|
492
|
+
type: 'select',
|
|
493
|
+
name: 'primary_server',
|
|
494
|
+
message: 'Primary server:',
|
|
495
|
+
choices: serverChoices,
|
|
496
|
+
initial: primaryServerInitial,
|
|
497
|
+
});
|
|
498
|
+
const primaryServer = primaryServerResponse['primary_server'];
|
|
499
|
+
const selectedServersResponse = await prompts({
|
|
500
|
+
type: 'multiselect',
|
|
501
|
+
name: 'selectedServers',
|
|
502
|
+
message: 'All servers (space to select):',
|
|
503
|
+
choices: serverChoices.map((s) => ({
|
|
504
|
+
...s,
|
|
505
|
+
selected: current['servers'].includes(s['value']),
|
|
506
|
+
})),
|
|
507
|
+
});
|
|
508
|
+
const selectedServers = selectedServersResponse['selectedServers'];
|
|
509
|
+
const updates = {};
|
|
510
|
+
if (id !== undefined) {
|
|
511
|
+
Reflect.set(updates, 'id', id);
|
|
512
|
+
}
|
|
513
|
+
if (interpreter !== undefined) {
|
|
514
|
+
Reflect.set(updates, 'interpreter', interpreter);
|
|
515
|
+
}
|
|
516
|
+
if (topic !== undefined) {
|
|
517
|
+
Reflect.set(updates, 'topic', topic);
|
|
518
|
+
}
|
|
519
|
+
if (mode !== undefined) {
|
|
520
|
+
Reflect.set(updates, 'mode', mode);
|
|
521
|
+
}
|
|
522
|
+
if (showVisitorInfo !== undefined) {
|
|
523
|
+
Reflect.set(updates, 'show_visitor_info', showVisitorInfo);
|
|
524
|
+
}
|
|
525
|
+
if (primaryServer !== undefined) {
|
|
526
|
+
Reflect.set(updates, 'primary_server', primaryServer);
|
|
527
|
+
}
|
|
528
|
+
if (selectedServers !== undefined) {
|
|
529
|
+
Reflect.set(updates, 'servers', selectedServers);
|
|
530
|
+
}
|
|
531
|
+
const errorTopicValue = errorTopic;
|
|
532
|
+
const errorTopicTrimmed = (errorTopicValue !== undefined) ? errorTopicValue.trim() : '';
|
|
533
|
+
const resolvedErrorTopic = (errorTopicTrimmed !== '') ? errorTopicTrimmed : undefined;
|
|
534
|
+
Reflect.set(updates, 'error_topic', resolvedErrorTopic);
|
|
535
|
+
if (current['type'] === 'http' && current['token'] !== undefined) {
|
|
536
|
+
const keepTokenResponse = await prompts({
|
|
537
|
+
type: 'confirm',
|
|
538
|
+
name: 'keepToken',
|
|
539
|
+
message: 'Keep current auth token?',
|
|
540
|
+
initial: true,
|
|
541
|
+
});
|
|
542
|
+
const keepToken = keepTokenResponse['keepToken'];
|
|
543
|
+
if (keepToken === false) {
|
|
544
|
+
const newToken = generateToken();
|
|
545
|
+
Reflect.set(updates, 'token', newToken);
|
|
546
|
+
Logger.info(` New token: ${newToken}`);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
else if (current['type'] === 'http' && current['token'] === undefined) {
|
|
550
|
+
const addTokenResponse = await prompts({
|
|
551
|
+
type: 'confirm',
|
|
552
|
+
name: 'addToken',
|
|
553
|
+
message: 'Add auth token?',
|
|
554
|
+
initial: false,
|
|
555
|
+
});
|
|
556
|
+
const addToken = addTokenResponse['addToken'];
|
|
557
|
+
if (addToken === true) {
|
|
558
|
+
const newToken = generateToken();
|
|
559
|
+
Reflect.set(updates, 'token', newToken);
|
|
560
|
+
Logger.info(` New token: ${newToken}`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
else if (current['type'] === 'email') {
|
|
564
|
+
const currentAllowedFrom = (current['allowed_from'] !== undefined) ? current['allowed_from'] : '';
|
|
565
|
+
const allowedFromResponse = await prompts({
|
|
566
|
+
type: 'text',
|
|
567
|
+
name: 'allowed_from',
|
|
568
|
+
message: 'Allowed from email (blank to clear):',
|
|
569
|
+
initial: currentAllowedFrom,
|
|
570
|
+
});
|
|
571
|
+
const allowedFrom = allowedFromResponse['allowed_from'];
|
|
572
|
+
const allowedFromTrimmed = (allowedFrom !== undefined) ? allowedFrom.trim() : '';
|
|
573
|
+
const resolvedAllowedFrom = (allowedFromTrimmed !== '') ? allowedFromTrimmed : undefined;
|
|
574
|
+
Reflect.set(updates, 'allowed_from', resolvedAllowedFrom);
|
|
575
|
+
}
|
|
576
|
+
const editImport = await import('../commands/context.js');
|
|
577
|
+
editImport.editContext(configPath, name, updates);
|
|
578
|
+
Logger.info(`Context "${name}" updated.`);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
585
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
else if (action === 'remove') {
|
|
589
|
+
try {
|
|
590
|
+
const contexts = listContexts(configPath);
|
|
591
|
+
contexts.sort((a, b) => a['name'].localeCompare(b['name']));
|
|
592
|
+
if (contexts['length'] === 0) {
|
|
593
|
+
Logger.warn('No contexts to remove.');
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
const selectResponse = await prompts({
|
|
597
|
+
type: 'select',
|
|
598
|
+
name: 'name',
|
|
599
|
+
message: 'Select context to remove:',
|
|
600
|
+
choices: contexts.map((context) => ({
|
|
601
|
+
title: context['name'], value: context['name'],
|
|
602
|
+
})),
|
|
603
|
+
});
|
|
604
|
+
const name = selectResponse['name'];
|
|
605
|
+
if (name !== undefined) {
|
|
606
|
+
const confirmResponse = await prompts({
|
|
607
|
+
type: 'confirm',
|
|
608
|
+
name: 'confirmed',
|
|
609
|
+
message: chalk.yellow(`Remove "${name}"?`),
|
|
610
|
+
initial: false,
|
|
611
|
+
});
|
|
612
|
+
const confirmed = confirmResponse['confirmed'];
|
|
613
|
+
if (confirmed === true) {
|
|
614
|
+
removeContext(configPath, name);
|
|
615
|
+
Logger.info(`Context "${name}" removed.`);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
catch (error) {
|
|
621
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
622
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
async function addContextFlow(configPath, servers) {
|
|
629
|
+
const autoId = generateId();
|
|
630
|
+
const typeResponse = await prompts({
|
|
631
|
+
type: 'select',
|
|
632
|
+
name: 'contextType',
|
|
633
|
+
message: 'Context type:',
|
|
634
|
+
choices: [
|
|
635
|
+
{
|
|
636
|
+
title: 'HTTP', value: 'http',
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
title: 'Email', value: 'email',
|
|
640
|
+
},
|
|
641
|
+
],
|
|
642
|
+
});
|
|
643
|
+
const contextType = typeResponse['contextType'];
|
|
644
|
+
if (contextType === undefined) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
const httpInterpreters = [
|
|
648
|
+
{
|
|
649
|
+
title: 'Plain Text', value: 'plain-text',
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
title: 'ntfy JSON', value: 'ntfy-json',
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
title: 'Seerr', value: 'seerr',
|
|
656
|
+
},
|
|
657
|
+
{
|
|
658
|
+
title: 'Synology DSM', value: 'synology',
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
title: 'Statuspage.io', value: 'statuspage',
|
|
662
|
+
},
|
|
663
|
+
];
|
|
664
|
+
const emailInterpreters = [
|
|
665
|
+
{
|
|
666
|
+
title: 'Plain Text', value: 'plain-text',
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
title: 'pfSense', value: 'pfsense',
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
title: 'UniFi', value: 'unifi',
|
|
673
|
+
},
|
|
674
|
+
];
|
|
675
|
+
const nameResponse = await prompts({
|
|
676
|
+
type: 'text',
|
|
677
|
+
name: 'name',
|
|
678
|
+
message: 'Context name:',
|
|
679
|
+
validate: (value) => value.trim()['length'] > 0 || 'Name is required',
|
|
680
|
+
});
|
|
681
|
+
const name = nameResponse['name'];
|
|
682
|
+
if (name === undefined) {
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const idMessage = (contextType === 'http') ? `ID (blank for auto: ${autoId}):` : 'ID (email local part, e.g. "pfsense"):';
|
|
686
|
+
const idResponse = await prompts({
|
|
687
|
+
type: 'text',
|
|
688
|
+
name: 'id',
|
|
689
|
+
message: idMessage,
|
|
690
|
+
validate: (value) => {
|
|
691
|
+
if (contextType === 'http') {
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
if (value.trim()['length'] === 0) {
|
|
695
|
+
return 'ID is required for email contexts';
|
|
696
|
+
}
|
|
697
|
+
if (LIB_REGEX_NON_ALPHANUMERIC_ID.test(value) === true) {
|
|
698
|
+
return 'ID must be alphanumeric (plus . _ -)';
|
|
699
|
+
}
|
|
700
|
+
return true;
|
|
701
|
+
},
|
|
702
|
+
});
|
|
703
|
+
const rawId = idResponse['id'];
|
|
704
|
+
if (rawId === undefined) {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
const interpreterChoices = (contextType === 'http') ? httpInterpreters : emailInterpreters;
|
|
708
|
+
const interpreterResponse = await prompts({
|
|
709
|
+
type: 'select',
|
|
710
|
+
name: 'interpreter',
|
|
711
|
+
message: 'Interpreter:',
|
|
712
|
+
choices: interpreterChoices,
|
|
713
|
+
});
|
|
714
|
+
const interpreter = interpreterResponse['interpreter'];
|
|
715
|
+
if (interpreter === undefined) {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
const topicResponse = await prompts({
|
|
719
|
+
type: 'text',
|
|
720
|
+
name: 'topic',
|
|
721
|
+
message: 'ntfy topic:',
|
|
722
|
+
validate: (value) => value.trim()['length'] > 0 || 'Topic is required',
|
|
723
|
+
});
|
|
724
|
+
const topic = topicResponse['topic'];
|
|
725
|
+
if (topic === undefined) {
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
const errorTopicResponse = await prompts({
|
|
729
|
+
type: 'text',
|
|
730
|
+
name: 'error_topic',
|
|
731
|
+
message: 'ntfy error topic (blank to skip):',
|
|
732
|
+
});
|
|
733
|
+
const errorTopic = errorTopicResponse['error_topic'];
|
|
734
|
+
const modeResponse = await prompts({
|
|
735
|
+
type: 'select',
|
|
736
|
+
name: 'mode',
|
|
737
|
+
message: 'Mode:',
|
|
738
|
+
choices: [
|
|
739
|
+
{
|
|
740
|
+
title: 'Send to one server only', value: 'send-once',
|
|
741
|
+
},
|
|
742
|
+
{
|
|
743
|
+
title: 'Send to all servers', value: 'send-all',
|
|
744
|
+
},
|
|
745
|
+
],
|
|
746
|
+
});
|
|
747
|
+
const mode = modeResponse['mode'];
|
|
748
|
+
if (mode === undefined) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const showVisitorInfoResponse = await prompts({
|
|
752
|
+
type: 'confirm',
|
|
753
|
+
name: 'show_visitor_info',
|
|
754
|
+
message: 'Show visitor info?',
|
|
755
|
+
initial: false,
|
|
756
|
+
});
|
|
757
|
+
const showVisitorInfo = showVisitorInfoResponse['show_visitor_info'];
|
|
758
|
+
if (showVisitorInfo === undefined) {
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const primaryServerResponse = await prompts({
|
|
762
|
+
type: 'select',
|
|
763
|
+
name: 'primary_server',
|
|
764
|
+
message: 'Primary server:',
|
|
765
|
+
choices: servers.map((server) => ({
|
|
766
|
+
title: server['name'], value: server['name'],
|
|
767
|
+
})),
|
|
768
|
+
});
|
|
769
|
+
const primaryServer = primaryServerResponse['primary_server'];
|
|
770
|
+
if (primaryServer === undefined) {
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
const selectedServersResponse = await prompts({
|
|
774
|
+
type: 'multiselect',
|
|
775
|
+
name: 'selectedServers',
|
|
776
|
+
message: 'All servers for this context (space to select):',
|
|
777
|
+
choices: servers.map((server) => ({
|
|
778
|
+
title: server['name'], value: server['name'],
|
|
779
|
+
})),
|
|
780
|
+
});
|
|
781
|
+
const selectedServers = selectedServersResponse['selectedServers'];
|
|
782
|
+
if (selectedServers === undefined) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const rawIdString = rawId;
|
|
786
|
+
const idTrimmed = rawIdString.trim();
|
|
787
|
+
const resolvedId = (idTrimmed !== '') ? idTrimmed : autoId;
|
|
788
|
+
const errorTopicString = (errorTopic !== undefined) ? (errorTopic) : '';
|
|
789
|
+
const errorTopicTrimmed = errorTopicString.trim();
|
|
790
|
+
const resolvedErrorTopic = (errorTopicTrimmed !== '') ? errorTopicTrimmed : undefined;
|
|
791
|
+
const topicString = topic;
|
|
792
|
+
const typedInterpreter = interpreter;
|
|
793
|
+
const typedMode = mode;
|
|
794
|
+
if (contextType === 'http') {
|
|
795
|
+
const autoToken = generateToken();
|
|
796
|
+
const tokenResponse = await prompts({
|
|
797
|
+
type: 'text',
|
|
798
|
+
name: 'token',
|
|
799
|
+
message: 'Auth token (blank to skip, enter to accept):',
|
|
800
|
+
initial: autoToken,
|
|
801
|
+
});
|
|
802
|
+
const rawToken = tokenResponse['token'];
|
|
803
|
+
const tokenTrimmed = (rawToken !== undefined) ? rawToken.trim() : '';
|
|
804
|
+
const resolvedToken = (tokenTrimmed !== '') ? tokenTrimmed : undefined;
|
|
805
|
+
addContext(configPath, {
|
|
806
|
+
name,
|
|
807
|
+
type: 'http',
|
|
808
|
+
id: resolvedId,
|
|
809
|
+
interpreter: typedInterpreter,
|
|
810
|
+
topic: topicString,
|
|
811
|
+
error_topic: resolvedErrorTopic,
|
|
812
|
+
mode: typedMode,
|
|
813
|
+
show_visitor_info: showVisitorInfo,
|
|
814
|
+
primary_server: primaryServer,
|
|
815
|
+
servers: selectedServers,
|
|
816
|
+
token: resolvedToken,
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
const allowedFromResponse = await prompts({
|
|
821
|
+
type: 'text',
|
|
822
|
+
name: 'allowed_from',
|
|
823
|
+
message: 'Allowed from email (blank to skip):',
|
|
824
|
+
});
|
|
825
|
+
const rawAllowedFrom = allowedFromResponse['allowed_from'];
|
|
826
|
+
const allowedFromTrimmed = (rawAllowedFrom !== undefined) ? rawAllowedFrom.trim() : '';
|
|
827
|
+
const resolvedAllowedFrom = (allowedFromTrimmed !== '') ? allowedFromTrimmed : undefined;
|
|
828
|
+
addContext(configPath, {
|
|
829
|
+
name,
|
|
830
|
+
type: 'email',
|
|
831
|
+
id: resolvedId,
|
|
832
|
+
interpreter: typedInterpreter,
|
|
833
|
+
topic: topicString,
|
|
834
|
+
error_topic: resolvedErrorTopic,
|
|
835
|
+
mode: typedMode,
|
|
836
|
+
show_visitor_info: showVisitorInfo,
|
|
837
|
+
primary_server: primaryServer,
|
|
838
|
+
servers: selectedServers,
|
|
839
|
+
allowed_from: resolvedAllowedFrom,
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
Logger.info(`Context "${name}" added.`);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
async function settingsFlow(configPath) {
|
|
846
|
+
let currentSettings = undefined;
|
|
847
|
+
try {
|
|
848
|
+
currentSettings = getSettings(configPath);
|
|
849
|
+
}
|
|
850
|
+
catch (error) {
|
|
851
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
852
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const workerNameResponse = await prompts({
|
|
856
|
+
type: 'text',
|
|
857
|
+
name: 'worker_name',
|
|
858
|
+
message: 'Worker name:',
|
|
859
|
+
initial: currentSettings['worker_name'],
|
|
860
|
+
validate: (value) => value.trim()['length'] > 0 || 'Worker name is required',
|
|
861
|
+
});
|
|
862
|
+
const workerName = workerNameResponse['worker_name'];
|
|
863
|
+
if (workerName === undefined) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
const baseDomainResponse = await prompts({
|
|
867
|
+
type: 'text',
|
|
868
|
+
name: 'base_domain',
|
|
869
|
+
message: 'Base domain:',
|
|
870
|
+
initial: currentSettings['base_domain'],
|
|
871
|
+
validate: (value) => value.trim()['length'] > 0 || 'Base domain is required',
|
|
872
|
+
});
|
|
873
|
+
const baseDomain = baseDomainResponse['base_domain'];
|
|
874
|
+
if (baseDomain === undefined) {
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
const showResponseOutputResponse = await prompts({
|
|
878
|
+
type: 'confirm',
|
|
879
|
+
name: 'show_response_output',
|
|
880
|
+
message: 'Show response output (debug mode)?',
|
|
881
|
+
initial: currentSettings['show_response_output'],
|
|
882
|
+
});
|
|
883
|
+
const showResponseOutput = showResponseOutputResponse['show_response_output'];
|
|
884
|
+
if (showResponseOutput === undefined) {
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
try {
|
|
888
|
+
updateSettings(configPath, {
|
|
889
|
+
worker_name: workerName,
|
|
890
|
+
base_domain: baseDomain,
|
|
891
|
+
show_response_output: showResponseOutput,
|
|
892
|
+
});
|
|
893
|
+
Logger.info('Settings updated.');
|
|
894
|
+
}
|
|
895
|
+
catch (error) {
|
|
896
|
+
const errorMessage = (error instanceof Error) ? error['message'] : String(error);
|
|
897
|
+
Logger.error(`Error: ${errorMessage}`);
|
|
898
|
+
}
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
export { interactiveMenu, };
|
|
902
|
+
//# sourceMappingURL=interactive.js.map
|