@coderoftime/fints 0.0.0-stage → 0.2.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 (249) hide show
  1. package/CHANGELOG.md +152 -0
  2. package/LICENSE +28 -0
  3. package/README.md +246 -2
  4. package/dist/client.d.ts +48 -0
  5. package/dist/client.d.ts.map +1 -0
  6. package/dist/client.js +199 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/core/account.d.ts +168 -0
  9. package/dist/core/account.d.ts.map +1 -0
  10. package/dist/core/account.js +245 -0
  11. package/dist/core/account.js.map +1 -0
  12. package/dist/core/amount.d.ts +63 -0
  13. package/dist/core/amount.d.ts.map +1 -0
  14. package/dist/core/amount.js +192 -0
  15. package/dist/core/amount.js.map +1 -0
  16. package/dist/core/balance.d.ts +55 -0
  17. package/dist/core/balance.d.ts.map +1 -0
  18. package/dist/core/balance.js +54 -0
  19. package/dist/core/balance.js.map +1 -0
  20. package/dist/core/bank-info.d.ts +49 -0
  21. package/dist/core/bank-info.d.ts.map +1 -0
  22. package/dist/core/bank-info.js +52 -0
  23. package/dist/core/bank-info.js.map +1 -0
  24. package/dist/core/client.d.ts +161 -0
  25. package/dist/core/client.d.ts.map +1 -0
  26. package/dist/core/client.js +2 -0
  27. package/dist/core/client.js.map +1 -0
  28. package/dist/core/config.d.ts +80 -0
  29. package/dist/core/config.d.ts.map +1 -0
  30. package/dist/core/config.js +153 -0
  31. package/dist/core/config.js.map +1 -0
  32. package/dist/core/errors.d.ts +153 -0
  33. package/dist/core/errors.d.ts.map +1 -0
  34. package/dist/core/errors.js +247 -0
  35. package/dist/core/errors.js.map +1 -0
  36. package/dist/core/feedback.d.ts +72 -0
  37. package/dist/core/feedback.d.ts.map +1 -0
  38. package/dist/core/feedback.js +127 -0
  39. package/dist/core/feedback.js.map +1 -0
  40. package/dist/core/transaction.d.ts +103 -0
  41. package/dist/core/transaction.d.ts.map +1 -0
  42. package/dist/core/transaction.js +96 -0
  43. package/dist/core/transaction.js.map +1 -0
  44. package/dist/core/transport.d.ts +64 -0
  45. package/dist/core/transport.d.ts.map +1 -0
  46. package/dist/core/transport.js +149 -0
  47. package/dist/core/transport.js.map +1 -0
  48. package/dist/formats/camt.d.ts +32 -0
  49. package/dist/formats/camt.d.ts.map +1 -0
  50. package/dist/formats/camt.js +242 -0
  51. package/dist/formats/camt.js.map +1 -0
  52. package/dist/formats/mt940.d.ts +54 -0
  53. package/dist/formats/mt940.d.ts.map +1 -0
  54. package/dist/formats/mt940.js +376 -0
  55. package/dist/formats/mt940.js.map +1 -0
  56. package/dist/formats/readers.d.ts +15 -0
  57. package/dist/formats/readers.d.ts.map +1 -0
  58. package/dist/formats/readers.js +42 -0
  59. package/dist/formats/readers.js.map +1 -0
  60. package/dist/formats/record-budget.d.ts +7 -0
  61. package/dist/formats/record-budget.d.ts.map +1 -0
  62. package/dist/formats/record-budget.js +17 -0
  63. package/dist/formats/record-budget.js.map +1 -0
  64. package/dist/formats/sepa-purpose.d.ts +28 -0
  65. package/dist/formats/sepa-purpose.d.ts.map +1 -0
  66. package/dist/formats/sepa-purpose.js +89 -0
  67. package/dist/formats/sepa-purpose.js.map +1 -0
  68. package/dist/index.d.ts +28 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +27 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/session/app-approval.d.ts +66 -0
  73. package/dist/session/app-approval.d.ts.map +1 -0
  74. package/dist/session/app-approval.js +226 -0
  75. package/dist/session/app-approval.js.map +1 -0
  76. package/dist/session/dialog-runner.d.ts +31 -0
  77. package/dist/session/dialog-runner.d.ts.map +1 -0
  78. package/dist/session/dialog-runner.js +111 -0
  79. package/dist/session/dialog-runner.js.map +1 -0
  80. package/dist/session/login-guard.d.ts +78 -0
  81. package/dist/session/login-guard.d.ts.map +1 -0
  82. package/dist/session/login-guard.js +181 -0
  83. package/dist/session/login-guard.js.map +1 -0
  84. package/dist/session/sepa-accounts.d.ts +40 -0
  85. package/dist/session/sepa-accounts.d.ts.map +1 -0
  86. package/dist/session/sepa-accounts.js +112 -0
  87. package/dist/session/sepa-accounts.js.map +1 -0
  88. package/dist/session/session-setup.d.ts +80 -0
  89. package/dist/session/session-setup.d.ts.map +1 -0
  90. package/dist/session/session-setup.js +182 -0
  91. package/dist/session/session-setup.js.map +1 -0
  92. package/dist/session/session-state.d.ts +50 -0
  93. package/dist/session/session-state.d.ts.map +1 -0
  94. package/dist/session/session-state.js +182 -0
  95. package/dist/session/session-state.js.map +1 -0
  96. package/dist/session/signed-dialog.d.ts +77 -0
  97. package/dist/session/signed-dialog.d.ts.map +1 -0
  98. package/dist/session/signed-dialog.js +170 -0
  99. package/dist/session/signed-dialog.js.map +1 -0
  100. package/dist/session/tan-selection.d.ts +96 -0
  101. package/dist/session/tan-selection.d.ts.map +1 -0
  102. package/dist/session/tan-selection.js +189 -0
  103. package/dist/session/tan-selection.js.map +1 -0
  104. package/dist/session/user-prompts.d.ts +65 -0
  105. package/dist/session/user-prompts.d.ts.map +1 -0
  106. package/dist/session/user-prompts.js +184 -0
  107. package/dist/session/user-prompts.js.map +1 -0
  108. package/dist/tan/challenge.d.ts +135 -0
  109. package/dist/tan/challenge.d.ts.map +1 -0
  110. package/dist/tan/challenge.js +184 -0
  111. package/dist/tan/challenge.js.map +1 -0
  112. package/dist/tan/flicker.d.ts +42 -0
  113. package/dist/tan/flicker.d.ts.map +1 -0
  114. package/dist/tan/flicker.js +296 -0
  115. package/dist/tan/flicker.js.map +1 -0
  116. package/dist/tan/tan-image.d.ts +22 -0
  117. package/dist/tan/tan-image.d.ts.map +1 -0
  118. package/dist/tan/tan-image.js +43 -0
  119. package/dist/tan/tan-image.js.map +1 -0
  120. package/dist/tan/tan-models.d.ts +149 -0
  121. package/dist/tan/tan-models.d.ts.map +1 -0
  122. package/dist/tan/tan-models.js +153 -0
  123. package/dist/tan/tan-models.js.map +1 -0
  124. package/dist/util/async.d.ts +22 -0
  125. package/dist/util/async.d.ts.map +1 -0
  126. package/dist/util/async.js +45 -0
  127. package/dist/util/async.js.map +1 -0
  128. package/dist/util/bytes.d.ts +22 -0
  129. package/dist/util/bytes.d.ts.map +1 -0
  130. package/dist/util/bytes.js +128 -0
  131. package/dist/util/bytes.js.map +1 -0
  132. package/dist/util/call-context.d.ts +12 -0
  133. package/dist/util/call-context.d.ts.map +1 -0
  134. package/dist/util/call-context.js +30 -0
  135. package/dist/util/call-context.js.map +1 -0
  136. package/dist/util/dates.d.ts +55 -0
  137. package/dist/util/dates.d.ts.map +1 -0
  138. package/dist/util/dates.js +189 -0
  139. package/dist/util/dates.js.map +1 -0
  140. package/dist/util/errors.d.ts +17 -0
  141. package/dist/util/errors.d.ts.map +1 -0
  142. package/dist/util/errors.js +24 -0
  143. package/dist/util/errors.js.map +1 -0
  144. package/dist/util/immutable-map.d.ts +16 -0
  145. package/dist/util/immutable-map.d.ts.map +1 -0
  146. package/dist/util/immutable-map.js +38 -0
  147. package/dist/util/immutable-map.js.map +1 -0
  148. package/dist/util/json.d.ts +17 -0
  149. package/dist/util/json.d.ts.map +1 -0
  150. package/dist/util/json.js +62 -0
  151. package/dist/util/json.js.map +1 -0
  152. package/dist/util/text.d.ts +37 -0
  153. package/dist/util/text.d.ts.map +1 -0
  154. package/dist/util/text.js +107 -0
  155. package/dist/util/text.js.map +1 -0
  156. package/dist/util/xml.d.ts +36 -0
  157. package/dist/util/xml.d.ts.map +1 -0
  158. package/dist/util/xml.js +194 -0
  159. package/dist/util/xml.js.map +1 -0
  160. package/dist/v3/account-extension.d.ts +25 -0
  161. package/dist/v3/account-extension.d.ts.map +1 -0
  162. package/dist/v3/account-extension.js +173 -0
  163. package/dist/v3/account-extension.js.map +1 -0
  164. package/dist/v3/bank-connection.d.ts +34 -0
  165. package/dist/v3/bank-connection.d.ts.map +1 -0
  166. package/dist/v3/bank-connection.js +58 -0
  167. package/dist/v3/bank-connection.js.map +1 -0
  168. package/dist/v3/dialog.d.ts +112 -0
  169. package/dist/v3/dialog.d.ts.map +1 -0
  170. package/dist/v3/dialog.js +241 -0
  171. package/dist/v3/dialog.js.map +1 -0
  172. package/dist/v3/message.d.ts +85 -0
  173. package/dist/v3/message.d.ts.map +1 -0
  174. package/dist/v3/message.js +303 -0
  175. package/dist/v3/message.js.map +1 -0
  176. package/dist/v3/parameter-store.d.ts +75 -0
  177. package/dist/v3/parameter-store.d.ts.map +1 -0
  178. package/dist/v3/parameter-store.js +143 -0
  179. package/dist/v3/parameter-store.js.map +1 -0
  180. package/dist/v3/parameters.d.ts +105 -0
  181. package/dist/v3/parameters.d.ts.map +1 -0
  182. package/dist/v3/parameters.js +450 -0
  183. package/dist/v3/parameters.js.map +1 -0
  184. package/dist/v3/protocol.d.ts +61 -0
  185. package/dist/v3/protocol.d.ts.map +1 -0
  186. package/dist/v3/protocol.js +113 -0
  187. package/dist/v3/protocol.js.map +1 -0
  188. package/dist/v3/queries.d.ts +51 -0
  189. package/dist/v3/queries.d.ts.map +1 -0
  190. package/dist/v3/queries.js +120 -0
  191. package/dist/v3/queries.js.map +1 -0
  192. package/dist/v3/segments.d.ts +106 -0
  193. package/dist/v3/segments.d.ts.map +1 -0
  194. package/dist/v3/segments.js +325 -0
  195. package/dist/v3/segments.js.map +1 -0
  196. package/dist/v3/syntax.d.ts +127 -0
  197. package/dist/v3/syntax.d.ts.map +1 -0
  198. package/dist/v3/syntax.js +367 -0
  199. package/dist/v3/syntax.js.map +1 -0
  200. package/package.json +67 -4
  201. package/src/client.ts +252 -0
  202. package/src/core/account.ts +323 -0
  203. package/src/core/amount.ts +211 -0
  204. package/src/core/balance.ts +85 -0
  205. package/src/core/bank-info.ts +66 -0
  206. package/src/core/client.ts +186 -0
  207. package/src/core/config.ts +182 -0
  208. package/src/core/errors.ts +277 -0
  209. package/src/core/feedback.ts +140 -0
  210. package/src/core/transaction.ts +161 -0
  211. package/src/core/transport.ts +189 -0
  212. package/src/formats/camt.ts +266 -0
  213. package/src/formats/mt940.ts +419 -0
  214. package/src/formats/readers.ts +49 -0
  215. package/src/formats/record-budget.ts +18 -0
  216. package/src/formats/sepa-purpose.ts +94 -0
  217. package/src/index.ts +70 -0
  218. package/src/session/app-approval.ts +278 -0
  219. package/src/session/dialog-runner.ts +122 -0
  220. package/src/session/login-guard.ts +221 -0
  221. package/src/session/sepa-accounts.ts +115 -0
  222. package/src/session/session-setup.ts +184 -0
  223. package/src/session/session-state.ts +204 -0
  224. package/src/session/signed-dialog.ts +192 -0
  225. package/src/session/tan-selection.ts +203 -0
  226. package/src/session/user-prompts.ts +193 -0
  227. package/src/tan/challenge.ts +261 -0
  228. package/src/tan/flicker.ts +308 -0
  229. package/src/tan/tan-image.ts +38 -0
  230. package/src/tan/tan-models.ts +252 -0
  231. package/src/util/async.ts +48 -0
  232. package/src/util/bytes.ts +129 -0
  233. package/src/util/call-context.ts +41 -0
  234. package/src/util/dates.ts +210 -0
  235. package/src/util/errors.ts +27 -0
  236. package/src/util/immutable-map.ts +47 -0
  237. package/src/util/json.ts +67 -0
  238. package/src/util/text.ts +112 -0
  239. package/src/util/xml.ts +183 -0
  240. package/src/v3/account-extension.ts +185 -0
  241. package/src/v3/bank-connection.ts +67 -0
  242. package/src/v3/dialog.ts +283 -0
  243. package/src/v3/message.ts +373 -0
  244. package/src/v3/parameter-store.ts +160 -0
  245. package/src/v3/parameters.ts +524 -0
  246. package/src/v3/protocol.ts +148 -0
  247. package/src/v3/queries.ts +190 -0
  248. package/src/v3/segments.ts +374 -0
  249. package/src/v3/syntax.ts +369 -0
