ntfy-reverse-proxy 2.0.4 → 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.
Files changed (193) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +10 -0
  3. package/build/src/cli/commands/config-io.d.ts +3 -3
  4. package/build/src/cli/commands/config-io.d.ts.map +1 -1
  5. package/build/src/cli/commands/config-io.js +1 -1
  6. package/build/src/cli/commands/config-io.js.map +1 -1
  7. package/build/src/cli/commands/context.d.ts +7 -7
  8. package/build/src/cli/commands/context.d.ts.map +1 -1
  9. package/build/src/cli/commands/context.js +1 -1
  10. package/build/src/cli/commands/context.js.map +1 -1
  11. package/build/src/cli/commands/deploy.d.ts +2 -2
  12. package/build/src/cli/commands/deploy.d.ts.map +1 -1
  13. package/build/src/cli/commands/deploy.js +72 -30
  14. package/build/src/cli/commands/deploy.js.map +1 -1
  15. package/build/src/cli/commands/generate.d.ts +2 -2
  16. package/build/src/cli/commands/generate.d.ts.map +1 -1
  17. package/build/src/cli/commands/generate.js +3 -3
  18. package/build/src/cli/commands/generate.js.map +1 -1
  19. package/build/src/cli/commands/server.d.ts +5 -5
  20. package/build/src/cli/commands/server.d.ts.map +1 -1
  21. package/build/src/cli/commands/server.js.map +1 -1
  22. package/build/src/cli/commands/settings.d.ts +3 -3
  23. package/build/src/cli/commands/settings.d.ts.map +1 -1
  24. package/build/src/cli/commands/settings.js.map +1 -1
  25. package/build/src/cli/commands/validate.d.ts +2 -2
  26. package/build/src/cli/commands/validate.d.ts.map +1 -1
  27. package/build/src/cli/commands/validate.js +3 -0
  28. package/build/src/cli/commands/validate.js.map +1 -1
  29. package/build/src/cli/index.d.ts +2 -2
  30. package/build/src/cli/index.d.ts.map +1 -1
  31. package/build/src/cli/index.js +4 -4
  32. package/build/src/cli/index.js.map +1 -1
  33. package/build/src/cli/menu/interactive.d.ts +2 -2
  34. package/build/src/cli/menu/interactive.d.ts.map +1 -1
  35. package/build/src/cli/menu/interactive.js +260 -94
  36. package/build/src/cli/menu/interactive.js.map +1 -1
  37. package/build/src/lib/regex.d.ts +4 -1
  38. package/build/src/lib/regex.d.ts.map +1 -1
  39. package/build/src/lib/regex.js +4 -1
  40. package/build/src/lib/regex.js.map +1 -1
  41. package/build/src/lib/schema.d.ts +24 -0
  42. package/build/src/lib/schema.d.ts.map +1 -1
  43. package/build/src/lib/schema.js +11 -2
  44. package/build/src/lib/schema.js.map +1 -1
  45. package/build/src/lib/utility.d.ts +2 -2
  46. package/build/src/lib/utility.d.ts.map +1 -1
  47. package/build/src/lib/utility.js +1 -1
  48. package/build/src/lib/utility.js.map +1 -1
  49. package/build/src/types/cli/commands/config-io.d.ts +12 -12
  50. package/build/src/types/cli/commands/context.d.ts +96 -58
  51. package/build/src/types/cli/commands/deploy.d.ts +342 -298
  52. package/build/src/types/cli/commands/generate.d.ts +40 -24
  53. package/build/src/types/cli/commands/server.d.ts +23 -23
  54. package/build/src/types/cli/commands/settings.d.ts +8 -8
  55. package/build/src/types/cli/commands/validate.d.ts +16 -16
  56. package/build/src/types/cli/index.d.ts +16 -20
  57. package/build/src/types/cli/menu/interactive.d.ts +233 -178
  58. package/build/src/types/lib/schema.d.ts +89 -81
  59. package/build/src/types/lib/utility.d.ts +4 -2
  60. package/build/src/types/shared.d.ts +85 -0
  61. package/build/src/types/tests/cli/commands/context.test.d.ts +102 -31
  62. package/build/src/types/tests/cli/commands/generate.test.d.ts +50 -4
  63. package/build/src/types/tests/cli/commands/server.test.d.ts +88 -23
  64. package/build/src/types/tests/cli/commands/settings.test.d.ts +65 -21
  65. package/build/src/types/tests/cli/commands/validate.test.d.ts +69 -8
  66. package/build/src/types/tests/cli/menu/interactive-integration.test.d.ts +99 -0
  67. package/build/src/types/tests/cli/menu/interactive.test.d.ts +275 -2
  68. package/build/src/types/tests/lib/schema.test.d.ts +258 -3
  69. package/build/src/types/tests/worker/index.test.d.ts +166 -8
  70. package/build/src/types/tests/worker/interpreters/ntfy-json.test.d.ts +94 -10
  71. package/build/src/types/tests/worker/interpreters/pfsense.test.d.ts +163 -4
  72. package/build/src/types/tests/worker/interpreters/plain-text.test.d.ts +67 -4
  73. package/build/src/types/tests/worker/interpreters/seerr.test.d.ts +138 -3
  74. package/build/src/types/tests/worker/interpreters/statuspage.test.d.ts +235 -30
  75. package/build/src/types/tests/worker/interpreters/synology.test.d.ts +61 -3
  76. package/build/src/types/tests/worker/interpreters/unifi.test.d.ts +93 -3
  77. package/build/src/types/tests/worker/landing/page.test.d.ts +73 -50
  78. package/build/src/types/tests/worker/pipeline/accumulate.test.d.ts +226 -15
  79. package/build/src/types/tests/worker/pipeline/authenticate.test.d.ts +148 -4
  80. package/build/src/types/tests/worker/pipeline/email.test.d.ts +82 -8
  81. package/build/src/types/tests/worker/pipeline/format.test.d.ts +112 -32
  82. package/build/src/types/tests/worker/pipeline/interpret.test.d.ts +109 -17
  83. package/build/src/types/tests/worker/pipeline/parse.test.d.ts +70 -5
  84. package/build/src/types/tests/worker/pipeline/receive.test.d.ts +156 -15
  85. package/build/src/types/tests/worker/pipeline/respond.test.d.ts +129 -10
  86. package/build/src/types/tests/worker/pipeline/route.test.d.ts +412 -74
  87. package/build/src/types/tests/worker/pipeline/send.test.d.ts +58 -23
  88. package/build/src/types/tests/worker/pipeline/split.test.d.ts +47 -9
  89. package/build/src/types/worker/handlers.d.ts +193 -0
  90. package/build/src/types/worker/index.d.ts +58 -203
  91. package/build/src/types/worker/interpreters/ntfy-json.d.ts +10 -10
  92. package/build/src/types/worker/interpreters/pfsense.d.ts +57 -49
  93. package/build/src/types/worker/interpreters/plain-text.d.ts +7 -7
  94. package/build/src/types/worker/interpreters/seerr.d.ts +63 -61
  95. package/build/src/types/worker/interpreters/statuspage.d.ts +201 -116
  96. package/build/src/types/worker/interpreters/synology.d.ts +48 -46
  97. package/build/src/types/worker/interpreters/unifi.d.ts +79 -54
  98. package/build/src/types/worker/landing/page.d.ts +30 -23
  99. package/build/src/types/worker/pipeline/accumulate.d.ts +46 -32
  100. package/build/src/types/worker/pipeline/authenticate.d.ts +94 -34
  101. package/build/src/types/worker/pipeline/email.d.ts +114 -50
  102. package/build/src/types/worker/pipeline/format.d.ts +31 -23
  103. package/build/src/types/worker/pipeline/interpret.d.ts +34 -34
  104. package/build/src/types/worker/pipeline/parse.d.ts +25 -19
  105. package/build/src/types/worker/pipeline/receive.d.ts +36 -34
  106. package/build/src/types/worker/pipeline/respond.d.ts +119 -63
  107. package/build/src/types/worker/pipeline/route.d.ts +33 -16
  108. package/build/src/types/worker/pipeline/send.d.ts +116 -79
  109. package/build/src/types/worker/pipeline/split.d.ts +21 -16
  110. package/build/src/worker/handlers.d.ts +5 -4
  111. package/build/src/worker/handlers.d.ts.map +1 -1
  112. package/build/src/worker/handlers.js +238 -202
  113. package/build/src/worker/handlers.js.map +1 -1
  114. package/build/src/worker/index.d.ts +2 -2
  115. package/build/src/worker/index.d.ts.map +1 -1
  116. package/build/src/worker/index.js +37 -9
  117. package/build/src/worker/index.js.map +1 -1
  118. package/build/src/worker/interpreters/ntfy-json.d.ts +2 -2
  119. package/build/src/worker/interpreters/ntfy-json.d.ts.map +1 -1
  120. package/build/src/worker/interpreters/ntfy-json.js.map +1 -1
  121. package/build/src/worker/interpreters/pfsense.d.ts +2 -2
  122. package/build/src/worker/interpreters/pfsense.d.ts.map +1 -1
  123. package/build/src/worker/interpreters/pfsense.js +20 -27
  124. package/build/src/worker/interpreters/pfsense.js.map +1 -1
  125. package/build/src/worker/interpreters/plain-text.d.ts +2 -2
  126. package/build/src/worker/interpreters/plain-text.d.ts.map +1 -1
  127. package/build/src/worker/interpreters/plain-text.js.map +1 -1
  128. package/build/src/worker/interpreters/seerr.d.ts +2 -2
  129. package/build/src/worker/interpreters/seerr.d.ts.map +1 -1
  130. package/build/src/worker/interpreters/seerr.js +16 -12
  131. package/build/src/worker/interpreters/seerr.js.map +1 -1
  132. package/build/src/worker/interpreters/statuspage.d.ts +2 -2
  133. package/build/src/worker/interpreters/statuspage.d.ts.map +1 -1
  134. package/build/src/worker/interpreters/statuspage.js +98 -47
  135. package/build/src/worker/interpreters/statuspage.js.map +1 -1
  136. package/build/src/worker/interpreters/synology.d.ts +2 -2
  137. package/build/src/worker/interpreters/synology.d.ts.map +1 -1
  138. package/build/src/worker/interpreters/synology.js +9 -5
  139. package/build/src/worker/interpreters/synology.js.map +1 -1
  140. package/build/src/worker/interpreters/unifi.d.ts +2 -2
  141. package/build/src/worker/interpreters/unifi.d.ts.map +1 -1
  142. package/build/src/worker/interpreters/unifi.js +34 -20
  143. package/build/src/worker/interpreters/unifi.js.map +1 -1
  144. package/build/src/worker/landing/page.d.ts +2 -2
  145. package/build/src/worker/landing/page.d.ts.map +1 -1
  146. package/build/src/worker/landing/page.js +4 -3
  147. package/build/src/worker/landing/page.js.map +1 -1
  148. package/build/src/worker/pipeline/accumulate.d.ts +5 -6
  149. package/build/src/worker/pipeline/accumulate.d.ts.map +1 -1
  150. package/build/src/worker/pipeline/accumulate.js +4 -11
  151. package/build/src/worker/pipeline/accumulate.js.map +1 -1
  152. package/build/src/worker/pipeline/authenticate.d.ts +2 -2
  153. package/build/src/worker/pipeline/authenticate.d.ts.map +1 -1
  154. package/build/src/worker/pipeline/authenticate.js +25 -7
  155. package/build/src/worker/pipeline/authenticate.js.map +1 -1
  156. package/build/src/worker/pipeline/email.d.ts +2 -2
  157. package/build/src/worker/pipeline/email.d.ts.map +1 -1
  158. package/build/src/worker/pipeline/email.js +34 -11
  159. package/build/src/worker/pipeline/email.js.map +1 -1
  160. package/build/src/worker/pipeline/format.d.ts +2 -3
  161. package/build/src/worker/pipeline/format.d.ts.map +1 -1
  162. package/build/src/worker/pipeline/format.js +2 -1
  163. package/build/src/worker/pipeline/format.js.map +1 -1
  164. package/build/src/worker/pipeline/interpret.d.ts +4 -3
  165. package/build/src/worker/pipeline/interpret.d.ts.map +1 -1
  166. package/build/src/worker/pipeline/interpret.js +7 -7
  167. package/build/src/worker/pipeline/interpret.js.map +1 -1
  168. package/build/src/worker/pipeline/parse.d.ts +2 -2
  169. package/build/src/worker/pipeline/parse.d.ts.map +1 -1
  170. package/build/src/worker/pipeline/parse.js +14 -7
  171. package/build/src/worker/pipeline/parse.js.map +1 -1
  172. package/build/src/worker/pipeline/receive.d.ts +2 -2
  173. package/build/src/worker/pipeline/receive.d.ts.map +1 -1
  174. package/build/src/worker/pipeline/receive.js +6 -6
  175. package/build/src/worker/pipeline/receive.js.map +1 -1
  176. package/build/src/worker/pipeline/respond.d.ts +2 -2
  177. package/build/src/worker/pipeline/respond.d.ts.map +1 -1
  178. package/build/src/worker/pipeline/respond.js +1 -1
  179. package/build/src/worker/pipeline/respond.js.map +1 -1
  180. package/build/src/worker/pipeline/route.d.ts +2 -3
  181. package/build/src/worker/pipeline/route.d.ts.map +1 -1
  182. package/build/src/worker/pipeline/route.js.map +1 -1
  183. package/build/src/worker/pipeline/send.d.ts +2 -2
  184. package/build/src/worker/pipeline/send.d.ts.map +1 -1
  185. package/build/src/worker/pipeline/send.js +80 -41
  186. package/build/src/worker/pipeline/send.js.map +1 -1
  187. package/build/src/worker/pipeline/split.d.ts +2 -2
  188. package/build/src/worker/pipeline/split.d.ts.map +1 -1
  189. package/build/src/worker/pipeline/split.js +4 -2
  190. package/build/src/worker/pipeline/split.js.map +1 -1
  191. package/package.json +11 -9
  192. package/build/src/types/tests/type-declarations.test.d.ts +0 -173
  193. package/build/src/types/worker/pipeline/shared.d.ts +0 -85
