@blamejs/blamejs-shop 0.4.102 → 0.4.103
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/CHANGELOG.md +2 -0
- package/lib/admin.js +50 -0
- package/lib/asset-manifest.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.4.x
|
|
10
10
|
|
|
11
|
+
- v0.4.103 (2026-06-25) — **A return refund that exceeds the order's remaining refundable balance is now refused cleanly, instead of failing at the payment provider.** The direct refund console refuses an over-refund up front: it compares the requested amount against the order's remaining refundable balance and returns a clear 'more than is still refundable' error before any money moves. The provider-backed return (RMA) refund path skipped that check — it issued the RMA's approved amount straight to the payment provider, relying on the provider to reject anything past the captured charge. The result was a late, opaque provider-failure error (and a returns workflow left mid-flight) instead of the clean, actionable refusal the console gives. The RMA refund path now applies the same remaining-balance guard before calling the provider: an approved amount greater than what remains refundable — including a return stacked on top of an earlier partial refund — is refused with the same clear message, the return is left in its received state so the operator can re-approve a corrected amount, and the payment provider is never dialed. A refund of an already-refunded return continues to return the existing conflict response. No configuration changes. **Fixed:** *Return (RMA) refunds honor the order's remaining-balance cap before reaching the payment provider* — A provider-backed return refund issued the return's approved amount directly to Stripe or PayPal with no remaining-balance check, so an amount larger than what was still refundable on the order — for example a return approved for more than the order total, or stacked on top of an earlier partial refund — failed only at the payment provider, surfacing as an opaque provider-failure error rather than the clean refusal the direct refund console returns. The return refund path now compares the approved amount against the order's remaining refundable balance first: an over-cap amount is refused with a clear message, the return stays in its received state so a corrected amount can be re-approved, and the provider is never called. A refund attempt on an already-refunded return still returns the existing conflict response.
|
|
12
|
+
|
|
11
13
|
- v0.4.102 (2026-06-25) — **Vendored framework refreshed to 0.15.26.** Updates the vendored blamejs framework to 0.15.26. The substantive upstream change is a worker-thread handle leak fix in the sandbox primitive: b.sandbox.run now awaits the worker's termination before resolving, so repeatedly running sandboxed code in a long-lived process no longer accumulates leaked MessagePort handles that keep the event loop alive and slow graceful shutdown. The follow-up 0.15.26 build is upstream test-harness correctness only and ships a library byte-for-byte identical to 0.15.25. No runtime API changes and no behavior change for this storefront, which does not run untrusted code through the sandbox primitive; no operator action required. **Changed:** *Vendored framework refreshed to 0.15.26* — Refreshes the vendored blamejs framework to 0.15.26. Upstream 0.15.25 fixes a worker-thread MessagePort leak in the sandbox primitive (b.sandbox.run now waits for the worker to terminate before resolving), and 0.15.26 is a test-harness-only build whose shipped library is identical to 0.15.25. There are no runtime API changes; this storefront does not expose the sandbox primitive on any request path, so there is no operator-visible behavior change and no action required.
|
|
12
14
|
|
|
13
15
|
- v0.4.101 (2026-06-25) — **Bulk cart operations now use the same per-line quantity ceiling as a normal add-to-cart, so a large line is no longer un-bulk-addable or silently reduced.** The cart enforces a per-line quantity ceiling on every add-to-cart. The bulk-operations surface (bulk add and reorder) carried its own copy of that ceiling that had drifted ten times lower than the cart's. The mismatch meant a line legitimately built up to the cart's ceiling through normal add-to-cart could not be added to in bulk (the whole bulk batch was rejected), and a reorder of such a line silently clamped its quantity down instead of preserving it. Bulk operations now source the ceiling directly from the cart primitive, so the two always agree: the same quantity that add-to-cart accepts is accepted in bulk, and a reorder no longer quietly reduces a line. No configuration changes. **Fixed:** *Bulk add and reorder share the cart's per-line quantity ceiling* — Bulk cart operations validated and clamped line quantities against their own ceiling, which was ten times lower than the one the cart applies on a normal add-to-cart. As a result a line whose quantity was legitimately built up to the cart's ceiling could not be bulk-added to — the entire batch was refused — and a reorder of that line silently clamped its quantity down rather than keeping it. The bulk surface now reads the ceiling from the cart primitive itself, so bulk add accepts exactly what add-to-cart accepts and a reorder preserves a line's quantity instead of reducing it.
|
package/lib/admin.js
CHANGED
|
@@ -4784,6 +4784,12 @@ function mount(router, deps) {
|
|
|
4784
4784
|
if (!e) return null;
|
|
4785
4785
|
if (e.code === "RMA_NOT_FOUND") return { status: 404, slug: "return-not-found" };
|
|
4786
4786
|
if (e.code === "RMA_TRANSITION_REFUSED") return { status: 409, slug: "return-transition-refused" };
|
|
4787
|
+
// A refund-cap refusal raised by the provider-refund pre-check (the same
|
|
4788
|
+
// over-refund / nothing-remaining guards the direct console maps to 422)
|
|
4789
|
+
// is the operator's problem — a clean 422, not a 502 provider failure.
|
|
4790
|
+
if (e._refundCode === "over-refund" || e._refundCode === "nothing-remaining") {
|
|
4791
|
+
return { status: 422, slug: e._refundCode };
|
|
4792
|
+
}
|
|
4787
4793
|
return null;
|
|
4788
4794
|
}
|
|
4789
4795
|
|
|
@@ -5173,11 +5179,55 @@ function mount(router, deps) {
|
|
|
5173
5179
|
// stamped at claim time is the operator's own text when supplied, else
|
|
5174
5180
|
// a stable marker; the live provider refund id is on the audit row +
|
|
5175
5181
|
// the JSON response, so it stays reconcilable without a second write.
|
|
5182
|
+
// Claiming first also keeps an already-refunded RMA a clean 409
|
|
5183
|
+
// (the atomic claim refuses it) rather than masking it behind the
|
|
5184
|
+
// amount guard below.
|
|
5176
5185
|
var claimed = await returns.refund(rma.id, {
|
|
5177
5186
|
operator_notes: (body.operator_notes && body.operator_notes.length)
|
|
5178
5187
|
? body.operator_notes
|
|
5179
5188
|
: "provider refund issued",
|
|
5180
5189
|
});
|
|
5190
|
+
|
|
5191
|
+
// Over-refund guard — claim succeeded, but the approved amount must
|
|
5192
|
+
// still fit the order's remaining refundable balance. Mirror the
|
|
5193
|
+
// direct console's over-refund cap BEFORE the provider is dialed, so
|
|
5194
|
+
// an RMA refund_amount_minor that exceeds what remains (already fully
|
|
5195
|
+
// refunded, or stacked past the order total via a prior console/RMA
|
|
5196
|
+
// refund) is refused cleanly (422) instead of failing late at the PSP
|
|
5197
|
+
// as a 502. recordPartialRefund (below) folds each RMA refund into
|
|
5198
|
+
// refundedTotalMinor, so `remaining` reflects prior console AND RMA
|
|
5199
|
+
// refunds alike. On refusal the just-taken claim is RELEASED (back to
|
|
5200
|
+
// received, retryable with a corrected amount) so the RMA never
|
|
5201
|
+
// strands in `refunded` with no money moved. An unset
|
|
5202
|
+
// refund_amount_minor means "refund what remains" — the provider caps
|
|
5203
|
+
// it at the capturable balance, so it proceeds unless nothing remains.
|
|
5204
|
+
// The whole guard runs inside a try/catch that RELEASES the claim on
|
|
5205
|
+
// ANY throw — whether the deliberate over-cap refusal below OR a
|
|
5206
|
+
// transient failure of the balance read itself. Without that, a
|
|
5207
|
+
// refundedTotalMinor read that rejects after the claim moved the RMA to
|
|
5208
|
+
// `refunded` would exit before the provider-call release path, stranding
|
|
5209
|
+
// the RMA behind a 409 with no money moved.
|
|
5210
|
+
try {
|
|
5211
|
+
var rmaAlreadyMinor = await order.refundedTotalMinor(order2.id);
|
|
5212
|
+
var rmaRemainingMinor = (Number(order2.grand_total_minor) || 0) - rmaAlreadyMinor;
|
|
5213
|
+
if (rmaRemainingMinor <= 0 ||
|
|
5214
|
+
(rma.refund_amount_minor != null && rma.refund_amount_minor > rmaRemainingMinor)) {
|
|
5215
|
+
var capErr = (rmaRemainingMinor <= 0)
|
|
5216
|
+
? new TypeError("This order is already fully refunded — nothing remains to refund.")
|
|
5217
|
+
: new TypeError("That RMA refund of " + pricing.format(rma.refund_amount_minor, order2.currency) +
|
|
5218
|
+
" is more than the " + pricing.format(rmaRemainingMinor, order2.currency) +
|
|
5219
|
+
" still refundable on this order.");
|
|
5220
|
+
capErr._refundCode = (rmaRemainingMinor <= 0) ? "nothing-remaining" : "over-refund";
|
|
5221
|
+
throw capErr;
|
|
5222
|
+
}
|
|
5223
|
+
} catch (guardErr) {
|
|
5224
|
+
// Release the just-taken claim (back to received, retryable) so
|
|
5225
|
+
// neither the over-cap refusal nor a transient read failure leaves
|
|
5226
|
+
// the RMA stranded in `refunded`. No money has moved yet.
|
|
5227
|
+
try { await returns.releaseRefundClaim(rma.id); }
|
|
5228
|
+
catch (_relErr) { /* drop-silent — guardErr below is the actionable one */ }
|
|
5229
|
+
throw guardErr;
|
|
5230
|
+
}
|
|
5181
5231
|
var idem = "rma-refund:" + rma.id;
|
|
5182
5232
|
var refund;
|
|
5183
5233
|
var providerRefund;
|
package/lib/asset-manifest.json
CHANGED
package/package.json
CHANGED