@develit-services/bank 6.0.0 → 6.1.1

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.cjs CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  const backendSdk = require('@develit-io/backend-sdk');
4
4
  const paymentDirection = require('./shared/bank.BsWBG0gb.cjs');
5
- const bank = require('./shared/bank.DQZxSHKV.cjs');
6
5
  const drizzleOrm = require('drizzle-orm');
7
6
  const cloudflare_workers = require('cloudflare:workers');
8
7
  const d1 = require('drizzle-orm/d1');
9
8
  require('jose');
9
+ const bank = require('./shared/bank.CSmuzdUJ.cjs');
10
10
  const zod = require('zod');
11
11
  const database_schema = require('./shared/bank.Ca3jzmIb.cjs');
12
12
  const generalCodes = require('@develit-io/general-codes');
@@ -107,50 +107,14 @@ async function heartbeatSyncWorkflows({
107
107
  );
108
108
  }
109
109
 
110
- async function dispatchSyncWorkflows({
111
- entities,
112
- createInstance,
113
- logger,
114
- now = Date.now,
115
- recoveryWindowMs = bank.DISPATCH_RECOVERY_WINDOW_MS
116
- }) {
117
- const at = now();
118
- await Promise.all(
119
- entities.map(async (entity) => {
120
- const { id, lastSyncAt } = entity;
121
- if (!lastSyncAt) {
122
- logger.warn("sync-workflow.dispatch.sync-age-unknown", { id });
123
- return;
124
- }
125
- const instanceId = bank.buildDispatchInstanceId(id, at, recoveryWindowMs);
126
- try {
127
- await createInstance(instanceId, id);
128
- logger.info("sync-workflow.dispatch.created", {
129
- id,
130
- instanceId,
131
- lastSyncAt: lastSyncAt.toISOString()
132
- });
133
- } catch (err) {
134
- if (bank.isAlreadyExists(err)) return;
135
- logger.error("sync-workflow.dispatch.failed", {
136
- id,
137
- instanceId,
138
- error: err instanceof Error ? err.message : String(err)
139
- });
140
- }
141
- })
142
- );
110
+ function isAlreadyExists(err) {
111
+ return /already exists/i.test(extractMessage(err));
143
112
  }
144
-
145
- function isDispatchEnabled(accountId, selection) {
146
- const raw = selection?.trim();
147
- if (!raw) return false;
148
- if (raw.toLowerCase() === "all") return true;
149
- return raw.split(",").map((id) => id.trim()).includes(accountId);
113
+ function isInstanceNotFound(err) {
114
+ return /instance.*not.?found|not.?found.*instance/i.test(extractMessage(err));
150
115
  }
151
- function isDispatchActive(accountId, selection, dispatchCron) {
152
- if (!dispatchCron?.trim()) return false;
153
- return isDispatchEnabled(accountId, selection);
116
+ function extractMessage(err) {
117
+ return err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : "";
154
118
  }
155
119
 
156
120
  const FINITE_STATUSES = /* @__PURE__ */ new Set([
@@ -987,32 +951,18 @@ exports.BankServiceBase = class BankServiceBase extends backendSdk.develitWorker
987
951
  { successMessage: "Account sync workflow started" },
988
952
  async ({ accountId }) => {
989
953
  await this.setSyncEnabledOrThrow(accountId, true);
990
- if (isDispatchActive(
991
- accountId,
992
- this.env.SYNC_DISPATCH_ACCOUNT_IDS,
993
- this.env.CRON_SYNC_WORKFLOW_DISPATCH
994
- )) {
995
- const instanceId = bank.buildDispatchInstanceId(accountId, Date.now());
996
- let instance2;
997
- try {
998
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create(
999
- bank.buildDispatchCreateOptions(instanceId, accountId)
1000
- );
1001
- } catch (err) {
1002
- if (!bank.isAlreadyExists(err)) throw err;
1003
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(instanceId);
1004
- }
1005
- return {
1006
- instanceId: instance2.id,
1007
- details: await instance2.status()
1008
- };
954
+ let instance;
955
+ try {
956
+ instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create({
957
+ id: accountId,
958
+ params: {
959
+ accountId
960
+ }
961
+ });
962
+ } catch (err) {
963
+ if (!isAlreadyExists(err)) throw err;
964
+ instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(accountId);
1009
965
  }
1010
- const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create({
1011
- id: accountId,
1012
- params: {
1013
- accountId
1014
- }
1015
- });
1016
966
  return {
1017
967
  instanceId: instance.id,
1018
968
  details: await instance.status()
@@ -1039,34 +989,13 @@ exports.BankServiceBase = class BankServiceBase extends backendSdk.develitWorker
1039
989
  { successMessage: "Account sync workflow restarted" },
1040
990
  async ({ accountId }) => {
1041
991
  await this.setSyncEnabledOrThrow(accountId, true);
1042
- if (isDispatchActive(
1043
- accountId,
1044
- this.env.SYNC_DISPATCH_ACCOUNT_IDS,
1045
- this.env.CRON_SYNC_WORKFLOW_DISPATCH
1046
- )) {
1047
- const instanceId = bank.buildDispatchInstanceId(accountId, Date.now());
1048
- let instance2;
1049
- try {
1050
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create(
1051
- bank.buildDispatchCreateOptions(instanceId, accountId)
1052
- );
1053
- } catch (err) {
1054
- if (!bank.isAlreadyExists(err)) throw err;
1055
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(instanceId);
1056
- await instance2.restart();
1057
- }
1058
- return {
1059
- instanceId: instance2.id,
1060
- details: await instance2.status()
1061
- };
1062
- }
1063
992
  let instance;
1064
993
  try {
1065
994
  const existing = await this.getCurrentSyncInstance(accountId);
1066
995
  await existing.restart();
1067
996
  instance = existing;
1068
997
  } catch (err) {
1069
- if (!bank.isInstanceNotFound(err)) throw err;
998
+ if (!isInstanceNotFound(err)) throw err;
1070
999
  }
1071
1000
  if (!instance) {
1072
1001
  instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create({
@@ -1376,19 +1305,11 @@ exports.BankServiceBase = class BankServiceBase extends backendSdk.develitWorker
1376
1305
  console.log("Scheduled CRON payment request statuses");
1377
1306
  await this.updatePaymentRequestStatuses();
1378
1307
  }
1379
- if (controller.cron === this.env.CRON_SYNC_WORKFLOW_DISPATCH) {
1380
- await this.dispatchSyncWorkflows();
1381
- }
1382
1308
  if (controller.cron === this.env.CRON_SYNC_WORKFLOW_HEARTBEAT) {
1383
1309
  console.log("Scheduled CRON sync workflow heartbeat");
1384
1310
  await this.heartbeatSyncWorkflows();
1385
1311
  }
1386
1312
  }
1387
- /**
1388
- * Lifecycle actions must target the instance that actually syncs the
1389
- * account — under dispatch that is the windowed instance recorded with the
1390
- * last sync write, not the legacy canonical id.
1391
- */
1392
1313
  async setSyncEnabledOrThrow(accountId, syncEnabled) {
1393
1314
  const [updated] = await updateAccountSyncEnabledCommand(this.db, {
1394
1315
  accountId,
@@ -1399,25 +1320,7 @@ exports.BankServiceBase = class BankServiceBase extends backendSdk.develitWorker
1399
1320
  }
1400
1321
  }
1401
1322
  async getCurrentSyncInstance(accountId) {
1402
- const account = await bank.getAccountByIdQuery(this.db, { accountId });
1403
- return this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(
1404
- bank.resolveCurrentSyncInstanceId(
1405
- accountId,
1406
- account?.lastSyncMetadata?.instanceId
1407
- )
1408
- );
1409
- }
1410
- async dispatchSyncWorkflows() {
1411
- const selection = this.env.SYNC_DISPATCH_ACCOUNT_IDS;
1412
- if (!selection?.trim()) return;
1413
- const accounts = await getSyncCandidateAccountsQuery(this.db);
1414
- await dispatchSyncWorkflows({
1415
- entities: accounts.filter((a) => isDispatchEnabled(a.id, selection)),
1416
- createInstance: (instanceId, accountId) => this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create(
1417
- bank.buildDispatchCreateOptions(instanceId, accountId)
1418
- ),
1419
- logger: syncEventConsoleLogger
1420
- });
1323
+ return this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(accountId);
1421
1324
  }
1422
1325
  async heartbeatSyncWorkflows() {
1423
1326
  const accounts = await getSyncCandidateAccountsQuery(this.db);
@@ -1432,13 +1335,7 @@ exports.BankServiceBase = class BankServiceBase extends backendSdk.develitWorker
1432
1335
  return;
1433
1336
  }
1434
1337
  await heartbeatSyncWorkflows({
1435
- entities: accounts.filter(
1436
- (a) => !isDispatchActive(
1437
- a.id,
1438
- this.env.SYNC_DISPATCH_ACCOUNT_IDS,
1439
- this.env.CRON_SYNC_WORKFLOW_DISPATCH
1440
- )
1441
- ).map((a) => ({
1338
+ entities: accounts.map((a) => ({
1442
1339
  id: a.id,
1443
1340
  iterationCount: a.lastSyncMetadata?.iterationCount,
1444
1341
  syncIntervalS: a.syncIntervalS,
@@ -2210,12 +2107,7 @@ exports.BankServiceBase = class BankServiceBase extends backendSdk.develitWorker
2210
2107
  if (includeWorkflow) {
2211
2108
  let status;
2212
2109
  try {
2213
- const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(
2214
- bank.resolveCurrentSyncInstanceId(
2215
- a.id,
2216
- a.lastSyncMetadata?.instanceId
2217
- )
2218
- );
2110
+ const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(a.id);
2219
2111
  status = await instance.status();
2220
2112
  } catch (_) {
2221
2113
  status = null;
@@ -2315,12 +2207,7 @@ exports.BankServiceBase = class BankServiceBase extends backendSdk.develitWorker
2315
2207
  throw accountNotFoundError();
2316
2208
  }
2317
2209
  try {
2318
- const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(
2319
- bank.resolveCurrentSyncInstanceId(
2320
- accountId,
2321
- account.lastSyncMetadata?.instanceId
2322
- )
2323
- );
2210
+ const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(accountId);
2324
2211
  await terminateSyncWorkflow(instance);
2325
2212
  } catch (error) {
2326
2213
  this.log({
package/dist/base.d.cts CHANGED
@@ -4212,14 +4212,8 @@ declare class BankServiceBase extends BankServiceBase_base {
4212
4212
  statusChanged: number;
4213
4213
  }>>;
4214
4214
  scheduled(controller: ScheduledController): Promise<void>;
4215
- /**
4216
- * Lifecycle actions must target the instance that actually syncs the
4217
- * account — under dispatch that is the windowed instance recorded with the
4218
- * last sync write, not the legacy canonical id.
4219
- */
4220
4215
  private setSyncEnabledOrThrow;
4221
4216
  private getCurrentSyncInstance;
4222
- private dispatchSyncWorkflows;
4223
4217
  private heartbeatSyncWorkflows;
4224
4218
  handleAuthorizationCallback(input: HandleAuthorizationCallbackInput): Promise<IRPCResponse<HandleAuthorizationCallbackOutput>>;
4225
4219
  closePaymentRequest(input: ClosePaymentRequestInput): Promise<IRPCResponse<ClosePaymentRequestOutput>>;
package/dist/base.d.mts CHANGED
@@ -4212,14 +4212,8 @@ declare class BankServiceBase extends BankServiceBase_base {
4212
4212
  statusChanged: number;
4213
4213
  }>>;
4214
4214
  scheduled(controller: ScheduledController): Promise<void>;
4215
- /**
4216
- * Lifecycle actions must target the instance that actually syncs the
4217
- * account — under dispatch that is the windowed instance recorded with the
4218
- * last sync write, not the legacy canonical id.
4219
- */
4220
4215
  private setSyncEnabledOrThrow;
4221
4216
  private getCurrentSyncInstance;
4222
- private dispatchSyncWorkflows;
4223
4217
  private heartbeatSyncWorkflows;
4224
4218
  handleAuthorizationCallback(input: HandleAuthorizationCallbackInput): Promise<IRPCResponse<HandleAuthorizationCallbackOutput>>;
4225
4219
  closePaymentRequest(input: ClosePaymentRequestInput): Promise<IRPCResponse<ClosePaymentRequestOutput>>;
package/dist/base.d.ts CHANGED
@@ -4212,14 +4212,8 @@ declare class BankServiceBase extends BankServiceBase_base {
4212
4212
  statusChanged: number;
4213
4213
  }>>;
4214
4214
  scheduled(controller: ScheduledController): Promise<void>;
4215
- /**
4216
- * Lifecycle actions must target the instance that actually syncs the
4217
- * account — under dispatch that is the windowed instance recorded with the
4218
- * last sync write, not the legacy canonical id.
4219
- */
4220
4215
  private setSyncEnabledOrThrow;
4221
4216
  private getCurrentSyncInstance;
4222
- private dispatchSyncWorkflows;
4223
4217
  private heartbeatSyncWorkflows;
4224
4218
  handleAuthorizationCallback(input: HandleAuthorizationCallbackInput): Promise<IRPCResponse<HandleAuthorizationCallbackOutput>>;
4225
4219
  closePaymentRequest(input: ClosePaymentRequestInput): Promise<IRPCResponse<ClosePaymentRequestOutput>>;
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
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.kz-PKVi5.mjs';
3
- import { k as isAlreadyExists, D as DISPATCH_RECOVERY_WINDOW_MS, l as buildDispatchInstanceId, m as encrypt, d as createCredentialsResolver, i as initiateConnector, n as buildDispatchCreateOptions, o as isInstanceNotFound, e as updatePaymentRequestStatusCommand, a as getPaymentRequestsByBatchIdQuery, g as getBatchByIdQuery, u as upsertBatchCommand, b as getAccountByIdQuery, r as resolveCurrentSyncInstanceId, p as importAesKey, j as createPaymentCommand } from './shared/bank.D9DoIABz.mjs';
4
3
  import { eq, sql, and, like, asc, desc, inArray, gte, lte, isNull, count } from 'drizzle-orm';
5
4
  import { WorkerEntrypoint } from 'cloudflare:workers';
6
5
  import { drizzle } from 'drizzle-orm/d1';
7
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.BWR4dqQ5.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';
@@ -105,50 +105,14 @@ async function heartbeatSyncWorkflows({
105
105
  );
106
106
  }
107
107
 
108
- async function dispatchSyncWorkflows({
109
- entities,
110
- createInstance,
111
- logger,
112
- now = Date.now,
113
- recoveryWindowMs = DISPATCH_RECOVERY_WINDOW_MS
114
- }) {
115
- const at = now();
116
- await Promise.all(
117
- entities.map(async (entity) => {
118
- const { id, lastSyncAt } = entity;
119
- if (!lastSyncAt) {
120
- logger.warn("sync-workflow.dispatch.sync-age-unknown", { id });
121
- return;
122
- }
123
- const instanceId = buildDispatchInstanceId(id, at, recoveryWindowMs);
124
- try {
125
- await createInstance(instanceId, id);
126
- logger.info("sync-workflow.dispatch.created", {
127
- id,
128
- instanceId,
129
- lastSyncAt: lastSyncAt.toISOString()
130
- });
131
- } catch (err) {
132
- if (isAlreadyExists(err)) return;
133
- logger.error("sync-workflow.dispatch.failed", {
134
- id,
135
- instanceId,
136
- error: err instanceof Error ? err.message : String(err)
137
- });
138
- }
139
- })
140
- );
108
+ function isAlreadyExists(err) {
109
+ return /already exists/i.test(extractMessage(err));
141
110
  }
142
-
143
- function isDispatchEnabled(accountId, selection) {
144
- const raw = selection?.trim();
145
- if (!raw) return false;
146
- if (raw.toLowerCase() === "all") return true;
147
- return raw.split(",").map((id) => id.trim()).includes(accountId);
111
+ function isInstanceNotFound(err) {
112
+ return /instance.*not.?found|not.?found.*instance/i.test(extractMessage(err));
148
113
  }
149
- function isDispatchActive(accountId, selection, dispatchCron) {
150
- if (!dispatchCron?.trim()) return false;
151
- return isDispatchEnabled(accountId, selection);
114
+ function extractMessage(err) {
115
+ return err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : "";
152
116
  }
153
117
 
154
118
  const FINITE_STATUSES = /* @__PURE__ */ new Set([
@@ -985,32 +949,18 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
985
949
  { successMessage: "Account sync workflow started" },
986
950
  async ({ accountId }) => {
987
951
  await this.setSyncEnabledOrThrow(accountId, true);
988
- if (isDispatchActive(
989
- accountId,
990
- this.env.SYNC_DISPATCH_ACCOUNT_IDS,
991
- this.env.CRON_SYNC_WORKFLOW_DISPATCH
992
- )) {
993
- const instanceId = buildDispatchInstanceId(accountId, Date.now());
994
- let instance2;
995
- try {
996
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create(
997
- buildDispatchCreateOptions(instanceId, accountId)
998
- );
999
- } catch (err) {
1000
- if (!isAlreadyExists(err)) throw err;
1001
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(instanceId);
1002
- }
1003
- return {
1004
- instanceId: instance2.id,
1005
- details: await instance2.status()
1006
- };
952
+ let instance;
953
+ try {
954
+ instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create({
955
+ id: accountId,
956
+ params: {
957
+ accountId
958
+ }
959
+ });
960
+ } catch (err) {
961
+ if (!isAlreadyExists(err)) throw err;
962
+ instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(accountId);
1007
963
  }
1008
- const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create({
1009
- id: accountId,
1010
- params: {
1011
- accountId
1012
- }
1013
- });
1014
964
  return {
1015
965
  instanceId: instance.id,
1016
966
  details: await instance.status()
@@ -1037,27 +987,6 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
1037
987
  { successMessage: "Account sync workflow restarted" },
1038
988
  async ({ accountId }) => {
1039
989
  await this.setSyncEnabledOrThrow(accountId, true);
1040
- if (isDispatchActive(
1041
- accountId,
1042
- this.env.SYNC_DISPATCH_ACCOUNT_IDS,
1043
- this.env.CRON_SYNC_WORKFLOW_DISPATCH
1044
- )) {
1045
- const instanceId = buildDispatchInstanceId(accountId, Date.now());
1046
- let instance2;
1047
- try {
1048
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create(
1049
- buildDispatchCreateOptions(instanceId, accountId)
1050
- );
1051
- } catch (err) {
1052
- if (!isAlreadyExists(err)) throw err;
1053
- instance2 = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(instanceId);
1054
- await instance2.restart();
1055
- }
1056
- return {
1057
- instanceId: instance2.id,
1058
- details: await instance2.status()
1059
- };
1060
- }
1061
990
  let instance;
1062
991
  try {
1063
992
  const existing = await this.getCurrentSyncInstance(accountId);
@@ -1374,19 +1303,11 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
1374
1303
  console.log("Scheduled CRON payment request statuses");
1375
1304
  await this.updatePaymentRequestStatuses();
1376
1305
  }
1377
- if (controller.cron === this.env.CRON_SYNC_WORKFLOW_DISPATCH) {
1378
- await this.dispatchSyncWorkflows();
1379
- }
1380
1306
  if (controller.cron === this.env.CRON_SYNC_WORKFLOW_HEARTBEAT) {
1381
1307
  console.log("Scheduled CRON sync workflow heartbeat");
1382
1308
  await this.heartbeatSyncWorkflows();
1383
1309
  }
1384
1310
  }
1385
- /**
1386
- * Lifecycle actions must target the instance that actually syncs the
1387
- * account — under dispatch that is the windowed instance recorded with the
1388
- * last sync write, not the legacy canonical id.
1389
- */
1390
1311
  async setSyncEnabledOrThrow(accountId, syncEnabled) {
1391
1312
  const [updated] = await updateAccountSyncEnabledCommand(this.db, {
1392
1313
  accountId,
@@ -1397,25 +1318,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
1397
1318
  }
1398
1319
  }
1399
1320
  async getCurrentSyncInstance(accountId) {
1400
- const account = await getAccountByIdQuery(this.db, { accountId });
1401
- return this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(
1402
- resolveCurrentSyncInstanceId(
1403
- accountId,
1404
- account?.lastSyncMetadata?.instanceId
1405
- )
1406
- );
1407
- }
1408
- async dispatchSyncWorkflows() {
1409
- const selection = this.env.SYNC_DISPATCH_ACCOUNT_IDS;
1410
- if (!selection?.trim()) return;
1411
- const accounts = await getSyncCandidateAccountsQuery(this.db);
1412
- await dispatchSyncWorkflows({
1413
- entities: accounts.filter((a) => isDispatchEnabled(a.id, selection)),
1414
- createInstance: (instanceId, accountId) => this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.create(
1415
- buildDispatchCreateOptions(instanceId, accountId)
1416
- ),
1417
- logger: syncEventConsoleLogger
1418
- });
1321
+ return this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(accountId);
1419
1322
  }
1420
1323
  async heartbeatSyncWorkflows() {
1421
1324
  const accounts = await getSyncCandidateAccountsQuery(this.db);
@@ -1430,13 +1333,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
1430
1333
  return;
1431
1334
  }
1432
1335
  await heartbeatSyncWorkflows({
1433
- entities: accounts.filter(
1434
- (a) => !isDispatchActive(
1435
- a.id,
1436
- this.env.SYNC_DISPATCH_ACCOUNT_IDS,
1437
- this.env.CRON_SYNC_WORKFLOW_DISPATCH
1438
- )
1439
- ).map((a) => ({
1336
+ entities: accounts.map((a) => ({
1440
1337
  id: a.id,
1441
1338
  iterationCount: a.lastSyncMetadata?.iterationCount,
1442
1339
  syncIntervalS: a.syncIntervalS,
@@ -2208,12 +2105,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
2208
2105
  if (includeWorkflow) {
2209
2106
  let status;
2210
2107
  try {
2211
- const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(
2212
- resolveCurrentSyncInstanceId(
2213
- a.id,
2214
- a.lastSyncMetadata?.instanceId
2215
- )
2216
- );
2108
+ const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(a.id);
2217
2109
  status = await instance.status();
2218
2110
  } catch (_) {
2219
2111
  status = null;
@@ -2313,12 +2205,7 @@ let BankServiceBase = class extends develitWorker(WorkerEntrypoint) {
2313
2205
  throw accountNotFoundError();
2314
2206
  }
2315
2207
  try {
2316
- const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(
2317
- resolveCurrentSyncInstanceId(
2318
- accountId,
2319
- account.lastSyncMetadata?.instanceId
2320
- )
2321
- );
2208
+ const instance = await this.env.SYNC_ACCOUNT_PAYMENTS_WORKFLOW.get(accountId);
2322
2209
  await terminateSyncWorkflow(instance);
2323
2210
  } catch (error) {
2324
2211
  this.log({
@@ -4,7 +4,7 @@ const backendSdk = require('@develit-io/backend-sdk');
4
4
  const paymentDirection = require('../shared/bank.BsWBG0gb.cjs');
5
5
  const batchLifecycle = require('../shared/bank.NF8bZBy0.cjs');
6
6
  const drizzleOrm = require('drizzle-orm');
7
- const bank = require('../shared/bank.DQZxSHKV.cjs');
7
+ const bank = require('../shared/bank.CSmuzdUJ.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');
@@ -66,18 +66,54 @@ const mergeLastSyncBankRefIds = (previous, incoming, cap = LAST_SYNC_BANK_REF_ID
66
66
  return [...new Set(merged)].slice(-cap);
67
67
  };
68
68
 
69
- async function pushToQueue$1(queue, message) {
70
- if (!Array.isArray(message)) {
71
- await queue.send(message, { contentType: "v8" });
72
- return;
69
+ const MAX_BATCH_MESSAGES = 100;
70
+ const MESSAGE_BYTE_CEILING = 112 * 1024;
71
+ const BATCH_BYTE_CEILING = 224 * 1024;
72
+ function estimateMessageBytes(message) {
73
+ return new TextEncoder().encode(JSON.stringify(message)).length;
74
+ }
75
+ function planQueueBatches(messages) {
76
+ const chunks = [];
77
+ const oversized = [];
78
+ let current = [];
79
+ let currentBytes = 0;
80
+ for (const message of messages) {
81
+ const bytes = estimateMessageBytes(message);
82
+ if (bytes > MESSAGE_BYTE_CEILING) {
83
+ oversized.push({ message, bytes });
84
+ continue;
85
+ }
86
+ if (current.length >= MAX_BATCH_MESSAGES || currentBytes + bytes > BATCH_BYTE_CEILING) {
87
+ chunks.push(current);
88
+ current = [];
89
+ currentBytes = 0;
90
+ }
91
+ current.push(message);
92
+ currentBytes += bytes;
73
93
  }
74
- await queue.sendBatch(
75
- message.map((m) => ({
76
- body: m,
77
- contentType: "v8"
78
- }))
79
- );
94
+ if (current.length > 0) {
95
+ chunks.push(current);
96
+ }
97
+ return { chunks, oversized };
98
+ }
99
+ async function pushToQueue(queue, message) {
100
+ const messages = Array.isArray(message) ? message : [message];
101
+ const { chunks, oversized } = planQueueBatches(messages);
102
+ for (const chunk of chunks) {
103
+ if (chunk.length === 1) {
104
+ await queue.send(chunk[0], { contentType: "v8" });
105
+ continue;
106
+ }
107
+ await queue.sendBatch(
108
+ chunk.map((m) => ({
109
+ body: m,
110
+ contentType: "v8"
111
+ }))
112
+ );
113
+ }
114
+ return { sent: messages.length - oversized.length, oversized };
80
115
  }
116
+
81
117
  async function failBatchAndPayments(db, batch, paymentRequests, reason) {
82
118
  const prCmds = paymentRequests.filter((p) => p.status !== "REJECTED").map(
83
119
  (p) => bank.updatePaymentRequestStatusCommand(db, {
@@ -289,7 +325,7 @@ class BankProcessBatch extends cloudflare_workers.WorkflowEntrypoint {
289
325
  timestamp: /* @__PURE__ */ new Date()
290
326
  }
291
327
  }));
292
- await pushToQueue$1(
328
+ await pushToQueue(
293
329
  this.env.QUEUE_BUS_QUEUE,
294
330
  eventsToEmit
295
331
  );
@@ -301,7 +337,7 @@ class BankProcessBatch extends cloudflare_workers.WorkflowEntrypoint {
301
337
  }
302
338
  if (!isMockConnector) {
303
339
  await step.do("enqueue authorization email", async () => {
304
- await pushToQueue$1(this.env.NOTIFICATIONS_QUEUE, {
340
+ await pushToQueue(this.env.NOTIFICATIONS_QUEUE, {
305
341
  type: "email",
306
342
  payload: {
307
343
  email: {
@@ -411,18 +447,6 @@ async function fetchBoundedByWindow({
411
447
  }
412
448
  }
413
449
 
414
- async function pushToQueue(queue, message) {
415
- if (!Array.isArray(message)) {
416
- await queue.send(message, { contentType: "v8" });
417
- return;
418
- }
419
- await queue.sendBatch(
420
- message.map((m) => ({
421
- body: m,
422
- contentType: "v8"
423
- }))
424
- );
425
- }
426
450
  class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
427
451
  async run(event, step) {
428
452
  const { accountId } = event.payload;
@@ -431,7 +455,6 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
431
455
  if (!accountId) {
432
456
  throw new cloudflare_workflows.NonRetryableError(`Haven't obtained accountId to load.`);
433
457
  }
434
- const deadlineMs = bank.computeWindowDeadline(event.instanceId, accountId);
435
458
  const workflowStartedAt = await step.do(
436
459
  "capture workflow start time",
437
460
  async () => Date.now()
@@ -455,19 +478,6 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
455
478
  if (!account.lastSyncAt) {
456
479
  throw new Error(`lastSyncedAt is not set for account: ${accountId}`);
457
480
  }
458
- if (bank.isSupersededBy(
459
- event.instanceId,
460
- account.lastSyncMetadata?.instanceId,
461
- accountId
462
- )) {
463
- logger.info("sync.superseded", {
464
- accountId,
465
- instanceId: event.instanceId,
466
- supersededBy: account.lastSyncMetadata?.instanceId,
467
- iteration
468
- });
469
- return;
470
- }
471
481
  const lastSyncAtMs = account.lastSyncAt.getTime();
472
482
  const windowMs = await step.do("resolve sync window", async () => {
473
483
  const window = resolveSyncWindow(
@@ -481,15 +491,6 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
481
491
  isCatchUp: window.isCatchUp
482
492
  };
483
493
  });
484
- if (deadlineMs != null && windowMs.dateFromMs >= deadlineMs) {
485
- logger.info("sync.window-elapsed", {
486
- accountId,
487
- instanceId: event.instanceId,
488
- iteration,
489
- deadline: new Date(deadlineMs).toISOString()
490
- });
491
- return;
492
- }
493
494
  const syncWindow = {
494
495
  dateFrom: new Date(windowMs.dateFromMs),
495
496
  dateTo: new Date(windowMs.dateToMs),
@@ -705,10 +706,18 @@ class BankSyncAccountPayments extends cloudflare_workers.WorkflowEntrypoint {
705
706
  seenInstanceId: account.lastSyncMetadata?.instanceId ?? null
706
707
  }).command;
707
708
  if (eventsToEmit.length) {
708
- await pushToQueue(
709
+ const { oversized } = await pushToQueue(
709
710
  this.env.QUEUE_BUS_QUEUE,
710
711
  eventsToEmit
711
712
  );
713
+ for (const { message, bytes } of oversized) {
714
+ logger.error("queue.event-oversized", {
715
+ accountId,
716
+ bytes,
717
+ eventSignal: message.eventSignal,
718
+ bankRefId: message.bankPayment.bankRefId
719
+ });
720
+ }
712
721
  }
713
722
  let syncStateRows;
714
723
  if (createCommands.length) {
@@ -2,7 +2,7 @@ import { first, uuidv4, asNonEmpty } from '@develit-io/backend-sdk';
2
2
  import { G as tables, H as relations, v as toBatchedPaymentFromPaymentRequest, z as toPreparedPayment, m as isPaymentCompleted } from '../shared/bank.kz-PKVi5.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 computeWindowDeadline, h as isSupersededBy, j as createPaymentCommand } from '../shared/bank.D9DoIABz.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.BWR4dqQ5.mjs';
6
6
  import { WorkflowEntrypoint } from 'cloudflare:workers';
7
7
  import { NonRetryableError } from 'cloudflare:workflows';
8
8
  import { drizzle } from 'drizzle-orm/d1';
@@ -64,18 +64,54 @@ const mergeLastSyncBankRefIds = (previous, incoming, cap = LAST_SYNC_BANK_REF_ID
64
64
  return [...new Set(merged)].slice(-cap);
65
65
  };
66
66
 
67
- async function pushToQueue$1(queue, message) {
68
- if (!Array.isArray(message)) {
69
- await queue.send(message, { contentType: "v8" });
70
- return;
67
+ const MAX_BATCH_MESSAGES = 100;
68
+ const MESSAGE_BYTE_CEILING = 112 * 1024;
69
+ const BATCH_BYTE_CEILING = 224 * 1024;
70
+ function estimateMessageBytes(message) {
71
+ return new TextEncoder().encode(JSON.stringify(message)).length;
72
+ }
73
+ function planQueueBatches(messages) {
74
+ const chunks = [];
75
+ const oversized = [];
76
+ let current = [];
77
+ let currentBytes = 0;
78
+ for (const message of messages) {
79
+ const bytes = estimateMessageBytes(message);
80
+ if (bytes > MESSAGE_BYTE_CEILING) {
81
+ oversized.push({ message, bytes });
82
+ continue;
83
+ }
84
+ if (current.length >= MAX_BATCH_MESSAGES || currentBytes + bytes > BATCH_BYTE_CEILING) {
85
+ chunks.push(current);
86
+ current = [];
87
+ currentBytes = 0;
88
+ }
89
+ current.push(message);
90
+ currentBytes += bytes;
71
91
  }
72
- await queue.sendBatch(
73
- message.map((m) => ({
74
- body: m,
75
- contentType: "v8"
76
- }))
77
- );
92
+ if (current.length > 0) {
93
+ chunks.push(current);
94
+ }
95
+ return { chunks, oversized };
96
+ }
97
+ async function pushToQueue(queue, message) {
98
+ const messages = Array.isArray(message) ? message : [message];
99
+ const { chunks, oversized } = planQueueBatches(messages);
100
+ for (const chunk of chunks) {
101
+ if (chunk.length === 1) {
102
+ await queue.send(chunk[0], { contentType: "v8" });
103
+ continue;
104
+ }
105
+ await queue.sendBatch(
106
+ chunk.map((m) => ({
107
+ body: m,
108
+ contentType: "v8"
109
+ }))
110
+ );
111
+ }
112
+ return { sent: messages.length - oversized.length, oversized };
78
113
  }
114
+
79
115
  async function failBatchAndPayments(db, batch, paymentRequests, reason) {
80
116
  const prCmds = paymentRequests.filter((p) => p.status !== "REJECTED").map(
81
117
  (p) => updatePaymentRequestStatusCommand(db, {
@@ -287,7 +323,7 @@ class BankProcessBatch extends WorkflowEntrypoint {
287
323
  timestamp: /* @__PURE__ */ new Date()
288
324
  }
289
325
  }));
290
- await pushToQueue$1(
326
+ await pushToQueue(
291
327
  this.env.QUEUE_BUS_QUEUE,
292
328
  eventsToEmit
293
329
  );
@@ -299,7 +335,7 @@ class BankProcessBatch extends WorkflowEntrypoint {
299
335
  }
300
336
  if (!isMockConnector) {
301
337
  await step.do("enqueue authorization email", async () => {
302
- await pushToQueue$1(this.env.NOTIFICATIONS_QUEUE, {
338
+ await pushToQueue(this.env.NOTIFICATIONS_QUEUE, {
303
339
  type: "email",
304
340
  payload: {
305
341
  email: {
@@ -409,18 +445,6 @@ async function fetchBoundedByWindow({
409
445
  }
410
446
  }
411
447
 
412
- async function pushToQueue(queue, message) {
413
- if (!Array.isArray(message)) {
414
- await queue.send(message, { contentType: "v8" });
415
- return;
416
- }
417
- await queue.sendBatch(
418
- message.map((m) => ({
419
- body: m,
420
- contentType: "v8"
421
- }))
422
- );
423
- }
424
448
  class BankSyncAccountPayments extends WorkflowEntrypoint {
425
449
  async run(event, step) {
426
450
  const { accountId } = event.payload;
@@ -429,7 +453,6 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
429
453
  if (!accountId) {
430
454
  throw new NonRetryableError(`Haven't obtained accountId to load.`);
431
455
  }
432
- const deadlineMs = computeWindowDeadline(event.instanceId, accountId);
433
456
  const workflowStartedAt = await step.do(
434
457
  "capture workflow start time",
435
458
  async () => Date.now()
@@ -453,19 +476,6 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
453
476
  if (!account.lastSyncAt) {
454
477
  throw new Error(`lastSyncedAt is not set for account: ${accountId}`);
455
478
  }
456
- if (isSupersededBy(
457
- event.instanceId,
458
- account.lastSyncMetadata?.instanceId,
459
- accountId
460
- )) {
461
- logger.info("sync.superseded", {
462
- accountId,
463
- instanceId: event.instanceId,
464
- supersededBy: account.lastSyncMetadata?.instanceId,
465
- iteration
466
- });
467
- return;
468
- }
469
479
  const lastSyncAtMs = account.lastSyncAt.getTime();
470
480
  const windowMs = await step.do("resolve sync window", async () => {
471
481
  const window = resolveSyncWindow(
@@ -479,15 +489,6 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
479
489
  isCatchUp: window.isCatchUp
480
490
  };
481
491
  });
482
- if (deadlineMs != null && windowMs.dateFromMs >= deadlineMs) {
483
- logger.info("sync.window-elapsed", {
484
- accountId,
485
- instanceId: event.instanceId,
486
- iteration,
487
- deadline: new Date(deadlineMs).toISOString()
488
- });
489
- return;
490
- }
491
492
  const syncWindow = {
492
493
  dateFrom: new Date(windowMs.dateFromMs),
493
494
  dateTo: new Date(windowMs.dateToMs),
@@ -703,10 +704,18 @@ class BankSyncAccountPayments extends WorkflowEntrypoint {
703
704
  seenInstanceId: account.lastSyncMetadata?.instanceId ?? null
704
705
  }).command;
705
706
  if (eventsToEmit.length) {
706
- await pushToQueue(
707
+ const { oversized } = await pushToQueue(
707
708
  this.env.QUEUE_BUS_QUEUE,
708
709
  eventsToEmit
709
710
  );
711
+ for (const { message, bytes } of oversized) {
712
+ logger.error("queue.event-oversized", {
713
+ accountId,
714
+ bytes,
715
+ eventSignal: message.eventSignal,
716
+ bankRefId: message.bankPayment.bankRefId
717
+ });
718
+ }
710
719
  }
711
720
  let syncStateRows;
712
721
  if (createCommands.length) {
@@ -17,8 +17,6 @@ interface BankServiceVariables {
17
17
  DBUCS_TX_AUTH_URI: string;
18
18
  REDIRECT_URI: string;
19
19
  SYNC_WORKFLOW_RESET_AFTER_ITERATIONS: string;
20
- CRON_SYNC_WORKFLOW_DISPATCH: string;
21
- SYNC_DISPATCH_ACCOUNT_IDS: string;
22
20
  [key: string]: string | number | boolean;
23
21
  }
24
22
  declare const BANK_SERVICE_BINDINGS: {
@@ -17,8 +17,6 @@ interface BankServiceVariables {
17
17
  DBUCS_TX_AUTH_URI: string;
18
18
  REDIRECT_URI: string;
19
19
  SYNC_WORKFLOW_RESET_AFTER_ITERATIONS: string;
20
- CRON_SYNC_WORKFLOW_DISPATCH: string;
21
- SYNC_DISPATCH_ACCOUNT_IDS: string;
22
20
  [key: string]: string | number | boolean;
23
21
  }
24
22
  declare const BANK_SERVICE_BINDINGS: {
package/dist/service.d.ts CHANGED
@@ -17,8 +17,6 @@ interface BankServiceVariables {
17
17
  DBUCS_TX_AUTH_URI: string;
18
18
  REDIRECT_URI: string;
19
19
  SYNC_WORKFLOW_RESET_AFTER_ITERATIONS: string;
20
- CRON_SYNC_WORKFLOW_DISPATCH: string;
21
- SYNC_DISPATCH_ACCOUNT_IDS: string;
22
20
  [key: string]: string | number | boolean;
23
21
  }
24
22
  declare const BANK_SERVICE_BINDINGS: {
@@ -7,53 +7,6 @@ import 'jose';
7
7
  import '@develit-io/general-codes';
8
8
  import { createHash } from 'node:crypto';
9
9
 
10
- const DISPATCH_RECOVERY_WINDOW_MS = 5 * 60 * 1e3;
11
- function parseInstanceWindow(instanceId, accountId) {
12
- const prefix = `${accountId}-`;
13
- if (!instanceId.startsWith(prefix)) return -1;
14
- const suffix = instanceId.slice(prefix.length);
15
- if (!/^\d+$/.test(suffix)) return -1;
16
- return Number(suffix);
17
- }
18
- function buildDispatchInstanceId(accountId, nowMs, recoveryWindowMs = DISPATCH_RECOVERY_WINDOW_MS) {
19
- return `${accountId}-${Math.floor(nowMs / recoveryWindowMs)}`;
20
- }
21
- function buildDispatchCreateOptions(instanceId, accountId) {
22
- return {
23
- id: instanceId,
24
- params: { accountId },
25
- // Dispatch mints ~24 instances per account per day and step outputs carry
26
- // bank payloads — the default 30-day retention would pile up billable
27
- // storage for state nobody reads after success.
28
- retention: {
29
- successRetention: "1 day",
30
- errorRetention: "7 days"
31
- }
32
- };
33
- }
34
- function computeWindowDeadline(instanceId, accountId, recoveryWindowMs = DISPATCH_RECOVERY_WINDOW_MS) {
35
- const window = parseInstanceWindow(instanceId, accountId);
36
- if (window < 0) return null;
37
- return (window + 1) * recoveryWindowMs;
38
- }
39
- function isAlreadyExists(err) {
40
- return /already exists/i.test(extractMessage(err));
41
- }
42
- function isInstanceNotFound(err) {
43
- return /instance.*not.?found|not.?found.*instance/i.test(extractMessage(err));
44
- }
45
- function extractMessage(err) {
46
- return err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : "";
47
- }
48
-
49
- function resolveCurrentSyncInstanceId(accountId, recordedInstanceId) {
50
- return recordedInstanceId ?? accountId;
51
- }
52
- function isSupersededBy(myInstanceId, recordedInstanceId, accountId) {
53
- if (recordedInstanceId == null) return false;
54
- return parseInstanceWindow(recordedInstanceId, accountId) > parseInstanceWindow(myInstanceId, accountId);
55
- }
56
-
57
10
  const createPaymentCommand = (db, { payment }) => {
58
11
  return {
59
12
  command: db.insert(tables.payment).values({
@@ -406,4 +359,4 @@ const initiateConnector = async ({
406
359
  }
407
360
  };
408
361
 
409
- export { DISPATCH_RECOVERY_WINDOW_MS as D, getPaymentRequestsByBatchIdQuery as a, getAccountByIdQuery as b, checksum as c, createCredentialsResolver as d, updatePaymentRequestStatusCommand as e, computeWindowDeadline as f, getBatchByIdQuery as g, isSupersededBy as h, initiateConnector as i, createPaymentCommand as j, isAlreadyExists as k, buildDispatchInstanceId as l, encrypt as m, buildDispatchCreateOptions as n, isInstanceNotFound as o, importAesKey as p, resolveCurrentSyncInstanceId as r, upsertBatchCommand as u };
362
+ export { getPaymentRequestsByBatchIdQuery as a, getAccountByIdQuery as b, checksum as c, createCredentialsResolver as d, updatePaymentRequestStatusCommand as e, createPaymentCommand as f, getBatchByIdQuery as g, encrypt as h, initiateConnector as i, importAesKey as j, upsertBatchCommand as u };
@@ -9,53 +9,6 @@ require('jose');
9
9
  require('@develit-io/general-codes');
10
10
  const node_crypto = require('node:crypto');
11
11
 
12
- const DISPATCH_RECOVERY_WINDOW_MS = 5 * 60 * 1e3;
13
- function parseInstanceWindow(instanceId, accountId) {
14
- const prefix = `${accountId}-`;
15
- if (!instanceId.startsWith(prefix)) return -1;
16
- const suffix = instanceId.slice(prefix.length);
17
- if (!/^\d+$/.test(suffix)) return -1;
18
- return Number(suffix);
19
- }
20
- function buildDispatchInstanceId(accountId, nowMs, recoveryWindowMs = DISPATCH_RECOVERY_WINDOW_MS) {
21
- return `${accountId}-${Math.floor(nowMs / recoveryWindowMs)}`;
22
- }
23
- function buildDispatchCreateOptions(instanceId, accountId) {
24
- return {
25
- id: instanceId,
26
- params: { accountId },
27
- // Dispatch mints ~24 instances per account per day and step outputs carry
28
- // bank payloads — the default 30-day retention would pile up billable
29
- // storage for state nobody reads after success.
30
- retention: {
31
- successRetention: "1 day",
32
- errorRetention: "7 days"
33
- }
34
- };
35
- }
36
- function computeWindowDeadline(instanceId, accountId, recoveryWindowMs = DISPATCH_RECOVERY_WINDOW_MS) {
37
- const window = parseInstanceWindow(instanceId, accountId);
38
- if (window < 0) return null;
39
- return (window + 1) * recoveryWindowMs;
40
- }
41
- function isAlreadyExists(err) {
42
- return /already exists/i.test(extractMessage(err));
43
- }
44
- function isInstanceNotFound(err) {
45
- return /instance.*not.?found|not.?found.*instance/i.test(extractMessage(err));
46
- }
47
- function extractMessage(err) {
48
- return err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : "";
49
- }
50
-
51
- function resolveCurrentSyncInstanceId(accountId, recordedInstanceId) {
52
- return recordedInstanceId ?? accountId;
53
- }
54
- function isSupersededBy(myInstanceId, recordedInstanceId, accountId) {
55
- if (recordedInstanceId == null) return false;
56
- return parseInstanceWindow(recordedInstanceId, accountId) > parseInstanceWindow(myInstanceId, accountId);
57
- }
58
-
59
12
  const createPaymentCommand = (db, { payment }) => {
60
13
  return {
61
14
  command: db.insert(paymentDirection.tables.payment).values({
@@ -408,11 +361,7 @@ const initiateConnector = async ({
408
361
  }
409
362
  };
410
363
 
411
- exports.DISPATCH_RECOVERY_WINDOW_MS = DISPATCH_RECOVERY_WINDOW_MS;
412
- exports.buildDispatchCreateOptions = buildDispatchCreateOptions;
413
- exports.buildDispatchInstanceId = buildDispatchInstanceId;
414
364
  exports.checksum = checksum;
415
- exports.computeWindowDeadline = computeWindowDeadline;
416
365
  exports.createCredentialsResolver = createCredentialsResolver;
417
366
  exports.createPaymentCommand = createPaymentCommand;
418
367
  exports.encrypt = encrypt;
@@ -421,9 +370,5 @@ exports.getBatchByIdQuery = getBatchByIdQuery;
421
370
  exports.getPaymentRequestsByBatchIdQuery = getPaymentRequestsByBatchIdQuery;
422
371
  exports.importAesKey = importAesKey;
423
372
  exports.initiateConnector = initiateConnector;
424
- exports.isAlreadyExists = isAlreadyExists;
425
- exports.isInstanceNotFound = isInstanceNotFound;
426
- exports.isSupersededBy = isSupersededBy;
427
- exports.resolveCurrentSyncInstanceId = resolveCurrentSyncInstanceId;
428
373
  exports.updatePaymentRequestStatusCommand = updatePaymentRequestStatusCommand;
429
374
  exports.upsertBatchCommand = upsertBatchCommand;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@develit-services/bank",
3
- "version": "6.0.0",
3
+ "version": "6.1.1",
4
4
  "author": "Develit.io s.r.o.",
5
5
  "type": "module",
6
6
  "exports": {