@@ -1,6 +1,6 @@
1
- import { existsSync, readFileSync } from 'fs';
2
- import { dirname, join } from 'path';
3
- import { fileURLToPath } from 'url';
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
4
  import { Bootstrap, CLIHeader, Logger } from '@cbnventures/nova/toolkit';
5
5
  import chalk from 'chalk';
6
6
  import prompts from 'prompts';
@@ -64,19 +64,24 @@ async function interactiveMenu(configDirs) {
64
64
  message: chalk.cyan('What would you like to do?'),
65
65
  choices: [
66
66
  {
67
- title: 'Manage Servers', value: 'servers',
67
+ title: 'Manage Servers',
68
+ value: 'servers',
68
69
  },
69
70
  {
70
- title: 'Manage Contexts', value: 'contexts',
71
+ title: 'Manage Contexts',
72
+ value: 'contexts',
71
73
  },
72
74
  {
73
- title: 'Settings', value: 'settings',
75
+ title: 'Settings',
76
+ value: 'settings',
74
77
  },
75
78
  {
76
- title: 'Deploy', value: 'deploy',
79
+ title: 'Deploy',
80
+ value: 'deploy',
77
81
  },
78
82
  {
79
- title: 'Exit', value: 'exit',
83
+ title: 'Exit',
84
+ value: 'exit',
80
85
  },
81
86
  ],
82
87
  });
