@nehorai/credits 2.2.0 → 3.1.0
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/adapters/index.cjs +169 -155
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.d.cts +2 -2
- package/dist/adapters/index.d.ts +2 -2
- package/dist/adapters/index.js +169 -155
- package/dist/adapters/index.js.map +1 -1
- package/dist/core/index.cjs +148 -24
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +113 -22
- package/dist/core/index.d.ts +113 -22
- package/dist/core/index.js +137 -22
- package/dist/core/index.js.map +1 -1
- package/dist/index-BrogG0Gc.d.cts +277 -0
- package/dist/index-DOvJES2m.d.ts +277 -0
- package/dist/index.cjs +324 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +311 -69
- package/dist/index.js.map +1 -1
- package/dist/repository/index.cjs +254 -49
- package/dist/repository/index.cjs.map +1 -1
- package/dist/repository/index.d.cts +3 -254
- package/dist/repository/index.d.ts +3 -254
- package/dist/repository/index.js +254 -49
- package/dist/repository/index.js.map +1 -1
- package/dist/sdk/index.cjs +1 -0
- package/dist/sdk/index.cjs.map +1 -1
- package/dist/sdk/index.d.cts +2 -2
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +1 -0
- package/dist/sdk/index.js.map +1 -1
- package/dist/service/index.cjs +42 -19
- package/dist/service/index.cjs.map +1 -1
- package/dist/service/index.d.cts +2 -2
- package/dist/service/index.d.ts +2 -2
- package/dist/service/index.js +42 -19
- package/dist/service/index.js.map +1 -1
- package/dist/{types-3c-IAwZI.d.ts → types-BL3YqxUD.d.ts} +28 -6
- package/dist/{types-MaViK5tD.d.cts → types-C3sxDvNb.d.cts} +29 -6
- package/dist/{types-MaViK5tD.d.ts → types-C3sxDvNb.d.ts} +29 -6
- package/dist/{types-XSjNXO5l.d.cts → types-YLAB8bFk.d.cts} +28 -6
- package/package.json +1 -1
package/dist/core/index.cjs
CHANGED
|
@@ -24,9 +24,11 @@ __export(core_exports, {
|
|
|
24
24
|
CREDIT_AMOUNT_SCALE: () => CREDIT_AMOUNT_SCALE,
|
|
25
25
|
CreditError: () => CreditError,
|
|
26
26
|
CreditErrorCode: () => CreditErrorCode,
|
|
27
|
+
NO_EXPIRED_BACKING_PREFIX: () => NO_EXPIRED_BACKING_PREFIX,
|
|
27
28
|
RESERVATION_STATUSES: () => RESERVATION_STATUSES,
|
|
28
29
|
RESERVED_JOURNAL_KEY_PREFIX: () => RESERVED_JOURNAL_KEY_PREFIX,
|
|
29
30
|
TERMINAL_RESERVATION_STATUSES: () => TERMINAL_RESERVATION_STATUSES,
|
|
31
|
+
allocateExpiredBacking: () => allocateExpiredBacking,
|
|
30
32
|
assertDirectStatusWriteAllowed: () => assertDirectStatusWriteAllowed,
|
|
31
33
|
assertHoldPlaced: () => assertHoldPlaced,
|
|
32
34
|
assertKnownReservationStatus: () => assertKnownReservationStatus,
|
|
@@ -42,9 +44,9 @@ __export(core_exports, {
|
|
|
42
44
|
assertValidStoredAmount: () => assertValidStoredAmount,
|
|
43
45
|
assertValidStoredAmountRaw: () => assertValidStoredAmountRaw,
|
|
44
46
|
assertValidTierBalanceInput: () => assertValidTierBalanceInput,
|
|
45
|
-
attributeExpiredBacking: () => attributeExpiredBacking,
|
|
46
47
|
backedBalanceFloor: () => backedBalanceFloor,
|
|
47
48
|
calculateAvailableCredits: () => calculateAvailableCredits,
|
|
49
|
+
canonicalAmount: () => canonicalAmount,
|
|
48
50
|
cappedBalance: () => cappedBalance,
|
|
49
51
|
classifyDatabaseError: () => classifyDatabaseError,
|
|
50
52
|
commitReservationWithJournal: () => commitReservationWithJournal,
|
|
@@ -61,10 +63,13 @@ __export(core_exports, {
|
|
|
61
63
|
createUnsupportedOperationError: () => createUnsupportedOperationError,
|
|
62
64
|
createUserNotFoundError: () => createUserNotFoundError,
|
|
63
65
|
describePaymentMismatch: () => describePaymentMismatch,
|
|
64
|
-
|
|
66
|
+
expiredBackingPatch: () => expiredBackingPatch,
|
|
65
67
|
genericDeferred: () => genericDeferred,
|
|
66
68
|
getSqlState: () => getSqlState,
|
|
67
69
|
hasPlacedHold: () => hasPlacedHold,
|
|
70
|
+
heldExpiredBacking: () => heldExpiredBacking,
|
|
71
|
+
holdExpiredBacking: () => holdExpiredBacking,
|
|
72
|
+
holdPlacedAtAfter: () => holdPlacedAtAfter,
|
|
68
73
|
isCreditError: () => isCreditError,
|
|
69
74
|
isCreditedOutcome: () => isCreditedOutcome,
|
|
70
75
|
isIdempotencyConflictError: () => isIdempotencyConflictError,
|
|
@@ -80,17 +85,21 @@ __export(core_exports, {
|
|
|
80
85
|
isValidCreditAmount: () => isValidCreditAmount,
|
|
81
86
|
isValidIdempotencyKey: () => isValidIdempotencyKey,
|
|
82
87
|
isWinningOutcome: () => isWinningOutcome,
|
|
88
|
+
multiplyAmount: () => multiplyAmount,
|
|
83
89
|
noopDeferred: () => noopDeferred,
|
|
84
90
|
normalizePaymentRef: () => normalizePaymentRef,
|
|
85
91
|
numericToCents: () => numericToCents,
|
|
86
92
|
planBalanceCap: () => planBalanceCap,
|
|
87
93
|
planBalanceTarget: () => planBalanceTarget,
|
|
88
94
|
planHoldCommit: () => planHoldCommit,
|
|
95
|
+
recordedExpiredBacking: () => recordedExpiredBacking,
|
|
89
96
|
releaseReservationWithJournal: () => releaseReservationWithJournal,
|
|
90
97
|
reserveCreditsForOperation: () => reserveCreditsForOperation,
|
|
91
98
|
sameAmount: () => sameAmount,
|
|
92
99
|
settleExpiredHoldBacking: () => settleExpiredHoldBacking,
|
|
93
100
|
spendableBalance: () => spendableBalance,
|
|
101
|
+
storedAmountCeil: () => storedAmountCeil,
|
|
102
|
+
storedAmountFloor: () => storedAmountFloor,
|
|
94
103
|
storedMonthlyLimit: () => storedMonthlyLimit,
|
|
95
104
|
sumAmounts: () => sumAmounts,
|
|
96
105
|
synchronousDeferred: () => synchronousDeferred,
|
|
@@ -270,6 +279,40 @@ function floatSum(values) {
|
|
|
270
279
|
for (const value of values) total += value;
|
|
271
280
|
return total;
|
|
272
281
|
}
|
|
282
|
+
function multiplyAmount(unit, quantity) {
|
|
283
|
+
const cents = toCents(unit);
|
|
284
|
+
const product = cents === null ? Number.NaN : cents * quantity;
|
|
285
|
+
if (cents === null || cents < 0 || !Number.isSafeInteger(quantity) || quantity < 0 || !Number.isSafeInteger(product) || product > MAX_CENTS) {
|
|
286
|
+
throw new CreditError(
|
|
287
|
+
`Cannot price ${quantity} units at ${unit}: the price must be a non-negative amount exact to ${CREDIT_AMOUNT_SCALE} decimals, the quantity a whole number, and the result at most ${CREDIT_AMOUNT_MAX}`,
|
|
288
|
+
CreditErrorCode.INVALID_AMOUNT,
|
|
289
|
+
{ unit, quantity, max: CREDIT_AMOUNT_MAX, scale: CREDIT_AMOUNT_SCALE }
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return product / 100;
|
|
293
|
+
}
|
|
294
|
+
var FLOAT_NOISE_FLOOR = 1e-6;
|
|
295
|
+
var FLOAT_NOISE_RELATIVE = 64 * Number.EPSILON;
|
|
296
|
+
function floatNoise(value) {
|
|
297
|
+
return Math.max(FLOAT_NOISE_FLOOR, Math.abs(value) * FLOAT_NOISE_RELATIVE);
|
|
298
|
+
}
|
|
299
|
+
function canonicalAmount(value) {
|
|
300
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return value;
|
|
301
|
+
const cents = Math.round(value * 100);
|
|
302
|
+
if (!Number.isSafeInteger(cents)) return value;
|
|
303
|
+
const onGrid = cents / 100 + 0;
|
|
304
|
+
return Math.abs(value - onGrid) < floatNoise(value) ? onGrid : value;
|
|
305
|
+
}
|
|
306
|
+
function storedAmountFloor(value) {
|
|
307
|
+
const canonical = canonicalAmount(value);
|
|
308
|
+
if (!Number.isFinite(canonical) || toCents(canonical) !== null) return canonical;
|
|
309
|
+
return Math.floor(canonical * 100) / 100;
|
|
310
|
+
}
|
|
311
|
+
function storedAmountCeil(value) {
|
|
312
|
+
const canonical = canonicalAmount(value);
|
|
313
|
+
if (!Number.isFinite(canonical) || toCents(canonical) !== null) return canonical;
|
|
314
|
+
return Math.ceil(canonical * 100) / 100;
|
|
315
|
+
}
|
|
273
316
|
function isValidCreditAmount(value) {
|
|
274
317
|
if (typeof value !== "number") return false;
|
|
275
318
|
const cents = toCents(value);
|
|
@@ -325,14 +368,19 @@ function backedBalanceFloor(reserved, bonusCredits) {
|
|
|
325
368
|
function cappedBalance(balance, cap, reserved, bonusCredits) {
|
|
326
369
|
return Math.min(balance, Math.max(cap, backedBalanceFloor(reserved, bonusCredits)));
|
|
327
370
|
}
|
|
328
|
-
function
|
|
329
|
-
|
|
371
|
+
function heldExpiredBacking(balance, stored) {
|
|
372
|
+
if (!(stored !== void 0 && stored > 0)) return 0;
|
|
373
|
+
return Math.max(0, Math.min(stored, balance));
|
|
374
|
+
}
|
|
375
|
+
function spendableBalance(balance, expiredHoldBacking) {
|
|
376
|
+
return sumAmounts(balance, -heldExpiredBacking(balance, expiredHoldBacking));
|
|
330
377
|
}
|
|
331
378
|
function planBalanceTarget(target, reserved, bonusCredits) {
|
|
379
|
+
assertValidBalanceTarget(target, "balance target", { reserved, bonusCredits });
|
|
332
380
|
const balance = Math.max(target, backedBalanceFloor(reserved, bonusCredits));
|
|
333
381
|
return { balance, expiredHoldBacking: sumAmounts(balance, -target) };
|
|
334
382
|
}
|
|
335
|
-
function planBalanceCap(balance, cap, reserved, bonusCredits, expiredHoldBacking
|
|
383
|
+
function planBalanceCap(balance, cap, reserved, bonusCredits, expiredHoldBacking) {
|
|
336
384
|
const spendable = spendableBalance(balance, expiredHoldBacking);
|
|
337
385
|
const target = Math.min(spendable, cap);
|
|
338
386
|
const kept = Math.max(
|
|
@@ -343,8 +391,8 @@ function planBalanceCap(balance, cap, reserved, bonusCredits, expiredHoldBacking
|
|
|
343
391
|
return { balance: next, expiredHoldBacking: Math.max(0, sumAmounts(next, -target)) };
|
|
344
392
|
}
|
|
345
393
|
function settleExpiredHoldBacking(balance, expiredHoldBacking, holdBacking) {
|
|
346
|
-
const held =
|
|
347
|
-
const used = Math.min(held, holdBacking);
|
|
394
|
+
const held = heldExpiredBacking(balance, expiredHoldBacking);
|
|
395
|
+
const used = Math.max(0, Math.min(held, holdBacking));
|
|
348
396
|
return { used, remaining: sumAmounts(held, -used) };
|
|
349
397
|
}
|
|
350
398
|
function planHoldCommit(balance, bonusCredits, expiredHoldBacking, holdBacking, amount) {
|
|
@@ -359,27 +407,83 @@ function planHoldCommit(balance, bonusCredits, expiredHoldBacking, holdBacking,
|
|
|
359
407
|
expiredHoldBacking: backing.remaining
|
|
360
408
|
};
|
|
361
409
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
410
|
+
var NO_EXPIRED_BACKING_PREFIX = {
|
|
411
|
+
holdPlacedAt: "",
|
|
412
|
+
id: "",
|
|
413
|
+
share: 0
|
|
414
|
+
};
|
|
415
|
+
function compareHolds(a, b) {
|
|
416
|
+
if (a.holdPlacedAt !== b.holdPlacedAt) return a.holdPlacedAt < b.holdPlacedAt ? -1 : 1;
|
|
417
|
+
if (a.id === b.id) return 0;
|
|
418
|
+
return a.id < b.id ? -1 : 1;
|
|
419
|
+
}
|
|
420
|
+
function recordedExpiredBacking(hold) {
|
|
421
|
+
const stored = hold.expiredBacking;
|
|
422
|
+
if (typeof stored !== "number" || !Number.isFinite(stored) || stored <= 0) return 0;
|
|
423
|
+
if (!isValidCreditAmount(hold.amount)) return 0;
|
|
424
|
+
return Math.min(storedAmountCeil(stored), hold.amount);
|
|
425
|
+
}
|
|
426
|
+
function allocateExpiredBacking(holds, total) {
|
|
427
|
+
const placed = holds.filter((hold) => hold.holdPlacedAt && isValidCreditAmount(hold.amount)).map((hold) => ({ ...hold, holdPlacedAt: hold.holdPlacedAt })).sort(compareHolds);
|
|
428
|
+
const wanted = Math.max(0, total);
|
|
429
|
+
if (wanted === 0) return { total: 0, frontier: null };
|
|
430
|
+
const recorded = placed.filter((hold) => recordedExpiredBacking(hold) > 0);
|
|
431
|
+
const shares = new Map(recorded.map((hold) => [hold.id, recordedExpiredBacking(hold)]));
|
|
432
|
+
let left = sumAmounts(wanted, ...[...shares.values()].map((share) => -share));
|
|
433
|
+
for (const hold of [...recorded].reverse()) {
|
|
434
|
+
if (left >= 0) break;
|
|
435
|
+
const share = shares.get(hold.id);
|
|
436
|
+
const cut = Math.min(share, -left);
|
|
437
|
+
shares.set(hold.id, sumAmounts(share, -cut));
|
|
438
|
+
left = sumAmounts(left, cut);
|
|
372
439
|
}
|
|
440
|
+
let frontier = NO_EXPIRED_BACKING_PREFIX;
|
|
373
441
|
for (const hold of placed) {
|
|
442
|
+
if (left <= 0) break;
|
|
443
|
+
if (shares.has(hold.id)) continue;
|
|
444
|
+
const share = Math.min(hold.amount, left);
|
|
445
|
+
frontier = { holdPlacedAt: hold.holdPlacedAt, id: hold.id, share };
|
|
446
|
+
left = sumAmounts(left, -share);
|
|
447
|
+
}
|
|
448
|
+
for (const hold of recorded) {
|
|
449
|
+
if (left <= 0) break;
|
|
374
450
|
const share = shares.get(hold.id);
|
|
375
451
|
const added = Math.min(sumAmounts(hold.amount, -share), left);
|
|
376
452
|
shares.set(hold.id, sumAmounts(share, added));
|
|
377
453
|
left = sumAmounts(left, -added);
|
|
378
454
|
}
|
|
379
|
-
|
|
455
|
+
const rewrites = recorded.filter((hold) => shares.get(hold.id) !== hold.expiredBacking).map((hold) => ({ id: hold.id, expiredBacking: shares.get(hold.id) }));
|
|
456
|
+
return { total: wanted, frontier, ...rewrites.length > 0 ? { rewrites } : {} };
|
|
380
457
|
}
|
|
381
|
-
function
|
|
382
|
-
|
|
458
|
+
function holdExpiredBacking(hold, frontier, rewrites) {
|
|
459
|
+
const rewritten = rewrites?.find((rewrite) => rewrite.id === hold.id);
|
|
460
|
+
const recorded = recordedExpiredBacking(
|
|
461
|
+
rewritten ? { ...hold, expiredBacking: rewritten.expiredBacking } : hold
|
|
462
|
+
);
|
|
463
|
+
if (recorded > 0) return recorded;
|
|
464
|
+
if (!frontier || !hold.holdPlacedAt) return 0;
|
|
465
|
+
const order = compareHolds({ holdPlacedAt: hold.holdPlacedAt, id: hold.id }, frontier);
|
|
466
|
+
if (order > 0) return 0;
|
|
467
|
+
return order < 0 ? hold.amount : Math.min(frontier.share, hold.amount);
|
|
468
|
+
}
|
|
469
|
+
function holdPlacedAtAfter(now, frontier) {
|
|
470
|
+
if (!frontier?.holdPlacedAt) return now;
|
|
471
|
+
const earliest = new Date(Date.parse(frontier.holdPlacedAt) + 1).toISOString();
|
|
472
|
+
return now > earliest ? now : earliest;
|
|
473
|
+
}
|
|
474
|
+
function expiredBackingPatch(next, stored) {
|
|
475
|
+
const total = Math.max(0, next.total);
|
|
476
|
+
const patch = {};
|
|
477
|
+
const storedTotal = stored.expiredHoldBacking;
|
|
478
|
+
if (total > 0 || storedTotal !== void 0 && storedTotal !== 0) {
|
|
479
|
+
patch.expiredHoldBacking = total;
|
|
480
|
+
}
|
|
481
|
+
if (total <= 0) {
|
|
482
|
+
if (stored.expiredBackingFrontier) patch.expiredBackingFrontier = null;
|
|
483
|
+
} else if (next.frontier) {
|
|
484
|
+
patch.expiredBackingFrontier = next.frontier;
|
|
485
|
+
}
|
|
486
|
+
return patch;
|
|
383
487
|
}
|
|
384
488
|
function assertValidBalanceTarget(value, field, context) {
|
|
385
489
|
assertRepresentableAmount(value, field, context);
|
|
@@ -392,7 +496,10 @@ function assertValidBalanceTarget(value, field, context) {
|
|
|
392
496
|
}
|
|
393
497
|
}
|
|
394
498
|
function assertValidTierBalanceInput(input, context) {
|
|
395
|
-
if (input.balanceCap === void 0)
|
|
499
|
+
if (input.balanceCap === void 0) {
|
|
500
|
+
if (input.balance !== void 0) assertValidBalanceTarget(input.balance, "balance", context);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
396
503
|
if (input.balance !== void 0) {
|
|
397
504
|
throw new CreditError(
|
|
398
505
|
"A tier update cannot set both balance and balanceCap",
|
|
@@ -912,17 +1019,25 @@ var DEFAULT_CONFIG = {
|
|
|
912
1019
|
}
|
|
913
1020
|
};
|
|
914
1021
|
var currentConfig = DEFAULT_CONFIG;
|
|
1022
|
+
function isOperationCostMap(value) {
|
|
1023
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
1024
|
+
return Object.values(value).every((cost) => isRepresentableAmount(cost) && cost >= 0);
|
|
1025
|
+
}
|
|
915
1026
|
function loadConfigFromEnv() {
|
|
916
1027
|
const envConfig = {};
|
|
917
1028
|
const operationCostsEnv = process.env.CREDITS_OPERATION_COSTS;
|
|
918
1029
|
if (operationCostsEnv) {
|
|
919
1030
|
try {
|
|
920
1031
|
const parsed = JSON.parse(operationCostsEnv);
|
|
921
|
-
if (
|
|
1032
|
+
if (isOperationCostMap(parsed)) {
|
|
922
1033
|
envConfig.operationCosts = {
|
|
923
1034
|
...DEFAULT_CONFIG.operationCosts,
|
|
924
1035
|
...parsed
|
|
925
1036
|
};
|
|
1037
|
+
} else {
|
|
1038
|
+
console.warn(
|
|
1039
|
+
"[Credits Config] Ignoring CREDITS_OPERATION_COSTS: it must be a JSON object whose costs are numbers >= 0, exact to the cent"
|
|
1040
|
+
);
|
|
926
1041
|
}
|
|
927
1042
|
} catch {
|
|
928
1043
|
console.warn("[Credits Config] Failed to parse CREDITS_OPERATION_COSTS env var as JSON");
|
|
@@ -1178,9 +1293,11 @@ async function reserveCreditsForOperation(repository, userId, amount, operationT
|
|
|
1178
1293
|
CREDIT_AMOUNT_SCALE,
|
|
1179
1294
|
CreditError,
|
|
1180
1295
|
CreditErrorCode,
|
|
1296
|
+
NO_EXPIRED_BACKING_PREFIX,
|
|
1181
1297
|
RESERVATION_STATUSES,
|
|
1182
1298
|
RESERVED_JOURNAL_KEY_PREFIX,
|
|
1183
1299
|
TERMINAL_RESERVATION_STATUSES,
|
|
1300
|
+
allocateExpiredBacking,
|
|
1184
1301
|
assertDirectStatusWriteAllowed,
|
|
1185
1302
|
assertHoldPlaced,
|
|
1186
1303
|
assertKnownReservationStatus,
|
|
@@ -1196,9 +1313,9 @@ async function reserveCreditsForOperation(repository, userId, amount, operationT
|
|
|
1196
1313
|
assertValidStoredAmount,
|
|
1197
1314
|
assertValidStoredAmountRaw,
|
|
1198
1315
|
assertValidTierBalanceInput,
|
|
1199
|
-
attributeExpiredBacking,
|
|
1200
1316
|
backedBalanceFloor,
|
|
1201
1317
|
calculateAvailableCredits,
|
|
1318
|
+
canonicalAmount,
|
|
1202
1319
|
cappedBalance,
|
|
1203
1320
|
classifyDatabaseError,
|
|
1204
1321
|
commitReservationWithJournal,
|
|
@@ -1215,10 +1332,13 @@ async function reserveCreditsForOperation(repository, userId, amount, operationT
|
|
|
1215
1332
|
createUnsupportedOperationError,
|
|
1216
1333
|
createUserNotFoundError,
|
|
1217
1334
|
describePaymentMismatch,
|
|
1218
|
-
|
|
1335
|
+
expiredBackingPatch,
|
|
1219
1336
|
genericDeferred,
|
|
1220
1337
|
getSqlState,
|
|
1221
1338
|
hasPlacedHold,
|
|
1339
|
+
heldExpiredBacking,
|
|
1340
|
+
holdExpiredBacking,
|
|
1341
|
+
holdPlacedAtAfter,
|
|
1222
1342
|
isCreditError,
|
|
1223
1343
|
isCreditedOutcome,
|
|
1224
1344
|
isIdempotencyConflictError,
|
|
@@ -1234,17 +1354,21 @@ async function reserveCreditsForOperation(repository, userId, amount, operationT
|
|
|
1234
1354
|
isValidCreditAmount,
|
|
1235
1355
|
isValidIdempotencyKey,
|
|
1236
1356
|
isWinningOutcome,
|
|
1357
|
+
multiplyAmount,
|
|
1237
1358
|
noopDeferred,
|
|
1238
1359
|
normalizePaymentRef,
|
|
1239
1360
|
numericToCents,
|
|
1240
1361
|
planBalanceCap,
|
|
1241
1362
|
planBalanceTarget,
|
|
1242
1363
|
planHoldCommit,
|
|
1364
|
+
recordedExpiredBacking,
|
|
1243
1365
|
releaseReservationWithJournal,
|
|
1244
1366
|
reserveCreditsForOperation,
|
|
1245
1367
|
sameAmount,
|
|
1246
1368
|
settleExpiredHoldBacking,
|
|
1247
1369
|
spendableBalance,
|
|
1370
|
+
storedAmountCeil,
|
|
1371
|
+
storedAmountFloor,
|
|
1248
1372
|
storedMonthlyLimit,
|
|
1249
1373
|
sumAmounts,
|
|
1250
1374
|
synchronousDeferred,
|