@n42/cli 0.2.32 → 0.2.42

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 CHANGED
@@ -1,4 +1,4 @@
1
- # Node42 CLI (n42)
1
+ # Node42 CLI
2
2
 
3
3
  Command-line interface for **eDelivery discovery, diagnostics, and
4
4
  validation**, with support for the Peppol network.
@@ -7,7 +7,11 @@ The Node42 CLI is designed for **system integrators, service providers,
7
7
  and operators** who need fast, repeatable insight into eDelivery
8
8
  routing, SML/SMK, SMP resolution, and Access Point behavior.
9
9
 
10
- ------------------------------------------------------------------------
10
+ While Node42's toolset **includes** modules capable of constructing and **sending
11
+ standards-compliant messages**, it is **intended for diagnostics**, validation,
12
+ and testing — not for production message exchange.
13
+
14
+
11
15
 
12
16
  ## Features
13
17
 
@@ -128,9 +132,15 @@ Artefacts are stored under:
128
132
 
129
133
  ## Error Handling
130
134
 
131
- Errors are printed with a clickable reference link:
135
+ Errors are printed with a clickable reference link.
132
136
 
133
- https://www.node42.dev/errors?code=XXXX
137
+ Example output:
138
+
139
+ ``` bash
140
+ Error: 9031 [View details]
141
+
142
+ Invalid token: the authorization token provided is invalid
143
+ ```
134
144
 
135
145
  ## Security
136
146
 
@@ -139,4 +149,9 @@ Errors are printed with a clickable reference link:
139
149
 
140
150
  ## License
141
151
 
142
- MIT License
152
+ MIT License
153
+
154
+ ## Author
155
+
156
+ Alex Olsson \
157
+ Node42
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@n42/cli",
3
- "version": "0.2.32",
3
+ "version": "0.2.42",
4
4
  "description": "Node42 CLI – Command-line interface for Peppol eDelivery path discovery, diagnostics, and tooling",
5
5
  "keywords": [
6
6
  "node42", "peppol", "edelivery", "diagnostics",
package/src/auth.js CHANGED
@@ -7,11 +7,54 @@ const { ask, startSpinner } = require("./utils");
7
7
  const db = require("./db");
8
8
  const C = require("./colors");
9
9
 
10
+ function setApiKey(userId, key) {
11
+ if (!key) return;
12
+
13
+ const database = db.load();
14
+
15
+ const u = database.user.find(x => x.id === userId);
16
+ if (!u) return;
17
+
18
+ u.apiKey = {
19
+ "value": key,
20
+ "createdAt": Date.now()
21
+ }
22
+
23
+ db.save(database);
24
+ }
25
+
26
+ function getApiKey(userId) {
27
+ const database = db.load();
28
+
29
+ const u = database.user.find(x => x.id === userId);
30
+ if (!u || !u.apiKey) return null;
31
+
32
+ return u.apiKey.value;
33
+ }
34
+
35
+ function removeApiKey(userId) {
36
+ const database = db.load();
37
+
38
+ const u = database.user.find(x => x.id === userId);
39
+ if (!u || !u.apiKey) return false;
40
+
41
+ delete u.apiKey;
42
+ db.save(database);
43
+
44
+ return true;
45
+ }
10
46
 
11
47
  async function login() {
12
48
  console.log(`${C.BOLD}Sign in to your account${C.RESET}`);
13
49
  let user = getUserWithIndex(0);
14
50
 
51
+ const apiKey = getApiKey(user.id);
52
+ if (apiKey) {
53
+ console.log(`\n${C.RED}API key authentication is configured.${C.RESET}`);
54
+ console.log(`Login is not required.\n`);
55
+ return;
56
+ }
57
+
15
58
  const username = await ask("Username", user.userMail ?? "");
16
59
  const password = await ask("Password", null, true);
17
60
  console.log();
@@ -158,21 +201,33 @@ async function refreshSession() {
158
201
  }
159
202
 
160
203
  async function fetchWithAuth(url, options = {}) {
204
+ const user = getUserWithIndex(0);
205
+ const apiKey = user ? getApiKey(user.id) : null;
206
+
161
207
  let { accessToken } = loadTokens();
162
- if (!accessToken) {
208
+
209
+ if (!accessToken && !apiKey) {
163
210
  handleError({ code: "N42E-9032" });
164
- return;
211
+ return null;
212
+ }
213
+
214
+ if (apiKey) {
215
+ console.log(`${C.DIM}Authenticating with API key.${C.RESET}\n`);
165
216
  }
166
217
 
167
218
  const res = await fetch(url, {
168
219
  ...options,
169
220
  headers: {
170
221
  ...(options.headers || {}),
171
- ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {})
222
+ ...(accessToken
223
+ ? { Authorization: `Bearer ${accessToken}` }
224
+ : apiKey
225
+ ? { "X-Api-Key": apiKey }
226
+ : {})
172
227
  }
173
228
  });
174
229
 
175
- if (res.status !== 401) {
230
+ if (apiKey || res.status !== 401) {
176
231
  return res;
177
232
  }
178
233
 
@@ -191,4 +246,4 @@ async function fetchWithAuth(url, options = {}) {
191
246
  });
192
247
  }
193
248
 
194
- module.exports = { login, logout, loadTokens, checkAuth, fetchWithAuth };
249
+ module.exports = { setApiKey, getApiKey, removeApiKey, login, logout, loadTokens, checkAuth, fetchWithAuth };
package/src/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const { Command } = require("commander");
4
- const { login, logout, checkAuth } = require("./auth");
4
+ const { login, logout, checkAuth, setApiKey, getApiKey, removeApiKey } = require("./auth");
5
5
  const { getUserWithIndex, getUserUsage } = require("./user");
6
6
  const { runDiscovery } = require("./discover");
7
7
  const { startSpinner, validateEnv, validateId, createAppDirs, capitalize, cleanAppDirs } = require("./utils");
@@ -40,6 +40,42 @@ program
40
40
  console.log(`Run: ${C.BOLD}source ${dest}${C.RESET}\n`);
41
41
  });
