@classytic/promo 0.2.0 → 0.2.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.
package/README.md CHANGED
@@ -151,7 +151,7 @@ if (result.appliedDiscounts.length > 0) {
151
151
  - stacking cap (`stackingMode: 'exclusive'` blocks subsequent programs; `maxStackablePromotions` caps the stackable chain).
152
152
  5. **Best-rule matching** — for each program, `matchBestRule` picks the highest-threshold rule whose gates all pass (code, date range, minimumAmount, minimumQuantity, product/category/SKU filters, `buyQuantity`). Scoring: `minimumAmount * 1000 + minimumQuantity`.
153
153
  6. **Reward computation** — linked rewards run through `computeDiscount` (scope-aware: `order`, `cheapest`, or `specific_products`; `maxDiscountAmount` capped; never exceeds running subtotal) or emit a `FreeProductLine`. The `runningSubtotal` decreases as each discount stacks.
154
- 7. **Cart-hash + evaluation stash** — a SHA-256 hash of the normalized items + subtotal + codes + customer identity is computed and returned on the `EvaluationResult`. Non-preview evaluations are stashed in an in-memory pending map keyed by `evaluationId` so `commit()` can replay program + voucher usage writes inside a single transaction.
154
+ 7. **Cart-hash + evaluation snapshot** — a SHA-256 hash of the normalized items + subtotal + codes + customer identity is computed and returned on the `EvaluationResult`. Non-preview evaluations are persisted via the configured `EvaluationStore` (Mongo by default; hosts can plug Redis / DynamoDB / custom by implementing the port) so `commit()` can replay program + voucher usage writes inside a single transaction. Snapshots survive process restart, horizontal scaling, serverless cold starts, and worker handoff. The default Mongo store applies a TTL index so abandoned snapshots auto-expire (default 30 min).
155
155
  8. **Dispatch `EVALUATION_COMPLETED`** via `dispatchPromoEvent` — routed through the configured `events.transport` and optionally persisted via the host `outbox` inside `ctx.session`.
156
156
 
157
157
  `commit(evaluationId, orderId, ctx, { cartHash })` (same service) consumes the stash: it optionally re-verifies the submitted `cartHash` (throws `CartHashMismatchError` on mismatch), opens a transaction, increments `program.usedCount` + per-customer usage on every applied program, increments voucher usage + appends a redemption record per applied voucher, emits `EVALUATION_COMMITTED`, and returns a `CommitResult`. `rollback(evaluationId, ctx)` drops the stash and emits `EVALUATION_ROLLED_BACK`.
@@ -171,7 +171,7 @@ All four repositories extend mongokit's `Repository<T>` directly — no wrapper
171
171
  | `reward` | (inherited only) |
172
172
  | `voucher` | `cancel`, `incrementUsage` (atomic `$inc` + `$push`), `addLedgerEntry` (atomic balance delta + ledger push), `expireByDate`, `getByCode`, `hasIdempotencyKey` |
173
173
 
174
- The two services (`engine.services.voucher`, `engine.services.evaluation`) exist because they coordinate multiple repositories + transactions + config: code generation + redemption + gift-card spend/top-up for vouchers, and the multi-program evaluation algorithm + in-memory pending-commit stash for evaluations.
174
+ The two services (`engine.services.voucher`, `engine.services.evaluation`) exist because they coordinate multiple repositories + transactions + config: code generation + redemption + gift-card spend/top-up for vouchers, and the multi-program evaluation algorithm + persistent evaluation snapshot store for evaluations.
175
175
 
176
176
  ---
177
177
 
@@ -203,7 +203,7 @@ engine.events.subscribe?.(PromoEvents.VOUCHER_REDEEMED, async (evt) => {
203
203
  });
204
204
  ```
205
205
 
206
- Representative event names: `promo:program.created` / `.activated` / `.paused` / `.archived`, `promo:rule.added` / `.updated` / `.removed`, `promo:reward.added` / `.updated` / `.removed`, `promo:voucher.generated` / `.redeemed` / `.cancelled` / `.expired`, `promo:gift_card.spent` / `.topped_up` / `.exhausted`, `promo:evaluation.completed` / `.committed` / `.rolled_back`.
206
+ Representative event names: `promo.program.created` / `.activated` / `.paused` / `.archived`, `promo.rule.added` / `.updated` / `.removed`, `promo.reward.added` / `.updated` / `.removed`, `promo.voucher.generated` / `.redeemed` / `.cancelled` / `.expired`, `promo.gift_card.spent` / `.topped_up` / `.exhausted`, `promo.evaluation.completed` / `.committed` / `.rolled_back`. The full canonical list is exported as `PromoEvents` from the package root.
207
207
 
208
208
  ---
209
209