@develit-services/bank 6.2.0 → 6.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.
package/dist/base.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _develit_io_backend_sdk from '@develit-io/backend-sdk';
2
2
  import { WorkflowInstanceStatus, IRPCResponse } from '@develit-io/backend-sdk';
3
- import { B as BatchSelectType, P as PaymentRequestSelectType, A as AccountSelectType, a as PaymentSelectType, L as LastSyncMetadata, C as ConnectorConfig, t as tables, b as ConnectorKey, c as ConfigEnvironmentBank, I as IBankConnector, d as PaymentType, e as CurrencyCode, H as HandleAuthorizationCallbackInput, f as HandleAuthorizationCallbackOutput } from './shared/bank.r1xIlFBl.js';
4
- import { S as SendPaymentInput, a as SendPaymentOutput, b as SendPaymentSyncInput, c as SendPaymentSyncOutput, F as FinbricksSupportedBanksResponse } from './shared/bank.Cu_7g0PZ.js';
3
+ import { B as BatchSelectType, P as PaymentRequestSelectType, A as AccountSelectType, a as PaymentSelectType, L as LastSyncMetadata, C as ConnectorConfig, t as tables, b as ConnectorKey, c as ConfigEnvironmentBank, I as IBankConnector, d as PaymentType, e as CurrencyCode, H as HandleAuthorizationCallbackInput, f as HandleAuthorizationCallbackOutput } from './shared/bank.DIx4G38W.js';
4
+ import { S as SendPaymentInput, a as SendPaymentOutput, b as SendPaymentSyncInput, c as SendPaymentSyncOutput, F as FinbricksSupportedBanksResponse } from './shared/bank.a661MsjV.js';
5
5
  import { WorkerEntrypoint } from 'cloudflare:workers';
6
6
  import { DrizzleD1Database } from 'drizzle-orm/d1';
7
7
  import { z } from 'zod';
