@pwngh/economy-lab
    Preparing search index...

    Interface SagaStore

    Tracks each multi-step payout (a "saga") as it moves through its states. A background sweep picks up sagas that are due and pushes each one to its next state.

    interface SagaStore {
        advance(
            id: string,
            from: "SUBMITTED" | "SETTLED" | "FAILED" | "REQUESTED" | "RESERVED",
            to: "SUBMITTED" | "SETTLED" | "FAILED" | "REQUESTED" | "RESERVED",
            patch: Partial<Saga>,
            options?: CallOptions,
        ): Promise<boolean>;
        claimDue(
            now: number,
            limit: number,
            options?: CallOptions,
        ): Promise<readonly Saga[]>;
        deadLetter(
            id: string,
            reason: string,
            options?: CallOptions,
        ): Promise<void>;
        findByProviderRef(
            providerRef: string,
            options?: CallOptions,
        ): Promise<Saga | null>;
        lastPayoutAt(userId: string, options?: CallOptions): Promise<number | null>;
        list(
            options?: CallOptions & {
                states?: readonly (
                    "SUBMITTED"
                    | "SETTLED"
                    | "FAILED"
                    | "REQUESTED"
                    | "RESERVED"
                )[];
            },
        ): AsyncIterable<Saga>;
        load(id: string, options?: CallOptions): Promise<Saga | null>;
        open(saga: Saga, options?: CallOptions): Promise<void>;
    }
    Index
    • Moves a saga from from to to and applies patch, only if it is still in from. Returns false and changes nothing if it already moved on, so two sweeps can't both advance it.

      Parameters

      • id: string
      • from: "SUBMITTED" | "SETTLED" | "FAILED" | "REQUESTED" | "RESERVED"
      • to: "SUBMITTED" | "SETTLED" | "FAILED" | "REQUESTED" | "RESERVED"
      • patch: Partial<Saga>
      • Optionaloptions: CallOptions

      Returns Promise<boolean>

    • Grabs up to limit due sagas, each locked so concurrent sweeps take different ones. Only RESERVED and SUBMITTED rows are candidates: a row still REQUESTED means its opening transaction crashed partway, and the sweep skips it on purpose.

      Parameters

      • now: number
      • limit: number
      • Optionaloptions: CallOptions

      Returns Promise<readonly Saga[]>

    • Sets the saga FAILED and records reason, whatever state it held — no compare-and-set, and no posting. This is the operator door (exposed over the HTTP store adapter); the payout sweep fails a saga via advance paired with the reserve-release posting in one transaction. An unknown id changes nothing.

      Parameters

      • id: string
      • reason: string
      • Optionaloptions: CallOptions

      Returns Promise<void>

    • If more than one saga ever carried this provider reference, the newest updatedAt wins.

      Parameters

      Returns Promise<Saga | null>

    • The max updatedAt over all of the user's sagas in any state, enforcing config.payoutMinIntervalMs. updatedAt only advances, so the max never undershoots the latest request; null when the user has no sagas, so a first request is always allowed.

      Parameters

      Returns Promise<number | null>

    • Every saga newest updatedAt first; ties on updatedAt break by id descending. states narrows to exactly those states (an empty list yields nothing); the SQL engines push the filter down.

      Parameters

      • Optionaloptions: CallOptions & {
            states?: readonly (
                "SUBMITTED"
                | "SETTLED"
                | "FAILED"
                | "REQUESTED"
                | "RESERVED"
            )[];
        }

      Returns AsyncIterable<Saga>

    • Upserts by saga.id. Called inside requestPayout's transaction with the reserve posting, so an open saga without its reserve never survives.

      Parameters

      Returns Promise<void>