@develit-services/bank 5.0.1 → 5.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.
@@ -1239,264 +1239,6 @@ class CsobConnector extends FinbricksConnector {
1239
1239
  }
1240
1240
  }
1241
1241
 
1242
- class AirBankConnector extends FinbricksConnector {
1243
- constructor(config) {
1244
- super("AIRBANK", config);
1245
- }
1246
- supportsBatch() {
1247
- return false;
1248
- }
1249
- }
1250
-
1251
- class CreditasConnector extends FinbricksConnector {
1252
- constructor(config) {
1253
- super("CREDITAS", config);
1254
- }
1255
- /**
1256
- * Creditas bank doesn't support batch payments at all.
1257
- */
1258
- supportsBatch() {
1259
- return false;
1260
- }
1261
- }
1262
-
1263
- class CSASConnector extends FinbricksConnector {
1264
- constructor(config) {
1265
- super("CSAS", config);
1266
- }
1267
- supportsBatch(paymentType) {
1268
- return paymentType === "DOMESTIC";
1269
- }
1270
- }
1271
-
1272
- class FioConnector extends FinbricksConnector {
1273
- constructor(config) {
1274
- super("FIO", config);
1275
- }
1276
- /**
1277
- * FIO supports batch only for DOMESTIC (CZK) payments.
1278
- * SEPA and SWIFT batch support is planned by Finbricks.
1279
- */
1280
- supportsBatch(paymentType) {
1281
- return paymentType === "DOMESTIC";
1282
- }
1283
- }
1284
-
1285
- class KBConnector extends FinbricksConnector {
1286
- constructor(config) {
1287
- super("KB", config);
1288
- }
1289
- supportsBatch(paymentType) {
1290
- return paymentType === "DOMESTIC";
1291
- }
1292
- }
1293
-
1294
- class MonetaConnector extends FinbricksConnector {
1295
- constructor(config) {
1296
- super("MONETA", config);
1297
- }
1298
- /**
1299
- * MONETA supports batch only for DOMESTIC (CZK) payments.
1300
- * SEPA and SWIFT batch support is planned by Finbricks.
1301
- */
1302
- supportsBatch(paymentType) {
1303
- return paymentType === "DOMESTIC";
1304
- }
1305
- /**
1306
- * MONETA rejects all special characters in endToEndIdentification.
1307
- * Boundaries between segments are unambiguous without a separator —
1308
- * `VS`/`SS`/`KS` prefixes are alphabetic and values are always numeric,
1309
- * so the parsing regex `VS[:\s]*(\d+)` extracts each value correctly.
1310
- *
1311
- * Format: `VS1234SS5678KS0308` (max 30 chars).
1312
- * Confirmed by Finbricks support (2026-04-23).
1313
- */
1314
- buildEndToEndId(payment) {
1315
- return buildEndToEndId(payment, { separator: "" });
1316
- }
1317
- }
1318
-
1319
- const isDeposit = (payment, creditorIban) => {
1320
- return payment.creditor.iban === creditorIban;
1321
- };
1322
- const getPaymentDirection = (payment, iban) => {
1323
- if (isDeposit(payment, iban)) return "INCOMING";
1324
- return "OUTGOING";
1325
- };
1326
-
1327
- const initiateConnector = async ({
1328
- bank,
1329
- env,
1330
- connectedAccounts,
1331
- resolveCredentials
1332
- }) => {
1333
- switch (bank) {
1334
- case "ERSTE":
1335
- return new ErsteConnector({
1336
- API_KEY: (await env.SECRETS_STORE.get({
1337
- secretName: "BANK_SERVICE_ERSTE_API_KEY"
1338
- })).data?.secretValue || "",
1339
- CLIENT_ID: (await env.SECRETS_STORE.get({
1340
- secretName: "BANK_SERVICE_ERSTE_CLIENT_ID"
1341
- })).data?.secretValue || "",
1342
- CLIENT_SECRET: (await env.SECRETS_STORE.get({
1343
- secretName: "BANK_SERVICE_ERSTE_CLIENT_SECRET"
1344
- })).data?.secretValue || "",
1345
- REDIRECT_URI: env.REDIRECT_URI,
1346
- AUTH_URI: env.ERSTE_AUTH_URI,
1347
- PAYMENTS_URI: env.ERSTE_PAYMENTS_URI,
1348
- ACCOUNTS_URI: env.ERSTE_ACCOUNTS_URI,
1349
- connectedAccounts,
1350
- resolveCredentials
1351
- });
1352
- case "CREDITAS":
1353
- return new CreditasConnector({
1354
- BASE_URI: env.FINBRICKS_BASE_URI,
1355
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1356
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1357
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1358
- })).data?.secretValue || "",
1359
- REDIRECT_URI: env.REDIRECT_URI,
1360
- connectedAccounts,
1361
- resolveCredentials
1362
- });
1363
- case "MOCK_COBS":
1364
- return new MockCobsConnector({
1365
- BASE_URI: env.FINBRICKS_BASE_URI,
1366
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1367
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1368
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1369
- })).data?.secretValue || "",
1370
- REDIRECT_URI: env.REDIRECT_URI,
1371
- connectedAccounts,
1372
- resolveCredentials
1373
- });
1374
- case "FIO":
1375
- return new FioConnector({
1376
- BASE_URI: env.FINBRICKS_BASE_URI,
1377
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1378
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1379
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1380
- })).data?.secretValue || "",
1381
- REDIRECT_URI: env.REDIRECT_URI,
1382
- connectedAccounts,
1383
- resolveCredentials
1384
- });
1385
- case "MONETA":
1386
- return new MonetaConnector({
1387
- BASE_URI: env.FINBRICKS_BASE_URI,
1388
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1389
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1390
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1391
- })).data?.secretValue || "",
1392
- REDIRECT_URI: env.REDIRECT_URI,
1393
- connectedAccounts,
1394
- resolveCredentials
1395
- });
1396
- case "AIRBANK":
1397
- return new AirBankConnector({
1398
- BASE_URI: env.FINBRICKS_BASE_URI,
1399
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1400
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1401
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1402
- })).data?.secretValue || "",
1403
- REDIRECT_URI: env.REDIRECT_URI,
1404
- connectedAccounts,
1405
- resolveCredentials
1406
- });
1407
- case "CSAS":
1408
- return new CSASConnector({
1409
- BASE_URI: env.FINBRICKS_BASE_URI,
1410
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1411
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1412
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1413
- })).data?.secretValue || "",
1414
- REDIRECT_URI: env.REDIRECT_URI,
1415
- connectedAccounts,
1416
- resolveCredentials
1417
- });
1418
- case "KB":
1419
- return new KBConnector({
1420
- BASE_URI: env.FINBRICKS_BASE_URI,
1421
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1422
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1423
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1424
- })).data?.secretValue || "",
1425
- REDIRECT_URI: env.REDIRECT_URI,
1426
- connectedAccounts,
1427
- resolveCredentials
1428
- });
1429
- case "CSOB":
1430
- return new CsobConnector({
1431
- BASE_URI: env.FINBRICKS_BASE_URI,
1432
- MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
1433
- PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
1434
- secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
1435
- })).data?.secretValue || "",
1436
- REDIRECT_URI: env.REDIRECT_URI,
1437
- connectedAccounts,
1438
- resolveCredentials
1439
- });
1440
- case "DBU":
1441
- return new DbuConnector({
1442
- BASE_URL: env.DBUCS_BASE_URI,
1443
- USERNAME: env.DBUCS_USERNAME,
1444
- APPLICATION_CODE: env.DBUCS_APPLICATION_CODE,
1445
- KV: env.BANK_KV,
1446
- API: env.DBU_CBS_BACKOFFICE_DEV,
1447
- REDIRECT_URI: env.REDIRECT_URI,
1448
- TX_AUTH_URI: env.DBUCS_TX_AUTH_URI,
1449
- connectedAccounts
1450
- });
1451
- default:
1452
- const mockConnector = new MockConnector();
1453
- mockConnector.connectedAccounts = connectedAccounts;
1454
- return mockConnector;
1455
- }
1456
- };
1457
- function mod97(string) {
1458
- let checksum = string.slice(0, 2);
1459
- let fragment = "";
1460
- for (let offset = 2; offset < string.length; offset += 7) {
1461
- fragment = checksum + string.substring(offset, offset + 7);
1462
- checksum = (parseInt(fragment, 10) % 97).toString();
1463
- }
1464
- return parseInt(checksum, 10);
1465
- }
1466
- const parseCzechIban = (iban) => {
1467
- const stripped = iban.replace(/\s/g, "").toUpperCase();
1468
- if (!stripped.startsWith("CZ") || stripped.length !== 24) {
1469
- throw new Error(`Invalid Czech IBAN: ${iban}`);
1470
- }
1471
- const bankCode = stripped.slice(4, 8);
1472
- const prefix = stripped.slice(8, 14).replace(/^0+/, "");
1473
- const main = stripped.slice(14, 24).replace(/^0+/, "");
1474
- const accountNumber = prefix ? `${prefix}-${main}` : main;
1475
- return { bankCode, accountNumber };
1476
- };
1477
- const calculateCzechIban = (accountNumber, bankCode) => {
1478
- const paddedBankCode = bankCode.padStart(4, "0");
1479
- let prefix = "";
1480
- let mainAccount = accountNumber;
1481
- if (accountNumber.includes("-")) {
1482
- const parts = accountNumber.split("-");
1483
- if (parts.length !== 2) {
1484
- throw new Error(
1485
- `Invalid account number format: expected "prefix-main" or "main", got "${accountNumber}"`
1486
- );
1487
- }
1488
- prefix = parts[0];
1489
- mainAccount = parts[1];
1490
- }
1491
- const paddedPrefix = prefix.padStart(6, "0");
1492
- const paddedAccount = mainAccount.padStart(10, "0");
1493
- const basicIban = paddedBankCode + paddedPrefix + paddedAccount;
1494
- const rearranged = basicIban + "123500";
1495
- const remainder = mod97(rearranged);
1496
- const checkDigits = (98 - remainder).toString().padStart(2, "0");
1497
- return `CZ${checkDigits}${basicIban}`;
1498
- };
1499
-
1500
1242
  const dbuAccountConfigSchema = zod.z.object({
1501
1243
  with4EyeApproval: zod.z.enum(["Y", "N"]).default("Y"),
1502
1244
  realizeImmediate: zod.z.enum(["Y", "N"]).default("Y"),
@@ -1543,80 +1285,119 @@ class DbuConnector extends IBankConnector {
1543
1285
  }
1544
1286
  async makeRequest(endpoint, requestId, options = {}) {
1545
1287
  const { method = "GET", headers = {}, query = {}, body } = options;
1546
- if (method === "POST" && !this.allowedPostEndpoints.includes(endpoint)) {
1547
- throw backendSdk.createInternalError(null, {
1548
- message: `DBU API endpoint ${endpoint} does not support POST method`,
1549
- code: "DBU_INVALID_METHOD"
1288
+ let url;
1289
+ let response;
1290
+ try {
1291
+ if (method === "POST" && !this.allowedPostEndpoints.includes(endpoint)) {
1292
+ throw backendSdk.createInternalError(null, {
1293
+ message: `DBU API endpoint ${endpoint} does not support POST method`,
1294
+ code: "DBU_INVALID_METHOD"
1295
+ });
1296
+ }
1297
+ const defaultHeaders = {
1298
+ "x-dcs-username": this.username,
1299
+ "x-dcs-session-id": `session-${this.sessionId}`,
1300
+ "x-dcs-request-id": `request-${requestId}`,
1301
+ "Content-Type": "application/json",
1302
+ ...headers
1303
+ };
1304
+ const baseUrl = this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl;
1305
+ const cleanEndpoint = endpoint.startsWith("/") ? endpoint.slice(1) : endpoint;
1306
+ url = new URL(`${baseUrl}/${cleanEndpoint}`);
1307
+ Object.entries(query).forEach(([key, value]) => {
1308
+ if (value !== void 0 && value !== null) {
1309
+ url.searchParams.append(key, value);
1310
+ }
1550
1311
  });
1551
- }
1552
- const defaultHeaders = {
1553
- "x-dcs-username": this.username,
1554
- "x-dcs-session-id": `session-${this.sessionId}`,
1555
- "x-dcs-request-id": `request-${requestId}`,
1556
- "Content-Type": "application/json",
1557
- ...headers
1558
- };
1559
- const baseUrl = this.baseUrl.endsWith("/") ? this.baseUrl.slice(0, -1) : this.baseUrl;
1560
- const cleanEndpoint = endpoint.startsWith("/") ? endpoint.slice(1) : endpoint;
1561
- const url = new URL(`${baseUrl}/${cleanEndpoint}`);
1562
- Object.entries(query).forEach(([key, value]) => {
1563
- if (value !== void 0 && value !== null) {
1564
- url.searchParams.append(key, value);
1312
+ const fetchOptions = {
1313
+ method,
1314
+ headers: defaultHeaders
1315
+ };
1316
+ if (body && method !== "GET") {
1317
+ fetchOptions.body = JSON.stringify(body);
1565
1318
  }
1566
- });
1567
- const fetchOptions = {
1568
- method,
1569
- headers: defaultHeaders
1570
- };
1571
- if (body && method !== "GET") {
1572
- fetchOptions.body = JSON.stringify(body);
1573
- }
1574
- console.log(
1575
- "[DBU] request",
1576
- JSON.stringify(
1577
- {
1578
- method,
1319
+ console.log(
1320
+ "[DBU] request",
1321
+ JSON.stringify(
1322
+ {
1323
+ method,
1324
+ url: url.toString(),
1325
+ requestId,
1326
+ headers: defaultHeaders,
1327
+ body: body ?? null
1328
+ },
1329
+ null,
1330
+ 2
1331
+ )
1332
+ );
1333
+ response = await this.api.fetch(url.toString(), fetchOptions);
1334
+ const responseText = await response.text().catch(() => "unable to read response");
1335
+ if (!response.ok) {
1336
+ let parsedBody = responseText;
1337
+ try {
1338
+ parsedBody = JSON.parse(responseText);
1339
+ } catch {
1340
+ }
1341
+ console.error("[DBU] error response", {
1342
+ status: response.status,
1343
+ statusText: response.statusText,
1579
1344
  url: url.toString(),
1580
1345
  requestId,
1581
- headers: defaultHeaders,
1582
- body: body ?? null
1583
- },
1584
- null,
1585
- 2
1586
- )
1587
- );
1588
- const response = await this.api.fetch(url.toString(), fetchOptions);
1589
- if (!response.ok) {
1590
- const errorBody = await response.text().catch(() => "unable to read body");
1591
- console.error("[DBU] error response", {
1592
- status: response.status,
1593
- statusText: response.statusText,
1594
- url: url.toString(),
1346
+ body: parsedBody
1347
+ });
1348
+ const errorMessage = typeof parsedBody === "string" ? parsedBody : JSON.stringify(parsedBody);
1349
+ throw backendSdk.createInternalError(
1350
+ new Error(`DBU API error: ${response.status}`),
1351
+ {
1352
+ message: `DBU request failed [${response.status}]: ${errorMessage}`
1353
+ }
1354
+ );
1355
+ }
1356
+ let data;
1357
+ try {
1358
+ data = JSON.parse(responseText);
1359
+ } catch (parseError) {
1360
+ console.error("[DBU] JSON parse error", {
1361
+ url: url.toString(),
1362
+ requestId,
1363
+ status: response.status,
1364
+ responseTextPreview: responseText.substring(0, 500),
1365
+ parseError: parseError instanceof Error ? parseError.message : String(parseError)
1366
+ });
1367
+ throw backendSdk.createInternalError(parseError, {
1368
+ message: "Failed to parse DBU response as JSON"
1369
+ });
1370
+ }
1371
+ console.log(
1372
+ "[DBU] response",
1373
+ JSON.stringify(
1374
+ {
1375
+ status: response.status,
1376
+ url: url.toString(),
1377
+ requestId,
1378
+ body: data
1379
+ },
1380
+ null,
1381
+ 2
1382
+ )
1383
+ );
1384
+ return data;
1385
+ } catch (error) {
1386
+ console.error("[DBU] makeRequest failed", {
1387
+ endpoint,
1595
1388
  requestId,
1596
- body: errorBody
1597
- });
1598
- throw backendSdk.createInternalError(
1599
- new Error(`DBU API error: ${response.status}`),
1600
- {
1601
- message: `DBU request failed [${response.status}]: ${errorBody}`
1389
+ method,
1390
+ url: url?.toString(),
1391
+ responseStatus: response?.status,
1392
+ responseStatusText: response?.statusText,
1393
+ error: {
1394
+ message: error instanceof Error ? error.message : String(error),
1395
+ name: error instanceof Error ? error.name : "Unknown",
1396
+ stack: error instanceof Error ? error.stack : void 0
1602
1397
  }
1603
- );
1398
+ });
1399
+ throw error;
1604
1400
  }
1605
- const data = await response.json();
1606
- console.log(
1607
- "[DBU] response",
1608
- JSON.stringify(
1609
- {
1610
- status: response.status,
1611
- url: url.toString(),
1612
- requestId,
1613
- body: data
1614
- },
1615
- null,
1616
- 2
1617
- )
1618
- );
1619
- return data;
1620
1401
  }
1621
1402
  mapDbuCurrencyCode(dbuCurrency) {
1622
1403
  const currency = dbuCurrency.toUpperCase();
@@ -2404,10 +2185,19 @@ class ErsteConnector extends IBankConnector {
2404
2185
  async getPaymentStatus(_) {
2405
2186
  throw new Error("Erste connector: getPaymentStatus not implemented");
2406
2187
  }
2407
- parseAuthorizationCallback(_callbackUrl) {
2408
- throw new Error(
2409
- "Erste connector: parseAuthorizationCallback not implemented"
2410
- );
2188
+ parseAuthorizationCallback(_callbackUrl) {
2189
+ throw new Error(
2190
+ "Erste connector: parseAuthorizationCallback not implemented"
2191
+ );
2192
+ }
2193
+ }
2194
+
2195
+ class KBConnector extends FinbricksConnector {
2196
+ constructor(config) {
2197
+ super("KB", config);
2198
+ }
2199
+ supportsBatch(paymentType) {
2200
+ return paymentType === "DOMESTIC";
2411
2201
  }
2412
2202
  }
2413
2203
 
@@ -2518,6 +2308,255 @@ const ottInsertSchema = zod$1.createInsertSchema(database_schema.ott);
2518
2308
  const ottUpdateSchema = zod$1.createUpdateSchema(database_schema.ott);
2519
2309
  const ottSelectSchema = zod$1.createSelectSchema(database_schema.ott);
2520
2310
 
2311
+ class AirBankConnector extends FinbricksConnector {
2312
+ constructor(config) {
2313
+ super("AIRBANK", config);
2314
+ }
2315
+ supportsBatch() {
2316
+ return false;
2317
+ }
2318
+ }
2319
+
2320
+ class CreditasConnector extends FinbricksConnector {
2321
+ constructor(config) {
2322
+ super("CREDITAS", config);
2323
+ }
2324
+ /**
2325
+ * Creditas bank doesn't support batch payments at all.
2326
+ */
2327
+ supportsBatch() {
2328
+ return false;
2329
+ }
2330
+ }
2331
+
2332
+ class CSASConnector extends FinbricksConnector {
2333
+ constructor(config) {
2334
+ super("CSAS", config);
2335
+ }
2336
+ supportsBatch(paymentType) {
2337
+ return paymentType === "DOMESTIC";
2338
+ }
2339
+ }
2340
+
2341
+ class FioConnector extends FinbricksConnector {
2342
+ constructor(config) {
2343
+ super("FIO", config);
2344
+ }
2345
+ /**
2346
+ * FIO supports batch only for DOMESTIC (CZK) payments.
2347
+ * SEPA and SWIFT batch support is planned by Finbricks.
2348
+ */
2349
+ supportsBatch(paymentType) {
2350
+ return paymentType === "DOMESTIC";
2351
+ }
2352
+ }
2353
+
2354
+ class MonetaConnector extends FinbricksConnector {
2355
+ constructor(config) {
2356
+ super("MONETA", config);
2357
+ }
2358
+ /**
2359
+ * MONETA supports batch only for DOMESTIC (CZK) payments.
2360
+ * SEPA and SWIFT batch support is planned by Finbricks.
2361
+ */
2362
+ supportsBatch(paymentType) {
2363
+ return paymentType === "DOMESTIC";
2364
+ }
2365
+ /**
2366
+ * MONETA rejects all special characters in endToEndIdentification.
2367
+ * Boundaries between segments are unambiguous without a separator —
2368
+ * `VS`/`SS`/`KS` prefixes are alphabetic and values are always numeric,
2369
+ * so the parsing regex `VS[:\s]*(\d+)` extracts each value correctly.
2370
+ *
2371
+ * Format: `VS1234SS5678KS0308` (max 30 chars).
2372
+ * Confirmed by Finbricks support (2026-04-23).
2373
+ */
2374
+ buildEndToEndId(payment) {
2375
+ return buildEndToEndId(payment, { separator: "" });
2376
+ }
2377
+ }
2378
+
2379
+ const isDeposit = (payment, creditorIban) => {
2380
+ return payment.creditor.iban === creditorIban;
2381
+ };
2382
+ const getPaymentDirection = (payment, iban) => {
2383
+ if (isDeposit(payment, iban)) return "INCOMING";
2384
+ return "OUTGOING";
2385
+ };
2386
+
2387
+ const initiateConnector = async ({
2388
+ bank,
2389
+ env,
2390
+ connectedAccounts,
2391
+ resolveCredentials
2392
+ }) => {
2393
+ switch (bank) {
2394
+ case "ERSTE":
2395
+ return new ErsteConnector({
2396
+ API_KEY: (await env.SECRETS_STORE.get({
2397
+ secretName: "BANK_SERVICE_ERSTE_API_KEY"
2398
+ })).data?.secretValue || "",
2399
+ CLIENT_ID: (await env.SECRETS_STORE.get({
2400
+ secretName: "BANK_SERVICE_ERSTE_CLIENT_ID"
2401
+ })).data?.secretValue || "",
2402
+ CLIENT_SECRET: (await env.SECRETS_STORE.get({
2403
+ secretName: "BANK_SERVICE_ERSTE_CLIENT_SECRET"
2404
+ })).data?.secretValue || "",
2405
+ REDIRECT_URI: env.REDIRECT_URI,
2406
+ AUTH_URI: env.ERSTE_AUTH_URI,
2407
+ PAYMENTS_URI: env.ERSTE_PAYMENTS_URI,
2408
+ ACCOUNTS_URI: env.ERSTE_ACCOUNTS_URI,
2409
+ connectedAccounts,
2410
+ resolveCredentials
2411
+ });
2412
+ case "CREDITAS":
2413
+ return new CreditasConnector({
2414
+ BASE_URI: env.FINBRICKS_BASE_URI,
2415
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2416
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2417
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2418
+ })).data?.secretValue || "",
2419
+ REDIRECT_URI: env.REDIRECT_URI,
2420
+ connectedAccounts,
2421
+ resolveCredentials
2422
+ });
2423
+ case "MOCK_COBS":
2424
+ return new MockCobsConnector({
2425
+ BASE_URI: env.FINBRICKS_BASE_URI,
2426
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2427
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2428
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2429
+ })).data?.secretValue || "",
2430
+ REDIRECT_URI: env.REDIRECT_URI,
2431
+ connectedAccounts,
2432
+ resolveCredentials
2433
+ });
2434
+ case "FIO":
2435
+ return new FioConnector({
2436
+ BASE_URI: env.FINBRICKS_BASE_URI,
2437
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2438
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2439
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2440
+ })).data?.secretValue || "",
2441
+ REDIRECT_URI: env.REDIRECT_URI,
2442
+ connectedAccounts,
2443
+ resolveCredentials
2444
+ });
2445
+ case "MONETA":
2446
+ return new MonetaConnector({
2447
+ BASE_URI: env.FINBRICKS_BASE_URI,
2448
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2449
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2450
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2451
+ })).data?.secretValue || "",
2452
+ REDIRECT_URI: env.REDIRECT_URI,
2453
+ connectedAccounts,
2454
+ resolveCredentials
2455
+ });
2456
+ case "AIRBANK":
2457
+ return new AirBankConnector({
2458
+ BASE_URI: env.FINBRICKS_BASE_URI,
2459
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2460
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2461
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2462
+ })).data?.secretValue || "",
2463
+ REDIRECT_URI: env.REDIRECT_URI,
2464
+ connectedAccounts,
2465
+ resolveCredentials
2466
+ });
2467
+ case "CSAS":
2468
+ return new CSASConnector({
2469
+ BASE_URI: env.FINBRICKS_BASE_URI,
2470
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2471
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2472
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2473
+ })).data?.secretValue || "",
2474
+ REDIRECT_URI: env.REDIRECT_URI,
2475
+ connectedAccounts,
2476
+ resolveCredentials
2477
+ });
2478
+ case "KB":
2479
+ return new KBConnector({
2480
+ BASE_URI: env.FINBRICKS_BASE_URI,
2481
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2482
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2483
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2484
+ })).data?.secretValue || "",
2485
+ REDIRECT_URI: env.REDIRECT_URI,
2486
+ connectedAccounts,
2487
+ resolveCredentials
2488
+ });
2489
+ case "CSOB":
2490
+ return new CsobConnector({
2491
+ BASE_URI: env.FINBRICKS_BASE_URI,
2492
+ MERCHANT_ID: env.FINBRICKS_MERCHANT_ID,
2493
+ PRIVATE_KEY_PEM: (await env.SECRETS_STORE.get({
2494
+ secretName: "BANK_SERVICE_FINBRICKS_PRIVATE_KEY_PEM"
2495
+ })).data?.secretValue || "",
2496
+ REDIRECT_URI: env.REDIRECT_URI,
2497
+ connectedAccounts,
2498
+ resolveCredentials
2499
+ });
2500
+ case "DBU":
2501
+ return new DbuConnector({
2502
+ BASE_URL: env.DBUCS_BASE_URI,
2503
+ USERNAME: env.DBUCS_USERNAME,
2504
+ APPLICATION_CODE: env.DBUCS_APPLICATION_CODE,
2505
+ KV: env.BANK_KV,
2506
+ API: env.DBU_CBS_BACKOFFICE_DEV,
2507
+ REDIRECT_URI: env.REDIRECT_URI,
2508
+ TX_AUTH_URI: env.DBUCS_TX_AUTH_URI,
2509
+ connectedAccounts
2510
+ });
2511
+ default:
2512
+ const mockConnector = new MockConnector();
2513
+ mockConnector.connectedAccounts = connectedAccounts;
2514
+ return mockConnector;
2515
+ }
2516
+ };
2517
+ function mod97(string) {
2518
+ let checksum = string.slice(0, 2);
2519
+ let fragment = "";
2520
+ for (let offset = 2; offset < string.length; offset += 7) {
2521
+ fragment = checksum + string.substring(offset, offset + 7);
2522
+ checksum = (parseInt(fragment, 10) % 97).toString();
2523
+ }
2524
+ return parseInt(checksum, 10);
2525
+ }
2526
+ const parseCzechIban = (iban) => {
2527
+ const stripped = iban.replace(/\s/g, "").toUpperCase();
2528
+ if (!stripped.startsWith("CZ") || stripped.length !== 24) {
2529
+ throw new Error(`Invalid Czech IBAN: ${iban}`);
2530
+ }
2531
+ const bankCode = stripped.slice(4, 8);
2532
+ const prefix = stripped.slice(8, 14).replace(/^0+/, "");
2533
+ const main = stripped.slice(14, 24).replace(/^0+/, "");
2534
+ const accountNumber = prefix ? `${prefix}-${main}` : main;
2535
+ return { bankCode, accountNumber };
2536
+ };
2537
+ const calculateCzechIban = (accountNumber, bankCode) => {
2538
+ const paddedBankCode = bankCode.padStart(4, "0");
2539
+ let prefix = "";
2540
+ let mainAccount = accountNumber;
2541
+ if (accountNumber.includes("-")) {
2542
+ const parts = accountNumber.split("-");
2543
+ if (parts.length !== 2) {
2544
+ throw new Error(
2545
+ `Invalid account number format: expected "prefix-main" or "main", got "${accountNumber}"`
2546
+ );
2547
+ }
2548
+ prefix = parts[0];
2549
+ mainAccount = parts[1];
2550
+ }
2551
+ const paddedPrefix = prefix.padStart(6, "0");
2552
+ const paddedAccount = mainAccount.padStart(10, "0");
2553
+ const basicIban = paddedBankCode + paddedPrefix + paddedAccount;
2554
+ const rearranged = basicIban + "123500";
2555
+ const remainder = mod97(rearranged);
2556
+ const checkDigits = (98 - remainder).toString().padStart(2, "0");
2557
+ return `CZ${checkDigits}${basicIban}`;
2558
+ };
2559
+
2521
2560
  exports.BASE_TERMINAL_STATUSES = BASE_TERMINAL_STATUSES;
2522
2561
  exports.CsobConnector = CsobConnector;
2523
2562
  exports.DbuConnector = DbuConnector;
@@ -2536,6 +2575,7 @@ exports.accountInsertSchema = accountInsertSchema;
2536
2575
  exports.accountSelectSchema = accountSelectSchema;
2537
2576
  exports.accountUpdateSchema = accountUpdateSchema;
2538
2577
  exports.assignAccount = assignAccount;
2578
+ exports.calculateCzechIban = calculateCzechIban;
2539
2579
  exports.dbuAccountConfigSchema = dbuAccountConfigSchema;
2540
2580
  exports.getNonTerminalPaymentRequestsQuery = getNonTerminalPaymentRequestsQuery;
2541
2581
  exports.hasPaymentAccountAssigned = hasPaymentAccountAssigned;