@classytic/loyalty 0.6.0 → 0.10.0

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 (32) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/dist/constants-DfrENxFG.mjs +75 -0
  3. package/dist/domain/earn-base.d.mts +35 -0
  4. package/dist/domain/earn-base.mjs +37 -0
  5. package/dist/domain/enums/index.d.mts +2 -2
  6. package/dist/domain/enums/index.mjs +1 -2
  7. package/dist/domain/rule-schedule.d.mts +24 -0
  8. package/dist/domain/rule-schedule.mjs +12 -0
  9. package/dist/events/index.d.mts +2 -2
  10. package/dist/events/index.mjs +3 -3
  11. package/dist/{events-BLjg3uLA.mjs → events-DhZolW61.mjs} +104 -4
  12. package/dist/{index-CR2k7jQ8.d.mts → index-BvyzKU7R.d.mts} +294 -34
  13. package/dist/{index-D6GvuvmF.d.mts → index-CorB0JL6.d.mts} +259 -113
  14. package/dist/index-DRrEhE0r.d.mts +604 -0
  15. package/dist/{index-YUFamhDk.d.mts → index-Db5Gb7x_.d.mts} +187 -39
  16. package/dist/index-tjMMmPzU.d.mts +36 -0
  17. package/dist/index.d.mts +121 -30
  18. package/dist/index.mjs +63 -10
  19. package/dist/{loyalty-events-DXirolM_.mjs → loyalty-events-j29B66YW.mjs} +20 -13
  20. package/dist/models/index.d.mts +2 -2
  21. package/dist/models/index.mjs +1 -2
  22. package/dist/{models-weWqS5Bc.mjs → models-BEGLduz1.mjs} +276 -7
  23. package/dist/notifications/index.d.mts +3 -4
  24. package/dist/repositories/index.d.mts +2 -2
  25. package/dist/repositories/index.mjs +1 -2
  26. package/dist/{repositories-B676z4bE.mjs → repositories-ER68JmUo.mjs} +1178 -102
  27. package/dist/types/index.d.mts +2 -3
  28. package/package.json +39 -22
  29. package/dist/config-CtkGj3xZ.d.mts +0 -178
  30. package/dist/constants-DOPBh6kt.mjs +0 -48
  31. package/dist/index-Cp_sXNpG.d.mts +0 -349
  32. package/dist/index-D_Oe3aDk.d.mts +0 -19