package/dist/client.js ADDED
@@ -0,0 +1,199 @@
1
+ import { FinTsConfig, requirePin } from './core/config.js';
2
+ import { FinTsStateError, FinTsUnsupportedError } from './core/errors.js';
3
+ import { DialogRunner } from './session/dialog-runner.js';
4
+ import { LoginGuard } from './session/login-guard.js';
5
+ import { SepaAccounts } from './session/sepa-accounts.js';
6
+ import { SessionSetup } from './session/session-setup.js';
7
+ import { restoreSession, saveSession } from './session/session-state.js';
8
+ import { TanSelection } from './session/tan-selection.js';
9
+ import { UserPrompts } from './session/user-prompts.js';
10
+ import { TanMedium } from './tan/tan-models.js';
11
+ import { SerialExecutor } from './util/async.js';
12
+ import { CallContext } from './util/call-context.js';
13
+ import { calendarDay, notAfterToday } from './util/dates.js';
14
+ import { invalidArgument } from './util/errors.js';
15
+ import { ParameterStore } from './v3/parameter-store.js';
16
+ import { FinTs3Protocol } from './v3/protocol.js';
17
+ import { balanceQuery, tanMediaQuery, transactionsQuery } from './v3/queries.js';
18
+ /** A token of the client call running now, so that a call from inside its callbacks is recognized. */
19
+ const runningCalls = new CallContext();
20
+ /**
21
+ * The calendar day of `bound`, the `name` bound of a `TransactionQuery`: the bank takes dates without time of day.
22
+ * Throws `TypeError` for anything but a valid `Date`, such as an Invalid Date, which would go out as `0NaNNaNNaN`.
23
+ */
24
+ function requestedDay(bound, name) {
25
+ if (bound === undefined)
26
+ return undefined;
27
+ if (!(bound instanceof Date) || Number.isNaN(bound.getTime()))
28
+ throw invalidArgument('Not a valid Date', name);
29
+ return calendarDay(bound);
30
+ }
31
+ /** FinTS 3.0 PIN/TAN client, the version German banks use. */
32
+ export class FinTs3Client {
33
+ // A call such as `getBalance` runs through these parts:
34
+ // 1. `DialogRunner.open` reuses the session's dialog or logs in, through `SessionSetup.remedied`, which logs in once
35
+ // more for each refusal it can take care of.
36
+ // 2. `SessionSetup.prepare` first settles what is open: the bank parameter data, the synchronization, and through
37
+ // `TanSelection` the TAN method and medium.
38
+ // 3. `SignedDialog.login` sends the login and completes the strong authentication the bank asks for, a TAN or an app
39
+ // approval (`AppApprovalWait`).
40
+ // 4. `DialogRunner.query` sends the order in that dialog, completes its approval the same way, and fetches all pages.
41
+ //
42
+ // `FinTs3Protocol` builds, signs and posts the messages of each `FinTs3Dialog`, the queries build the orders and read
43
+ // the answers, and the `ParameterStore` keeps the bank's parameter data and IDs. `SepaAccounts` completes IBAN and
44
+ // BIC, and `UserPrompts` is everything the app is told or asked. The `LoginGuard` holds the PIN: the protocol takes it
45
+ // from the guard for every message it signs, and `SignedDialog` has the guard judge every answer, so that the PIN does
46
+ // not go out after a refusal.
47
+ //
48
+ // The fields are ECMAScript private, so that neither `util.inspect` nor `JSON.stringify` of a client reaches the PIN
49
+ // or the account data behind them.
50
+ #prompts;
51
+ #guard;
52
+ #parameters;
53
+ #protocol;
54
+ #sessionState;
55
+ #tans;
56
+ #setup;
57
+ #dialogs;
58
+ #sepa;
59
+ #queue = new SerialExecutor();
60
+ #closed;
61
+ /** The call running now, which a call from inside its callbacks would wait for. */
62
+ #runningCall;
63
+ /**
64
+ * A client with the session restored from `FinTsClientOptions.state` where it was saved for this user and bank.
65
+ *
66
+ * Throws `TypeError` if the configuration is invalid, as the constructor of `FinTsConfig` tells, or the PIN is empty,
67
+ * begins or ends with a blank, or has characters FinTS 3.0 cannot send: it uses ISO 8859-1, so `€` and most
68
+ * non-Latin letters are not possible.
69
+ */
70
+ constructor(init) {
71
+ const config = init.config instanceof FinTsConfig ? init.config : new FinTsConfig(init.config);
72
+ this.#prompts = new UserPrompts(init.options);
73
+ this.#guard = new LoginGuard(requirePin(init.pin));
74
+ this.#parameters = new ParameterStore(config);
75
+ this.#protocol = new FinTs3Protocol(this.#parameters, this.#guard, init.options.transport, this.#prompts.logger);
76
+ this.#sessionState = restoreSession(init.options.state, this.#parameters, this.#guard);
77
+ this.#tans = new TanSelection(this.#protocol, this.#sessionState, this.#prompts);
78
+ const session = {
79
+ parameters: this.#parameters,
80
+ state: this.#sessionState,
81
+ prompts: this.#prompts,
82
+ guard: this.#guard,
83
+ };
84
+ this.#setup = new SessionSetup(session, this.#protocol, this.#tans);
85
+ this.#dialogs = new DialogRunner(this.#setup);
86
+ this.#sepa = new SepaAccounts(this.#parameters, this.#sessionState, this.#dialogs);
87
+ }
88
+ get state() {
89
+ return saveSession(this.#parameters, this.#guard, this.#sessionState);
90
+ }
91
+ get loginRefusal() {
92
+ return this.#guard.refusal;
93
+ }
94
+ get selectedTanMethod() {
95
+ return this.#sessionState.tanMethod;
96
+ }
97
+ get selectedTanMedium() {
98
+ return this.#sessionState.tanMedium;
99
+ }
100
+ selectTanMethod(securityFunction, tanMedium) {
101
+ return this.#serialized(async () => {
102
+ await this.#dialogs.end();
103
+ this.#tans.select(securityFunction, tanMedium);
104
+ });
105
+ }
106
+ clearLoginRefusal(pin) {
107
+ return this.#serialized(async () => {
108
+ const sendable = requirePin(pin);
109
+ // The dialog ends with the PIN it was opened with.
110
+ await this.#dialogs.end();
111
+ this.#guard.replacePin(sendable);
112
+ this.#tans.forgetMedium();
113
+ });
114
+ }
115
+ getBankInfo() {
116
+ return this.#serialized(() => this.#setup.remedied(() => this.#setup.bankInfo()));
117
+ }
118
+ getTanMethods() {
119
+ return this.#serialized(() => this.#setup.remedied(() => this.#setup.methods()));
120
+ }
121
+ getTanMedia() {
122
+ return this.#serialized(async () => {
123
+ // The session keeps the list of a lookup that found no medium; the app gets media of its own.
124
+ const lookedUp = (await this.#setup.remedied(() => this.#setup.prepare())) ?? this.#tans.lookedUpMedia;
125
+ return (lookedUp?.map((m) => new TanMedium(m)) ??
126
+ (await this.#dialogs.query(() => {
127
+ const query = tanMediaQuery(this.#parameters);
128
+ if (query === undefined)
129
+ throw new FinTsUnsupportedError('The bank does not list TAN media');
130
+ return query;
131
+ })));
132
+ });
133
+ }
134
+ getAccounts() {
135
+ return this.#serialized(() => this.#sepa.completedAccounts());
136
+ }
137
+ getBalance(account) {
138
+ return this.#serialized(async () => {
139
+ const completed = await this.#sepa.complete(account);
140
+ // The dialog start delivers the user parameter data, which may carry the complete balance: then the client must
141
+ // not ask for it separately (Formals E.3.1.1, F.3.2).
142
+ await this.#dialogs.open();
143
+ return (this.#parameters.userParameters?.completeBalance(completed) ??
144
+ (await this.#dialogs.query(() => balanceQuery(this.#parameters, completed))));
145
+ });
146
+ }
147
+ async getTransactions(account, query = {}) {
148
+ // Checked before the call waits for others; an async method, so that every argument error is a rejection.
149
+ const firstDay = requestedDay(query.from, 'from');
150
+ const lastDay = requestedDay(query.to, 'to');
151
+ if (firstDay !== undefined && lastDay !== undefined && firstDay.getTime() > lastDay.getTime()) {
152
+ throw invalidArgument('`from` lies on a day after `to`', 'from');
153
+ }
154
+ return this.#serialized(async () => {
155
+ const completed = await this.#sepa.complete(account);
156
+ const transactions = await this.#dialogs.query(() => transactionsQuery(this.#parameters, completed, query.format ?? 'auto', notAfterToday(firstDay), notAfterToday(lastDay)));
157
+ // A stable sort, so that transactions of the same day keep the bank's order.
158
+ return transactions.sort((a, b) => (a.bookingDate ?? a.valueDate).getTime() - (b.bookingDate ?? b.valueDate).getTime());
159
+ });
160
+ }
161
+ close() {
162
+ this.#closed ??= this.#closeNow();
163
+ return this.#closed;
164
+ }
165
+ #closeNow() {
166
+ this.#prompts.close();
167
+ this.#protocol.beginClose();
168
+ return this.#queue.run(() => this.#prompts.reportingCallbackErrors(async () => {
169
+ try {
170
+ await this.#dialogs.end();
171
+ }
172
+ finally {
173
+ this.#guard.close();
174
+ this.#protocol.close();
175
+ }
176
+ }));
177
+ }
178
+ #serialized(action) {
179
+ const caller = runningCalls.current;
180
+ if (caller !== undefined && caller === this.#runningCall) {
181
+ // The call would wait behind the running one, which waits for the callback: neither would ever end.
182
+ return Promise.reject(new FinTsStateError('The FinTS client was called from inside one of its callbacks'));
183
+ }
184
+ return this.#queue.run(async () => {
185
+ const call = {};
186
+ this.#runningCall = call;
187
+ try {
188
+ return await runningCalls.run(call, () => this.#guard.runCall(() => {
189
+ this.#prompts.checkOpen();
190
+ return this.#prompts.reportingCallbackErrors(action);
191
+ }));
192
+ }
193
+ finally {
194
+ this.#runningCall = undefined;
195
+ }
196
+ });
197
+ }
198
+ }
199
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ /** Account kind derived from the FinTS account type code. */
2
+ export type AccountCategory =
3
+ /** Current account (type codes 1 to 9). */
4
+ 'checking'
5
+ /** Savings account (10 to 19). */
6
+ | 'savings'
7
+ /** Fixed-term deposit (20 to 29). */
8
+ | 'fixedDeposit'
9
+ /** Securities account (30 to 39). */
10
+ | 'securities'
11
+ /** Loan account (40 to 49). */
12
+ | 'loan'
13
+ /** Credit card account (50 to 59). */
14
+ | 'creditCard'
15
+ /** Fund deposit (60 to 69). */
16
+ | 'fund'
17
+ /** Home savings contract (70 to 79). */
18
+ | 'homeSavings'
19
+ /** Insurance (80 to 89). */
20
+ | 'insurance'
21
+ /** Any other type code. */
22
+ | 'other'
23
+ /** The bank states no type code. */
24
+ | 'unknown';
25
+ /** What `Account` takes; the bank states the details it knows. */
26
+ export interface AccountInit {
27
+ accountNumber?: string | undefined;
28
+ subAccount?: string | undefined;
29
+ bankCode: string;
30
+ countryCode?: string | undefined;
31
+ iban?: string | undefined;
32
+ bic?: string | undefined;
33
+ customerId?: string | undefined;
34
+ currency?: string | undefined;
35
+ ownerName?: string | undefined;
36
+ productName?: string | undefined;
37
+ typeCode?: number | undefined;
38
+ allowedTransactions?: readonly string[] | undefined;
39
+ allowedTransactionsComplete?: boolean | undefined;
40
+ dataStatus?: AccountDataStatus | undefined;
41
+ }
42
+ /**
43
+ * A bank account as reported by the user parameter data or the SEPA account query.
44
+ *
45
+ * An account the app builds itself, such as from a stored IBAN, stands for the one of `getAccounts` it `matches`:
46
+ * queries take the details the bank states of that one, and the transactions the bank permits for it. One the bank
47
+ * names nowhere goes out with its account number, sub-account, IBAN, BIC, bank and country code and currency only, and
48
+ * is refused with `FinTsUnsupportedError` where the bank's lists of permitted transactions are complete. Queries never
49
+ * take the permitted transactions from the app's account.
50
+ */
51
+ export declare class Account {
52
+ /** National account number. */
53
+ readonly accountNumber: string | undefined;
54
+ /** Sub-account characteristic (Unterkontomerkmal). */
55
+ readonly subAccount: string | undefined;
56
+ /** German bank code (BLZ) of the bank holding the account. */
57
+ readonly bankCode: string;
58
+ /** Numeric country code of the bank, `280` for Germany. */
59
+ readonly countryCode: string;
60
+ /**
61
+ * International bank account number, in its electronic format: without blanks and in capitals, however
62
+ * `AccountInit.iban` wrote it, such as in groups of four as printed.
63
+ */
64
+ readonly iban: string | undefined;
65
+ /** Bank identifier code of the bank holding the account, without blanks and in capitals. */
66
+ readonly bic: string | undefined;
67
+ /** Customer ID the account is assigned to; may differ from the login name. */
68
+ readonly customerId: string | undefined;
69
+ /** Currency of the account, for example `EUR`. */
70
+ readonly currency: string | undefined;
71
+ /** Name of the account holder. */
72
+ readonly ownerName: string | undefined;
73
+ /** The bank's name for the account, for example `Girokonto`. */
74
+ readonly productName: string | undefined;
75
+ /** Raw FinTS account type (1–99); see `category`. */
76
+ readonly typeCode: number | undefined;
77
+ /**
78
+ * The transactions the bank lists as permitted for this account, by their segment IDs, such as `HKSAL`.
79
+ *
80
+ * The client applies them itself: `getBalance` and `getTransactions` do not send a query they rule out, and fail with
81
+ * `FinTsUnsupportedError`.
82
+ */
83
+ readonly allowedTransactions: readonly string[];
84
+ /**
85
+ * Whether `allowedTransactions` is complete: the bank permits nothing it does not list (FinTS "UPD-Verwendung" 0).
86
+ * Otherwise the bank's lists say nothing about a transaction they leave out, and only the bank can tell.
87
+ */
88
+ readonly allowedTransactionsComplete: boolean;
89
+ /** What the bank tells about the data it holds for the account, where it does. */
90
+ readonly dataStatus: AccountDataStatus | undefined;
91
+ /** Takes copies of the permitted transactions and the data status of `init`, which no other account shares. */
92
+ constructor(init: AccountInit);
93
+ /** The kind of account, derived from `typeCode`. */
94
+ get category(): AccountCategory;
95
+ /**
96
+ * Whether `other` is the same account: by IBAN when both have one, otherwise by account number, sub-account and
97
+ * bank.
98
+ *
99
+ * Account numbers are compared without leading zeros, since banks pad them differently. An empty bank or country
100
+ * code, as of a balance record without bank identification, matches any.
101
+ */
102
+ matches(other: Account): boolean;
103
+ /** This account with the given details replaced; a detail that is `undefined` stays as it is. */
104
+ copyWith(changes: Omit<Partial<AccountInit>, 'bankCode' | 'countryCode'>): Account;
105
+ /**
106
+ * The product name and the last digits of the IBAN or account number only, so that logs and crash reports do not
107
+ * collect account data.
108
+ */
109
+ toString(): string;
110
+ }
111
+ /**
112
+ * Accounts by IBAN and by national account, to find the first one an account `matches` without comparing it with each:
113
+ * a bank may list tens of thousands.
114
+ *
115
+ * Bank and country codes count as they are, where `matches` takes an empty one for any: the accounts a bank lists state
116
+ * both.
117
+ */
118
+ export declare class AccountIndex {
119
+ private readonly accounts;
120
+ private readonly byIban;
121
+ private readonly byNational;
122
+ /** Those without IBAN only: an account with IBAN matches one with IBAN by that alone. */
123
+ private readonly byNationalWithoutIban;
124
+ constructor(accounts: readonly Account[]);
125
+ /** The first of the accounts that `account` matches. */
126
+ find(account: Account): Account | undefined;
127
+ }
128
+ /**
129
+ * What the bank tells about the data it holds for an account, so that an app asks only for what has changed (FinTS 3.0
130
+ * user parameter data, "Erweiterung, kontobezogen", Formals E.3.1 and F).
131
+ *
132
+ * The rules are binding for an app that stores transactions; banks may refuse an app that ignores them:
133
+ * - Do not fetch the transactions again while the bank names the ID they were stored with (`mt940TransactionsId` or
134
+ * `camtTransactionsId`, for the format the app asked for, so pass `format` to `getTransactions` explicitly), or, in
135
+ * the older format, the timestamp `lastTransactions`.
136
+ * - Do not fetch them before `nextTransactionsAt`.
137
+ * - Do not ask for the balance separately where `transactionBalancesCurrent` says that the transactions carry the
138
+ * current one.
139
+ */
140
+ export declare class AccountDataStatus {
141
+ /**
142
+ * IDs of the data the bank holds for the user, keyed by the segment ID of the query that fetches them, for example
143
+ * `HKKAZ` (transactions as MT940) or `HKCAZ` (as camt): the data have changed when the ID changes. An empty ID means
144
+ * that the user has no such data; a query the map leaves out, that the bank tells nothing about it.
145
+ */
146
+ readonly inventory: ReadonlyMap<string, string>;
147
+ /**
148
+ * The timestamp of the last transactions the bank provided, in the older format of the extension (`umsltzt`);
149
+ * compared like an ID in `inventory`.
150
+ */
151
+ readonly lastTransactions: string | undefined;
152
+ /** The moment before which the bank provides no new transactions. */
153
+ readonly nextTransactionsAt: Date | undefined;
154
+ /** Whether the balances the transactions carry are the current ones. */
155
+ readonly transactionBalancesCurrent: boolean;
156
+ /** Takes copies of the inventory and the date of `init`, which no other status shares. */
157
+ constructor(init: {
158
+ inventory?: ReadonlyMap<string, string>;
159
+ lastTransactions?: string | undefined;
160
+ nextTransactionsAt?: Date | undefined;
161
+ transactionBalancesCurrent?: boolean;
162
+ });
163
+ /** The ID of the transactions the bank holds as MT940, its entry for `HKKAZ` in `inventory`. */
164
+ get mt940TransactionsId(): string | undefined;
165
+ /** The ID of the transactions the bank holds as camt, its entry for `HKCAZ` in `inventory`. */
166
+ get camtTransactionsId(): string | undefined;
167
+ }
168
+ //# sourceMappingURL=account.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.d.ts","sourceRoot":"","sources":["../../src/core/account.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,245 @@
1
+ import { copyDate } from '../util/dates.js';
2
+ import { ImmutableMap } from '../util/immutable-map.js';
3
+ import { maskedId, nonBlank } from '../util/text.js';
4
+ import { defaultCountryCode } from './config.js';
5
+ const categoriesByTens = [
6
+ 'checking',
7
+ 'savings',
8
+ 'fixedDeposit',
9
+ 'securities',
10
+ 'loan',
11
+ 'creditCard',
12
+ 'fund',
13
+ 'homeSavings',
14
+ 'insurance',
15
+ ];
16
+ /** The category of the FinTS account type `code`, which is `undefined` if the bank states none. */
17
+ function accountCategoryOf(code) {
18
+ if (code === undefined || code < 1)
19
+ return 'unknown';
20
+ return categoriesByTens[Math.floor(code / 10)] ?? 'other';
21
+ }
22
+ /**
23
+ * A bank account as reported by the user parameter data or the SEPA account query.
24
+ *
25
+ * An account the app builds itself, such as from a stored IBAN, stands for the one of `getAccounts` it `matches`:
26
+ * queries take the details the bank states of that one, and the transactions the bank permits for it. One the bank
27
+ * names nowhere goes out with its account number, sub-account, IBAN, BIC, bank and country code and currency only, and
28
+ * is refused with `FinTsUnsupportedError` where the bank's lists of permitted transactions are complete. Queries never
29
+ * take the permitted transactions from the app's account.
30
+ */
31
+ export class Account {
32
+ /** National account number. */
33
+ accountNumber;
34
+ /** Sub-account characteristic (Unterkontomerkmal). */
35
+ subAccount;
36
+ /** German bank code (BLZ) of the bank holding the account. */
37
+ bankCode;
38
+ /** Numeric country code of the bank, `280` for Germany. */
39
+ countryCode;
40
+ /**
41
+ * International bank account number, in its electronic format: without blanks and in capitals, however
42
+ * `AccountInit.iban` wrote it, such as in groups of four as printed.
43
+ */
44
+ iban;
45
+ /** Bank identifier code of the bank holding the account, without blanks and in capitals. */
46
+ bic;
47
+ /** Customer ID the account is assigned to; may differ from the login name. */
48
+ customerId;
49
+ /** Currency of the account, for example `EUR`. */
50
+ currency;
51
+ /** Name of the account holder. */
52
+ ownerName;
53
+ /** The bank's name for the account, for example `Girokonto`. */
54
+ productName;
55
+ /** Raw FinTS account type (1–99); see `category`. */
56
+ typeCode;
57
+ /**
58
+ * The transactions the bank lists as permitted for this account, by their segment IDs, such as `HKSAL`.
59
+ *
60
+ * The client applies them itself: `getBalance` and `getTransactions` do not send a query they rule out, and fail with
61
+ * `FinTsUnsupportedError`.
62
+ */
63
+ allowedTransactions;
64
+ /**
65
+ * Whether `allowedTransactions` is complete: the bank permits nothing it does not list (FinTS "UPD-Verwendung" 0).
66
+ * Otherwise the bank's lists say nothing about a transaction they leave out, and only the bank can tell.
67
+ */
68
+ allowedTransactionsComplete;
69
+ /** What the bank tells about the data it holds for the account, where it does. */
70
+ dataStatus;
71
+ /** Takes copies of the permitted transactions and the data status of `init`, which no other account shares. */
72
+ constructor(init) {
73
+ this.accountNumber = init.accountNumber;
74
+ this.subAccount = init.subAccount;
75
+ this.bankCode = init.bankCode;
76
+ this.countryCode = init.countryCode ?? defaultCountryCode;
77
+ this.iban = electronicFormat(init.iban);
78
+ this.bic = electronicFormat(init.bic);
79
+ this.customerId = init.customerId;
80
+ this.currency = init.currency;
81
+ this.ownerName = init.ownerName;
82
+ this.productName = init.productName;
83
+ this.typeCode = init.typeCode;
84
+ this.allowedTransactions = Object.freeze([...(init.allowedTransactions ?? [])]);
85
+ this.allowedTransactionsComplete = init.allowedTransactionsComplete ?? false;
86
+ this.dataStatus = init.dataStatus && new AccountDataStatus(init.dataStatus);
87
+ }
88
+ /** The kind of account, derived from `typeCode`. */
89
+ get category() {
90
+ return accountCategoryOf(this.typeCode);
91
+ }
92
+ /**
93
+ * Whether `other` is the same account: by IBAN when both have one, otherwise by account number, sub-account and
94
+ * bank.
95
+ *
96
+ * Account numbers are compared without leading zeros, since banks pad them differently. An empty bank or country
97
+ * code, as of a balance record without bank identification, matches any.
98
+ */
99
+ matches(other) {
100
+ if (this.iban !== undefined && other.iban !== undefined)
101
+ return this.iban === other.iban;
102
+ const number = nationalNumber(this);
103
+ return (number !== undefined &&
104
+ number === nationalNumber(other) &&
105
+ (this.subAccount ?? '') === (other.subAccount ?? '') &&
106
+ sameOrUnstated(this.bankCode, other.bankCode) &&
107
+ sameOrUnstated(this.countryCode, other.countryCode));
108
+ }
109
+ /** This account with the given details replaced; a detail that is `undefined` stays as it is. */
110
+ copyWith(changes) {
111
+ return new Account({
112
+ accountNumber: changes.accountNumber ?? this.accountNumber,
113
+ subAccount: changes.subAccount ?? this.subAccount,
114
+ bankCode: this.bankCode,
115
+ countryCode: this.countryCode,
116
+ iban: changes.iban ?? this.iban,
117
+ bic: changes.bic ?? this.bic,
118
+ customerId: changes.customerId ?? this.customerId,
119
+ currency: changes.currency ?? this.currency,
120
+ ownerName: changes.ownerName ?? this.ownerName,
121
+ productName: changes.productName ?? this.productName,
122
+ typeCode: changes.typeCode ?? this.typeCode,
123
+ allowedTransactions: changes.allowedTransactions ?? this.allowedTransactions,
124
+ allowedTransactionsComplete: changes.allowedTransactionsComplete ?? this.allowedTransactionsComplete,
125
+ dataStatus: changes.dataStatus ?? this.dataStatus,
126
+ });
127
+ }
128
+ /**
129
+ * The product name and the last digits of the IBAN or account number only, so that logs and crash reports do not
130
+ * collect account data.
131
+ */
132
+ toString() {
133
+ const id = this.iban ?? this.accountNumber;
134
+ const parts = [
135
+ ...(id === undefined ? [] : [maskedId(id)]),
136
+ ...(this.productName === undefined ? [] : [this.productName]),
137
+ ];
138
+ return `Account(${parts.join(', ')})`;
139
+ }
140
+ }
141
+ /**
142
+ * An IBAN or BIC in the form the bank sends and compares, without blanks and in capitals; `undefined` for blanks only.
143
+ */
144
+ function electronicFormat(code) {
145
+ return nonBlank(code?.replace(/\s/g, '').toUpperCase());
146
+ }
147
+ function sameOrUnstated(a, b) {
148
+ return a === '' || b === '' || a === b;
149
+ }
150
+ /** The account number as `Account.matches` compares it: without leading zeros. */
151
+ function nationalNumber(account) {
152
+ return account.accountNumber?.replace(/^0+/, '');
153
+ }
154
+ /**
155
+ * Accounts by IBAN and by national account, to find the first one an account `matches` without comparing it with each:
156
+ * a bank may list tens of thousands.
157
+ *
158
+ * Bank and country codes count as they are, where `matches` takes an empty one for any: the accounts a bank lists state
159
+ * both.
160
+ */
161
+ export class AccountIndex {
162
+ accounts;
163
+ byIban = new Map();
164
+ byNational = new Map();
165
+ /** Those without IBAN only: an account with IBAN matches one with IBAN by that alone. */
166
+ byNationalWithoutIban = new Map();
167
+ constructor(accounts) {
168
+ this.accounts = accounts;
169
+ accounts.forEach((account, i) => {
170
+ const national = nationalKey(account);
171
+ if (account.iban !== undefined)
172
+ keepFirst(this.byIban, account.iban, i);
173
+ if (national === undefined)
174
+ return;
175
+ keepFirst(this.byNational, national, i);
176
+ if (account.iban === undefined)
177
+ keepFirst(this.byNationalWithoutIban, national, i);
178
+ });
179
+ }
180
+ /** The first of the accounts that `account` matches. */
181
+ find(account) {
182
+ const national = nationalKey(account);
183
+ const byNational = account.iban === undefined ? this.byNational : this.byNationalWithoutIban;
184
+ const found = [
185
+ account.iban === undefined ? undefined : this.byIban.get(account.iban),
186
+ national === undefined ? undefined : byNational.get(national),
187
+ ].filter((i) => i !== undefined);
188
+ return found.length === 0 ? undefined : this.accounts[Math.min(...found)];
189
+ }
190
+ }
191
+ function nationalKey(account) {
192
+ const number = nationalNumber(account);
193
+ return number === undefined
194
+ ? undefined
195
+ : JSON.stringify([number, account.subAccount ?? '', account.bankCode, account.countryCode]);
196
+ }
197
+ function keepFirst(index, key, position) {
198
+ if (!index.has(key))
199
+ index.set(key, position);
200
+ }
201
+ /**
202
+ * What the bank tells about the data it holds for an account, so that an app asks only for what has changed (FinTS 3.0
203
+ * user parameter data, "Erweiterung, kontobezogen", Formals E.3.1 and F).
204
+ *
205
+ * The rules are binding for an app that stores transactions; banks may refuse an app that ignores them:
206
+ * - Do not fetch the transactions again while the bank names the ID they were stored with (`mt940TransactionsId` or
207
+ * `camtTransactionsId`, for the format the app asked for, so pass `format` to `getTransactions` explicitly), or, in
208
+ * the older format, the timestamp `lastTransactions`.
209
+ * - Do not fetch them before `nextTransactionsAt`.
210
+ * - Do not ask for the balance separately where `transactionBalancesCurrent` says that the transactions carry the
211
+ * current one.
212
+ */
213
+ export class AccountDataStatus {
214
+ /**
215
+ * IDs of the data the bank holds for the user, keyed by the segment ID of the query that fetches them, for example
216
+ * `HKKAZ` (transactions as MT940) or `HKCAZ` (as camt): the data have changed when the ID changes. An empty ID means
217
+ * that the user has no such data; a query the map leaves out, that the bank tells nothing about it.
218
+ */
219
+ inventory;
220
+ /**
221
+ * The timestamp of the last transactions the bank provided, in the older format of the extension (`umsltzt`);
222
+ * compared like an ID in `inventory`.
223
+ */
224
+ lastTransactions;
225
+ /** The moment before which the bank provides no new transactions. */
226
+ nextTransactionsAt;
227
+ /** Whether the balances the transactions carry are the current ones. */
228
+ transactionBalancesCurrent;
229
+ /** Takes copies of the inventory and the date of `init`, which no other status shares. */
230
+ constructor(init) {
231
+ this.inventory = new ImmutableMap(init.inventory ?? []);
232
+ this.lastTransactions = init.lastTransactions;
233
+ this.nextTransactionsAt = copyDate(init.nextTransactionsAt);
234
+ this.transactionBalancesCurrent = init.transactionBalancesCurrent ?? false;
235
+ }
236
+ /** The ID of the transactions the bank holds as MT940, its entry for `HKKAZ` in `inventory`. */
237
+ get mt940TransactionsId() {
238
+ return this.inventory.get('HKKAZ');
239
+ }
240
+ /** The ID of the transactions the bank holds as camt, its entry for `HKCAZ` in `inventory`. */
241
+ get camtTransactionsId() {
242
+ return this.inventory.get('HKCAZ');
243
+ }
244
+ }
245
+ //# sourceMappingURL=account.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account.js","sourceRoot":"","sources":["../../src/core/account.ts"],"names":[],"mappings":"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"}