@@ -164,6 +164,7 @@ declare const sendBatchInputSchema: z.ZodObject<{
164
164
  city: z.ZodOptional<z.ZodString>;
165
165
  postalCode: z.ZodOptional<z.ZodString>;
166
166
  countryCode: z.ZodOptional<z.ZodEnum<{
167
+ IM: "IM";
167
168
  AF: "AF";
168
169
  AL: "AL";
169
170
  DZ: "DZ";
@@ -253,7 +254,6 @@ declare const sendBatchInputSchema: z.ZodObject<{
253
254
  IR: "IR";
254
255
  IQ: "IQ";
255
256
  IE: "IE";
256
- IM: "IM";
257
257
  IL: "IL";
258
258
  IT: "IT";
259
259
  CI: "CI";
@@ -436,6 +436,7 @@ declare const sendBatchInputSchema: z.ZodObject<{
436
436
  AVAX: "AVAX";
437
437
  }>>;
438
438
  countryCode: z.ZodOptional<z.ZodEnum<{
439
+ IM: "IM";
439
440
  AF: "AF";
440
441
  AL: "AL";
441
442
  DZ: "DZ";
@@ -525,7 +526,6 @@ declare const sendBatchInputSchema: z.ZodObject<{
525
526
  IR: "IR";
526
527
  IQ: "IQ";
527
528
  IE: "IE";
528
- IM: "IM";
529
529
  IL: "IL";
530
530
  IT: "IT";
531
531
  CI: "CI";
@@ -729,6 +729,7 @@ declare const sendBatchInputSchema: z.ZodObject<{
729
729
  city: z.ZodOptional<z.ZodString>;
730
730
  postalCode: z.ZodOptional<z.ZodString>;
731
731
  countryCode: z.ZodOptional<z.ZodEnum<{
732
+ IM: "IM";
732
733
  AF: "AF";
733
734
  AL: "AL";
734
735
  DZ: "DZ";
@@ -818,7 +819,6 @@ declare const sendBatchInputSchema: z.ZodObject<{
818
819
  IR: "IR";
819
820
  IQ: "IQ";
820
821
  IE: "IE";
821
- IM: "IM";
822
822
  IL: "IL";
823
823
  IT: "IT";
824
824
  CI: "CI";
@@ -1001,6 +1001,7 @@ declare const sendBatchInputSchema: z.ZodObject<{
1001
1001
  AVAX: "AVAX";
1002
1002
  }>>;
1003
1003
  countryCode: z.ZodOptional<z.ZodEnum<{
1004
+ IM: "IM";
1004
1005
  AF: "AF";
1005
1006
  AL: "AL";
1006
1007
  DZ: "DZ";
@@ -1090,7 +1091,6 @@ declare const sendBatchInputSchema: z.ZodObject<{
1090
1091
  IR: "IR";
1091
1092
  IQ: "IQ";
1092
1093
  IE: "IE";
1093
- IM: "IM";
1094
1094
  IL: "IL";
1095
1095
  IT: "IT";
1096
1096
  CI: "CI";
@@ -1262,6 +1262,7 @@ declare const authorizeAccountInputSchema: z.ZodObject<{
1262
1262
  city: z.ZodOptional<z.ZodString>;
1263
1263
  postalCode: z.ZodOptional<z.ZodString>;
1264
1264
  countryCode: z.ZodOptional<z.ZodEnum<{
1265
+ IM: "IM";
1265
1266
  AF: "AF";
1266
1267
  AL: "AL";
1267
1268
  DZ: "DZ";
@@ -1351,7 +1352,6 @@ declare const authorizeAccountInputSchema: z.ZodObject<{
1351
1352
  IR: "IR";
1352
1353
  IQ: "IQ";
1353
1354
  IE: "IE";
1354
- IM: "IM";
1355
1355
  IL: "IL";
1356
1356
  IT: "IT";
1357
1357
  CI: "CI";
@@ -1618,6 +1618,7 @@ declare const simulateDepositInputSchema: z.ZodObject<{
1618
1618
  city: z.ZodOptional<z.ZodString>;
1619
1619
  postalCode: z.ZodOptional<z.ZodString>;
1620
1620
  countryCode: z.ZodOptional<z.ZodEnum<{
1621
+ IM: "IM";
1621
1622
  AF: "AF";
1622
1623
  AL: "AL";
1623
1624
  DZ: "DZ";
@@ -1707,7 +1708,6 @@ declare const simulateDepositInputSchema: z.ZodObject<{
1707
1708
  IR: "IR";
1708
1709
  IQ: "IQ";
1709
1710
  IE: "IE";
1710
- IM: "IM";
1711
1711
  IL: "IL";
1712
1712
  IT: "IT";
1713
1713
  CI: "CI";
@@ -1890,6 +1890,7 @@ declare const simulateDepositInputSchema: z.ZodObject<{
1890
1890
  AVAX: "AVAX";
1891
1891
  }>>;
1892
1892
  countryCode: z.ZodOptional<z.ZodEnum<{
1893
+ IM: "IM";
1893
1894
  AF: "AF";
1894
1895
  AL: "AL";
1895
1896
  DZ: "DZ";
@@ -1979,7 +1980,6 @@ declare const simulateDepositInputSchema: z.ZodObject<{
1979
1980
  IR: "IR";
1980
1981
  IQ: "IQ";
1981
1982
  IE: "IE";
1982
- IM: "IM";
1983
1983
  IL: "IL";
1984
1984
  IT: "IT";
1985
1985
  CI: "CI";
@@ -2183,6 +2183,7 @@ declare const simulateDepositInputSchema: z.ZodObject<{
2183
2183
  city: z.ZodOptional<z.ZodString>;
2184
2184
  postalCode: z.ZodOptional<z.ZodString>;
2185
2185
  countryCode: z.ZodOptional<z.ZodEnum<{
2186
+ IM: "IM";
2186
2187
  AF: "AF";
2187
2188
  AL: "AL";
2188
2189
  DZ: "DZ";
@@ -2272,7 +2273,6 @@ declare const simulateDepositInputSchema: z.ZodObject<{
2272
2273
  IR: "IR";
2273
2274
  IQ: "IQ";
2274
2275
  IE: "IE";
2275
- IM: "IM";
2276
2276
  IL: "IL";
2277
2277
  IT: "IT";
2278
2278
  CI: "CI";
@@ -2455,6 +2455,7 @@ declare const simulateDepositInputSchema: z.ZodObject<{
2455
2455
  AVAX: "AVAX";
2456
2456
  }>>;
2457
2457
  countryCode: z.ZodOptional<z.ZodEnum<{
2458
+ IM: "IM";
2458
2459
  AF: "AF";
2459
2460
  AL: "AL";
2460
2461
  DZ: "DZ";
@@ -2544,7 +2545,6 @@ declare const simulateDepositInputSchema: z.ZodObject<{
2544
2545
  IR: "IR";
2545
2546
  IQ: "IQ";
2546
2547
  IE: "IE";
2547
- IM: "IM";
2548
2548
  IL: "IL";
2549
2549
  IT: "IT";
2550
2550
  CI: "CI";
@@ -2711,15 +2711,15 @@ declare const getBatchesInputSchema: z.ZodObject<{
2711
2711
  filterBatchAccountId: z.ZodOptional<z.ZodUnion<readonly [z.ZodUUID, z.ZodArray<z.ZodUUID>]>>;
2712
2712
  filterBatchStatus: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
2713
2713
  AUTHORIZED: "AUTHORIZED";
2714
+ COMPLETED: "COMPLETED";
2714
2715
  PROCESSING: "PROCESSING";
2715
2716
  READY_TO_SIGN: "READY_TO_SIGN";
2716
- COMPLETED: "COMPLETED";
2717
2717
  FAILED: "FAILED";
2718
2718
  }>, z.ZodArray<z.ZodEnum<{
2719
2719
  AUTHORIZED: "AUTHORIZED";
2720
+ COMPLETED: "COMPLETED";
2720
2721
  PROCESSING: "PROCESSING";
2721
2722
  READY_TO_SIGN: "READY_TO_SIGN";
2722
- COMPLETED: "COMPLETED";
2723
2723
  FAILED: "FAILED";
2724
2724
  }>>]>>;
2725
2725
  }, z.core.$strip>;
@@ -2825,9 +2825,9 @@ declare const getPaymentsInputSchema: z.ZodObject<{
2825
2825
  limit: z.ZodNumber;
2826
2826
  sort: z.ZodObject<{
2827
2827
  column: z.ZodEnum<{
2828
+ amount: "amount";
2828
2829
  createdAt: "createdAt";
2829
2830
  updatedAt: "updatedAt";
2830
- amount: "amount";
2831
2831
  }>;
2832
2832
  direction: z.ZodEnum<{
2833
2833
  asc: "asc";
@@ -2956,18 +2956,18 @@ declare const getPaymentsInputSchema: z.ZodObject<{
2956
2956
  filterPaymentDateFrom: z.ZodOptional<z.ZodDate>;
2957
2957
  filterPaymentDateTo: z.ZodOptional<z.ZodDate>;
2958
2958
  filterPaymentStatus: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
2959
- PROCESSING: "PROCESSING";
2960
2959
  BOOKED: "BOOKED";
2961
2960
  REJECTED: "REJECTED";
2961
+ PROCESSING: "PROCESSING";
2962
2962
  PENDING: "PENDING";
2963
2963
  CANCELLED: "CANCELLED";
2964
2964
  SCHEDULED: "SCHEDULED";
2965
2965
  HOLD: "HOLD";
2966
2966
  INFO: "INFO";
2967
2967
  }>, z.ZodArray<z.ZodEnum<{
2968
- PROCESSING: "PROCESSING";
2969
2968
  BOOKED: "BOOKED";
2970
2969
  REJECTED: "REJECTED";
2970
+ PROCESSING: "PROCESSING";
2971
2971
  PENDING: "PENDING";
2972
2972
  CANCELLED: "CANCELLED";
2973
2973
  SCHEDULED: "SCHEDULED";
@@ -3626,6 +3626,7 @@ declare const updateAccountInputSchema: z.ZodObject<{
3626
3626
  city: z.ZodOptional<z.ZodString>;
3627
3627
  postalCode: z.ZodOptional<z.ZodString>;
3628
3628
  countryCode: z.ZodOptional<z.ZodEnum<{
3629
+ IM: "IM";
3629
3630
  AF: "AF";
3630
3631
  AL: "AL";
3631
3632
  DZ: "DZ";
@@ -3715,7 +3716,6 @@ declare const updateAccountInputSchema: z.ZodObject<{
3715
3716
  IR: "IR";
3716
3717
  IQ: "IQ";
3717
3718
  IE: "IE";
3718
- IM: "IM";
3719
3719
  IL: "IL";
3720
3720
  IT: "IT";
3721
3721
  CI: "CI";
@@ -3892,9 +3892,9 @@ declare const getPaymentRequestsInputSchema: z.ZodObject<{
3892
3892
  limit: z.ZodNumber;
3893
3893
  sort: z.ZodObject<{
3894
3894
  column: z.ZodEnum<{
3895
+ amount: "amount";
3895
3896
  createdAt: "createdAt";
3896
3897
  updatedAt: "updatedAt";
3897
- amount: "amount";
3898
3898
  }>;
3899
3899
  direction: z.ZodEnum<{
3900
3900
  asc: "asc";
@@ -3903,17 +3903,17 @@ declare const getPaymentRequestsInputSchema: z.ZodObject<{
3903
3903
  }, z.core.$strip>;
3904
3904
  filterAccountId: z.ZodOptional<z.ZodUnion<readonly [z.ZodUUID, z.ZodArray<z.ZodUUID>]>>;
3905
3905
  filterStatus: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
3906
+ OPENED: "OPENED";
3906
3907
  AUTHORIZED: "AUTHORIZED";
3907
3908
  COMPLETED: "COMPLETED";
3908
- OPENED: "OPENED";
3909
3909
  BOOKED: "BOOKED";
3910
3910
  SETTLED: "SETTLED";
3911
3911
  REJECTED: "REJECTED";
3912
3912
  CLOSED: "CLOSED";
3913
3913
  }>, z.ZodArray<z.ZodEnum<{
3914
+ OPENED: "OPENED";
3914
3915
  AUTHORIZED: "AUTHORIZED";
3915
3916
  COMPLETED: "COMPLETED";
3916
- OPENED: "OPENED";
3917
3917
  BOOKED: "BOOKED";
3918
3918
  SETTLED: "SETTLED";
3919
3919
  REJECTED: "REJECTED";
package/dist/base.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { uuidv4, first, buildMultiFilterConditions as buildMultiFilterConditions$1, bankAccountMetadataSchema, structuredAddressSchema, workflowInstanceStatusSchema, develitWorker, createInternalError, action, service } from '@develit-io/backend-sdk';
2
- import { G as tables, g as accountInsertSchema, H as relations, o as isProcessedStatus, p as isTerminalStatus, L as getNonTerminalPaymentRequestsQuery, x as toIncomingPayment, N as calculateCzechIban, j as assignAccount, u as toBatchedPayment, y as toPaymentRequestInsert, a as FinbricksClient, F as FINBRICKS_ENDPOINTS } from './shared/bank.BTysRSoT.mjs';
2
+ import { G as tables, g as accountInsertSchema, H as relations, o as isProcessedStatus, p as isTerminalStatus, N as getNonTerminalPaymentRequestsQuery, x as toIncomingPayment, O as calculateCzechIban, j as assignAccount, u as toBatchedPayment, y as toPaymentRequestInsert, a as FinbricksClient, F as FINBRICKS_ENDPOINTS } from './shared/bank.N9K_wiwt.mjs';
3
3
  import { eq, sql, and, like, asc, desc, inArray, gte, lte, isNull, count } from 'drizzle-orm';
4
4
  import { WorkerEntrypoint } from 'cloudflare:workers';
5
5
  import { drizzle } from 'drizzle-orm/d1';
6
6
  import 'jose';
7
- import { h as encrypt, d as createCredentialsResolver, i as initiateConnector, e as updatePaymentRequestStatusCommand, a as getPaymentRequestsByBatchIdQuery, g as getBatchByIdQuery, u as upsertBatchCommand, j as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from './shared/bank.Dfog9v5Q.mjs';
7
+ import { h as encrypt, d as createCredentialsResolver, i as initiateConnector, e as updatePaymentRequestStatusCommand, a as getPaymentRequestsByBatchIdQuery, g as getBatchByIdQuery, u as upsertBatchCommand, j as importAesKey, f as createPaymentCommand, b as getAccountByIdQuery } from './shared/bank.4ljYMHJL.mjs';
8
8
  import { z } from 'zod';
9
9
  import { I as INSTRUCTION_PRIORITIES, C as CHARGE_BEARERS, g as PAYMENT_TYPES, b as CONNECTOR_KEYS, a as BATCH_STATUSES, f as PAYMENT_STATUSES, P as PAYMENT_DIRECTIONS, e as PAYMENT_REQUEST_STATUSES } from './shared/bank.BT7HayCV.mjs';
10
10
  import { CURRENCY_CODES } from '@develit-io/general-codes';
@@ -1,4 +1,4 @@
1
- export { aB as account, aC as accountCredentials, aD as batch, aE as ott, aF as payment, aG as paymentRequest } from '../shared/bank.r1xIlFBl.cjs';
1
+ export { aB as account, aC as accountCredentials, aD as batch, aE as ott, aF as payment, aG as paymentRequest } from '../shared/bank.DIx4G38W.cjs';
2
2
  import 'drizzle-orm/sqlite-core';
3
3
  import 'drizzle-orm';
4
4
  import '@develit-io/general-codes';
@@ -1,4 +1,4 @@
1
- export { aB as account, aC as accountCredentials, aD as batch, aE as ott, aF as payment, aG as paymentRequest } from '../shared/bank.r1xIlFBl.mjs';
1
+ export { aB as account, aC as accountCredentials, aD as batch, aE as ott, aF as payment, aG as paymentRequest } from '../shared/bank.DIx4G38W.mjs';
2
2
  import 'drizzle-orm/sqlite-core';
3
3
  import 'drizzle-orm';
4
4
  import '@develit-io/general-codes';
@@ -1,4 +1,4 @@
1
- export { aB as account, aC as accountCredentials, aD as batch, aE as ott, aF as payment, aG as paymentRequest } from '../shared/bank.r1xIlFBl.js';
1
+ export { aB as account, aC as accountCredentials, aD as batch, aE as ott, aF as payment, aG as paymentRequest } from '../shared/bank.DIx4G38W.js';
2
2
  import 'drizzle-orm/sqlite-core';
3
3
  import 'drizzle-orm';
4
4
  import '@develit-io/general-codes';
@@ -1,14 +1,15 @@
1
1
  'use strict';
2
2
 
3
3
  const backendSdk = require('@develit-io/backend-sdk');
4
- const paymentDirection = require('../shared/bank.BrZjHUNG.cjs');
4
+ const paymentDirection = require('../shared/bank.Z1R7hzNr.cjs');
5
5
  const batchLifecycle = require('../shared/bank.NF8bZBy0.cjs');
6
6
  const drizzleOrm = require('drizzle-orm');
7
- const bank = require('../shared/bank.DIR_r2s2.cjs');
7
+ const bank = require('../shared/bank.D1KOxBVA.cjs');
8
8
  const cloudflare_workers = require('cloudflare:workers');
9
9
  const cloudflare_workflows = require('cloudflare:workflows');
10
10
  const d1 = require('drizzle-orm/d1');
11
11
  require('node:crypto');
12
+ const superjson = require('superjson');
12
13
  require('date-fns');
13
14
  require('../shared/bank.Ca3jzmIb.cjs');
14
15
  require('drizzle-orm/sqlite-core');
@@ -17,6 +18,10 @@ require('jose');
17
18
  require('zod');
18
19
  require('drizzle-orm/zod');
19
20
 
21
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
22
+
23
+ const superjson__default = /*#__PURE__*/_interopDefaultCompat(superjson);
24
+
20
25
  const updateAccountLastSyncCommand = (db, {
21
26
  lastSyncAt,
22
27
  accountId,
@@ -412,8 +417,7 @@ function guardStepResultSize(value, ceilingBytes = STEP_RESULT_BYTE_CEILING) {
412
417
  }
413
418
  function rethrowFetchError(err) {
414
419
  if (err instanceof cloudflare_workflows.NonRetryableError) throw err;
415
- const message = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : JSON.stringify(err);
416
- throw new Error(message);
420
+ throw new Error(paymentDirection.extractErrorDetails(err).message);
417
421
  }
418
422
 
419
423
  const MIN_CATCH_UP_WINDOW_MS = 6 * 60 * 60 * 1e3;
@@ -435,7 +439,10 @@ async function fetchBoundedByWindow({
435
439
  const halvedSpanMs = Math.floor(
436
440
  (current.dateTo.getTime() - current.dateFrom.getTime()) / 2
437
441
  );
438
- if (halvedSpanMs < minWindowMs) throw tooLarge;
442
+ if (halvedSpanMs < minWindowMs) {
443
+ tooLarge.oversizedResult = { result, window: current };
444
+ throw tooLarge;
445
+ }
439
446
  current = {
440
447
  dateFrom: current.dateFrom,
441
448
  dateTo: new Date(current.dateFrom.getTime() + halvedSpanMs),
@@ -447,6 +454,24 @@ async function fetchBoundedByWindow({
447
454
  }
448
455
  }
449
456
 
457
+ function buildPaymentsR2Key(params) {
458
+ return `sync-account-payments/${params.accountId}/${params.instanceId}/${params.iteration}.json`;
459
+ }
460
+ async function writePaymentsToR2(bucket, key, payments) {
461
+ await bucket.put(key, superjson__default.stringify(payments), {
462
+ httpMetadata: { contentType: "application/json" }
463
+ });
464
+ }
465
+ async function readPaymentsFromR2(bucket, key) {
466
+ const object = await bucket.get(key);
467
+ if (!object) {
468
+ throw new Error(
469
+ `Expected a payments payload at R2 key "${key}" but it was missing`
470
+ );
471
+ }
472
+ return superjson__default.parse(await object.text());
473
+ }
474
+
450
475
  class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
451
476
  async run(event, step) {
452
477
  const { accountId } = event.payload;
@@ -553,9 +578,10 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
553
578
  }))
554
579
  );
555
580
  };
556
- let bounded;
581
+ let paymentsRef;
582
+ let effectiveSyncWindow;
557
583
  try {
558
- bounded = await fetchBoundedByWindow({
584
+ const bounded = await fetchBoundedByWindow({
559
585
  window: syncWindow,
560
586
  fetchWindow,
561
587
  guardResult: guardStepResultSize,
@@ -567,56 +593,76 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
567
593
  dateTo: narrowed.dateTo.toISOString()
568
594
  })
569
595
  });
596
+ paymentsRef = { kind: "inline", items: bounded.result };
597
+ effectiveSyncWindow = bounded.window;
570
598
  } catch (err) {
571
- if (err instanceof StepResultTooLargeError) {
572
- logger.error("payments.fetch.result-too-large", {
573
- accountId,
574
- connectorKey: account.connectorKey,
575
- dateFrom: syncWindow.dateFrom.toISOString(),
576
- dateTo: syncWindow.dateTo.toISOString()
577
- });
599
+ if (!(err instanceof StepResultTooLargeError) || !err.oversizedResult) {
600
+ throw err;
578
601
  }
579
- throw err;
602
+ const { result, window } = err.oversizedResult;
603
+ const r2Key = buildPaymentsR2Key({
604
+ accountId,
605
+ instanceId: event.instanceId,
606
+ iteration
607
+ });
608
+ await writePaymentsToR2(this.env.BANK_SYNC_R2, r2Key, result);
609
+ logger.error("payments.fetch.result-too-large", {
610
+ accountId,
611
+ connectorKey: account.connectorKey,
612
+ dateFrom: syncWindow.dateFrom.toISOString(),
613
+ dateTo: syncWindow.dateTo.toISOString(),
614
+ r2Key,
615
+ count: result.length
616
+ });
617
+ paymentsRef = { kind: "r2", key: r2Key, count: result.length };
618
+ effectiveSyncWindow = window;
580
619
  }
581
620
  logger.info("payments.fetch.completed", {
582
621
  accountId,
583
622
  connectorKey: account.connectorKey,
584
- paymentsCount: bounded.result.length
623
+ paymentsCount: paymentsRef.kind === "inline" ? paymentsRef.items.length : paymentsRef.count
585
624
  });
586
625
  return {
587
- payments: bounded.result,
626
+ paymentsRef,
588
627
  windowMs: {
589
- dateFromMs: bounded.window.dateFrom.getTime(),
590
- dateToMs: bounded.window.dateTo.getTime(),
591
- isCatchUp: bounded.window.isCatchUp
628
+ dateFromMs: effectiveSyncWindow.dateFrom.getTime(),
629
+ dateToMs: effectiveSyncWindow.dateTo.getTime(),
630
+ isCatchUp: effectiveSyncWindow.isCatchUp
592
631
  }
593
632
  };
594
633
  } catch (err) {
634
+ const details = paymentDirection.extractErrorDetails(err);
595
635
  logger.error("payments.fetch.failed", {
596
636
  accountId,
597
637
  connectorKey: account.connectorKey,
598
- error: err instanceof Error ? err.message : String(err)
638
+ error: details.message,
639
+ errorCode: details.code,
640
+ errorStatus: details.status,
641
+ stack: err instanceof Error ? err.stack : void 0
599
642
  });
600
643
  rethrowFetchError(err);
601
644
  }
602
645
  }
603
646
  );
604
- const payments = fetched.payments;
605
647
  const effectiveWindow = {
606
648
  dateFrom: new Date(fetched.windowMs.dateFromMs),
607
649
  dateTo: new Date(fetched.windowMs.dateToMs),
608
650
  isCatchUp: fetched.windowMs.isCatchUp
609
651
  };
610
- const paymentsToProcess = payments.filter(
611
- (p) => paymentDirection.isPaymentCompleted(p.parsed)
612
- );
613
- const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
614
- const paymentsToInsert = paymentsToProcess.filter(
615
- (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
616
- );
617
652
  await step.do(
618
653
  "process new payments and update lastSyncAt",
619
654
  async (ctx) => {
655
+ const payments = fetched.paymentsRef.kind === "r2" ? await readPaymentsFromR2(
656
+ this.env.BANK_SYNC_R2,
657
+ fetched.paymentsRef.key
658
+ ) : fetched.paymentsRef.items;
659
+ const paymentsToProcess = payments.filter(
660
+ (p) => paymentDirection.isPaymentCompleted(p.parsed)
661
+ );
662
+ const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
663
+ const paymentsToInsert = paymentsToProcess.filter(
664
+ (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
665
+ );
620
666
  const eventsToEmit = [];
621
667
  const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
622
668
  const BANK_REF_ID_CHUNK_SIZE = 90;
@@ -734,6 +780,9 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
734
780
  instanceId: event.instanceId
735
781
  });
736
782
  }
783
+ if (fetched.paymentsRef.kind === "r2") {
784
+ await this.env.BANK_SYNC_R2.delete(fetched.paymentsRef.key);
785
+ }
737
786
  return {
738
787
  ...lastSyncMetadata,
739
788
  newLastSyncAt: effectiveWindow.dateTo
@@ -1,12 +1,13 @@
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, m as isPaymentCompleted } from '../shared/bank.BTysRSoT.mjs';
2
+ import { G as tables, H as relations, v as toBatchedPaymentFromPaymentRequest, z as toPreparedPayment, J as extractErrorDetails, m as isPaymentCompleted } from '../shared/bank.N9K_wiwt.mjs';
3
3
  import { i as isBatchAuthorized, b as isBatchFailed, d as isBatchProcessing } from '../shared/bank.XqSw509X.mjs';
4
4
  import { sql, and, eq, inArray } from 'drizzle-orm';
5
- import { g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, i as initiateConnector, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.Dfog9v5Q.mjs';
5
+ import { g as getBatchByIdQuery, a as getPaymentRequestsByBatchIdQuery, c as checksum, u as upsertBatchCommand, b as getAccountByIdQuery, d as createCredentialsResolver, i as initiateConnector, e as updatePaymentRequestStatusCommand, f as createPaymentCommand } from '../shared/bank.4ljYMHJL.mjs';
6
6
  import { WorkflowEntrypoint } from 'cloudflare:workers';
7
7
  import { NonRetryableError } from 'cloudflare:workflows';
8
8
  import { drizzle } from 'drizzle-orm/d1';
9
9
  import 'node:crypto';
10
+ import superjson from 'superjson';
10
11
  import 'date-fns';
11
12
  import '../shared/bank.BT7HayCV.mjs';
12
13
  import 'drizzle-orm/sqlite-core';
@@ -410,8 +411,7 @@ function guardStepResultSize(value, ceilingBytes = STEP_RESULT_BYTE_CEILING) {
410
411
  }
411
412
  function rethrowFetchError(err) {
412
413
  if (err instanceof NonRetryableError) throw err;
413
- const message = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : JSON.stringify(err);
414
- throw new Error(message);
414
+ throw new Error(extractErrorDetails(err).message);
415
415
  }
416
416
 
417
417
  const MIN_CATCH_UP_WINDOW_MS = 6 * 60 * 60 * 1e3;
@@ -433,7 +433,10 @@ async function fetchBoundedByWindow({
433
433
  const halvedSpanMs = Math.floor(
434
434
  (current.dateTo.getTime() - current.dateFrom.getTime()) / 2
435
435
  );
436
- if (halvedSpanMs < minWindowMs) throw tooLarge;
436
+ if (halvedSpanMs < minWindowMs) {
437
+ tooLarge.oversizedResult = { result, window: current };
438
+ throw tooLarge;
439
+ }
437
440
  current = {
438
441
  dateFrom: current.dateFrom,
439
442
  dateTo: new Date(current.dateFrom.getTime() + halvedSpanMs),
@@ -445,6 +448,24 @@ async function fetchBoundedByWindow({
445
448
  }
446
449
  }
447
450
 
451
+ function buildPaymentsR2Key(params) {
452
+ return `sync-account-payments/${params.accountId}/${params.instanceId}/${params.iteration}.json`;
453
+ }
454
+ async function writePaymentsToR2(bucket, key, payments) {
455
+ await bucket.put(key, superjson.stringify(payments), {
456
+ httpMetadata: { contentType: "application/json" }
457
+ });
458
+ }
459
+ async function readPaymentsFromR2(bucket, key) {
460
+ const object = await bucket.get(key);
461
+ if (!object) {
462
+ throw new Error(
463
+ `Expected a payments payload at R2 key "${key}" but it was missing`
464
+ );
465
+ }
466
+ return superjson.parse(await object.text());
467
+ }
468
+
448
469
  class BankSyncAccountPayments extends WorkflowEntrypoint {
449
470
  async run(event, step) {
450
471
  const { accountId } = event.payload;
@@ -551,9 +572,10 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
551
572
  }))
552
573
  );
553
574
  };
554
- let bounded;
575
+ let paymentsRef;
576
+ let effectiveSyncWindow;
555
577
  try {
556
- bounded = await fetchBoundedByWindow({
578
+ const bounded = await fetchBoundedByWindow({
557
579
  window: syncWindow,
558
580
  fetchWindow,
559
581
  guardResult: guardStepResultSize,
@@ -565,56 +587,76 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
565
587
  dateTo: narrowed.dateTo.toISOString()
566
588
  })
567
589
  });
590
+ paymentsRef = { kind: "inline", items: bounded.result };
591
+ effectiveSyncWindow = bounded.window;
568
592
  } catch (err) {
569
- if (err instanceof StepResultTooLargeError) {
570
- logger.error("payments.fetch.result-too-large", {
571
- accountId,
572
- connectorKey: account.connectorKey,
573
- dateFrom: syncWindow.dateFrom.toISOString(),
574
- dateTo: syncWindow.dateTo.toISOString()
575
- });
593
+ if (!(err instanceof StepResultTooLargeError) || !err.oversizedResult) {
594
+ throw err;
576
595
  }
577
- throw err;
596
+ const { result, window } = err.oversizedResult;
597
+ const r2Key = buildPaymentsR2Key({
598
+ accountId,
599
+ instanceId: event.instanceId,
600
+ iteration
601
+ });
602
+ await writePaymentsToR2(this.env.BANK_SYNC_R2, r2Key, result);
603
+ logger.error("payments.fetch.result-too-large", {
604
+ accountId,
605
+ connectorKey: account.connectorKey,
606
+ dateFrom: syncWindow.dateFrom.toISOString(),
607
+ dateTo: syncWindow.dateTo.toISOString(),
608
+ r2Key,
609
+ count: result.length
610
+ });
611
+ paymentsRef = { kind: "r2", key: r2Key, count: result.length };
612
+ effectiveSyncWindow = window;
578
613
  }
579
614
  logger.info("payments.fetch.completed", {
580
615
  accountId,
581
616
  connectorKey: account.connectorKey,
582
- paymentsCount: bounded.result.length
617
+ paymentsCount: paymentsRef.kind === "inline" ? paymentsRef.items.length : paymentsRef.count
583
618
  });
584
619
  return {
585
- payments: bounded.result,
620
+ paymentsRef,
586
621
  windowMs: {
587
- dateFromMs: bounded.window.dateFrom.getTime(),
588
- dateToMs: bounded.window.dateTo.getTime(),
589
- isCatchUp: bounded.window.isCatchUp
622
+ dateFromMs: effectiveSyncWindow.dateFrom.getTime(),
623
+ dateToMs: effectiveSyncWindow.dateTo.getTime(),
624
+ isCatchUp: effectiveSyncWindow.isCatchUp
590
625
  }
591
626
  };
592
627
  } catch (err) {
628
+ const details = extractErrorDetails(err);
593
629
  logger.error("payments.fetch.failed", {
594
630
  accountId,
595
631
  connectorKey: account.connectorKey,
596
- error: err instanceof Error ? err.message : String(err)
632
+ error: details.message,
633
+ errorCode: details.code,
634
+ errorStatus: details.status,
635
+ stack: err instanceof Error ? err.stack : void 0
597
636
  });
598
637
  rethrowFetchError(err);
599
638
  }
600
639
  }
601
640
  );
602
- const payments = fetched.payments;
603
641
  const effectiveWindow = {
604
642
  dateFrom: new Date(fetched.windowMs.dateFromMs),
605
643
  dateTo: new Date(fetched.windowMs.dateToMs),
606
644
  isCatchUp: fetched.windowMs.isCatchUp
607
645
  };
608
- const paymentsToProcess = payments.filter(
609
- (p) => isPaymentCompleted(p.parsed)
610
- );
611
- const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
612
- const paymentsToInsert = paymentsToProcess.filter(
613
- (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
614
- );
615
646
  await step.do(
616
647
  "process new payments and update lastSyncAt",
617
648
  async (ctx) => {
649
+ const payments = fetched.paymentsRef.kind === "r2" ? await readPaymentsFromR2(
650
+ this.env.BANK_SYNC_R2,
651
+ fetched.paymentsRef.key
652
+ ) : fetched.paymentsRef.items;
653
+ const paymentsToProcess = payments.filter(
654
+ (p) => isPaymentCompleted(p.parsed)
655
+ );
656
+ const lastSyncBankRefIds = account.lastSyncMetadata?.lastSyncBankRefIds || [];
657
+ const paymentsToInsert = paymentsToProcess.filter(
658
+ (p) => !lastSyncBankRefIds.includes(p.parsed.bankRefId)
659
+ );
618
660
  const eventsToEmit = [];
619
661
  const bankRefIds = paymentsToInsert.map((p) => p.parsed.bankRefId).filter((id) => id != null);
620
662
  const BANK_REF_ID_CHUNK_SIZE = 90;
@@ -732,6 +774,9 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
732
774
  instanceId: event.instanceId
733
775
  });
734
776
  }
777
+ if (fetched.paymentsRef.kind === "r2") {
778
+ await this.env.BANK_SYNC_R2.delete(fetched.paymentsRef.key);
779
+ }
735
780
  return {
736
781
  ...lastSyncMetadata,
737
782
  newLastSyncAt: effectiveWindow.dateTo
package/dist/service.cjs CHANGED
@@ -6,6 +6,9 @@ const BANK_SERVICE_BINDINGS = {
6
6
  SECRETS_STORE: { kind: "service", target: "secrets-store", bare: true },
7
7
  BANK_KV: { kind: "kv", suffix: "bank" },
8
8
  BANK_D1: { kind: "d1", suffix: "bank" },
9
+ // Spillover for `fetch bank payments` results too large to return from a
10
+ // Workflow step directly — see sync-payments-store.ts.
11
+ BANK_SYNC_R2: { kind: "r2", suffix: "bank-sync-payloads" },
9
12
  QUEUE_BUS_QUEUE: { kind: "queueProducer", suffix: "queue-bus" },
10
13
  NOTIFICATIONS_QUEUE: { kind: "queueProducer", suffix: "notifications" },
11
14
  SYNC_ACCOUNT_PAYMENTS_WORKFLOW: {