@@ -115,16 +120,20 @@ async function serverMenu(configPath) {
115
120
  message: chalk.cyan('Manage Servers'),
116
121
  choices: [
117
122
  {
118
- title: 'Add', value: 'add',
123
+ title: 'Add',
124
+ value: 'add',
119
125
  },
120
126
  {
121
- title: 'Edit', value: 'edit',
127
+ title: 'Edit',
128
+ value: 'edit',
122
129
  },
123
130
  {
124
- title: 'Remove', value: 'remove',
131
+ title: 'Remove',
132
+ value: 'remove',
125
133
  },
126
134
  {
127
- title: 'Back', value: 'back',
135
+ title: chalk.dim('Go back'),
136
+ value: 'back',
128
137
  },
129
138
  ],
130
139
  });
@@ -198,12 +207,19 @@ async function serverMenu(configPath) {
198
207
  type: 'select',
199
208
  name: 'name',
200
209
  message: 'Select server to edit:',
201
- choices: servers.map((server) => ({
202
- title: server['name'], value: server['name'],
203
- })),
210
+ choices: [
211
+ ...servers.map((server) => ({
212
+ title: server['name'],
213
+ value: server['name'],
214
+ })),
215
+ {
216
+ title: chalk.dim('Go back'),
217
+ value: 'back',
218
+ },
219
+ ],
204
220
  });