42
42
 
43
+ program
44
+ .command("apikey")
45
+ .description("Manage API key authentication")
46
+ .option("--set <key>", "Authenticate using an API key")
47
+ .option("--remove", "Remove stored API key")
48
+ .action((options) => {
49
+ const user = getUserWithIndex(0);
50
+ if (!user) {
51
+ console.error(`${C.RED}No local user context found${C.RESET}`);
52
+ process.exit(1);
53
+ }
54
+
55
+ console.log(`${C.BOLD}Node42 Account${C.RESET} (${user.userMail})\n`);
56
+
57
+ if (options.set) {
58
+ setApiKey(user.id, options.set);
59
+
60
+ if (getApiKey(user.id) === options.set) {
61
+ console.log(`${C.GREEN}API key authentication configured${C.RESET}\n`);
62
+ } else {
63
+ console.log(`${C.RED}API key configuration failed${C.RESET}\n`);
64
+ }
65
+ return;
66
+ }
67
+
68
+ if (options.remove) {
69
+ const removed = removeApiKey(user.id);
70
+ console.log(removed ? `${C.RED}API key removed${C.RESET}\n` : `${C.RED}No API key configured${C.RESET}\n`);
71
+ return;
72
+ }
73
+
74
+ // default: show status
75
+ const apiKey = getApiKey(user.id);
76
+ console.log(apiKey ? `${C.RED}API key configured${C.RESET}\n` : `${C.RED}No API key configured${C.RESET}\n`);
77
+ });
78
+
43
79
  program
44
80
  .command("login")
45
81
  .description("Authenticate using username and password and store tokens locally")
@@ -78,9 +114,8 @@ program
78
114
 
79
115
  const user = getUserWithIndex(0);
80
116
  const currentMonth = new Date().toISOString().slice(0, 7);
81
- console.log(`Node42 Account (CLI v${pkg.version})
117
+ console.log(`Node42 Account: ${C.BOLD}${user.id}${C.RESET}
82
118
  ${C.BOLD}User${C.RESET}
83
- ID : ${C.CYAN}${user.id}${C.RESET}
84
119
  Name : ${user.userName}
85
120
  Email : ${user.userMail}
86
121
  Role : ${user.role}
package/src/errors.js CHANGED
@@ -15,10 +15,12 @@ function handleError(err) {
15
15
  : `${WWW_URL}/errors`;
16
16
  //console.log(url);
17
17
 
18
+ const link = `\u001B]8;;${url}\u0007View details\u001B]8;;\u0007`;
19
+
18
20
  if (message) {
19
- console.error(`\r${C.RED}${err.message}${C.RESET}\nSee details: ${C.BOLD}${url}${C.RESET}\n`);
21
+ console.error(`\r${C.BOLD}Error: ${code}${C.RESET} ${C.BLUE}[${link}]${C.RESET}\n\n${C.RED}${err.message}${C.RESET}\n`);
20
22
  } else {
21
- console.error(`\rSee details: ${C.BOLD}${url}${C.RESET}\n`);
23
+ console.error(`\r${C.BOLD}Error: ${code}${C.RESET} ${C.BLUE}[${url}]${C.RESET}\n\nFor details, see the documentation.\n`);
22
24
  }
23
25
  }
24
26