@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.
- package/CHANGELOG.md +180 -0
- package/dist/constants-DfrENxFG.mjs +75 -0
- package/dist/domain/earn-base.d.mts +35 -0
- package/dist/domain/earn-base.mjs +37 -0
- package/dist/domain/enums/index.d.mts +2 -2
- package/dist/domain/enums/index.mjs +1 -2
- package/dist/domain/rule-schedule.d.mts +24 -0
- package/dist/domain/rule-schedule.mjs +12 -0
- package/dist/events/index.d.mts +2 -2
- package/dist/events/index.mjs +3 -3
- package/dist/{events-BLjg3uLA.mjs → events-DhZolW61.mjs} +104 -4
- package/dist/{index-CR2k7jQ8.d.mts → index-BvyzKU7R.d.mts} +294 -34
- package/dist/{index-D6GvuvmF.d.mts → index-CorB0JL6.d.mts} +259 -113
- package/dist/index-DRrEhE0r.d.mts +604 -0
- package/dist/{index-YUFamhDk.d.mts → index-Db5Gb7x_.d.mts} +187 -39
- package/dist/index-tjMMmPzU.d.mts +36 -0
- package/dist/index.d.mts +121 -30
- package/dist/index.mjs +63 -10
- package/dist/{loyalty-events-DXirolM_.mjs → loyalty-events-j29B66YW.mjs} +20 -13
- package/dist/models/index.d.mts +2 -2
- package/dist/models/index.mjs +1 -2
- package/dist/{models-weWqS5Bc.mjs → models-BEGLduz1.mjs} +276 -7
- package/dist/notifications/index.d.mts +3 -4
- package/dist/repositories/index.d.mts +2 -2
- package/dist/repositories/index.mjs +1 -2
- package/dist/{repositories-B676z4bE.mjs → repositories-ER68JmUo.mjs} +1178 -102
- package/dist/types/index.d.mts +2 -3
- package/package.json +39 -22
- package/dist/config-CtkGj3xZ.d.mts +0 -178
- package/dist/constants-DOPBh6kt.mjs +0 -48
- package/dist/index-Cp_sXNpG.d.mts +0 -349
- 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 };
|