noxctl 0.1.0 → 0.3.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 +279 -29
- package/dist/auth.d.ts +15 -7
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +128 -22
- package/dist/auth.js.map +1 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1640 -70
- package/dist/cli.js.map +1 -1
- package/dist/completions.d.ts +13 -0
- package/dist/completions.d.ts.map +1 -0
- package/dist/completions.js +150 -0
- package/dist/completions.js.map +1 -0
- package/dist/config-paths.d.ts +2 -0
- package/dist/config-paths.d.ts.map +1 -0
- package/dist/config-paths.js +7 -0
- package/dist/config-paths.js.map +1 -0
- package/dist/credentials-store.d.ts +13 -3
- package/dist/credentials-store.d.ts.map +1 -1
- package/dist/credentials-store.js +197 -62
- package/dist/credentials-store.js.map +1 -1
- package/dist/date-periods.d.ts +14 -0
- package/dist/date-periods.d.ts.map +1 -0
- package/dist/date-periods.js +103 -0
- package/dist/date-periods.js.map +1 -0
- package/dist/formatter.d.ts +11 -2
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +27 -4
- package/dist/formatter.js.map +1 -1
- package/dist/fortnox-client.d.ts +1 -0
- package/dist/fortnox-client.d.ts.map +1 -1
- package/dist/fortnox-client.js +28 -5
- package/dist/fortnox-client.js.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +92 -2
- package/dist/index.js.map +1 -1
- package/dist/keychain-target.d.ts +32 -0
- package/dist/keychain-target.d.ts.map +1 -0
- package/dist/keychain-target.js +349 -0
- package/dist/keychain-target.js.map +1 -0
- package/dist/operations/analytics.d.ts +84 -0
- package/dist/operations/analytics.d.ts.map +1 -0
- package/dist/operations/analytics.js +154 -0
- package/dist/operations/analytics.js.map +1 -0
- package/dist/operations/contracts.d.ts +23 -0
- package/dist/operations/contracts.d.ts.map +1 -0
- package/dist/operations/contracts.js +52 -0
- package/dist/operations/contracts.js.map +1 -0
- package/dist/operations/costcenters.d.ts +20 -0
- package/dist/operations/costcenters.d.ts.map +1 -0
- package/dist/operations/costcenters.js +38 -0
- package/dist/operations/costcenters.js.map +1 -0
- package/dist/operations/customers.d.ts.map +1 -1
- package/dist/operations/customers.js +12 -2
- package/dist/operations/customers.js.map +1 -1
- package/dist/operations/financial-years.d.ts +16 -0
- package/dist/operations/financial-years.d.ts.map +1 -0
- package/dist/operations/financial-years.js +32 -0
- package/dist/operations/financial-years.js.map +1 -0
- package/dist/operations/invoice-payments.d.ts +21 -0
- package/dist/operations/invoice-payments.d.ts.map +1 -0
- package/dist/operations/invoice-payments.js +40 -0
- package/dist/operations/invoice-payments.js.map +1 -0
- package/dist/operations/offers.d.ts +25 -0
- package/dist/operations/offers.d.ts.map +1 -0
- package/dist/operations/offers.js +48 -0
- package/dist/operations/offers.js.map +1 -0
- package/dist/operations/orders.d.ts +24 -0
- package/dist/operations/orders.d.ts.map +1 -0
- package/dist/operations/orders.js +44 -0
- package/dist/operations/orders.js.map +1 -0
- package/dist/operations/pricelists.d.ts +36 -0
- package/dist/operations/pricelists.d.ts.map +1 -0
- package/dist/operations/pricelists.js +52 -0
- package/dist/operations/pricelists.js.map +1 -0
- package/dist/operations/projects.d.ts +19 -0
- package/dist/operations/projects.d.ts.map +1 -0
- package/dist/operations/projects.js +33 -0
- package/dist/operations/projects.js.map +1 -0
- package/dist/operations/supplier-invoice-payments.d.ts +20 -0
- package/dist/operations/supplier-invoice-payments.d.ts.map +1 -0
- package/dist/operations/supplier-invoice-payments.js +34 -0
- package/dist/operations/supplier-invoice-payments.js.map +1 -0
- package/dist/operations/taxreductions.d.ts +19 -0
- package/dist/operations/taxreductions.d.ts.map +1 -0
- package/dist/operations/taxreductions.js +28 -0
- package/dist/operations/taxreductions.js.map +1 -0
- package/dist/operations/vouchers.d.ts +15 -0
- package/dist/operations/vouchers.d.ts.map +1 -1
- package/dist/operations/vouchers.js +97 -0
- package/dist/operations/vouchers.js.map +1 -1
- package/dist/profile-name.d.ts +9 -0
- package/dist/profile-name.d.ts.map +1 -0
- package/dist/profile-name.js +58 -0
- package/dist/profile-name.js.map +1 -0
- package/dist/profiles.d.ts +55 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +210 -0
- package/dist/profiles.js.map +1 -0
- package/dist/tools/analytics.d.ts +3 -0
- package/dist/tools/analytics.d.ts.map +1 -0
- package/dist/tools/analytics.js +52 -0
- package/dist/tools/analytics.js.map +1 -0
- package/dist/tools/bookkeeping.d.ts.map +1 -1
- package/dist/tools/bookkeeping.js +38 -2
- package/dist/tools/bookkeeping.js.map +1 -1
- package/dist/tools/contracts.d.ts +3 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +136 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/costcenters.d.ts +3 -0
- package/dist/tools/costcenters.d.ts.map +1 -0
- package/dist/tools/costcenters.js +79 -0
- package/dist/tools/costcenters.js.map +1 -0
- package/dist/tools/financial-years.d.ts +3 -0
- package/dist/tools/financial-years.d.ts.map +1 -0
- package/dist/tools/financial-years.js +33 -0
- package/dist/tools/financial-years.js.map +1 -0
- package/dist/tools/invoice-payments.d.ts +3 -0
- package/dist/tools/invoice-payments.d.ts.map +1 -0
- package/dist/tools/invoice-payments.js +60 -0
- package/dist/tools/invoice-payments.js.map +1 -0
- package/dist/tools/offers.d.ts +3 -0
- package/dist/tools/offers.d.ts.map +1 -0
- package/dist/tools/offers.js +130 -0
- package/dist/tools/offers.js.map +1 -0
- package/dist/tools/orders.d.ts +3 -0
- package/dist/tools/orders.d.ts.map +1 -0
- package/dist/tools/orders.js +114 -0
- package/dist/tools/orders.js.map +1 -0
- package/dist/tools/pricelists.d.ts +3 -0
- package/dist/tools/pricelists.d.ts.map +1 -0
- package/dist/tools/pricelists.js +104 -0
- package/dist/tools/pricelists.js.map +1 -0
- package/dist/tools/projects.d.ts +3 -0
- package/dist/tools/projects.d.ts.map +1 -0
- package/dist/tools/projects.js +80 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/status.d.ts.map +1 -1
- package/dist/tools/status.js +6 -1
- package/dist/tools/status.js.map +1 -1
- package/dist/tools/supplier-invoice-payments.d.ts +3 -0
- package/dist/tools/supplier-invoice-payments.d.ts.map +1 -0
- package/dist/tools/supplier-invoice-payments.js +60 -0
- package/dist/tools/supplier-invoice-payments.js.map +1 -0
- package/dist/tools/taxreductions.d.ts +3 -0
- package/dist/tools/taxreductions.d.ts.map +1 -0
- package/dist/tools/taxreductions.js +51 -0
- package/dist/tools/taxreductions.js.map +1 -0
- package/dist/views.d.ts +28 -0
- package/dist/views.d.ts.map +1 -1
- package/dist/views.js +234 -0
- package/dist/views.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,11 +3,60 @@ import fsSync from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { execFileSync, spawnSync } from 'node:child_process';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import { DEFAULT_PROFILE, LEGACY_KEYCHAIN_ACCOUNT, keychainAccount, sanitizeForFilename, validateProfileName, } from './profile-name.js';
|
|
7
|
+
import { configDir } from './config-paths.js';
|
|
8
|
+
import { activeKeychainPath, readDedicatedSecret } from './keychain-target.js';
|
|
9
|
+
function legacyCredentialsFile() {
|
|
10
|
+
return path.join(configDir(), 'credentials.json');
|
|
11
|
+
}
|
|
12
|
+
function legacyWindowsCredentialsFile() {
|
|
13
|
+
return path.join(configDir(), 'credentials.dpapi');
|
|
14
|
+
}
|
|
9
15
|
const SERVICE_NAME = 'fortnox-mcp';
|
|
10
|
-
|
|
16
|
+
function normalizeProfile(profile) {
|
|
17
|
+
const validated = validateProfileName(profile).toLowerCase();
|
|
18
|
+
return { normalized: validated, isDefault: validated === DEFAULT_PROFILE };
|
|
19
|
+
}
|
|
20
|
+
function windowsCredentialsFile(profile) {
|
|
21
|
+
return path.join(configDir(), `credentials.${sanitizeForFilename(profile)}.dpapi`);
|
|
22
|
+
}
|
|
23
|
+
// Dual-write to the legacy slot during the 0.2.x compatibility window so an
|
|
24
|
+
// older 0.1 binary can still read credentials written by this one. Flip to
|
|
25
|
+
// `false` in 0.3.0 and delete the legacy reader branch below.
|
|
26
|
+
// REMOVE IN 0.3.0
|
|
27
|
+
export const LEGACY_DUAL_WRITE = true;
|
|
28
|
+
function parseBlobMeta(blob) {
|
|
29
|
+
try {
|
|
30
|
+
const parsed = JSON.parse(blob);
|
|
31
|
+
const schema = typeof parsed.schema_version === 'number' ? parsed.schema_version : 1;
|
|
32
|
+
const epoch = typeof parsed.last_write_epoch === 'number' ? parsed.last_write_epoch : 0;
|
|
33
|
+
return { schema, epoch };
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function pickHigher(newBlob, legacyBlob) {
|
|
40
|
+
const nMeta = parseBlobMeta(newBlob);
|
|
41
|
+
const lMeta = parseBlobMeta(legacyBlob);
|
|
42
|
+
if (nMeta && !lMeta)
|
|
43
|
+
return { blob: newBlob, picked: 'new' };
|
|
44
|
+
if (!nMeta && lMeta)
|
|
45
|
+
return { blob: legacyBlob, picked: 'legacy' };
|
|
46
|
+
if (!nMeta && !lMeta)
|
|
47
|
+
return { blob: newBlob, picked: 'new' };
|
|
48
|
+
const n = nMeta;
|
|
49
|
+
const l = lMeta;
|
|
50
|
+
if (n.schema > l.schema)
|
|
51
|
+
return { blob: newBlob, picked: 'new' };
|
|
52
|
+
if (l.schema > n.schema)
|
|
53
|
+
return { blob: legacyBlob, picked: 'legacy' };
|
|
54
|
+
if (n.epoch > l.epoch)
|
|
55
|
+
return { blob: newBlob, picked: 'new' };
|
|
56
|
+
if (l.epoch > n.epoch)
|
|
57
|
+
return { blob: legacyBlob, picked: 'legacy' };
|
|
58
|
+
return { blob: newBlob, picked: 'new' };
|
|
59
|
+
}
|
|
11
60
|
function decodeHexIfNeeded(value) {
|
|
12
61
|
// macOS `security -w` returns hex-encoded output when the password
|
|
13
62
|
// contains control characters (e.g. newlines from pretty-printed JSON).
|
|
@@ -24,21 +73,33 @@ function decodeHexIfNeeded(value) {
|
|
|
24
73
|
}
|
|
25
74
|
return value;
|
|
26
75
|
}
|
|
27
|
-
function loadMacSecret() {
|
|
76
|
+
function loadMacSecret(account) {
|
|
77
|
+
// Dedicated-keychain mode: read prompt-free from the YubiKey-locked keychain.
|
|
78
|
+
// A locked keychain throws KeychainLockedError (propagated so the caller can
|
|
79
|
+
// tell the user to run `noxctl keychain unlock`), not a silent null.
|
|
80
|
+
const dedicated = activeKeychainPath();
|
|
81
|
+
if (dedicated)
|
|
82
|
+
return readDedicatedSecret(account, dedicated);
|
|
28
83
|
try {
|
|
29
|
-
const raw = execFileSync('security', ['find-generic-password', '-a',
|
|
84
|
+
const raw = execFileSync('security', ['find-generic-password', '-a', account, '-s', SERVICE_NAME, '-w'], { encoding: 'utf-8' }).trim();
|
|
30
85
|
return decodeHexIfNeeded(raw);
|
|
31
86
|
}
|
|
32
87
|
catch {
|
|
33
88
|
return null;
|
|
34
89
|
}
|
|
35
90
|
}
|
|
36
|
-
function saveMacSecret(secret) {
|
|
91
|
+
function saveMacSecret(account, secret) {
|
|
37
92
|
// macOS `security add-generic-password -w` requires the password as a CLI
|
|
38
93
|
// argument, which is briefly visible via `ps`. Instead, use an inline Swift
|
|
39
94
|
// script that reads the secret from stdin and writes to the Keychain via
|
|
40
95
|
// the Security framework — the secret never appears in process arguments.
|
|
41
96
|
const scriptPath = path.join(os.tmpdir(), `noxctl-keychain-${process.pid}.swift`);
|
|
97
|
+
// In dedicated-keychain mode, target that keychain file; otherwise the
|
|
98
|
+
// default (login) keychain. The path is passed as argv (not interpolated) so
|
|
99
|
+
// an odd path can't break or inject into the Swift source.
|
|
100
|
+
const keychainPath = activeKeychainPath() ?? '';
|
|
101
|
+
// account is either LEGACY_KEYCHAIN_ACCOUNT ("default") or `profile:<validated>`.
|
|
102
|
+
// Validation in profile-name.ts restricts the character set so embedding is safe.
|
|
42
103
|
const swiftScript = `
|
|
43
104
|
import Foundation
|
|
44
105
|
import Security
|
|
@@ -47,28 +108,38 @@ let data = FileHandle.standardInput.readDataToEndOfFile()
|
|
|
47
108
|
guard let password = String(data: data, encoding: .utf8) else { exit(1) }
|
|
48
109
|
|
|
49
110
|
let service = "${SERVICE_NAME}"
|
|
50
|
-
let account = "${
|
|
111
|
+
let account = "${account}"
|
|
112
|
+
|
|
113
|
+
let kcPath = CommandLine.arguments.count > 1 ? CommandLine.arguments[1] : ""
|
|
114
|
+
var useKeychain: SecKeychain? = nil
|
|
115
|
+
if !kcPath.isEmpty {
|
|
116
|
+
var kc: SecKeychain?
|
|
117
|
+
if SecKeychainOpen(kcPath, &kc) == errSecSuccess { useKeychain = kc }
|
|
118
|
+
else { exit(1) }
|
|
119
|
+
}
|
|
51
120
|
|
|
52
|
-
|
|
121
|
+
var deleteQuery: [String: Any] = [
|
|
53
122
|
kSecClass as String: kSecClassGenericPassword,
|
|
54
123
|
kSecAttrService as String: service,
|
|
55
124
|
kSecAttrAccount as String: account
|
|
56
125
|
]
|
|
126
|
+
if let kc = useKeychain { deleteQuery[kSecMatchSearchList as String] = [kc] }
|
|
57
127
|
SecItemDelete(deleteQuery as CFDictionary)
|
|
58
128
|
|
|
59
129
|
let pwData = password.data(using: String.Encoding.utf8)!
|
|
60
|
-
|
|
130
|
+
var addQuery: [String: Any] = [
|
|
61
131
|
kSecClass as String: kSecClassGenericPassword,
|
|
62
132
|
kSecAttrService as String: service,
|
|
63
133
|
kSecAttrAccount as String: account,
|
|
64
134
|
kSecValueData as String: pwData
|
|
65
135
|
]
|
|
136
|
+
if let kc = useKeychain { addQuery[kSecUseKeychain as String] = kc }
|
|
66
137
|
let status = SecItemAdd(addQuery as CFDictionary, nil)
|
|
67
138
|
if status != errSecSuccess { exit(1) }
|
|
68
139
|
`;
|
|
69
140
|
try {
|
|
70
141
|
fsSync.writeFileSync(scriptPath, swiftScript, { mode: 0o600 });
|
|
71
|
-
const result = spawnSync('swift', [scriptPath], {
|
|
142
|
+
const result = spawnSync('swift', [scriptPath, keychainPath], {
|
|
72
143
|
input: secret,
|
|
73
144
|
encoding: 'utf-8',
|
|
74
145
|
});
|
|
@@ -76,18 +147,18 @@ if status != errSecSuccess { exit(1) }
|
|
|
76
147
|
throw new Error(result.stderr || 'Swift keychain helper failed');
|
|
77
148
|
}
|
|
78
149
|
}
|
|
79
|
-
catch {
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
'-
|
|
90
|
-
|
|
150
|
+
catch (err) {
|
|
151
|
+
// Fail closed rather than fall back to `security add-generic-password -w
|
|
152
|
+
// <secret>`: that CLI only accepts the password via the argv `-w` slot
|
|
153
|
+
// (briefly visible to other processes via `ps`) or an interactive prompt,
|
|
154
|
+
// so a fallback would leak the credential into process arguments — exactly
|
|
155
|
+
// what the stdin-based Swift writer above exists to avoid. `swift` ships
|
|
156
|
+
// with the Xcode Command Line Tools, so guide the user to install them.
|
|
157
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
158
|
+
throw new Error(`Could not store credentials securely: the Swift Keychain helper failed (${detail}). ` +
|
|
159
|
+
`The 'swift' toolchain is required to write credentials without exposing them in ` +
|
|
160
|
+
`process arguments — install the Xcode Command Line Tools with 'xcode-select --install' ` +
|
|
161
|
+
`and try again.`);
|
|
91
162
|
}
|
|
92
163
|
finally {
|
|
93
164
|
try {
|
|
@@ -98,26 +169,28 @@ if status != errSecSuccess { exit(1) }
|
|
|
98
169
|
}
|
|
99
170
|
}
|
|
100
171
|
}
|
|
101
|
-
function loadLinuxSecret() {
|
|
172
|
+
function loadLinuxSecret(account) {
|
|
102
173
|
try {
|
|
103
|
-
return execFileSync('secret-tool', ['lookup', 'service', SERVICE_NAME, 'account',
|
|
174
|
+
return execFileSync('secret-tool', ['lookup', 'service', SERVICE_NAME, 'account', account], {
|
|
175
|
+
encoding: 'utf-8',
|
|
176
|
+
}).trim();
|
|
104
177
|
}
|
|
105
178
|
catch {
|
|
106
179
|
return null;
|
|
107
180
|
}
|
|
108
181
|
}
|
|
109
|
-
function saveLinuxSecret(secret) {
|
|
110
|
-
execFileSync('secret-tool', ['store', '--label=Fortnox MCP credentials', 'service', SERVICE_NAME, 'account',
|
|
182
|
+
function saveLinuxSecret(account, secret) {
|
|
183
|
+
execFileSync('secret-tool', ['store', '--label=Fortnox MCP credentials', 'service', SERVICE_NAME, 'account', account], { input: secret });
|
|
111
184
|
}
|
|
112
|
-
function loadWindowsSecret() {
|
|
185
|
+
function loadWindowsSecret(file) {
|
|
113
186
|
try {
|
|
114
187
|
return execFileSync('powershell', [
|
|
115
188
|
'-NoProfile',
|
|
116
189
|
'-NonInteractive',
|
|
117
190
|
'-Command',
|
|
118
191
|
[
|
|
119
|
-
`if (-not (Test-Path '${
|
|
120
|
-
`$protected = [Convert]::FromBase64String([IO.File]::ReadAllText('${
|
|
192
|
+
`if (-not (Test-Path '${file}')) { exit 0 }`,
|
|
193
|
+
`$protected = [Convert]::FromBase64String([IO.File]::ReadAllText('${file}'))`,
|
|
121
194
|
'$bytes = [System.Security.Cryptography.ProtectedData]::Unprotect($protected, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)',
|
|
122
195
|
'[Text.Encoding]::UTF8.GetString($bytes)',
|
|
123
196
|
].join('; '),
|
|
@@ -127,7 +200,7 @@ function loadWindowsSecret() {
|
|
|
127
200
|
return null;
|
|
128
201
|
}
|
|
129
202
|
}
|
|
130
|
-
function saveWindowsSecret(secret) {
|
|
203
|
+
function saveWindowsSecret(file, secret) {
|
|
131
204
|
// Read the secret from stdin instead of embedding it in the PowerShell
|
|
132
205
|
// command string, which would be visible via `ps` / Task Manager.
|
|
133
206
|
const result = spawnSync('powershell', [
|
|
@@ -135,89 +208,151 @@ function saveWindowsSecret(secret) {
|
|
|
135
208
|
'-NonInteractive',
|
|
136
209
|
'-Command',
|
|
137
210
|
[
|
|
138
|
-
`[IO.Directory]::CreateDirectory('${
|
|
211
|
+
`[IO.Directory]::CreateDirectory('${configDir()}') | Out-Null`,
|
|
139
212
|
'$plain = [Console]::In.ReadToEnd()',
|
|
140
213
|
'$bytes = [Text.Encoding]::UTF8.GetBytes($plain)',
|
|
141
214
|
'$protected = [System.Security.Cryptography.ProtectedData]::Protect($bytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)',
|
|
142
|
-
`[IO.File]::WriteAllText('${
|
|
215
|
+
`[IO.File]::WriteAllText('${file}', [Convert]::ToBase64String($protected), [Text.Encoding]::UTF8)`,
|
|
143
216
|
].join('; '),
|
|
144
217
|
], { input: secret, encoding: 'utf-8' });
|
|
145
218
|
if (result.status !== 0) {
|
|
146
219
|
throw new Error(`Failed to save credentials: ${result.stderr || 'unknown error'}`);
|
|
147
220
|
}
|
|
148
221
|
}
|
|
149
|
-
async function
|
|
222
|
+
async function loadLegacyPlaintextSecret() {
|
|
150
223
|
try {
|
|
151
|
-
return await fs.readFile(
|
|
224
|
+
return await fs.readFile(legacyCredentialsFile(), 'utf-8');
|
|
152
225
|
}
|
|
153
226
|
catch {
|
|
154
227
|
return null;
|
|
155
228
|
}
|
|
156
229
|
}
|
|
157
|
-
async function
|
|
230
|
+
async function removeLegacyPlaintextSecret() {
|
|
158
231
|
try {
|
|
159
|
-
await fs.rm(
|
|
232
|
+
await fs.rm(legacyCredentialsFile(), { force: true });
|
|
160
233
|
}
|
|
161
234
|
catch {
|
|
162
235
|
// ignore cleanup failures
|
|
163
236
|
}
|
|
164
237
|
}
|
|
165
|
-
|
|
238
|
+
function loadFromBackend(account, windowsFile) {
|
|
166
239
|
if (process.platform === 'darwin')
|
|
167
|
-
return loadMacSecret()
|
|
240
|
+
return loadMacSecret(account);
|
|
168
241
|
if (process.platform === 'win32')
|
|
169
|
-
return loadWindowsSecret()
|
|
170
|
-
return loadLinuxSecret()
|
|
242
|
+
return loadWindowsSecret(windowsFile);
|
|
243
|
+
return loadLinuxSecret(account);
|
|
171
244
|
}
|
|
172
|
-
export async function
|
|
245
|
+
export async function loadCredentialBlob(profile = DEFAULT_PROFILE) {
|
|
246
|
+
const { normalized, isDefault } = normalizeProfile(profile);
|
|
247
|
+
if (!isDefault) {
|
|
248
|
+
const blob = loadFromBackend(keychainAccount(normalized), windowsCredentialsFile(normalized));
|
|
249
|
+
return { blob, source: blob ? 'new' : null, legacyBlob: null };
|
|
250
|
+
}
|
|
251
|
+
const newBlob = loadFromBackend(keychainAccount(normalized), windowsCredentialsFile(normalized));
|
|
252
|
+
const legacyBlob = loadFromBackend(LEGACY_KEYCHAIN_ACCOUNT, legacyWindowsCredentialsFile());
|
|
253
|
+
if (newBlob && legacyBlob) {
|
|
254
|
+
const { blob, picked } = pickHigher(newBlob, legacyBlob);
|
|
255
|
+
return {
|
|
256
|
+
blob,
|
|
257
|
+
source: picked === 'new' ? 'both-new-preferred' : 'both-legacy-preferred',
|
|
258
|
+
legacyBlob,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (newBlob)
|
|
262
|
+
return { blob: newBlob, source: 'new', legacyBlob: null };
|
|
263
|
+
if (legacyBlob)
|
|
264
|
+
return { blob: legacyBlob, source: 'legacy', legacyBlob };
|
|
265
|
+
const plaintext = await loadLegacyPlaintextSecret();
|
|
266
|
+
if (plaintext)
|
|
267
|
+
return { blob: plaintext, source: 'legacy-plaintext', legacyBlob: plaintext };
|
|
268
|
+
return { blob: null, source: null, legacyBlob: null };
|
|
269
|
+
}
|
|
270
|
+
function writeToBackend(account, windowsFile, secret) {
|
|
173
271
|
if (process.platform === 'darwin') {
|
|
174
|
-
saveMacSecret(secret);
|
|
272
|
+
saveMacSecret(account, secret);
|
|
175
273
|
}
|
|
176
274
|
else if (process.platform === 'win32') {
|
|
177
|
-
saveWindowsSecret(secret);
|
|
275
|
+
saveWindowsSecret(windowsFile, secret);
|
|
178
276
|
}
|
|
179
277
|
else {
|
|
180
|
-
saveLinuxSecret(secret);
|
|
278
|
+
saveLinuxSecret(account, secret);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
export async function saveCredentialBlob(secret, profile = DEFAULT_PROFILE, options = {}) {
|
|
282
|
+
const { normalized, isDefault } = normalizeProfile(profile);
|
|
283
|
+
// Primary write: always the new per-profile slot (profile:<name> or
|
|
284
|
+
// credentials.<name>.dpapi). For default this is `profile:default` /
|
|
285
|
+
// `credentials.default.dpapi`.
|
|
286
|
+
writeToBackend(keychainAccount(normalized), windowsCredentialsFile(normalized), secret);
|
|
287
|
+
// Compatibility dual-write: for the default profile only, and only when the
|
|
288
|
+
// caller observed a legacy blob during load. This keeps an older 0.1 binary
|
|
289
|
+
// functional during the 0.2.x window without silently creating a legacy slot
|
|
290
|
+
// for users who never had one. Best-effort — a failure here must not break
|
|
291
|
+
// the auth flow, since the authoritative new-slot write already succeeded.
|
|
292
|
+
// REMOVE IN 0.3.0.
|
|
293
|
+
if (LEGACY_DUAL_WRITE && isDefault && options.alsoWriteLegacy) {
|
|
294
|
+
try {
|
|
295
|
+
writeToBackend(LEGACY_KEYCHAIN_ACCOUNT, legacyWindowsCredentialsFile(), secret);
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
299
|
+
console.warn(`Warning: could not mirror credentials to legacy slot: ${msg}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
if (isDefault) {
|
|
303
|
+
await removeLegacyPlaintextSecret();
|
|
181
304
|
}
|
|
182
|
-
await removeLegacySecret();
|
|
183
305
|
}
|
|
184
|
-
function deleteMacSecret() {
|
|
306
|
+
function deleteMacSecret(account) {
|
|
307
|
+
const keychainPath = activeKeychainPath();
|
|
185
308
|
try {
|
|
186
|
-
execFileSync('security', [
|
|
309
|
+
execFileSync('security', [
|
|
310
|
+
'delete-generic-password',
|
|
311
|
+
'-a',
|
|
312
|
+
account,
|
|
313
|
+
'-s',
|
|
314
|
+
SERVICE_NAME,
|
|
315
|
+
...(keychainPath ? [keychainPath] : []),
|
|
316
|
+
]);
|
|
187
317
|
return true;
|
|
188
318
|
}
|
|
189
319
|
catch {
|
|
190
320
|
return false;
|
|
191
321
|
}
|
|
192
322
|
}
|
|
193
|
-
function deleteLinuxSecret() {
|
|
323
|
+
function deleteLinuxSecret(account) {
|
|
194
324
|
try {
|
|
195
|
-
execFileSync('secret-tool', ['clear', 'service', SERVICE_NAME, 'account',
|
|
325
|
+
execFileSync('secret-tool', ['clear', 'service', SERVICE_NAME, 'account', account]);
|
|
196
326
|
return true;
|
|
197
327
|
}
|
|
198
328
|
catch {
|
|
199
329
|
return false;
|
|
200
330
|
}
|
|
201
331
|
}
|
|
202
|
-
async function deleteWindowsSecret() {
|
|
332
|
+
async function deleteWindowsSecret(file) {
|
|
203
333
|
try {
|
|
204
|
-
await fs.rm(
|
|
334
|
+
await fs.rm(file, { force: true });
|
|
205
335
|
return true;
|
|
206
336
|
}
|
|
207
337
|
catch {
|
|
208
338
|
return false;
|
|
209
339
|
}
|
|
210
340
|
}
|
|
211
|
-
|
|
212
|
-
let deleted = false;
|
|
341
|
+
async function deleteAtAccount(account, windowsFile) {
|
|
213
342
|
if (process.platform === 'darwin')
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
343
|
+
return deleteMacSecret(account);
|
|
344
|
+
if (process.platform === 'win32')
|
|
345
|
+
return deleteWindowsSecret(windowsFile);
|
|
346
|
+
return deleteLinuxSecret(account);
|
|
347
|
+
}
|
|
348
|
+
export async function deleteCredentialBlob(profile = DEFAULT_PROFILE) {
|
|
349
|
+
const { normalized, isDefault } = normalizeProfile(profile);
|
|
350
|
+
if (isDefault) {
|
|
351
|
+
const legacyDeleted = await deleteAtAccount(LEGACY_KEYCHAIN_ACCOUNT, legacyWindowsCredentialsFile());
|
|
352
|
+
const newDeleted = await deleteAtAccount(keychainAccount(normalized), windowsCredentialsFile(normalized));
|
|
353
|
+
await removeLegacyPlaintextSecret();
|
|
354
|
+
return legacyDeleted || newDeleted;
|
|
355
|
+
}
|
|
356
|
+
return deleteAtAccount(keychainAccount(normalized), windowsCredentialsFile(normalized));
|
|
222
357
|
}
|
|
223
358
|
//# sourceMappingURL=credentials-store.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials-store.js","sourceRoot":"","sources":["../src/credentials-store.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"credentials-store.js","sourceRoot":"","sources":["../src/credentials-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface DateRange {
|
|
2
|
+
from: string;
|
|
3
|
+
to: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function resolvePeriod(period: string, today?: Date): DateRange;
|
|
6
|
+
export declare function applyPeriod(opts: {
|
|
7
|
+
period?: string;
|
|
8
|
+
from?: string;
|
|
9
|
+
to?: string;
|
|
10
|
+
}): {
|
|
11
|
+
from?: string;
|
|
12
|
+
to?: string;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=date-periods.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-periods.d.ts","sourceRoot":"","sources":["../src/date-periods.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAyDD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,IAAiB,GAAG,SAAS,CA8CjF;AAGD,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAMA"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Natural date-period parsing for CLI --period arguments.
|
|
2
|
+
//
|
|
3
|
+
// Periods are CALENDAR-year based. Fortnox supports broken fiscal years;
|
|
4
|
+
// a fiscal-year-aware design is tracked separately — until then "Q1" always
|
|
5
|
+
// means January–March of the named (or current) calendar year.
|
|
6
|
+
const EN_MONTHS = [
|
|
7
|
+
'january',
|
|
8
|
+
'february',
|
|
9
|
+
'march',
|
|
10
|
+
'april',
|
|
11
|
+
'may',
|
|
12
|
+
'june',
|
|
13
|
+
'july',
|
|
14
|
+
'august',
|
|
15
|
+
'september',
|
|
16
|
+
'october',
|
|
17
|
+
'november',
|
|
18
|
+
'december',
|
|
19
|
+
];
|
|
20
|
+
const SV_MONTHS = [
|
|
21
|
+
'januari',
|
|
22
|
+
'februari',
|
|
23
|
+
'mars',
|
|
24
|
+
'april',
|
|
25
|
+
'maj',
|
|
26
|
+
'juni',
|
|
27
|
+
'juli',
|
|
28
|
+
'augusti',
|
|
29
|
+
'september',
|
|
30
|
+
'oktober',
|
|
31
|
+
'november',
|
|
32
|
+
'december',
|
|
33
|
+
];
|
|
34
|
+
function iso(year, month, day) {
|
|
35
|
+
return `${String(year).padStart(4, '0')}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
|
36
|
+
}
|
|
37
|
+
function lastDayOfMonth(year, month) {
|
|
38
|
+
return new Date(year, month, 0).getDate();
|
|
39
|
+
}
|
|
40
|
+
function monthRange(year, month) {
|
|
41
|
+
return { from: iso(year, month, 1), to: iso(year, month, lastDayOfMonth(year, month)) };
|
|
42
|
+
}
|
|
43
|
+
function quarterRange(year, quarter) {
|
|
44
|
+
const startMonth = (quarter - 1) * 3 + 1;
|
|
45
|
+
const endMonth = startMonth + 2;
|
|
46
|
+
return {
|
|
47
|
+
from: iso(year, startMonth, 1),
|
|
48
|
+
to: iso(year, endMonth, lastDayOfMonth(year, endMonth)),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function yearRange(year) {
|
|
52
|
+
return { from: iso(year, 1, 1), to: iso(year, 12, 31) };
|
|
53
|
+
}
|
|
54
|
+
export function resolvePeriod(period, today = new Date()) {
|
|
55
|
+
const input = period.trim().toLowerCase();
|
|
56
|
+
const year = today.getFullYear();
|
|
57
|
+
const month = today.getMonth() + 1; // 1-based
|
|
58
|
+
const quarter = Math.ceil(month / 3);
|
|
59
|
+
// Q1..Q4, optionally year-qualified (2025-Q3 or 2025Q3)
|
|
60
|
+
const quarterMatch = /^(?:(\d{4})-?)?q([1-4])$/.exec(input);
|
|
61
|
+
if (quarterMatch) {
|
|
62
|
+
return quarterRange(quarterMatch[1] ? parseInt(quarterMatch[1], 10) : year, parseInt(quarterMatch[2], 10));
|
|
63
|
+
}
|
|
64
|
+
// Bare year
|
|
65
|
+
if (/^\d{4}$/.test(input))
|
|
66
|
+
return yearRange(parseInt(input, 10));
|
|
67
|
+
// Month names (English and Swedish), current calendar year
|
|
68
|
+
const enIdx = EN_MONTHS.indexOf(input);
|
|
69
|
+
if (enIdx !== -1)
|
|
70
|
+
return monthRange(year, enIdx + 1);
|
|
71
|
+
const svIdx = SV_MONTHS.indexOf(input);
|
|
72
|
+
if (svIdx !== -1)
|
|
73
|
+
return monthRange(year, svIdx + 1);
|
|
74
|
+
switch (input) {
|
|
75
|
+
case 'this-quarter':
|
|
76
|
+
return quarterRange(year, quarter);
|
|
77
|
+
case 'last-quarter':
|
|
78
|
+
return quarter === 1 ? quarterRange(year - 1, 4) : quarterRange(year, quarter - 1);
|
|
79
|
+
case 'this-month':
|
|
80
|
+
return monthRange(year, month);
|
|
81
|
+
case 'last-month':
|
|
82
|
+
return month === 1 ? monthRange(year - 1, 12) : monthRange(year, month - 1);
|
|
83
|
+
case 'this-year':
|
|
84
|
+
return yearRange(year);
|
|
85
|
+
case 'last-year':
|
|
86
|
+
return yearRange(year - 1);
|
|
87
|
+
case 'ytd':
|
|
88
|
+
return { from: iso(year, 1, 1), to: iso(year, month, today.getDate()) };
|
|
89
|
+
}
|
|
90
|
+
throw new Error(`Unrecognized period "${period}". Supported: Q1–Q4, 2025-Q3, month names (march/mars), ` +
|
|
91
|
+
'this-quarter, last-quarter, this-month, last-month, this-year, last-year, ytd, or a bare year. ' +
|
|
92
|
+
'Periods are calendar-year based.');
|
|
93
|
+
}
|
|
94
|
+
// Shared by CLI actions: merge --period into from/to, rejecting ambiguous mixes.
|
|
95
|
+
export function applyPeriod(opts) {
|
|
96
|
+
if (!opts.period)
|
|
97
|
+
return { from: opts.from, to: opts.to };
|
|
98
|
+
if (opts.from || opts.to) {
|
|
99
|
+
throw new Error('--period cannot be combined with --from/--to.');
|
|
100
|
+
}
|
|
101
|
+
return resolvePeriod(opts.period);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=date-periods.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-periods.js","sourceRoot":"","sources":["../src/date-periods.ts"],"names":[],"mappings":"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"}
|
package/dist/formatter.d.ts
CHANGED
|
@@ -57,6 +57,15 @@ export declare function isJsonMode(programOpts: {
|
|
|
57
57
|
fd: 1;
|
|
58
58
|
}): boolean;
|
|
59
59
|
export declare function outputList(data: Record<string, unknown>[], columns: Column[], json: boolean, rawData: unknown, meta?: Record<string, unknown>): void;
|
|
60
|
-
export declare function outputDetail(record: Record<string, unknown>, columns: Column[], json: boolean): void;
|
|
61
|
-
export
|
|
60
|
+
export declare function outputDetail(record: Record<string, unknown>, columns: Column[], json: boolean, jsonEnvelopeKey?: string): void;
|
|
61
|
+
export interface ErrorEnvelope {
|
|
62
|
+
error: {
|
|
63
|
+
status?: number;
|
|
64
|
+
message: string;
|
|
65
|
+
hint?: string;
|
|
66
|
+
source: 'fortnox-api' | 'noxctl';
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export declare function errorEnvelope(err: unknown): ErrorEnvelope;
|
|
70
|
+
export declare function outputConfirmation(message: string, json: boolean, rawData: unknown, columns?: Column[], jsonEnvelopeKey?: string): void;
|
|
62
71
|
//# sourceMappingURL=formatter.d.ts.map
|
package/dist/formatter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,MAAM,CAAC;CACrC;AA+BD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAgBtF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,CAWvF;AAED,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAOjE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAkDvE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACnE,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACnE,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;IACJ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QACnE,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;IACJ,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CA6ET;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,UAAU,CAAC,WAAW,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM;;CAAiB,GAAG,OAAO,CAK7F;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC/B,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,OAAO,EACb,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAQN;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../src/formatter.ts"],"names":[],"mappings":"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"}
|
package/dist/formatter.js
CHANGED
|
@@ -180,16 +180,39 @@ export function outputList(data, columns, json, rawData, meta) {
|
|
|
180
180
|
if (metaLine)
|
|
181
181
|
console.log(metaLine);
|
|
182
182
|
}
|
|
183
|
-
export function outputDetail(record, columns, json) {
|
|
183
|
+
export function outputDetail(record, columns, json, jsonEnvelopeKey) {
|
|
184
184
|
if (json) {
|
|
185
|
-
|
|
185
|
+
const payload = jsonEnvelopeKey ? { [jsonEnvelopeKey]: record } : record;
|
|
186
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
186
187
|
return;
|
|
187
188
|
}
|
|
188
189
|
console.log(formatDetail(record, columns));
|
|
189
190
|
}
|
|
190
|
-
|
|
191
|
+
// Duck-typed rather than instanceof so the formatter stays decoupled from
|
|
192
|
+
// fortnox-client (and survives errors crossing module-instance boundaries).
|
|
193
|
+
export function errorEnvelope(err) {
|
|
194
|
+
if (err instanceof Error &&
|
|
195
|
+
err.name === 'FortnoxApiError' &&
|
|
196
|
+
'statusCode' in err &&
|
|
197
|
+
'fortnoxMessage' in err) {
|
|
198
|
+
const apiErr = err;
|
|
199
|
+
return {
|
|
200
|
+
error: {
|
|
201
|
+
status: apiErr.statusCode,
|
|
202
|
+
message: apiErr.fortnoxMessage,
|
|
203
|
+
...(apiErr.hint ? { hint: apiErr.hint } : {}),
|
|
204
|
+
source: 'fortnox-api',
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
error: { message: err instanceof Error ? err.message : String(err), source: 'noxctl' },
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
export function outputConfirmation(message, json, rawData, columns, jsonEnvelopeKey) {
|
|
191
213
|
if (json) {
|
|
192
|
-
|
|
214
|
+
const payload = jsonEnvelopeKey ? { [jsonEnvelopeKey]: rawData } : rawData;
|
|
215
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
193
216
|
return;
|
|
194
217
|
}
|
|
195
218
|
console.log(message);
|