@classytic/loyalty 0.2.1 → 0.2.3
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 +33 -0
- package/README.md +7 -0
- package/dist/{config-DoZPGBfW.d.mts → config-96Sl6oNJ.d.mts} +1 -1
- package/dist/events/index.d.mts +1 -1
- package/dist/{index-ClPKmtxh.d.mts → index-Cl-WGBFJ.d.mts} +21 -3
- package/dist/{index-C4jFHS7m.d.mts → index-DArT4zkB.d.mts} +1 -1
- package/dist/{index-BOWqBSWx.d.mts → index-DWarXsmw.d.mts} +22 -0
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +7 -5
- package/dist/models/index.d.mts +49 -1
- package/dist/models/index.mjs +1 -1
- package/dist/{models-uhh9c-7k.mjs → models-0_OQIqBy.mjs} +25 -1
- package/dist/repositories/index.d.mts +1 -1
- package/dist/repositories/index.mjs +1 -1
- package/dist/{repositories-DBSxe9st.mjs → repositories-BMwidCp-.mjs} +18 -5
- package/dist/types/index.d.mts +2 -2
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,39 @@
|
|
|
3
3
|
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
4
4
|
adhering to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
5
5
|
|
|
6
|
+
## [0.2.3] — 2026-05-08
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **§P8 dispatch — `outbox.save` failures now propagate.** [src/events/dispatch.ts](src/events/dispatch.ts)
|
|
11
|
+
previously caught `outbox.save` errors and swallowed them silently. Per
|
|
12
|
+
PACKAGE_RULES §P8 the outbox row is the durability anchor for the
|
|
13
|
+
transactional-outbox pattern: if the save fails, the caller's transaction
|
|
14
|
+
MUST roll back so the business doc and the event row land atomically.
|
|
15
|
+
Swallowing the failure meant a parent doc could commit while the event
|
|
16
|
+
vanished, with no relay row to recover from. Fix re-throws after logging.
|
|
17
|
+
`events.publish` failures continue to be swallowed (correctly, per §P8 —
|
|
18
|
+
the host's outbox relay re-publishes from the durable row), but now log
|
|
19
|
+
before swallowing so failures are observable.
|
|
20
|
+
- **`DispatchDeps.logger` field added.** Optional. Both arms of the
|
|
21
|
+
dispatch helper log through it when set, surfacing failures in the host's
|
|
22
|
+
observability stack without coupling the package to a specific logger.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **Peer-dep ranges tightened** — `@classytic/mongokit` `>=3.13.3`
|
|
27
|
+
(was `>=3.13.0`) and `@classytic/repo-core` `>=0.4.2` (was `>=0.4.0`).
|
|
28
|
+
3.13.3 preserves `errorLabels` on `MongoServerError` so concurrent
|
|
29
|
+
transactional writes (the `claim()`-based redemption + tier-eval paths)
|
|
30
|
+
retry correctly under contention; 0.4.2 adds the typed `FindAllOptions`
|
|
31
|
+
shape with `limit?` for callers that need a bounded non-paginated read.
|
|
32
|
+
|
|
33
|
+
### Internal
|
|
34
|
+
|
|
35
|
+
- Replaced 4 `arr.find()!` non-null assertions in [src/index.ts](src/index.ts)
|
|
36
|
+
+ scenario tests with explicit narrowing — TS now proves what the runtime
|
|
37
|
+
shape already guaranteed.
|
|
38
|
+
|
|
6
39
|
## [0.2.0]
|
|
7
40
|
|
|
8
41
|
Structural rewrite on top of the 0.1.0 shape. The public API is now a
|
package/README.md
CHANGED
|
@@ -139,6 +139,13 @@ import type {
|
|
|
139
139
|
} from '@classytic/loyalty';
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
+
## Migration Notes
|
|
143
|
+
|
|
144
|
+
Earning rates now live in earning rules, not host membership config fields such
|
|
145
|
+
as `PlatformConfig.membership.pointsPerAmount` or `amountPerPoint`. See
|
|
146
|
+
[docs/config-engine-migration.md](docs/config-engine-migration.md) for the
|
|
147
|
+
`LoyaltyConfig` to engine boundary and migration checklist.
|
|
148
|
+
|
|
142
149
|
## Events
|
|
143
150
|
|
|
144
151
|
```typescript
|
|
@@ -2,7 +2,7 @@ import { t as NotificationAdapter } from "./notification.port-CJ9nXj0k.mjs";
|
|
|
2
2
|
import { EventTransport } from "@classytic/primitives/events";
|
|
3
3
|
import { Connection } from "mongoose";
|
|
4
4
|
import { OutboxStore } from "@classytic/primitives/outbox";
|
|
5
|
-
import { TenantConfig, TenantFieldType } from "@classytic/
|
|
5
|
+
import { TenantConfig, TenantFieldType } from "@classytic/repo-core/tenant";
|
|
6
6
|
|
|
7
7
|
//#region src/types/config.d.ts
|
|
8
8
|
type LoyaltyModelName = 'Member' | 'PointTransaction' | 'EarningRule' | 'TierDefinition' | 'Redemption' | 'Referral';
|
package/dist/events/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as PointsExpired, B as ReferralRewarded, C as MemberDeactivated, D as MultiTierReferralAwarded, E as MemberSuspended, F as RedemptionReserved, G as TierUpgraded, H as TierGraceStarted, I as RedemptionReversed, J as InProcessLoyaltyBusOptions, K as loyaltyEventDefinitions, L as ReferralApproved, M as PointsRedeemed, N as RedemptionConfirmed, O as PointsAdjusted, P as RedemptionReleased, R as ReferralRecorded, S as LoyaltyEventSchema, T as MemberReactivated, U as TierOverrideCleared, V as TierDowngraded, W as TierOverrideExpired, Y as createEvent, _ as TierChangedPayload, a as LoyaltyEventMap, b as LoyaltyEventDefinition, c as LoyaltyEvents, d as PointsAdjustedPayload, f as PointsEarnedPayload, g as ReferralPayload, h as RedemptionReversedPayload, i as CampaignAwardedPayload, j as PointsExpiringSoon, k as PointsEarned, l as MemberLifecyclePayload, m as RedemptionPayload, n as EventHandler, o as LoyaltyEventName, p as PointsExpiredPayload, q as InProcessLoyaltyBus, r as EventTransport, s as LoyaltyEventPayload, t as DomainEvent, u as MultiTierReferralAwardedPayload, v as TierOverrideLifecyclePayload, w as MemberEnrolled, x as LoyaltyEventPayloadOf, y as CampaignAwarded, z as ReferralRejected } from "../index-
|
|
1
|
+
import { A as PointsExpired, B as ReferralRewarded, C as MemberDeactivated, D as MultiTierReferralAwarded, E as MemberSuspended, F as RedemptionReserved, G as TierUpgraded, H as TierGraceStarted, I as RedemptionReversed, J as InProcessLoyaltyBusOptions, K as loyaltyEventDefinitions, L as ReferralApproved, M as PointsRedeemed, N as RedemptionConfirmed, O as PointsAdjusted, P as RedemptionReleased, R as ReferralRecorded, S as LoyaltyEventSchema, T as MemberReactivated, U as TierOverrideCleared, V as TierDowngraded, W as TierOverrideExpired, Y as createEvent, _ as TierChangedPayload, a as LoyaltyEventMap, b as LoyaltyEventDefinition, c as LoyaltyEvents, d as PointsAdjustedPayload, f as PointsEarnedPayload, g as ReferralPayload, h as RedemptionReversedPayload, i as CampaignAwardedPayload, j as PointsExpiringSoon, k as PointsEarned, l as MemberLifecyclePayload, m as RedemptionPayload, n as EventHandler, o as LoyaltyEventName, p as PointsExpiredPayload, q as InProcessLoyaltyBus, r as EventTransport, s as LoyaltyEventPayload, t as DomainEvent, u as MultiTierReferralAwardedPayload, v as TierOverrideLifecyclePayload, w as MemberEnrolled, x as LoyaltyEventPayloadOf, y as CampaignAwarded, z as ReferralRejected } from "../index-DArT4zkB.mjs";
|
|
2
2
|
export { CampaignAwarded, CampaignAwardedPayload, DomainEvent, EventHandler, EventTransport, InProcessLoyaltyBus, InProcessLoyaltyBusOptions, LoyaltyEventDefinition, LoyaltyEventMap, LoyaltyEventName, LoyaltyEventPayload, LoyaltyEventPayloadOf, LoyaltyEventSchema, LoyaltyEvents, MemberDeactivated, MemberEnrolled, MemberLifecyclePayload, MemberReactivated, MemberSuspended, MultiTierReferralAwarded, MultiTierReferralAwardedPayload, PointsAdjusted, PointsAdjustedPayload, PointsEarned, PointsEarnedPayload, PointsExpired, PointsExpiredPayload, PointsExpiringSoon, PointsRedeemed, RedemptionConfirmed, RedemptionPayload, RedemptionReleased, RedemptionReserved, RedemptionReversed, RedemptionReversedPayload, ReferralApproved, ReferralPayload, ReferralRecorded, ReferralRejected, ReferralRewarded, TierChangedPayload, TierDowngraded, TierGraceStarted, TierOverrideCleared, TierOverrideExpired, TierOverrideLifecyclePayload, TierUpgraded, createEvent, loyaltyEventDefinitions };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { i as ReferralStatus, r as RedemptionStatus } from "./index-DMK8a98J.mjs";
|
|
2
|
-
import { S as EarningRule, _ as TierEvaluationBatch, d as EarningResult, f as ExpirationResult, g as TierEvaluation, h as RedemptionValidation, o as LoyaltyContext, v as PointTransaction, x as TierDefinition, y as Member } from "./index-
|
|
2
|
+
import { S as EarningRule, _ as TierEvaluationBatch, d as EarningResult, f as ExpirationResult, g as TierEvaluation, h as RedemptionValidation, o as LoyaltyContext, v as PointTransaction, x as TierDefinition, y as Member } from "./index-DWarXsmw.mjs";
|
|
3
3
|
import { t as NotificationAdapter } from "./notification.port-CJ9nXj0k.mjs";
|
|
4
|
-
import { c as ResolvedTenant, o as RepositoryPlugins, s as ResolvedConfig } from "./config-
|
|
4
|
+
import { c as ResolvedTenant, o as RepositoryPlugins, s as ResolvedConfig } from "./config-96Sl6oNJ.mjs";
|
|
5
5
|
import { LoyaltyModels } from "./models/index.mjs";
|
|
6
6
|
import { EventTransport } from "@classytic/primitives/events";
|
|
7
7
|
import { ClientSession, Model } from "mongoose";
|
|
8
8
|
import { PluginType, Repository } from "@classytic/mongokit";
|
|
9
9
|
import { OutboxStore } from "@classytic/primitives/outbox";
|
|
10
|
+
import { ApprovalChain } from "@classytic/primitives/approval";
|
|
10
11
|
|
|
11
12
|
//#region src/domain/ports/unit-of-work.port.d.ts
|
|
12
13
|
interface UnitOfWork {
|
|
@@ -134,7 +135,12 @@ declare class EarningRuleRepository extends Repository<EarningRule> {
|
|
|
134
135
|
txRepo: PointTransactionRepository;
|
|
135
136
|
config: ResolvedConfig;
|
|
136
137
|
constructor(model: Model<EarningRule>, plugins?: PluginType[]);
|
|
137
|
-
|
|
138
|
+
private applyCreateDefaults;
|
|
139
|
+
/**
|
|
140
|
+
* Auto-injects `programId` from `LoyaltyConfig.program.id` and the tenant id
|
|
141
|
+
* from repo options when omitted. This keeps custom-program engines aligned
|
|
142
|
+
* with `MemberRepository.enroll(...)`, which uses the same config default.
|
|
143
|
+
*/
|
|
138
144
|
create(data: Parameters<Repository<EarningRule>['create']>[0], options?: Parameters<Repository<EarningRule>['create']>[1]): Promise<EarningRule>;
|
|
139
145
|
createMany(docs: Parameters<Repository<EarningRule>['createMany']>[0], options?: Parameters<Repository<EarningRule>['createMany']>[1]): Promise<EarningRule[]>;
|
|
140
146
|
evaluateOrder(input: {
|
|
@@ -187,6 +193,18 @@ interface Redemption {
|
|
|
187
193
|
*/
|
|
188
194
|
initialBalance?: number;
|
|
189
195
|
remainingBalance?: number;
|
|
196
|
+
/**
|
|
197
|
+
* Optional multi-step approval chain (P7 canonical — same shape as
|
|
198
|
+
* `@classytic/purchase` / `@classytic/order`). High-value redemptions
|
|
199
|
+
* (gift cards above threshold, large discount vouchers) gate on
|
|
200
|
+
* `isApproved(approvals)` before `confirm()` flips the FSM. Single-tier
|
|
201
|
+
* flows skip the chain entirely.
|
|
202
|
+
*/
|
|
203
|
+
approvals?: ApprovalChain | null;
|
|
204
|
+
/** Snapshot of the matrix policy id that produced this chain (host-managed). */
|
|
205
|
+
approvalPolicyId?: string | null;
|
|
206
|
+
/** Version of the matrix policy at submit time — frozen for audit. */
|
|
207
|
+
approvalPolicyVersion?: number | null;
|
|
190
208
|
createdAt: Date;
|
|
191
209
|
updatedAt: Date;
|
|
192
210
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as LoyaltyContext } from "./index-
|
|
1
|
+
import { o as LoyaltyContext } from "./index-DWarXsmw.mjs";
|
|
2
2
|
import { DomainEvent, DomainEvent as DomainEvent$1, EventHandler, EventHandler as EventHandler$1, EventTransport, EventTransport as EventTransport$1 } from "@classytic/primitives/events";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { a as RuleStatus, n as MemberStatus, o as RuleType, s as TransactionType } from "./index-DMK8a98J.mjs";
|
|
2
2
|
import { OperationContext } from "@classytic/primitives/context";
|
|
3
|
+
import { ApprovalChain } from "@classytic/primitives/approval";
|
|
3
4
|
|
|
4
5
|
//#region src/domain/entities/earning-rule.d.ts
|
|
5
6
|
interface EarningConditions {
|
|
@@ -124,6 +125,19 @@ interface PointTransaction {
|
|
|
124
125
|
expiredAt?: Date;
|
|
125
126
|
metadata?: Record<string, unknown>;
|
|
126
127
|
actorId: string;
|
|
128
|
+
/**
|
|
129
|
+
* Optional multi-step approval chain (P7 canonical — same shape as
|
|
130
|
+
* `@classytic/purchase` / `@classytic/order`). Manual `adjustment` /
|
|
131
|
+
* `bonus` transactions above a host-defined threshold gate on
|
|
132
|
+
* `isApproved(approvals)` before the journal entry is committed.
|
|
133
|
+
* Automatic transactions (earn from purchase, expiry sweeps) skip the
|
|
134
|
+
* chain entirely — single-tier flows leave this null.
|
|
135
|
+
*/
|
|
136
|
+
approvals?: ApprovalChain | null;
|
|
137
|
+
/** Snapshot of the matrix policy id that produced this chain (host-managed). */
|
|
138
|
+
approvalPolicyId?: string | null;
|
|
139
|
+
/** Version of the matrix policy at submit time — frozen for audit. */
|
|
140
|
+
approvalPolicyVersion?: number | null;
|
|
127
141
|
createdAt: Date;
|
|
128
142
|
}
|
|
129
143
|
//#endregion
|
|
@@ -245,6 +259,14 @@ interface CreateEarningRuleInput {
|
|
|
245
259
|
reward: EarningReward;
|
|
246
260
|
startsAt?: Date | string;
|
|
247
261
|
endsAt?: Date | string;
|
|
262
|
+
/**
|
|
263
|
+
* Loyalty program this rule belongs to.
|
|
264
|
+
*
|
|
265
|
+
* Optional for repository-created rules: `EarningRuleRepository.create(...)`
|
|
266
|
+
* and `createMany(...)` fill this from `LoyaltyConfig.program.id`, matching
|
|
267
|
+
* the default used by `MemberRepository.enroll(...)`. Pass explicitly only
|
|
268
|
+
* when creating a rule for a different program.
|
|
269
|
+
*/
|
|
248
270
|
programId?: string;
|
|
249
271
|
metadata?: Record<string, unknown>;
|
|
250
272
|
}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { S as EarningRule, a as EnrollInput, b as MemberBalance, c as UpdateTierInput, d as EarningResult, g as TierEvaluation, h as RedemptionValidation, i as EarnPointsInput, l as BalanceSummary, n as CreateEarningRuleInput, o as LoyaltyContext, r as CreateTierInput, s as UpdateEarningRuleInput, t as AdjustPointsInput, v as PointTransaction, x as TierDefinition, y as Member } from "./index-
|
|
1
|
+
import { S as EarningRule, a as EnrollInput, b as MemberBalance, c as UpdateTierInput, d as EarningResult, g as TierEvaluation, h as RedemptionValidation, i as EarnPointsInput, l as BalanceSummary, n as CreateEarningRuleInput, o as LoyaltyContext, r as CreateTierInput, s as UpdateEarningRuleInput, t as AdjustPointsInput, v as PointTransaction, x as TierDefinition, y as Member } from "./index-DWarXsmw.mjs";
|
|
2
2
|
import { t as NotificationAdapter } from "./notification.port-CJ9nXj0k.mjs";
|
|
3
|
-
import { c as ResolvedTenant, n as LoyaltyConfig, r as LoyaltyModelName, s as ResolvedConfig } from "./config-
|
|
4
|
-
import { A as PointsExpired, B as ReferralRewarded, C as MemberDeactivated, E as MemberSuspended, F as RedemptionReserved, G as TierUpgraded, H as TierGraceStarted, J as InProcessLoyaltyBusOptions, K as loyaltyEventDefinitions, L as ReferralApproved, M as PointsRedeemed, N as RedemptionConfirmed, O as PointsAdjusted, P as RedemptionReleased, R as ReferralRecorded, S as LoyaltyEventSchema, T as MemberReactivated, V as TierDowngraded, Y as createEvent, _ as TierChangedPayload, a as LoyaltyEventMap, b as LoyaltyEventDefinition, c as LoyaltyEvents, d as PointsAdjustedPayload, f as PointsEarnedPayload, g as ReferralPayload, j as PointsExpiringSoon, k as PointsEarned, l as MemberLifecyclePayload, m as RedemptionPayload, o as LoyaltyEventName, p as PointsExpiredPayload, q as InProcessLoyaltyBus, s as LoyaltyEventPayload, w as MemberEnrolled, x as LoyaltyEventPayloadOf, z as ReferralRejected } from "./index-
|
|
3
|
+
import { c as ResolvedTenant, n as LoyaltyConfig, r as LoyaltyModelName, s as ResolvedConfig } from "./config-96Sl6oNJ.mjs";
|
|
4
|
+
import { A as PointsExpired, B as ReferralRewarded, C as MemberDeactivated, E as MemberSuspended, F as RedemptionReserved, G as TierUpgraded, H as TierGraceStarted, J as InProcessLoyaltyBusOptions, K as loyaltyEventDefinitions, L as ReferralApproved, M as PointsRedeemed, N as RedemptionConfirmed, O as PointsAdjusted, P as RedemptionReleased, R as ReferralRecorded, S as LoyaltyEventSchema, T as MemberReactivated, V as TierDowngraded, Y as createEvent, _ as TierChangedPayload, a as LoyaltyEventMap, b as LoyaltyEventDefinition, c as LoyaltyEvents, d as PointsAdjustedPayload, f as PointsEarnedPayload, g as ReferralPayload, j as PointsExpiringSoon, k as PointsEarned, l as MemberLifecyclePayload, m as RedemptionPayload, o as LoyaltyEventName, p as PointsExpiredPayload, q as InProcessLoyaltyBus, s as LoyaltyEventPayload, w as MemberEnrolled, x as LoyaltyEventPayloadOf, z as ReferralRejected } from "./index-DArT4zkB.mjs";
|
|
5
5
|
import { LoyaltyModels } from "./models/index.mjs";
|
|
6
|
-
import { a as ReferralRepository, c as Redemption, d as MemberRepository, f as UnitOfWork, i as TierDefinitionRepository, l as EarningRuleRepository, n as LoyaltyRepositories, o as Referral, s as RedemptionRepository, u as PointTransactionRepository } from "./index-
|
|
6
|
+
import { a as ReferralRepository, c as Redemption, d as MemberRepository, f as UnitOfWork, i as TierDefinitionRepository, l as EarningRuleRepository, n as LoyaltyRepositories, o as Referral, s as RedemptionRepository, u as PointTransactionRepository } from "./index-Cl-WGBFJ.mjs";
|
|
7
7
|
import { DomainEvent, EventHandler, EventTransport, EventTransport as EventTransport$1 } from "@classytic/primitives/events";
|
|
8
8
|
|
|
9
9
|
//#region src/index.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as DEFAULT_TENANT_FIELD, r as DEFAULT_TENANT_TYPE } from "./constants-DkQYkOK1.mjs";
|
|
2
|
-
import { a as PointTransactionRepository, c as ValidationError, i as RedemptionRepository, n as TierDefinitionRepository, o as MemberRepository, r as ReferralRepository, s as EarningRuleRepository, t as createRepositories } from "./repositories-
|
|
2
|
+
import { a as PointTransactionRepository, c as ValidationError, i as RedemptionRepository, n as TierDefinitionRepository, o as MemberRepository, r as ReferralRepository, s as EarningRuleRepository, t as createRepositories } from "./repositories-BMwidCp-.mjs";
|
|
3
3
|
import { E as InProcessLoyaltyBus, T as loyaltyEventDefinitions, _ as ReferralRecorded, a as MemberSuspended, b as TierDowngraded, c as PointsEarned, d as PointsRedeemed, f as RedemptionConfirmed, g as ReferralApproved, i as MemberReactivated, l as PointsExpired, m as RedemptionReserved, n as MemberDeactivated, p as RedemptionReleased, r as MemberEnrolled, s as PointsAdjusted, u as PointsExpiringSoon, v as ReferralRejected, w as TierUpgraded, x as TierGraceStarted, y as ReferralRewarded } from "./events-BtZOdiPw.mjs";
|
|
4
|
-
import { n as createModels } from "./models-
|
|
4
|
+
import { n as createModels } from "./models-0_OQIqBy.mjs";
|
|
5
5
|
import { n as createEvent, t as LoyaltyEvents } from "./loyalty-events-Cyt9TwX6.mjs";
|
|
6
6
|
//#region src/index.ts
|
|
7
7
|
function resolveConfig(config) {
|
|
@@ -62,11 +62,13 @@ var MongoUnitOfWork = class {
|
|
|
62
62
|
async withTransaction(cb) {
|
|
63
63
|
const session = await this.connection.startSession();
|
|
64
64
|
try {
|
|
65
|
-
|
|
65
|
+
const slot = { assigned: false };
|
|
66
66
|
await session.withTransaction(async () => {
|
|
67
|
-
|
|
67
|
+
slot.value = await cb(session);
|
|
68
|
+
slot.assigned = true;
|
|
68
69
|
});
|
|
69
|
-
|
|
70
|
+
if (!slot.assigned) throw new Error("withTransaction: callback did not assign a result");
|
|
71
|
+
return slot.value;
|
|
70
72
|
} finally {
|
|
71
73
|
await session.endSession();
|
|
72
74
|
}
|
package/dist/models/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as ResolvedTenant, i as ModelName, r as LoyaltyModelName, t as IndexDefinition } from "../config-
|
|
1
|
+
import { c as ResolvedTenant, i as ModelName, r as LoyaltyModelName, t as IndexDefinition } from "../config-96Sl6oNJ.mjs";
|
|
2
2
|
import * as _$mongoose from "mongoose";
|
|
3
3
|
import { Connection, Model } from "mongoose";
|
|
4
4
|
|
|
@@ -243,6 +243,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
243
243
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
244
244
|
expiresAt?: NativeDate | null | undefined;
|
|
245
245
|
expiredAt?: NativeDate | null | undefined;
|
|
246
|
+
approvals?: any;
|
|
247
|
+
approvalPolicyId?: string | null | undefined;
|
|
248
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
246
249
|
createdAt: NativeDate;
|
|
247
250
|
}, {}, {}, {
|
|
248
251
|
id: string;
|
|
@@ -261,6 +264,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
261
264
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
262
265
|
expiresAt?: NativeDate | null | undefined;
|
|
263
266
|
expiredAt?: NativeDate | null | undefined;
|
|
267
|
+
approvals?: any;
|
|
268
|
+
approvalPolicyId?: string | null | undefined;
|
|
269
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
264
270
|
createdAt: NativeDate;
|
|
265
271
|
}, {
|
|
266
272
|
id: string;
|
|
@@ -284,6 +290,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
284
290
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
285
291
|
expiresAt?: NativeDate | null | undefined;
|
|
286
292
|
expiredAt?: NativeDate | null | undefined;
|
|
293
|
+
approvals?: any;
|
|
294
|
+
approvalPolicyId?: string | null | undefined;
|
|
295
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
287
296
|
createdAt: NativeDate;
|
|
288
297
|
} & {
|
|
289
298
|
_id: _$mongoose.Types.ObjectId;
|
|
@@ -311,6 +320,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
311
320
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
312
321
|
expiresAt?: NativeDate | null | undefined;
|
|
313
322
|
expiredAt?: NativeDate | null | undefined;
|
|
323
|
+
approvals?: any;
|
|
324
|
+
approvalPolicyId?: string | null | undefined;
|
|
325
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
314
326
|
createdAt: NativeDate;
|
|
315
327
|
}, _$mongoose.Document<unknown, {}, {
|
|
316
328
|
programId: string;
|
|
@@ -327,6 +339,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
327
339
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
328
340
|
expiresAt?: NativeDate | null | undefined;
|
|
329
341
|
expiredAt?: NativeDate | null | undefined;
|
|
342
|
+
approvals?: any;
|
|
343
|
+
approvalPolicyId?: string | null | undefined;
|
|
344
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
330
345
|
createdAt: NativeDate;
|
|
331
346
|
}, {
|
|
332
347
|
id: string;
|
|
@@ -350,6 +365,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
350
365
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
351
366
|
expiresAt?: NativeDate | null | undefined;
|
|
352
367
|
expiredAt?: NativeDate | null | undefined;
|
|
368
|
+
approvals?: any;
|
|
369
|
+
approvalPolicyId?: string | null | undefined;
|
|
370
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
353
371
|
createdAt: NativeDate;
|
|
354
372
|
} & {
|
|
355
373
|
_id: _$mongoose.Types.ObjectId;
|
|
@@ -372,6 +390,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
372
390
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
373
391
|
expiresAt?: NativeDate | null | undefined;
|
|
374
392
|
expiredAt?: NativeDate | null | undefined;
|
|
393
|
+
approvals?: any;
|
|
394
|
+
approvalPolicyId?: string | null | undefined;
|
|
395
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
375
396
|
createdAt: NativeDate;
|
|
376
397
|
} & {
|
|
377
398
|
_id: _$mongoose.Types.ObjectId;
|
|
@@ -392,6 +413,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
392
413
|
earningRuleId?: _$mongoose.Types.ObjectId | null | undefined;
|
|
393
414
|
expiresAt?: NativeDate | null | undefined;
|
|
394
415
|
expiredAt?: NativeDate | null | undefined;
|
|
416
|
+
approvals?: any;
|
|
417
|
+
approvalPolicyId?: string | null | undefined;
|
|
418
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
395
419
|
createdAt: NativeDate;
|
|
396
420
|
} & {
|
|
397
421
|
_id: _$mongoose.Types.ObjectId;
|
|
@@ -883,6 +907,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
883
907
|
ownerType: string;
|
|
884
908
|
ownerId: string;
|
|
885
909
|
expiresAt?: NativeDate | null | undefined;
|
|
910
|
+
approvals?: any;
|
|
911
|
+
approvalPolicyId?: string | null | undefined;
|
|
912
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
886
913
|
confirmedAt?: NativeDate | null | undefined;
|
|
887
914
|
releasedAt?: NativeDate | null | undefined;
|
|
888
915
|
reversedAt?: NativeDate | null | undefined;
|
|
@@ -904,6 +931,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
904
931
|
ownerType: string;
|
|
905
932
|
ownerId: string;
|
|
906
933
|
expiresAt?: NativeDate | null | undefined;
|
|
934
|
+
approvals?: any;
|
|
935
|
+
approvalPolicyId?: string | null | undefined;
|
|
936
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
907
937
|
confirmedAt?: NativeDate | null | undefined;
|
|
908
938
|
releasedAt?: NativeDate | null | undefined;
|
|
909
939
|
reversedAt?: NativeDate | null | undefined;
|
|
@@ -927,6 +957,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
927
957
|
ownerType: string;
|
|
928
958
|
ownerId: string;
|
|
929
959
|
expiresAt?: NativeDate | null | undefined;
|
|
960
|
+
approvals?: any;
|
|
961
|
+
approvalPolicyId?: string | null | undefined;
|
|
962
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
930
963
|
confirmedAt?: NativeDate | null | undefined;
|
|
931
964
|
releasedAt?: NativeDate | null | undefined;
|
|
932
965
|
reversedAt?: NativeDate | null | undefined;
|
|
@@ -954,6 +987,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
954
987
|
ownerType: string;
|
|
955
988
|
ownerId: string;
|
|
956
989
|
expiresAt?: NativeDate | null | undefined;
|
|
990
|
+
approvals?: any;
|
|
991
|
+
approvalPolicyId?: string | null | undefined;
|
|
992
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
957
993
|
confirmedAt?: NativeDate | null | undefined;
|
|
958
994
|
releasedAt?: NativeDate | null | undefined;
|
|
959
995
|
reversedAt?: NativeDate | null | undefined;
|
|
@@ -973,6 +1009,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
973
1009
|
ownerType: string;
|
|
974
1010
|
ownerId: string;
|
|
975
1011
|
expiresAt?: NativeDate | null | undefined;
|
|
1012
|
+
approvals?: any;
|
|
1013
|
+
approvalPolicyId?: string | null | undefined;
|
|
1014
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
976
1015
|
confirmedAt?: NativeDate | null | undefined;
|
|
977
1016
|
releasedAt?: NativeDate | null | undefined;
|
|
978
1017
|
reversedAt?: NativeDate | null | undefined;
|
|
@@ -996,6 +1035,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
996
1035
|
ownerType: string;
|
|
997
1036
|
ownerId: string;
|
|
998
1037
|
expiresAt?: NativeDate | null | undefined;
|
|
1038
|
+
approvals?: any;
|
|
1039
|
+
approvalPolicyId?: string | null | undefined;
|
|
1040
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
999
1041
|
confirmedAt?: NativeDate | null | undefined;
|
|
1000
1042
|
releasedAt?: NativeDate | null | undefined;
|
|
1001
1043
|
reversedAt?: NativeDate | null | undefined;
|
|
@@ -1021,6 +1063,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
1021
1063
|
ownerType: string;
|
|
1022
1064
|
ownerId: string;
|
|
1023
1065
|
expiresAt?: NativeDate | null | undefined;
|
|
1066
|
+
approvals?: any;
|
|
1067
|
+
approvalPolicyId?: string | null | undefined;
|
|
1068
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
1024
1069
|
confirmedAt?: NativeDate | null | undefined;
|
|
1025
1070
|
releasedAt?: NativeDate | null | undefined;
|
|
1026
1071
|
reversedAt?: NativeDate | null | undefined;
|
|
@@ -1046,6 +1091,9 @@ declare function createModels(connection: Connection, tenant: ResolvedTenant, in
|
|
|
1046
1091
|
ownerType: string;
|
|
1047
1092
|
ownerId: string;
|
|
1048
1093
|
expiresAt?: NativeDate | null | undefined;
|
|
1094
|
+
approvals?: any;
|
|
1095
|
+
approvalPolicyId?: string | null | undefined;
|
|
1096
|
+
approvalPolicyVersion?: number | null | undefined;
|
|
1049
1097
|
confirmedAt?: NativeDate | null | undefined;
|
|
1050
1098
|
releasedAt?: NativeDate | null | undefined;
|
|
1051
1099
|
reversedAt?: NativeDate | null | undefined;
|
package/dist/models/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createModels, t as LoyaltyModelCollisionError } from "../models-
|
|
1
|
+
import { n as createModels, t as LoyaltyModelCollisionError } from "../models-0_OQIqBy.mjs";
|
|
2
2
|
export { LoyaltyModelCollisionError, createModels };
|
|
@@ -232,6 +232,18 @@ function createPointTransactionSchema() {
|
|
|
232
232
|
actorId: {
|
|
233
233
|
type: String,
|
|
234
234
|
required: true
|
|
235
|
+
},
|
|
236
|
+
approvals: {
|
|
237
|
+
type: mongoose.Schema.Types.Mixed,
|
|
238
|
+
default: null
|
|
239
|
+
},
|
|
240
|
+
approvalPolicyId: {
|
|
241
|
+
type: String,
|
|
242
|
+
default: null
|
|
243
|
+
},
|
|
244
|
+
approvalPolicyVersion: {
|
|
245
|
+
type: Number,
|
|
246
|
+
default: null
|
|
235
247
|
}
|
|
236
248
|
}, { timestamps: {
|
|
237
249
|
createdAt: true,
|
|
@@ -297,7 +309,19 @@ function createRedemptionSchema() {
|
|
|
297
309
|
reversalTransactionId: { type: mongoose.Schema.Types.ObjectId },
|
|
298
310
|
transactionId: { type: mongoose.Schema.Types.ObjectId },
|
|
299
311
|
initialBalance: { type: Number },
|
|
300
|
-
remainingBalance: { type: Number }
|
|
312
|
+
remainingBalance: { type: Number },
|
|
313
|
+
approvals: {
|
|
314
|
+
type: mongoose.Schema.Types.Mixed,
|
|
315
|
+
default: null
|
|
316
|
+
},
|
|
317
|
+
approvalPolicyId: {
|
|
318
|
+
type: String,
|
|
319
|
+
default: null
|
|
320
|
+
},
|
|
321
|
+
approvalPolicyVersion: {
|
|
322
|
+
type: Number,
|
|
323
|
+
default: null
|
|
324
|
+
}
|
|
301
325
|
}, { timestamps: true });
|
|
302
326
|
schema.index({
|
|
303
327
|
ownerType: 1,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ReferralRepository, d as MemberRepository, i as TierDefinitionRepository, l as EarningRuleRepository, n as LoyaltyRepositories, r as createRepositories, s as RedemptionRepository, t as CreateRepositoriesInput, u as PointTransactionRepository } from "../index-
|
|
1
|
+
import { a as ReferralRepository, d as MemberRepository, i as TierDefinitionRepository, l as EarningRuleRepository, n as LoyaltyRepositories, r as createRepositories, s as RedemptionRepository, t as CreateRepositoriesInput, u as PointTransactionRepository } from "../index-Cl-WGBFJ.mjs";
|
|
2
2
|
export { CreateRepositoriesInput, EarningRuleRepository, LoyaltyRepositories, MemberRepository, PointTransactionRepository, RedemptionRepository, ReferralRepository, TierDefinitionRepository, createRepositories };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as PointTransactionRepository, i as RedemptionRepository, n as TierDefinitionRepository, o as MemberRepository, r as ReferralRepository, s as EarningRuleRepository, t as createRepositories } from "../repositories-
|
|
1
|
+
import { a as PointTransactionRepository, i as RedemptionRepository, n as TierDefinitionRepository, o as MemberRepository, r as ReferralRepository, s as EarningRuleRepository, t as createRepositories } from "../repositories-BMwidCp-.mjs";
|
|
2
2
|
export { EarningRuleRepository, MemberRepository, PointTransactionRepository, RedemptionRepository, ReferralRepository, TierDefinitionRepository, createRepositories };
|
|
@@ -193,14 +193,22 @@ var EarningRuleRepository = class extends Repository {
|
|
|
193
193
|
constructor(model, plugins = []) {
|
|
194
194
|
super(model, plugins);
|
|
195
195
|
}
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
applyCreateDefaults(data, options) {
|
|
197
|
+
data.programId ??= this.config.programId;
|
|
198
198
|
injectTenantIntoData(data, options, this.config.tenant);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Auto-injects `programId` from `LoyaltyConfig.program.id` and the tenant id
|
|
202
|
+
* from repo options when omitted. This keeps custom-program engines aligned
|
|
203
|
+
* with `MemberRepository.enroll(...)`, which uses the same config default.
|
|
204
|
+
*/
|
|
205
|
+
async create(data, options) {
|
|
206
|
+
this.applyCreateDefaults(data, options);
|
|
199
207
|
return super.create(data, options);
|
|
200
208
|
}
|
|
201
209
|
async createMany(docs, options) {
|
|
202
210
|
const opts = options;
|
|
203
|
-
for (const doc of docs)
|
|
211
|
+
for (const doc of docs) this.applyCreateDefaults(doc, opts);
|
|
204
212
|
return super.createMany(docs, options);
|
|
205
213
|
}
|
|
206
214
|
async evaluateOrder(input, ctx) {
|
|
@@ -346,10 +354,15 @@ async function dispatchLoyaltyEvent(deps, event, ctx) {
|
|
|
346
354
|
const saveOptions = {};
|
|
347
355
|
if (ctx.session !== void 0) saveOptions.session = ctx.session;
|
|
348
356
|
await deps.outbox.save(event, saveOptions);
|
|
349
|
-
} catch (
|
|
357
|
+
} catch (err) {
|
|
358
|
+
deps.logger?.error(`[loyalty] outbox.save failed for ${event.type}:`, err);
|
|
359
|
+
throw err;
|
|
360
|
+
}
|
|
350
361
|
if (deps.events) try {
|
|
351
362
|
await deps.events.publish(event);
|
|
352
|
-
} catch (
|
|
363
|
+
} catch (err) {
|
|
364
|
+
deps.logger?.error(`[loyalty] events.publish failed for ${event.type}:`, err);
|
|
365
|
+
}
|
|
353
366
|
}
|
|
354
367
|
//#endregion
|
|
355
368
|
//#region src/utils/code-generator.ts
|
package/dist/types/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as TierEvaluationBatch, a as EnrollInput, c as UpdateTierInput, d as EarningResult, f as ExpirationResult, g as TierEvaluation, h as RedemptionValidation, i as EarnPointsInput, l as BalanceSummary, m as PaginatedResult, n as CreateEarningRuleInput, o as LoyaltyContext, p as ListQuery, r as CreateTierInput, s as UpdateEarningRuleInput, t as AdjustPointsInput, u as EarningBreakdown } from "../index-
|
|
2
|
-
import { a as PluginType, c as ResolvedTenant, i as ModelName, l as TenantConfig, n as LoyaltyConfig, o as RepositoryPlugins, s as ResolvedConfig, t as IndexDefinition } from "../config-
|
|
1
|
+
import { _ as TierEvaluationBatch, a as EnrollInput, c as UpdateTierInput, d as EarningResult, f as ExpirationResult, g as TierEvaluation, h as RedemptionValidation, i as EarnPointsInput, l as BalanceSummary, m as PaginatedResult, n as CreateEarningRuleInput, o as LoyaltyContext, p as ListQuery, r as CreateTierInput, s as UpdateEarningRuleInput, t as AdjustPointsInput, u as EarningBreakdown } from "../index-DWarXsmw.mjs";
|
|
2
|
+
import { a as PluginType, c as ResolvedTenant, i as ModelName, l as TenantConfig, n as LoyaltyConfig, o as RepositoryPlugins, s as ResolvedConfig, t as IndexDefinition } from "../config-96Sl6oNJ.mjs";
|
|
3
3
|
export { AdjustPointsInput, BalanceSummary, CreateEarningRuleInput, CreateTierInput, EarnPointsInput, EarningBreakdown, EarningResult, EnrollInput, ExpirationResult, IndexDefinition, ListQuery, LoyaltyConfig, LoyaltyContext, ModelName, PaginatedResult, PluginType, RedemptionValidation, RepositoryPlugins, ResolvedConfig, ResolvedTenant, TenantConfig, TierEvaluation, TierEvaluationBatch, UpdateEarningRuleInput, UpdateTierInput };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/loyalty",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Loyalty points, tiers, earning rules, referrals, and redemption engine for MongoDB",
|
|
5
5
|
"author": "Classytic",
|
|
6
6
|
"homepage": "https://www.npmjs.com/package/@classytic/loyalty",
|
|
@@ -78,18 +78,18 @@
|
|
|
78
78
|
"release": "npm run push -- main && npm run release:tag && npm publish"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
|
-
"@classytic/mongokit": ">=3.
|
|
82
|
-
"@classytic/primitives": ">=0.
|
|
83
|
-
"@classytic/repo-core": ">=0.2
|
|
81
|
+
"@classytic/mongokit": ">=3.13.3",
|
|
82
|
+
"@classytic/primitives": ">=0.5.0",
|
|
83
|
+
"@classytic/repo-core": ">=0.4.2",
|
|
84
84
|
"mongoose": ">=9.4.1",
|
|
85
85
|
"zod": ">=4.0.0"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
88
|
"@biomejs/biome": "^2.4.9",
|
|
89
89
|
"@classytic/dev-tools": "^0.2.0",
|
|
90
|
-
"@classytic/mongokit": "
|
|
91
|
-
"@classytic/primitives": ">=0.
|
|
92
|
-
"@classytic/repo-core": "
|
|
90
|
+
"@classytic/mongokit": "^3.13.3",
|
|
91
|
+
"@classytic/primitives": ">=0.5.0",
|
|
92
|
+
"@classytic/repo-core": "^0.4.2",
|
|
93
93
|
"@types/node": "^25.5.0",
|
|
94
94
|
"@vitest/coverage-v8": "^3.2.4",
|
|
95
95
|
"knip": "^6.3.0",
|