@cfxlabsinc/b2b-services
    Preparing search index...
    Index

    Constructors

    Methods

    • Mark a product_quote row as accepted. Stamps accepted_at = now() and surfaces typed errors when the quote isn't acceptable. Once the stamp lands, the row counts toward rolling-window usage (the read path filters WHERE accepted_at IS NOT NULL).

      Single round-trip on the happy path — a guarded UPDATE flips only acceptable rows. On miss we re-SELECT to disambiguate the failure (NOT_FOUND vs ALREADY_ACCEPTED vs EXPIRED vs NOT_OK).

      Idempotency: re-calling on an already-accepted quote returns QUOTE_ALREADY_ACCEPTED. Callers that legitimately replay (e.g. Temporal activity retries) should map that code to success.

      Parameters

      • __namedParameters: { customerId: string; quoteId: string }

      Returns Promise<
          | { ok: true; value: { quoteId: string } }
          | { error: ServiceError; ok: false },
      >

    • Stateless preview — resolves the route + fee template + amount math without writing an audit row and without enforcing usage-window limits. Use this for UI previews and any caller that has no intent to trade.

      When amount is null returns the fee template + go/no-go (route status); no concrete amounts are computed.

      Usage-based matchers (usage30dUsd, etc.) only fire when the caller pre-fetches usage and passes it via input.usage. Estimate does not fetch on its own — that's quote()'s job.

      Parameters

      • input: ResolveInput

      Returns Promise<
          | { ok: true; value: QuoteOutput }
          | { error: PreRouteError | QuoteInvariantError; ok: false },
      >

    • Look up a single audit row by external id, scoped to the caller's customer. The audit table is append-only, so callers get a frozen snapshot of what the resolver decided at quote time — the on-disk row is the source of truth for replay, receipts, and downstream reconciliation.

      Returns null when the row doesn't exist or belongs to a different customer (treated as not-found per the service-pattern convention — no QUOTE_NOT_FOUND error code surfaced).

      Parameters

      • __namedParameters: { customerId: string; id: string }

      Returns Promise<ProductQuote | null>

    • Public read-only entry point for callers (admin dashboards, internal reports) that need rolling-window usage outside the quote() flow. Same query and semantics as the internal pre-fetch — counts every product_quote row stamped with accepted_at, scoped to the entity.

      Parameters

      • args: {
            customerId: string;
            entityId: string;
            entityType: "IDENTITY" | "ORGANIZATION";
            productName:
                | "organization.v1"
                | "identity.v1"
                | "card.physical_card.v1"
                | "card.virtual_card.v1"
                | "deposit.us_cash.v1"
                | "deposit.rtp.v1"
                | "deposit.us_bank_ach.v1"
                | "deposit.ach_credit.v1"
                | "deposit.us_wire.v1"
                | "deposit.swift_wire.v1"
                | "transfer.redemption.v1"
                | "swap.v1"
                | "withdraw.blockchain.v1"
                | "withdraw.ke_bank.v1"
                | "withdraw.ke_momo.v1"
                | "withdraw.mx_bank_spei.v1"
                | "withdraw.swift_wire.v1"
                | "withdraw.tg_momo.v1"
                | "withdraw.us_bank_ach.v1"
                | "withdraw.us_instant.v1"
                | "withdraw.us_wire.v1"
                | "withdraw.ach_pull.v1"
                | "withdraw.us_wire_drawdown.v1"
                | "account.virtual-account.v1"
                | "deposit.*"
                | "withdraw.*";
        }

      Returns Promise<{ aggregate: UsageSnapshot | null; product: UsageSnapshot }>

    • Transactional quote — same math as estimate(), plus per-product and aggregate-domain limit enforcement, plus a write to product_quote for end-to-end audit. Returns the inserted row's external id as quoteId, which downstream consumers (deposit/withdrawal/swap) persist on their own quote rows via db.helpers.productQuoteInternalId({ quoteId }) — a scalar subquery that resolves the externalId string to the int FK at insert time. Service interfaces stay string-only; ints are confined to the DB layer.

      Usage is fetched internally from product_quote (rows where acceptedAt IS NOT NULL count toward the rolling windows). Pass bypassLimits: true to opt out — for documented internal admin flows that have authorization to skip enforcement.

      Auditing scope: a row is written iff a candidate route was picked — i.e. OK, LIMIT_EXCEEDED, or INACTIVE (winning activation rule's value is INACTIVE). Pre-pick failures (PRODUCT_INACTIVE, NO_ELIGIBLE_ROUTE, ENTITY_*, PRODUCT_BLOCKED) do not write.

      Parameters

      • input: ResolveInput

      Returns Promise<
          | { ok: true; value: QuoteOutput & { quoteId: string } }
          | {
              error: PreRouteError | QuoteInvariantError | LimitExceededError;
              ok: false;
          },
      >

    • Re-resolve a pending product_quote against new inputs and patch the row in place — single audit row per logical transaction, mutated as the deposit lifecycle learns more about it. Designed for floating quotes (created with amount: null for a barcode-style placeholder) that need to be settled later with the real amount + recomputed fees

      • a fresh limit check.

      Only the genuinely updatable inputs are exposed on the signature — amount, regionCode, bankId, speed, bypassLimits. The static dimensions (productName, entity id, source/target currency, cashDepositRetailerId, decimalPlaces, idempotencyKey) are read back from the existing row and merged in. Callers can't change which customer / entity / product the quote belongs to, by construction.

      Re-runs the full resolver pipeline, then UPDATEs the row's fee snapshot, route version FKs, outcome, violation, and pinned criteria columns. bypassLimits: true skips usage prefetch + enforcement (e.g. AuthCommit settling the final amount after limits already passed at Auth); otherwise a violation lands as outcome = LIMIT_EXCEEDED + a snapshot and the method returns LIMIT_EXCEEDED.

      Once the row is accepted (accepted_at IS NOT NULL) the DB-level trigger rejects every UPDATE — at that point the row is frozen so rolling-window usage stays stable. Callers see QUOTE_ALREADY_ACCEPTED surfaced from the pre-check below; the trigger backs that guard up.

      Parameters

      • __namedParameters: {
            customerId: string;
            data: {
                amount?: { source: BigNumber } | { target: BigNumber } | null;
                bankId?: string;
                bypassLimits?: boolean;
                regionCode?: string;
                speed?: Speed;
            };
            id: string;
        }

      Returns Promise<
          | { ok: true; value: QuoteOutput & { quoteId: string } }
          | {
              error:
                  | PreRouteError
                  | QuoteInvariantError
                  | LimitExceededError
                  | ServiceError<"QUOTE_NOT_FOUND" | "QUOTE_ALREADY_ACCEPTED">;
              ok: false;
          },
      >