205
221
  const name = selectResponse['name'];
206
- if (name !== undefined) {
222
+ if (name !== undefined && name !== 'back') {
207
223
  const current = servers.find((server) => server['name'] === name);
208
224
  const currentServer = (current !== undefined) ? current['server'] : undefined;
209
225
  const updates = await prompts([
@@ -217,8 +233,8 @@ async function serverMenu(configPath) {
217
233
  return 'URL must start with https://';
218
234
  }
219
235
  try {
220
- const urlInstance = new URL(value);
221
- void urlInstance;
236
+ const editUrlInstance = new URL(value);
237
+ void editUrlInstance;
222
238
  return true;
223
239
  }
224
240
  catch {
@@ -240,6 +256,9 @@ async function serverMenu(configPath) {
240
256
  },
241
257
  },
242
258
  ]);
259
+ if (updates['server'] === undefined || updates['token'] === undefined) {
260
+ continue;
261
+ }
243
262
  const editImport = await import('../commands/server.js');
244
263
  const updatesServerString = updates['server'];
245
264
  const serverUrlTrimmed = updatesServerString.trim();
@@ -262,45 +281,52 @@ async function serverMenu(configPath) {
262
281
  }
263
282
  }
264
283
  catch (error) {
265
- const errorMessage = (error instanceof Error) ? error['message'] : String(error);
266
- Logger.error(`Error: ${errorMessage}`);
284
+ const editErrorMessage = (error instanceof Error) ? error['message'] : String(error);
285
+ Logger.error(`Error: ${editErrorMessage}`);
267
286
  }
268
287
  }
