@classytic/promo 0.1.0 → 0.2.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 +128 -0
- package/README.md +226 -22
- package/dist/{index-J5BC20DN.d.mts → constants-CrbSSQG5.d.mts} +1 -3
- package/dist/{constants-BVajdyL3.mjs → constants-D0Rntp2f.mjs} +1 -3
- package/dist/index.d.mts +763 -10
- package/dist/index.mjs +1721 -34
- package/dist/schemas/index.d.mts +253 -0
- package/dist/schemas/index.mjs +135 -0
- package/package.json +20 -35
- package/dist/config-iZjn_8pp.d.mts +0 -71
- package/dist/domain/enums/index.d.mts +0 -2
- package/dist/domain/enums/index.mjs +0 -2
- package/dist/domain/index.d.mts +0 -61
- package/dist/domain/index.mjs +0 -4
- package/dist/domain-errors-BEkXvy5O.mjs +0 -80
- package/dist/event-emitter.port-DaodlJSG.d.mts +0 -8
- package/dist/event-types-CsTV1FKX.mjs +0 -25
- package/dist/events/index.d.mts +0 -2
- package/dist/events/index.mjs +0 -3
- package/dist/events-CprEWlN7.mjs +0 -25
- package/dist/index-B7lLH19a.d.mts +0 -13
- package/dist/index-C52zSBkI.d.mts +0 -96
- package/dist/index-Cu9iwy4v.d.mts +0 -99
- package/dist/index-l09KqnlE.d.mts +0 -81
- package/dist/models/index.d.mts +0 -2
- package/dist/models/index.mjs +0 -2
- package/dist/models-DdBNae7h.mjs +0 -277
- package/dist/repositories/index.d.mts +0 -2
- package/dist/repositories/index.mjs +0 -2
- package/dist/repositories-DgZIY9wD.mjs +0 -295
- package/dist/results-Ca5ZCNbN.d.mts +0 -218
- package/dist/services/index.d.mts +0 -2
- package/dist/services/index.mjs +0 -2
- package/dist/services-Cz0gHrmX.mjs +0 -815
- package/dist/types/index.d.mts +0 -3
- package/dist/types/index.mjs +0 -1
- package/dist/unit-of-work.port-DaMW8WZK.d.mts +0 -7
- package/dist/voucher.port-yxfb3MHJ.d.mts +0 -146
package/dist/index.d.mts
CHANGED
|
@@ -1,20 +1,773 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import { c as ProgramType, f as StackingMode, g as VoucherStatus, i as DiscountScope, m as TriggerMode, r as DiscountMode, s as ProgramStatus, u as RewardType } from "./constants-CrbSSQG5.mjs";
|
|
2
|
+
import { ResolvedTenantConfig, TenantConfig } from "@classytic/primitives/tenant";
|
|
3
|
+
import { DomainEvent, DomainEvent as DomainEvent$1, EventHandler, EventTransport, EventTransport as EventTransport$1 } from "@classytic/primitives/events";
|
|
4
|
+
import { ClientSession, Connection, Model } from "mongoose";
|
|
5
|
+
import { PluginType, Repository } from "@classytic/mongokit";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { OutboxStore } from "@classytic/primitives/outbox";
|
|
8
|
+
import { OperationContext } from "@classytic/primitives/context";
|
|
9
9
|
|
|
10
|
+
//#region src/types/config.d.ts
|
|
11
|
+
type TenantConfig$1 = false | TenantConfig;
|
|
12
|
+
interface IndexDefinition {
|
|
13
|
+
fields: Record<string, 1 | -1>;
|
|
14
|
+
options?: Record<string, unknown> | undefined;
|
|
15
|
+
}
|
|
16
|
+
type ModelName = 'program' | 'rule' | 'reward' | 'voucher';
|
|
17
|
+
interface RepositoryPlugins {
|
|
18
|
+
program?: PluginType[] | undefined;
|
|
19
|
+
rule?: PluginType[] | undefined;
|
|
20
|
+
reward?: PluginType[] | undefined;
|
|
21
|
+
voucher?: PluginType[] | undefined;
|
|
22
|
+
}
|
|
23
|
+
interface PromoConfig {
|
|
24
|
+
mongoose: Connection;
|
|
25
|
+
tenant?: TenantConfig$1 | undefined;
|
|
26
|
+
evaluation?: {
|
|
27
|
+
maxStackablePromotions?: number | undefined;
|
|
28
|
+
allowExclusiveAndStackable?: boolean | undefined;
|
|
29
|
+
} | undefined;
|
|
30
|
+
voucher?: {
|
|
31
|
+
codeLength?: number | undefined;
|
|
32
|
+
codePrefix?: string | undefined;
|
|
33
|
+
defaultExpiryDays?: number | undefined;
|
|
34
|
+
} | undefined;
|
|
35
|
+
giftCard?: {
|
|
36
|
+
allowNegativeBalance?: boolean | undefined;
|
|
37
|
+
maxBalance?: number | undefined;
|
|
38
|
+
} | undefined;
|
|
39
|
+
indexes?: Partial<Record<ModelName, IndexDefinition[]>> | undefined;
|
|
40
|
+
autoIndex?: boolean | Partial<Record<ModelName, boolean>> | undefined;
|
|
41
|
+
events?: {
|
|
42
|
+
transport?: EventTransport$1 | undefined;
|
|
43
|
+
} | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Host-provided outbox store (PACKAGE_RULES §5.5 + §P8). When wired, every
|
|
46
|
+
* domain event is persisted to the outbox inside the caller's `ctx.session`
|
|
47
|
+
* BEFORE being published to the transport — giving at-least-once delivery
|
|
48
|
+
* via the host-side relay. Absent → transport-only best-effort.
|
|
49
|
+
*
|
|
50
|
+
* Explicit `| undefined` per `exactOptionalPropertyTypes` convention.
|
|
51
|
+
*/
|
|
52
|
+
outbox?: OutboxStore | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Optional logger for dispatch-layer errors. Used by the shared
|
|
55
|
+
* `dispatch()` helper to surface outbox/transport failures without
|
|
56
|
+
* aborting the domain mutation. Defaults to `console`.
|
|
57
|
+
*/
|
|
58
|
+
logger?: {
|
|
59
|
+
error(message: string, ...args: unknown[]): void;
|
|
60
|
+
} | undefined;
|
|
61
|
+
plugins?: RepositoryPlugins | undefined;
|
|
62
|
+
}
|
|
63
|
+
type ResolvedTenant = ResolvedTenantConfig;
|
|
64
|
+
interface ResolvedConfig {
|
|
65
|
+
evaluation: {
|
|
66
|
+
maxStackablePromotions: number;
|
|
67
|
+
allowExclusiveAndStackable: boolean;
|
|
68
|
+
};
|
|
69
|
+
voucher: {
|
|
70
|
+
codeLength: number;
|
|
71
|
+
codePrefix: string;
|
|
72
|
+
defaultExpiryDays: number | null;
|
|
73
|
+
};
|
|
74
|
+
giftCard: {
|
|
75
|
+
allowNegativeBalance: boolean;
|
|
76
|
+
maxBalance: number | null;
|
|
77
|
+
};
|
|
78
|
+
tenant: ResolvedTenant;
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/models/create-models.d.ts
|
|
82
|
+
interface PromoModels {
|
|
83
|
+
Program: Model<unknown>;
|
|
84
|
+
Rule: Model<unknown>;
|
|
85
|
+
Reward: Model<unknown>;
|
|
86
|
+
Voucher: Model<unknown>;
|
|
87
|
+
}
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/types/inputs.d.ts
|
|
90
|
+
/**
|
|
91
|
+
* Extends `@classytic/primitives`' {@link OperationContext}. The
|
|
92
|
+
* `[key: string]: unknown` fall-through lets hosts pass dynamic tenant keys
|
|
93
|
+
* when they've configured a custom `contextKey` on `TenantConfig`.
|
|
94
|
+
*/
|
|
95
|
+
interface PromoContext extends OperationContext {
|
|
96
|
+
/** Narrowed from primitives' `IdLike` to string. */
|
|
97
|
+
actorId?: string;
|
|
98
|
+
/** Narrowed from primitives' `IdLike` to string. */
|
|
99
|
+
organizationId?: string;
|
|
100
|
+
/** Narrows primitives' `session: unknown` to the concrete Mongoose type so
|
|
101
|
+
* this context flows directly into mongokit repository calls. */
|
|
102
|
+
session?: ClientSession;
|
|
103
|
+
[key: string]: unknown;
|
|
104
|
+
}
|
|
105
|
+
interface CreateProgramInput {
|
|
106
|
+
name: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
programType: ProgramType;
|
|
109
|
+
triggerMode: TriggerMode;
|
|
110
|
+
stackingMode?: StackingMode;
|
|
111
|
+
priority?: number;
|
|
112
|
+
startsAt?: Date;
|
|
113
|
+
endsAt?: Date;
|
|
114
|
+
maxUsageTotal?: number;
|
|
115
|
+
maxUsagePerCustomer?: number;
|
|
116
|
+
applicableCustomerIds?: string[];
|
|
117
|
+
applicableCustomerTags?: string[];
|
|
118
|
+
metadata?: Record<string, unknown>;
|
|
119
|
+
}
|
|
120
|
+
interface UpdateProgramInput {
|
|
121
|
+
name?: string;
|
|
122
|
+
description?: string;
|
|
123
|
+
stackingMode?: StackingMode;
|
|
124
|
+
priority?: number;
|
|
125
|
+
startsAt?: Date;
|
|
126
|
+
endsAt?: Date;
|
|
127
|
+
maxUsageTotal?: number;
|
|
128
|
+
maxUsagePerCustomer?: number;
|
|
129
|
+
applicableCustomerIds?: string[];
|
|
130
|
+
applicableCustomerTags?: string[];
|
|
131
|
+
metadata?: Record<string, unknown>;
|
|
132
|
+
}
|
|
133
|
+
interface CreateRuleInput {
|
|
134
|
+
name?: string;
|
|
135
|
+
minimumAmount?: number;
|
|
136
|
+
minimumQuantity?: number;
|
|
137
|
+
applicableProductIds?: string[];
|
|
138
|
+
applicableCategories?: string[];
|
|
139
|
+
applicableSkus?: string[];
|
|
140
|
+
buyQuantity?: number;
|
|
141
|
+
code?: string;
|
|
142
|
+
startsAt?: Date;
|
|
143
|
+
endsAt?: Date;
|
|
144
|
+
metadata?: Record<string, unknown>;
|
|
145
|
+
}
|
|
146
|
+
interface UpdateRuleInput {
|
|
147
|
+
name?: string;
|
|
148
|
+
minimumAmount?: number;
|
|
149
|
+
minimumQuantity?: number;
|
|
150
|
+
applicableProductIds?: string[];
|
|
151
|
+
applicableCategories?: string[];
|
|
152
|
+
applicableSkus?: string[];
|
|
153
|
+
buyQuantity?: number;
|
|
154
|
+
code?: string;
|
|
155
|
+
startsAt?: Date;
|
|
156
|
+
endsAt?: Date;
|
|
157
|
+
metadata?: Record<string, unknown>;
|
|
158
|
+
}
|
|
159
|
+
interface CreateRewardInput {
|
|
160
|
+
ruleId?: string;
|
|
161
|
+
rewardType: RewardType;
|
|
162
|
+
discountMode?: DiscountMode;
|
|
163
|
+
discountAmount?: number;
|
|
164
|
+
maxDiscountAmount?: number;
|
|
165
|
+
discountScope?: DiscountScope;
|
|
166
|
+
applicableProductIds?: string[];
|
|
167
|
+
freeProductId?: string;
|
|
168
|
+
freeProductSku?: string;
|
|
169
|
+
freeQuantity?: number;
|
|
170
|
+
giftCardAmount?: number;
|
|
171
|
+
metadata?: Record<string, unknown>;
|
|
172
|
+
}
|
|
173
|
+
interface UpdateRewardInput {
|
|
174
|
+
discountMode?: DiscountMode;
|
|
175
|
+
discountAmount?: number;
|
|
176
|
+
maxDiscountAmount?: number;
|
|
177
|
+
discountScope?: DiscountScope;
|
|
178
|
+
applicableProductIds?: string[];
|
|
179
|
+
freeProductId?: string;
|
|
180
|
+
freeProductSku?: string;
|
|
181
|
+
freeQuantity?: number;
|
|
182
|
+
giftCardAmount?: number;
|
|
183
|
+
metadata?: Record<string, unknown>;
|
|
184
|
+
}
|
|
185
|
+
interface GenerateCodesInput {
|
|
186
|
+
programId: string;
|
|
187
|
+
count: number;
|
|
188
|
+
customerId?: string;
|
|
189
|
+
expiresAt?: Date;
|
|
190
|
+
metadata?: Record<string, unknown>;
|
|
191
|
+
}
|
|
192
|
+
interface GenerateSingleCodeInput {
|
|
193
|
+
programId: string;
|
|
194
|
+
code?: string;
|
|
195
|
+
customerId?: string;
|
|
196
|
+
expiresAt?: Date;
|
|
197
|
+
initialBalance?: number;
|
|
198
|
+
metadata?: Record<string, unknown>;
|
|
199
|
+
}
|
|
200
|
+
interface RedeemVoucherInput {
|
|
201
|
+
code: string;
|
|
202
|
+
orderId: string;
|
|
203
|
+
customerId?: string;
|
|
204
|
+
discountAmount: number;
|
|
205
|
+
idempotencyKey?: string;
|
|
206
|
+
}
|
|
207
|
+
interface GiftCardSpendInput {
|
|
208
|
+
code: string;
|
|
209
|
+
amount: number;
|
|
210
|
+
orderId: string;
|
|
211
|
+
description?: string;
|
|
212
|
+
idempotencyKey?: string;
|
|
213
|
+
}
|
|
214
|
+
interface GiftCardTopUpInput {
|
|
215
|
+
code: string;
|
|
216
|
+
amount: number;
|
|
217
|
+
description?: string;
|
|
218
|
+
idempotencyKey?: string;
|
|
219
|
+
}
|
|
220
|
+
interface CartItem {
|
|
221
|
+
productId: string;
|
|
222
|
+
sku?: string;
|
|
223
|
+
categoryId?: string;
|
|
224
|
+
quantity: number;
|
|
225
|
+
unitPrice: number;
|
|
226
|
+
lineTotal?: number;
|
|
227
|
+
}
|
|
228
|
+
interface EvaluateInput {
|
|
229
|
+
items: CartItem[];
|
|
230
|
+
subtotal: number;
|
|
231
|
+
codes?: string[];
|
|
232
|
+
customerId?: string;
|
|
233
|
+
customerTags?: string[];
|
|
234
|
+
}
|
|
235
|
+
interface ListQuery {
|
|
236
|
+
page?: number;
|
|
237
|
+
limit?: number;
|
|
238
|
+
sort?: string;
|
|
239
|
+
filters?: Record<string, unknown>;
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/events/dispatch.d.ts
|
|
243
|
+
interface DispatchLogger {
|
|
244
|
+
error(message: string, ...args: unknown[]): void;
|
|
245
|
+
}
|
|
246
|
+
interface DispatchDeps {
|
|
247
|
+
events?: EventTransport$1 | undefined;
|
|
248
|
+
outbox?: OutboxStore | undefined;
|
|
249
|
+
logger?: DispatchLogger | undefined;
|
|
250
|
+
}
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/domain/entities/program.d.ts
|
|
253
|
+
interface Program {
|
|
254
|
+
_id: string;
|
|
255
|
+
name: string;
|
|
256
|
+
description?: string;
|
|
257
|
+
programType: ProgramType;
|
|
258
|
+
triggerMode: TriggerMode;
|
|
259
|
+
status: ProgramStatus;
|
|
260
|
+
stackingMode: StackingMode;
|
|
261
|
+
priority: number;
|
|
262
|
+
startsAt?: Date;
|
|
263
|
+
endsAt?: Date;
|
|
264
|
+
maxUsageTotal?: number;
|
|
265
|
+
usedCount: number;
|
|
266
|
+
maxUsagePerCustomer?: number;
|
|
267
|
+
applicableCustomerIds: string[];
|
|
268
|
+
applicableCustomerTags: string[];
|
|
269
|
+
customerUsageCounts?: Record<string, number>;
|
|
270
|
+
metadata?: Record<string, unknown>;
|
|
271
|
+
createdAt: Date;
|
|
272
|
+
updatedAt: Date;
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
275
|
+
//#region src/repositories/program.repository.d.ts
|
|
276
|
+
declare class ProgramRepository extends Repository<Program> {
|
|
277
|
+
private dispatchDeps;
|
|
278
|
+
constructor(model: Model<Program>, plugins?: PluginType[], dispatchDeps?: DispatchDeps);
|
|
279
|
+
activate(id: string, ctx: PromoContext): Promise<Program>;
|
|
280
|
+
pause(id: string, ctx: PromoContext): Promise<Program>;
|
|
281
|
+
archive(id: string, ctx: PromoContext): Promise<Program>;
|
|
282
|
+
private _transition;
|
|
283
|
+
incrementUsage(id: string, ctx?: Record<string, unknown>): Promise<Program>;
|
|
284
|
+
decrementUsage(id: string, ctx?: Record<string, unknown>): Promise<Program>;
|
|
285
|
+
getCustomerUsage(id: string, customerId: string, ctx?: Record<string, unknown>): Promise<number>;
|
|
286
|
+
incrementCustomerUsage(id: string, customerId: string, ctx?: Record<string, unknown>): Promise<Program>;
|
|
287
|
+
findActive(now?: Date, ctx?: Record<string, unknown>): Promise<Program[]>;
|
|
288
|
+
}
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/domain/entities/reward.d.ts
|
|
291
|
+
interface Reward {
|
|
292
|
+
_id: string;
|
|
293
|
+
programId: string;
|
|
294
|
+
ruleId?: string;
|
|
295
|
+
rewardType: RewardType;
|
|
296
|
+
discountMode?: DiscountMode;
|
|
297
|
+
discountAmount?: number;
|
|
298
|
+
maxDiscountAmount?: number;
|
|
299
|
+
discountScope: DiscountScope;
|
|
300
|
+
applicableProductIds: string[];
|
|
301
|
+
freeProductId?: string;
|
|
302
|
+
freeProductSku?: string;
|
|
303
|
+
freeQuantity: number;
|
|
304
|
+
giftCardAmount?: number;
|
|
305
|
+
metadata?: Record<string, unknown>;
|
|
306
|
+
createdAt: Date;
|
|
307
|
+
updatedAt: Date;
|
|
308
|
+
}
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region src/repositories/reward.repository.d.ts
|
|
311
|
+
declare class RewardRepository extends Repository<Reward> {
|
|
312
|
+
constructor(model: Model<Reward>, plugins?: PluginType[]);
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/domain/entities/rule.d.ts
|
|
316
|
+
interface Rule {
|
|
317
|
+
_id: string;
|
|
318
|
+
programId: string;
|
|
319
|
+
name?: string;
|
|
320
|
+
minimumAmount: number;
|
|
321
|
+
minimumQuantity: number;
|
|
322
|
+
applicableProductIds: string[];
|
|
323
|
+
applicableCategories: string[];
|
|
324
|
+
applicableSkus: string[];
|
|
325
|
+
buyQuantity?: number;
|
|
326
|
+
code?: string;
|
|
327
|
+
startsAt?: Date;
|
|
328
|
+
endsAt?: Date;
|
|
329
|
+
metadata?: Record<string, unknown>;
|
|
330
|
+
createdAt: Date;
|
|
331
|
+
updatedAt: Date;
|
|
332
|
+
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/repositories/rule.repository.d.ts
|
|
335
|
+
declare class RuleRepository extends Repository<Rule> {
|
|
336
|
+
constructor(model: Model<Rule>, plugins?: PluginType[]);
|
|
337
|
+
}
|
|
338
|
+
//#endregion
|
|
339
|
+
//#region src/domain/entities/voucher.d.ts
|
|
340
|
+
interface BalanceLedgerEntry {
|
|
341
|
+
amount: number;
|
|
342
|
+
orderId?: string;
|
|
343
|
+
description?: string;
|
|
344
|
+
createdAt: Date;
|
|
345
|
+
idempotencyKey?: string;
|
|
346
|
+
}
|
|
347
|
+
interface VoucherRedemption {
|
|
348
|
+
orderId: string;
|
|
349
|
+
customerId?: string;
|
|
350
|
+
discountAmount: number;
|
|
351
|
+
redeemedAt: Date;
|
|
352
|
+
idempotencyKey?: string;
|
|
353
|
+
}
|
|
354
|
+
interface Voucher {
|
|
355
|
+
_id: string;
|
|
356
|
+
programId: string;
|
|
357
|
+
code: string;
|
|
358
|
+
status: VoucherStatus;
|
|
359
|
+
customerId?: string;
|
|
360
|
+
usageLimit: number;
|
|
361
|
+
usedCount: number;
|
|
362
|
+
initialBalance?: number;
|
|
363
|
+
currentBalance?: number;
|
|
364
|
+
balanceLedger: BalanceLedgerEntry[];
|
|
365
|
+
expiresAt?: Date;
|
|
366
|
+
redemptions: VoucherRedemption[];
|
|
367
|
+
metadata?: Record<string, unknown>;
|
|
368
|
+
createdAt: Date;
|
|
369
|
+
updatedAt: Date;
|
|
370
|
+
}
|
|
371
|
+
//#endregion
|
|
372
|
+
//#region src/repositories/voucher.repository.d.ts
|
|
373
|
+
declare class VoucherRepository extends Repository<Voucher> {
|
|
374
|
+
private dispatchDeps;
|
|
375
|
+
private tenantField;
|
|
376
|
+
constructor(model: Model<Voucher>, plugins?: PluginType[], dispatchDeps?: DispatchDeps, tenantField?: string);
|
|
377
|
+
/**
|
|
378
|
+
* Copy the tenant id from `ctx` onto the write payload so the doc persists
|
|
379
|
+
* with the correct `organizationId` even when the host has opted OUT of the
|
|
380
|
+
* auto-wired `multiTenantPlugin` (e.g. arc hosts that scope at the
|
|
381
|
+
* framework layer — see `@classytic/order` CLAUDE.md: "Child repos set
|
|
382
|
+
* `organizationId` explicitly on the doc"). No-op when `ctx` omits the
|
|
383
|
+
* tenant id or the payload already carries it.
|
|
384
|
+
*/
|
|
385
|
+
private _injectTenant;
|
|
386
|
+
create(data: Parameters<Repository<Voucher>['create']>[0], options?: Parameters<Repository<Voucher>['create']>[1]): Promise<Voucher>;
|
|
387
|
+
createMany(docs: Parameters<Repository<Voucher>['createMany']>[0], options?: Parameters<Repository<Voucher>['createMany']>[1]): Promise<Voucher[]>;
|
|
388
|
+
/** Domain verb: cancel a voucher (status transition + event). */
|
|
389
|
+
cancel(id: string, ctx: PromoContext): Promise<Voucher>;
|
|
390
|
+
/** Atomic usage increment + push redemption record. */
|
|
391
|
+
incrementUsage(id: string, redemption: Record<string, unknown>, ctx?: Record<string, unknown>): Promise<Voucher>;
|
|
392
|
+
/** Atomic balance delta + push ledger entry. */
|
|
393
|
+
addLedgerEntry(id: string, entry: Record<string, unknown>, balanceDelta: number, ctx?: Record<string, unknown>): Promise<Voucher>;
|
|
394
|
+
/**
|
|
395
|
+
* Batch expire by date.
|
|
396
|
+
*
|
|
397
|
+
* Routes through `findAll` + per-doc `update` instead of a raw
|
|
398
|
+
* `this.Model.updateMany`. Rationale:
|
|
399
|
+
* 1. `findAll` casts the filter through the schema (so an ObjectId
|
|
400
|
+
* tenant field on a write-time String context doesn't silently
|
|
401
|
+
* return 0 rows the way a raw `$match` would).
|
|
402
|
+
* 2. `update` fires the full hook pipeline (multi-tenant, audit,
|
|
403
|
+
* soft-delete) on every expiration — a bulk `updateMany` at the
|
|
404
|
+
* Model layer bypasses all of them.
|
|
405
|
+
* Volume is bounded per tenant (active + past-expiry vouchers), so an
|
|
406
|
+
* N+1 loop is acceptable for correctness.
|
|
407
|
+
*/
|
|
408
|
+
expireByDate(before: Date, ctx?: Record<string, unknown>): Promise<number>;
|
|
409
|
+
/**
|
|
410
|
+
* Lookup voucher by unique code, scoped to the tenant in `ctx` when
|
|
411
|
+
* tenant scoping is configured.
|
|
412
|
+
*
|
|
413
|
+
* Manual tenant injection mirrors `expireByDate` and `ProgramRepository.findActive`
|
|
414
|
+
* — it makes the method work whether the host opts into the auto-wired
|
|
415
|
+
* `multiTenantPlugin` or enforces scoping at its own framework layer
|
|
416
|
+
* (e.g. arc's preset + `BaseController`). Without this, a host that
|
|
417
|
+
* runs the plugin off would leak vouchers across branches at
|
|
418
|
+
* validate/redeem/spend/topUp call sites.
|
|
419
|
+
*/
|
|
420
|
+
getByCode(code: string, ctx?: Record<string, unknown>): Promise<Voucher | null>;
|
|
421
|
+
/**
|
|
422
|
+
* Idempotency check on nested arrays. Routes through mongokit's `count`
|
|
423
|
+
* so `multiTenantPlugin` injects the configured tenant field from
|
|
424
|
+
* `ctx` — a non-tenant-scoped check would cross organization boundaries.
|
|
425
|
+
*/
|
|
426
|
+
hasIdempotencyKey(id: string, key: string, ctx?: Record<string, unknown>): Promise<boolean>;
|
|
427
|
+
}
|
|
428
|
+
//#endregion
|
|
429
|
+
//#region src/repositories/create-repositories.d.ts
|
|
430
|
+
interface PromoRepositories {
|
|
431
|
+
program: ProgramRepository;
|
|
432
|
+
rule: RuleRepository;
|
|
433
|
+
reward: RewardRepository;
|
|
434
|
+
voucher: VoucherRepository;
|
|
435
|
+
}
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/domain/ports/unit-of-work.port.d.ts
|
|
438
|
+
type TransactionSession = ClientSession;
|
|
439
|
+
interface UnitOfWork {
|
|
440
|
+
withTransaction<T>(cb: (session: TransactionSession) => Promise<T>): Promise<T>;
|
|
441
|
+
}
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/types/results.d.ts
|
|
444
|
+
interface DiscountLine {
|
|
445
|
+
programId: string;
|
|
446
|
+
programName: string;
|
|
447
|
+
rewardId: string;
|
|
448
|
+
type: 'percentage' | 'fixed';
|
|
449
|
+
scope: 'order' | 'cheapest' | 'specific_products';
|
|
450
|
+
amount: number;
|
|
451
|
+
description: string;
|
|
452
|
+
voucherCode?: string;
|
|
453
|
+
}
|
|
454
|
+
interface FreeProductLine {
|
|
455
|
+
programId: string;
|
|
456
|
+
programName: string;
|
|
457
|
+
rewardId: string;
|
|
458
|
+
productId?: string;
|
|
459
|
+
productSku?: string;
|
|
460
|
+
quantity: number;
|
|
461
|
+
description: string;
|
|
462
|
+
}
|
|
463
|
+
interface RejectedCode {
|
|
464
|
+
code: string;
|
|
465
|
+
reason: string;
|
|
466
|
+
}
|
|
467
|
+
interface EvaluationResult {
|
|
468
|
+
evaluationId: string;
|
|
469
|
+
/**
|
|
470
|
+
* Deterministic hash of the evaluated cart (items + subtotal + codes +
|
|
471
|
+
* customerId). Hosts that want tamper-proof commits pass this hash back
|
|
472
|
+
* to `EvaluationService.commit(evaluationId, orderId, ctx, { cartHash })`;
|
|
473
|
+
* the engine throws `CartHashMismatchError` when the caller's hash does
|
|
474
|
+
* not match what was evaluated. Omitting the hash at commit keeps the
|
|
475
|
+
* legacy "trusted host" behaviour.
|
|
476
|
+
*/
|
|
477
|
+
cartHash: string;
|
|
478
|
+
appliedDiscounts: DiscountLine[];
|
|
479
|
+
freeProducts: FreeProductLine[];
|
|
480
|
+
totalDiscount: number;
|
|
481
|
+
subtotalAfterDiscount: number;
|
|
482
|
+
appliedCodes: string[];
|
|
483
|
+
rejectedCodes: RejectedCode[];
|
|
484
|
+
warnings: string[];
|
|
485
|
+
isPreview: boolean;
|
|
486
|
+
programsApplied: string[];
|
|
487
|
+
}
|
|
488
|
+
interface CommitResult {
|
|
489
|
+
evaluationId: string;
|
|
490
|
+
orderId: string;
|
|
491
|
+
totalDiscount: number;
|
|
492
|
+
programsCommitted: number;
|
|
493
|
+
vouchersUsed: number;
|
|
494
|
+
}
|
|
495
|
+
interface VoucherValidation {
|
|
496
|
+
valid: boolean;
|
|
497
|
+
voucher?: {
|
|
498
|
+
code: string;
|
|
499
|
+
programId: string;
|
|
500
|
+
programType: string;
|
|
501
|
+
status: string;
|
|
502
|
+
remainingUses: number;
|
|
503
|
+
currentBalance?: number;
|
|
504
|
+
expiresAt?: Date;
|
|
505
|
+
};
|
|
506
|
+
error?: string;
|
|
507
|
+
}
|
|
508
|
+
interface GiftCardBalance {
|
|
509
|
+
code: string;
|
|
510
|
+
initialBalance: number;
|
|
511
|
+
currentBalance: number;
|
|
512
|
+
spent: number;
|
|
513
|
+
voucherId: string;
|
|
514
|
+
}
|
|
515
|
+
interface PaginatedResult<T> {
|
|
516
|
+
docs: T[];
|
|
517
|
+
page: number;
|
|
518
|
+
limit: number;
|
|
519
|
+
total: number;
|
|
520
|
+
pages: number;
|
|
521
|
+
hasNext: boolean;
|
|
522
|
+
hasPrev: boolean;
|
|
523
|
+
}
|
|
524
|
+
//#endregion
|
|
525
|
+
//#region src/services/evaluation.service.d.ts
|
|
526
|
+
interface CommitOptions {
|
|
527
|
+
/**
|
|
528
|
+
* The `cartHash` returned from `evaluate`. When provided, the engine
|
|
529
|
+
* verifies it matches the hash computed at evaluation time and throws
|
|
530
|
+
* `CartHashMismatchError` on mismatch. Guards against cart-tampering
|
|
531
|
+
* between evaluate and commit (e.g. user previews a big discount on a
|
|
532
|
+
* heavy cart, swaps the cart for a cheaper one, then commits the stale
|
|
533
|
+
* discount). Hosts that trust their own commit pipeline end-to-end may
|
|
534
|
+
* omit it for the legacy behaviour.
|
|
535
|
+
*/
|
|
536
|
+
cartHash?: string;
|
|
537
|
+
}
|
|
538
|
+
declare class EvaluationService {
|
|
539
|
+
private programRepo;
|
|
540
|
+
private ruleRepo;
|
|
541
|
+
private rewardRepo;
|
|
542
|
+
private voucherRepo;
|
|
543
|
+
private unitOfWork;
|
|
544
|
+
private dispatchDeps;
|
|
545
|
+
private config;
|
|
546
|
+
private pendingEvaluations;
|
|
547
|
+
constructor(programRepo: ProgramRepository, ruleRepo: RuleRepository, rewardRepo: RewardRepository, voucherRepo: VoucherRepository, unitOfWork: UnitOfWork, dispatchDeps: DispatchDeps, config: ResolvedConfig);
|
|
548
|
+
evaluate(input: EvaluateInput, ctx: PromoContext): Promise<EvaluationResult>;
|
|
549
|
+
preview(input: EvaluateInput, ctx: PromoContext): Promise<EvaluationResult>;
|
|
550
|
+
commit(evaluationId: string, orderId: string, ctx: PromoContext, options?: CommitOptions): Promise<CommitResult>;
|
|
551
|
+
rollback(evaluationId: string, ctx: PromoContext): Promise<void>;
|
|
552
|
+
private doEvaluate;
|
|
553
|
+
private isCustomerEligible;
|
|
554
|
+
private matchBestRule;
|
|
555
|
+
private matchSingleRule;
|
|
556
|
+
private filterRewardsByRule;
|
|
557
|
+
private computeDiscount;
|
|
558
|
+
private getEligibleItems;
|
|
559
|
+
private describeDiscount;
|
|
560
|
+
}
|
|
561
|
+
//#endregion
|
|
562
|
+
//#region src/services/voucher.service.d.ts
|
|
563
|
+
/**
|
|
564
|
+
* VoucherService — multi-repo domain orchestration only.
|
|
565
|
+
*
|
|
566
|
+
* Code generation, redemption (transactional + idempotency), gift card
|
|
567
|
+
* spend/topUp, and validation live here because they need programRepo +
|
|
568
|
+
* voucherRepo + config + transactions.
|
|
569
|
+
*
|
|
570
|
+
* Simple lookups (getById, getByCode, getAll) and the cancel domain verb
|
|
571
|
+
* live on VoucherRepository directly — callers use the repo. §2/§3.
|
|
572
|
+
*/
|
|
573
|
+
declare class VoucherService {
|
|
574
|
+
private voucherRepo;
|
|
575
|
+
private programRepo;
|
|
576
|
+
private unitOfWork;
|
|
577
|
+
private dispatchDeps;
|
|
578
|
+
private config;
|
|
579
|
+
constructor(voucherRepo: VoucherRepository, programRepo: ProgramRepository, unitOfWork: UnitOfWork, dispatchDeps: DispatchDeps, config: ResolvedConfig);
|
|
580
|
+
generateCodes(input: GenerateCodesInput, ctx: PromoContext): Promise<Voucher[]>;
|
|
581
|
+
generateSingleCode(input: GenerateSingleCodeInput, ctx: PromoContext): Promise<Voucher>;
|
|
582
|
+
validateCode(code: string, ctx: PromoContext): Promise<VoucherValidation>;
|
|
583
|
+
redeem(input: RedeemVoucherInput, ctx: PromoContext): Promise<Voucher>;
|
|
584
|
+
getBalance(code: string, ctx: PromoContext): Promise<GiftCardBalance>;
|
|
585
|
+
spend(input: GiftCardSpendInput, ctx: PromoContext): Promise<GiftCardBalance>;
|
|
586
|
+
private spendInTransaction;
|
|
587
|
+
topUp(input: GiftCardTopUpInput, ctx: PromoContext): Promise<GiftCardBalance>;
|
|
588
|
+
private assertVoucherUsable;
|
|
589
|
+
}
|
|
590
|
+
//#endregion
|
|
591
|
+
//#region src/services/create-services.d.ts
|
|
592
|
+
interface PromoServices {
|
|
593
|
+
voucher: VoucherService;
|
|
594
|
+
evaluation: EvaluationService;
|
|
595
|
+
}
|
|
596
|
+
//#endregion
|
|
597
|
+
//#region src/events/event-constants.d.ts
|
|
598
|
+
declare const PromoEvents: {
|
|
599
|
+
readonly PROGRAM_CREATED: "promo.program.created";
|
|
600
|
+
readonly PROGRAM_ACTIVATED: "promo.program.activated";
|
|
601
|
+
readonly PROGRAM_PAUSED: "promo.program.paused";
|
|
602
|
+
readonly PROGRAM_ARCHIVED: "promo.program.archived";
|
|
603
|
+
readonly RULE_ADDED: "promo.rule.added";
|
|
604
|
+
readonly RULE_UPDATED: "promo.rule.updated";
|
|
605
|
+
readonly RULE_REMOVED: "promo.rule.removed";
|
|
606
|
+
readonly REWARD_ADDED: "promo.reward.added";
|
|
607
|
+
readonly REWARD_UPDATED: "promo.reward.updated";
|
|
608
|
+
readonly REWARD_REMOVED: "promo.reward.removed";
|
|
609
|
+
readonly VOUCHER_GENERATED: "promo.voucher.generated";
|
|
610
|
+
readonly VOUCHER_REDEEMED: "promo.voucher.redeemed";
|
|
611
|
+
readonly VOUCHER_CANCELLED: "promo.voucher.cancelled";
|
|
612
|
+
readonly VOUCHER_EXPIRED: "promo.voucher.expired";
|
|
613
|
+
readonly GIFT_CARD_SPENT: "promo.gift_card.spent";
|
|
614
|
+
readonly GIFT_CARD_TOPPED_UP: "promo.gift_card.topped_up";
|
|
615
|
+
readonly GIFT_CARD_EXHAUSTED: "promo.gift_card.exhausted";
|
|
616
|
+
readonly EVALUATION_COMPLETED: "promo.evaluation.completed";
|
|
617
|
+
readonly EVALUATION_COMMITTED: "promo.evaluation.committed";
|
|
618
|
+
readonly EVALUATION_ROLLED_BACK: "promo.evaluation.rolled_back";
|
|
619
|
+
};
|
|
620
|
+
type PromoEventName = (typeof PromoEvents)[keyof typeof PromoEvents];
|
|
621
|
+
//#endregion
|
|
622
|
+
//#region src/events/promo-event-catalog.d.ts
|
|
623
|
+
interface PromoEventSchema {
|
|
624
|
+
type: 'object';
|
|
625
|
+
properties?: Record<string, {
|
|
626
|
+
type?: string;
|
|
627
|
+
format?: string;
|
|
628
|
+
[key: string]: unknown;
|
|
629
|
+
}>;
|
|
630
|
+
required?: string[];
|
|
631
|
+
[key: string]: unknown;
|
|
632
|
+
}
|
|
633
|
+
interface PromoEventDefinition<TSchema extends z.ZodType = z.ZodType> {
|
|
634
|
+
readonly name: string;
|
|
635
|
+
readonly version: number;
|
|
636
|
+
readonly description?: string;
|
|
637
|
+
readonly schema: PromoEventSchema;
|
|
638
|
+
readonly zodSchema: TSchema;
|
|
639
|
+
create(payload: z.infer<TSchema>, meta?: Partial<DomainEvent$1['meta']>): DomainEvent$1<z.infer<TSchema>>;
|
|
640
|
+
readonly __payload?: z.infer<TSchema>;
|
|
641
|
+
}
|
|
642
|
+
type PromoEventPayloadOf<D> = D extends PromoEventDefinition<infer S> ? z.infer<S> : never;
|
|
643
|
+
declare const ProgramCreated: PromoEventDefinition<z.ZodObject<{
|
|
644
|
+
programId: z.ZodString;
|
|
645
|
+
programType: z.ZodString;
|
|
646
|
+
status: z.ZodString;
|
|
647
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
648
|
+
}, z.core.$strip>>;
|
|
649
|
+
declare const ProgramActivated: PromoEventDefinition<z.ZodObject<{
|
|
650
|
+
programId: z.ZodString;
|
|
651
|
+
programType: z.ZodString;
|
|
652
|
+
status: z.ZodString;
|
|
653
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
654
|
+
}, z.core.$strip>>;
|
|
655
|
+
declare const ProgramPaused: PromoEventDefinition<z.ZodObject<{
|
|
656
|
+
programId: z.ZodString;
|
|
657
|
+
programType: z.ZodString;
|
|
658
|
+
status: z.ZodString;
|
|
659
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
660
|
+
}, z.core.$strip>>;
|
|
661
|
+
declare const ProgramArchived: PromoEventDefinition<z.ZodObject<{
|
|
662
|
+
programId: z.ZodString;
|
|
663
|
+
programType: z.ZodString;
|
|
664
|
+
status: z.ZodString;
|
|
665
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
666
|
+
}, z.core.$strip>>;
|
|
667
|
+
declare const RuleAdded: PromoEventDefinition<z.ZodObject<{
|
|
668
|
+
programId: z.ZodString;
|
|
669
|
+
ruleId: z.ZodString;
|
|
670
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
671
|
+
}, z.core.$strip>>;
|
|
672
|
+
declare const RuleUpdated: PromoEventDefinition<z.ZodObject<{
|
|
673
|
+
programId: z.ZodString;
|
|
674
|
+
ruleId: z.ZodString;
|
|
675
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
676
|
+
}, z.core.$strip>>;
|
|
677
|
+
declare const RuleRemoved: PromoEventDefinition<z.ZodObject<{
|
|
678
|
+
programId: z.ZodString;
|
|
679
|
+
ruleId: z.ZodString;
|
|
680
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
681
|
+
}, z.core.$strip>>;
|
|
682
|
+
declare const RewardAdded: PromoEventDefinition<z.ZodObject<{
|
|
683
|
+
programId: z.ZodString;
|
|
684
|
+
rewardId: z.ZodString;
|
|
685
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
686
|
+
}, z.core.$strip>>;
|
|
687
|
+
declare const RewardUpdated: PromoEventDefinition<z.ZodObject<{
|
|
688
|
+
programId: z.ZodString;
|
|
689
|
+
rewardId: z.ZodString;
|
|
690
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
691
|
+
}, z.core.$strip>>;
|
|
692
|
+
declare const RewardRemoved: PromoEventDefinition<z.ZodObject<{
|
|
693
|
+
programId: z.ZodString;
|
|
694
|
+
rewardId: z.ZodString;
|
|
695
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
696
|
+
}, z.core.$strip>>;
|
|
697
|
+
declare const VoucherGenerated: PromoEventDefinition<z.ZodObject<{
|
|
698
|
+
programId: z.ZodString;
|
|
699
|
+
voucherIds: z.ZodArray<z.ZodString>;
|
|
700
|
+
codes: z.ZodArray<z.ZodString>;
|
|
701
|
+
count: z.ZodNumber;
|
|
702
|
+
actorId: z.ZodOptional<z.ZodString>;
|
|
703
|
+
}, z.core.$strip>>;
|
|
704
|
+
declare const VoucherRedeemed: PromoEventDefinition<z.ZodObject<{
|
|
705
|
+
voucherId: z.ZodString;
|
|
706
|
+
code: z.ZodString;
|
|
707
|
+
orderId: z.ZodString;
|
|
708
|
+
discountAmount: z.ZodNumber;
|
|
709
|
+
customerId: z.ZodOptional<z.ZodString>;
|
|
710
|
+
}, z.core.$strip>>;
|
|
711
|
+
declare const VoucherCancelled: PromoEventDefinition<z.ZodObject<{
|
|
712
|
+
voucherId: z.ZodString;
|
|
713
|
+
code: z.ZodString;
|
|
714
|
+
status: z.ZodString;
|
|
715
|
+
}, z.core.$strip>>;
|
|
716
|
+
declare const VoucherExpired: PromoEventDefinition<z.ZodObject<{
|
|
717
|
+
voucherId: z.ZodString;
|
|
718
|
+
code: z.ZodString;
|
|
719
|
+
status: z.ZodString;
|
|
720
|
+
}, z.core.$strip>>;
|
|
721
|
+
declare const GiftCardSpent: PromoEventDefinition<z.ZodObject<{
|
|
722
|
+
voucherId: z.ZodString;
|
|
723
|
+
code: z.ZodString;
|
|
724
|
+
amount: z.ZodNumber;
|
|
725
|
+
remainingBalance: z.ZodNumber;
|
|
726
|
+
orderId: z.ZodString;
|
|
727
|
+
}, z.core.$strip>>;
|
|
728
|
+
declare const GiftCardToppedUp: PromoEventDefinition<z.ZodObject<{
|
|
729
|
+
voucherId: z.ZodString;
|
|
730
|
+
code: z.ZodString;
|
|
731
|
+
amount: z.ZodNumber;
|
|
732
|
+
newBalance: z.ZodNumber;
|
|
733
|
+
}, z.core.$strip>>;
|
|
734
|
+
declare const GiftCardExhausted: PromoEventDefinition<z.ZodObject<{
|
|
735
|
+
voucherId: z.ZodString;
|
|
736
|
+
code: z.ZodString;
|
|
737
|
+
status: z.ZodString;
|
|
738
|
+
}, z.core.$strip>>;
|
|
739
|
+
declare const EvaluationCompleted: PromoEventDefinition<z.ZodObject<{
|
|
740
|
+
evaluationId: z.ZodString;
|
|
741
|
+
totalDiscount: z.ZodNumber;
|
|
742
|
+
programsApplied: z.ZodNumber;
|
|
743
|
+
codesUsed: z.ZodArray<z.ZodString>;
|
|
744
|
+
isPreview: z.ZodBoolean;
|
|
745
|
+
}, z.core.$strip>>;
|
|
746
|
+
declare const EvaluationCommitted: PromoEventDefinition<z.ZodObject<{
|
|
747
|
+
evaluationId: z.ZodString;
|
|
748
|
+
orderId: z.ZodString;
|
|
749
|
+
totalDiscount: z.ZodNumber;
|
|
750
|
+
}, z.core.$strip>>;
|
|
751
|
+
declare const EvaluationRolledBack: PromoEventDefinition<z.ZodObject<{
|
|
752
|
+
evaluationId: z.ZodString;
|
|
753
|
+
}, z.core.$strip>>;
|
|
754
|
+
/**
|
|
755
|
+
* Every promo event defined in the package — pass to Arc's
|
|
756
|
+
* `EventRegistry`. Hosts wire ONE array; the whole `promo.*` namespace
|
|
757
|
+
* becomes introspectable via OpenAPI and auto-validated at publish time
|
|
758
|
+
* when `eventPlugin({ validateMode: 'reject' })` is set.
|
|
759
|
+
*/
|
|
760
|
+
declare const promoEventDefinitions: ReadonlyArray<PromoEventDefinition>;
|
|
761
|
+
//#endregion
|
|
10
762
|
//#region src/index.d.ts
|
|
11
763
|
declare function resolveConfig(config: PromoConfig): ResolvedConfig;
|
|
12
764
|
interface PromoEngine {
|
|
13
765
|
models: PromoModels;
|
|
14
766
|
repositories: PromoRepositories;
|
|
15
767
|
services: PromoServices;
|
|
16
|
-
events:
|
|
768
|
+
events: EventTransport$1;
|
|
769
|
+
syncIndexes(): Promise<void>;
|
|
17
770
|
}
|
|
18
771
|
declare function createPromoEngine(config: PromoConfig): PromoEngine;
|
|
19
772
|
//#endregion
|
|
20
|
-
export { type BalanceLedgerEntry, type CartItem, type CommitResult, type CreateProgramInput, type CreateRewardInput, type CreateRuleInput, type DiscountLine, type EvaluateInput, type EvaluationResult, type
|
|
773
|
+
export { type BalanceLedgerEntry, type CartItem, type CommitResult, type CreateProgramInput, type CreateRewardInput, type CreateRuleInput, type DiscountLine, type DomainEvent, type EvaluateInput, EvaluationCommitted, EvaluationCompleted, type EvaluationResult, EvaluationRolledBack, type EventHandler, type EventTransport, type FreeProductLine, type GenerateCodesInput, type GenerateSingleCodeInput, type GiftCardBalance, GiftCardExhausted, type GiftCardSpendInput, GiftCardSpent, type GiftCardTopUpInput, GiftCardToppedUp, type ListQuery, type PaginatedResult, type Program, ProgramActivated, ProgramArchived, ProgramCreated, ProgramPaused, ProgramRepository, type PromoConfig, type PromoContext, PromoEngine, type PromoEventDefinition, type PromoEventName, type PromoEventPayloadOf, type PromoEventSchema, PromoEvents, type PromoModels, type PromoRepositories, type PromoServices, type RedeemVoucherInput, type RejectedCode, type ResolvedConfig, type ResolvedTenant, type Reward, RewardAdded, RewardRemoved, RewardRepository, RewardUpdated, type Rule, RuleAdded, RuleRemoved, RuleRepository, RuleUpdated, type UpdateProgramInput, type UpdateRewardInput, type UpdateRuleInput, type Voucher, VoucherCancelled, VoucherExpired, VoucherGenerated, VoucherRedeemed, type VoucherRedemption, VoucherRepository, type VoucherValidation, createPromoEngine, promoEventDefinitions, resolveConfig };
|