@coderoftime/fints 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/CHANGELOG.md +519 -1
  2. package/README.md +138 -40
  3. package/dist/client.d.ts +49 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +242 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/core/account.d.ts +46 -7
  8. package/dist/core/account.d.ts.map +1 -1
  9. package/dist/core/account.js +143 -24
  10. package/dist/core/account.js.map +1 -1
  11. package/dist/core/amount.d.ts +15 -4
  12. package/dist/core/amount.d.ts.map +1 -1
  13. package/dist/core/amount.js +46 -9
  14. package/dist/core/amount.js.map +1 -1
  15. package/dist/core/balance.d.ts +4 -0
  16. package/dist/core/balance.d.ts.map +1 -1
  17. package/dist/core/balance.js +11 -5
  18. package/dist/core/balance.js.map +1 -1
  19. package/dist/core/bank-info.d.ts +21 -4
  20. package/dist/core/bank-info.d.ts.map +1 -1
  21. package/dist/core/bank-info.js +26 -5
  22. package/dist/core/bank-info.js.map +1 -1
  23. package/dist/core/client.d.ts +81 -19
  24. package/dist/core/client.d.ts.map +1 -1
  25. package/dist/core/config.d.ts +40 -20
  26. package/dist/core/config.d.ts.map +1 -1
  27. package/dist/core/config.js +85 -30
  28. package/dist/core/config.js.map +1 -1
  29. package/dist/core/errors.d.ts +100 -26
  30. package/dist/core/errors.d.ts.map +1 -1
  31. package/dist/core/errors.js +136 -53
  32. package/dist/core/errors.js.map +1 -1
  33. package/dist/core/feedback.d.ts +11 -1
  34. package/dist/core/feedback.d.ts.map +1 -1
  35. package/dist/core/feedback.js +14 -2
  36. package/dist/core/feedback.js.map +1 -1
  37. package/dist/core/transaction.d.ts +11 -1
  38. package/dist/core/transaction.d.ts.map +1 -1
  39. package/dist/core/transaction.js +21 -4
  40. package/dist/core/transaction.js.map +1 -1
  41. package/dist/core/transport.d.ts +48 -6
  42. package/dist/core/transport.d.ts.map +1 -1
  43. package/dist/core/transport.js +126 -29
  44. package/dist/core/transport.js.map +1 -1
  45. package/dist/formats/camt.d.ts +28 -5
  46. package/dist/formats/camt.d.ts.map +1 -1
  47. package/dist/formats/camt.js +132 -50
  48. package/dist/formats/camt.js.map +1 -1
  49. package/dist/formats/mt940.d.ts +29 -5
  50. package/dist/formats/mt940.d.ts.map +1 -1
  51. package/dist/formats/mt940.js +209 -113
  52. package/dist/formats/mt940.js.map +1 -1
  53. package/dist/formats/readers.d.ts +6 -2
  54. package/dist/formats/readers.d.ts.map +1 -1
  55. package/dist/formats/readers.js +28 -29
  56. package/dist/formats/readers.js.map +1 -1
  57. package/dist/formats/record-budget.d.ts +7 -0
  58. package/dist/formats/record-budget.d.ts.map +1 -0
  59. package/dist/formats/record-budget.js +17 -0
  60. package/dist/formats/record-budget.js.map +1 -0
  61. package/dist/formats/sepa-purpose.d.ts +9 -0
  62. package/dist/formats/sepa-purpose.d.ts.map +1 -1
  63. package/dist/formats/sepa-purpose.js +32 -2
  64. package/dist/formats/sepa-purpose.js.map +1 -1
  65. package/dist/index.d.ts +3 -3
  66. package/dist/index.d.ts.map +1 -1
  67. package/dist/index.js +2 -2
  68. package/dist/index.js.map +1 -1
  69. package/dist/session/app-approval.d.ts +11 -5
  70. package/dist/session/app-approval.d.ts.map +1 -1
  71. package/dist/session/app-approval.js +23 -12
  72. package/dist/session/app-approval.js.map +1 -1
  73. package/dist/session/dialog-runner.d.ts +11 -11
  74. package/dist/session/dialog-runner.d.ts.map +1 -1
  75. package/dist/session/dialog-runner.js +34 -19
  76. package/dist/session/dialog-runner.js.map +1 -1
  77. package/dist/session/login-guard.d.ts +54 -49
  78. package/dist/session/login-guard.d.ts.map +1 -1
  79. package/dist/session/login-guard.js +170 -83
  80. package/dist/session/login-guard.js.map +1 -1
  81. package/dist/session/sepa-accounts.d.ts +20 -14
  82. package/dist/session/sepa-accounts.d.ts.map +1 -1
  83. package/dist/session/sepa-accounts.js +62 -46
  84. package/dist/session/sepa-accounts.js.map +1 -1
  85. package/dist/session/session-setup.d.ts +41 -24
  86. package/dist/session/session-setup.d.ts.map +1 -1
  87. package/dist/session/session-setup.js +106 -63
  88. package/dist/session/session-setup.js.map +1 -1
  89. package/dist/session/session-state.d.ts +10 -6
  90. package/dist/session/session-state.d.ts.map +1 -1
  91. package/dist/session/session-state.js +72 -18
  92. package/dist/session/session-state.js.map +1 -1
  93. package/dist/session/signed-dialog.d.ts +83 -0
  94. package/dist/session/signed-dialog.d.ts.map +1 -0
  95. package/dist/session/signed-dialog.js +185 -0
  96. package/dist/session/signed-dialog.js.map +1 -0
  97. package/dist/session/tan-selection.d.ts +26 -18
  98. package/dist/session/tan-selection.d.ts.map +1 -1
  99. package/dist/session/tan-selection.js +44 -33
  100. package/dist/session/tan-selection.js.map +1 -1
  101. package/dist/session/user-prompts.d.ts +14 -5
  102. package/dist/session/user-prompts.d.ts.map +1 -1
  103. package/dist/session/user-prompts.js +53 -18
  104. package/dist/session/user-prompts.js.map +1 -1
  105. package/dist/tan/challenge.d.ts +47 -24
  106. package/dist/tan/challenge.d.ts.map +1 -1
  107. package/dist/tan/challenge.js +56 -51
  108. package/dist/tan/challenge.js.map +1 -1
  109. package/dist/tan/flicker.d.ts +11 -1
  110. package/dist/tan/flicker.d.ts.map +1 -1
  111. package/dist/tan/flicker.js +70 -24
  112. package/dist/tan/flicker.js.map +1 -1
  113. package/dist/tan/tan-image.d.ts +6 -2
  114. package/dist/tan/tan-image.d.ts.map +1 -1
  115. package/dist/tan/tan-image.js +14 -6
  116. package/dist/tan/tan-image.js.map +1 -1
  117. package/dist/tan/tan-models.d.ts +14 -2
  118. package/dist/tan/tan-models.d.ts.map +1 -1
  119. package/dist/tan/tan-models.js +24 -7
  120. package/dist/tan/tan-models.js.map +1 -1
  121. package/dist/util/arguments.d.ts +13 -0
  122. package/dist/util/arguments.d.ts.map +1 -0
  123. package/dist/util/arguments.js +40 -0
  124. package/dist/util/arguments.js.map +1 -0
  125. package/dist/util/async.d.ts +4 -3
  126. package/dist/util/async.d.ts.map +1 -1
  127. package/dist/util/async.js +6 -7
  128. package/dist/util/async.js.map +1 -1
  129. package/dist/util/bytes.d.ts +3 -4
  130. package/dist/util/bytes.d.ts.map +1 -1
  131. package/dist/util/bytes.js +13 -21
  132. package/dist/util/bytes.js.map +1 -1
  133. package/dist/util/call-context.d.ts.map +1 -1
  134. package/dist/util/call-context.js +3 -2
  135. package/dist/util/call-context.js.map +1 -1
  136. package/dist/util/dates.d.ts +6 -20
  137. package/dist/util/dates.d.ts.map +1 -1
  138. package/dist/util/dates.js +58 -28
  139. package/dist/util/dates.js.map +1 -1
  140. package/dist/util/errors.d.ts +13 -3
  141. package/dist/util/errors.d.ts.map +1 -1
  142. package/dist/util/errors.js +19 -6
  143. package/dist/util/errors.js.map +1 -1
  144. package/dist/util/immutable-map.d.ts +5 -2
  145. package/dist/util/immutable-map.d.ts.map +1 -1
  146. package/dist/util/immutable-map.js +15 -12
  147. package/dist/util/immutable-map.js.map +1 -1
  148. package/dist/util/inspect.d.ts +11 -0
  149. package/dist/util/inspect.d.ts.map +1 -0
  150. package/dist/util/inspect.js +14 -0
  151. package/dist/util/inspect.js.map +1 -0
  152. package/dist/util/json.d.ts +4 -0
  153. package/dist/util/json.d.ts.map +1 -1
  154. package/dist/util/json.js +18 -0
  155. package/dist/util/json.js.map +1 -1
  156. package/dist/util/text.d.ts +38 -5
  157. package/dist/util/text.d.ts.map +1 -1
  158. package/dist/util/text.js +90 -16
  159. package/dist/util/text.js.map +1 -1
  160. package/dist/util/xml.d.ts +9 -6
  161. package/dist/util/xml.d.ts.map +1 -1
  162. package/dist/util/xml.js +129 -56
  163. package/dist/util/xml.js.map +1 -1
  164. package/dist/v3/account-extension.d.ts.map +1 -1
  165. package/dist/v3/account-extension.js +7 -10
  166. package/dist/v3/account-extension.js.map +1 -1
  167. package/dist/v3/bank-connection.d.ts +54 -0
  168. package/dist/v3/bank-connection.d.ts.map +1 -0
  169. package/dist/v3/bank-connection.js +118 -0
  170. package/dist/v3/bank-connection.js.map +1 -0
  171. package/dist/v3/dialog.d.ts +84 -46
  172. package/dist/v3/dialog.d.ts.map +1 -1
  173. package/dist/v3/dialog.js +174 -60
  174. package/dist/v3/dialog.js.map +1 -1
  175. package/dist/v3/message.d.ts +32 -11
  176. package/dist/v3/message.d.ts.map +1 -1
  177. package/dist/v3/message.js +144 -83
  178. package/dist/v3/message.js.map +1 -1
  179. package/dist/v3/parameter-store.d.ts +111 -0
  180. package/dist/v3/parameter-store.d.ts.map +1 -0
  181. package/dist/v3/parameter-store.js +197 -0
  182. package/dist/v3/parameter-store.js.map +1 -0
  183. package/dist/v3/parameters.d.ts +44 -17
  184. package/dist/v3/parameters.d.ts.map +1 -1
  185. package/dist/v3/parameters.js +136 -60
  186. package/dist/v3/parameters.js.map +1 -1
  187. package/dist/v3/protocol.d.ts +50 -50
  188. package/dist/v3/protocol.d.ts.map +1 -1
  189. package/dist/v3/protocol.js +91 -210
  190. package/dist/v3/protocol.js.map +1 -1
  191. package/dist/v3/queries.d.ts +51 -0
  192. package/dist/v3/queries.d.ts.map +1 -0
  193. package/dist/v3/queries.js +128 -0
  194. package/dist/v3/queries.js.map +1 -0
  195. package/dist/v3/segments.d.ts +43 -19
  196. package/dist/v3/segments.d.ts.map +1 -1
  197. package/dist/v3/segments.js +84 -33
  198. package/dist/v3/segments.js.map +1 -1
  199. package/dist/v3/syntax.d.ts +68 -13
  200. package/dist/v3/syntax.d.ts.map +1 -1
  201. package/dist/v3/syntax.js +183 -102
  202. package/dist/v3/syntax.js.map +1 -1
  203. package/package.json +10 -6
  204. package/src/client.ts +293 -0
  205. package/src/core/account.ts +153 -24
  206. package/src/core/amount.ts +45 -10
  207. package/src/core/balance.ts +12 -5
  208. package/src/core/bank-info.ts +29 -5
  209. package/src/core/client.ts +83 -19
  210. package/src/core/config.ts +95 -35
  211. package/src/core/errors.ts +148 -54
  212. package/src/core/feedback.ts +16 -2
  213. package/src/core/transaction.ts +22 -4
  214. package/src/core/transport.ts +153 -32
  215. package/src/formats/camt.ts +153 -45
  216. package/src/formats/mt940.ts +244 -122
  217. package/src/formats/readers.ts +28 -31
  218. package/src/formats/record-budget.ts +18 -0
  219. package/src/formats/sepa-purpose.ts +29 -2
  220. package/src/index.ts +4 -2
  221. package/src/session/app-approval.ts +51 -38
  222. package/src/session/dialog-runner.ts +61 -31
  223. package/src/session/login-guard.ts +189 -87
  224. package/src/session/sepa-accounts.ts +63 -45
  225. package/src/session/session-setup.ts +105 -68
  226. package/src/session/session-state.ts +74 -23
  227. package/src/session/signed-dialog.ts +222 -0
  228. package/src/session/tan-selection.ts +50 -39
  229. package/src/session/user-prompts.ts +62 -18
  230. package/src/tan/challenge.ts +87 -64
  231. package/src/tan/flicker.ts +72 -23
  232. package/src/tan/tan-image.ts +15 -6
  233. package/src/tan/tan-models.ts +26 -7
  234. package/src/util/arguments.ts +40 -0
  235. package/src/util/async.ts +10 -9
  236. package/src/util/bytes.ts +14 -20
  237. package/src/util/call-context.ts +3 -2
  238. package/src/util/dates.ts +64 -33
  239. package/src/util/errors.ts +22 -6
  240. package/src/util/immutable-map.ts +15 -12
  241. package/src/util/inspect.ts +14 -0
  242. package/src/util/json.ts +16 -0
  243. package/src/util/text.ts +87 -15
  244. package/src/util/xml.ts +130 -52
  245. package/src/v3/account-extension.ts +7 -12
  246. package/src/v3/bank-connection.ts +126 -0
  247. package/src/v3/dialog.ts +186 -92
  248. package/src/v3/message.ts +140 -79
  249. package/src/v3/parameter-store.ts +226 -0
  250. package/src/v3/parameters.ts +166 -66
  251. package/src/v3/protocol.ts +103 -253
  252. package/src/v3/queries.ts +198 -0
  253. package/src/v3/segments.ts +86 -31
  254. package/src/v3/syntax.ts +172 -93
  255. package/dist/session/bank-connection.d.ts +0 -28
  256. package/dist/session/bank-connection.d.ts.map +0 -1
  257. package/dist/session/bank-connection.js +0 -48
  258. package/dist/session/bank-connection.js.map +0 -1
  259. package/dist/session/parameter-data.d.ts +0 -83
  260. package/dist/session/parameter-data.d.ts.map +0 -1
  261. package/dist/session/parameter-data.js +0 -68
  262. package/dist/session/parameter-data.js.map +0 -1
  263. package/dist/session/pin-tan-client.d.ts +0 -54
  264. package/dist/session/pin-tan-client.d.ts.map +0 -1
  265. package/dist/session/pin-tan-client.js +0 -153
  266. package/dist/session/pin-tan-client.js.map +0 -1
  267. package/dist/session/pin-tan-dialog.d.ts +0 -71
  268. package/dist/session/pin-tan-dialog.d.ts.map +0 -1
  269. package/dist/session/pin-tan-dialog.js +0 -124
  270. package/dist/session/pin-tan-dialog.js.map +0 -1
  271. package/dist/session/protocol.d.ts +0 -209
  272. package/dist/session/protocol.d.ts.map +0 -1
  273. package/dist/session/protocol.js +0 -75
  274. package/dist/session/protocol.js.map +0 -1
  275. package/dist/session/response-handler.d.ts +0 -48
  276. package/dist/session/response-handler.d.ts.map +0 -1
  277. package/dist/session/response-handler.js +0 -121
  278. package/dist/session/response-handler.js.map +0 -1
  279. package/dist/v3/client.d.ts +0 -24
  280. package/dist/v3/client.d.ts.map +0 -1
  281. package/dist/v3/client.js +0 -16
  282. package/dist/v3/client.js.map +0 -1
  283. package/src/session/bank-connection.ts +0 -51
  284. package/src/session/parameter-data.ts +0 -137
  285. package/src/session/pin-tan-client.ts +0 -186
  286. package/src/session/pin-tan-dialog.ts +0 -160
  287. package/src/session/protocol.ts +0 -311
  288. package/src/session/response-handler.ts +0 -130
  289. package/src/v3/client.ts +0 -29
