@coderoftime/fints 0.2.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.
Files changed (215) hide show
  1. package/CHANGELOG.md +377 -0
  2. package/README.md +31 -23
  3. package/dist/client.d.ts +3 -2
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +52 -9
  6. package/dist/client.js.map +1 -1
  7. package/dist/core/account.d.ts +15 -4
  8. package/dist/core/account.d.ts.map +1 -1
  9. package/dist/core/account.js +84 -36
  10. package/dist/core/account.js.map +1 -1
  11. package/dist/core/amount.d.ts +13 -3
  12. package/dist/core/amount.d.ts.map +1 -1
  13. package/dist/core/amount.js +42 -8
  14. package/dist/core/amount.js.map +1 -1
  15. package/dist/core/balance.d.ts +3 -0
  16. package/dist/core/balance.d.ts.map +1 -1
  17. package/dist/core/balance.js +5 -0
  18. package/dist/core/balance.js.map +1 -1
  19. package/dist/core/bank-info.d.ts +20 -3
  20. package/dist/core/bank-info.d.ts.map +1 -1
  21. package/dist/core/bank-info.js +25 -4
  22. package/dist/core/bank-info.js.map +1 -1
  23. package/dist/core/client.d.ts +42 -15
  24. package/dist/core/client.d.ts.map +1 -1
  25. package/dist/core/config.d.ts +15 -7
  26. package/dist/core/config.d.ts.map +1 -1
  27. package/dist/core/config.js +29 -14
  28. package/dist/core/config.js.map +1 -1
  29. package/dist/core/errors.d.ts +17 -5
  30. package/dist/core/errors.d.ts.map +1 -1
  31. package/dist/core/errors.js +25 -7
  32. package/dist/core/errors.js.map +1 -1
  33. package/dist/core/feedback.d.ts +7 -0
  34. package/dist/core/feedback.d.ts.map +1 -1
  35. package/dist/core/feedback.js +10 -1
  36. package/dist/core/feedback.js.map +1 -1
  37. package/dist/core/transaction.d.ts +5 -0
  38. package/dist/core/transaction.d.ts.map +1 -1
  39. package/dist/core/transaction.js +12 -0
  40. package/dist/core/transaction.js.map +1 -1
  41. package/dist/core/transport.d.ts +22 -7
  42. package/dist/core/transport.d.ts.map +1 -1
  43. package/dist/core/transport.js +51 -11
  44. package/dist/core/transport.js.map +1 -1
  45. package/dist/formats/camt.d.ts +7 -4
  46. package/dist/formats/camt.d.ts.map +1 -1
  47. package/dist/formats/camt.js +53 -54
  48. package/dist/formats/camt.js.map +1 -1
  49. package/dist/formats/mt940.d.ts +18 -6
  50. package/dist/formats/mt940.d.ts.map +1 -1
  51. package/dist/formats/mt940.js +83 -66
  52. package/dist/formats/mt940.js.map +1 -1
  53. package/dist/formats/readers.d.ts.map +1 -1
  54. package/dist/formats/readers.js +6 -2
  55. package/dist/formats/readers.js.map +1 -1
  56. package/dist/formats/sepa-purpose.d.ts +7 -4
  57. package/dist/formats/sepa-purpose.d.ts.map +1 -1
  58. package/dist/formats/sepa-purpose.js +18 -9
  59. package/dist/formats/sepa-purpose.js.map +1 -1
  60. package/dist/session/dialog-runner.d.ts +5 -2
  61. package/dist/session/dialog-runner.d.ts.map +1 -1
  62. package/dist/session/dialog-runner.js +23 -7
  63. package/dist/session/dialog-runner.js.map +1 -1
  64. package/dist/session/login-guard.d.ts +4 -4
  65. package/dist/session/login-guard.d.ts.map +1 -1
  66. package/dist/session/login-guard.js +29 -14
  67. package/dist/session/login-guard.js.map +1 -1
  68. package/dist/session/session-setup.d.ts +14 -5
  69. package/dist/session/session-setup.d.ts.map +1 -1
  70. package/dist/session/session-setup.js +30 -9
  71. package/dist/session/session-setup.js.map +1 -1
  72. package/dist/session/session-state.d.ts +4 -3
  73. package/dist/session/session-state.d.ts.map +1 -1
  74. package/dist/session/session-state.js +28 -9
  75. package/dist/session/session-state.js.map +1 -1
  76. package/dist/session/signed-dialog.d.ts +19 -13
  77. package/dist/session/signed-dialog.d.ts.map +1 -1
  78. package/dist/session/signed-dialog.js +45 -30
  79. package/dist/session/signed-dialog.js.map +1 -1
  80. package/dist/session/user-prompts.d.ts +6 -1
  81. package/dist/session/user-prompts.d.ts.map +1 -1
  82. package/dist/session/user-prompts.js +19 -4
  83. package/dist/session/user-prompts.js.map +1 -1
  84. package/dist/tan/challenge.d.ts +15 -13
  85. package/dist/tan/challenge.d.ts.map +1 -1
  86. package/dist/tan/challenge.js +32 -26
  87. package/dist/tan/challenge.js.map +1 -1
  88. package/dist/tan/flicker.d.ts +5 -1
  89. package/dist/tan/flicker.d.ts.map +1 -1
  90. package/dist/tan/flicker.js +42 -30
  91. package/dist/tan/flicker.js.map +1 -1
  92. package/dist/tan/tan-image.d.ts +4 -1
  93. package/dist/tan/tan-image.d.ts.map +1 -1
  94. package/dist/tan/tan-image.js +8 -2
  95. package/dist/tan/tan-image.js.map +1 -1
  96. package/dist/tan/tan-models.d.ts +9 -1
  97. package/dist/tan/tan-models.d.ts.map +1 -1
  98. package/dist/tan/tan-models.js +14 -2
  99. package/dist/tan/tan-models.js.map +1 -1
  100. package/dist/util/arguments.d.ts +13 -0
  101. package/dist/util/arguments.d.ts.map +1 -0
  102. package/dist/util/arguments.js +40 -0
  103. package/dist/util/arguments.js.map +1 -0
  104. package/dist/util/async.d.ts +4 -1
  105. package/dist/util/async.d.ts.map +1 -1
  106. package/dist/util/async.js +6 -3
  107. package/dist/util/async.js.map +1 -1
  108. package/dist/util/bytes.d.ts +1 -1
  109. package/dist/util/bytes.d.ts.map +1 -1
  110. package/dist/util/bytes.js +3 -3
  111. package/dist/util/bytes.js.map +1 -1
  112. package/dist/util/dates.d.ts +3 -10
  113. package/dist/util/dates.d.ts.map +1 -1
  114. package/dist/util/dates.js +49 -39
  115. package/dist/util/dates.js.map +1 -1
  116. package/dist/util/errors.d.ts +5 -3
  117. package/dist/util/errors.d.ts.map +1 -1
  118. package/dist/util/errors.js +8 -4
  119. package/dist/util/errors.js.map +1 -1
  120. package/dist/util/immutable-map.d.ts +5 -2
  121. package/dist/util/immutable-map.d.ts.map +1 -1
  122. package/dist/util/immutable-map.js +15 -12
  123. package/dist/util/immutable-map.js.map +1 -1
  124. package/dist/util/inspect.d.ts +11 -0
  125. package/dist/util/inspect.d.ts.map +1 -0
  126. package/dist/util/inspect.js +14 -0
  127. package/dist/util/inspect.js.map +1 -0
  128. package/dist/util/text.d.ts +18 -2
  129. package/dist/util/text.d.ts.map +1 -1
  130. package/dist/util/text.js +50 -5
  131. package/dist/util/text.js.map +1 -1
  132. package/dist/util/xml.d.ts +6 -4
  133. package/dist/util/xml.d.ts.map +1 -1
  134. package/dist/util/xml.js +106 -44
  135. package/dist/util/xml.js.map +1 -1
  136. package/dist/v3/bank-connection.d.ts +23 -3
  137. package/dist/v3/bank-connection.d.ts.map +1 -1
  138. package/dist/v3/bank-connection.js +66 -6
  139. package/dist/v3/bank-connection.js.map +1 -1
  140. package/dist/v3/dialog.d.ts +6 -2
  141. package/dist/v3/dialog.d.ts.map +1 -1
  142. package/dist/v3/dialog.js +20 -9
  143. package/dist/v3/dialog.js.map +1 -1
  144. package/dist/v3/message.d.ts +18 -10
  145. package/dist/v3/message.d.ts.map +1 -1
  146. package/dist/v3/message.js +92 -75
  147. package/dist/v3/message.js.map +1 -1
  148. package/dist/v3/parameter-store.d.ts +43 -7
  149. package/dist/v3/parameter-store.d.ts.map +1 -1
  150. package/dist/v3/parameter-store.js +69 -15
  151. package/dist/v3/parameter-store.js.map +1 -1
  152. package/dist/v3/parameters.d.ts +12 -11
  153. package/dist/v3/parameters.d.ts.map +1 -1
  154. package/dist/v3/parameters.js +57 -35
  155. package/dist/v3/parameters.js.map +1 -1
  156. package/dist/v3/protocol.d.ts +16 -9
  157. package/dist/v3/protocol.d.ts.map +1 -1
  158. package/dist/v3/protocol.js +57 -26
  159. package/dist/v3/protocol.js.map +1 -1
  160. package/dist/v3/queries.d.ts +2 -2
  161. package/dist/v3/queries.d.ts.map +1 -1
  162. package/dist/v3/queries.js +24 -16
  163. package/dist/v3/queries.js.map +1 -1
  164. package/dist/v3/segments.d.ts +18 -11
  165. package/dist/v3/segments.d.ts.map +1 -1
  166. package/dist/v3/segments.js +30 -21
  167. package/dist/v3/segments.js.map +1 -1
  168. package/dist/v3/syntax.d.ts +15 -11
  169. package/dist/v3/syntax.d.ts.map +1 -1
  170. package/dist/v3/syntax.js +30 -15
  171. package/dist/v3/syntax.js.map +1 -1
  172. package/package.json +1 -1
  173. package/src/client.ts +58 -17
  174. package/src/core/account.ts +91 -35
  175. package/src/core/amount.ts +42 -9
  176. package/src/core/balance.ts +6 -0
  177. package/src/core/bank-info.ts +28 -4
  178. package/src/core/client.ts +42 -15
  179. package/src/core/config.ts +37 -18
  180. package/src/core/errors.ts +27 -7
  181. package/src/core/feedback.ts +12 -1
  182. package/src/core/transaction.ts +13 -0
  183. package/src/core/transport.ts +62 -16
  184. package/src/formats/camt.ts +62 -51
  185. package/src/formats/mt940.ts +114 -78
  186. package/src/formats/readers.ts +6 -2
  187. package/src/formats/sepa-purpose.ts +17 -9
  188. package/src/session/dialog-runner.ts +34 -7
  189. package/src/session/login-guard.ts +29 -13
  190. package/src/session/session-setup.ts +27 -9
  191. package/src/session/session-state.ts +25 -8
  192. package/src/session/signed-dialog.ts +60 -30
  193. package/src/session/user-prompts.ts +28 -3
  194. package/src/tan/challenge.ts +50 -36
  195. package/src/tan/flicker.ts +40 -29
  196. package/src/tan/tan-image.ts +9 -2
  197. package/src/tan/tan-models.ts +16 -2
  198. package/src/util/arguments.ts +40 -0
  199. package/src/util/async.ts +10 -4
  200. package/src/util/bytes.ts +3 -3
  201. package/src/util/dates.ts +52 -38
  202. package/src/util/errors.ts +9 -4
  203. package/src/util/immutable-map.ts +15 -12
  204. package/src/util/inspect.ts +14 -0
  205. package/src/util/text.ts +47 -5
  206. package/src/util/xml.ts +105 -38
  207. package/src/v3/bank-connection.ts +65 -6
  208. package/src/v3/dialog.ts +18 -8
  209. package/src/v3/message.ts +81 -72
  210. package/src/v3/parameter-store.ts +82 -16
  211. package/src/v3/parameters.ts +68 -41
  212. package/src/v3/protocol.ts +61 -28
  213. package/src/v3/queries.ts +26 -18
  214. package/src/v3/segments.ts +32 -20
  215. package/src/v3/syntax.ts +31 -14
