Appearance
Amounts
Costs and rewards share the same normalized shape: resource id plus amount.
ts
import {
collectAmounts,
normalizeAmounts,
type AmountsInput,
type Cost,
type Reward,
} from "@idlekitjs/economy";Shapes
ts
interface ResourceAmount {
resourceId: ResourceId;
amount: number;
}
type Cost = readonly ResourceAmount[];
type Reward = readonly ResourceAmount[];
type AmountsInput = readonly (readonly [ResourceId, number] | ResourceAmount)[];Tuple syntax:
ts
const cost = [["currency:coins", 100]] as const;Object syntax:
ts
const reward = [{ resourceId: "currency:gems", amount: 5 }] as const;They can be mixed in one AmountsInput.
Normalization
Normalization is consistent across costs and rewards:
- duplicate resource ids are merged by sum;
- zero totals are filtered out;
- negative amounts are invalid;
NaN,Infinityand-Infinityare invalid.
ts
normalizeAmounts([
["currency:coins", 100],
["currency:coins", 25],
]);
// [{ resourceId: "currency:coins", amount: 125 }]normalizeAmounts(input) is strict and throws EconomyError when any line is invalid.
collectAmounts(input) is lenient and returns both valid normalized amounts and invalid lines:
ts
const collected = collectAmounts([
["currency:coins", 10],
["currency:coins", Number.NaN],
]);
collected.amounts; // [{ resourceId: "currency:coins", amount: 10 }]
collected.invalid; // [{ resourceId: "currency:coins", amount: NaN }]Transactions use the lenient path so bad content becomes a TransactionFailure instead of a thrown programming error.
Costs vs rewards
Cost and Reward use the same line shape, but they mean different actions. A cost is consumed before apply. A reward is credited only after the transaction has previewed successfully, paid the cost and run apply.
Rewards cannot be negative. Use a cost to debit a resource.