@develit-services/bank 5.2.0 → 5.2.2

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.
@@ -1,8 +1,8 @@
1
1
  import { first, uuidv4, asNonEmpty } from '@develit-io/backend-sdk';
2
- import { G as tables, H as relations, v as toBatchedPaymentFromPaymentRequest, z as toPreparedPayment, J as initiateConnector, m as isPaymentCompleted } from '../shared/bank.Bkxo76q4.mjs';
2
+ import { G as tables, H as relations, v as toBatchedPaymentFromPaymentRequest, z as toPreparedPayment, J as initiateConnector, m as isPaymentCompleted } from '../shared/bank.Cg2epnnD.mjs';
3
3
  import { i as isBatchAuthorized, b as isBatchFailed, d as isBatchProcessing } from '../shared/bank.XqSw509X.mjs';
4
4
  import { eq, and, inArray } from 'drizzle-orm';
5
- import { g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.BRD2WfnT.mjs';
5
+ import { g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.5RiBQTe0.mjs';
6
6
  import { WorkflowEntrypoint } from 'cloudflare:workers';
7
7
  import { NonRetryableError } from 'cloudflare:workflows';
8
8
  import { drizzle } from 'drizzle-orm/d1';
@@ -313,16 +313,12 @@ async function pushToQueue(queue, message) {
313
313
  await queue.send(message, { contentType: "v8" });
314
314
  return;
315
315
  }
316
- const QUEUE_BATCH_SIZE = 100;
317
- for (let i = 0; i < message.length; i += QUEUE_BATCH_SIZE) {
318
- const chunk = message.slice(i, i + QUEUE_BATCH_SIZE);
319
- await queue.sendBatch(
320
- chunk.map((m) => ({
321
- body: m,
322
- contentType: "v8"
323
- }))
324
- );
325
- }
316
+ await queue.sendBatch(
317
+ message.map((m) => ({
318
+ body: m,
319
+ contentType: "v8"
320
+ }))
321
+ );
326
322
  }
327
323
  class BankSyncAccountPayments extends WorkflowEntrypoint {
328
324
  async run(event, step) {
@@ -348,13 +344,13 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
348
344
  if (!account.lastSyncAt) {
349
345
  throw new Error(`lastSyncedAt is not set for account: ${accountId}`);
350
346
  }
351
- await step.do(
352
- "fetch and process payments",
347
+ const payments = await step.do(
348
+ "fetch bank payments",
353
349
  {
354
350
  retries: { limit: 5, delay: "2 minutes", backoff: "exponential" },
355
- timeout: "5 minutes"
351
+ timeout: "2 minutes"
356
352
  },
357
- async (ctx) => {
353
+ async () => {
358
354
  try {
359
355
  logger.info("payments.fetch.started", {
360
356
  accountId,
@@ -377,192 +373,19 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
377
373
  }
378
374
  ]
379
375
  });
380
- const payments = await connector.getAllAccountPayments({
376
+ const result = await connector.getAllAccountPayments({
381
377
  account,
382
378
  filter: { dateFrom: account.lastSyncAt }
383
379
  });
384
380
  logger.info("payments.fetch.completed", {
385
381
  accountId,
386
382
  connectorKey: account.connectorKey,
387
- paymentsCount: payments.length
388
- });
389
- const paymentsToProcess = payments.filter(
390
- (p) => isPaymentCompleted(p.parsed)
391
- );
392
- logger.info("payments.filtered.toProcess", {
393
- accountId,
394
- totalFetched: payments.length,
395
- paymentsToProcess: paymentsToProcess.length,
396
- sampleStatuses: payments.slice(0, 5).map((p) => ({
397
- bankRefId: p.parsed.bankRefId,
398
- status: p.parsed.status,
399
- isCompleted: isPaymentCompleted(p.parsed)
400
- }))
401
- });
402
- const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
403
- const paymentsToInsert = paymentsToProcess.filter(
404
- (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
405
- );
406
- logger.info("payments.filtered.toInsert", {
407
- accountId,
408
- paymentsToProcess: paymentsToProcess.length,
409
- paymentsToInsert: paymentsToInsert.length,
410
- lastSyncBankRefIdsCount: lastSyncBankRefIds.length,
411
- sampleLastSyncBankRefIds: lastSyncBankRefIds.slice(0, 10),
412
- sampleToInsert: paymentsToInsert.slice(0, 5).map((p) => p.parsed.bankRefId)
413
- });
414
- const eventsToEmit = [];
415
- const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
416
- const BANK_REF_ID_CHUNK_SIZE = 90;
417
- const matchingRequests = [];
418
- for (let i = 0; i < bankRefIds.length; i += BANK_REF_ID_CHUNK_SIZE) {
419
- const chunkIds = bankRefIds.slice(i, i + BANK_REF_ID_CHUNK_SIZE);
420
- const rows = await db.select().from(tables.paymentRequest).where(
421
- and(
422
- inArray(tables.paymentRequest.bankRefId, chunkIds),
423
- eq(tables.paymentRequest.accountId, account.id),
424
- eq(
425
- tables.paymentRequest.connectorKey,
426
- account.connectorKey
427
- )
428
- )
429
- );
430
- matchingRequests.push(...rows);
431
- }
432
- const requestByBankRefId = Object.fromEntries(
433
- matchingRequests.map((r) => [r.bankRefId, r])
434
- );
435
- const enrichedPayments = paymentsToInsert.map((p) => {
436
- const req = p.parsed.bankRefId && requestByBankRefId[p.parsed.bankRefId] || null;
437
- if (!req) return p;
438
- return {
439
- ...p,
440
- parsed: {
441
- ...p.parsed,
442
- // queue-bus: transaction matching (DBU doesn't echo these in statements)
443
- vs: p.parsed.vs ?? req.vs,
444
- ss: p.parsed.ss ?? req.ss,
445
- ks: p.parsed.ks ?? req.ks,
446
- message: p.parsed.message ?? req.message,
447
- // queue-bus: party creation
448
- creditor: {
449
- ...p.parsed.creditor,
450
- holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
451
- },
452
- debtor: {
453
- ...p.parsed.debtor,
454
- holderName: p.parsed.debtor?.holderName ?? req.debtor?.holderName
455
- }
456
- // NOT enriched: chargeBearer, instructionPriority, refId, batchId,
457
- // createdAt, address, swiftBic — no downstream consumer in payment table
458
- }
459
- };
460
- });
461
- const createCommands = enrichedPayments.map(
462
- (p) => createPaymentCommand(db, { payment: p.parsed }).command
463
- );
464
- logger.info("payments.commands.created", {
465
- accountId,
466
- createCommandsCount: createCommands.length,
467
- enrichedPaymentsCount: enrichedPayments.length
468
- });
469
- eventsToEmit.push(
470
- ...enrichedPayments.map((p) => ({
471
- eventType: "BANK_PAYMENT",
472
- eventSignal: "paymentFetched",
473
- bankPayment: p.parsed,
474
- metadata: {
475
- correlationId: p.parsed.correlationId,
476
- entityId: p.parsed.id,
477
- timestamp: /* @__PURE__ */ new Date()
478
- }
479
- }))
480
- );
481
- const lastSyncMetadata = {
482
- payments: payments.length,
483
- paymentsToProcess: paymentsToProcess.length,
484
- paymentsInserted: paymentsToInsert.length,
485
- lastSyncBankRefIds: paymentsToProcess.filter((p) => p.parsed.status === "BOOKED").map((p) => p.parsed.bankRefId),
486
- lastSyncPayments: lastSyncBankRefIds.length,
487
- eventsEmitted: eventsToEmit.length,
488
- iterationCount: getStepCount(ctx),
489
- workflowStartedAt
490
- };
491
- const updateLastSyncCommand = updateAccountLastSyncCommand(db, {
492
- accountId: account.id,
493
- lastSyncAt: now,
494
- lastSyncMetadata
495
- }).command;
496
- logger.info("payments.database.beforeBatch", {
497
- accountId,
498
- createCommandsCount: createCommands.length,
499
- willUseBatch: createCommands.length > 0
383
+ paymentsCount: result.length
500
384
  });
501
- if (createCommands.length) {
502
- logger.info("payments.database.batchStart", {
503
- accountId,
504
- totalCommands: createCommands.length + 1,
505
- paymentsToInsert: createCommands.length
506
- });
507
- const BATCH_CHUNK_SIZE = 90;
508
- let totalInserted = 0;
509
- for (let i = 0; i < createCommands.length; i += BATCH_CHUNK_SIZE) {
510
- const chunkCommands = createCommands.slice(
511
- i,
512
- i + BATCH_CHUNK_SIZE
513
- );
514
- const isLastChunk = i + BATCH_CHUNK_SIZE >= createCommands.length;
515
- const batchCommands = isLastChunk ? asNonEmpty([updateLastSyncCommand, ...chunkCommands]) : asNonEmpty(chunkCommands);
516
- logger.info("payments.database.batchChunk", {
517
- accountId,
518
- chunkIndex: Math.floor(i / BATCH_CHUNK_SIZE),
519
- chunkSize: chunkCommands.length,
520
- isLastChunk
521
- });
522
- await db.batch(batchCommands);
523
- totalInserted += chunkCommands.length;
524
- }
525
- logger.info("payments.database.batchComplete", {
526
- accountId,
527
- inserted: totalInserted,
528
- chunks: Math.ceil(createCommands.length / BATCH_CHUNK_SIZE)
529
- });
530
- } else {
531
- logger.info("payments.database.updateOnly", {
532
- accountId,
533
- reason: "no new payments to insert"
534
- });
535
- await updateLastSyncCommand.execute();
536
- logger.info("payments.database.updateComplete", {
537
- accountId
538
- });
539
- }
540
- if (eventsToEmit.length) {
541
- logger.info("payments.queue.sending", {
542
- accountId,
543
- eventsCount: eventsToEmit.length
544
- });
545
- await pushToQueue(
546
- this.env.QUEUE_BUS_QUEUE,
547
- eventsToEmit
548
- );
549
- logger.info("payments.queue.sent", {
550
- accountId,
551
- eventsCount: eventsToEmit.length
552
- });
553
- }
554
- logger.info("payments.process.complete", {
555
- accountId,
556
- ...lastSyncMetadata,
557
- newLastSyncAt: now
558
- });
559
- return {
560
- ...lastSyncMetadata,
561
- newLastSyncAt: now
562
- };
385
+ return result;
563
386
  } catch (err) {
564
387
  const message = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : JSON.stringify(err);
565
- logger.error("payments.process.failed", {
388
+ logger.error("payments.fetch.failed", {
566
389
  accountId,
567
390
  connectorKey: account.connectorKey,
568
391
  error: message
@@ -571,6 +394,109 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
571
394
  }
572
395
  }
573
396
  );
397
+ const paymentsToProcess = payments.filter(
398
+ (p) => isPaymentCompleted(p.parsed)
399
+ );
400
+ const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
401
+ const paymentsToInsert = paymentsToProcess.filter(
402
+ (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
403
+ );
404
+ await step.do(
405
+ "process new payments and update lastSyncAt",
406
+ async (ctx) => {
407
+ const eventsToEmit = [];
408
+ const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
409
+ const BANK_REF_ID_CHUNK_SIZE = 90;
410
+ const matchingRequests = [];
411
+ for (let i = 0; i < bankRefIds.length; i += BANK_REF_ID_CHUNK_SIZE) {
412
+ const chunkIds = bankRefIds.slice(i, i + BANK_REF_ID_CHUNK_SIZE);
413
+ const rows = await db.select().from(tables.paymentRequest).where(
414
+ and(
415
+ inArray(tables.paymentRequest.bankRefId, chunkIds),
416
+ eq(tables.paymentRequest.accountId, account.id),
417
+ eq(tables.paymentRequest.connectorKey, account.connectorKey)
418
+ )
419
+ );
420
+ matchingRequests.push(...rows);
421
+ }
422
+ const requestByBankRefId = Object.fromEntries(
423
+ matchingRequests.map((r) => [r.bankRefId, r])
424
+ );
425
+ const enrichedPayments = paymentsToInsert.map((p) => {
426
+ const req = p.parsed.bankRefId && requestByBankRefId[p.parsed.bankRefId] || null;
427
+ if (!req) return p;
428
+ return {
429
+ ...p,
430
+ parsed: {
431
+ ...p.parsed,
432
+ // queue-bus: transaction matching (DBU doesn't echo these in statements)
433
+ vs: p.parsed.vs ?? req.vs,
434
+ ss: p.parsed.ss ?? req.ss,
435
+ ks: p.parsed.ks ?? req.ks,
436
+ message: p.parsed.message ?? req.message,
437
+ // queue-bus: party creation
438
+ creditor: {
439
+ ...p.parsed.creditor,
440
+ holderName: p.parsed.creditor?.holderName ?? req.creditor?.holderName
441
+ },
442
+ debtor: {
443
+ ...p.parsed.debtor,
444
+ holderName: p.parsed.debtor?.holderName ?? req.debtor?.holderName
445
+ }
446
+ // NOT enriched: chargeBearer, instructionPriority, refId, batchId,
447
+ // createdAt, address, swiftBic — no downstream consumer in payment table
448
+ }
449
+ };
450
+ });
451
+ const createCommands = enrichedPayments.map(
452
+ (p) => createPaymentCommand(db, { payment: p.parsed }).command
453
+ );
454
+ eventsToEmit.push(
455
+ ...enrichedPayments.map((p) => ({
456
+ eventType: "BANK_PAYMENT",
457
+ eventSignal: "paymentFetched",
458
+ bankPayment: p.parsed,
459
+ metadata: {
460
+ correlationId: p.parsed.correlationId,
461
+ entityId: p.parsed.id,
462
+ timestamp: /* @__PURE__ */ new Date()
463
+ }
464
+ }))
465
+ );
466
+ const lastSyncMetadata = {
467
+ payments: payments.length,
468
+ paymentsToProcess: paymentsToProcess.length,
469
+ paymentsInserted: paymentsToInsert.length,
470
+ lastSyncBankRefIds: paymentsToProcess.filter((p) => p.parsed.status === "BOOKED").map((p) => p.parsed.bankRefId),
471
+ lastSyncPayments: lastSyncBankRefIds.length,
472
+ eventsEmitted: eventsToEmit.length,
473
+ iterationCount: getStepCount(ctx),
474
+ workflowStartedAt
475
+ };
476
+ const updateLastSyncCommand = updateAccountLastSyncCommand(db, {
477
+ accountId: account.id,
478
+ lastSyncAt: now,
479
+ lastSyncMetadata
480
+ }).command;
481
+ if (createCommands.length) {
482
+ await db.batch(
483
+ asNonEmpty([updateLastSyncCommand, ...createCommands])
484
+ );
485
+ } else {
486
+ await updateLastSyncCommand;
487
+ }
488
+ if (eventsToEmit.length) {
489
+ await pushToQueue(
490
+ this.env.QUEUE_BUS_QUEUE,
491
+ eventsToEmit
492
+ );
493
+ }
494
+ return {
495
+ ...lastSyncMetadata,
496
+ newLastSyncAt: now
497
+ };
498
+ }
499
+ );
574
500
  await step.sleep(
575
501
  "Sleep for next sync",
576
502
  `${account.syncIntervalS} seconds`
@@ -1,5 +1,5 @@
1
1
  import { sql, and, eq, isNull } from 'drizzle-orm';
2
- import { G as tables } from './bank.Bkxo76q4.mjs';
2
+ import { G as tables } from './bank.Cg2epnnD.mjs';
3
3
  import { uuidv4 } from '@develit-io/backend-sdk';
4
4
  import './bank.BzDNLxB_.mjs';
5
5
  import 'date-fns';
@@ -1,4 +1,4 @@
1
- import { e as CurrencyCode, R as BankCode, a1 as CountryCode, P as PaymentRequestSelectType } from './bank.BJTq7Qw9.mjs';
1
+ import { e as CurrencyCode, R as BankCode, a1 as CountryCode, P as PaymentRequestSelectType } from './bank.CdkOsZE8.mjs';
2
2
  import { z } from 'zod';
3
3
 
4
4
  type ReferenceType = `${'VS' | 'SS' | 'KS'}:${number}`;
@@ -444,6 +444,7 @@ declare const sendPaymentInputSchema: z.ZodObject<{
444
444
  GW: "GW";
445
445
  GY: "GY";
446
446
  HT: "HT";
447
+ HK: "HK";
447
448
  HN: "HN";
448
449
  HU: "HU";
449
450
  IS: "IS";
@@ -715,6 +716,7 @@ declare const sendPaymentInputSchema: z.ZodObject<{
715
716
  GW: "GW";
716
717
  GY: "GY";
717
718
  HT: "HT";
719
+ HK: "HK";
718
720
  HN: "HN";
719
721
  HU: "HU";
720
722
  IS: "IS";
@@ -1007,6 +1009,7 @@ declare const sendPaymentInputSchema: z.ZodObject<{
1007
1009
  GW: "GW";
1008
1010
  GY: "GY";
1009
1011
  HT: "HT";
1012
+ HK: "HK";
1010
1013
  HN: "HN";
1011
1014
  HU: "HU";
1012
1015
  IS: "IS";
@@ -1278,6 +1281,7 @@ declare const sendPaymentInputSchema: z.ZodObject<{
1278
1281
  GW: "GW";
1279
1282
  GY: "GY";
1280
1283
  HT: "HT";
1284
+ HK: "HK";
1281
1285
  HN: "HN";
1282
1286
  HU: "HU";
1283
1287
  IS: "IS";
@@ -1658,6 +1662,7 @@ declare const sendPaymentSyncInputSchema: z.ZodObject<{
1658
1662
  GW: "GW";
1659
1663
  GY: "GY";
1660
1664
  HT: "HT";
1665
+ HK: "HK";
1661
1666
  HN: "HN";
1662
1667
  HU: "HU";
1663
1668
  IS: "IS";
@@ -1929,6 +1934,7 @@ declare const sendPaymentSyncInputSchema: z.ZodObject<{
1929
1934
  GW: "GW";
1930
1935
  GY: "GY";
1931
1936
  HT: "HT";
1937
+ HK: "HK";
1932
1938
  HN: "HN";
1933
1939
  HU: "HU";
1934
1940
  IS: "IS";
@@ -2221,6 +2227,7 @@ declare const sendPaymentSyncInputSchema: z.ZodObject<{
2221
2227
  GW: "GW";
2222
2228
  GY: "GY";
2223
2229
  HT: "HT";
2230
+ HK: "HK";
2224
2231
  HN: "HN";
2225
2232
  HU: "HU";
2226
2233
  IS: "IS";
@@ -2492,6 +2499,7 @@ declare const sendPaymentSyncInputSchema: z.ZodObject<{
2492
2499
  GW: "GW";
2493
2500
  GY: "GY";
2494
2501
  HT: "HT";
2502
+ HK: "HK";
2495
2503
  HN: "HN";
2496
2504
  HU: "HU";
2497
2505
  IS: "IS";