@blamejs/blamejs-shop 0.4.103 → 0.4.105
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 +4 -0
- package/README.md +1 -1
- package/SECURITY.md +11 -8
- package/lib/affiliates.js +2 -2
- package/lib/api-keys.js +1 -1
- package/lib/asset-manifest.json +1 -1
- package/lib/auto-discount.js +4 -4
- package/lib/auto-replenish.js +1 -1
- package/lib/backorder.js +2 -2
- package/lib/carrier-accounts.js +1 -1
- package/lib/cart-bulk-ops.js +1 -1
- package/lib/cart.js +2 -2
- package/lib/catalog.js +3 -3
- package/lib/click-and-collect.js +2 -2
- package/lib/customer-merge.js +2 -2
- package/lib/customer-surveys.js +1 -1
- package/lib/cycle-counting.js +1 -1
- package/lib/dropship-forwarding.js +1 -1
- package/lib/dunning.js +1 -1
- package/lib/email-campaigns.js +4 -4
- package/lib/giftcards.js +6 -6
- package/lib/inventory-allocations.js +1 -1
- package/lib/inventory-audits.js +1 -1
- package/lib/inventory-receive.js +2 -2
- package/lib/inventory-writeoffs.js +1 -1
- package/lib/invoice-renderer.js +1 -1
- package/lib/knowledge-base.js +1 -1
- package/lib/loyalty-redemption.js +3 -3
- package/lib/loyalty.js +410 -195
- package/lib/operator-approvals.js +1 -1
- package/lib/operator-help-center.js +1 -1
- package/lib/order-exchanges.js +1 -1
- package/lib/order-export.js +4 -4
- package/lib/payment-retries.js +2 -2
- package/lib/pick-lists.js +1 -1
- package/lib/plan-changes.js +1 -1
- package/lib/preorder.js +4 -4
- package/lib/print-on-demand.js +1 -1
- package/lib/print-queue.js +2 -2
- package/lib/purchase-orders.js +1 -1
- package/lib/push-notifications.js +2 -2
- package/lib/quotes.js +7 -7
- package/lib/referrals.js +3 -3
- package/lib/reorder-reminders.js +1 -1
- package/lib/returns.js +4 -4
- package/lib/seller-signup.js +1 -1
- package/lib/shipping-insurance.js +2 -2
- package/lib/sms-dispatcher.js +2 -2
- package/lib/split-shipments.js +1 -1
- package/lib/stock-alerts.js +1 -1
- package/lib/stock-transfers.js +4 -4
- package/lib/subscription-gifts.js +2 -2
- package/lib/suggestion-box.js +2 -2
- package/lib/webhooks.js +10 -3
- package/lib/wishlist-alerts.js +1 -1
- package/lib/wishlist-digest.js +1 -1
- package/package.json +1 -1
|
@@ -737,7 +737,7 @@ function create(opts) {
|
|
|
737
737
|
"executed_at = ?2, result_json = ?3, updated_at = ?2 WHERE id = ?4 AND status = 'approved'",
|
|
738
738
|
[executedBy, ts, resultJson, requestId],
|
|
739
739
|
);
|
|
740
|
-
if (
|
|
740
|
+
if (!b.sql.casWon(claim).won) {
|
|
741
741
|
var raced = new Error("operatorApprovals.markExecuted: request " +
|
|
742
742
|
JSON.stringify(requestId) + " is no longer approved — execution refused");
|
|
743
743
|
raced.code = "APPROVAL_EXECUTE_RACE";
|
|
@@ -844,7 +844,7 @@ function create(opts) {
|
|
|
844
844
|
"VALUES (?1, ?2, ?3, ?4, ?5)",
|
|
845
845
|
[b.uuid.v7(), slug, operatorId, vote, ts],
|
|
846
846
|
);
|
|
847
|
-
var changed = inserted && (
|
|
847
|
+
var changed = inserted && (b.sql.casWon(inserted).won);
|
|
848
848
|
if (changed) {
|
|
849
849
|
var col = vote === "helpful" ? "helpful_count" : "not_helpful_count";
|
|
850
850
|
await query(
|
package/lib/order-exchanges.js
CHANGED
|
@@ -300,7 +300,7 @@ function create(opts) {
|
|
|
300
300
|
"WHERE id = ?3 AND status = 'pending'",
|
|
301
301
|
[approverId, ts, exchangeId],
|
|
302
302
|
);
|
|
303
|
-
if (
|
|
303
|
+
if (!b.sql.casWon(claim).won) {
|
|
304
304
|
var refused = new Error(
|
|
305
305
|
"order-exchanges: transition 'approveExchange' refused from state '" +
|
|
306
306
|
existing.status + "' (lost the race to a concurrent transition)"
|
package/lib/order-export.js
CHANGED
|
@@ -600,7 +600,7 @@ function create(opts) {
|
|
|
600
600
|
"WHERE id = ?2 AND status = ?3",
|
|
601
601
|
[ts, exportId, row.status],
|
|
602
602
|
);
|
|
603
|
-
if (
|
|
603
|
+
if (!b.sql.casWon(upd).won) {
|
|
604
604
|
var raced = new Error("order-export.cancelExport: " + exportId +
|
|
605
605
|
" changed state concurrently (no longer " + row.status + ") — refused");
|
|
606
606
|
raced.code = "ORDER_EXPORT_CANCEL_REFUSED";
|
|
@@ -664,7 +664,7 @@ function create(opts) {
|
|
|
664
664
|
"WHERE id = ?2 AND status = ?3",
|
|
665
665
|
[ts, exportId, row.status],
|
|
666
666
|
);
|
|
667
|
-
if (
|
|
667
|
+
if (!b.sql.casWon(upd).won) {
|
|
668
668
|
var raced = new Error("order-export.markExportRunning: " + exportId +
|
|
669
669
|
" changed state concurrently (no longer " + row.status + ") — refused");
|
|
670
670
|
raced.code = "ORDER_EXPORT_START_REFUSED";
|
|
@@ -703,7 +703,7 @@ function create(opts) {
|
|
|
703
703
|
"byte_size = ?2, file_sha3_512 = ?3, completed_at = ?4 WHERE id = ?5 AND status = ?6",
|
|
704
704
|
[input.row_count, input.byte_size, input.file_sha3_512, ts, input.export_id, row.status],
|
|
705
705
|
);
|
|
706
|
-
if (
|
|
706
|
+
if (!b.sql.casWon(upd).won) {
|
|
707
707
|
var raced = new Error("order-export.markExportComplete: " + input.export_id +
|
|
708
708
|
" changed state concurrently (no longer " + row.status + ") — refused");
|
|
709
709
|
raced.code = "ORDER_EXPORT_COMPLETE_REFUSED";
|
|
@@ -744,7 +744,7 @@ function create(opts) {
|
|
|
744
744
|
"WHERE id = ?3 AND status = ?4",
|
|
745
745
|
[errorText, ts, input.export_id, row.status],
|
|
746
746
|
);
|
|
747
|
-
if (
|
|
747
|
+
if (!b.sql.casWon(upd).won) {
|
|
748
748
|
var raced = new Error("order-export.markExportFailed: " + input.export_id +
|
|
749
749
|
" changed state concurrently (no longer " + row.status + ") — refused");
|
|
750
750
|
raced.code = "ORDER_EXPORT_FAIL_REFUSED";
|
package/lib/payment-retries.js
CHANGED
|
@@ -602,7 +602,7 @@ function create(opts) {
|
|
|
602
602
|
"WHERE id = ?1 AND status = 'active' AND next_retry_at = ?2",
|
|
603
603
|
[enrollment.id, enrollment.next_retry_at],
|
|
604
604
|
);
|
|
605
|
-
if (
|
|
605
|
+
if (!b.sql.casWon(claim).won) continue; // another tick claimed it
|
|
606
606
|
|
|
607
607
|
// Pre-charge prep. The claim above nulled next_retry_at to take
|
|
608
608
|
// the row out of the due set; a throw HERE (a missing policy /
|
|
@@ -707,7 +707,7 @@ function create(opts) {
|
|
|
707
707
|
"WHERE id = ?2 AND status = 'active' AND attempt_count = ?3",
|
|
708
708
|
[nextAttempt, enrollment.id, attemptCount],
|
|
709
709
|
);
|
|
710
|
-
if (
|
|
710
|
+
if (!b.sql.casWon(outcomeClaim).won) {
|
|
711
711
|
return await _refetchEnrollment(enrollment.id);
|
|
712
712
|
}
|
|
713
713
|
|
package/lib/pick-lists.js
CHANGED
|
@@ -565,7 +565,7 @@ function create(opts) {
|
|
|
565
565
|
"WHERE id = ?2 AND status IN ('generated', 'in_progress')",
|
|
566
566
|
[ts, listId],
|
|
567
567
|
);
|
|
568
|
-
if (
|
|
568
|
+
if (!b.sql.casWon(claim).won) {
|
|
569
569
|
// Lost the race (or the row left an eligible state between the
|
|
570
570
|
// read and the claim). Surface the same terminal-state refusal
|
|
571
571
|
// a sequential caller would see — the shipments belong to the
|
package/lib/plan-changes.js
CHANGED
|
@@ -485,7 +485,7 @@ function create(opts) {
|
|
|
485
485
|
"WHERE id = ?2 AND status = 'pending'",
|
|
486
486
|
[now, row.id],
|
|
487
487
|
);
|
|
488
|
-
if (
|
|
488
|
+
if (!b.sql.casWon(claim).won) continue; // another run claimed it
|
|
489
489
|
|
|
490
490
|
await query(
|
|
491
491
|
"UPDATE subscriptions SET plan_id = ?1, updated_at = ?2 WHERE id = ?3",
|
package/lib/preorder.js
CHANGED
|
@@ -265,7 +265,7 @@ function create(opts) {
|
|
|
265
265
|
"WHERE id = ?2 AND status = 'active'",
|
|
266
266
|
[ts, reservation.id],
|
|
267
267
|
);
|
|
268
|
-
if (
|
|
268
|
+
if (!b.sql.casWon(claim).won) {
|
|
269
269
|
// Lost the race — a concurrent converter already claimed this
|
|
270
270
|
// reservation. Skip the side-effect; the winner mints the order.
|
|
271
271
|
return { won: false, orderId: null };
|
|
@@ -436,7 +436,7 @@ function create(opts) {
|
|
|
436
436
|
"AND (max_units_available IS NULL OR units_reserved + ?1 <= max_units_available)",
|
|
437
437
|
[input.quantity, ts, input.campaign_slug],
|
|
438
438
|
);
|
|
439
|
-
if (
|
|
439
|
+
if (!b.sql.casWon(claim).won) {
|
|
440
440
|
throw new TypeError("preorder.reserve: would exceed max_units_available " +
|
|
441
441
|
"(cap=" + campaign.max_units_available + ", reserved=" + campaign.units_reserved +
|
|
442
442
|
", requested=" + input.quantity + ")");
|
|
@@ -529,7 +529,7 @@ function create(opts) {
|
|
|
529
529
|
"cancel_reason = ?2 WHERE id = ?3 AND status = 'active'",
|
|
530
530
|
[ts, reason, reservation.id],
|
|
531
531
|
);
|
|
532
|
-
if (
|
|
532
|
+
if (!b.sql.casWon(claim).won) {
|
|
533
533
|
throw new TypeError("preorder.cancelReservation: reservation " +
|
|
534
534
|
JSON.stringify(reservation.id) + " was already cancelled or converted concurrently");
|
|
535
535
|
}
|
|
@@ -621,7 +621,7 @@ function create(opts) {
|
|
|
621
621
|
"WHERE slug = ?2 AND status = 'active'",
|
|
622
622
|
[ts, input.slug],
|
|
623
623
|
);
|
|
624
|
-
if (
|
|
624
|
+
if (!b.sql.casWon(claim).won) {
|
|
625
625
|
throw new TypeError("preorder.launchCampaign: campaign " +
|
|
626
626
|
JSON.stringify(input.slug) + " was already launched concurrently");
|
|
627
627
|
}
|
package/lib/print-on-demand.js
CHANGED
|
@@ -332,7 +332,7 @@ function create(opts) {
|
|
|
332
332
|
" WHERE id = ?" + p + " AND status = ?" + (p + 1),
|
|
333
333
|
params,
|
|
334
334
|
);
|
|
335
|
-
if (
|
|
335
|
+
if (!b.sql.casWon(upd).won) {
|
|
336
336
|
var raced = new Error("print-on-demand: fulfillment " + fulfillmentId +
|
|
337
337
|
" changed state concurrently (no longer " + current.status + ") — transition refused");
|
|
338
338
|
raced.code = "POD_FULFILLMENT_TRANSITION_REFUSED";
|
package/lib/print-queue.js
CHANGED
|
@@ -374,7 +374,7 @@ function create(opts) {
|
|
|
374
374
|
"claimed_at = ?2 WHERE id = ?3 AND status = 'queued'",
|
|
375
375
|
[input.station_id, ts, jobId],
|
|
376
376
|
);
|
|
377
|
-
if (upd.
|
|
377
|
+
if (!b.sql.casWon(upd).won) return null;
|
|
378
378
|
return await _getRow(jobId);
|
|
379
379
|
},
|
|
380
380
|
|
|
@@ -452,7 +452,7 @@ function create(opts) {
|
|
|
452
452
|
[ts, reason, jobId],
|
|
453
453
|
);
|
|
454
454
|
var failed = await _getRow(jobId);
|
|
455
|
-
if (
|
|
455
|
+
if (!b.sql.casWon(upd).won) {
|
|
456
456
|
// Another caller already transitioned this job out of
|
|
457
457
|
// in_progress. Return its current state; do not re-insert a
|
|
458
458
|
// retry row (that's the exactly-once side-effect we're
|
package/lib/purchase-orders.js
CHANGED
|
@@ -643,7 +643,7 @@ function create(opts) {
|
|
|
643
643
|
[cAdd, ts, cLine.id, cPrior],
|
|
644
644
|
);
|
|
645
645
|
}
|
|
646
|
-
if (
|
|
646
|
+
if (!b.sql.casWon(lineClaim).won) {
|
|
647
647
|
// Lost the race on this line (a concurrent receipt already
|
|
648
648
|
// advanced it past the value we observed) — roll back the
|
|
649
649
|
// line claims we already won this call, self-targeting the
|
|
@@ -823,7 +823,7 @@ function create(opts) {
|
|
|
823
823
|
"failed_at = ?2 WHERE id = ?3 AND status = 'queued'",
|
|
824
824
|
["provider_unavailable_at_dispatch", now, row.id],
|
|
825
825
|
);
|
|
826
|
-
if (
|
|
826
|
+
if (!b.sql.casWon(lostFail).won) continue;
|
|
827
827
|
advanced.push(await _getNotification(row.id));
|
|
828
828
|
continue;
|
|
829
829
|
}
|
|
@@ -834,7 +834,7 @@ function create(opts) {
|
|
|
834
834
|
"WHERE id = ?2 AND status = 'queued'",
|
|
835
835
|
[now, row.id],
|
|
836
836
|
);
|
|
837
|
-
if (
|
|
837
|
+
if (!b.sql.casWon(claimed).won) continue;
|
|
838
838
|
advanced.push(await _getNotification(row.id));
|
|
839
839
|
}
|
|
840
840
|
return advanced;
|
package/lib/quotes.js
CHANGED
|
@@ -683,7 +683,7 @@ function create(opts) {
|
|
|
683
683
|
[shipping, tax, total, currency, validUntil, operatorNotes,
|
|
684
684
|
delivery, payment, ts, quoteId, fromStatus],
|
|
685
685
|
);
|
|
686
|
-
if (
|
|
686
|
+
if (!b.sql.casWon(claim).won) {
|
|
687
687
|
var raced = new Error("quotes." + verbLabel + ": refused — quote " + quoteId +
|
|
688
688
|
" is no longer in the " + fromStatus + " state (settled by a concurrent call)");
|
|
689
689
|
raced.code = "QUOTE_TRANSITION_REFUSED";
|
|
@@ -880,7 +880,7 @@ function create(opts) {
|
|
|
880
880
|
"accepted_by_customer = ?2, updated_at = ?1 WHERE id = ?3 AND status = 'responded'",
|
|
881
881
|
[ts, acceptedBy, quoteId],
|
|
882
882
|
);
|
|
883
|
-
if (
|
|
883
|
+
if (!b.sql.casWon(claim).won) {
|
|
884
884
|
var raced = new Error("quotes.customerAccept: refused — quote " + quoteId +
|
|
885
885
|
" is no longer responded (accepted, rejected, or withdrawn by a concurrent call)");
|
|
886
886
|
raced.code = "QUOTE_TRANSITION_REFUSED";
|
|
@@ -913,7 +913,7 @@ function create(opts) {
|
|
|
913
913
|
"reject_reason = ?2, updated_at = ?1 WHERE id = ?3 AND status = 'responded'",
|
|
914
914
|
[ts, reason, quoteId],
|
|
915
915
|
);
|
|
916
|
-
if (
|
|
916
|
+
if (!b.sql.casWon(claim).won) {
|
|
917
917
|
var raced = new Error("quotes.customerReject: refused — quote " + quoteId +
|
|
918
918
|
" is no longer responded (settled by a concurrent call)");
|
|
919
919
|
raced.code = "QUOTE_TRANSITION_REFUSED";
|
|
@@ -954,7 +954,7 @@ function create(opts) {
|
|
|
954
954
|
"cancel_reason = ?2, updated_at = ?1 WHERE id = ?3 AND status IN ('requested', 'responded')",
|
|
955
955
|
[ts, reason, quoteId],
|
|
956
956
|
);
|
|
957
|
-
if (
|
|
957
|
+
if (!b.sql.casWon(claim).won) {
|
|
958
958
|
var raced = new Error("quotes.cancelQuote: refused — quote " + quoteId +
|
|
959
959
|
" is no longer cancellable (accepted, rejected, or settled by a concurrent call)");
|
|
960
960
|
raced.code = "QUOTE_TRANSITION_REFUSED";
|
|
@@ -998,7 +998,7 @@ function create(opts) {
|
|
|
998
998
|
"WHERE id = ?2 AND status = 'accepted'",
|
|
999
999
|
[ts, quoteId],
|
|
1000
1000
|
);
|
|
1001
|
-
if (
|
|
1001
|
+
if (!b.sql.casWon(claim).won) {
|
|
1002
1002
|
var raced = new Error("quotes.convertToOrder: refused — quote " + quoteId +
|
|
1003
1003
|
" is no longer accepted (converted by a concurrent call)");
|
|
1004
1004
|
raced.code = "QUOTE_TRANSITION_REFUSED";
|
|
@@ -1326,7 +1326,7 @@ function create(opts) {
|
|
|
1326
1326
|
"AND valid_until IS NOT NULL AND valid_until <= ?3",
|
|
1327
1327
|
[asOf, r.rows[i].id, asOf],
|
|
1328
1328
|
);
|
|
1329
|
-
if (
|
|
1329
|
+
if (b.sql.casWon(claim).won) expired += 1;
|
|
1330
1330
|
else skipped += 1;
|
|
1331
1331
|
}
|
|
1332
1332
|
return { scanned: r.rows.length, expired: expired, skipped: skipped };
|
|
@@ -1361,7 +1361,7 @@ function create(opts) {
|
|
|
1361
1361
|
"UPDATE quotes SET status = 'expired', updated_at = ?1 WHERE id = ?2 AND status = 'responded'",
|
|
1362
1362
|
[asOf, quoteId],
|
|
1363
1363
|
);
|
|
1364
|
-
if (
|
|
1364
|
+
if (!b.sql.casWon(claim).won) {
|
|
1365
1365
|
var raced = new Error("quotes.markExpired: refused — quote " + quoteId +
|
|
1366
1366
|
" is no longer responded (settled by a concurrent call)");
|
|
1367
1367
|
raced.code = "QUOTE_TRANSITION_REFUSED";
|
package/lib/referrals.js
CHANGED
|
@@ -409,7 +409,7 @@ function create(opts) {
|
|
|
409
409
|
"WHERE id = ?3 AND signed_up_customer_id IS NULL",
|
|
410
410
|
[ts, customerId, invitationId],
|
|
411
411
|
);
|
|
412
|
-
if (
|
|
412
|
+
if (!b.sql.casWon(claim).won) continue;
|
|
413
413
|
var updated = await query(
|
|
414
414
|
"SELECT id, referral_code_id, signed_up_customer_id, signed_up_at, reward_status " +
|
|
415
415
|
"FROM referral_invitations WHERE id = ?1",
|
|
@@ -466,7 +466,7 @@ function create(opts) {
|
|
|
466
466
|
"WHERE id = ?3 AND first_purchase_at IS NULL",
|
|
467
467
|
[ts, orderId, inv.id],
|
|
468
468
|
);
|
|
469
|
-
if (
|
|
469
|
+
if (!b.sql.casWon(claim).won) {
|
|
470
470
|
// Lost the claim — another concurrent call already recorded the
|
|
471
471
|
// first qualifying purchase. Re-read so the loser reports the
|
|
472
472
|
// winner's pinned values, not a stale snapshot.
|
|
@@ -554,7 +554,7 @@ function create(opts) {
|
|
|
554
554
|
"WHERE id = ?2 AND reversed_at IS NULL",
|
|
555
555
|
[ts, inv.id],
|
|
556
556
|
);
|
|
557
|
-
if (
|
|
557
|
+
if (!b.sql.casWon(claim).won) return null;
|
|
558
558
|
// Decrement the referrer's leaderboard count, floored at zero (the
|
|
559
559
|
// `> 0` guard plus the schema CHECK keep it non-negative even if the
|
|
560
560
|
// count drifted).
|
package/lib/reorder-reminders.js
CHANGED
|
@@ -536,7 +536,7 @@ function create(opts) {
|
|
|
536
536
|
"WHERE id = ?2 AND status = 'active' AND next_remind_at = ?3",
|
|
537
537
|
[nextRemindAt, enrollment.id, enrollment.next_remind_at],
|
|
538
538
|
);
|
|
539
|
-
if (
|
|
539
|
+
if (!b.sql.casWon(claim).won) {
|
|
540
540
|
// Another tick already advanced this row's cursor (or it was
|
|
541
541
|
// cancelled between the SELECT and now) — it owns the send.
|
|
542
542
|
// Skip without dispatching so the customer is nudged once.
|
package/lib/returns.js
CHANGED
|
@@ -348,7 +348,7 @@ function create(opts) {
|
|
|
348
348
|
"updated_at = ?3 WHERE id = ?5 AND status = 'pending'",
|
|
349
349
|
[input.refund_amount_minor, refundCurrency, ts, operatorNotes, rmaId],
|
|
350
350
|
);
|
|
351
|
-
if (
|
|
351
|
+
if (!b.sql.casWon(upd).won) {
|
|
352
352
|
var current = await this._currentStatus(rmaId);
|
|
353
353
|
_assertTransition(current, "approve");
|
|
354
354
|
var raced = new Error("returns: approve already claimed for rma " + rmaId);
|
|
@@ -376,7 +376,7 @@ function create(opts) {
|
|
|
376
376
|
"updated_at = ?3 WHERE id = ?4 AND status = 'approved'",
|
|
377
377
|
[rxAt, operatorNotes, ts, rmaId],
|
|
378
378
|
);
|
|
379
|
-
if (
|
|
379
|
+
if (!b.sql.casWon(upd).won) {
|
|
380
380
|
var current = await this._currentStatus(rmaId);
|
|
381
381
|
_assertTransition(current, "markReceived");
|
|
382
382
|
var raced = new Error("returns: markReceived already claimed for rma " + rmaId);
|
|
@@ -412,7 +412,7 @@ function create(opts) {
|
|
|
412
412
|
"updated_at = ?3 WHERE id = ?4 AND status = 'received'",
|
|
413
413
|
[rfAt, operatorNotes, ts, rmaId],
|
|
414
414
|
);
|
|
415
|
-
if (
|
|
415
|
+
if (!b.sql.casWon(upd).won) {
|
|
416
416
|
// Either the RMA doesn't exist or it isn't in 'received'. Read the
|
|
417
417
|
// current status to surface the right typed refusal (RMA_NOT_FOUND
|
|
418
418
|
// vs RMA_TRANSITION_REFUSED) so the caller's mapping is unchanged.
|
|
@@ -444,7 +444,7 @@ function create(opts) {
|
|
|
444
444
|
"updated_at = ?1 WHERE id = ?2 AND status = 'refunded'",
|
|
445
445
|
[ts, rmaId],
|
|
446
446
|
);
|
|
447
|
-
return
|
|
447
|
+
return b.sql.casWon(upd).won;
|
|
448
448
|
},
|
|
449
449
|
|
|
450
450
|
reject: async function (rmaId, input) {
|
package/lib/seller-signup.js
CHANGED
|
@@ -874,7 +874,7 @@ function create(opts) {
|
|
|
874
874
|
"OR (status = 'approved' AND vendor_slug IS NULL AND approved_at = ?4))",
|
|
875
875
|
[ts, approvedBy, applicationId, app.approved_at],
|
|
876
876
|
);
|
|
877
|
-
if (
|
|
877
|
+
if (!b.sql.casWon(claim).won) {
|
|
878
878
|
var raced = new Error(
|
|
879
879
|
"seller-signup.approveApplication: refused — application is not in an approvable state (concurrent approval)"
|
|
880
880
|
);
|
|
@@ -621,7 +621,7 @@ function create(opts) {
|
|
|
621
621
|
"resolved_at = ?2, updated_at = ?2 WHERE id = ?3 AND status = 'filed'",
|
|
622
622
|
[input.payout_minor, now, claimId],
|
|
623
623
|
);
|
|
624
|
-
if (
|
|
624
|
+
if (!b.sql.casWon(approvedUpd).won) {
|
|
625
625
|
var racedApprove = await _getClaimRow(claimId);
|
|
626
626
|
throw new TypeError("shippingInsurance.markClaimApproved: claim " + claimId +
|
|
627
627
|
" is " + (racedApprove ? racedApprove.status : "gone") +
|
|
@@ -658,7 +658,7 @@ function create(opts) {
|
|
|
658
658
|
"resolved_at = ?2, updated_at = ?2 WHERE id = ?3 AND status = 'filed'",
|
|
659
659
|
[denialReason, now, claimId],
|
|
660
660
|
);
|
|
661
|
-
if (
|
|
661
|
+
if (!b.sql.casWon(deniedUpd).won) {
|
|
662
662
|
var racedDeny = await _getClaimRow(claimId);
|
|
663
663
|
throw new TypeError("shippingInsurance.markClaimDenied: claim " + claimId +
|
|
664
664
|
" is " + (racedDeny ? racedDeny.status : "gone") +
|
package/lib/sms-dispatcher.js
CHANGED
|
@@ -880,7 +880,7 @@ function create(opts) {
|
|
|
880
880
|
"failed_at = ?2 WHERE id = ?3 AND status = 'queued'",
|
|
881
881
|
["no_provider_at_dispatch", now, row.id],
|
|
882
882
|
);
|
|
883
|
-
if (
|
|
883
|
+
if (!b.sql.casWon(lostFail).won) continue;
|
|
884
884
|
advanced.push(await _getMessage(row.id));
|
|
885
885
|
continue;
|
|
886
886
|
}
|
|
@@ -892,7 +892,7 @@ function create(opts) {
|
|
|
892
892
|
"sent_at = ?2 WHERE id = ?3 AND status = 'queued'",
|
|
893
893
|
[providerSlug, now, row.id],
|
|
894
894
|
);
|
|
895
|
-
if (
|
|
895
|
+
if (!b.sql.casWon(claimed).won) continue;
|
|
896
896
|
advanced.push(await _getMessage(row.id));
|
|
897
897
|
}
|
|
898
898
|
return advanced;
|
package/lib/split-shipments.js
CHANGED
|
@@ -616,7 +616,7 @@ function create(opts) {
|
|
|
616
616
|
"WHERE id = ?2 AND status = 'proposed'",
|
|
617
617
|
[ts, input.plan.id],
|
|
618
618
|
);
|
|
619
|
-
if (
|
|
619
|
+
if (!b.sql.casWon(claim).won) {
|
|
620
620
|
// Lost the race (or the row was concurrently cancelled/executed
|
|
621
621
|
// between the read above and the claim). Re-read so the message
|
|
622
622
|
// reflects the row's actual current status.
|
package/lib/stock-alerts.js
CHANGED
|
@@ -623,7 +623,7 @@ function create(opts) {
|
|
|
623
623
|
"WHERE id = ?3 AND notified_at IS NULL",
|
|
624
624
|
[now, _hashUnsubToken(rowUnsubToken), row.id],
|
|
625
625
|
);
|
|
626
|
-
if (!claim ||
|
|
626
|
+
if (!claim || !b.sql.casWon(claim).won) continue;
|
|
627
627
|
row.notified_at = now;
|
|
628
628
|
row.unsubscribe_token = rowUnsubToken;
|
|
629
629
|
fired.push(row);
|
package/lib/stock-transfers.js
CHANGED
|
@@ -497,7 +497,7 @@ function create(opts) {
|
|
|
497
497
|
"carrier = ?2, tracking_number = ?3 WHERE id = ?4 AND status = 'open'",
|
|
498
498
|
[shippedAt, carrier, tracking, id],
|
|
499
499
|
);
|
|
500
|
-
if (
|
|
500
|
+
if (!b.sql.casWon(claim).won) {
|
|
501
501
|
throw new TypeError("stock-transfers.markShipped: transfer " + id +
|
|
502
502
|
" is no longer open (shipped by a concurrent call)");
|
|
503
503
|
}
|
|
@@ -602,7 +602,7 @@ function create(opts) {
|
|
|
602
602
|
"WHERE id = ?2 AND status IN ('shipped', 'in_transit')",
|
|
603
603
|
[receivedAt, id],
|
|
604
604
|
);
|
|
605
|
-
if (
|
|
605
|
+
if (!b.sql.casWon(claim).won) {
|
|
606
606
|
throw new TypeError("stock-transfers.markReceived: transfer " + id +
|
|
607
607
|
" is no longer shipped or in_transit (received by a concurrent call)");
|
|
608
608
|
}
|
|
@@ -667,7 +667,7 @@ function create(opts) {
|
|
|
667
667
|
"WHERE id = ?2 AND status = 'received'",
|
|
668
668
|
[ts, id],
|
|
669
669
|
);
|
|
670
|
-
if (
|
|
670
|
+
if (!b.sql.casWon(claim).won) {
|
|
671
671
|
throw new TypeError("stock-transfers.reconcile: transfer " + id +
|
|
672
672
|
" is no longer received (already reconciled by a concurrent call) — refusing to double-credit");
|
|
673
673
|
}
|
|
@@ -756,7 +756,7 @@ function create(opts) {
|
|
|
756
756
|
"WHERE id = ?2 AND status IN ('open', 'shipped', 'in_transit', 'received')",
|
|
757
757
|
[reason, id],
|
|
758
758
|
);
|
|
759
|
-
if (
|
|
759
|
+
if (!b.sql.casWon(claim).won) {
|
|
760
760
|
throw new TypeError("stock-transfers.markException: transfer " + id +
|
|
761
761
|
" is no longer in a non-terminal state (settled by a concurrent call)");
|
|
762
762
|
}
|
|
@@ -476,7 +476,7 @@ function create(opts) {
|
|
|
476
476
|
"WHERE id = ?2 AND status IN ('pending','delivered')",
|
|
477
477
|
[now, existing.id],
|
|
478
478
|
);
|
|
479
|
-
if (
|
|
479
|
+
if (!b.sql.casWon(claim).won) {
|
|
480
480
|
// Lost the race — re-read so we surface the actual post-race status.
|
|
481
481
|
var after = await _getRaw(existing.id);
|
|
482
482
|
var raceErr = new Error(
|
|
@@ -557,7 +557,7 @@ function create(opts) {
|
|
|
557
557
|
"WHERE id = ?3 AND status IN ('pending','delivered')",
|
|
558
558
|
[ts, reason, giftId],
|
|
559
559
|
);
|
|
560
|
-
if (
|
|
560
|
+
if (!b.sql.casWon(r).won) {
|
|
561
561
|
var after = await _getRaw(giftId);
|
|
562
562
|
var raceErr = new Error(
|
|
563
563
|
"subscriptionGifts.cancelGift: gift status changed to '" +
|
package/lib/suggestion-box.js
CHANGED
|
@@ -602,7 +602,7 @@ function create(opts) {
|
|
|
602
602
|
"VALUES (?1, ?2, ?3, ?4, ?5)",
|
|
603
603
|
[voteId, sid, sessionHash, vote, ts],
|
|
604
604
|
);
|
|
605
|
-
var changed = ins && (
|
|
605
|
+
var changed = ins && b.sql.casWon(ins).won;
|
|
606
606
|
if (!changed) {
|
|
607
607
|
// Existing vote — surface "already voted" so the client can
|
|
608
608
|
// render a UI confirmation rather than silently no-op.
|
|
@@ -768,7 +768,7 @@ function create(opts) {
|
|
|
768
768
|
"WHERE id = ?3 AND status <> 'duplicate' AND archived_at IS NULL",
|
|
769
769
|
[cid, ts, sid],
|
|
770
770
|
);
|
|
771
|
-
if (
|
|
771
|
+
if (!b.sql.casWon(claim).won) {
|
|
772
772
|
// Lost the race (a concurrent linkDuplicates already flipped the
|
|
773
773
|
// source) — or it was archived between the read and the claim.
|
|
774
774
|
// Re-read to distinguish: a row now in 'duplicate' is the
|
package/lib/webhooks.js
CHANGED
|
@@ -589,9 +589,16 @@ function create(opts) {
|
|
|
589
589
|
"WHERE id = ?2 AND next_retry_at IS NOT NULL AND next_retry_at <= ?3 AND delivered_at IS NULL",
|
|
590
590
|
[now + RETRY_CLAIM_LEASE_MS, row.id, now],
|
|
591
591
|
);
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
592
|
+
// casWon inspects only top-level count fields (rowCount / changes /
|
|
593
|
+
// affectedRows). This module accepts an injected opts.query that may be
|
|
594
|
+
// a raw-D1 runner reporting the count under a nested meta.changes, so
|
|
595
|
+
// surface that as a top-level rowCount before the verdict — otherwise
|
|
596
|
+
// a successful claim with only meta.changes would be read as
|
|
597
|
+
// indeterminate and abort the tick, leaving the delivery merely leased.
|
|
598
|
+
if (claim && claim.rowCount == null && claim.meta && typeof claim.meta.changes === "number") {
|
|
599
|
+
claim.rowCount = claim.meta.changes;
|
|
600
|
+
}
|
|
601
|
+
if (!b.sql.casWon(claim).won) continue; // lost the claim to a concurrent tick
|
|
595
602
|
var d = await _attempt(row.id, endpoint, row.event_type, row.payload_json);
|
|
596
603
|
attempted.push(d);
|
|
597
604
|
}
|
package/lib/wishlist-alerts.js
CHANGED
|
@@ -650,7 +650,7 @@ function create(opts) {
|
|
|
650
650
|
+ ")",
|
|
651
651
|
[id, customerId, policySlug, sku, now, dedupeSince, capActive, weekSince, capValue],
|
|
652
652
|
);
|
|
653
|
-
return
|
|
653
|
+
return b.sql.casWon(r).won;
|
|
654
654
|
}
|
|
655
655
|
|
|
656
656
|
// Walk every wishlist entry that has a non-null variant_id. Whole-
|
package/lib/wishlist-digest.js
CHANGED
|
@@ -929,7 +929,7 @@ function create(opts) {
|
|
|
929
929
|
"WHERE id = ?2 AND status = 'active' AND next_dispatch_at = ?3",
|
|
930
930
|
[nextDispatchAt, enrollment.id, observedNext],
|
|
931
931
|
);
|
|
932
|
-
if (
|
|
932
|
+
if (!b.sql.casWon(claim).won) {
|
|
933
933
|
// Another tick already claimed this period — don't double-send.
|
|
934
934
|
continue;
|
|
935
935
|
}
|
package/package.json
CHANGED