@@ -1,349 +0,0 @@
1
- import { a as RuleStatus, n as MemberStatus, o as RuleType, s as TransactionType } from "./index-D_Oe3aDk.mjs";
2
- import "./config-CtkGj3xZ.mjs";
3
- import { OperationContext } from "@classytic/primitives/context";
4
- import { ApprovalChain } from "@classytic/primitives/approval";
5
- //#region src/domain/entities/earning-rule.d.ts
6
- interface EarningConditions {
7
- /**
8
- * Minimum order total for the rule to apply — **integer minor units** of the
9
- * host's ambient currency (paisa for BDT). `10000` = ৳100. Compared against
10
- * `evaluateOrder`'s `orderTotal` (also minor units).
11
- */
12
- minOrderAmount?: number;
13
- categories?: string[];
14
- tiers?: string[];
15
- actions?: string[];
16
- /**
17
- * Days the rule applies, JS `getDay()` convention: 0=Sun … 6=Sat. Empty /
18
- * omitted = every day. Evaluated against the wall-clock weekday in the
19
- * engine's configured `timezone` (UTC when unset), never the server's local
20
- * clock. See `LoyaltyShape.timezone`.
21
- */
22
- dayOfWeek?: number[];
23
- dateRange?: {
24
- start?: Date;
25
- end?: Date;
26
- };
27
- }
28
- interface EarningReward {
29
- /**
30
- * Points awarded per `rateBasis` minor units of spend:
31
- * `points = pointsPerAmount × (orderTotalMinor / rateBasis)` (rounded once
32
- * per `roundingMode`). REQUIRES `rateBasis` — there is no implicit
33
- * "per 1 major unit" basis anymore (that ambiguity was the bug).
34
- * "5 points per ৳100" = `{ pointsPerAmount: 5, rateBasis: 10000 }`.
35
- */
36
- pointsPerAmount?: number;
37
- /**
38
- * RATE: the explicit integer minor-unit basis `pointsPerAmount` is quoted
39
- * against (≥ 1). Required whenever `pointsPerAmount` is set.
40
- */
41
- rateBasis?: number;
42
- /**
43
- * RATE: integer minor units of spend per single point (≥ 1).
44
- * `points = orderTotalMinor / amountPerPoint` (rounded per `roundingMode`).
45
- * "1 point per ৳100" = `amountPerPoint: 10000`.
46
- */
47
- amountPerPoint?: number;
48
- fixedPoints?: number;
49
- multiplier?: number;
50
- roundingMode?: 'floor' | 'round' | 'ceil';
51
- maxPointsPerTransaction?: number;
52
- }
53
- interface EarningRule {
54
- _id: string;
55
- programId: string;
56
- name: string;
57
- description?: string;
58
- type: RuleType;
59
- status: RuleStatus;
60
- priority: number;
61
- conditions: EarningConditions;
62
- reward: EarningReward;
63
- startsAt?: Date;
64
- endsAt?: Date;
65
- metadata?: Record<string, unknown>;
66
- createdAt: Date;
67
- updatedAt: Date;
68
- }
69
- //#endregion
70
- //#region src/domain/entities/tier-definition.d.ts
71
- interface TierQualification {
72
- minLifetimePoints?: number;
73
- /**
74
- * Minimum lifetime spend — **integer minor units** (paisa for BDT).
75
- * Declared for host-side qualification logic only: the in-package tier
76
- * evaluation checks lifetime POINTS exclusively and never reads this field.
77
- */
78
- minLifetimeSpend?: number;
79
- evaluationPeriodDays?: number;
80
- }
81
- interface TierBenefits {
82
- pointsMultiplier?: number;
83
- discountPercent?: number;
84
- freeShipping?: boolean;
85
- customBenefits?: Record<string, unknown>;
86
- }
87
- interface TierDowngrade {
88
- enabled: boolean;
89
- gracePeriodDays: number;
90
- }
91
- interface TierDefinition {
92
- _id: string;
93
- programId: string;
94
- name: string;
95
- rank: number;
96
- qualificationCriteria: TierQualification;
97
- benefits: TierBenefits;
98
- downgrade: TierDowngrade;
99
- color?: string;
100
- metadata?: Record<string, unknown>;
101
- createdAt: Date;
102
- updatedAt: Date;
103
- }
104
- //#endregion
105
- //#region src/domain/entities/member.d.ts
106
- interface MemberBalance {
107
- current: number;
108
- lifetime: number;
109
- redeemed: number;
110
- expired: number;
111
- }
112
- interface Member {
113
- _id: string;
114
- programId: string;
115
- externalId: string;
116
- externalType: string;
117
- status: MemberStatus;
118
- /** Public loyalty card identifier (e.g., MBR-DHK-00004821-8). Set by the integration layer. */
119
- cardId?: string;
120
- /** Referral code for the referral system (separate from cardId). Auto-generated on enrollment. */
121
- referralCode: string;
122
- tier: string | null;
123
- tierOverride: string | null;
124
- tierOverrideReason?: string;
125
- /**
126
- * Optional TTL on a manual tier override. When set, `evaluateMember`
127
- * treats the override as already cleared once `tierOverrideExpiresAt <=
128
- * now`, and a host-scheduled `sweepExpiredOverrides` cron clears the
129
- * field + emits a `TIER_OVERRIDE_EXPIRED` audit event.
130
- */
131
- tierOverrideExpiresAt?: Date;
132
- /** Optional upstream referrer for multi-tier referral chains. */
133
- referredBy?: string;
134
- tierQualifiedAt?: Date;
135
- tierExpiresAt?: Date;
136
- balance: MemberBalance;
137
- enrolledAt: Date;
138
- deactivatedAt?: Date;
139
- metadata?: Record<string, unknown>;
140
- createdAt: Date;
141
- updatedAt: Date;
142
- }
143
- //#endregion
144
- //#region src/domain/entities/point-transaction.d.ts
145
- interface PointTransaction {
146
- _id: string;
147
- memberId: string;
148
- programId: string;
149
- type: TransactionType;
150
- points: number;
151
- balanceAfter: number;
152
- description: string;
153
- referenceType?: string;
154
- referenceId?: string;
155
- idempotencyKey?: string;
156
- earningRuleId?: string;
157
- expiresAt?: Date;
158
- expiredAt?: Date;
159
- metadata?: Record<string, unknown>;
160
- actorId: string;
161
- /**
162
- * Optional multi-step approval chain (P7 canonical — same shape as
163
- * `@classytic/purchase` / `@classytic/order`). Manual `adjustment` /
164
- * `bonus` transactions above a host-defined threshold gate on
165
- * `isApproved(approvals)` before the journal entry is committed.
166
- * Automatic transactions (earn from purchase, expiry sweeps) skip the
167
- * chain entirely — single-tier flows leave this null.
168
- */
169
- approvals?: ApprovalChain | null;
170
- /** Snapshot of the matrix policy id that produced this chain (host-managed). */
171
- approvalPolicyId?: string | null;
172
- /** Version of the matrix policy at submit time — frozen for audit. */
173
- approvalPolicyVersion?: number | null;
174
- createdAt: Date;
175
- }
176
- //#endregion
177
- //#region src/types/results.d.ts
178
- interface BalanceSummary extends MemberBalance {
179
- tier: string | null;
180
- tierOverride: string | null;
181
- }
182
- interface EarningBreakdown {
183
- ruleId: string;
184
- ruleName: string;
185
- points: number;
186
- }
187
- interface EarningResult {
188
- totalPoints: number;
189
- breakdown: EarningBreakdown[];
190
- transactions: PointTransaction[];
191
- }
192
- interface TierEvaluation {
193
- memberId: string;
194
- previousTier: string | null;
195
- newTier: string | null;
196
- action: 'upgraded' | 'downgraded' | 'grace_period' | 'unchanged';
197
- graceExpiresAt?: Date;
198
- }
199
- interface TierEvaluationBatch {
200
- upgraded: number;
201
- downgraded: number;
202
- unchanged: number;
203
- }
204
- interface RedemptionValidation {
205
- valid: boolean;
206
- error?: string;
207
- pointsToRedeem: number;
208
- /**
209
- * Discount in **integer minor units** (paisa for BDT) — always exactly
210
- * `pointsToRedeem × pointValueMinor`.
211
- */
212
- discountAmount: number;
213
- maxAllowedPoints: number;
214
- }
215
- interface ExpirationResult {
216
- membersAffected: number;
217
- pointsExpired: number;
218
- transactionCount: number;
219
- }
220
- interface PaginatedResult<T> {
221
- docs: T[];
222
- total: number;
223
- page: number;
224
- pages: number;
225
- hasNext: boolean;
226
- hasPrev: boolean;
227
- }
228
- interface ListQuery {
229
- page?: number;
230
- limit?: number;
231
- sort?: Record<string, 1 | -1>;
232
- }
233
- //#endregion
234
- //#region src/types/index.d.ts
235
- /**
236
- * Context passed to every loyalty operation.
237
- *
238
- * The tenant key is dynamic — if you configured `tenant: { field: 'companyId', contextKey: 'companyId' }`,
239
- * pass `{ companyId: '...' }` in the context. The `[key: string]: unknown` index allows this.
240
- *
241
- * For the default config (`tenant: true` or `tenant: undefined`), pass `organizationId`.
242
- * For `tenant: false`, the tenant key is ignored.
243
- */
244
- /**
245
- * Extends `@classytic/primitives`' {@link OperationContext} with loyalty-
246
- * specific fields. `actorId` is narrowed to a required `string` since every
247
- * loyalty mutation is attributed; other primitives fields (`correlationId`,
248
- * `traceId`, `requestId`, `session`, `metadata`) flow through unchanged.
249
- */
250
- interface LoyaltyContext extends OperationContext {
251
- /** Required for loyalty: who is performing this operation. Narrowed to string. */
252
- actorId: string;
253
- /** Narrowed from primitives' `IdLike` to string. */
254
- organizationId?: string;
255
- /** Override program ID for multi-program setups. */
256
- programId?: string;
257
- /**
258
- * Cooperative cancellation for long-running cron loops (point expiry,
259
- * reservation cleanup, tier evaluation, override sweeps, campaign award).
260
- * Checked at each loop boundary via `throwIfAborted` — aborting between
261
- * iterations never rolls back an already-committed transaction, and each
262
- * per-item write is its own unit of work. Threaded to mongokit round-trips
263
- * by hosts that pass it; mongokit (3.16+) honours it at every op boundary.
264
- */
265
- signal?: AbortSignal | undefined;
266
- /** Dynamic tenant key support — e.g. `{ companyId: '...' }` — when a host
267
- * configured a custom `contextKey`. */
268
- [key: string]: unknown;
269
- }
270
- interface EnrollInput {
271
- externalId: string;
272
- externalType: string;
273
- programId?: string;
274
- tier?: string;
275
- cardId?: string;
276
- metadata?: Record<string, unknown>;
277
- }
278
- interface EarnPointsInput {
279
- memberId: string;
280
- points: number;
281
- description: string;
282
- referenceType?: string;
283
- referenceId?: string;
284
- earningRuleId?: string;
285
- expiresAt?: Date;
286
- idempotencyKey?: string;
287
- metadata?: Record<string, unknown>;
288
- }
289
- interface AdjustPointsInput {
290
- memberId: string;
291
- points: number;
292
- description: string;
293
- reason: string;
294
- referenceType?: string;
295
- referenceId?: string;
296
- idempotencyKey?: string;
297
- metadata?: Record<string, unknown>;
298
- }
299
- interface CreateEarningRuleInput {
300
- name: string;
301
- type: 'order' | 'action' | 'category' | 'tier_bonus';
302
- priority?: number;
303
- description?: string;
304
- conditions?: EarningConditions;
305
- reward: EarningReward;
306
- startsAt?: Date | string;
307
- endsAt?: Date | string;
308
- /**
309
- * Loyalty program this rule belongs to.
310
- *
311
- * Optional for repository-created rules: `EarningRuleRepository.create(...)`
312
- * and `createMany(...)` fill this from `LoyaltyShape.program.id`, matching
313
- * the default used by `MemberRepository.enroll(...)`. Pass explicitly only
314
- * when creating a rule for a different program.
315
- */
316
- programId?: string;
317
- metadata?: Record<string, unknown>;
318
- }
319
- interface UpdateEarningRuleInput {
320
- name?: string;
321
- priority?: number;
322
- description?: string;
323
- conditions?: EarningConditions;
324
- reward?: EarningReward;
325
- startsAt?: Date | string;
326
- endsAt?: Date | string;
327
- metadata?: Record<string, unknown>;
328
- }
329
- interface CreateTierInput {
330
- name: string;
331
- rank: number;
332
- qualificationCriteria?: TierQualification;
333
- benefits?: TierBenefits;
334
- downgrade?: TierDowngrade;
335
- color?: string;
336
- programId?: string;
337
- metadata?: Record<string, unknown>;
338
- }
339
- interface UpdateTierInput {
340
- name?: string;
341
- rank?: number;
342
- qualificationCriteria?: TierQualification;
343
- benefits?: TierBenefits;
344
- downgrade?: TierDowngrade;
345
- color?: string;
346
- metadata?: Record<string, unknown>;
347
- }
348
- //#endregion
349
- export { EarningRule as S, TierEvaluationBatch as _, EnrollInput as a, MemberBalance as b, UpdateTierInput as c, EarningResult as d, ExpirationResult as f, TierEvaluation as g, RedemptionValidation as h, EarnPointsInput as i, BalanceSummary as l, PaginatedResult as m, CreateEarningRuleInput as n, LoyaltyContext as o, ListQuery as p, CreateTierInput as r, UpdateEarningRuleInput as s, AdjustPointsInput as t, EarningBreakdown as u, PointTransaction as v, TierDefinition as x, Member as y };
@@ -1,19 +0,0 @@
1
- //#region src/constants.d.ts
2
- declare const TRANSACTION_TYPES: readonly ["earn", "redeem", "adjust", "expire", "transfer", "referral_bonus"];
3
- declare const MEMBER_STATUSES: readonly ["active", "inactive", "suspended"];
4
- declare const RULE_TYPES: readonly ["order", "action", "category", "tier_bonus"];
5
- declare const RULE_STATUSES: readonly ["active", "paused", "expired"];
6
- declare const REFERRAL_STATUSES: readonly ["pending", "approved", "rejected", "expired"];
7
- declare const REDEMPTION_STATUSES: readonly ["reserved", "confirmed", "released", "expired", "reversed"];
8
- declare const EARNING_ACTIONS: readonly ["signup", "referral", "birthday", "review", "profile_complete"];
9
- //#endregion
10
- //#region src/domain/enums/index.d.ts
11
- type TransactionType = (typeof TRANSACTION_TYPES)[number];
12
- type MemberStatus = (typeof MEMBER_STATUSES)[number];
13
- type RuleType = (typeof RULE_TYPES)[number];
14
- type RuleStatus = (typeof RULE_STATUSES)[number];
15
- type ReferralStatus = (typeof REFERRAL_STATUSES)[number];
16
- type RedemptionStatus = (typeof REDEMPTION_STATUSES)[number];
17
- type EarningAction = (typeof EARNING_ACTIONS)[number];
18
- //#endregion
19
- export { RuleStatus as a, EARNING_ACTIONS as c, REFERRAL_STATUSES as d, RULE_STATUSES as f, ReferralStatus as i, MEMBER_STATUSES as l, TRANSACTION_TYPES as m, MemberStatus as n, RuleType as o, RULE_TYPES as p, RedemptionStatus as r, TransactionType as s, EarningAction as t, REDEMPTION_STATUSES as u };