noxctl 0.4.1 → 0.5.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.
@@ -60,8 +60,8 @@ export class FortnoxApiError extends Error {
60
60
  }
61
61
  export class FortnoxRequestTimeoutError extends Error {
62
62
  outcomeUnknown;
63
- constructor(method, endpoint, timeoutMs) {
64
- const mutation = !['GET', 'HEAD', 'OPTIONS'].includes(method);
63
+ constructor(method, endpoint, timeoutMs, isMutation) {
64
+ const mutation = isMutation ?? !['GET', 'HEAD', 'OPTIONS'].includes(method);
65
65
  const suffix = mutation
66
66
  ? ' The outcome is unknown; verify the result in Fortnox before retrying to avoid duplicate side effects.'
67
67
  : ' It is safe to retry the read request.';
@@ -197,73 +197,191 @@ async function retryWithBackoff(fn, retryable, maxRetries = MAX_RETRIES) {
197
197
  }
198
198
  throw new Error('Unreachable');
199
199
  }
200
- export async function fortnoxRequest(endpoint, options = {}) {
200
+ // Issue the HTTP request and translate a non-2xx answer into a FortnoxApiError.
201
+ // Returns the raw Response so callers can decide how to read the body.
202
+ async function sendRequest(endpoint, options, method, timeoutMs) {
203
+ await waitForRateLimit();
204
+ const token = await getValidToken();
205
+ const url = new URL(`${BASE_URL}/${endpoint}`);
206
+ if (options.params) {
207
+ for (const [key, value] of Object.entries(options.params)) {
208
+ if (value !== undefined) {
209
+ url.searchParams.set(key, String(value));
210
+ }
211
+ }
212
+ }
213
+ // Accept is always application/json, even for the endpoints that answer with a
214
+ // PDF. This looks wrong but is not: Fortnox rejects Accept: application/pdf (and
215
+ // application/octet-stream) on its PDF endpoints with
216
+ // {"ErrorInformation":{"error":1,"message":"Invalid response type","code":1000030}}.
217
+ // Do not "fix" this header.
218
+ const headers = {
219
+ Authorization: `Bearer ${token}`,
220
+ Accept: 'application/json',
221
+ };
222
+ const fetchOptions = {
223
+ method,
224
+ headers,
225
+ signal: AbortSignal.timeout(timeoutMs),
226
+ };
227
+ if (options.rawBody !== undefined) {
228
+ // A raw body (e.g. FormData for a multipart file upload): do NOT set
229
+ // Content-Type — fetch/undici derives it (and the multipart boundary)
230
+ // from the body itself.
231
+ fetchOptions.body = options.rawBody;
232
+ }
233
+ else {
234
+ headers['Content-Type'] = 'application/json';
235
+ if (options.body) {
236
+ fetchOptions.body = JSON.stringify(options.body);
237
+ }
238
+ }
239
+ const response = await fetch(url.toString(), fetchOptions);
240
+ if (!response.ok) {
241
+ let errorMessage = `HTTP ${response.status}`;
242
+ let details;
243
+ try {
244
+ const errorBody = (await response.json());
245
+ if (errorBody?.ErrorInformation) {
246
+ errorMessage = errorBody.ErrorInformation.message || errorMessage;
247
+ details = `Error code: ${errorBody.ErrorInformation.code}`;
248
+ }
249
+ }
250
+ catch {
251
+ // ignore parse errors
252
+ }
253
+ throw new FortnoxApiError(response.status, errorMessage, details, endpoint, retryAfterDelay(response));
254
+ }
255
+ return response;
256
+ }
257
+ // Shared retry/timeout envelope; `readBody` turns a successful Response into T.
258
+ async function request(endpoint, options, readBody) {
201
259
  const method = (options.method || 'GET').toUpperCase();
202
- const retryable = method === 'GET' || method === 'HEAD' || method === 'OPTIONS';
260
+ const isMutation = options.mutation ?? !(method === 'GET' || method === 'HEAD' || method === 'OPTIONS');
261
+ const retryable = !isMutation;
203
262
  const timeoutMs = options.rawBody === undefined ? REQUEST_TIMEOUT_MS : UPLOAD_TIMEOUT_MS;
204
263
  try {
205
- return await retryWithBackoff(async () => {
206
- await waitForRateLimit();
207
- const token = await getValidToken();
208
- const url = new URL(`${BASE_URL}/${endpoint}`);
209
- if (options.params) {
210
- for (const [key, value] of Object.entries(options.params)) {
211
- if (value !== undefined) {
212
- url.searchParams.set(key, String(value));
213
- }
214
- }
215
- }
216
- const headers = {
217
- Authorization: `Bearer ${token}`,
218
- Accept: 'application/json',
219
- };
220
- const fetchOptions = {
221
- method,
222
- headers,
223
- signal: AbortSignal.timeout(timeoutMs),
224
- };
225
- if (options.rawBody !== undefined) {
226
- // A raw body (e.g. FormData for a multipart file upload): do NOT set
227
- // Content-Type — fetch/undici derives it (and the multipart boundary)
228
- // from the body itself.
229
- fetchOptions.body = options.rawBody;
230
- }
231
- else {
232
- headers['Content-Type'] = 'application/json';
233
- if (options.body) {
234
- fetchOptions.body = JSON.stringify(options.body);
235
- }
236
- }
237
- const response = await fetch(url.toString(), fetchOptions);
238
- if (!response.ok) {
239
- let errorMessage = `HTTP ${response.status}`;
240
- let details;
241
- try {
242
- const errorBody = (await response.json());
243
- if (errorBody?.ErrorInformation) {
244
- errorMessage = errorBody.ErrorInformation.message || errorMessage;
245
- details = `Error code: ${errorBody.ErrorInformation.code}`;
246
- }
247
- }
248
- catch {
249
- // ignore parse errors
250
- }
251
- throw new FortnoxApiError(response.status, errorMessage, details, endpoint, retryAfterDelay(response));
252
- }
253
- // Some endpoints return empty responses (e.g., DELETE)
254
- const text = await response.text();
255
- if (!text)
256
- return undefined;
257
- return JSON.parse(text);
258
- }, retryable);
264
+ return await retryWithBackoff(async () => readBody(await sendRequest(endpoint, options, method, timeoutMs)), retryable);
259
265
  }
260
266
  catch (err) {
261
267
  if (isTimeoutError(err)) {
262
- throw new FortnoxRequestTimeoutError(method, endpoint, timeoutMs);
268
+ throw new FortnoxRequestTimeoutError(method, endpoint, timeoutMs, isMutation);
263
269
  }
264
270
  throw err;
265
271
  }
266
272
  }
273
+ export async function fortnoxRequest(endpoint, options = {}) {
274
+ return request(endpoint, options, async (response) => {
275
+ // Some endpoints return empty responses (e.g., DELETE)
276
+ const text = await response.text();
277
+ if (!text)
278
+ return undefined;
279
+ return JSON.parse(text);
280
+ });
281
+ }
282
+ // Summarize an unexpected (non-binary) body for an error message, preferring the
283
+ // Fortnox error envelope when the body turns out to be one.
284
+ function describeUnexpectedBody(buf) {
285
+ const text = buf.toString('utf-8', 0, 2000).trim();
286
+ try {
287
+ const parsed = JSON.parse(text);
288
+ const info = parsed?.ErrorInformation;
289
+ if (info?.message) {
290
+ return info.code === undefined ? info.message : `${info.message} (code ${info.code})`;
291
+ }
292
+ }
293
+ catch {
294
+ // not JSON — fall through to the raw excerpt
295
+ }
296
+ return text.slice(0, 200) || '<empty body>';
297
+ }
298
+ const PDF_MAGIC = '%PDF-';
299
+ const PDF_TRAILER = '%%EOF';
300
+ function startsWithPdfMagic(buf) {
301
+ return buf.subarray(0, PDF_MAGIC.length).toString('latin1') === PDF_MAGIC;
302
+ }
303
+ /**
304
+ * A PDF that both starts with the magic number and carries its end-of-file
305
+ * trailer, i.e. one that was not cut short in transit. Used where a *partial*
306
+ * document would be worse than none — replacing an already-saved copy, say.
307
+ * The trailer may be followed by whitespace, so search the tail rather than
308
+ * requiring it at the very end.
309
+ */
310
+ function isCompletePdf(buf) {
311
+ if (!startsWithPdfMagic(buf))
312
+ return false;
313
+ const tail = buf.subarray(Math.max(0, buf.length - 1024)).toString('latin1');
314
+ return tail.includes(PDF_TRAILER);
315
+ }
316
+ /** Fortnox can answer 2xx with an error envelope; detect one in a raw body. */
317
+ function fortnoxErrorInBody(buf) {
318
+ if (startsWithPdfMagic(buf))
319
+ return undefined;
320
+ try {
321
+ const parsed = JSON.parse(buf.toString('utf-8', 0, 4096));
322
+ const info = parsed?.ErrorInformation;
323
+ return info?.message ? { message: info.message, code: info.code } : undefined;
324
+ }
325
+ catch {
326
+ return undefined;
327
+ }
328
+ }
329
+ /**
330
+ * Fetch a PDF from one of Fortnox's document endpoints. Shares rate limiting,
331
+ * retries, timeouts and error mapping with `fortnoxRequest`.
332
+ *
333
+ * The returned bytes are validated by their magic number rather than by the
334
+ * Content-Type header: Fortnox can answer 200 with a JSON error envelope, and a
335
+ * proxy can return an HTML error page, either of which would otherwise be saved
336
+ * as `invoice-1001.pdf` and look like success until someone opened the file.
337
+ */
338
+ export async function fortnoxRequestPdf(endpoint, options = {}) {
339
+ return request(endpoint, options, async (response) => {
340
+ const buf = Buffer.from(await response.arrayBuffer());
341
+ if (!startsWithPdfMagic(buf)) {
342
+ const contentType = response.headers?.get?.('content-type') || 'an unknown content type';
343
+ throw new Error(`Fortnox returned ${contentType} that is not a PDF for ${endpoint}: ${describeUnexpectedBody(buf)}`);
344
+ }
345
+ return buf;
346
+ });
347
+ }
348
+ /**
349
+ * For endpoints where the PDF is a by-product of a state change — Fortnox's
350
+ * `/print` both returns the document and sets `Sent`.
351
+ *
352
+ * Once the server has answered 2xx the mutation has happened, so nothing about
353
+ * the body may raise: a truncated or malformed payload is reported as "no PDF"
354
+ * rather than as an error, because throwing here would turn a completed
355
+ * accounting change into a reported failure. Always treated as a mutation, so
356
+ * it is never auto-retried.
357
+ */
358
+ export async function fortnoxRequestPdfFromMutation(endpoint, options = {}) {
359
+ return request(endpoint, { ...options, mutation: true }, async (response) => {
360
+ let buf;
361
+ try {
362
+ buf = Buffer.from(await response.arrayBuffer());
363
+ }
364
+ catch {
365
+ // Body unreadable (truncated stream, aborted transfer). The status line
366
+ // already said the action succeeded; report it as such.
367
+ return undefined;
368
+ }
369
+ if (isCompletePdf(buf))
370
+ return buf;
371
+ // A well-formed Fortnox error envelope is positive evidence that the action
372
+ // did NOT happen — unlike an unreadable body, which is merely inconclusive.
373
+ // Fortnox can send these with a 2xx status, so this has to be checked here
374
+ // rather than left to the status code.
375
+ const failure = fortnoxErrorInBody(buf);
376
+ if (failure) {
377
+ throw new FortnoxApiError(response.status, failure.message, `Error code: ${failure.code}`, endpoint);
378
+ }
379
+ // Something else came back — an incomplete PDF, or a payload we cannot
380
+ // interpret. Inconclusive, so treat the action as done but offer no
381
+ // document: callers must not overwrite a good file with this.
382
+ return undefined;
383
+ });
384
+ }
267
385
  /**
268
386
  * Fetch all pages of a paginated Fortnox list endpoint.
269
387
  * `dataKey` is the envelope key (e.g. "Invoices", "Customers").
@@ -1 +1 @@
1
- {"version":3,"file":"fortnox-client.js","sourceRoot":"","sources":["../src/fortnox-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,MAAM,QAAQ,GAAG,0BAA0B,CAAC;AAC5C,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAClC,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,8CAA8C;AAC9C,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,iBAAiB,GAAa,EAAE,CAAC;AACvC,IAAI,aAAa,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;AAErD,KAAK,UAAU,gBAAgB;IAC7B,IAAI,OAAoB,CAAC;IACzB,MAAM,QAAQ,GAAG,aAAa,CAAC;IAC/B,aAAa,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC5C,OAAO,GAAG,OAAO,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,CAAC;IACf,IAAI,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,OAAO,iBAAiB,CAAC,MAAM,GAAG,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAE,IAAI,GAAG,GAAG,cAAc,EAAE,CAAC;gBACrF,iBAAiB,CAAC,KAAK,EAAE,CAAC;YAC5B,CAAC;YAED,IAAI,iBAAiB,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;gBAC1C,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC5B,OAAO;YACT,CAAC;YAED,MAAM,cAAc,GAAG,iBAAiB,CAAC,CAAC,CAAE,CAAC;YAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,cAAc,GAAG,GAAG,GAAG,EAAE,CAAC,CAAC;YACvE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;YAAS,CAAC;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAQD,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAItB;IACA;IACA;IAEA;IAPF,IAAI,CAAU;IAE9B,YACkB,UAAkB,EAClB,cAAsB,EACtB,OAAgB,EAChC,QAAiB,EACD,YAAqB;QAErC,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,kBAAkB,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,CAAC,CAAC,aAAa,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,MAAM,KAAK,GAAG,CAAC,GAAG,UAAU,sBAAsB,UAAU,MAAM,cAAc,EAAE,CAAC,CAAC;QACpF,IAAI,IAAI;YAAE,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;QACtC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAXR,eAAU,GAAV,UAAU,CAAQ;QAClB,mBAAc,GAAd,cAAc,CAAQ;QACtB,YAAO,GAAP,OAAO,CAAS;QAEhB,iBAAY,GAAZ,YAAY,CAAS;QAQrC,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IACnC,cAAc,CAAU;IAExC,YAAY,MAAc,EAAE,QAAgB,EAAE,SAAiB;QAC7D,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,QAAQ;YACrB,CAAC,CAAC,wGAAwG;YAC1G,CAAC,CAAC,wCAAwC,CAAC;QAC7C,KAAK,CAAC,WAAW,MAAM,IAAI,QAAQ,oBAAoB,SAAS,OAAO,MAAM,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;QACzC,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC;IACjC,CAAC;CACF;AAED,SAAS,YAAY,CAAC,UAAkB,EAAE,OAAe,EAAE,QAAiB;IAC1E,4EAA4E;IAC5E,mEAAmE;IACnE,6EAA6E;IAC7E,kEAAkE;IAClE,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,+LAA+L,CAAC;IACzM,CAAC;IAED,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,GAAG;YACN,OAAO,8DAA8D,CAAC;QACxE,KAAK,GAAG;YACN,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,KAAK,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;gBACxC,IAAI,KAAK,EAAE,CAAC;oBACV,OAAO,YAAY,KAAK,8FAA8F,CAAC;gBACzH,CAAC;YACH,CAAC;YACD,OAAO,iGAAiG,CAAC;QAC3G,KAAK,GAAG;YACN,OAAO,6DAA6D,CAAC;QACvE,KAAK,GAAG;YACN,OAAO,8HAA8H,CAAC;QACxI;YACE,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;gBACtB,OAAO,8CAA8C,CAAC;YACxD,CAAC;YACD,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB;IACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,OAAO,GAA2B;QACtC,QAAQ,EAAE,SAAS;QACnB,SAAS,EAAE,UAAU;QACrB,QAAQ,EAAE,SAAS;QACnB,eAAe,EAAE,SAAS;QAC1B,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,UAAU;QACrB,gBAAgB,EAAE,iBAAiB;QACnC,uBAAuB,EAAE,iBAAiB;QAC1C,QAAQ,EAAE,aAAa;QACvB,QAAQ,EAAE,aAAa;QACvB,kBAAkB,EAAE,oBAAoB;QACxC,QAAQ,EAAE,UAAU;QACpB,QAAQ,EAAE,SAAS;QACnB,WAAW,EAAE,YAAY;QACzB,aAAa,EAAE,SAAS;QACxB,UAAU,EAAE,OAAO;QACnB,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,OAAO;QACd,OAAO,EAAE,SAAS;QAClB,sBAAsB,EAAE,aAAa;QACrC,SAAS,EAAE,QAAQ;QACnB,kBAAkB,EAAE,QAAQ;QAC5B,sBAAsB,EAAE,QAAQ;QAChC,mBAAmB,EAAE,QAAQ;QAC7B,aAAa,EAAE,QAAQ;KACxB,CAAC;IACF,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,OAAO,KAAK,CAAC;IAC5C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,OAAO,GAAY,GAAG,CAAC;IAC3B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;QACjF,MAAM,KAAK,GAAG,OAA8C,CAAC;QAC7D,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC;QACtD,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;IACxB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CAAC,GAAY;IAClC,OAAO,CACL,GAAG,YAAY,KAAK;QACpB,CAAC,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,WAAW,CAAC,CAC7F,CAAC;AACJ,CAAC;AAED,SAAS,uBAAuB,CAAC,GAAY;IAC3C,IAAI,cAAc,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,IACE,IAAI;QACJ,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EACtF,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,GAAG,YAAY,SAAS,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,eAAe,CAAC,QAAkB;IACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAE3B,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC/F,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,kBAAkB,CAAC,CAAC;AAC1D,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,EAAoB,EACpB,SAAkB,EAClB,UAAU,GAAG,WAAW;IAExB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,KAAK,UAAU;gBAAE,MAAM,GAAG,CAAC;YACtC,IAAI,CAAC,SAAS;gBAAE,MAAM,GAAG,CAAC;YAE1B,2DAA2D;YAC3D,IAAI,GAAG,YAAY,eAAe,EAAE,CAAC;gBACnC,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC5C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;oBAAE,MAAM,GAAG,CAAC;YACrD,CAAC;iBAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzC,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,MAAM,KAAK,GACT,GAAG,YAAY,eAAe,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS;gBAC9D,CAAC,CAAC,GAAG,CAAC,YAAY;gBAClB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,CAAC,CAAC;YAChE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;AACjC,CAAC;AASD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,UAA0B,EAAE;IAE5B,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;IACvD,MAAM,SAAS,GAAG,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,SAAS,CAAC;IAEhF,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAEzF,IAAI,CAAC;QACH,OAAO,MAAM,gBAAgB,CAAC,KAAK,IAAI,EAAE;YACvC,MAAM,gBAAgB,EAAE,CAAC;YAEzB,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,QAAQ,IAAI,QAAQ,EAAE,CAAC,CAAC;YAE/C,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC1D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;wBACxB,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;oBAC3C,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,OAAO,GAA2B;gBACtC,aAAa,EAAE,UAAU,KAAK,EAAE;gBAChC,MAAM,EAAE,kBAAkB;aAC3B,CAAC;YAEF,MAAM,YAAY,GAAgB;gBAChC,MAAM;gBACN,OAAO;gBACP,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC;aACvC,CAAC;YAEF,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAClC,qEAAqE;gBACrE,sEAAsE;gBACtE,wBAAwB;gBACxB,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;gBAC7C,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;oBACjB,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,YAAY,CAAC,CAAC;YAE3D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,IAAI,YAAY,GAAG,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAC7C,IAAI,OAA2B,CAAC;gBAChC,IAAI,CAAC;oBACH,MAAM,SAAS,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAEvC,CAAC;oBACF,IAAI,SAAS,EAAE,gBAAgB,EAAE,CAAC;wBAChC,YAAY,GAAG,SAAS,CAAC,gBAAgB,CAAC,OAAO,IAAI,YAAY,CAAC;wBAClE,OAAO,GAAG,eAAe,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;oBAC7D,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,sBAAsB;gBACxB,CAAC;gBACD,MAAM,IAAI,eAAe,CACvB,QAAQ,CAAC,MAAM,EACf,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,eAAe,CAAC,QAAQ,CAAC,CAC1B,CAAC;YACJ,CAAC;YAED,uDAAuD;YACvD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAc,CAAC;YAEjC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;QAC/B,CAAC,EAAE,SAAS,CAAC,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,IAAI,0BAA0B,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QACpE,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,OAAe,EACf,SAAsD,EAAE;IAExD,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,GAAG,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,cAAc,CAA0B,QAAQ,EAAE;YACnE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE;SACxC,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,IAAI,CAAC,OAAO,CAAS,IAAI,EAAE,CAAC;QAC3C,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,eAEL,CAAC;QACd,UAAU,GAAG,IAAI,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;QACxC,cAAc,GAAG,IAAI,EAAE,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC;QACzD,IAAI,EAAE,CAAC;IACT,CAAC,QAAQ,IAAI,IAAI,UAAU,EAAE;IAE7B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"fortnox-client.js","sourceRoot":"","sources":["../src/fortnox-client.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,44 @@ export interface SendEmailOptions {
26
26
  bcc?: string;
27
27
  }
28
28
  export declare function sendInvoice(documentNumber: string, method?: SendMethod, emailOptions?: SendEmailOptions): Promise<Record<string, unknown>>;
29
+ /**
30
+ * Fetch an invoice as a PDF. Always uses /preview, which returns the same
31
+ * document as /print but leaves the invoice untouched.
32
+ *
33
+ * Marking the invoice as sent is deliberately NOT folded in here: callers that
34
+ * want both run this first, write the bytes out, and only then call
35
+ * `markInvoicePrinted`. Doing it the other way round means a full disk or a bad
36
+ * path leaves an invoice flagged as sent with no PDF to show for it.
37
+ */
38
+ export declare function getInvoicePdf(documentNumber: string): Promise<Buffer>;
39
+ export interface MarkInvoicePrintedResult {
40
+ /** The invoice's state after printing. */
41
+ invoice: Record<string, unknown>;
42
+ /**
43
+ * Whether that state was actually read back from Fortnox. When false, the
44
+ * print request was accepted but its effect could not be confirmed — callers
45
+ * must report the outcome as unknown rather than as sent.
46
+ */
47
+ confirmed: boolean;
48
+ /**
49
+ * The document Fortnox generated for this print action, when it came back
50
+ * intact. Callers saving a copy should prefer these bytes over a separately
51
+ * fetched /preview: the two are distinct requests, so a concurrent edit could
52
+ * otherwise leave the saved file a version behind the one marked as sent.
53
+ */
54
+ pdf?: Buffer;
55
+ }
56
+ /**
57
+ * Mark an invoice as sent via Fortnox's /print action, and report its resulting
58
+ * state. /print is a GET that changes data, so it is flagged as a mutation to
59
+ * keep it out of the automatic retry path.
60
+ *
61
+ * Once the /print request succeeds the invoice has been changed, so from that
62
+ * point on this function does not throw: neither a malformed PDF body nor a
63
+ * failed read-back may turn a completed accounting change into a reported
64
+ * failure.
65
+ */
66
+ export declare function markInvoicePrinted(documentNumber: string): Promise<MarkInvoicePrintedResult>;
29
67
  export declare function bookkeepInvoice(documentNumber: string): Promise<Record<string, unknown>>;
30
68
  export declare function creditInvoice(documentNumber: string): Promise<Record<string, unknown>>;
31
69
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"invoices.d.ts","sourceRoot":"","sources":["../../src/operations/invoices.ts"],"names":[],"mappings":"AAOA,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,eAAe,CAAC,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;CAChG;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,YAAY,CAAC,MAAM,GAAE,kBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuB7F;AAED,wBAAsB,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAGzF;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC;AAED,wBAAsB,aAAa,CACjC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAUlC;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,WAAW,CAC/B,cAAc,EAAE,MAAM,EACtB,MAAM,GAAE,UAAoB,EAC5B,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAqBlC;AAED,wBAAsB,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQ9F;AAED,wBAAsB,aAAa,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQ5F"}
1
+ {"version":3,"file":"invoices.d.ts","sourceRoot":"","sources":["../../src/operations/invoices.ts"],"names":[],"mappings":"AAYA,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IACpC,eAAe,CAAC,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;CAChG;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAsB,YAAY,CAAC,MAAM,GAAE,kBAAuB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuB7F;AAED,wBAAsB,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAGzF;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC;AAED,wBAAsB,aAAa,CACjC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAUlC;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,WAAW,CAC/B,cAAc,EAAE,MAAM,EACtB,MAAM,GAAE,UAAoB,EAC5B,YAAY,CAAC,EAAE,gBAAgB,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA8BlC;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE3E;AAED,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,wBAAwB,CAAC,CAuBnC;AAED,wBAAsB,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQ9F;AAED,wBAAsB,aAAa,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAQ5F"}
@@ -1,4 +1,4 @@
1
- import { fortnoxRequest, fetchAllPages } from '../fortnox-client.js';
1
+ import { fortnoxRequest, fortnoxRequestPdf, fortnoxRequestPdfFromMutation, fetchAllPages, } from '../fortnox-client.js';
2
2
  import { documentSegment } from '../identifiers.js';
3
3
  export async function listInvoices(params = {}) {
4
4
  const queryParams = {
@@ -55,10 +55,61 @@ export async function sendInvoice(documentNumber, method = 'email', emailOptions
55
55
  body: { Invoice: { EmailInformation: emailInfo } },
56
56
  });
57
57
  }
58
- const endpointSuffix = method === 'email' ? 'email' : method === 'einvoice' ? 'einvoice' : 'print';
59
- const data = await fortnoxRequest(`invoices/${documentId}/${endpointSuffix}`);
58
+ if (method === 'print') {
59
+ return (await markInvoicePrinted(documentNumber)).invoice;
60
+ }
61
+ // Exhaustive on purpose: no silent fallback. 'email' and 'einvoice' both send
62
+ // the invoice to the customer, so an unrecognised method must fail loudly
63
+ // rather than pick one of them.
64
+ if (method !== 'email' && method !== 'einvoice') {
65
+ throw new Error(`Unsupported send method: ${String(method)}`);
66
+ }
67
+ const data = await fortnoxRequest(`invoices/${documentId}/${method}`);
60
68
  return data?.Invoice || {};
61
69
  }
70
+ /**
71
+ * Fetch an invoice as a PDF. Always uses /preview, which returns the same
72
+ * document as /print but leaves the invoice untouched.
73
+ *
74
+ * Marking the invoice as sent is deliberately NOT folded in here: callers that
75
+ * want both run this first, write the bytes out, and only then call
76
+ * `markInvoicePrinted`. Doing it the other way round means a full disk or a bad
77
+ * path leaves an invoice flagged as sent with no PDF to show for it.
78
+ */
79
+ export async function getInvoicePdf(documentNumber) {
80
+ return fortnoxRequestPdf(`invoices/${documentSegment(documentNumber)}/preview`);
81
+ }
82
+ /**
83
+ * Mark an invoice as sent via Fortnox's /print action, and report its resulting
84
+ * state. /print is a GET that changes data, so it is flagged as a mutation to
85
+ * keep it out of the automatic retry path.
86
+ *
87
+ * Once the /print request succeeds the invoice has been changed, so from that
88
+ * point on this function does not throw: neither a malformed PDF body nor a
89
+ * failed read-back may turn a completed accounting change into a reported
90
+ * failure.
91
+ */
92
+ export async function markInvoicePrinted(documentNumber) {
93
+ const documentId = documentSegment(documentNumber);
94
+ const pdf = await fortnoxRequestPdfFromMutation(`invoices/${documentId}/print`);
95
+ try {
96
+ return { invoice: await getInvoice(documentNumber), confirmed: true, pdf };
97
+ }
98
+ catch (err) {
99
+ // Fortnox accepted the print request, so the change has most likely been
100
+ // applied — but "most likely" is not "confirmed". Deliberately no
101
+ // `Sent: true` here: synthesizing it would present an unverified outcome as
102
+ // established fact about someone's accounting records.
103
+ return {
104
+ invoice: {
105
+ DocumentNumber: documentNumber,
106
+ Note: `Fortnox accepted the print request, but reading the invoice back failed, so its sent status could not be confirmed: ${err instanceof Error ? err.message : String(err)}`,
107
+ },
108
+ confirmed: false,
109
+ pdf,
110
+ };
111
+ }
112
+ }
62
113
  export async function bookkeepInvoice(documentNumber) {
63
114
  const data = await fortnoxRequest(`invoices/${documentSegment(documentNumber)}/bookkeep`, {
64
115
  method: 'PUT',
@@ -1 +1 @@
1
- {"version":3,"file":"invoices.js","sourceRoot":"","sources":["../../src/operations/invoices.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"invoices.js","sourceRoot":"","sources":["../../src/operations/invoices.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"invoices.d.ts","sourceRoot":"","sources":["../../src/tools/invoices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiCpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyN5D"}
1
+ {"version":3,"file":"invoices.d.ts","sourceRoot":"","sources":["../../src/tools/invoices.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkGpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgU5D"}
@@ -1,5 +1,8 @@
1
1
  import { z } from 'zod';
2
- import { listInvoices, getInvoice, createInvoice, updateInvoice, sendInvoice, bookkeepInvoice, creditInvoice, } from '../operations/invoices.js';
2
+ import { closeSync, constants as fsConstants, lstatSync, mkdtempSync, openSync, writeSync, } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join, resolve } from 'node:path';
5
+ import { listInvoices, getInvoice, createInvoice, updateInvoice, sendInvoice, getInvoicePdf, markInvoicePrinted, bookkeepInvoice, creditInvoice, } from '../operations/invoices.js';
3
6
  import { invoiceListColumns, invoiceDetailColumns, invoiceConfirmColumns } from '../views.js';
4
7
  import { confirmationResponse, detailResponse, dryRunResponse, listResponse, requireConfirmation, } from '../tool-output.js';
5
8
  const InvoiceRowSchema = z.object({
@@ -13,6 +16,52 @@ const InvoiceRowSchema = z.object({
13
16
  Discount: z.number().optional().describe('Rabatt i procent'),
14
17
  });
15
18
  const DocumentNumberSchema = z.string().regex(/^\d+$/, 'Document number must be numeric');
19
+ /**
20
+ * Write a PDF to `target`, refusing to write through a symlink.
21
+ *
22
+ * These paths come from tool arguments, i.e. they are model-generated and can be
23
+ * influenced by whatever the model just read. `O_EXCL` already refuses to follow
24
+ * a symlink; `O_NOFOLLOW` gives the overwrite path the same guarantee, so
25
+ * "replace this file" can never silently truncate a symlink's target instead.
26
+ * O_NOFOLLOW is POSIX-only, so Windows falls back to an explicit lstat check.
27
+ */
28
+ function writePdf(target, pdf, overwrite) {
29
+ const { O_WRONLY, O_CREAT, O_TRUNC, O_EXCL, O_NOFOLLOW } = fsConstants;
30
+ const flags = overwrite
31
+ ? O_WRONLY | O_CREAT | O_TRUNC | (O_NOFOLLOW ?? 0)
32
+ : O_WRONLY | O_CREAT | O_EXCL;
33
+ // Windows has no O_NOFOLLOW, so the flag above degrades to a no-op there.
34
+ // Check explicitly instead. This is a TOCTOU-racy fallback rather than an
35
+ // atomic guarantee, but it closes the ordinary case on the one platform the
36
+ // kernel flag cannot cover.
37
+ if (overwrite && !O_NOFOLLOW && lstatSync(target, { throwIfNoEntry: false })?.isSymbolicLink()) {
38
+ throw new Error(`${target} is a symbolic link. Refusing to write through it — pass the real path instead.`);
39
+ }
40
+ try {
41
+ const fd = openSync(target, flags, 0o600);
42
+ try {
43
+ // writeSync may return a short count; keep going until the whole buffer
44
+ // has landed. writeFileSync used to do this loop internally.
45
+ let written = 0;
46
+ while (written < pdf.length) {
47
+ written += writeSync(fd, pdf, written, pdf.length - written);
48
+ }
49
+ }
50
+ finally {
51
+ closeSync(fd);
52
+ }
53
+ }
54
+ catch (err) {
55
+ const code = err.code;
56
+ if (code === 'EEXIST') {
57
+ throw new Error(`${target} already exists. Pass a different outputPath, or overwrite: true to replace it.`);
58
+ }
59
+ if (code === 'ELOOP') {
60
+ throw new Error(`${target} is a symbolic link. Refusing to write through it — pass the real path instead.`);
61
+ }
62
+ throw err;
63
+ }
64
+ }
16
65
  export function registerInvoiceTools(server) {
17
66
  server.tool('fortnox_list_invoices', 'Lista/filtrera fakturor i Fortnox. Returnerar: DocumentNumber, CustomerName, InvoiceDate, DueDate, Total, Balance.', {
18
67
  filter: z
@@ -128,6 +177,92 @@ export function registerInvoiceTools(server) {
128
177
  const invoice = await sendInvoice(documentNumber, sendMethod, emailOptions);
129
178
  return confirmationResponse(`Faktura ${documentNumber} skickad via ${sendMethod}.`, invoice, invoiceConfirmColumns, includeRaw);
130
179
  });
180
+ server.tool('fortnox_invoice_pdf', 'Hämta en faktura som PDF och spara den på disk. Returnerar sökvägen till filen (inte PDF-innehållet). PDF:en hämtas alltid via Fortnox /preview, vilket INTE ändrar fakturan. Med markSent anropas /print efteråt, efter att filen skrivits.', {
181
+ documentNumber: DocumentNumberSchema.describe('Fakturanummer'),
182
+ outputPath: z
183
+ .string()
184
+ .optional()
185
+ .describe('Sökväg att spara PDF:en till. Skriver inte över en befintlig fil om inte overwrite är satt. Utelämnas: en ny privat temp-katalog används.'),
186
+ overwrite: z
187
+ .boolean()
188
+ .optional()
189
+ .describe('Tillåt att en befintlig fil på outputPath skrivs över'),
190
+ markSent: z
191
+ .boolean()
192
+ .optional()
193
+ .describe('Markera även fakturan som skickad i Fortnox (använder /print)'),
194
+ confirm: z
195
+ .boolean()
196
+ .optional()
197
+ .describe('Bekräfta — krävs endast när markSent är satt, eftersom den ändrar fakturan'),
198
+ dryRun: z.boolean().optional().describe('Visa åtgärden utan att hämta PDF:en'),
199
+ }, async ({ documentNumber, outputPath, overwrite, markSent, confirm, dryRun }) => {
200
+ const action = markSent
201
+ ? `download invoice ${documentNumber} as PDF and mark it as sent`
202
+ : `download invoice ${documentNumber} as PDF`;
203
+ if (dryRun)
204
+ return dryRunResponse(action);
205
+ // Only the /print variant changes the invoice; a plain download is read-only.
206
+ if (markSent && !confirm)
207
+ requireConfirmation(action);
208
+ // Arguments here are agent-generated, so a stray path must not silently
209
+ // truncate an existing file. Without an explicit path we use a fresh
210
+ // private directory rather than a predictable, clobber-prone temp name.
211
+ const target = outputPath
212
+ ? resolve(outputPath)
213
+ : join(mkdtempSync(join(tmpdir(), 'noxctl-')), `invoice-${documentNumber}.pdf`);
214
+ const pdf = await getInvoicePdf(documentNumber);
215
+ writePdf(target, pdf, overwrite);
216
+ // Only now that the PDF is safely on disk do we change anything in Fortnox.
217
+ // If that fails, the download still succeeded — say so, or the caller has
218
+ // no idea a usable file is sitting there.
219
+ let printed;
220
+ if (markSent) {
221
+ try {
222
+ printed = await markInvoicePrinted(documentNumber);
223
+ }
224
+ catch (err) {
225
+ throw new Error(`Faktura ${documentNumber} sparades som PDF: ${target} (${pdf.length} bytes), men kunde inte markeras som skickad: ${err instanceof Error ? err.message : String(err)}`);
226
+ }
227
+ }
228
+ // Prefer the document /print actually produced, so the saved copy matches
229
+ // the version that was marked as sent. Best-effort: the /preview copy is
230
+ // already on disk, and the invoice is already flagged, so a failure here
231
+ // must not be raised as if the whole operation failed.
232
+ let bytes = pdf.length;
233
+ let refreshNote = '';
234
+ if (printed?.pdf) {
235
+ try {
236
+ writePdf(target, printed.pdf, true);
237
+ bytes = printed.pdf.length;
238
+ }
239
+ catch (err) {
240
+ refreshNote = ` Den sparade filen är /preview-versionen; kunde inte skriva om den med den utskrivna versionen: ${err instanceof Error ? err.message : String(err)}`;
241
+ }
242
+ }
243
+ // Only state that the invoice is sent if Fortnox confirmed it. Asking for
244
+ // markSent is not evidence that it took effect.
245
+ let sentNote = '';
246
+ if (printed && !printed.confirmed) {
247
+ sentNote = ` ${String(printed.invoice.Note)}`;
248
+ }
249
+ else if (printed && printed.invoice.Sent === true) {
250
+ sentNote = ' Fakturan är nu markerad som skickad.';
251
+ }
252
+ else if (printed) {
253
+ sentNote = ' Varning: Fortnox rapporterar fortfarande fakturan som ej skickad.';
254
+ }
255
+ return confirmationResponse(`Faktura ${documentNumber} sparad som PDF: ${target} (${bytes} bytes).` +
256
+ sentNote +
257
+ refreshNote, {
258
+ DocumentNumber: documentNumber,
259
+ Path: target,
260
+ Bytes: bytes,
261
+ // Report what Fortnox says, not what we asked for; undefined means
262
+ // "not checked" or "could not be confirmed".
263
+ Sent: printed?.confirmed ? printed.invoice.Sent : undefined,
264
+ });
265
+ });
131
266
  server.tool('fortnox_bookkeep_invoice', 'Bokför en faktura i Fortnox', {
132
267
  documentNumber: DocumentNumberSchema.describe('Fakturanummer att bokföra'),
133
268
  confirm: z.boolean().optional().describe('Bekräfta att fakturan ska bokföras'),