package/dist/v3/syntax.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // Internal to the package, and named after the FinTS specification. Documentation is where the meaning is not evident.
2
2
  import { BytesBuilder, latin1Decode, latin1Encode, utf8Encode } from '../util/bytes.js';
3
3
  import { FormatError } from '../util/errors.js';
4
- import { decodeBankText, isLatin1, tryParseInt } from '../util/text.js';
4
+ import { decodeBankText, isLatin1, trimBlanks, tryParseInt } from '../util/text.js';
5
5
  // FinTS 3.0 syntax characters.
6
6
  const dataElementSeparator = 0x2b; // '+'
7
7
  const groupElementSeparator = 0x3a; // ':'
@@ -58,6 +58,7 @@ export class Segment {
58
58
  source;
59
59
  start;
60
60
  end;
61
+ typeValue;
61
62
  constructor(elements,
62
63
  /** The bytes the segment was read from: `start` to `end` in `source`, terminator included. */
63
64
  source, start, end) {
@@ -67,7 +68,8 @@ export class Segment {
67
68
  this.end = end;
68
69
  }
69
70
  get type() {
70
- return this.text(0)?.trim() ?? '';
71
+ this.typeValue ??= trimBlanks(this.text(0) ?? '');
72
+ return this.typeValue;
71
73
  }
72
74
  get version() {
73
75
  return this.integer(0, 2) ?? 0;
@@ -92,6 +94,11 @@ export class Segment {
92
94
  const e = this.element(index, sub);
93
95
  return e?.isBinary === true ? e.bytes : undefined;
94
96
  }
97
+ /** The binary data or the text without escape characters at `index`; `undefined` for an empty element. */
98
+ bytes(index, sub = 0) {
99
+ const e = this.element(index, sub);
100
+ return e === undefined || e.isEmpty ? undefined : e.bytes;
101
+ }
95
102
  /**
96
103
  * The element at `index` as the bank sent it, for a value the client sends back, such as the dialog ID: untrimmed,
97
104
  * and one character per byte (ISO 8859-1, the FinTS 3.0 character set), so that `Verbatim` gives the bank back the
@@ -104,7 +111,7 @@ export class Segment {
104
111
  return latin1Decode(e.bytes);
105
112
  }
106
113
  integer(index, sub = 0) {
107
- return tryParseInt(this.text(index, sub)?.trim());
114
+ return tryParseInt(this.text(index, sub));
108
115
  }
109
116
  /** The texts of the group at `index`; `undefined` for empty elements. */
110
117
  texts(index) {
@@ -139,16 +146,19 @@ export function encodeText(value) {
139
146
  return isLatin1(value) ? latin1Encode(value) : utf8Encode(value);
140
147
  }
141
148
  /**
142
- * The data elements one message may hold, segment headers and group elements included: several times what the
143
- * parameter data of a user with hundreds of accounts take, and few enough that a hostile message cannot exhaust the
144
- * memory, at about `dataElementMemory` bytes each.
149
+ * The data elements and segments one parse may produce together, segment headers and group elements included: what
150
+ * the user parameter data of 6,000 accounts take, at about 155 data elements each, which is about what 9,999 KB, the
151
+ * largest message size HIBPA can state, hold of real data. Without a limit, a message of nothing but separators would
152
+ * take a hundred times its size in memory.
153
+ *
154
+ * @internal Exported for the tests.
145
155
  */
146
- export const maxDataElements = 200_000;
156
+ export const maxParts = 1_000_000;
147
157
  /**
148
- * The memory a data element of a received message takes, in bytes, with its share of the segment and of a return code:
149
- * about this much in V8, however few bytes of the message it is made of.
158
+ * What `IncomingMessage3.size` counts for each data element it keeps: more than any of them takes once parsed, so that
159
+ * a message of many short elements counts as the memory it holds rather than its bytes.
150
160
  */
151
- export const dataElementMemory = 256;
161
+ export const parsedElementBytes = 512;
152
162
  /** Every empty data element of a received segment; it has no bytes to change. */
153
163
  const emptyElement = new DataElement(new Uint8Array(0), 0, 0, false);
154
164
  function isSeparator(byte) {
@@ -166,10 +176,15 @@ function isDigit(byte) {
166
176
  *
167
177
  * The elements share the memory of `data`. Throws `FormatError` for anything a complete message cannot hold: a
168
178
  * malformed binary length, binary data beyond the end of `data` or not followed by a separator, a last segment without
169
- * terminator, and more elements than `budget` has left, which parses of the same message share.
179
+ * terminator, and more than `maxParts` data elements and segments, an empty one included.
170
180
  */
171
- export function parseSegments(data, budget = { elements: maxDataElements }) {
181
+ export function parseSegments(data) {
172
182
  const segments = [];
183
+ let parts = 0;
184
+ const count = () => {
185
+ if (++parts > maxParts)
186
+ throw new FormatError(`More than ${maxParts} data elements and segments`);
187
+ };
173
188
  // Created with their first element: an array that starts empty reserves room for more than most of them hold.
174
189
  let elements;
175
190
  let group;
@@ -212,8 +227,7 @@ export function parseSegments(data, budget = { elements: maxDataElements }) {
212
227
  i++;
213
228
  continue;
214
229
  }
215
- if (--budget.elements < 0)
216
- throw new FormatError('Too many data elements');
230
+ count();
217
231
  if (elements === undefined && group === undefined)
218
232
  segmentStart = i;
219
233
  const element = data[i] === binaryMarker ? readBinary() : readText();
@@ -230,6 +244,7 @@ export function parseSegments(data, budget = { elements: maxDataElements }) {
230
244
  elements.push(group);
231
245
  group = undefined;
232
246
  if (separator === segmentTerminator) {
247
+ count();
233
248
  const segment = new Segment(elements, data, segmentStart, i);
234
249
  // Skip empty segments, such as a stray double terminator.
235
250
  if (segment.type !== '')
@@ -360,7 +375,7 @@ function encodeValue(value) {
360
375
  else {
361
376
  // All but binary data go without leading and trailing blanks (Formals B.4.1). Encode first, then escape the bytes,
362
377
  // so that nothing unescaped slips into the syntax.
363
- writeEscaped(out, encodeText(String(value).trim()));
378
+ writeEscaped(out, encodeText(trimBlanks(String(value))));
364
379
  }
365
380
  return out.takeBytes();
366
381
  }
@@ -1 +1 @@
1
- {"version":3,"file":"syntax.js","sourceRoot":"","sources":["../../src/v3/syntax.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"syntax.js","sourceRoot":"","sources":["../../src/v3/syntax.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coderoftime/fints",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "FinTS 3.0 client for German banks: accounts, balances and transactions with PIN/TAN, PSD2 strong customer authentication and decoupled app approval.",
5
5
  "keywords": [
6
6
  "fints",
package/src/client.ts CHANGED
@@ -1,10 +1,11 @@
1
- import type { Account } from './core/account.js';
1
+ import { Account } from './core/account.js';
2
2
  import type { Balance } from './core/balance.js';
3
3
  import type { BankInfo } from './core/bank-info.js';
4
4
  import type { FinTsClient, FinTsClientOptions, TransactionQuery } from './core/client.js';
5
5
  import { FinTsConfig, requirePin, type FinTsConfigInit } from './core/config.js';
6
6
  import { FinTsStateError, FinTsUnsupportedError, type FinTsLoginRefusedError } from './core/errors.js';
7
- import type { Transaction } from './core/transaction.js';
7
+ import type { Transaction, TransactionFormat } from './core/transaction.js';
8
+ import type { FinTsTransport } from './core/transport.js';
8
9
  import { DialogRunner } from './session/dialog-runner.js';
9
10
  import { LoginGuard } from './session/login-guard.js';
10
11
  import { SepaAccounts } from './session/sepa-accounts.js';
@@ -13,6 +14,7 @@ import { restoreSession, saveSession, type SessionState } from './session/sessio
13
14
  import { TanSelection } from './session/tan-selection.js';
14
15
  import { UserPrompts } from './session/user-prompts.js';
15
16
  import { TanMedium, type TanMethod } from './tan/tan-models.js';
17
+ import { optionalString, requireString } from './util/arguments.js';
16
18
  import { SerialExecutor } from './util/async.js';
17
19
  import { CallContext } from './util/call-context.js';
18
20
  import { calendarDay, notAfterToday } from './util/dates.js';
@@ -39,6 +41,24 @@ export interface FinTs3ClientInit {
39
41
  /** A token of the client call running now, so that a call from inside its callbacks is recognized. */
40
42
  const runningCalls = new CallContext<object>();
41
43
 
44
+ /**
45
+ * `transport`, `undefined` for `null`; throws `TypeError` unless it is neither or has the functions of a
46
+ * `FinTsTransport`.
47
+ */
48
+ function optionalTransport(transport: unknown): FinTsTransport | undefined {
49
+ if (transport === undefined || transport === null) return undefined;
50
+ const candidate = transport as Partial<FinTsTransport>;
51
+ if (typeof candidate.post !== 'function' || typeof candidate.close !== 'function') {
52
+ throw invalidArgument('Must have the functions post and close', 'transport');
53
+ }
54
+ return transport as FinTsTransport;
55
+ }
56
+
57
+ /** Throws `TypeError` for anything but an `Account`, such as one written to JSON and read back. */
58
+ function requireAccount(account: unknown): void {
59
+ if (!(account instanceof Account)) throw invalidArgument('Must be an Account', 'account');
60
+ }
61
+
42
62
  /**
43
63
  * The calendar day of `bound`, the `name` bound of a `TransactionQuery`: the bank takes dates without time of day.
44
64
  * Throws `TypeError` for anything but a valid `Date`, such as an Invalid Date, which would go out as `0NaNNaNNaN`.
@@ -49,6 +69,16 @@ function requestedDay(bound: unknown, name: string): Date | undefined {
49
69
  return calendarDay(bound);
50
70
  }
51
71
 
72
+ /**
73
+ * The format a `TransactionQuery` asks for with `format`: `auto` where it is `undefined`. Throws `TypeError` for anything
74
+ * but a `TransactionFormat`, such as `'CAMT'` or `null`.
75
+ */
76
+ function requestedFormat(format: unknown): TransactionFormat {
77
+ if (format === undefined) return 'auto';
78
+ if (format === 'auto' || format === 'mt940' || format === 'camt') return format;
79
+ throw invalidArgument("Must be 'auto', 'mt940' or 'camt'", 'format');
80
+ }
81
+
52
82
  /** FinTS 3.0 PIN/TAN client, the version German banks use. */
53
83
  export class FinTs3Client implements FinTsClient {
54
84
  // A call such as `getBalance` runs through these parts:
@@ -89,15 +119,22 @@ export class FinTs3Client implements FinTsClient {
89
119
  *
90
120
  * Throws `TypeError` if the configuration is invalid, as the constructor of `FinTsConfig` tells, or the PIN is empty,
91
121
  * begins or ends with a blank, or has characters FinTS 3.0 cannot send: it uses ISO 8859-1, so `€` and most
92
- * non-Latin letters are not possible.
122
+ * non-Latin letters are not possible. Throws `TypeError` as well for an option of another type than
123
+ * `FinTsClientOptions` names, as `FinTsClientOptions` tells.
93
124
  */
94
125
  constructor(init: FinTs3ClientInit) {
95
126
  const config = init.config instanceof FinTsConfig ? init.config : new FinTsConfig(init.config);
127
+ const { state, transport } = init.options;
96
128
  this.#prompts = new UserPrompts(init.options);
97
129
  this.#guard = new LoginGuard(requirePin(init.pin));
98
130
  this.#parameters = new ParameterStore(config);
99
- this.#protocol = new FinTs3Protocol(this.#parameters, this.#guard, init.options.transport, this.#prompts.logger);
100
- this.#sessionState = restoreSession(init.options.state, this.#parameters, this.#guard);
131
+ this.#protocol = new FinTs3Protocol(
132
+ this.#parameters,
133
+ this.#guard,
134
+ optionalTransport(transport),
135
+ this.#prompts.logger,
136
+ );
137
+ this.#sessionState = restoreSession(optionalString(state, 'state'), this.#parameters, this.#guard);
101
138
  this.#tans = new TanSelection(this.#protocol, this.#sessionState, this.#prompts);
102
139
  const session = {
103
140
  parameters: this.#parameters,
@@ -126,10 +163,13 @@ export class FinTs3Client implements FinTsClient {
126
163
  return this.#sessionState.tanMedium;
127
164
  }
128
165
 
129
- selectTanMethod(securityFunction: string, tanMedium?: string): Promise<void> {
166
+ async selectTanMethod(securityFunction: string, tanMedium?: string): Promise<void> {
167
+ // Checked before the dialog ends; an async method, so that every argument error is a rejection.
168
+ const method = requireString(securityFunction, 'securityFunction');
169
+ const medium = optionalString(tanMedium, 'tanMedium');
130
170
  return this.#serialized(async () => {
131
171
  await this.#dialogs.end();
132
- this.#tans.select(securityFunction, tanMedium);
172
+ this.#tans.select(method, medium);
133
173
  });
134
174
  }
135
175
 
@@ -170,7 +210,9 @@ export class FinTs3Client implements FinTsClient {
170
210
  return this.#serialized(() => this.#sepa.completedAccounts());
171
211
  }
172
212
 
173
- getBalance(account: Account): Promise<Balance> {
213
+ async getBalance(account: Account): Promise<Balance> {
214
+ // Checked before the call waits for others; an async method, so that every argument error is a rejection.
215
+ requireAccount(account);
174
216
  return this.#serialized(async () => {
175
217
  const completed = await this.#sepa.complete(account);
176
218
  // The dialog start delivers the user parameter data, which may carry the complete balance: then the client must
@@ -185,21 +227,17 @@ export class FinTs3Client implements FinTsClient {
185
227
 
186
228
  async getTransactions(account: Account, query: TransactionQuery = {}): Promise<Transaction[]> {
187
229
  // Checked before the call waits for others; an async method, so that every argument error is a rejection.
230
+ requireAccount(account);
188
231
  const firstDay = requestedDay(query.from, 'from');
189
232
  const lastDay = requestedDay(query.to, 'to');
190
233
  if (firstDay !== undefined && lastDay !== undefined && firstDay.getTime() > lastDay.getTime()) {
191
234
  throw invalidArgument('`from` lies on a day after `to`', 'from');
192
235
  }
236
+ const format = requestedFormat(query.format);
193
237
  return this.#serialized(async () => {
194
238
  const completed = await this.#sepa.complete(account);
195
239
  const transactions = await this.#dialogs.query(() =>
196
- transactionsQuery(
197
- this.#parameters,
198
- completed,
199
- query.format ?? 'auto',
200
- notAfterToday(firstDay),
201
- notAfterToday(lastDay),
202
- ),
240
+ transactionsQuery(this.#parameters, completed, format, notAfterToday(firstDay), notAfterToday(lastDay)),
203
241
  );
204
242
  // A stable sort, so that transactions of the same day keep the bank's order.
205
243
  return transactions.sort(
@@ -239,9 +277,12 @@ export class FinTs3Client implements FinTsClient {
239
277
  this.#runningCall = call;
240
278
  try {
241
279
  return await runningCalls.run(call, () =>
242
- this.#guard.runCall(() => {
280
+ this.#guard.runCall(async () => {
281
+ this.#prompts.checkOpen();
282
+ const result = await this.#prompts.reportingCallbackErrors(action);
283
+ // Also where the last answer arrived after `close`: a closed client hands out no account data.
243
284
  this.#prompts.checkOpen();
244
- return this.#prompts.reportingCallbackErrors(action);
285
+ return result;
245
286
  }),
246
287
  );
247
288
  } finally {
@@ -1,5 +1,9 @@
1
+ import { optionalBoolean, optionalInteger, optionalString, requireString } from '../util/arguments.js';
1
2
  import { copyDate } from '../util/dates.js';
3
+ import { invalidArgument } from '../util/errors.js';
2
4
  import { ImmutableMap } from '../util/immutable-map.js';
5
+ import { inspectCustom } from '../util/inspect.js';
6
+ import { isString } from '../util/json.js';
3
7
  import { maskedId, nonBlank } from '../util/text.js';
4
8
  import { defaultCountryCode } from './config.js';
5
9
 
@@ -127,22 +131,28 @@ export class Account {
127
131
  /** What the bank tells about the data it holds for the account, where it does. */
128
132
  readonly dataStatus: AccountDataStatus | undefined;
129
133
 
130
- /** Takes copies of the permitted transactions and the data status of `init`, which no other account shares. */
134
+ /**
135
+ * Takes copies of the permitted transactions and the data status of `init`, which no other account shares.
136
+ *
137
+ * Throws `TypeError` for a detail of another type than `AccountInit` names, such as a number as `bankCode` or
138
+ * `accountNumber`, or a missing `bankCode`; `null` counts as a detail not given. The message leaves out the value.
139
+ */
131
140
  constructor(init: AccountInit) {
132
- this.accountNumber = init.accountNumber;
133
- this.subAccount = init.subAccount;
134
- this.bankCode = init.bankCode;
135
- this.countryCode = init.countryCode ?? defaultCountryCode;
136
- this.iban = electronicFormat(init.iban);
137
- this.bic = electronicFormat(init.bic);
138
- this.customerId = init.customerId;
139
- this.currency = init.currency;
140
- this.ownerName = init.ownerName;
141
- this.productName = init.productName;
142
- this.typeCode = init.typeCode;
143
- this.allowedTransactions = Object.freeze([...(init.allowedTransactions ?? [])]);
144
- this.allowedTransactionsComplete = init.allowedTransactionsComplete ?? false;
145
- this.dataStatus = init.dataStatus && new AccountDataStatus(init.dataStatus);
141
+ this.accountNumber = optionalString(init.accountNumber, 'accountNumber');
142
+ this.subAccount = optionalString(init.subAccount, 'subAccount');
143
+ this.bankCode = requireString(init.bankCode, 'bankCode');
144
+ this.countryCode = optionalString(init.countryCode, 'countryCode') ?? defaultCountryCode;
145
+ this.iban = electronicFormat(optionalString(init.iban, 'iban'));
146
+ this.bic = electronicFormat(optionalString(init.bic, 'bic'));
147
+ this.customerId = optionalString(init.customerId, 'customerId');
148
+ this.currency = optionalString(init.currency, 'currency');
149
+ this.ownerName = optionalString(init.ownerName, 'ownerName');
150
+ this.productName = optionalString(init.productName, 'productName');
151
+ this.typeCode = optionalInteger(init.typeCode, 'typeCode');
152
+ this.allowedTransactions = Object.freeze(segmentIds(init.allowedTransactions));
153
+ this.allowedTransactionsComplete =
154
+ optionalBoolean(init.allowedTransactionsComplete, 'allowedTransactionsComplete') ?? false;
155
+ this.dataStatus = copiedDataStatus(init.dataStatus);
146
156
  }
147
157
 
148
158
  /** The kind of account, derived from `typeCode`. */
@@ -201,13 +211,35 @@ export class Account {
201
211
  ];
202
212
  return `Account(${parts.join(', ')})`;
203
213
  }
214
+
215
+ /** What Node.js's `util.inspect` and `console.log` show: `toString`, not the fields. */
216
+ [inspectCustom](): string {
217
+ return this.toString();
218
+ }
204
219
  }
205
220
 
206
221
  /**
207
- * An IBAN or BIC in the form the bank sends and compares, without blanks and in capitals; `undefined` for blanks only.
222
+ * An IBAN or BIC in the form the bank sends and compares, without blanks, U+0085 (NEL) among them, and in capitals;
223
+ * `undefined` for blanks only.
208
224
  */
209
225
  function electronicFormat(code: string | undefined): string | undefined {
210
- return nonBlank(code?.replace(/\s/g, '').toUpperCase());
226
+ return nonBlank(code?.replace(/[\s\u0085]/g, '').toUpperCase());
227
+ }
228
+
229
+ /** A copy of `ids`, none for `undefined` or `null`; throws `TypeError` unless they are an array of strings. */
230
+ function segmentIds(ids: unknown): string[] {
231
+ if (ids === undefined || ids === null) return [];
232
+ if (!Array.isArray(ids) || !ids.every(isString)) {
233
+ throw invalidArgument('Must be an array of strings', 'allowedTransactions');
234
+ }
235
+ return [...ids];
236
+ }
237
+
238
+ /** A copy of `status`, none for `undefined` or `null`; throws `TypeError` unless it is an `AccountDataStatus`. */
239
+ function copiedDataStatus(status: unknown): AccountDataStatus | undefined {
240
+ if (status === undefined || status === null) return undefined;
241
+ if (!(status instanceof AccountDataStatus)) throw invalidArgument('Must be an AccountDataStatus', 'dataStatus');
242
+ return new AccountDataStatus(status);
211
243
  }
212
244
 
213
245
  function sameOrUnstated(a: string, b: string): boolean {
@@ -222,12 +254,11 @@ function nationalNumber(account: Account): string | undefined {
222
254
  /**
223
255
  * Accounts by IBAN and by national account, to find the first one an account `matches` without comparing it with each:
224
256
  * a bank may list tens of thousands.
225
- *
226
- * Bank and country codes count as they are, where `matches` takes an empty one for any: the accounts a bank lists state
227
- * both.
228
257
  */
229
258
  export class AccountIndex {
230
259
  private readonly byIban = new Map<string, number>();
260
+
261
+ /** By national account, under its bank and country code and under `null` for any of each, as `matches` takes them. */
231
262
  private readonly byNational = new Map<string, number>();
232
263
 
233
264
  /** Those without IBAN only: an account with IBAN matches one with IBAN by that alone. */
@@ -235,31 +266,48 @@ export class AccountIndex {
235
266
 
236
267
  constructor(private readonly accounts: readonly Account[]) {
237
268
  accounts.forEach((account, i) => {
238
- const national = nationalKey(account);
239
269
  if (account.iban !== undefined) keepFirst(this.byIban, account.iban, i);
240
- if (national === undefined) return;
241
- keepFirst(this.byNational, national, i);
242
- if (account.iban === undefined) keepFirst(this.byNationalWithoutIban, national, i);
270
+ const number = nationalNumber(account);
271
+ if (number === undefined) return;
272
+ for (const bankCode of [account.bankCode, null]) {
273
+ for (const countryCode of [account.countryCode, null]) {
274
+ const national = nationalKey(number, account.subAccount, bankCode, countryCode);
275
+ keepFirst(this.byNational, national, i);
276
+ if (account.iban === undefined) keepFirst(this.byNationalWithoutIban, national, i);
277
+ }
278
+ }
243
279
  });
244
280
  }
245
281
 
246
282
  /** The first of the accounts that `account` matches. */
247
283
  find(account: Account): Account | undefined {
248
- const national = nationalKey(account);
284
+ const number = nationalNumber(account);
249
285
  const byNational = account.iban === undefined ? this.byNational : this.byNationalWithoutIban;
250
- const found = [
251
- account.iban === undefined ? undefined : this.byIban.get(account.iban),
252
- national === undefined ? undefined : byNational.get(national),
253
- ].filter((i) => i !== undefined);
254
- return found.length === 0 ? undefined : this.accounts[Math.min(...found)];
286
+ const found = [account.iban === undefined ? undefined : this.byIban.get(account.iban)];
287
+ if (number !== undefined) {
288
+ for (const bankCode of codesMatching(account.bankCode)) {
289
+ for (const countryCode of codesMatching(account.countryCode)) {
290
+ found.push(byNational.get(nationalKey(number, account.subAccount, bankCode, countryCode)));
291
+ }
292
+ }
293
+ }
294
+ const positions = found.filter((i) => i !== undefined);
295
+ return positions.length === 0 ? undefined : this.accounts[Math.min(...positions)];
255
296
  }
256
297
  }
257
298
 
258
- function nationalKey(account: Account): string | undefined {
259
- const number = nationalNumber(account);
260
- return number === undefined
261
- ? undefined
262
- : JSON.stringify([number, account.subAccount ?? '', account.bankCode, account.countryCode]);
299
+ /** The keys of the codes that `code` matches: an empty one matches any, and a stated one also an empty one. */
300
+ function codesMatching(code: string): (string | null)[] {
301
+ return code === '' ? [null] : [code, ''];
302
+ }
303
+
304
+ function nationalKey(
305
+ number: string,
306
+ subAccount: string | undefined,
307
+ bankCode: string | null,
308
+ countryCode: string | null,
309
+ ): string {
310
+ return JSON.stringify([number, subAccount ?? '', bankCode, countryCode]);
263
311
  }
264
312
 
265
313
  function keepFirst(index: Map<string, number>, key: string, position: number): void {
@@ -320,4 +368,12 @@ export class AccountDataStatus {
320
368
  get camtTransactionsId(): string | undefined {
321
369
  return this.inventory.get('HKCAZ');
322
370
  }
371
+
372
+ /**
373
+ * What Node.js's `util.inspect` and `console.log` show: the queries `inventory` holds an ID for, not the IDs, which
374
+ * mark the user's data.
375
+ */
376
+ [inspectCustom](): string {
377
+ return `AccountDataStatus(${[...this.inventory.keys()].join(', ')})`;
378
+ }
323
379
  }
@@ -1,4 +1,7 @@
1
- import { FormatError } from '../util/errors.js';
1
+ import { requireString } from '../util/arguments.js';
2
+ import { FormatError, invalidArgument } from '../util/errors.js';
3
+ import { inspectCustom } from '../util/inspect.js';
4
+ import { trimBlanks } from '../util/text.js';
2
5
 
3
6
  /** Most decimal places an amount has: ISO 20022, the widest of the bank formats, allows five. */
4
7
  const maxScale = 5;
@@ -10,6 +13,9 @@ const powersOfTen = [1, 10, 100, 1000, 10000, 100000];
10
13
  /** Most digits a parsed amount has: few enough that the sum of two parsed amounts still fits. */
11
14
  const maxDigits = 15;
12
15
 
16
+ /** Most characters a parsed value has: room for the zeros banks pad amounts with besides `maxDigits` digits. */
17
+ const maxLength = 64;
18
+
13
19
  const decimal = /^([+-]?)(\d*)(?:[.,](\d*))?$/;
14
20
 
15
21
  /** Decimal places of the minor unit of `currency` (ISO 4217): two, except for the currencies listed here. */
@@ -63,8 +69,13 @@ export class Amount {
63
69
  /**
64
70
  * An amount of `minorUnits` with `scale` decimal places; throws `RangeError` for a `scale` outside 0 to 5, and for
65
71
  * `minorUnits` that are no integer or beyond 2^53 - 1 in either direction, about 90 trillion at two decimal places.
72
+ * Throws `TypeError` for `minorUnits` or `scale` that are no number, such as `'1234'`, and a `currency` that is no
73
+ * string.
66
74
  */
67
75
  constructor(minorUnits: number, scale: number, currency: string) {
76
+ if (typeof minorUnits !== 'number') throw invalidArgument('Must be a number', 'minorUnits');
77
+ if (typeof scale !== 'number') throw invalidArgument('Must be a number', 'scale');
78
+ requireString(currency, 'currency');
68
79
  if (!Number.isInteger(scale) || scale < 0 || scale > maxScale) {
69
80
  throw new RangeError(`scale must be an integer from 0 to ${maxScale}: ${scale}`);
70
81
  }
@@ -83,11 +94,15 @@ export class Amount {
83
94
  * `JPY`, three for `KWD`. It has more where the value has more significant digits. So `100,` in `EUR` is `100.00`, in
84
95
  * `JPY` `100`.
85
96
  *
86
- * Throws `FormatError` for anything else, so that `1.234,56` in bank data is an error, not a guess, and for more than
87
- * five decimal places (trailing zeros aside) or more than 15 digits.
97
+ * Throws `FormatError` for anything else, so that `1.234,56` in bank data is an error, not a guess, for more than
98
+ * five decimal places (trailing zeros aside) or more than 15 digits, and for more than 64 characters, zeros included
99
+ * and surrounding blanks aside. Throws `TypeError` for a `value` or `currency` that is no string.
88
100
  */
89
101
  static parseDecimal(value: string, currency: string): Amount {
90
- const match = decimal.exec(value.trim());
102
+ const trimmed = trimBlanks(requireString(value, 'value'));
103
+ requireString(currency, 'currency');
104
+ if (trimmed.length > maxLength) throw new FormatError(`Amount longer than ${maxLength} characters`, value);
105
+ const match = decimal.exec(trimmed);
91
106
  const whole = match?.[2] ?? '';
92
107
  let fraction = match?.[3] ?? '';
93
108
  if (!match || (whole === '' && fraction === '')) throw new FormatError('Invalid amount', value);
@@ -175,14 +190,15 @@ export class Amount {
175
190
  return `${this.toDecimalString()} ${this.currency}`;
176
191
  }
177
192
 
193
+ /** What Node.js's `util.inspect` and `console.log` show: `toString`, not the fields. */
194
+ [inspectCustom](): string {
195
+ return this.toString();
196
+ }
197
+
178
198
  /** The minor units of both amounts at the larger scale, as `bigint`s, since the factor could leave the safe range. */
179
199
  private atCommonScale(other: Amount): [bigint, bigint] {
180
200
  const target = Math.max(this.scale, other.scale);
181
- return [this.rescale(target), other.rescale(target)];
182
- }
183
-
184
- private rescale(target: number): bigint {
185
- return BigInt(this.minorUnits) * BigInt(powersOfTen[target - this.scale]!);
201
+ return [unitsAtScale(this, target), unitsAtScale(other, target)];
186
202
  }
187
203
 
188
204
  private compareValue(other: Amount): number {
@@ -197,6 +213,23 @@ export class Amount {
197
213
  }
198
214
  }
199
215
 
216
+ function unitsAtScale(amount: Amount, scale: number): bigint {
217
+ return BigInt(amount.minorUnits) * BigInt(powersOfTen[scale - amount.scale]!);
218
+ }
219
+
220
+ /**
221
+ * Whether `parts` are all in the currency of `total` and add up to exactly `total`; unlike `add`, also where a sum on
222
+ * the way lies beyond what an amount holds.
223
+ */
224
+ export function addsUpTo(parts: readonly Amount[], total: Amount): boolean {
225
+ let sum = 0n;
226
+ for (const part of parts) {
227
+ if (part.currency !== total.currency) return false;
228
+ sum += unitsAtScale(part, maxScale);
229
+ }
230
+ return sum === unitsAtScale(total, maxScale);
231
+ }
232
+
200
233
  /**
201
234
  * `amount` as a credit (unchanged) or a debit (negated), by the bank's credit/debit `mark`.
202
235
  *
@@ -1,4 +1,5 @@
1
1
  import { copyDate, formatIsoDate } from '../util/dates.js';
2
+ import { inspectCustom } from '../util/inspect.js';
2
3
  import type { Account } from './account.js';
3
4
  import type { Amount } from './amount.js';
4
5
 
@@ -82,4 +83,9 @@ export class Balance {
82
83
  toString(): string {
83
84
  return `Balance(${this.account.toString()}, ${formatIsoDate(this.bookedAsOf)})`;
84
85
  }
86
+
87
+ /** What Node.js's `util.inspect` and `console.log` show: `toString`, not the fields. */
88
+ [inspectCustom](): string {
89
+ return this.toString();
90
+ }
85
91
  }