@substrat-run/connector-fortnox 0.2.0 → 0.4.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/LICENSE +661 -0
- package/README.md +43 -19
- package/dist/api.d.ts +12 -17
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +38 -10
- package/dist/api.js.map +1 -1
- package/dist/connect.d.ts +44 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/connect.js +98 -0
- package/dist/connect.js.map +1 -0
- package/dist/index.d.ts +13 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/mock.d.ts +24 -4
- package/dist/mock.d.ts.map +1 -1
- package/dist/mock.js +49 -9
- package/dist/mock.js.map +1 -1
- package/dist/sie4.d.ts +35 -1
- package/dist/sie4.d.ts.map +1 -1
- package/dist/sie4.js +61 -1
- package/dist/sie4.js.map +1 -1
- package/package.json +13 -13
package/dist/mock.d.ts
CHANGED
|
@@ -4,13 +4,13 @@ import type { FetchLike } from '@substrat-run/kernel';
|
|
|
4
4
|
* whole sweep without a provider account.
|
|
5
5
|
*
|
|
6
6
|
* **What a mock proves:** that our shape works — the client-credentials mint, the
|
|
7
|
-
*
|
|
7
|
+
* PC8/CP437 decode, the year-overlap pick, the paging, the unchanged-hash skip.
|
|
8
8
|
* **What it cannot prove:** that our reading of Fortnox's API is correct. The mock IS
|
|
9
9
|
* our reading. Green here means *ready to check against a real company*, which is what
|
|
10
10
|
* `test/live.test.ts` does when a credential is present.
|
|
11
11
|
*
|
|
12
12
|
* The one thing it models with real bytes rather than a convenient string is the SIE
|
|
13
|
-
* response: {@link FortnoxMock.sieBytes} encodes to
|
|
13
|
+
* response: {@link FortnoxMock.sieBytes} encodes to PC8/CP437, so a connector that
|
|
14
14
|
* forgot to decode explicitly fails here rather than in production with mangled
|
|
15
15
|
* account names.
|
|
16
16
|
*/
|
|
@@ -32,9 +32,27 @@ export interface FortnoxMockOptions {
|
|
|
32
32
|
sie?: Record<number, string>;
|
|
33
33
|
/** Seconds a minted token claims to live. */
|
|
34
34
|
expiresIn?: number;
|
|
35
|
+
/**
|
|
36
|
+
* The one-time consent code the authorization-code exchange accepts — what a
|
|
37
|
+
* consent-flow test (`completeFortnoxConsent`) presents. SINGLE-use, as Fortnox's
|
|
38
|
+
* is: the second exchange of the same code answers `invalid_grant`, which is the
|
|
39
|
+
* reloaded-callback-tab case a connect flow must survive.
|
|
40
|
+
*/
|
|
41
|
+
consentCode?: string;
|
|
35
42
|
}
|
|
36
|
-
/**
|
|
37
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Encode to PC8 (code page 437) — the charset a real Fortnox SIE export declares in
|
|
45
|
+
* `#FORMAT` and actually sends.
|
|
46
|
+
*
|
|
47
|
+
* This used to encode ISO-8859-1, and that single wrong premise is what let a wrong
|
|
48
|
+
* decoder pass every test in this package: the mock encoded latin1, the reader decoded
|
|
49
|
+
* latin1, and the two agreed with each other while disagreeing with Fortnox. Only the
|
|
50
|
+
* live suite could see it. Encoding here the way the provider really does is what makes
|
|
51
|
+
* the mock evidence about Fortnox rather than about our own assumption.
|
|
52
|
+
*
|
|
53
|
+
* A code point with no CP437 representation becomes `?`, exactly as Fortnox would.
|
|
54
|
+
*/
|
|
55
|
+
export declare function pc8Bytes(text: string): Uint8Array;
|
|
38
56
|
export declare class FortnoxMock {
|
|
39
57
|
readonly apiBase = "https://api.fortnox.test/3";
|
|
40
58
|
readonly oauthBase = "https://apps.fortnox.test/oauth-v1";
|
|
@@ -45,6 +63,8 @@ export declare class FortnoxMock {
|
|
|
45
63
|
private readonly years;
|
|
46
64
|
private readonly sie;
|
|
47
65
|
private readonly expiresIn;
|
|
66
|
+
/** Spends to `undefined` on the first successful exchange. */
|
|
67
|
+
private consentCode;
|
|
48
68
|
/** Every token this mock has minted — a test asserts the mint happened exactly once. */
|
|
49
69
|
readonly mints: string[];
|
|
50
70
|
/** Every REST path fetched, in order. */
|
package/dist/mock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAQtD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,cAAc,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpE,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAejD;AAED,qBAAa,WAAW;IACtB,QAAQ,CAAC,OAAO,gCAAgC;IAChD,QAAQ,CAAC,SAAS,wCAAwC;IAE1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6C;IACrE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoD;IAC1E,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAyB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,8DAA8D;IAC9D,OAAO,CAAC,WAAW,CAAqB;IAExC,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAM;IAC9B,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAM;IAE9B,YAAY,OAAO,GAAE,kBAAuB,EAgB3C;IAED,iFAAiF;IACjF,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAElD;IAED,OAAO,CAAC,IAAI;IAUZ,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,CA2EvB;CACH"}
|
package/dist/mock.js
CHANGED
|
@@ -1,11 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { CP437_HIGH } from './sie4.js';
|
|
2
|
+
/**
|
|
3
|
+
* Encode to PC8 (code page 437) — the charset a real Fortnox SIE export declares in
|
|
4
|
+
* `#FORMAT` and actually sends.
|
|
5
|
+
*
|
|
6
|
+
* This used to encode ISO-8859-1, and that single wrong premise is what let a wrong
|
|
7
|
+
* decoder pass every test in this package: the mock encoded latin1, the reader decoded
|
|
8
|
+
* latin1, and the two agreed with each other while disagreeing with Fortnox. Only the
|
|
9
|
+
* live suite could see it. Encoding here the way the provider really does is what makes
|
|
10
|
+
* the mock evidence about Fortnox rather than about our own assumption.
|
|
11
|
+
*
|
|
12
|
+
* A code point with no CP437 representation becomes `?`, exactly as Fortnox would.
|
|
13
|
+
*/
|
|
14
|
+
export function pc8Bytes(text) {
|
|
15
|
+
// `for...of` iterates CODE POINTS; `text[i]` would hand back UTF-16 code units, so an
|
|
16
|
+
// astral character (an emoji in a voucher text, say) would split into two surrogate
|
|
17
|
+
// halves and emit two `?` bytes where the contract above promises one.
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const ch of text) {
|
|
20
|
+
const code = ch.codePointAt(0) ?? 0x3f;
|
|
21
|
+
if (code < 0x80) {
|
|
22
|
+
out.push(code);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const high = CP437_HIGH.indexOf(ch);
|
|
26
|
+
out.push(high === -1 ? 0x3f : 0x80 + high);
|
|
7
27
|
}
|
|
8
|
-
return out;
|
|
28
|
+
return new Uint8Array(out);
|
|
9
29
|
}
|
|
10
30
|
export class FortnoxMock {
|
|
11
31
|
apiBase = 'https://api.fortnox.test/3';
|
|
@@ -17,6 +37,8 @@ export class FortnoxMock {
|
|
|
17
37
|
years;
|
|
18
38
|
sie;
|
|
19
39
|
expiresIn;
|
|
40
|
+
/** Spends to `undefined` on the first successful exchange. */
|
|
41
|
+
consentCode;
|
|
20
42
|
/** Every token this mock has minted — a test asserts the mint happened exactly once. */
|
|
21
43
|
mints = [];
|
|
22
44
|
/** Every REST path fetched, in order. */
|
|
@@ -36,6 +58,7 @@ export class FortnoxMock {
|
|
|
36
58
|
];
|
|
37
59
|
this.sie = options.sie ?? {};
|
|
38
60
|
this.expiresIn = options.expiresIn ?? 3600;
|
|
61
|
+
this.consentCode = options.consentCode;
|
|
39
62
|
}
|
|
40
63
|
/** Replace one year's SIE payload — how a test simulates "the books changed". */
|
|
41
64
|
setSie(financialYearId, text) {
|
|
@@ -47,7 +70,7 @@ export class FortnoxMock {
|
|
|
47
70
|
ok: status >= 200 && status < 300,
|
|
48
71
|
status,
|
|
49
72
|
text: async () => text,
|
|
50
|
-
arrayBuffer: async () =>
|
|
73
|
+
arrayBuffer: async () => pc8Bytes(text).buffer,
|
|
51
74
|
};
|
|
52
75
|
}
|
|
53
76
|
/** The `fetch` a connector is handed. */
|
|
@@ -61,6 +84,23 @@ export class FortnoxMock {
|
|
|
61
84
|
if (auth !== expected) {
|
|
62
85
|
return this.json({ error: 'invalid_client', error_description: 'bad client credentials' }, 401);
|
|
63
86
|
}
|
|
87
|
+
// The consent flow's one-time exchange: no TenantId header (the exchange is what
|
|
88
|
+
// DISCOVERS the company), and the code spends on first use.
|
|
89
|
+
if (String(init?.body ?? '').includes('grant_type=authorization_code')) {
|
|
90
|
+
const code = new URLSearchParams(String(init?.body ?? '')).get('code') ?? undefined;
|
|
91
|
+
if (this.consentCode === undefined || code !== this.consentCode) {
|
|
92
|
+
return this.json({ error: 'invalid_grant', error_description: 'code spent or unknown' }, 400);
|
|
93
|
+
}
|
|
94
|
+
this.consentCode = undefined;
|
|
95
|
+
const token = `consent-token-${this.mints.length + 1}`;
|
|
96
|
+
this.mints.push(token);
|
|
97
|
+
return this.json({
|
|
98
|
+
access_token: token,
|
|
99
|
+
token_type: 'bearer',
|
|
100
|
+
expires_in: this.expiresIn,
|
|
101
|
+
scope: 'bookkeeping companyinformation',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
64
104
|
if ((headers['TenantId'] ?? '') !== this.tenantId) {
|
|
65
105
|
// Fortnox answers 400 here, not 404 — a wrong TenantId reads like a bad client
|
|
66
106
|
// pair unless the message is surfaced, which is why the connector surfaces it.
|
|
@@ -97,7 +137,7 @@ export class FortnoxMock {
|
|
|
97
137
|
if (text === undefined) {
|
|
98
138
|
return this.json({ ErrorInformation: { message: 'no such financial year' } }, 404);
|
|
99
139
|
}
|
|
100
|
-
const bytes =
|
|
140
|
+
const bytes = pc8Bytes(text);
|
|
101
141
|
return {
|
|
102
142
|
ok: true,
|
|
103
143
|
status: 200,
|
package/dist/mock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock.js","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mock.js","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"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"}
|
package/dist/sie4.d.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* per-voucher REST endpoints.
|
|
5
5
|
*
|
|
6
6
|
* Deliberately a parser over a *text* input, with no I/O of its own: the decoding
|
|
7
|
-
* from
|
|
7
|
+
* from PC8/CP437 happens in {@link decodeSie} below, called at the seam that owns the
|
|
8
|
+
* bytes ({@link FortnoxApi.sieFile}),
|
|
8
9
|
* so this file is pure and testable against a fixture, and a caller reading SIE from
|
|
9
10
|
* somewhere else (an upload, an archive) can use it unchanged.
|
|
10
11
|
*
|
|
@@ -22,6 +23,39 @@
|
|
|
22
23
|
* ignored rather than fatal: SIE files carry vendor extensions, and refusing a
|
|
23
24
|
* file over a post we do not read would break on a Fortnox release that adds one.
|
|
24
25
|
*/
|
|
26
|
+
/**
|
|
27
|
+
* Bytes 0x80–0xFF of code page 437, in order — the half of PC8 that is not ASCII.
|
|
28
|
+
*
|
|
29
|
+
* Generated from the code page, not typed from memory. Only the Swedish letters are
|
|
30
|
+
* load-bearing here (0x84 ä, 0x86 å, 0x8E Ä, 0x8F Å, 0x94 ö, 0x99 Ö), but a partial
|
|
31
|
+
* table would silently mangle everything else, so the whole upper half is present.
|
|
32
|
+
*/
|
|
33
|
+
export declare const CP437_HIGH: string;
|
|
34
|
+
/**
|
|
35
|
+
* Decode a SIE file's bytes, honouring the charset it declares in `#FORMAT`.
|
|
36
|
+
*
|
|
37
|
+
* ## Why this is not `TextDecoder`
|
|
38
|
+
*
|
|
39
|
+
* SIE4 files are **PC8, which is code page 437** — an MS-DOS charset that predates the
|
|
40
|
+
* standard and is NOT in the WHATWG Encoding registry, so `new TextDecoder('cp437')`
|
|
41
|
+
* throws `RangeError` in every runtime. There is no web-standard decoder to reach for,
|
|
42
|
+
* which is why the table above exists rather than an import.
|
|
43
|
+
*
|
|
44
|
+
* ## Why the wrong decoder was invisible
|
|
45
|
+
*
|
|
46
|
+
* This previously decoded as `iso-8859-1`, and nothing complained — twice over. Every
|
|
47
|
+
* byte 0x00–0xFF is a valid latin1 code point, so a mis-decode can never produce U+FFFD
|
|
48
|
+
* and the "no replacement character" check that guarded this could not fail by
|
|
49
|
+
* construction. And `TextDecoder('iso-8859-1')` is really **windows-1252**, so Fortnox's
|
|
50
|
+
* `0x94` ö arrived as `”`. The result was correct-looking Swedish account names with the
|
|
51
|
+
* wrong letters in them — wrong data on a screen, never a throw. Confirmed against
|
|
52
|
+
* api.fortnox.se 2026-09-03, whose export declares `#FORMAT PC8`.
|
|
53
|
+
*
|
|
54
|
+
* A file declaring any other charset is REFUSED rather than decoded on a guess: PC8 is
|
|
55
|
+
* what SIE4 mandates and what every Fortnox export observed so far sends, and a wrong
|
|
56
|
+
* guess is invisible rather than loud.
|
|
57
|
+
*/
|
|
58
|
+
export declare function decodeSie(bytes: ArrayBuffer | Uint8Array): string;
|
|
25
59
|
/** A parsed `#KONTO` — the chart of accounts. */
|
|
26
60
|
export interface SieAccount {
|
|
27
61
|
number: string;
|
package/dist/sie4.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sie4.d.ts","sourceRoot":"","sources":["../src/sie4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
1
|
+
{"version":3,"file":"sie4.d.ts","sourceRoot":"","sources":["../src/sie4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,QAQ6E,CAAC;AAErG;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,CAuBjE;AAED,iDAAiD;AACjD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,mFAAmF;AACnF,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,yCAAyC;AACzC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,2CAA2C;AAC3C,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,cAAc,EAAE,CAAC;CAChC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC3C,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,QAAQ,EAAE,UAAU,EAAE,CAAC;CACxB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CA0DnD;AAgBD,4EAA4E;AAC5E,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAiBzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAkGjD"}
|
package/dist/sie4.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* per-voucher REST endpoints.
|
|
5
5
|
*
|
|
6
6
|
* Deliberately a parser over a *text* input, with no I/O of its own: the decoding
|
|
7
|
-
* from
|
|
7
|
+
* from PC8/CP437 happens in {@link decodeSie} below, called at the seam that owns the
|
|
8
|
+
* bytes ({@link FortnoxApi.sieFile}),
|
|
8
9
|
* so this file is pure and testable against a fixture, and a caller reading SIE from
|
|
9
10
|
* somewhere else (an upload, an archive) can use it unchanged.
|
|
10
11
|
*
|
|
@@ -22,6 +23,65 @@
|
|
|
22
23
|
* ignored rather than fatal: SIE files carry vendor extensions, and refusing a
|
|
23
24
|
* file over a post we do not read would break on a Fortnox release that adds one.
|
|
24
25
|
*/
|
|
26
|
+
/**
|
|
27
|
+
* Bytes 0x80–0xFF of code page 437, in order — the half of PC8 that is not ASCII.
|
|
28
|
+
*
|
|
29
|
+
* Generated from the code page, not typed from memory. Only the Swedish letters are
|
|
30
|
+
* load-bearing here (0x84 ä, 0x86 å, 0x8E Ä, 0x8F Å, 0x94 ö, 0x99 Ö), but a partial
|
|
31
|
+
* table would silently mangle everything else, so the whole upper half is present.
|
|
32
|
+
*/
|
|
33
|
+
export const CP437_HIGH = '\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5' +
|
|
34
|
+
'\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00a2\u00a3\u00a5\u20a7\u0192' +
|
|
35
|
+
'\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u2310\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb' +
|
|
36
|
+
'\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510' +
|
|
37
|
+
'\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567' +
|
|
38
|
+
'\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580' +
|
|
39
|
+
'\u03b1\u00df\u0393\u03c0\u03a3\u03c3\u00b5\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u03c6\u03b5\u2229' +
|
|
40
|
+
'\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u00a0';
|
|
41
|
+
/**
|
|
42
|
+
* Decode a SIE file's bytes, honouring the charset it declares in `#FORMAT`.
|
|
43
|
+
*
|
|
44
|
+
* ## Why this is not `TextDecoder`
|
|
45
|
+
*
|
|
46
|
+
* SIE4 files are **PC8, which is code page 437** — an MS-DOS charset that predates the
|
|
47
|
+
* standard and is NOT in the WHATWG Encoding registry, so `new TextDecoder('cp437')`
|
|
48
|
+
* throws `RangeError` in every runtime. There is no web-standard decoder to reach for,
|
|
49
|
+
* which is why the table above exists rather than an import.
|
|
50
|
+
*
|
|
51
|
+
* ## Why the wrong decoder was invisible
|
|
52
|
+
*
|
|
53
|
+
* This previously decoded as `iso-8859-1`, and nothing complained — twice over. Every
|
|
54
|
+
* byte 0x00–0xFF is a valid latin1 code point, so a mis-decode can never produce U+FFFD
|
|
55
|
+
* and the "no replacement character" check that guarded this could not fail by
|
|
56
|
+
* construction. And `TextDecoder('iso-8859-1')` is really **windows-1252**, so Fortnox's
|
|
57
|
+
* `0x94` ö arrived as `”`. The result was correct-looking Swedish account names with the
|
|
58
|
+
* wrong letters in them — wrong data on a screen, never a throw. Confirmed against
|
|
59
|
+
* api.fortnox.se 2026-09-03, whose export declares `#FORMAT PC8`.
|
|
60
|
+
*
|
|
61
|
+
* A file declaring any other charset is REFUSED rather than decoded on a guess: PC8 is
|
|
62
|
+
* what SIE4 mandates and what every Fortnox export observed so far sends, and a wrong
|
|
63
|
+
* guess is invisible rather than loud.
|
|
64
|
+
*/
|
|
65
|
+
export function decodeSie(bytes) {
|
|
66
|
+
const view = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
|
67
|
+
// `#FORMAT` is ASCII and sits in the header, so it can be read before the charset is
|
|
68
|
+
// known — the one thing safe to decode without having decided first.
|
|
69
|
+
const header = String.fromCharCode(...view.subarray(0, 512));
|
|
70
|
+
const declared = /^#FORMAT\s+"?([A-Za-z0-9-]+)"?/m.exec(header)?.[1]?.toUpperCase();
|
|
71
|
+
if (declared !== undefined && declared !== 'PC8') {
|
|
72
|
+
// Refusing beats guessing. Reading a charset wrong does not throw anywhere
|
|
73
|
+
// downstream — it yields plausible Swedish account names with the wrong letters,
|
|
74
|
+
// which is precisely the failure that survived a year of green tests here.
|
|
75
|
+
throw new Error(`SIE #FORMAT ${declared} is not supported — this reader implements PC8 (CP437) only`);
|
|
76
|
+
}
|
|
77
|
+
let out = '';
|
|
78
|
+
for (const byte of view) {
|
|
79
|
+
// The index is provably in range (0x00–0x7F took the other branch), so the
|
|
80
|
+
// fallback is unreachable; it is here only because the compiler cannot see that.
|
|
81
|
+
out += byte < 0x80 ? String.fromCharCode(byte) : (CP437_HIGH[byte - 0x80] ?? '\ufffd');
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
25
85
|
/**
|
|
26
86
|
* Split one SIE line into fields, honouring quoting and object lists.
|
|
27
87
|
*
|
package/dist/sie4.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sie4.js","sourceRoot":"","sources":["../src/sie4.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
1
|
+
{"version":3,"file":"sie4.js","sourceRoot":"","sources":["../src/sie4.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/connector-fortnox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Substrat connector: Fortnox accounting (Swedish). Reads a company's bookkeeping as SIE4 on a poll and lands it into a scope through the vertical's own operation. Auth is OAuth2 client-credentials against a service consent, so there is no refresh token to rotate. Host code — swept on a ScopeHost, never module code.",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -24,22 +24,22 @@
|
|
|
24
24
|
"default": "./dist/index.js"
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "tsc -p tsconfig.json",
|
|
29
|
-
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
30
|
-
"test": "vitest run"
|
|
31
|
-
},
|
|
32
27
|
"dependencies": {
|
|
33
|
-
"@substrat-run/contracts": "
|
|
34
|
-
"@substrat-run/kernel": "
|
|
28
|
+
"@substrat-run/contracts": "^0.98.1",
|
|
29
|
+
"@substrat-run/kernel": "^0.98.1"
|
|
35
30
|
},
|
|
36
31
|
"devDependencies": {
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
32
|
+
"typescript": "^7.0.0",
|
|
33
|
+
"vitest": "^3.2.7",
|
|
34
|
+
"zod": "^4.4.3",
|
|
35
|
+
"@substrat-run/adapter-sqlite": "^0.98.1"
|
|
41
36
|
},
|
|
42
37
|
"peerDependencies": {
|
|
43
38
|
"zod": "^4.4.0"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsc -p tsconfig.json",
|
|
42
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
43
|
+
"test": "vitest run"
|
|
44
44
|
}
|
|
45
|
-
}
|
|
45
|
+
}
|