269
288
  else if (action === 'remove') {
270
289
  try {
271
- const servers = listServers(configPath);
272
- servers.sort((a, b) => a['name'].localeCompare(b['name']));
273
- if (servers['length'] === 0) {
290
+ const removeServers = listServers(configPath);
291
+ removeServers.sort((a, b) => a['name'].localeCompare(b['name']));
292
+ if (removeServers['length'] === 0) {
274
293
  Logger.warn('No servers to remove.');
275
294
  }
276
295
  else {
277
- const selectResponse = await prompts({
296
+ const removeSelectResponse = await prompts({
278
297
  type: 'select',
279
298
  name: 'name',
280
299
  message: 'Select server to remove:',
281
- choices: servers.map((server) => ({
282
- title: server['name'], value: server['name'],
283
- })),
300
+ choices: [
301
+ ...removeServers.map((server) => ({
302
+ title: server['name'],
303
+ value: server['name'],
304
+ })),
305
+ {
306
+ title: chalk.dim('Go back'),
307
+ value: 'back',
308
+ },
309
+ ],
284
310
  });
285
- const name = selectResponse['name'];
286
- if (name !== undefined) {
311
+ const removeName = removeSelectResponse['name'];
312
+ if (removeName !== undefined && removeName !== 'back') {
287
313
  const confirmResponse = await prompts({
288
314
  type: 'confirm',
289
315
  name: 'confirmed',
290
- message: chalk.yellow(`Remove "${name}"?`),
316
+ message: chalk.yellow(`Remove "${removeName}"?`),
291
317
  initial: false,
292
318
  });
293
319
  const confirmed = confirmResponse['confirmed'];
294
320
  if (confirmed === true) {
295
- removeServer(configPath, name);
296
- Logger.info(`Server "${name}" removed.`);
321
+ removeServer(configPath, removeName);
322
+ Logger.info(`Server "${removeName}" removed.`);
297
323
  }
298
324
  }
299
325
  }
300
326
  }
301
327
  catch (error) {
302
- const errorMessage = (error instanceof Error) ? error['message'] : String(error);
303
- Logger.error(`Error: ${errorMessage}`);
328
+ const removeErrorMessage = (error instanceof Error) ? error['message'] : String(error);
329
+ Logger.error(`Error: ${removeErrorMessage}`);
304
330
  }
305
331
  }
306
332
  }
@@ -315,16 +341,20 @@ async function contextMenu(configPath) {
315
341
  message: chalk.cyan('Manage Contexts'),
316
342
  choices: [
317
343
  {
318
- title: 'Add', value: 'add',
344
+ title: 'Add',
345
+ value: 'add',
319
346
  },
320
347
  {
321
- title: 'Edit', value: 'edit',
348
+ title: 'Edit',
349
+ value: 'edit',
322
350
  },
323
351
  {
324
- title: 'Remove', value: 'remove',
352
+ title: 'Remove',
353
+ value: 'remove',
325
354
  },
326
355
  {
327
- title: 'Back', value: 'back',
356
+ title: chalk.dim('Go back'),
357
+ value: 'back',
328
358
  },
329
359
  ],
330
360
  });
@@ -360,17 +390,25 @@ async function contextMenu(configPath) {
360
390
  type: 'select',
361
391
  name: 'name',
362
392
  message: 'Select context to edit:',
363
- choices: contexts.map((context) => ({
364
- title: context['name'], value: context['name'],
365
- })),
393
+ choices: [
394
+ ...contexts.map((context) => ({
395
+ title: context['name'],
396
+ value: context['name'],
397
+ })),
398
+ {
399
+ title: chalk.dim('Go back'),
400
+ value: 'back',
401
+ },
402
+ ],
366
403
  });
367
404
  const name = selectResponse['name'];
368
- if (name !== undefined) {
405
+ if (name !== undefined && name !== 'back') {
369
406
  const current = contexts.find((context) => context['name'] === name);
370
407
  if (current !== undefined) {
371
- const servers = listServers(configPath);
372
- const serverChoices = servers.map((server) => ({
373
- title: server['name'], value: server['name'],
408
+ const editServers = listServers(configPath);
409
+ const serverChoices = editServers.map((server) => ({
410
+ title: server['name'],
411
+ value: server['name'],
374
412
  }));
375
413
  const keepIdResponse = await prompts({
376
414
  type: 'confirm',
@@ -379,6 +417,9 @@ async function contextMenu(configPath) {
379
417
  initial: true,
380
418
  });
381
419
  const keepId = keepIdResponse['keepId'];
420
+ if (keepId === undefined) {
421
+ continue;
422
+ }
382
423
  let id = undefined;
383
424
  if (keepId === false) {
384
425
  id = generateId();
@@ -386,37 +427,46 @@ async function contextMenu(configPath) {
386
427
  }
387
428
  const httpChoices = [
388
429
  {
389
- title: 'Plain Text', value: 'plain-text',
430
+ title: 'Plain Text',
431
+ value: 'plain-text',
390
432
  },
391
433
  {
392
- title: 'ntfy JSON', value: 'ntfy-json',
434
+ title: 'ntfy JSON',
435
+ value: 'ntfy-json',
393
436
  },
394
437
  {
395
- title: 'Seerr', value: 'seerr',
438
+ title: 'Seerr',
439
+ value: 'seerr',
396
440
  },
397
441
  {
398
- title: 'Synology DSM', value: 'synology',
442
+ title: 'Synology DSM',
443
+ value: 'synology',
399
444
  },
400
445
  {
401
- title: 'Statuspage.io', value: 'statuspage',
446
+ title: 'Statuspage.io',
447
+ value: 'statuspage',
402
448
  },
403
449
  ];
404
450
  const emailChoices = [
405
451
  {
406
- title: 'Plain Text', value: 'plain-text',
452
+ title: 'Plain Text',
453
+ value: 'plain-text',
407
454
  },
408
455
  {
409
- title: 'pfSense', value: 'pfsense',
456
+ title: 'pfSense',
457
+ value: 'pfsense',
410
458
  },
411
459
  {
412
- title: 'UniFi', value: 'unifi',
460
+ title: 'UniFi',
461
+ value: 'unifi',
413
462
  },
414
463
  ];
415
464
  const knownChoices = (current['type'] === 'http') ? httpChoices : emailChoices;
416
465
  const exists = knownChoices.some((c) => c['value'] === current['interpreter']);
417
466
  if (exists === false) {
418
467
  knownChoices.unshift({
419
- title: `${current['interpreter']} (current, unknown)`, value: current['interpreter'],
468
+ title: `${current['interpreter']} (current, unknown)`,
469
+ value: current['interpreter'],
420
470
  });
421
471
  }
422
472
  const httpValues = [
@@ -442,6 +492,9 @@ async function contextMenu(configPath) {
442
492
  initial: interpreterInitial,
443
493
  });
444
494
  const interpreter = interpreterResponse['interpreter'];
495
+ if (interpreter === undefined) {
496
+ continue;
497
+ }
445
498
  const topicResponse = await prompts({
446
499
  type: 'text',
447
500
  name: 'topic',
@@ -450,6 +503,9 @@ async function contextMenu(configPath) {
450
503
  validate: (value) => value.trim()['length'] > 0 || 'Topic is required',
451
504
  });
452
505
  const topic = topicResponse['topic'];
506
+ if (topic === undefined) {
507
+ continue;
508
+ }
453
509
  const currentErrorTopic = (current['error_topic'] !== undefined) ? current['error_topic'] : '';
454
510
  const errorTopicResponse = await prompts({
455
511
  type: 'text',
@@ -458,6 +514,31 @@ async function contextMenu(configPath) {
458
514
  initial: currentErrorTopic,
459
515
  });
460
516
  const errorTopic = errorTopicResponse['error_topic'];
517
+ if (errorTopic === undefined) {
518
+ continue;
519
+ }
520
+ const currentErrorEvents = current['error_events'];
521
+ const errorEventsResponse = await prompts({
522
+ type: 'multiselect',
523
+ name: 'error_events',
524
+ message: 'Errors that notify the error topic (space to select):',
525
+ choices: [
526
+ {
527
+ title: 'Authentication (failed auth, scanner traffic)',
528
+ value: 'authentication',
529
+ selected: currentErrorEvents === undefined || currentErrorEvents.includes('authentication'),
530
+ },
531
+ {
532
+ title: 'Interpretation (interpreter errors)',
533
+ value: 'interpretation',
534
+ selected: currentErrorEvents === undefined || currentErrorEvents.includes('interpretation'),
535
+ },
536
+ ],
537
+ });
538
+ const errorEvents = errorEventsResponse['error_events'];
539
+ if (errorEvents === undefined) {
540
+ continue;
541
+ }
461
542
  const modeInitial = (current['mode'] === 'send-all') ? 1 : 0;
462
543
  const modeResponse = await prompts({
463
544
  type: 'select',
@@ -465,15 +546,20 @@ async function contextMenu(configPath) {
465
546
  message: 'Mode:',
466
547
  choices: [
467
548
  {
468
- title: 'Send to one server only', value: 'send-once',
549
+ title: 'Send to one server only',
550
+ value: 'send-once',
469
551
  },
470
552
  {
471
- title: 'Send to all servers', value: 'send-all',
553
+ title: 'Send to all servers',
554
+ value: 'send-all',
472
555
  },
473
556
  ],
474
557
  initial: modeInitial,
475
558
  });
476
559
  const mode = modeResponse['mode'];
560
+ if (mode === undefined) {
561
+ continue;
562
+ }
477
563
  const showVisitorInfoResponse = await prompts({
478
564
  type: 'confirm',
479
565
  name: 'show_visitor_info',
@@ -481,10 +567,14 @@ async function contextMenu(configPath) {
481
567
  initial: current['show_visitor_info'],
482
568
  });
483
569
  const showVisitorInfo = showVisitorInfoResponse['show_visitor_info'];
570
+ if (showVisitorInfo === undefined) {
571
+ continue;
572
+ }
484
573
  const primaryServerIdx = serverChoices.findIndex((s) => s['value'] === current['primary_server']);
485
574
  if (primaryServerIdx < 0) {
486
575
  serverChoices.unshift({
487
- title: `${current['primary_server']} (current, not found)`, value: current['primary_server'],
576
+ title: `${current['primary_server']} (current, not found)`,
577
+ value: current['primary_server'],
488
578
  });
489
579
  }
490
580
  const primaryServerInitial = (primaryServerIdx >= 0) ? primaryServerIdx : 0;
@@ -496,6 +586,9 @@ async function contextMenu(configPath) {
496
586
  initial: primaryServerInitial,
497
587
  });
498
588
  const primaryServer = primaryServerResponse['primary_server'];
589
+ if (primaryServer === undefined) {
590
+ continue;
591
+ }
499
592
  const selectedServersResponse = await prompts({
500
593
  type: 'multiselect',
501
594
  name: 'selectedServers',
@@ -506,6 +599,9 @@ async function contextMenu(configPath) {
506
599
  })),
507
600
  });
508
601
  const selectedServers = selectedServersResponse['selectedServers'];
602
+ if (selectedServers === undefined) {
603
+ continue;
604
+ }
509
605
  const updates = {};
510
606
  if (id !== undefined) {
511
607
  Reflect.set(updates, 'id', id);
@@ -531,7 +627,12 @@ async function contextMenu(configPath) {
531
627
  const errorTopicValue = errorTopic;
532
628
  const errorTopicTrimmed = (errorTopicValue !== undefined) ? errorTopicValue.trim() : '';
533
629
  const resolvedErrorTopic = (errorTopicTrimmed !== '') ? errorTopicTrimmed : undefined;
534
- Reflect.set(updates, 'error_topic', resolvedErrorTopic);
630
+ if (errorTopic !== undefined) {
631
+ Reflect.set(updates, 'error_topic', resolvedErrorTopic);
632
+ }
633
+ if (errorEvents !== undefined) {
634
+ Reflect.set(updates, 'error_events', errorEvents);
635
+ }
535
636
  if (current['type'] === 'http' && current['token'] !== undefined) {
536
637
  const keepTokenResponse = await prompts({
537
638
  type: 'confirm',
@@ -540,6 +641,9 @@ async function contextMenu(configPath) {
540
641
  initial: true,
541
642
  });
542
643
  const keepToken = keepTokenResponse['keepToken'];
644
+ if (keepToken === undefined) {
645
+ continue;
646
+ }
543
647
  if (keepToken === false) {
544
648
  const newToken = generateToken();
545
649
  Reflect.set(updates, 'token', newToken);
@@ -554,10 +658,13 @@ async function contextMenu(configPath) {
554
658
  initial: false,
555
659
  });
556
660
  const addToken = addTokenResponse['addToken'];
661
+ if (addToken === undefined) {
662
+ continue;
663
+ }
557
664
  if (addToken === true) {
558
- const newToken = generateToken();
559
- Reflect.set(updates, 'token', newToken);
560
- Logger.info(` New token: ${newToken}`);
665
+ const addNewToken = generateToken();
666
+ Reflect.set(updates, 'token', addNewToken);
667
+ Logger.info(` New token: ${addNewToken}`);
561
668
  }
562
669
  }
563
670
  else if (current['type'] === 'email') {
@@ -569,9 +676,14 @@ async function contextMenu(configPath) {
569
676
  initial: currentAllowedFrom,
570
677
  });
571
678
  const allowedFrom = allowedFromResponse['allowed_from'];
679
+ if (allowedFrom === undefined) {
680
+ continue;
681
+ }
572
682
  const allowedFromTrimmed = (allowedFrom !== undefined) ? allowedFrom.trim() : '';
573
683
  const resolvedAllowedFrom = (allowedFromTrimmed !== '') ? allowedFromTrimmed : undefined;
574
- Reflect.set(updates, 'allowed_from', resolvedAllowedFrom);
684
+ if (allowedFrom !== undefined) {
685
+ Reflect.set(updates, 'allowed_from', resolvedAllowedFrom);
686
+ }
575
687
  }
576
688
  const editImport = await import('../commands/context.js');
577
689
  editImport.editContext(configPath, name, updates);
@@ -581,45 +693,52 @@ async function contextMenu(configPath) {
581
693
  }
582
694
  }
583
695
  catch (error) {
584
- const errorMessage = (error instanceof Error) ? error['message'] : String(error);
585
- Logger.error(`Error: ${errorMessage}`);
696
+ const editErrorMessage = (error instanceof Error) ? error['message'] : String(error);
697
+ Logger.error(`Error: ${editErrorMessage}`);
586
698
  }
587
699
  }
588
700
  else if (action === 'remove') {
589
701
  try {
590
- const contexts = listContexts(configPath);
591
- contexts.sort((a, b) => a['name'].localeCompare(b['name']));
592
- if (contexts['length'] === 0) {
702
+ const removeContexts = listContexts(configPath);
703
+ removeContexts.sort((a, b) => a['name'].localeCompare(b['name']));
704
+ if (removeContexts['length'] === 0) {
593
705
  Logger.warn('No contexts to remove.');
594
706
  }
595
707
  else {
596
- const selectResponse = await prompts({
708
+ const removeSelectResponse = await prompts({
597
709
  type: 'select',
598
710
  name: 'name',
599
711
  message: 'Select context to remove:',
600
- choices: contexts.map((context) => ({
601
- title: context['name'], value: context['name'],
602
- })),
712
+ choices: [
713
+ ...removeContexts.map((context) => ({
714
+ title: context['name'],
715
+ value: context['name'],
716
+ })),
717
+ {
718
+ title: chalk.dim('Go back'),
719
+ value: 'back',
720
+ },
721
+ ],
603
722
  });
604
- const name = selectResponse['name'];
605
- if (name !== undefined) {
723
+ const removeName = removeSelectResponse['name'];
724
+ if (removeName !== undefined && removeName !== 'back') {
606
725
  const confirmResponse = await prompts({
607
726
  type: 'confirm',
608
727
  name: 'confirmed',
609
- message: chalk.yellow(`Remove "${name}"?`),
728
+ message: chalk.yellow(`Remove "${removeName}"?`),
610
729
  initial: false,
611
730
  });
612
731
  const confirmed = confirmResponse['confirmed'];
613
732
  if (confirmed === true) {
614
- removeContext(configPath, name);
615
- Logger.info(`Context "${name}" removed.`);
733
+ removeContext(configPath, removeName);
734
+ Logger.info(`Context "${removeName}" removed.`);
616
735
  }
617
736
  }
618
737
  }
619
738
  }
620
739
  catch (error) {
621
- const errorMessage = (error instanceof Error) ? error['message'] : String(error);
622
- Logger.error(`Error: ${errorMessage}`);
740
+ const removeErrorMessage = (error instanceof Error) ? error['message'] : String(error);
741
+ Logger.error(`Error: ${removeErrorMessage}`);
623
742
  }
624
743
  }
625
744
  }
@@ -633,10 +752,12 @@ async function addContextFlow(configPath, servers) {
633
752
  message: 'Context type:',
634
753
  choices: [
635
754
  {
636
- title: 'HTTP', value: 'http',
755
+ title: 'HTTP',
756
+ value: 'http',
637
757
  },
638
758
  {
639
- title: 'Email', value: 'email',
759
+ title: 'Email',
760
+ value: 'email',
640
761
  },
641
762
  ],
642
763
  });
@@ -646,30 +767,38 @@ async function addContextFlow(configPath, servers) {
646
767
  }
647
768
  const httpInterpreters = [
648
769
  {
649
- title: 'Plain Text', value: 'plain-text',
770
+ title: 'Plain Text',
771
+ value: 'plain-text',
650
772
  },
651
773
  {
652
- title: 'ntfy JSON', value: 'ntfy-json',
774
+ title: 'ntfy JSON',
775
+ value: 'ntfy-json',
653
776
  },
654
777
  {
655
- title: 'Seerr', value: 'seerr',
778
+ title: 'Seerr',
779
+ value: 'seerr',
656
780
  },
657
781
  {
658
- title: 'Synology DSM', value: 'synology',
782
+ title: 'Synology DSM',
783
+ value: 'synology',
659
784
  },
660
785
  {
661
- title: 'Statuspage.io', value: 'statuspage',
786
+ title: 'Statuspage.io',
787
+ value: 'statuspage',
662
788
  },
663
789
  ];
664
790
  const emailInterpreters = [
665
791
  {
666
- title: 'Plain Text', value: 'plain-text',
792
+ title: 'Plain Text',
793
+ value: 'plain-text',
667
794
  },
668
795
  {
669
- title: 'pfSense', value: 'pfsense',
796
+ title: 'pfSense',
797
+ value: 'pfsense',
670
798
  },
671
799
  {
672
- title: 'UniFi', value: 'unifi',
800
+ title: 'UniFi',
801
+ value: 'unifi',
673
802
  },
674
803
  ];
675
804
  const nameResponse = await prompts({
@@ -731,16 +860,42 @@ async function addContextFlow(configPath, servers) {
731
860
  message: 'ntfy error topic (blank to skip):',
732
861
  });
733
862
  const errorTopic = errorTopicResponse['error_topic'];
863
+ if (errorTopic === undefined) {
864
+ return;
865
+ }
866
+ const errorEventsResponse = await prompts({
867
+ type: 'multiselect',
868
+ name: 'error_events',
869
+ message: 'Errors that notify the error topic (space to select):',
870
+ choices: [
871
+ {
872
+ title: 'Authentication (failed auth, scanner traffic)',
873
+ value: 'authentication',
874
+ selected: true,
875
+ },
876
+ {
877
+ title: 'Interpretation (interpreter errors)',
878
+ value: 'interpretation',
879
+ selected: true,
880
+ },
881
+ ],
882
+ });
883
+ const errorEvents = errorEventsResponse['error_events'];
884
+ if (errorEvents === undefined) {
885
+ return;
886
+ }
734
887
  const modeResponse = await prompts({
735
888
  type: 'select',
736
889
  name: 'mode',
737
890
  message: 'Mode:',
738
891
  choices: [
739
892
  {
740
- title: 'Send to one server only', value: 'send-once',
893
+ title: 'Send to one server only',
894
+ value: 'send-once',
741
895
  },
742
896
  {
743
- title: 'Send to all servers', value: 'send-all',
897
+ title: 'Send to all servers',
898
+ value: 'send-all',
744
899
  },
745
900
  ],
746
901
  });
@@ -763,7 +918,8 @@ async function addContextFlow(configPath, servers) {
763
918
  name: 'primary_server',
764
919
  message: 'Primary server:',
765
920
  choices: servers.map((server) => ({
766
- title: server['name'], value: server['name'],
921
+ title: server['name'],
922
+ value: server['name'],
767
923
  })),
768
924
  });
769
925
  const primaryServer = primaryServerResponse['primary_server'];
@@ -775,7 +931,8 @@ async function addContextFlow(configPath, servers) {
775
931
  name: 'selectedServers',
776
932
  message: 'All servers for this context (space to select):',
777
933
  choices: servers.map((server) => ({
778
- title: server['name'], value: server['name'],
934
+ title: server['name'],
935
+ value: server['name'],
779
936
  })),
780
937
  });
781
938
  const selectedServers = selectedServersResponse['selectedServers'];
@@ -791,6 +948,7 @@ async function addContextFlow(configPath, servers) {
791
948
  const topicString = topic;
792
949
  const typedInterpreter = interpreter;
793
950
  const typedMode = mode;
951
+ const typedErrorEvents = errorEvents;
794
952
  if (contextType === 'http') {
795
953
  const autoToken = generateToken();
796
954
  const tokenResponse = await prompts({
@@ -800,6 +958,9 @@ async function addContextFlow(configPath, servers) {
800
958
  initial: autoToken,
801
959
  });
802
960
  const rawToken = tokenResponse['token'];
961
+ if (rawToken === undefined) {
962
+ return;
963
+ }
803
964
  const tokenTrimmed = (rawToken !== undefined) ? rawToken.trim() : '';
804
965
  const resolvedToken = (tokenTrimmed !== '') ? tokenTrimmed : undefined;
805
966
  addContext(configPath, {
@@ -809,6 +970,7 @@ async function addContextFlow(configPath, servers) {
809
970
  interpreter: typedInterpreter,
810
971
  topic: topicString,
811
972
  error_topic: resolvedErrorTopic,
973
+ error_events: typedErrorEvents,
812
974
  mode: typedMode,
813
975
  show_visitor_info: showVisitorInfo,
814
976
  primary_server: primaryServer,
@@ -823,6 +985,9 @@ async function addContextFlow(configPath, servers) {
823
985
  message: 'Allowed from email (blank to skip):',
824
986
  });
825
987
  const rawAllowedFrom = allowedFromResponse['allowed_from'];
988
+ if (rawAllowedFrom === undefined) {
989
+ return;
990
+ }
826
991
  const allowedFromTrimmed = (rawAllowedFrom !== undefined) ? rawAllowedFrom.trim() : '';
827
992
  const resolvedAllowedFrom = (allowedFromTrimmed !== '') ? allowedFromTrimmed : undefined;
828
993
  addContext(configPath, {
@@ -832,6 +997,7 @@ async function addContextFlow(configPath, servers) {
832
997
  interpreter: typedInterpreter,
833
998
  topic: topicString,
834
999
  error_topic: resolvedErrorTopic,
1000
+ error_events: typedErrorEvents,
835
1001
  mode: typedMode,
836
1002
  show_visitor_info: showVisitorInfo,
837
1003
  primary_server: primaryServer,
@@ -893,8 +1059,8 @@ async function settingsFlow(configPath) {
893
1059
  Logger.info('Settings updated.');
894
1060
  }
895
1061
  catch (error) {
896
- const errorMessage = (error instanceof Error) ? error['message'] : String(error);
897
- Logger.error(`Error: ${errorMessage}`);
1062
+ const updateErrorMessage = (error instanceof Error) ? error['message'] : String(error);
1063
+ Logger.error(`Error: ${updateErrorMessage}`);
898
1064
  }
899
1065
  return;
900
1066
  }