package/CHANGELOG.md CHANGED
@@ -1,3 +1,519 @@
1
+ ## 0.3.0
2
+
3
+ An app may notice these changes: arguments and options of another type than declared, such as a number as `bankCode`
4
+ or a `state` that is no string, and a user ID or customer ID of more than 30 characters fail with a `TypeError` before
5
+ the bank is contacted; the client reads its options once; `close` waits up to five seconds for the request on its way,
6
+ so the call it ends fails with `FinTsStateError` where the answer comes in time; a TAN goes out as the user typed it;
7
+ `console.log` shows the models of the package only by what identifies no person, account or TAN, and `toString` of
8
+ `FinTsFeedback` and `BankMessage` leaves out the bank's texts; `feedback` and `source` of an error are getters; and more
9
+ malformed bank data fail with `FinTsProtocolError`. Where these notes compare with the Dart package, they mean its
10
+ source after its release 0.2.0, unless they name 0.2.0, which differs in more ways: it keeps no refused login in the
11
+ saved state.
12
+
13
+ ### Breaking
14
+
15
+ - `getTransactions` rejects a `format` other than `'auto'`, `'mt940'` and `'camt'` with a `TypeError`, before it waits
16
+ for other calls or contacts the bank: one such as `'CAMT'` asked for MT940, and `null` meant `'auto'`, as `undefined`
17
+ still does.
18
+ - `getBalance` and `getTransactions` reject anything but an `Account`, such as one written to JSON and read back, with a
19
+ `TypeError` before they wait for other calls or contact the bank. They logged in, fetched the SEPA account list, and
20
+ then failed with an unrelated `TypeError`.
21
+ - `selectTanMethod` rejects a TAN method or medium that is no string, and a missing method, with a `TypeError` before it
22
+ ends the dialog. A number as the method was saved and then dropped at the next login, which asked `tanMethodSelector`
23
+ instead; a medium of another type went out as its text or as a data element group, which the bank refused as a login;
24
+ and a state saved in between could not be restored.
25
+ - `FinTs3Client` throws a `TypeError` for options of another type, before contacting the bank: a missing `tanCallback`
26
+ or one that is no function, another callback that is neither a function nor `undefined` or `null`, a `state` that is
27
+ neither a string nor `undefined` or `null`, such as the parsed JSON a store hands back, and a `transport` without the
28
+ functions `post` and `close`. A callback that was no function failed the call after its messages had gone out,
29
+ `tanCallback` at the first TAN challenge after the PIN-signed login; a `state` that was no string was ignored; and a
30
+ transport without `close` made `close` reject.
31
+ - The client reads its options once, when it is built, as the Dart package does: assigning another `tanCallback`,
32
+ selector, `onBankMessage` or `onWarning` to the options object afterwards no longer changes what the client calls.
33
+ - `Account`, `Amount` and `FinTsConfig` throw a `TypeError` ('Invalid argument (<name>): …', without the value) for an
34
+ argument of another type than declared, as the Dart package's types refuse it: such as a number as `bankCode`,
35
+ `accountNumber`, `iban`, `currency` or `customerId`, a missing `bankCode`, a string as `minorUnits`, `scale` or
36
+ `typeCode`, anything but an array of strings as `allowedTransactions`, anything but a boolean as `allowInsecureUrl`,
37
+ and anything but an `AccountDataStatus` as `dataStatus`. `Amount.parseDecimal` does for a `value` or `currency` that
38
+ is no string. Such an account passed the constructor, threw in `toString`, and failed `getBalance` and
39
+ `getTransactions` only after the login, or matched none of the bank's accounts, so that the query failed with
40
+ `FinTsUnsupportedError` or went out without the bank's IBAN and BIC. A `dataStatus` written to JSON and read back
41
+ failed with an unrelated `TypeError` ('object is not iterable'), and a string counted as an empty status. An amount
42
+ kept a number as its currency, and a string as `minorUnits` threw a `RangeError` that showed it as a valid value.
43
+ - `FinTsConfig` throws a `TypeError` for a `userId` or `customerId` longer than 30 characters, the length FinTS 3.0
44
+ gives them (Formals, data type `id`). The bank refused such a login with a syntax error, which the client counted as
45
+ a refused login, so it sent the PIN no more.
46
+ - A `FinTsConfig` is frozen once its constructor has checked it: assigning to a field throws a `TypeError` in
47
+ strict-mode code and does nothing otherwise, and a subclass cannot add fields.
48
+ - As in the Dart package, `Mt940.parse` and `Mt940.parseTransactions` throw a `TypeError` for a `status` other than
49
+ `'booked'` and `'pending'`, `null` included, which meant `'booked'`, and for a `currency` that is no string;
50
+ `Camt.parse` and `Camt.parseTransactions` for a status other than these, `undefined` and `null`. Such a status became
51
+ the transactions' `status`, and such a currency that of their amounts. `SepaPurpose.parseParts` throws a `TypeError`
52
+ for a string, whose characters it took for parts, and for parts that are no strings.
53
+ - camt documents are read as XML 1.0 has them, failing `getTransactions` with `FinTsProtocolError` and `Camt.parse` with
54
+ `FormatError` for a name that is no XML name, such as `<1x>`, an end tag with another namespace prefix than its start
55
+ tag, a second XML declaration or one inside or after the root element, a processing instruction without a target, and
56
+ an attribute stated twice.
57
+ - camt: a `Dt` that holds a date and time is read like a `DtTm`. One whose time the client cannot read, such as
58
+ `2024-03-15T25:00:00` or `2024-03-15T10:00`, fails `getTransactions` with `FinTsProtocolError` and `Camt.parse` with
59
+ `FormatError` instead of counting on the date written. So do a UTC offset beyond ±14:00, such as `+15:00`, which XML
60
+ Schema does not allow and which the client used to read as an offset, and `24:00:00` with a fraction of a second other
61
+ than zero.
62
+ - `BankInfo.maxMessageSize`, `minTimeout` and `maxTimeout` are `undefined` for a value above 9999, the four digits HIBPA
63
+ allows, as in the Dart package. The client then sends messages of any size and starts a new dialog after 5 idle
64
+ minutes. `TanChallenge.plainMessage` leaves a structured challenge of more than 65,536 characters as the bank sent it,
65
+ as the Dart package does.
66
+ - `close` no longer aborts a request on its way at once: it waits up to five seconds for the answer and only then aborts
67
+ it, and the dialog ends then have five seconds once that request is over, so `close` may take about ten seconds where
68
+ the bank has stopped answering. Where the answer comes in time, the running call fails with `FinTsStateError` instead
69
+ of `FinTsTransportError`, also where that answer completes it, unless the answer brings an error of its own, such as a
70
+ rejected PIN, which it fails with instead; a request aborted after the five seconds still fails it with
71
+ `FinTsTransportError`. A call whose last answer arrives after `close`, within those five seconds, fails with
72
+ `FinTsStateError` instead of returning its result.
73
+ - A TAN goes out as the user typed it, except for full-width characters, which count as their ASCII counterparts, and
74
+ the ideographic space U+3000, which counts as a blank, as in the Dart package. Unicode NFKC changed it before:
75
+ superscript, circled and mathematical digits counted as digits, and characters that ISO 8859-1 holds went out altered,
76
+ such as `²` as `2` or a no-break space inside the TAN as a space, which the bank counts as a failed attempt; `µ`, `½`
77
+ and the like failed with a `TypeError` as not sendable. Other characters outside ISO 8859-1, and digits other than 0
78
+ to 9 for a `numericTan` method, fail the call with a `TypeError` before it is sent.
79
+ - `FinTsFeedback.toString` gives the code only, such as `FinTsFeedback(3072)`, and `BankMessage.toString` gives
80
+ `BankMessage(…)`, as `console.log` showed them already. So `String(f)`, template strings and loggers that call
81
+ `toString` no longer collect the bank's texts and parameters, which with return code 3072 hold the new login data, or
82
+ a message that may address the user by name. To show them to the user, use `code`, `text` and `parameters`, or
83
+ `subject` and `text`. The message of a `FinTsBankError` stays as it was, with the code, text and parameters of each
84
+ error, such as `9010: Konto gesperrt [DE89370400440532013000]`.
85
+ - `FinTsBankError.feedback` and `FormatError.source` are getters instead of own properties of the error, so
86
+ `Object.keys`, object spread and `JSON.stringify` of the error leave them out.
87
+
88
+ ### Security
89
+
90
+ - Plain JavaScript can no longer change a `FinTsConfig` once checked, which could send the PIN to an http URL, or login
91
+ data the constructor had not checked, to the bank.
92
+ - `FinTsConfig` refuses an `allowInsecureUrl` that is no boolean, such as the string `'false'` read from an environment
93
+ variable, with a `TypeError`: it allowed plain http to a loopback host, where the PIN passes any proxy the runtime's
94
+ `fetch` takes from the environment.
95
+ - `console.log` and `util.inspect` on Node.js, Deno and Bun show the objects of this package only by what identifies no
96
+ person, account or TAN. An `Account`, `Balance`, `Transaction`, `TanMethod` or `TanMedium` shows as its `toString`, a
97
+ `TanChallenge` by its method, kind and attempt, a `FinTsFeedback` by its code and a `TanAnswer` by its kind.
98
+ `AccountDataStatus`, `BankInfo`, `FinTsConfig`, `FlickerCode` and `TanImage` show codes, versions and sizes only, the
99
+ statements of `Mt940.parse` and `Camt.parse` the last digits of the account and the number of transactions, and a
100
+ `BankMessage` shows as `BankMessage(…)`. Until now they showed every field: the bank's texts, references and
101
+ parameters (with return code 3072 the new login data), TAN media names, the TAN, the challenge data and image, the
102
+ login name and product ID, and a statement's full account. An error shows its message and stack, and a
103
+ `FinTsTransportError` its `statusCode`; the message of a `FinTsBankError` holds the texts and parameters of its
104
+ errors, as before. `JSON.stringify` and the browser console still show every field.
105
+ - Node.js's report of an uncaught error ignores what `console.log` shows of an object. It printed the whole `feedback`
106
+ of a `FinTsBankError`, including the texts, references and parameters of its successes and warnings and, with return
107
+ code 3072, the new login data, as well as the `source` of a `FormatError`. `JSON.stringify` of such an error, and
108
+ loggers that copy an error's fields, got them too. Both are getters now, so an uncaught `FinTsBankError` or
109
+ `FormatError` prints its message and stack only, as in the Dart package, and `JSON.stringify` leaves them out.
110
+ - `TanMedium.toString` leaves out the medium's name, which the user may have chosen after themselves, such as
111
+ `Max’s iPhone`: it gives `TanMedium(M, active)`, or, for a card, the last digits of its number,
112
+ `TanMedium(…2014, active)`, as before for a card without a name.
113
+ - A PIN that begins or ends with U+0085 (NEL) fails with a `TypeError` before it is sent, like one with other blanks at
114
+ either end. It went out with the byte 0x85, which the bank could count as a failed attempt.
115
+ - New login data (3072) next to an error in the answer to the login's TAN or app approval, such as 9941 for a wrong TAN,
116
+ an aborted dialog (9800) or any other error but a rejected PIN, end the old ones as well, as in the Dart package: the
117
+ call fails with `FinTsLoginDataChangedError`, the client ends the dialog where the bank keeps it open, and no later
118
+ call logs in with the old data. Until now the call failed with `FinTsTanError`, `FinTsDialogAbortedError` or
119
+ `FinTsBankError`, and the next call logged in again with the old login data and the PIN, which the bank may count as a
120
+ failed attempt, and asked for another TAN.
121
+ - A refused login, and the count of logins whose answer was lost, are restored from a saved state whose owner names the
122
+ server by something other than a string, such as a number or `null`, as in the Dart package; the rest of such a state
123
+ is dropped, as for another server. Until now the whole state was dropped, and the next call sent the PIN the bank had
124
+ refused.
125
+ - A `state` that is no string, such as the parsed JSON a json column returns, fails the `FinTs3Client` constructor with
126
+ a `TypeError`: the client ignored it, and with it a refused login it held, and sent the PIN again.
127
+ - A refused login stays refused where the `loginGuard` section of a saved state for the same user is damaged, such as a
128
+ return code without its code or `unreadLogins` that is no integer: the client restores a `FinTsLoginRefusedError`
129
+ without return codes and sends the PIN no more until `clearLoginRefusal`. Such damage dropped the refusal, and the
130
+ next call sent the refused PIN again. A state without the section, as fints-ts 0.1 and the Dart package 0.2.0 save
131
+ it, restores as before.
132
+ - `HttpTransport` copies each part of an answer as it arrives, as the Dart package does. An answer within
133
+ `maxResponseBytes` that a server sent in one-byte parts took gigabytes of memory and could end a Node.js process with
134
+ an out-of-memory error, which the app cannot catch. A `fetch` that refills the part it handed out corrupted the
135
+ answer.
136
+ - The documentation of `HttpTransport` and `allowInsecureUrl` warns that plain http to a local server goes wherever the
137
+ global `fetch` sends it, as https does. Whatever replaces `globalThis.fetch`, such as a test's stub, and on Node.js a
138
+ global dispatcher get every message with the PIN. A proxy that the runtime's `fetch` takes from the environment, as
139
+ Node.js does with `NODE_USE_ENV_PROXY=1`, and Deno and Bun do from `HTTP_PROXY`, sees the PIN unencrypted: exempt the
140
+ host with `NO_PROXY` or pass a `fetch` that connects directly. The Dart package connects to the loopback host
141
+ directly, also bypassing a client set with `runWithClient`.
142
+ - The limits on bank data are those of the Dart package. The following fail the call with `FinTsProtocolError`, and
143
+ `Mt940.parse`, `Camt.parse` and `Amount.parseDecimal` with `FormatError`: an answer with more than 1,000,000 data
144
+ elements and segments in its plain or in its encrypted part, or with more than one encrypted part (HNVSD); XML nested
145
+ more than 100 levels deep, an empty element such as `<a/>` included, or with more than 500,000 nodes besides text or
146
+ one per 16 characters, whichever is more; an MT940 field of more than 65,536 characters; and an amount written with
147
+ more than 64 characters. The limits were 200,000 data elements per answer, the encrypted part included, and XML of 256
148
+ levels or 1,000,000 elements and attributes; fields and amounts had none. A hostile answer can now take up to about
149
+ 210 MB of memory while it is read, instead of about 25 MB. The 128 MiB a query may hold count each data element its
150
+ pages keep as 512 bytes instead of 256, and no longer count the elements of the encrypted part's envelope, so a query
151
+ of many short elements stops after half as many. The 200,000 statements and transactions per query stay.
152
+ - XML text or an attribute value of megabytes of `&`, or of unknown entities such as `&a;`, fails at its first bad
153
+ reference. The parser first found every reference, which took more than a second and about a gigabyte of memory for
154
+ 12 MB, beyond the 210 MB the limits allow.
155
+ - camt: remittance information (`Ustrd`) of more than 65,536 characters, as for an MT940 field, fails
156
+ `getTransactions` with `FinTsProtocolError` and `Camt.parse` with `FormatError`. Megabytes of SEPA keywords took
157
+ about 40 times their size in memory.
158
+ - camt: blanks alone between elements, such as the line breaks of an indented document, are no longer kept as text,
159
+ which halves the memory such a document takes while it is read.
160
+ - MT940: the counterparty's IBAN and BIC come from the subfields `?31` and `?30` only, where the bank states them. A
161
+ payer could write `IBAN+…` and `BIC+…` into the end-to-end reference, and these filled `counterpartyIban` and
162
+ `counterpartyBic` where the subfields stated none. Both values stay readable in `purposeCodes`.
163
+ - In a browser, `HttpTransport` sends no cookies and no referrer with a message, and the browser's cache keeps no copy
164
+ of the exchange (`credentials: 'omit'`, `referrerPolicy: 'no-referrer'`, `cache: 'no-store'`). With the defaults,
165
+ cookies of the page and its URL as referrer went along to a server on the page's own origin.
166
+ - The relay server of the README refuses a body without `Content-Length` or of more than 1 MiB before reading it:
167
+ update relays built from it. The documentation of `FinTsTransport.post` says that the client bounds neither the time
168
+ of the exchange nor the size of the answer, so a transport of the app's own has to, as `HttpTransport` does.
169
+
170
+ ### Fixed
171
+
172
+ - `close` ends the dialog of a request it aborts after five seconds, unless that request opened the dialog, whose ID
173
+ only the answer tells: the end goes out after the abort, under the next message number, since the bank may have
174
+ received the aborted message. Until now the abort dropped the dialog without an end, and the bank kept it open until
175
+ its timeout. The answer to that end refuses the login only for a rejected PIN, as at any dialog end, not for an error
176
+ such as a message number the bank did not expect because the aborted message never reached it.
177
+ - `close` gives the dialog ends five seconds once the request on its way, if any, is over: then the client stops
178
+ waiting for them, a transport that takes the abort, as `HttpTransport` does, stops them, and none goes out later. A
179
+ bank that has stopped answering held up `close` for the end of an open dialog until the transport's timeout, 90
180
+ seconds by default.
181
+ - The answer to a request on its way when `close` is called counts as any other, as in the Dart package: the logger gets
182
+ it, and the saved state keeps the bank and user parameter data, the customer system ID, the TAN medium and the SEPA
183
+ account list it brings. `close` aborted it at once, so a client restored from the state repeated the anonymous dialog,
184
+ the synchronization, which has the bank register another customer system ID, the lookup of the TAN media or the SEPA
185
+ account list, and its next login reported user parameter data version 0. The dialog of that request is ended as well,
186
+ also where the request opened it, whose ID only the answer tells, and a login answered so no longer counts as one
187
+ whose answer was lost.
188
+ - A dialog end that `close` keeps from going out, once the time after the request on its way is up, no longer reaches
189
+ the logger as an outgoing message, as in the Dart package: the logger showed a dialog end the bank never received.
190
+ - A TAN medium name the app passes to `selectTanMethod`, also from the saved state, goes out without blanks at either
191
+ end (Formals B.4.1), and one of blanks only as no name, as in the Dart package: a bank that knows the medium without
192
+ them refused the login, and the state kept the refusal. `selectedTanMedium` and the state keep the name as the app
193
+ passed it. A name the bank issued still goes back as the bank sent it, blanks at either end included, and the medium
194
+ in use of a state saved by 0.2.0, which does not tell the two apart, as 0.2.0 sent it.
195
+ - `selectTanMethod(method, null)` leaves the TAN medium to the next login, which looks the media up where the method
196
+ needs one, as without a medium and as in the Dart package. The login went out without a medium, which the bank
197
+ refused, and the client kept the refusal until `clearLoginRefusal`.
198
+ - A `tanMethodSelector` or `tanMediumSelector` that returns `null` picks the first method or medium, as for `undefined`,
199
+ instead of failing the call with a `TypeError`; the selector types allow `null`.
200
+ - `null` for `logger`, `onBankMessage`, `onWarning`, `tanMethodSelector`, `tanMediumSelector` or `state` means none, as
201
+ in the Dart package. `logger: null` failed every call that exchanged messages, and `close`, after their traffic;
202
+ `onBankMessage: null` and `onWarning: null` failed a call whose answer carried a bank message or a warning; and a
203
+ `null` selector failed the call after the PIN-signed synchronization or the lookup of the TAN media.
204
+ - `null` counts as not given for the details of an `Account`, whose `toString` threw for an `accountNumber` of `null`,
205
+ for the `customerId` of `FinTsConfig`, which is then the user ID, where a `TypeError` without the package's message
206
+ was thrown, and for the `currency` of `Mt940.parse`, which gave amounts in the currency `null` instead of the
207
+ `FormatError` 'MT940 statement without currency', as in the Dart package.
208
+ - Where the bank parameter data rule out a login, by the PIN's length or the message's size, the client fetches them
209
+ anew in an anonymous dialog, which carries no PIN, and tries the login once more, which goes out only if the new
210
+ limits allow it; where they rule it out as well, the call fails with the error that names the new limits, as in the
211
+ Dart package. Until now outdated parameter data, as saved ones may be, failed every call that logs in with a
212
+ `TypeError` (`FinTsProtocolError` for the size) until the app dropped `client.state`. It takes only the limits from
213
+ the anonymous answer, and only from parameter data of another version than those kept, the PIN's length only where
214
+ they state it. Those limits serve until the login brings the user's parameter data, which the login asks for by
215
+ reporting version 0, so the login the new limits judge may be up to two bytes shorter than the one the old ones
216
+ stopped. The anonymous parameter data never replace the user's. A bank that does not answer anonymously cannot refresh
217
+ them; the call then fails as before, without sending the PIN.
218
+ - A SEPA account list saved empty, as fints-ts 0.1 and the Dart package 0.2.0 saved it, is ignored on restore, as the
219
+ Dart package does after 0.2.0, so the client asks the bank for it again. Until the bank changed its user parameter
220
+ data, such a state kept the client from asking: `getAccounts` returned the accounts without their BIC, and an account
221
+ the app built from its IBAN went out without one, which a bank may refuse, or failed with `FinTsUnsupportedError`
222
+ where the user parameter data name the account by its number only.
223
+ - `TanChallenge.tanMediumName` is `undefined` for a challenge in the dialog that looks up the TAN media, or where the
224
+ bank echoes it, instead of the placeholder `noref`.
225
+ - The client no longer keeps the result of its last call, such as the transactions, until its next call or `close`.
226
+ - `console.log` and `util.inspect` show an `Amount` as its `toString`, such as `-123.45 EUR`, as the Dart package prints
227
+ it, instead of its fields `minorUnits`, `scale` and `currency`.
228
+ - An answer that is no FinTS message at all, such as the web page of a proxy or a maintenance notice, fails with the
229
+ `FinTsProtocolError` 'Malformed bank data: Not a FinTS message: no message header' instead of 'Malformed bank data:
230
+ Segment without terminator'. A message that starts with its header and is cut short still reports what is wrong with
231
+ it.
232
+ - `HttpTransport` refuses an answer whose `Content-Length` announces more than `maxResponseBytes` at once, without
233
+ reading it, with the same `FinTsTransportError` as for a body over the limit, as the Dart package does. A server that
234
+ announced more and then stalled held the call until the timeout, 90 seconds by default. One that sent the whole answer
235
+ had it read up to the limit before the refusal.
236
+ - `getTransactions` reads statement data that a bank sends as text instead of binary data, as it did for booked camt
237
+ documents: booked and pending MT940 (HIKAZ) and the pending camt document (HICAZ) were dropped without an error. A
238
+ malformed or overlong binary length still fails the call with `FinTsProtocolError`.
239
+ - `TransactionFormat` `auto` takes camt.052 where the bank offers it and MT940 cannot be requested for the account (the
240
+ bank offers no `HKKAZ` version the client implements, or PIN/TAN does not permit it), instead of failing with
241
+ `FinTsUnsupportedError`.
242
+ - A FinTS 3.0 time `240000` is midnight of the next day. So `Balance.bookedAsOfTime`, `Balance.bookingTime` and
243
+ `TanChallenge.validUntil` are set for it instead of `undefined`, and the account extension of the user parameter data
244
+ is read with it instead of being dropped as malformed, BIC, balance and data status included. `bookedAsOf` and
245
+ `bookingDate` stay the stated day.
246
+ - camt: a booking or value date given as `DtTm` without a `T` after the date, such as `2023-12-31`,
247
+ `2024-01-02 10:00:00` or `2024-01-02t10:00:00`, is the date written, as in the Dart package, instead of failing
248
+ `getTransactions` with `FinTsProtocolError`. Whatever follows the date is not read then. A `DtTm` or `Dt` with the
249
+ time `24:00:00` is midnight of the next day, as a FinTS 3.0 time `240000` is. A `Dt` with date and time counts on its
250
+ German day, as a `DtTm` does: `2024-03-15T23:30:00Z` is 16 March.
251
+ - MT940 and camt: `SVWZ+` after `ABWA+` or `ABWE+`, the order some banks write them in, starts the remittance
252
+ information, which went into the ultimate debtor or creditor, leaving the whole text, keywords and all, as the
253
+ purpose. Any other keyword in that text still starts no value, and one that occurs twice still has none.
254
+ - MT940: `getTransactions` joins pages with `@@` where none of them holds a line break. After a first page without `@@`,
255
+ such as `:20:X`, the `@@` of the other pages were read as text, and the query returned no transactions without an
256
+ error.
257
+ - camt: a comment ends only after its `<!--`, so that `<!-->` starts one instead of closing at once, which turned the
258
+ comment into text; an attribute counts by its name, namespace prefix and all, so that `q:Ccy` is not the currency of
259
+ an amount; an element named with a leading colon, such as `<:Ntry>`, is not the unprefixed one.
260
+ - The `EREF`, `MREF` and `CRED` of camt `purposeCodes` keep the place the remittance text gives them, before `SVWZ` as
261
+ banks write them, instead of following all other keywords. Their values still come from their elements only.
262
+ - MT940: the booking date of an MT942 lies between its value date and the creation date `:13D:`, which the statement's
263
+ balances otherwise bound, instead of in the year closest to the value date: a booking `1230` with value date
264
+ 2023-06-15 in an MT942 created on 2024-01-02 is dated 2023-12-30, not 2022-12-30.
265
+ - MT940: a statement whose closing balance is dated before its opening balance, or whose creation date `:13D:` cannot be
266
+ read or is stated twice, is a `FormatError` (`FinTsProtocolError` in `getTransactions`) instead of being read.
267
+ - MT940: a statement that balances is read also where a sum on the way lies beyond what an `Amount` holds (about 90
268
+ trillion at two decimal places, less with more decimals), as camt batch bookings are. It failed `getTransactions` with
269
+ `FinTsProtocolError` 'Malformed bank data: MT940 amounts too large to add up', and `Mt940.parse` with `FormatError`. A
270
+ statement that does not balance fails with 'MT940 transactions do not add up to the closing balance' however large its
271
+ amounts, as in the Dart package.
272
+ - MT940: the subfield that ends a `:86:` field keeps the blanks at its end, as in the Dart package and before 0.2.0.
273
+ Where the bank writes it before subfields it continues, such as `?33Mustermann?32Max `, the purpose, the
274
+ counterparty's name and the SEPA keywords are joined with that blank (`Max Mustermann`, not `MaxMustermann`). Only the
275
+ statement end and line feeds are dropped from the end of a field.
276
+ - camt: a batch booking whose details add up to it is split also where their sum on the way lies beyond what an `Amount`
277
+ holds (about 90 trillion at two decimal places), whatever the order of the details; such a batch stayed one booking.
278
+ - U+0085 (NEL), the byte 0x85 in ISO 8859-1 text, counts as a blank wherever the client drops the blanks around a value,
279
+ as Unicode and the Dart package have it. That covers what it reads: MT940, SEPA purpose and camt values (a camt `Sts`
280
+ of `PDNG` followed by it reads as pending, not booked), the parameter data, such as the account owner, a segment's
281
+ type and numbers, amounts and challenge texts; and what it sends: segment values, the login details of `FinTsConfig`
282
+ and the TAN the user enters. The IBAN and BIC of an `Account`, which go without any blanks, drop it as well.
283
+ - camt: U+0085 (NEL), the byte 0x85 in ISO 8859-1, counts as white space between the parts of a start or end tag and
284
+ between the nodes outside the root element, as other Unicode white space did and as in the Dart package. Such a
285
+ document failed `getTransactions` with `FinTsProtocolError` and `Camt.parse` with `FormatError`.
286
+ - Bank text read as UTF-8 that starts with two byte order marks loses both, as in the Dart package; the second stayed as
287
+ U+FEFF in data element texts and the message log, and on an MT940 page after the first it failed `getTransactions`
288
+ with `FinTsProtocolError`.
289
+ - The security control reference that ties the signature head (HNSHK) to the signature end (HNSHA) is drawn uniformly:
290
+ its first nine digits up to 794967295 came up a quarter more often than the rest.
291
+ - A number in the parameter data beyond 9007199254740991 (2^53 - 1), which a JavaScript number holds only approximately,
292
+ counts as not stated, as a malformed one does. Such a version of the bank or user parameter data went back to the bank
293
+ as `100000000000000000000` or `1e+22` instead of `0`. A minimum PIN length of that size failed every login with a
294
+ `TypeError`. Polling parameters of that size let a decoupled TAN method poll every 60 seconds with no limit on the
295
+ number of requests other than the 10 minutes, instead of the defaults. An account type of that size made `category`
296
+ `'other'` instead of `'unknown'`.
297
+ - A number in the parameter data written `-0`, such as a version or an account type, reads as 0, as in the Dart package,
298
+ not as JavaScript's negative zero, which `util.inspect` shows as `-0` and `Object.is` tells apart from 0.
299
+ - An account in the user parameter data whose national account has the older layout without sub-account (number, country
300
+ and bank code, such as `1234567890:280:12345678`) keeps its country and bank code, as in the Dart package. It got the
301
+ sub-account `280`, the country code `12345678` and the configured bank code, so queries for it named an account the
302
+ bank does not know. Three elements whose last is a country code, such as `1234567890:01:280` or `987654321::040`,
303
+ still read as number, sub-account and country code: a country code has three digits, a German bank code eight.
304
+ - `getAccounts` completes an account of the user parameter data with the IBAN and BIC of the SEPA account list also
305
+ where one of the two states no bank or country code, which matches any, as in `Account.matches` and the Dart package.
306
+ This happens with a saved state edited so, or where a code the bank sent was only a byte order mark. The list entry
307
+ came out as an account of its own, and an account the app built from its IBAN went out as that entry, without bank
308
+ code, permitted transactions and currency.
309
+ - Up to three further pages of a query may ask for an approval, as its first page may: the client asks `tanCallback`, or
310
+ waits for the app approval, as for the first page. Until now only the first page could, and a bank that asked again
311
+ for a later page failed every such query with `FinTsProtocolError`, without asking the user. Where a fourth further
312
+ page of the same query asks for an approval, the call still fails with `FinTsProtocolError`, before the user is asked,
313
+ and the dialog ends. A query thus asks the user four times at most, and an approval the user cancels still fails the
314
+ call with `FinTsTanCancelledError` and loses the pages fetched so far. The Dart package 0.2.0 asks for every page, up
315
+ to 1000.
316
+ - `close` no longer waits for a transport that ignores the abort: five seconds after `close`, the request on its way
317
+ fails with a `FinTsTransportError` whatever the transport, and the dialog ends then have five seconds of their own.
318
+ A custom transport that ignored the `AbortSignal` and had no timeout of its own held up the call, and with it
319
+ `close`, forever.
320
+ - A network error whose cause has no message of its own, as Node.js reports a refused or failed connection to a host
321
+ with both IPv6 and IPv4 addresses, gives the reasons of the attempts or the error code, such as
322
+ `fetch failed: connect ECONNREFUSED ::1:3000; connect ECONNREFUSED 127.0.0.1:3000`, instead of just `fetch failed: `.
323
+ - The bank's dialog abort message (Formals B.7.6) fails the call with a `FinTsBankError` that carries the bank's
324
+ return codes and text, and ends the dialog. The bank sends it unencrypted, with the dialog ID `unbekannt` and message
325
+ number 9999, where it cannot tell them, such as for a broken message header, an unknown bank code or a bank locked
326
+ for a release. Such an answer to any message but the first of a dialog failed with the `FinTsProtocolError` 'The
327
+ answer belongs to another message than the one sent', which lost the bank's text, and the client then sent a dialog
328
+ end to the dialog the bank had aborted.
329
+ - Balance and transaction queries that name the account by its international account (`HKSAL` 7 and 8, `HKKAZ` 7,
330
+ `HKCAZ`) name an account with BIC by IBAN and BIC only, without account number, sub-account and bank code, where the
331
+ bank parameter data rule out the national account (`HISPAS` 'Nationale Kontoverbindung erlaubt' `N`). They no longer
332
+ send an IBAN without its BIC, which the specification rules out (Messages B.3.2): such an account goes out with its
333
+ account number, sub-account and bank code instead, where it has an account number. Until now these queries always
334
+ sent the national account, and an IBAN without BIC with an empty BIC.
335
+ - The account extension of the user parameter data (BIC, data status and complete balance) is read where the bank
336
+ pads it with U+0085 (NEL) or U+00A0, as the client allows for the other fields. Such an extension was ignored, so the
337
+ client fetched the BIC with the SEPA account list and the balance with a balance query.
338
+ - A synchronization with the one-step method that the bank answers with `9955` (one-step TAN method not allowed) and
339
+ `3920`, as PIN/TAN B.8.2 prescribes for a user bound to two-step methods, is repeated with a method the bank lists,
340
+ with or without `9800`. It refused the login for good and forgot the PIN.
341
+ - A call whose TAN method prompt after a refused login ends with an error, such as `close` during
342
+ `tanMethodSelector`, fails with that error and leaves no refusal behind. The refusal, which named a TAN method the
343
+ user may not use and not the PIN, outlasted the call: the client forgot the PIN, saved the refusal in `client.state`,
344
+ and refused every login until `clearLoginRefusal`.
345
+ - Plain JavaScript can no longer change `Transaction.purposeCodes` or `AccountDataStatus.inventory` through the map
346
+ inside them: `ImmutableMap` keeps its entries in an ECMAScript-private field.
347
+ - A flicker code whose start code states a length of 0, or sets bit 6 of its length, is refused, as a data element of
348
+ such a length already was. `FlickerCode.parse` read an empty start code, which rendered as ASCII data of length 0,
349
+ and dropped bit 6.
350
+ - A flicker code whose tenth control byte announces another one is refused. It was read as if the list had ended
351
+ there, and the rest of the code was read from the wrong position.
352
+ - A blank in the data of a flicker code, such as `1,00 EUR`, stays part of the data. The client removed every white
353
+ space before reading the code, so such a code in HHD_UC was refused and the challenge had no `flickerCode`.
354
+ - A challenge whose HHD_UC is neither a photoTAN image nor a flicker code takes the flicker code of its challenge text
355
+ (`CHLGUC`). `TanChallenge.flickerCode` was `undefined` then, although `plainMessage` left out the code.
356
+ - Challenge text counts as a combined challenge only where it starts with `CHLGUC`, after blanks, and the four digits
357
+ after it state the length of the code. Elsewhere it is shown as the bank sent it: `plainMessage` dropped everything
358
+ up to a `CHLGTEXT` anywhere in the text, such as in a payment purpose the bank copied in, and a `CHLGUC` in the
359
+ middle of the text gave a flicker code.
360
+ - `TanImage.tryParse` refuses a container that declares an image of 0 bytes. It gave an image whose `toDataUrl()` was
361
+ an empty `data:` URL.
362
+ - MT940: the balance date `0` or `000000`, which the specification allows for the first statement of an account,
363
+ reads as no date (`openingDate` or `closingDate` `undefined`). It failed `getTransactions` with
364
+ `FinTsProtocolError` and `Mt940.parse` with `FormatError`.
365
+ - MT940: the `:61:` customer reference `KREF+` reads as the `KREF+` value of `:86:`, as the specification has it,
366
+ instead of `'KREF+'` for every such transaction.
367
+ - MT940: a bank code in `?30` next to an IBAN in `?31` is `counterpartyBankCode`, not `counterpartyBic`.
368
+ - `Mt940.parse` reads text that starts with a byte order mark or blanks, as `fs.readFile(…, 'utf8')` returns it. It
369
+ dropped the first `:20:` and returned its statement without `reference`.
370
+ - camt: a transaction whose remittance information is structured only (`Strd/CdtrRefInf/Ref`, such as an RF creditor
371
+ reference) takes that reference as its `purpose`, which was `undefined` or the `AddtlTxInf`.
372
+ - The README example saves `client.state` after `close`, not before, also where `close` fails: the answers `close`
373
+ waits for may bring a PIN the bank rejects at the dialog end, which a client restored from a state saved before would
374
+ send again, as well as the parameter data and the customer system ID of a request on its way.
375
+ - The README says what the type declarations need: the global `URL`, `AbortSignal` and `fetch` types, from the
376
+ TypeScript lib `DOM` or `@types/node`, instead of a TypeScript version.
377
+
378
+ ## 0.2.0
379
+
380
+ ### Breaking
381
+
382
+ - Keep a `FinTs3Client` out of Vue's reactive state (`ref`, `reactive`, Pinia): its fields are ECMAScript private now,
383
+ which Vue's proxies cannot reach, so every call fails with a `TypeError`. Use a plain variable, a `shallowRef` or
384
+ `markRaw`.
385
+ - `FinTsTransport.post` takes an `AbortSignal` as fourth argument, which the client aborts on `close`: pass it to
386
+ `fetch`. Code that calls `post` itself must pass one; `HttpTransport.post` takes it optionally.
387
+ - A custom transport reports failures as `FinTsTransportError`, with `statusCode` for an HTTP error. The client turns
388
+ any other error, another `FinTsError` included, into a `FinTsTransportError` that keeps only its message and that of
389
+ its cause, and `FinTsTransportError` takes and carries no `cause` any more.
390
+ - A refused login is a `FinTsLoginRefusedError`, which `FinTsPinError` and `FinTsLoginDataChangedError` now extend, also
391
+ where the bank ends the dialog in answer to the login (it was `FinTsDialogAbortedError`). The client sends the PIN no
392
+ more then: see Added for `loginRefusal` and `clearLoginRefusal`.
393
+ - `FinTsTanSetupError` replaces `FinTsUnsupportedError` where the client has no TAN method or medium to log in with: let
394
+ the user choose a medium or another method (`selectTanMethod`) rather than hide the feature.
395
+ - `FinTsError` takes the message only, as `Error` does, and `FinTsBankError` takes no `name`: a subclass declares
396
+ `override name = '…'`.
397
+ - `FinTsConfig` throws a `TypeError` for what the bank would refuse: a URL with user name or password, a country code of
398
+ other than three digits (280 for Germany, not 276), a German bank code of other than eight, and login details outside
399
+ ISO 8859-1. It trims the login details and the product, and `config.url` is a new copy at each access.
400
+ - `HttpTransport` throws a `TypeError` for a `timeoutMs` that is no positive number up to 2147483647, and for a
401
+ `maxResponseBytes` that is no positive number.
402
+ - A TAN longer than `TanMethod.maxTanLength`, with anything but the digits 0 to 9 for a `numericTan` method, or with
403
+ characters outside ISO 8859-1 fails the call with a `TypeError` before it is sent. Full-width digits count as digits
404
+ (NFKC).
405
+ - A TAN callback answer that is no `TanAnswer`, such as the `undefined` of a callback that returns nothing, fails the
406
+ call with a `TypeError`.
407
+ - Bank data are read strictly, failing `getTransactions` with `FinTsProtocolError` and the parsers with `FormatError`:
408
+ an MT940 statement that does not balance, states a balance, its account or its number twice, or holds an unreadable
409
+ balance, and MT940 text without fields; in camt, an unreadable date, a `DtTm` without time, and a document without
410
+ statements.
411
+ - A negative amount next to a credit/debit mark is malformed: in camt and HISAL it fails the call, and it voids the
412
+ account extension of the user parameter data; a camt debit of `-5.00` used to read as a credit.
413
+ - `TanImage.tryParse` takes PNG, JPEG, GIF, WebP and BMP only, no SVG, and `TanImage.mimeType` is in lower case.
414
+ `FlickerCode.parse` rejects a code that would not render as the bank sent it, so `TanChallenge.flickerCode` is
415
+ `undefined` for it.
416
+ - `Account` keeps IBAN and BIC without blanks and in capitals. `Account.allowedTransactions` counts segment IDs only,
417
+ such as `HKCAZ`, no versioned names such as `HKCAZ_1`.
418
+ - `FinTsFeedback.parameters`, and with them the new login data of `FinTsLoginDataChangedError`, and
419
+ `TanChallenge.reference` are read one character per byte (ISO 8859-1), as the client sends them back.
420
+
421
+ ### Security
422
+
423
+ - The client keeps the PIN in a private field, out of reach of `JSON.stringify` and Node.js's `util.inspect`, though not
424
+ of a debugger or the browser's DevTools: never log the client. It forgets the PIN once closed or refused.
425
+ - A refused login is kept in `state`, as the bank's return codes, so that a client restored from it, also one for
426
+ another URL of the bank, does not send the PIN. Any error in the answer to a login refuses it, and so does a wrong PIN
427
+ reported later, at the dialog end included. Run the clients of one user one after another: the state saved last wins.
428
+ - After two logins in a row whose answer was lost, timed out or could not be read, which the bank may have counted, the
429
+ client refuses the login itself, with a `FinTsLoginRefusedError` without return codes, also across restored clients.
430
+ - A call sends at most three logins the bank refuses: another TAN method and a new customer system ID count once per
431
+ call each, and a refused one-step login is repeated with another method only where the bank names the method (9075, or
432
+ a 3920 next to no error but 9050 or 9800).
433
+ - New login data (3072) fail the call as soon as an answer to the login brings them, before any approval and also next
434
+ to errors; `clearLoginRefusal` cannot lift them.
435
+ - `close` stops a running call at its next message and aborts the request on its way; only the ends of its dialogs go
436
+ out after it.
437
+ - Error messages keep the PIN and account data out: a transport's error passes on its message only, without `cause`;
438
+ `FormatError` and `FinTsProtocolError` leave out the data; a URL with credentials is rejected before `fetch` puts it
439
+ in an error.
440
+ - Messages go to the bank's URL only: `HttpTransport` rejects the answer to a redirect its `fetch` followed or from
441
+ another URL, and the transport gets a copy of the checked URL for each message.
442
+ - An answer must be one complete message, with the number and, once assigned, the dialog ID of the message sent: one cut
443
+ short, broken in its framing, joined to another or answering another message fails with `FinTsProtocolError`. The
444
+ first answer of a dialog cannot be matched, so a relay must never mix up answers.
445
+ - Parameter data come only from the answers to a dialog's opening; the anonymous dialog's serve until the user's arrive,
446
+ and those of another user, of a rejected customer system ID (9391) or of a state from an earlier version or the Dart
447
+ package are fetched anew.
448
+ - A balance (HISAL) and camt transactions (HICAZ) must be for the account asked for, or the call fails with
449
+ `FinTsProtocolError`. MT940 is not checked, since banks write the `:25:` line in many ways.
450
+ - An account the app builds itself goes out as the bank knows it and is checked against the transactions the bank
451
+ permits for it; one the bank names nowhere fails with `FinTsUnsupportedError` where those lists are complete
452
+ (UPD-Verwendung 0).
453
+ - Hostile answers no longer exhaust the memory or hold up the thread: past 200,000 data elements per answer, 128 MiB or
454
+ 200,000 statements and transactions per query, or XML of 256 levels or a million elements and attributes, a call fails
455
+ with `FinTsProtocolError`, and `Mt940.parse` and `Camt.parse` with `FormatError`; reading takes linear time.
456
+ - An MT940 statement must balance, and name its account and number once, so that a payer cannot add a transaction or an
457
+ account with a purpose line that starts like a field, such as `:61:` or `:25:`.
458
+ - A SEPA keyword in the text the payer or payee writes (`SVWZ+`, `ABWA+`, `ABWE+`) is part of that text, and one that
459
+ occurs twice has no value: such text replaced the creditor ID, mandate reference or IBAN the bank stated.
460
+ - The creditor ID of a camt transaction is the creditor's (`Cdtr`) only, and the `EREF`, `MREF` and `CRED` of
461
+ `purposeCodes` come from their elements only, never from the remittance text.
462
+ - A flicker code that would not render as the bank sent it is refused rather than shown altered on the TAN generator,
463
+ and so is a data element length of 0 or above 63. A TAN image of type SVG, which may carry scripts, is refused.
464
+ - The docs say to show challenge text as text, never as HTML (`innerHTML`, `v-html`): it is the bank's text, or a
465
+ relay's.
466
+ - The README relay serves the signed-in sessions of the app only, limits their requests, forwards to the bank of the
467
+ session only, refuses redirects and passes the signal on: update relays built from it.
468
+
469
+ ### Fixed
470
+
471
+ - The README relay reports the relay's HTTP status as `FinTsTransportError.statusCode`, and its server passes the bank's
472
+ on. Without it, a bank that fails on the anonymous announcement of strong authentication never delivered its parameter
473
+ data.
474
+ - The README names the minimum Deno (2.1) and Bun (1.2.6): with older ones a call from inside a callback waits forever
475
+ instead of failing with `FinTsStateError`.
476
+ - The docs say when a call logs in again, which may ask for another approval, that `getTanMethods` may log in, that
477
+ `FinTsUnsupportedError` may follow a login, and the client's own limits of an app approval: 60 status requests where
478
+ the bank states none, and 10 minutes.
479
+ - The PIN's length limits apply to the login only: a synchronization whose first parameter data ruled out the PIN the
480
+ bank had accepted failed its own dialog end.
481
+ - An answer to a TAN or an app approval that asks for an approval once more (0030, 3955) fails with `FinTsProtocolError`
482
+ instead of reading as done, and only the first page of a query may ask for an approval.
483
+ - While the client polls for an app approval, new instructions of the bank replace the open prompt, whose
484
+ `TanChallenge.resolved` settles; a settled prompt is no longer kept until `close`.
485
+ - `getTanMedia` asks the bank unless the same call has just looked the media up; the list of a lookup that found no
486
+ active medium is handed out by every call; a TAN method switched back to has its media looked up anew;
487
+ `clearLoginRefusal` forgets the TAN medium, which the bank may have refused.
488
+ - `getTransactions` rejects a `from` or `to` that is no valid `Date` with a `TypeError`, before it waits for other
489
+ calls; an Invalid Date went out as `0NaNNaNNaN`.
490
+ - Values the bank issued go back as it sent them: dialog ID, customer system ID, TAN order reference, position to
491
+ continue at and TAN medium name, such as one in UTF-8 that fits ISO 8859-1, which the bank did not know otherwise.
492
+ - A SEPA account list the bank answers by ending the dialog counts as rejected, and an empty one is not saved, so that
493
+ neither costs every client another login.
494
+ - `HttpTransport` calls its `fetch` as a plain function (a browser's native one failed with `Illegal invocation`),
495
+ checks the size of an answer without a stream body, and reads the body of node-fetch.
496
+ - MT940: `@@` separates the lines wherever the first line holds it; each page is decoded on its own; a booking date lies
497
+ in the year that places it within its statement; only `?` separates the subfields of `:86:`.
498
+ - camt: a batch booking is split only into details that add up to it, in its currency; details count in `NtryDtls` and
499
+ purpose lines in `RmtInf` only; a `DtTm` counts on its German day; purpose lines cut at 35 characters keep their
500
+ blanks; `&constructor;` is an unknown entity.
501
+ - Models keep copies of the `Date`s they are given, so that changing one in place changes no other, nor what a later
502
+ `getAccounts`, `getBalance` or `getTanMedia` returns. A complete balance of the account extension states the
503
+ `productName`.
504
+ - An account of the user parameter data whose national account leaves out the bank code keeps its country code.
505
+ - `state` encodes the parameter data once, as the bank sent them, and bank text is decoded in bulk: both held up the
506
+ thread with large data.
507
+ - `FinTs3Client` extends no internal class, so that its declarations name no internal types.
508
+
509
+ ### Added
510
+
511
+ - `FinTsClient.loginRefusal`, the refused login that keeps the client from sending the PIN, and
512
+ `clearLoginRefusal(pin)`, which lifts it with a PIN the user has entered anew; `FinTsLoginRefusedError`.
513
+ - `FinTsTanSetupError`, for a missing TAN method or medium.
514
+ - `Camt.parse`, which gives each statement of a camt document as a `CamtStatement` with its account.
515
+ - `close` aborts a request on its way, through the signal of `FinTsTransport.post`; `HttpTransport` stops it.
516
+
1
517
  ## 0.1.0
2
518
 
3
519
  First release: a TypeScript port of the FinTS 3.0 client of the Dart package `fints`.
@@ -7,5 +523,7 @@ First release: a TypeScript port of the FinTS 3.0 client of the Dart package `fi
7
523
  parameters; TAN method and medium selection, chipTAN flicker codes and photoTAN images.
8
524
  - Bank parameter data, customer system ID and the chosen TAN method in an exportable state string, in the layout of the
9
525
  Dart package.
10
- - A client never sends its PIN again once the bank has refused a login.
526
+ - A client never sends its PIN again once the bank has refused a login, but where the bank names a reason the client
527
+ takes care of in the same call: another TAN method (3920, or 9075 after the one-step method) or a new customer system
528
+ ID (9391).
11
529
  - Runs wherever `fetch`, Web Crypto and `TextDecoder` are available; no runtime dependencies.