@fire-spark/core 0.3.5 → 0.4.1

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.
Files changed (3) hide show
  1. package/dist/index.d.ts +22 -17
  2. package/dist/index.js +522 -501
  3. package/package.json +3 -3
package/dist/index.d.ts CHANGED
@@ -408,7 +408,7 @@ type ApplyRedeemInput = {
408
408
  reward_id: string;
409
409
  /**
410
410
  * Reward units to redeem (integer ≥ 1). With `payment_id` it is
411
- * informational: `amount` and `points` already cover every unit.
411
+ * informational: `amount` already covers every unit.
412
412
  */
413
413
  quantity: number;
414
414
  /** 0–1, compounded per unit over the remaining value. */
@@ -423,19 +423,17 @@ type ApplyRedeemInput = {
423
423
  /** Root line to discount; omit to discount the whole order (prorated). */
424
424
  line_uid?: string;
425
425
  /**
426
- * Points / balance: the merchant `REDEMPTION` payment that pays `amount`
427
- * (a tender, not a discount). Requires `amount` and `points`. Redeems
428
- * with the same `payment_id` share one tender (`details.rewards[]`).
426
+ * Reward paid as a tender (voucher, balance…, not a discount): the
427
+ * merchant `REDEMPTION` payment that pays `amount`. Requires `amount`.
428
+ * Redeems with the same `payment_id` share one tender
429
+ * (`details.rewards[]`).
429
430
  */
430
431
  payment_id?: string;
431
432
  /**
432
- * Total money the points cover for the whole entry (all `quantity`
433
+ * Total money the reward covers for the whole entry (all `quantity`
433
434
  * units, not per unit); trimmed to total − tip − delivery.
434
435
  */
435
436
  amount?: number;
436
- /** Total points spent for the whole entry (not per unit). */
437
- points?: number;
438
- program?: string;
439
437
  /** Provider of the REDEMPTION payment (default `firespark`). */
440
438
  provider?: PaymentProvider;
441
439
  /** ISO datetime with offset; validation fails once it has passed. */
@@ -517,9 +515,9 @@ declare class Order {
517
515
  emptyOrder(): void;
518
516
  /**
519
517
  * Appends a redeem to `line_uid` (root line) or to the order. Steps keep
520
- * the order in which redeems were applied. With `payment_id` (points /
521
- * balance) it is not a discount: `amount` and `points` are totals of the
522
- * whole entry (every unit, not per unit) and `quantity` is informational.
518
+ * the order in which redeems were applied. With `payment_id` (voucher,
519
+ * balance…) it is not a discount: `amount` is the total of the whole
520
+ * entry (every unit, not per unit) and `quantity` is informational.
523
521
  * Every redeem with the same `payment_id` is paid by one REDEMPTION
524
522
  * tender whose `details.rewards[]` lists them; their summed amount is
525
523
  * capped at total − tip − delivery (D15, D18, D19).
@@ -528,9 +526,8 @@ declare class Order {
528
526
  /**
529
527
  * Removes `quantity` units of `reward_id` from `line_uid` or the order,
530
528
  * latest applied first. Removing more units than applied clears them all
531
- * (and the REDEMPTION tender of a points / balance redeem). A points /
532
- * balance entry that keeps some units keeps the same share of its
533
- * `amount` and `points`.
529
+ * (and the REDEMPTION tender of a payment redeem). A payment redeem that
530
+ * keeps some units keeps the same share of its `amount`.
534
531
  */
535
532
  removeRedeem(input: RemoveRedeemInput): void;
536
533
  private rememberLogScope;
@@ -544,7 +541,7 @@ declare class Order {
544
541
  cancelOrder(): Promise<void>;
545
542
  /**
546
543
  * Reopens this placed, unpaid order: the server voids every payment
547
- * (REDEMPTION points released), cancels it as `VOIDED` and opens a new
544
+ * (REDEMPTION rewards released), cancels it as `VOIDED` and opens a new
548
545
  * `OPEN` order with the same content. This instance is closed afterwards;
549
546
  * replace it with the returned `Order` (same HTTP options and listener).
550
547
  *
@@ -786,6 +783,12 @@ declare const isDeviceCharged: (tender: {
786
783
  }) => boolean;
787
784
  /** Most a REDEMPTION can cover: order total − tip − delivery (D18). */
788
785
  declare const redemptionCap: (order: Pick<Order$1, "lines" | "totals">) => number;
786
+ /**
787
+ * Trims payment redeems in application order so their sum fits the cap.
788
+ * Discount redeems are left untouched. The last trimmed amount is whatever
789
+ * room remains, so the kept amounts sum to at most `cap`.
790
+ */
791
+ declare const clampPaymentRedeems: (redeem: readonly OrderRedeem[], cap: number, _currency: string) => OrderRedeem[];
789
792
  type SimpleTenderPayment = {
790
793
  id?: string;
791
794
  type?: PaymentTenderInput["method"];
@@ -856,7 +859,7 @@ declare const listMenusStream: (scope?: StorefrontMenuScope, options?: ListMenus
856
859
  //#endregion
857
860
  //#region src/services/payments.d.ts
858
861
  type ListPaymentsOptions = ServiceHttpOptions & {
859
- /** Keep `REDEMPTION` payments (points / balance) for redeem flows. */
862
+ /** Keep `REDEMPTION` payments (vouchers, balance…) for redeem flows. */
860
863
  includeRedemptions?: boolean;
861
864
  };
862
865
  /**
@@ -1145,6 +1148,8 @@ declare class RulesEngine {
1145
1148
  private assertBoolean;
1146
1149
  private assertCurrency;
1147
1150
  private assertEnum;
1151
+ private customerAge;
1152
+ private customerDate;
1148
1153
  private assertAbsoluteDate;
1149
1154
  private assertRelativeDate;
1150
1155
  private assertRecurringDate;
@@ -1319,4 +1324,4 @@ declare const validateCardholderName: (value: string) => CardholderNameError | n
1319
1324
  */
1320
1325
  declare const cardPreviewGroups: (value: string) => CardPreviewSlot[][];
1321
1326
  //#endregion
1322
- export { type ApplyRedeemInput, type AuthConfigureOptions, CARD_BRANDS, type CardBrand, type CardBrandSpec, type CardCvcError, type CardExpiry, type CardExpiryError, type CardNumberError, type CardPreviewSlot, type CardholderNameError, type CreateOrderOptions, type CreateSessionOptions, type CustomizationPath, type CustomizationSession, DEFAULT_RECOMMENDATION_TYPES, type ExchangeOptions, type FailedCharge, type FlatMenuCategory, type GroupDisplayType, type IdBuilder, type ListMenusStreamOptions, type ListPaymentsOptions, type Menu, type MenuCategoryNode, type MenuLookup, type MilestoneSteps, type MilestoneTrackItem, type ModifierControlType, type ModifierCtx, type ModifierGroupCtx, type NestedMenuCategory, Order, type OrderCustomerSource, type OrderDraft, type OrderIssue, type OrderIssueCode, type OrderLineDiff, type OrderLineIssue, type OrderLineIssueCode, type OrderScope, OrderSyncPendingError, OrderValidationError, type OrderValidationResult, type PayIntentOptions, type PayIntentResult, type PayOptions, type PaymentCardBrand, type PaymentProgressEvent, type PaymentProgressListener, type PaymentRunOptions, type PaymentSessionOptions, type PricingModifier, type Product, type ProductCtx, type QuantitiesByPath, type RecommendationType, RecurringDateCron, type RemoveRedeemInput, type ReorderOrderOptions, type ResetOptions, type ReversalOutcome, type ReverseAllOptions, RulesEngine, type ScheduleWindow, type SelectionStatus, type SelectionsByPath, type SerializedError, type ServiceHttpOptions, type SimpleTenderPayment, type Snapshot, type StorefrontAccessToken, type StorefrontErrorDetails, StorefrontHttpError, type TrackWorkflow, type ValidateOptions, type ValidateOrderAgainstMenuInput, type Variant, type VariantGroup, type VariantGroupCtx, type VariantOptionCtx, type VariantSelection, type VerifyWebhookSignatureInput, type VisitedState, addLines, auth, buildCustomerSnapshot, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, orderPaymentRedeems, parseExpiry, paymentMatchesClientConditions, recomputeRedemptions, recomputeTotals, redemptionCap, remainingAmount, removeLine, replaceLine, resolveCheckout, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, stripRedemptionLines, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
1327
+ export { type ApplyRedeemInput, type AuthConfigureOptions, CARD_BRANDS, type CardBrand, type CardBrandSpec, type CardCvcError, type CardExpiry, type CardExpiryError, type CardNumberError, type CardPreviewSlot, type CardholderNameError, type CreateOrderOptions, type CreateSessionOptions, type CustomizationPath, type CustomizationSession, DEFAULT_RECOMMENDATION_TYPES, type ExchangeOptions, type FailedCharge, type FlatMenuCategory, type GroupDisplayType, type IdBuilder, type ListMenusStreamOptions, type ListPaymentsOptions, type Menu, type MenuCategoryNode, type MenuLookup, type MilestoneSteps, type MilestoneTrackItem, type ModifierControlType, type ModifierCtx, type ModifierGroupCtx, type NestedMenuCategory, Order, type OrderCustomerSource, type OrderDraft, type OrderIssue, type OrderIssueCode, type OrderLineDiff, type OrderLineIssue, type OrderLineIssueCode, type OrderScope, OrderSyncPendingError, OrderValidationError, type OrderValidationResult, type PayIntentOptions, type PayIntentResult, type PayOptions, type PaymentCardBrand, type PaymentProgressEvent, type PaymentProgressListener, type PaymentRunOptions, type PaymentSessionOptions, type PricingModifier, type Product, type ProductCtx, type QuantitiesByPath, type RecommendationType, RecurringDateCron, type RemoveRedeemInput, type ReorderOrderOptions, type ResetOptions, type ReversalOutcome, type ReverseAllOptions, RulesEngine, type ScheduleWindow, type SelectionStatus, type SelectionsByPath, type SerializedError, type ServiceHttpOptions, type SimpleTenderPayment, type Snapshot, type StorefrontAccessToken, type StorefrontErrorDetails, StorefrontHttpError, type TrackWorkflow, type ValidateOptions, type ValidateOrderAgainstMenuInput, type Variant, type VariantGroup, type VariantGroupCtx, type VariantOptionCtx, type VariantSelection, type VerifyWebhookSignatureInput, type VisitedState, addLines, auth, buildCustomerSnapshot, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, clampPaymentRedeems, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, orderPaymentRedeems, parseExpiry, paymentMatchesClientConditions, recomputeRedemptions, recomputeTotals, redemptionCap, remainingAmount, removeLine, replaceLine, resolveCheckout, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, stripRedemptionLines, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DIGITAL_COLLECT_AT, PARTIAL_APPROVAL_ERROR, activeIntent, amountTolerance, createAttemptReference, createPaymentError, currencyDecimals, currentIntent, defaultReversalFor, discountRedeems, groupPaymentRedeems, isDeliveryFee, isPaymentError, isPaymentRedeem, isRealPaymentMethod, isRealPaymentMethod as isRealPaymentMethod$1, isTenderSettled, isTipFee, liveTenders, memoryPaymentStorage, missingDeviceFields, orderPaymentRedeems, orderPaymentRedeems as orderPaymentRedeems$1, paymentRedeemsCoverTotal, resolvePaymentPolicy, resolveProviderEnvironment, roundTo, scopedPaymentStorage, taxBreakdown, toChargeAmount, withTerminalLock } from "@fire-spark/payments";
1
+ import { DIGITAL_COLLECT_AT, PARTIAL_APPROVAL_ERROR, activeIntent, amountTolerance, createAttemptReference, createPaymentError, currentIntent, defaultReversalFor, discountRedeems, groupPaymentRedeems, isDeliveryFee, isPaymentError, isPaymentRedeem, isRealPaymentMethod, isRealPaymentMethod as isRealPaymentMethod$1, isTenderSettled, isTipFee, liveTenders, memoryPaymentStorage, missingDeviceFields, money, moneyNumber, moneyZero, orderPaymentRedeems, orderPaymentRedeems as orderPaymentRedeems$1, paymentRedeemsCoverTotal, resolvePaymentPolicy, resolveProviderEnvironment, scopedPaymentStorage, taxBreakdown, toChargeAmount, withTerminalLock } from "@fire-spark/payments";
2
2
  import advancedFormat from "dayjs/plugin/advancedFormat.js";
3
3
  import isBetween from "dayjs/plugin/isBetween.js";
4
4
  import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js";
@@ -3465,40 +3465,42 @@ const isDeviceCharged = (tender) => {
3465
3465
  /** Most a REDEMPTION can cover: order total − tip − delivery (D18). */
3466
3466
  const redemptionCap = (order) => {
3467
3467
  const primaryOnly = order.lines.filter((line) => line.parent_uid == null).reduce((sum, line) => {
3468
- return isTipFee(line) || isDeliveryFee(line) ? sum + line.group_total : sum;
3469
- }, 0);
3470
- const decimals = currencyDecimals(order.totals.currency);
3471
- return Math.max(roundTo(order.totals.total - primaryOnly, decimals), 0);
3468
+ if (!(isTipFee(line) || isDeliveryFee(line))) return sum;
3469
+ return sum.plus(line.group_total);
3470
+ }, moneyZero());
3471
+ const cap = money(order.totals.total).minus(primaryOnly);
3472
+ if (cap.lt(0)) return 0;
3473
+ return moneyNumber(cap);
3472
3474
  };
3473
3475
  /**
3474
3476
  * Room left for order-level payment redeems: the D18 cap minus what the
3475
3477
  * payment redeems kept on lines already cover.
3476
3478
  */
3477
3479
  const orderRedeemCap = (order) => {
3478
- const used = orderPaymentRedeems({ lines: order.lines }).reduce((sum, item) => sum + (item.amount ?? 0), 0);
3479
- const decimals = currencyDecimals(order.totals.currency);
3480
- return Math.max(roundTo(redemptionCap(order) - used, decimals), 0);
3480
+ const used = orderPaymentRedeems({ lines: order.lines }).reduce((sum, item) => {
3481
+ return sum.plus(item.amount ?? 0);
3482
+ }, moneyZero());
3483
+ const left = money(redemptionCap(order)).minus(used);
3484
+ if (left.lt(0)) return 0;
3485
+ return moneyNumber(left);
3481
3486
  };
3482
3487
  /**
3483
- * Trims payment redeems in application order so their sum fits the cap;
3484
- * points shrink in proportion. Discount redeems are left untouched.
3488
+ * Trims payment redeems in application order so their sum fits the cap.
3489
+ * Discount redeems are left untouched. The last trimmed amount is whatever
3490
+ * room remains, so the kept amounts sum to at most `cap`.
3485
3491
  */
3486
- const clampPaymentRedeems = (redeem, cap, currency) => {
3487
- const decimals = currencyDecimals(currency);
3488
- let left = cap;
3492
+ const clampPaymentRedeems = (redeem, cap, _currency) => {
3493
+ let left = money(cap);
3489
3494
  return redeem.flatMap((item) => {
3490
3495
  if (!isPaymentRedeem(item)) return [item];
3491
- const amount = item.amount ?? 0;
3492
- const fits = Math.max(roundTo(Math.min(amount, left), decimals), 0);
3493
- left = roundTo(left - fits, decimals);
3494
- if (fits <= 0) return [];
3495
- if (fits + amountTolerance(currency) >= amount) return [item];
3496
- const ratio = amount > 0 ? fits / amount : 0;
3497
- const points = roundTo((item.points ?? 0) * ratio, 0);
3496
+ const amount = money(item.amount ?? 0);
3497
+ const fits = amount.lt(left) ? amount : left;
3498
+ left = left.minus(fits);
3499
+ if (fits.lte(0)) return [];
3500
+ if (fits.eq(amount)) return [item];
3498
3501
  return [{
3499
3502
  ...item,
3500
- amount: fits,
3501
- points
3503
+ amount: moneyNumber(fits)
3502
3504
  }];
3503
3505
  });
3504
3506
  };
@@ -3887,14 +3889,15 @@ const chargedTenders = (intents) => {
3887
3889
  };
3888
3890
  /** Settled tenders plus PENDING `confirm_after_inject`, order currency. */
3889
3891
  const coveredAmount = (intents) => {
3890
- return chargedTenders(intents).reduce((sum, tender) => {
3891
- return sum + tender.amount.total;
3892
- }, 0);
3892
+ return moneyNumber(chargedTenders(intents).reduce((sum, tender) => {
3893
+ return sum.plus(tender.amount.total);
3894
+ }, moneyZero()));
3893
3895
  };
3894
3896
  const remainingAmount = (order) => {
3895
- const decimals = currencyDecimals(order.totals.currency);
3896
- const left = order.totals.total - coveredAmount(order.payment_intents);
3897
- return Math.max(roundTo(left, decimals), 0);
3897
+ const covered = money(coveredAmount(order.payment_intents));
3898
+ const left = money(order.totals.total).minus(covered);
3899
+ if (left.lt(0)) return 0;
3900
+ return moneyNumber(left);
3898
3901
  };
3899
3902
  const isPlaced = (order) => order.status !== "OPEN";
3900
3903
  /** Orchestrator failures carry the charge-currency amount, not the order's. */
@@ -4024,12 +4027,9 @@ var PaymentSession = class {
4024
4027
  const conversion = await this.chargeAmount(payment, amount, server);
4025
4028
  const config = record(payment.config);
4026
4029
  const methodConfig = record(payment.method.config);
4027
- const share = order.totals.total > 0 ? amount / order.totals.total : 1;
4028
- const decimals = currencyDecimals(order.totals.currency);
4029
- const taxes = taxBreakdown(order.lines, {
4030
- share,
4031
- decimals
4032
- });
4030
+ const total = order.totals.total;
4031
+ const share = moneyNumber(total > 0 ? money(amount).div(total) : money(1));
4032
+ const taxes = taxBreakdown(order.lines, { share });
4033
4033
  const info = order.customer.customer_info;
4034
4034
  const customer = {
4035
4035
  document: info.document_number ?? null,
@@ -4722,17 +4722,14 @@ const emptyTotals = (currency = "USD") => {
4722
4722
  //#region src/order/redemptions.ts
4723
4723
  const ORDER_KEY = "ORDER";
4724
4724
  const buildPaymentRedeem = (input) => {
4725
- const { reward_id, quantity, payment_id, amount, points } = input;
4725
+ const { reward_id, quantity, payment_id, amount } = input;
4726
4726
  if (amount === void 0 || !(amount > 0)) throw new Error("Redeem with payment_id requires amount > 0");
4727
- if (points === void 0 || !(points >= 0)) throw new Error("Redeem with payment_id requires points ≥ 0");
4728
4727
  const redeem = {
4729
4728
  reward_id,
4730
4729
  quantity,
4731
4730
  payment_id,
4732
4731
  amount
4733
4732
  };
4734
- redeem.points = points;
4735
- if (input.program !== void 0) redeem.program = input.program;
4736
4733
  if (input.expires_at !== void 0) redeem.expires_at = input.expires_at;
4737
4734
  return redeem;
4738
4735
  };
@@ -4766,12 +4763,10 @@ const keepUnits = (item, rest) => {
4766
4763
  };
4767
4764
  const ratio = new Big(rest).div(item.quantity);
4768
4765
  const amount = new Big(item.amount ?? 0).times(ratio).round(6).toNumber();
4769
- const points = new Big(item.points ?? 0).times(ratio).round(0).toNumber();
4770
4766
  return {
4771
4767
  ...item,
4772
4768
  quantity: rest,
4773
- amount,
4774
- points
4769
+ amount
4775
4770
  };
4776
4771
  };
4777
4772
  /**
@@ -5094,7 +5089,7 @@ const cloneOrder = (order) => {
5094
5089
  };
5095
5090
  const redeemSignature$1 = (items) => {
5096
5091
  return items.map((item) => {
5097
- return `${`${item.reward_id}:${item.quantity}:${item.payment_id ?? ""}`}:${`${item.amount ?? ""}:${item.points ?? ""}`}:${`${item.discount_rate ?? ""}:${item.discount_amount ?? ""}`}`;
5092
+ return `${`${item.reward_id}:${item.quantity}:${item.payment_id ?? ""}`}:${`${item.amount ?? ""}`}:${`${item.discount_rate ?? ""}:${item.discount_amount ?? ""}`}`;
5098
5093
  }).join("|");
5099
5094
  };
5100
5095
  const buildHttpOptions = (options) => {
@@ -5509,9 +5504,9 @@ var Order = class Order {
5509
5504
  }
5510
5505
  /**
5511
5506
  * Appends a redeem to `line_uid` (root line) or to the order. Steps keep
5512
- * the order in which redeems were applied. With `payment_id` (points /
5513
- * balance) it is not a discount: `amount` and `points` are totals of the
5514
- * whole entry (every unit, not per unit) and `quantity` is informational.
5507
+ * the order in which redeems were applied. With `payment_id` (voucher,
5508
+ * balance…) it is not a discount: `amount` is the total of the whole
5509
+ * entry (every unit, not per unit) and `quantity` is informational.
5515
5510
  * Every redeem with the same `payment_id` is paid by one REDEMPTION
5516
5511
  * tender whose `details.rewards[]` lists them; their summed amount is
5517
5512
  * capped at total − tip − delivery (D15, D18, D19).
@@ -5520,7 +5515,7 @@ var Order = class Order {
5520
5515
  if (this.deleted) return;
5521
5516
  const { line_uid, provider, ...rest } = input;
5522
5517
  const redeem = buildRedeem(rest);
5523
- if (isPaymentRedeem(redeem) && line_uid !== void 0) throw new Error("Points / balance redeems apply to the whole order");
5518
+ if (isPaymentRedeem(redeem) && line_uid !== void 0) throw new Error("Payment redeems apply to the whole order");
5524
5519
  if (redeem.payment_id && provider) this.redemptionProviders.set(redeem.payment_id, provider);
5525
5520
  if (line_uid === void 0) {
5526
5521
  this.commitLines({ redeem: [...this.appliedRedeem(), redeem] });
@@ -5540,9 +5535,8 @@ var Order = class Order {
5540
5535
  /**
5541
5536
  * Removes `quantity` units of `reward_id` from `line_uid` or the order,
5542
5537
  * latest applied first. Removing more units than applied clears them all
5543
- * (and the REDEMPTION tender of a points / balance redeem). A points /
5544
- * balance entry that keeps some units keeps the same share of its
5545
- * `amount` and `points`.
5538
+ * (and the REDEMPTION tender of a payment redeem). A payment redeem that
5539
+ * keeps some units keeps the same share of its `amount`.
5546
5540
  */
5547
5541
  removeRedeem(input) {
5548
5542
  if (this.deleted) return;
@@ -5649,7 +5643,7 @@ var Order = class Order {
5649
5643
  }
5650
5644
  /**
5651
5645
  * Reopens this placed, unpaid order: the server voids every payment
5652
- * (REDEMPTION points released), cancels it as `VOIDED` and opens a new
5646
+ * (REDEMPTION rewards released), cancels it as `VOIDED` and opens a new
5653
5647
  * `OPEN` order with the same content. This instance is closed afterwards;
5654
5648
  * replace it with the returned `Order` (same HTTP options and listener).
5655
5649
  *
@@ -6968,391 +6962,8 @@ const verifyWebhookSignature = async (input) => {
6968
6962
  return safeEqual(received, await hmacHex(secret, body));
6969
6963
  };
6970
6964
  //#endregion
6971
- //#region src/rules/assert.ts
6972
- const assert = (value, message) => {
6973
- if (value) return;
6974
- throw new Error(message);
6975
- };
6976
- //#endregion
6977
- //#region src/rules/common.ts
6978
- const primitiveError = (primitive) => {
6979
- return `Condition primitive must be ${primitive}`;
6980
- };
6981
- const typeError = (type) => {
6982
- return `Condition type must be ${type}`;
6983
- };
6984
- const defaultConditionError = "Condition was not met";
6985
- const getLineByProductId = (lines, productId) => {
6986
- if (!productId) return void 0;
6987
- return lines?.find((line) => line.id === productId);
6988
- };
6989
- const countCartProducts = (lines, includeModifiers) => {
6990
- if (!lines?.length) return 0;
6991
- return lines.filter((line) => {
6992
- if (line.type === "FEE") return false;
6993
- if (includeModifiers) return true;
6994
- if (!(line.parent_uid == null)) return false;
6995
- return line.type === "PRODUCT" || line.type == null;
6996
- }).reduce((sum, line) => sum + line.quantity, 0);
6997
- };
6998
- const getLineTagValues = (lines, tag) => {
6999
- if (!tag) return [];
7000
- const values = [];
7001
- for (const line of lines ?? []) {
7002
- const value = line.tags?.[tag];
7003
- if (typeof value === "undefined") continue;
7004
- values.push(value);
7005
- }
7006
- return values;
7007
- };
7008
- //#endregion
7009
- //#region src/rules/booleanMatcher.ts
7010
- const matchBooleanOperator = (condition, matcher) => {
7011
- const { primitive, operator, value } = condition;
7012
- assert(primitive === "boolean", primitiveError("boolean"));
7013
- if (typeof matcher === "undefined") return false;
7014
- assert(typeof value === "boolean", "Invalid boolean value");
7015
- switch (operator) {
7016
- case "is": return matcher === value;
7017
- case "is not": return matcher !== value;
7018
- default: throw new Error(`Operator ${operator} not supported in boolean matcher`);
7019
- }
7020
- };
7021
- const isAnonymousCustomer = (condition, isAnonymous) => {
7022
- const { type, primitive, value } = condition;
7023
- const matcherType = "Customer is anonymous";
7024
- assert(primitive === "boolean", primitiveError("boolean"));
7025
- assert(type === matcherType, typeError(matcherType));
7026
- assert(value != null, "Invalid value");
7027
- return matchBooleanOperator(condition, isAnonymous ?? false);
7028
- };
7029
- const orderIncludesProductWithTag$3 = (condition, matcher) => {
7030
- const { type, primitive, value } = condition;
7031
- const matcherType = "Order includes product with tag";
7032
- assert(primitive === "boolean", primitiveError("boolean"));
7033
- assert(type === matcherType, typeError(matcherType));
7034
- assert(value != null, "Invalid value");
7035
- return matchBooleanOperator(condition, matcher);
7036
- };
7037
- const isAnonymousOrder = (condition, isAnonymous) => {
7038
- const { type, primitive, value } = condition;
7039
- const matcherType = "Is anonymous order";
7040
- assert(primitive === "boolean", primitiveError("boolean"));
7041
- assert(type === matcherType, typeError(matcherType));
7042
- assert(value != null, "Invalid value");
7043
- return matchBooleanOperator(condition, isAnonymous ?? false);
7044
- };
7045
- const paymentIsMixed = (condition, isMixed) => {
7046
- const { type, primitive, value } = condition;
7047
- const matcherType = "Payment is mixed";
7048
- assert(primitive === "boolean", primitiveError("boolean"));
7049
- assert(type === matcherType, typeError(matcherType));
7050
- assert(value != null, "Invalid value");
7051
- return matchBooleanOperator(condition, isMixed ?? false);
7052
- };
7053
- const paymentCaptured = (condition, captured) => {
7054
- const { type, primitive, value } = condition;
7055
- const matcherType = "Payment captured";
7056
- assert(primitive === "boolean", primitiveError("boolean"));
7057
- assert(type === matcherType, typeError(matcherType));
7058
- assert(value != null, "Invalid value");
7059
- return matchBooleanOperator(condition, captured ?? false);
7060
- };
7061
- //#endregion
7062
- //#region src/rules/currencyMatcher.ts
7063
- const matchCurrencyOperator = (condition, matcher) => {
7064
- const { primitive, operator, value } = condition;
7065
- assert(primitive === "currency", primitiveError("currency"));
7066
- if (typeof matcher === "undefined") return false;
7067
- assert(typeof value === "number", "Invalid currency value");
7068
- switch (operator) {
7069
- case "equal to": return matcher === value;
7070
- case "not equal to": return matcher !== value;
7071
- case "greater than": return matcher > value;
7072
- case "greater than or equal to": return matcher >= value;
7073
- case "less than": return matcher < value;
7074
- case "less than or equal to": return matcher <= value;
7075
- default: throw new Error(`Operator ${operator} not supported in currency matcher`);
7076
- }
7077
- };
7078
- const orderIncludesProductWithTag$2 = (condition, matcher) => {
7079
- const { type, primitive, value } = condition;
7080
- const matcherType = "Order includes product with tag";
7081
- assert(primitive === "currency", primitiveError("currency"));
7082
- assert(type === matcherType, typeError(matcherType));
7083
- assert(value != null, "Invalid value");
7084
- return matchCurrencyOperator(condition, matcher);
7085
- };
7086
- const orderTotal = (condition, total) => {
7087
- const { type, primitive, value } = condition;
7088
- const matcherType = "Order total";
7089
- assert(primitive === "currency", primitiveError("currency"));
7090
- assert(type === matcherType, typeError(matcherType));
7091
- assert(value != null, "Invalid value");
7092
- return matchCurrencyOperator(condition, total);
7093
- };
7094
- //#endregion
7095
- //#region src/rules/customMatcher.ts
7096
- const MULTI_OPERATORS = [
7097
- "is any of",
7098
- "is none of",
7099
- "is all of"
7100
- ];
7101
- const isMultiOperator = (operator) => {
7102
- return MULTI_OPERATORS.includes(operator);
7103
- };
7104
- const splitCsv = (value) => {
7105
- return value.split(",").map((part) => part.trim()).filter(Boolean);
7106
- };
7107
- const matchCustomEquality = (condition, matcher) => {
7108
- const { primitive, operator, value } = condition;
7109
- assert(primitive === "custom", primitiveError("custom"));
7110
- if (typeof matcher === "undefined") return false;
7111
- assert(typeof value === "string", "Invalid custom value");
7112
- switch (operator) {
7113
- case "is": return matcher === value;
7114
- case "is not": return matcher !== value;
7115
- default: throw new Error(`Operator ${operator} not supported in custom matcher`);
7116
- }
7117
- };
7118
- const matchCustomMulti = (condition, matcher) => {
7119
- const { primitive, operator, value } = condition;
7120
- assert(primitive === "custom", primitiveError("custom"));
7121
- if (typeof matcher === "undefined") return false;
7122
- assert(typeof value === "string", "Invalid custom value");
7123
- const allowed = splitCsv(value);
7124
- if (allowed.length === 0) return false;
7125
- const candidates = typeof matcher === "object" ? matcher : [matcher];
7126
- if (candidates.length === 0) return false;
7127
- if (operator === "is any of") return allowed.some((id) => candidates.includes(id));
7128
- if (operator === "is none of") return !allowed.some((id) => candidates.includes(id));
7129
- if (operator === "is all of") return allowed.every((id) => candidates.includes(id));
7130
- throw new Error(`Operator ${operator} not supported in custom matcher`);
7131
- };
7132
- /**
7133
- * The operator picks the arity: `Payment` is single-select in order rules and
7134
- * multi-select in fulfillment workflows. `matcher` may be a set (one id per
7135
- * tender): `is` matches when some id matches, `is not` when none does.
7136
- */
7137
- const matchCustom = (condition, matcher) => {
7138
- if (isMultiOperator(condition.operator)) return matchCustomMulti(condition, matcher);
7139
- if (typeof matcher === "undefined" || typeof matcher === "string") return matchCustomEquality(condition, matcher);
7140
- if (matcher.length === 0) return false;
7141
- const matches = (id) => matchCustomEquality(condition, id);
7142
- if (condition.operator === "is not") return matcher.every(matches);
7143
- return matcher.some(matches);
7144
- };
7145
- const assertCustom = (condition, order) => {
7146
- const { type } = condition;
7147
- switch (type) {
7148
- case "Fulfillment":
7149
- case "Fulfillments": return matchCustom(condition, order.fulfillment_id);
7150
- case "Store":
7151
- case "Stores": return matchCustom(condition, order.store_id);
7152
- case "Channel":
7153
- case "Channels": return matchCustom(condition, order.channel_id);
7154
- case "Brand":
7155
- case "Brands": return matchCustom(condition, order.brand_id);
7156
- default: throw new Error(`Condition ${type} not supported in custom matcher`);
7157
- }
7158
- };
7159
- //#endregion
7160
- //#region src/rules/enumMatcher.ts
7161
- const matchEnumOperator = (condition, matcher) => {
7162
- const { primitive, operator, value } = condition;
7163
- assert(primitive === "enum", primitiveError("enum"));
7164
- if (typeof matcher === "undefined") return false;
7165
- switch (operator) {
7166
- case "is":
7167
- assert(typeof value === "string", "Expected a single enum value");
7168
- return matcher === value;
7169
- case "is not":
7170
- assert(typeof value === "string", "Expected a single enum value");
7171
- return matcher !== value;
7172
- case "is any of":
7173
- assert(Array.isArray(value), "Expected a list of enum values");
7174
- return value.includes(matcher);
7175
- case "is none of":
7176
- assert(Array.isArray(value), "Expected a list of enum values");
7177
- return !value.includes(matcher);
7178
- default: throw new Error(`Operator ${operator} not supported in enum matcher`);
7179
- }
7180
- };
7181
- const NEGATIVE_ENUM_OPERATORS = ["is not", "is none of"];
7182
- /**
7183
- * Enum condition over a set (one value per tender): positive operators
7184
- * match when some value matches, negative ones when none matches.
7185
- */
7186
- const matchEnumSet = (condition, matcher) => {
7187
- if (typeof matcher === "undefined" || typeof matcher === "string") return matchEnumOperator(condition, matcher);
7188
- if (matcher.length === 0) return false;
7189
- const matches = (value) => matchEnumOperator(condition, value);
7190
- if (NEGATIVE_ENUM_OPERATORS.includes(condition.operator)) return matcher.every(matches);
7191
- return matcher.some(matches);
7192
- };
7193
- const paymentCollectAt = (condition, collectAt) => {
7194
- const matcherType = "Payment collect at";
7195
- assert(condition.primitive === "enum", primitiveError("enum"));
7196
- assert(condition.type === matcherType, typeError(matcherType));
7197
- return matchEnumSet(condition, collectAt);
7198
- };
7199
- const paymentMethod = (condition, method) => {
7200
- const matcherType = "Payment method";
7201
- assert(condition.primitive === "enum", primitiveError("enum"));
7202
- assert(condition.type === matcherType, typeError(matcherType));
7203
- return matchEnumSet(condition, method);
7204
- };
7205
- const paymentStatus = (condition, status) => {
7206
- const matcherType = "Payment status";
7207
- assert(condition.primitive === "enum", primitiveError("enum"));
7208
- assert(condition.type === matcherType, typeError(matcherType));
7209
- return matchEnumOperator(condition, status);
7210
- };
7211
- const CONDITION_INTERPRETATION_DEFAULT = "server";
7212
- const isInterpretationCompatible = (interpretation, runtime, fallback) => {
7213
- if (!runtime) return true;
7214
- const value = interpretation ?? fallback;
7215
- if (value === "both") return true;
7216
- return value === runtime;
7217
- };
7218
- //#endregion
7219
- //#region src/rules/numberMatcher.ts
7220
- const matchNumberOperator = (condition, matcher) => {
7221
- const { primitive, operator, value } = condition;
7222
- assert(primitive === "number", primitiveError("number"));
7223
- if (typeof matcher === "undefined") return false;
7224
- assert(typeof value === "number", "Invalid number value");
7225
- switch (operator) {
7226
- case "equal to": return matcher === value;
7227
- case "not equal to": return matcher !== value;
7228
- case "greater than": return matcher > value;
7229
- case "greater than or equal to": return matcher >= value;
7230
- case "less than": return matcher < value;
7231
- case "less than or equal to": return matcher <= value;
7232
- default: throw new Error(`Operator ${operator} not supported in number matcher`);
7233
- }
7234
- };
7235
- const orderIncludesProduct = (condition, quantity) => {
7236
- const { type, primitive, value } = condition;
7237
- const matcherType = "Order includes product";
7238
- assert(primitive === "number", primitiveError("number"));
7239
- assert(type === matcherType, typeError(matcherType));
7240
- assert(value != null, "Invalid value");
7241
- return matchNumberOperator(condition, quantity ?? 0);
7242
- };
7243
- const cartProductCount = (condition, count) => {
7244
- const { type, primitive, value } = condition;
7245
- const matcherType = "Cart product count";
7246
- assert(primitive === "number", primitiveError("number"));
7247
- assert(type === matcherType, typeError(matcherType));
7248
- assert(value != null, "Invalid value");
7249
- return matchNumberOperator(condition, count);
7250
- };
7251
- const orderIncludesProductWithTag$1 = (condition, matcher) => {
7252
- const { type, primitive, value } = condition;
7253
- const matcherType = "Order includes product with tag";
7254
- assert(primitive === "number", primitiveError("number"));
7255
- assert(type === matcherType, typeError(matcherType));
7256
- assert(value != null, "Invalid value");
7257
- return matchNumberOperator(condition, matcher);
7258
- };
7259
- //#endregion
7260
- //#region src/rules/stringCondition.utils.ts
7261
- const getCaseInsensitive = (condition) => {
7262
- return condition.caseInsensitive ?? false;
7263
- };
7264
- const normalizeStringForMatch = (value, caseInsensitive) => {
7265
- if (caseInsensitive) return value.toLowerCase();
7266
- return value;
7267
- };
7268
- const normalizePairForMatch = (matcher, expected, caseInsensitive) => {
7269
- return {
7270
- matcher: normalizeStringForMatch(matcher, caseInsensitive),
7271
- expected: normalizeStringForMatch(expected, caseInsensitive)
7272
- };
7273
- };
7274
- //#endregion
7275
- //#region src/rules/stringMatcher.ts
7276
- const matchStringOperator = (condition, matcher) => {
7277
- const { primitive, operator, value } = condition;
7278
- assert(primitive === "string", primitiveError("string"));
7279
- if (typeof matcher === "undefined") return false;
7280
- const caseInsensitive = getCaseInsensitive(condition);
7281
- const pair = normalizePairForMatch(matcher, String(value), caseInsensitive);
7282
- const normalizedMatcher = pair.matcher;
7283
- const normalizedExpected = pair.expected;
7284
- switch (operator) {
7285
- case "equal to": return normalizedMatcher === normalizedExpected;
7286
- case "not equal to": return normalizedMatcher !== normalizedExpected;
7287
- case "starts with": return normalizedMatcher.startsWith(normalizedExpected);
7288
- case "ends with": return normalizedMatcher.endsWith(normalizedExpected);
7289
- case "contains": return normalizedMatcher.includes(normalizedExpected);
7290
- default: throw new Error(`Operator ${operator} not supported in string matcher`);
7291
- }
7292
- };
7293
- const orderIncludesProductWithTag = (condition, matcher) => {
7294
- const { type, primitive, value } = condition;
7295
- const matcherType = "Order includes product with tag";
7296
- assert(primitive === "string", primitiveError("string"));
7297
- assert(type === matcherType, typeError(matcherType));
7298
- assert(value != null, "Invalid value");
7299
- return matchStringOperator(condition, matcher);
7300
- };
7301
- //#endregion
7302
- //#region src/rules/monitoringMatcher.ts
7303
- const windowOf = (condition) => {
7304
- if (!("window_minutes" in condition)) return void 0;
7305
- return condition.window_minutes;
7306
- };
7307
- const accumulatedEvents = (condition, count) => {
7308
- const { type, primitive, value } = condition;
7309
- const matcherType = "Accumulated events";
7310
- assert(primitive === "number", primitiveError("number"));
7311
- assert(type === matcherType, typeError(matcherType));
7312
- assert(value != null, "Invalid value");
7313
- if (typeof count === "undefined") return false;
7314
- return matchNumberOperator(condition, count);
7315
- };
7316
- const apiErrorRate = (condition, rate) => {
7317
- const { type, primitive, value } = condition;
7318
- const matcherType = "API error rate";
7319
- assert(primitive === "number", primitiveError("number"));
7320
- assert(type === matcherType, typeError(matcherType));
7321
- assert(value != null, "Invalid value");
7322
- if (typeof rate === "undefined") return false;
7323
- return matchNumberOperator(condition, rate);
7324
- };
7325
- const httpStatus = (condition, status) => {
7326
- const { type, primitive, value } = condition;
7327
- const matcherType = "HTTP status";
7328
- assert(primitive === "number", primitiveError("number"));
7329
- assert(type === matcherType, typeError(matcherType));
7330
- assert(value != null, "Invalid value");
7331
- if (typeof status === "undefined") return false;
7332
- return matchNumberOperator(condition, status);
7333
- };
7334
- const requestPath = (condition, path) => {
7335
- const { type, primitive, value } = condition;
7336
- const matcherType = "Request path";
7337
- assert(primitive === "string", primitiveError("string"));
7338
- assert(type === matcherType, typeError(matcherType));
7339
- assert(value != null, "Invalid value");
7340
- return matchStringOperator(condition, path);
7341
- };
7342
- const failureMessage = (condition, message) => {
7343
- const { type, primitive, value } = condition;
7344
- const matcherType = "Failure message";
7345
- assert(primitive === "string", primitiveError("string"));
7346
- assert(type === matcherType, typeError(matcherType));
7347
- assert(value != null, "Invalid value");
7348
- return matchStringOperator(condition, message);
7349
- };
7350
- const windowMinutes = (condition) => {
7351
- return windowOf(condition);
7352
- };
7353
- //#endregion
7354
- //#region src/rules/recurringDateCron.ts
7355
- var import_dayjs_min = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
6965
+ //#region ../../node_modules/.pnpm/dayjs@1.11.9/node_modules/dayjs/dayjs.min.js
6966
+ var require_dayjs_min = /* @__PURE__ */ __commonJSMin(((exports, module) => {
7356
6967
  (function(t, e) {
7357
6968
  "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : (t = "undefined" != typeof globalThis ? globalThis : t || self).dayjs = e();
7358
6969
  })(exports, (function() {
@@ -7647,7 +7258,412 @@ var import_dayjs_min = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((
7647
7258
  return w(1e3 * t);
7648
7259
  }, w.en = D[g], w.Ls = D, w.p = {}, w;
7649
7260
  }));
7650
- })))(), 1);
7261
+ }));
7262
+ //#endregion
7263
+ //#region src/rules/assert.ts
7264
+ const assert = (value, message) => {
7265
+ if (value) return;
7266
+ throw new Error(message);
7267
+ };
7268
+ //#endregion
7269
+ //#region src/rules/common.ts
7270
+ const primitiveError = (primitive) => {
7271
+ return `Condition primitive must be ${primitive}`;
7272
+ };
7273
+ const typeError = (type) => {
7274
+ return `Condition type must be ${type}`;
7275
+ };
7276
+ const defaultConditionError = "Condition was not met";
7277
+ const getLineByProductId = (lines, productId) => {
7278
+ if (!productId) return void 0;
7279
+ return lines?.find((line) => line.id === productId);
7280
+ };
7281
+ const countCartProducts = (lines, includeModifiers) => {
7282
+ if (!lines?.length) return 0;
7283
+ return lines.filter((line) => {
7284
+ if (line.type === "FEE") return false;
7285
+ if (includeModifiers) return true;
7286
+ if (!(line.parent_uid == null)) return false;
7287
+ return line.type === "PRODUCT" || line.type == null;
7288
+ }).reduce((sum, line) => sum + line.quantity, 0);
7289
+ };
7290
+ const getLineTagValues = (lines, tag) => {
7291
+ if (!tag) return [];
7292
+ const values = [];
7293
+ for (const line of lines ?? []) {
7294
+ const value = line.tags?.[tag];
7295
+ if (typeof value === "undefined") continue;
7296
+ values.push(value);
7297
+ }
7298
+ return values;
7299
+ };
7300
+ //#endregion
7301
+ //#region src/rules/absoluteDateMatcher.ts
7302
+ var import_dayjs_min = /* @__PURE__ */ __toESM(require_dayjs_min(), 1);
7303
+ const matchAbsoluteDateOperator = (condition, matcher) => {
7304
+ const { primitive, operator, value } = condition;
7305
+ assert(primitive === "absolute date", primitiveError("absolute date"));
7306
+ if (typeof matcher === "undefined") return false;
7307
+ const matcherDate = (0, import_dayjs_min.default)(matcher);
7308
+ const expectedDate = (0, import_dayjs_min.default)(value);
7309
+ switch (operator) {
7310
+ case "is": return matcherDate.isSame(expectedDate, "day");
7311
+ case "is not": return !matcherDate.isSame(expectedDate, "day");
7312
+ case "is before": return matcherDate.isBefore(expectedDate, "day");
7313
+ case "is after": return matcherDate.isAfter(expectedDate, "day");
7314
+ default: {
7315
+ const msg = `Operator ${operator} not supported in absolute date matcher`;
7316
+ throw new Error(msg);
7317
+ }
7318
+ }
7319
+ };
7320
+ //#endregion
7321
+ //#region src/rules/booleanMatcher.ts
7322
+ const matchBooleanOperator = (condition, matcher) => {
7323
+ const { primitive, operator, value } = condition;
7324
+ assert(primitive === "boolean", primitiveError("boolean"));
7325
+ if (typeof matcher === "undefined") return false;
7326
+ assert(typeof value === "boolean", "Invalid boolean value");
7327
+ switch (operator) {
7328
+ case "is": return matcher === value;
7329
+ case "is not": return matcher !== value;
7330
+ default: throw new Error(`Operator ${operator} not supported in boolean matcher`);
7331
+ }
7332
+ };
7333
+ const isAnonymousCustomer = (condition, isAnonymous) => {
7334
+ const { type, primitive, value } = condition;
7335
+ const matcherType = "Customer is anonymous";
7336
+ assert(primitive === "boolean", primitiveError("boolean"));
7337
+ assert(type === matcherType, typeError(matcherType));
7338
+ assert(value != null, "Invalid value");
7339
+ return matchBooleanOperator(condition, isAnonymous ?? false);
7340
+ };
7341
+ const orderIncludesProductWithTag$3 = (condition, matcher) => {
7342
+ const { type, primitive, value } = condition;
7343
+ const matcherType = "Order includes product with tag";
7344
+ assert(primitive === "boolean", primitiveError("boolean"));
7345
+ assert(type === matcherType, typeError(matcherType));
7346
+ assert(value != null, "Invalid value");
7347
+ return matchBooleanOperator(condition, matcher);
7348
+ };
7349
+ const isAnonymousOrder = (condition, isAnonymous) => {
7350
+ const { type, primitive, value } = condition;
7351
+ const matcherType = "Is anonymous order";
7352
+ assert(primitive === "boolean", primitiveError("boolean"));
7353
+ assert(type === matcherType, typeError(matcherType));
7354
+ assert(value != null, "Invalid value");
7355
+ return matchBooleanOperator(condition, isAnonymous ?? false);
7356
+ };
7357
+ const paymentIsMixed = (condition, isMixed) => {
7358
+ const { type, primitive, value } = condition;
7359
+ const matcherType = "Payment is mixed";
7360
+ assert(primitive === "boolean", primitiveError("boolean"));
7361
+ assert(type === matcherType, typeError(matcherType));
7362
+ assert(value != null, "Invalid value");
7363
+ return matchBooleanOperator(condition, isMixed ?? false);
7364
+ };
7365
+ const paymentCaptured = (condition, captured) => {
7366
+ const { type, primitive, value } = condition;
7367
+ const matcherType = "Payment captured";
7368
+ assert(primitive === "boolean", primitiveError("boolean"));
7369
+ assert(type === matcherType, typeError(matcherType));
7370
+ assert(value != null, "Invalid value");
7371
+ return matchBooleanOperator(condition, captured ?? false);
7372
+ };
7373
+ //#endregion
7374
+ //#region src/rules/currencyMatcher.ts
7375
+ const matchCurrencyOperator = (condition, matcher) => {
7376
+ const { primitive, operator, value } = condition;
7377
+ assert(primitive === "currency", primitiveError("currency"));
7378
+ if (typeof matcher === "undefined") return false;
7379
+ assert(typeof value === "number", "Invalid currency value");
7380
+ switch (operator) {
7381
+ case "equal to": return matcher === value;
7382
+ case "not equal to": return matcher !== value;
7383
+ case "greater than": return matcher > value;
7384
+ case "greater than or equal to": return matcher >= value;
7385
+ case "less than": return matcher < value;
7386
+ case "less than or equal to": return matcher <= value;
7387
+ default: throw new Error(`Operator ${operator} not supported in currency matcher`);
7388
+ }
7389
+ };
7390
+ const orderIncludesProductWithTag$2 = (condition, matcher) => {
7391
+ const { type, primitive, value } = condition;
7392
+ const matcherType = "Order includes product with tag";
7393
+ assert(primitive === "currency", primitiveError("currency"));
7394
+ assert(type === matcherType, typeError(matcherType));
7395
+ assert(value != null, "Invalid value");
7396
+ return matchCurrencyOperator(condition, matcher);
7397
+ };
7398
+ const orderTotal = (condition, total) => {
7399
+ const { type, primitive, value } = condition;
7400
+ const matcherType = "Order total";
7401
+ assert(primitive === "currency", primitiveError("currency"));
7402
+ assert(type === matcherType, typeError(matcherType));
7403
+ assert(value != null, "Invalid value");
7404
+ return matchCurrencyOperator(condition, total);
7405
+ };
7406
+ //#endregion
7407
+ //#region src/rules/customMatcher.ts
7408
+ const MULTI_OPERATORS = [
7409
+ "is any of",
7410
+ "is none of",
7411
+ "is all of"
7412
+ ];
7413
+ const isMultiOperator = (operator) => {
7414
+ return MULTI_OPERATORS.includes(operator);
7415
+ };
7416
+ const splitCsv = (value) => {
7417
+ return value.split(",").map((part) => part.trim()).filter(Boolean);
7418
+ };
7419
+ const matchCustomEquality = (condition, matcher) => {
7420
+ const { primitive, operator, value } = condition;
7421
+ assert(primitive === "custom", primitiveError("custom"));
7422
+ if (typeof matcher === "undefined") return false;
7423
+ assert(typeof value === "string", "Invalid custom value");
7424
+ switch (operator) {
7425
+ case "is": return matcher === value;
7426
+ case "is not": return matcher !== value;
7427
+ default: throw new Error(`Operator ${operator} not supported in custom matcher`);
7428
+ }
7429
+ };
7430
+ const matchCustomMulti = (condition, matcher) => {
7431
+ const { primitive, operator, value } = condition;
7432
+ assert(primitive === "custom", primitiveError("custom"));
7433
+ if (typeof matcher === "undefined") return false;
7434
+ assert(typeof value === "string", "Invalid custom value");
7435
+ const allowed = splitCsv(value);
7436
+ if (allowed.length === 0) return false;
7437
+ const candidates = typeof matcher === "object" ? matcher : [matcher];
7438
+ if (candidates.length === 0) return false;
7439
+ if (operator === "is any of") return allowed.some((id) => candidates.includes(id));
7440
+ if (operator === "is none of") return !allowed.some((id) => candidates.includes(id));
7441
+ if (operator === "is all of") return allowed.every((id) => candidates.includes(id));
7442
+ throw new Error(`Operator ${operator} not supported in custom matcher`);
7443
+ };
7444
+ /**
7445
+ * The operator picks the arity: `Payment` is single-select in order rules and
7446
+ * multi-select in fulfillment workflows. `matcher` may be a set (one id per
7447
+ * tender): `is` matches when some id matches, `is not` when none does.
7448
+ */
7449
+ const matchCustom = (condition, matcher) => {
7450
+ if (isMultiOperator(condition.operator)) return matchCustomMulti(condition, matcher);
7451
+ if (typeof matcher === "undefined" || typeof matcher === "string") return matchCustomEquality(condition, matcher);
7452
+ if (matcher.length === 0) return false;
7453
+ const matches = (id) => matchCustomEquality(condition, id);
7454
+ if (condition.operator === "is not") return matcher.every(matches);
7455
+ return matcher.some(matches);
7456
+ };
7457
+ const assertCustom = (condition, order) => {
7458
+ const { type } = condition;
7459
+ switch (type) {
7460
+ case "Fulfillment":
7461
+ case "Fulfillments": return matchCustom(condition, order.fulfillment_id);
7462
+ case "Store":
7463
+ case "Stores": return matchCustom(condition, order.store_id);
7464
+ case "Channel":
7465
+ case "Channels": return matchCustom(condition, order.channel_id);
7466
+ case "Brand":
7467
+ case "Brands": return matchCustom(condition, order.brand_id);
7468
+ default: throw new Error(`Condition ${type} not supported in custom matcher`);
7469
+ }
7470
+ };
7471
+ //#endregion
7472
+ //#region src/rules/enumMatcher.ts
7473
+ const matchEnumOperator = (condition, matcher) => {
7474
+ const { primitive, operator, value } = condition;
7475
+ assert(primitive === "enum", primitiveError("enum"));
7476
+ if (typeof matcher === "undefined") return false;
7477
+ switch (operator) {
7478
+ case "is":
7479
+ assert(typeof value === "string", "Expected a single enum value");
7480
+ return matcher === value;
7481
+ case "is not":
7482
+ assert(typeof value === "string", "Expected a single enum value");
7483
+ return matcher !== value;
7484
+ case "is any of":
7485
+ assert(Array.isArray(value), "Expected a list of enum values");
7486
+ return value.includes(matcher);
7487
+ case "is none of":
7488
+ assert(Array.isArray(value), "Expected a list of enum values");
7489
+ return !value.includes(matcher);
7490
+ default: throw new Error(`Operator ${operator} not supported in enum matcher`);
7491
+ }
7492
+ };
7493
+ const NEGATIVE_ENUM_OPERATORS = ["is not", "is none of"];
7494
+ /**
7495
+ * Enum condition over a set (one value per tender): positive operators
7496
+ * match when some value matches, negative ones when none matches.
7497
+ */
7498
+ const matchEnumSet = (condition, matcher) => {
7499
+ if (typeof matcher === "undefined" || typeof matcher === "string") return matchEnumOperator(condition, matcher);
7500
+ if (matcher.length === 0) return false;
7501
+ const matches = (value) => matchEnumOperator(condition, value);
7502
+ if (NEGATIVE_ENUM_OPERATORS.includes(condition.operator)) return matcher.every(matches);
7503
+ return matcher.some(matches);
7504
+ };
7505
+ const paymentCollectAt = (condition, collectAt) => {
7506
+ const matcherType = "Payment collect at";
7507
+ assert(condition.primitive === "enum", primitiveError("enum"));
7508
+ assert(condition.type === matcherType, typeError(matcherType));
7509
+ return matchEnumSet(condition, collectAt);
7510
+ };
7511
+ const paymentMethod = (condition, method) => {
7512
+ const matcherType = "Payment method";
7513
+ assert(condition.primitive === "enum", primitiveError("enum"));
7514
+ assert(condition.type === matcherType, typeError(matcherType));
7515
+ return matchEnumSet(condition, method);
7516
+ };
7517
+ const paymentStatus = (condition, status) => {
7518
+ const matcherType = "Payment status";
7519
+ assert(condition.primitive === "enum", primitiveError("enum"));
7520
+ assert(condition.type === matcherType, typeError(matcherType));
7521
+ return matchEnumOperator(condition, status);
7522
+ };
7523
+ const CONDITION_INTERPRETATION_DEFAULT = "server";
7524
+ const isInterpretationCompatible = (interpretation, runtime, fallback) => {
7525
+ if (!runtime) return true;
7526
+ const value = interpretation ?? fallback;
7527
+ if (value === "both") return true;
7528
+ return value === runtime;
7529
+ };
7530
+ //#endregion
7531
+ //#region src/rules/numberMatcher.ts
7532
+ const matchNumberOperator = (condition, matcher) => {
7533
+ const { primitive, operator, value } = condition;
7534
+ assert(primitive === "number", primitiveError("number"));
7535
+ if (typeof matcher === "undefined") return false;
7536
+ assert(typeof value === "number", "Invalid number value");
7537
+ switch (operator) {
7538
+ case "equal to": return matcher === value;
7539
+ case "not equal to": return matcher !== value;
7540
+ case "greater than": return matcher > value;
7541
+ case "greater than or equal to": return matcher >= value;
7542
+ case "less than": return matcher < value;
7543
+ case "less than or equal to": return matcher <= value;
7544
+ default: throw new Error(`Operator ${operator} not supported in number matcher`);
7545
+ }
7546
+ };
7547
+ const orderIncludesProduct = (condition, quantity) => {
7548
+ const { type, primitive, value } = condition;
7549
+ const matcherType = "Order includes product";
7550
+ assert(primitive === "number", primitiveError("number"));
7551
+ assert(type === matcherType, typeError(matcherType));
7552
+ assert(value != null, "Invalid value");
7553
+ return matchNumberOperator(condition, quantity ?? 0);
7554
+ };
7555
+ const cartProductCount = (condition, count) => {
7556
+ const { type, primitive, value } = condition;
7557
+ const matcherType = "Cart product count";
7558
+ assert(primitive === "number", primitiveError("number"));
7559
+ assert(type === matcherType, typeError(matcherType));
7560
+ assert(value != null, "Invalid value");
7561
+ return matchNumberOperator(condition, count);
7562
+ };
7563
+ const orderIncludesProductWithTag$1 = (condition, matcher) => {
7564
+ const { type, primitive, value } = condition;
7565
+ const matcherType = "Order includes product with tag";
7566
+ assert(primitive === "number", primitiveError("number"));
7567
+ assert(type === matcherType, typeError(matcherType));
7568
+ assert(value != null, "Invalid value");
7569
+ return matchNumberOperator(condition, matcher);
7570
+ };
7571
+ //#endregion
7572
+ //#region src/rules/stringCondition.utils.ts
7573
+ const getCaseInsensitive = (condition) => {
7574
+ return condition.caseInsensitive ?? false;
7575
+ };
7576
+ const normalizeStringForMatch = (value, caseInsensitive) => {
7577
+ if (caseInsensitive) return value.toLowerCase();
7578
+ return value;
7579
+ };
7580
+ const normalizePairForMatch = (matcher, expected, caseInsensitive) => {
7581
+ return {
7582
+ matcher: normalizeStringForMatch(matcher, caseInsensitive),
7583
+ expected: normalizeStringForMatch(expected, caseInsensitive)
7584
+ };
7585
+ };
7586
+ //#endregion
7587
+ //#region src/rules/stringMatcher.ts
7588
+ const matchStringOperator = (condition, matcher) => {
7589
+ const { primitive, operator, value } = condition;
7590
+ assert(primitive === "string", primitiveError("string"));
7591
+ if (typeof matcher === "undefined") return false;
7592
+ const caseInsensitive = getCaseInsensitive(condition);
7593
+ const pair = normalizePairForMatch(matcher, String(value), caseInsensitive);
7594
+ const normalizedMatcher = pair.matcher;
7595
+ const normalizedExpected = pair.expected;
7596
+ switch (operator) {
7597
+ case "equal to": return normalizedMatcher === normalizedExpected;
7598
+ case "not equal to": return normalizedMatcher !== normalizedExpected;
7599
+ case "starts with": return normalizedMatcher.startsWith(normalizedExpected);
7600
+ case "ends with": return normalizedMatcher.endsWith(normalizedExpected);
7601
+ case "contains": return normalizedMatcher.includes(normalizedExpected);
7602
+ default: throw new Error(`Operator ${operator} not supported in string matcher`);
7603
+ }
7604
+ };
7605
+ const orderIncludesProductWithTag = (condition, matcher) => {
7606
+ const { type, primitive, value } = condition;
7607
+ const matcherType = "Order includes product with tag";
7608
+ assert(primitive === "string", primitiveError("string"));
7609
+ assert(type === matcherType, typeError(matcherType));
7610
+ assert(value != null, "Invalid value");
7611
+ return matchStringOperator(condition, matcher);
7612
+ };
7613
+ //#endregion
7614
+ //#region src/rules/monitoringMatcher.ts
7615
+ const windowOf = (condition) => {
7616
+ if (!("window_minutes" in condition)) return void 0;
7617
+ return condition.window_minutes;
7618
+ };
7619
+ const accumulatedEvents = (condition, count) => {
7620
+ const { type, primitive, value } = condition;
7621
+ const matcherType = "Accumulated events";
7622
+ assert(primitive === "number", primitiveError("number"));
7623
+ assert(type === matcherType, typeError(matcherType));
7624
+ assert(value != null, "Invalid value");
7625
+ if (typeof count === "undefined") return false;
7626
+ return matchNumberOperator(condition, count);
7627
+ };
7628
+ const apiErrorRate = (condition, rate) => {
7629
+ const { type, primitive, value } = condition;
7630
+ const matcherType = "API error rate";
7631
+ assert(primitive === "number", primitiveError("number"));
7632
+ assert(type === matcherType, typeError(matcherType));
7633
+ assert(value != null, "Invalid value");
7634
+ if (typeof rate === "undefined") return false;
7635
+ return matchNumberOperator(condition, rate);
7636
+ };
7637
+ const httpStatus = (condition, status) => {
7638
+ const { type, primitive, value } = condition;
7639
+ const matcherType = "HTTP status";
7640
+ assert(primitive === "number", primitiveError("number"));
7641
+ assert(type === matcherType, typeError(matcherType));
7642
+ assert(value != null, "Invalid value");
7643
+ if (typeof status === "undefined") return false;
7644
+ return matchNumberOperator(condition, status);
7645
+ };
7646
+ const requestPath = (condition, path) => {
7647
+ const { type, primitive, value } = condition;
7648
+ const matcherType = "Request path";
7649
+ assert(primitive === "string", primitiveError("string"));
7650
+ assert(type === matcherType, typeError(matcherType));
7651
+ assert(value != null, "Invalid value");
7652
+ return matchStringOperator(condition, path);
7653
+ };
7654
+ const failureMessage = (condition, message) => {
7655
+ const { type, primitive, value } = condition;
7656
+ const matcherType = "Failure message";
7657
+ assert(primitive === "string", primitiveError("string"));
7658
+ assert(type === matcherType, typeError(matcherType));
7659
+ assert(value != null, "Invalid value");
7660
+ return matchStringOperator(condition, message);
7661
+ };
7662
+ const windowMinutes = (condition) => {
7663
+ return windowOf(condition);
7664
+ };
7665
+ //#endregion
7666
+ //#region src/rules/recurringDateCron.ts
7651
7667
  import_dayjs_min.default.extend(utc);
7652
7668
  import_dayjs_min.default.extend(timezone);
7653
7669
  import_dayjs_min.default.extend(isBetween);
@@ -7844,6 +7860,47 @@ const currentDate = (condition, referenceDate) => {
7844
7860
  return matchRecurringDateOperator(condition, current);
7845
7861
  };
7846
7862
  //#endregion
7863
+ //#region src/rules/relativeDateMatcher.ts
7864
+ const matchRelativeDateOperator = (condition, matcher, referenceDate) => {
7865
+ const { primitive, operator, value } = condition;
7866
+ assert(primitive === "relative date", primitiveError("relative date"));
7867
+ if (typeof matcher === "undefined") return false;
7868
+ assert(typeof value === "string", "Invalid relative date value");
7869
+ const [amountString, unitRaw] = value.split("/");
7870
+ assert(amountString && unitRaw, "Amount & Unit required");
7871
+ const amount = parseInt(amountString, 10);
7872
+ const unit = unitRaw;
7873
+ const issueDate = (0, import_dayjs_min.default)(referenceDate ?? (/* @__PURE__ */ new Date()).toISOString());
7874
+ const matcherDate = (0, import_dayjs_min.default)(matcher);
7875
+ switch (operator) {
7876
+ case "occurred": {
7877
+ const endDate = issueDate.subtract(amount, unit).endOf(unit);
7878
+ const startDate = endDate.startOf(unit);
7879
+ const sameStart = matcherDate.isSame(startDate, unit);
7880
+ const afterStart = matcherDate.isAfter(startDate);
7881
+ const sameEnd = matcherDate.isSame(endDate, unit);
7882
+ const beforeEnd = matcherDate.isBefore(endDate);
7883
+ return (sameStart || afterStart) && (sameEnd || beforeEnd);
7884
+ }
7885
+ case "occurred in the last": {
7886
+ const targetDate = issueDate.subtract(amount, unit);
7887
+ const sameTarget = matcherDate.isSame(targetDate, unit);
7888
+ const afterTarget = matcherDate.isAfter(targetDate);
7889
+ const sameIssue = matcherDate.isSame(issueDate, unit);
7890
+ const beforeIssue = matcherDate.isBefore(issueDate);
7891
+ return (sameTarget || afterTarget) && (sameIssue || beforeIssue);
7892
+ }
7893
+ case "occurred more than": {
7894
+ const targetDate = issueDate.subtract(amount, unit);
7895
+ return matcherDate.isBefore(targetDate, unit);
7896
+ }
7897
+ default: {
7898
+ const msg = `Operator ${operator} not supported in relative date matcher`;
7899
+ throw new Error(msg);
7900
+ }
7901
+ }
7902
+ };
7903
+ //#endregion
7847
7904
  //#region src/rules/RulesEngine.ts
7848
7905
  var RulesEngine = class {
7849
7906
  order;
@@ -7941,6 +7998,7 @@ var RulesEngine = class {
7941
7998
  const monitoring = this.getDependency("monitoring", type);
7942
7999
  return httpStatus(condition, monitoring.http_status);
7943
8000
  }
8001
+ if (type === "Customer age") return matchNumberOperator(condition, this.customerAge());
7944
8002
  throw new Error(`Condition ${type} not supported in number matcher`);
7945
8003
  };
7946
8004
  assertBoolean = (condition) => {
@@ -7998,17 +8056,40 @@ var RulesEngine = class {
7998
8056
  default: throw new Error(`Condition ${type} not supported in enum matcher`);
7999
8057
  }
8000
8058
  };
8059
+ customerAge = () => {
8060
+ const dob = this.customer?.dob;
8061
+ if (!dob) return void 0;
8062
+ const born = new Date(dob);
8063
+ const now = new Date(this.referenceDate ?? Date.now());
8064
+ if (Number.isNaN(born.getTime()) || Number.isNaN(now.getTime())) return;
8065
+ let age = now.getUTCFullYear() - born.getUTCFullYear();
8066
+ const month = now.getUTCMonth() - born.getUTCMonth();
8067
+ const beforeBirthday = now.getUTCDate() < born.getUTCDate();
8068
+ if (month < 0 || month === 0 && beforeBirthday) age -= 1;
8069
+ return age;
8070
+ };
8071
+ customerDate = (type) => {
8072
+ const customer = this.customer;
8073
+ if (type === "Birthday") return customer?.dob;
8074
+ if (type === "Registration") return customer?.registered_at;
8075
+ if (type === "Customer last visit") return customer?.last_visit_at;
8076
+ if (type === "Customer last session") return customer?.last_session_at;
8077
+ };
8001
8078
  assertAbsoluteDate = (condition) => {
8002
8079
  const { primitive, type } = condition;
8003
8080
  assert(primitive === "absolute date", primitiveError("absolute date"));
8004
- const msg = `Condition ${type} not supported in absolute date matcher`;
8005
- throw new Error(msg);
8081
+ if (type !== "Today") {
8082
+ const msg = `Condition ${type} not supported in absolute date matcher`;
8083
+ throw new Error(msg);
8084
+ }
8085
+ const today = this.referenceDate ?? (/* @__PURE__ */ new Date()).toISOString();
8086
+ return matchAbsoluteDateOperator(condition, today);
8006
8087
  };
8007
8088
  assertRelativeDate = (condition) => {
8008
8089
  const { primitive, type } = condition;
8009
8090
  assert(primitive === "relative date", primitiveError("relative date"));
8010
- const msg = `Condition ${type} not supported in relative date matcher`;
8011
- throw new Error(msg);
8091
+ const fact = this.customerDate(type);
8092
+ return matchRelativeDateOperator(condition, fact, this.referenceDate);
8012
8093
  };
8013
8094
  assertRecurringDate = (condition) => {
8014
8095
  const { primitive, type } = condition;
@@ -8113,66 +8194,6 @@ var RulesEngine = class {
8113
8194
  };
8114
8195
  };
8115
8196
  //#endregion
8116
- //#region src/rules/absoluteDateMatcher.ts
8117
- const matchAbsoluteDateOperator = (condition, matcher) => {
8118
- const { primitive, operator, value } = condition;
8119
- assert(primitive === "absolute date", primitiveError("absolute date"));
8120
- if (typeof matcher === "undefined") return false;
8121
- const matcherDate = (0, import_dayjs_min.default)(matcher);
8122
- const expectedDate = (0, import_dayjs_min.default)(value);
8123
- switch (operator) {
8124
- case "is": return matcherDate.isSame(expectedDate, "day");
8125
- case "is not": return !matcherDate.isSame(expectedDate, "day");
8126
- case "is before": return matcherDate.isBefore(expectedDate, "day");
8127
- case "is after": return matcherDate.isAfter(expectedDate, "day");
8128
- default: {
8129
- const msg = `Operator ${operator} not supported in absolute date matcher`;
8130
- throw new Error(msg);
8131
- }
8132
- }
8133
- };
8134
- //#endregion
8135
- //#region src/rules/relativeDateMatcher.ts
8136
- const matchRelativeDateOperator = (condition, matcher, referenceDate) => {
8137
- const { primitive, operator, value } = condition;
8138
- assert(primitive === "relative date", primitiveError("relative date"));
8139
- if (typeof matcher === "undefined") return false;
8140
- assert(typeof value === "string", "Invalid relative date value");
8141
- const [amountString, unitRaw] = value.split("/");
8142
- assert(amountString && unitRaw, "Amount & Unit required");
8143
- const amount = parseInt(amountString, 10);
8144
- const unit = unitRaw;
8145
- const issueDate = (0, import_dayjs_min.default)(referenceDate ?? (/* @__PURE__ */ new Date()).toISOString());
8146
- const matcherDate = (0, import_dayjs_min.default)(matcher);
8147
- switch (operator) {
8148
- case "occurred": {
8149
- const endDate = issueDate.subtract(amount, unit).endOf(unit);
8150
- const startDate = endDate.startOf(unit);
8151
- const sameStart = matcherDate.isSame(startDate, unit);
8152
- const afterStart = matcherDate.isAfter(startDate);
8153
- const sameEnd = matcherDate.isSame(endDate, unit);
8154
- const beforeEnd = matcherDate.isBefore(endDate);
8155
- return (sameStart || afterStart) && (sameEnd || beforeEnd);
8156
- }
8157
- case "occurred in the last": {
8158
- const targetDate = issueDate.subtract(amount, unit);
8159
- const sameTarget = matcherDate.isSame(targetDate, unit);
8160
- const afterTarget = matcherDate.isAfter(targetDate);
8161
- const sameIssue = matcherDate.isSame(issueDate, unit);
8162
- const beforeIssue = matcherDate.isBefore(issueDate);
8163
- return (sameTarget || afterTarget) && (sameIssue || beforeIssue);
8164
- }
8165
- case "occurred more than": {
8166
- const targetDate = issueDate.subtract(amount, unit);
8167
- return matcherDate.isBefore(targetDate, unit);
8168
- }
8169
- default: {
8170
- const msg = `Operator ${operator} not supported in relative date matcher`;
8171
- throw new Error(msg);
8172
- }
8173
- }
8174
- };
8175
- //#endregion
8176
8197
  //#region src/rules/checkout.ts
8177
8198
  const DEFAULT_SHIPPING_FIELDS = {
8178
8199
  address_line1: "required",
@@ -8625,4 +8646,4 @@ const cardPreviewGroups = (value) => {
8625
8646
  return groups;
8626
8647
  };
8627
8648
  //#endregion
8628
- export { CARD_BRANDS, DEFAULT_RECOMMENDATION_TYPES, Order, OrderSyncPendingError, OrderValidationError, RecurringDateCron, RulesEngine, StorefrontHttpError, addLines, auth, buildCustomerSnapshot, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, orderPaymentRedeems, parseExpiry, paymentMatchesClientConditions, recomputeRedemptions, recomputeTotals, redemptionCap, remainingAmount, removeLine, replaceLine, resolveCheckout, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, stripRedemptionLines, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
8649
+ export { CARD_BRANDS, DEFAULT_RECOMMENDATION_TYPES, Order, OrderSyncPendingError, OrderValidationError, RecurringDateCron, RulesEngine, StorefrontHttpError, addLines, auth, buildCustomerSnapshot, cardBrandSpec, cardDigits, cardNumberGaps, cardNumberMaxLength, cardPreviewGroups, caretAfterDigits, clampPaymentRedeems, collectOrderLineDiffs, computeStartingPrice, countCartProducts, coveredAmount, createSession, currentNodes, cvcMaxLength, defaultConditionError, detectCardBrand, flattenMenuCategories, flushLogs, formatCardNumber, formatCvc, formatExpiry, fromOrderLines, genId, genOrderId, getLogContext, getScheduleWindow, indexMenu, isCardNumberComplete, isCardNumberDefinitelyInvalid, isCheckoutFieldFilled, isCvcComplete, isDeviceCharged, isDeviceNotLinked, isExpiryComplete, isKioskUnauthorized, isMilestoneStepDone, isOnSchedule, isOrderValidationError, isPosDeviceNotLinked, isPosUnauthorized, isRealPaymentMethod, isStorefrontNotFound, isVariantBase, listMenusStream, localizePosError, log, logError, luhnCheck, matchAbsoluteDateOperator, matchBooleanOperator, matchCurrencyOperator, matchEnumOperator, matchNumberOperator, matchRecurringDateOperator, matchRelativeDateOperator, matchStringOperator, milestoneSteps, milestoneTrack, nestMenuCategories, normalizeCardholderName, orderPaymentRedeems, parseExpiry, paymentMatchesClientConditions, recomputeRedemptions, recomputeTotals, redemptionCap, remainingAmount, removeLine, replaceLine, resolveCheckout, reversePayment, runPaymentAttempt, selectablePayments, serializeError, services, setLineQuantity, storefrontJson, stripRedemptionLines, toOrderLines, toPaymentCardBrand, validateCardNumber, validateCardholderName, validateCvc, validateExpiry, validateOrderAgainstMenu, verifyWebhookSignature, visitedStates };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fire-spark/core",
3
- "version": "0.3.5",
3
+ "version": "0.4.1",
4
4
  "description": "Fire Spark headless SDK",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -20,8 +20,8 @@
20
20
  "big.js": "6.2.1",
21
21
  "dayjs": "1.11.9",
22
22
  "@types/big.js": "6.2.2",
23
- "@fire-spark/payments": "^0.3.5",
24
- "@fire-spark/types": "^0.3.5"
23
+ "@fire-spark/payments": "^0.4.1",
24
+ "@fire-spark/types": "^0.4.1"
25
25
  },
26
26
  "devDependencies": {
27
27
  "tsdown": "^0.22.14",