@classytic/loyalty 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { t as NotificationAdapter } from "./notification.port-9B5xlzxQ.mjs";
1
+ 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";
@@ -1,2 +1,2 @@
1
- import { A as TierUpgraded, B as PointsEarnedPayload, C as ReferralRecorded, D as TierGraceStarted, E as TierDowngraded, F as LoyaltyEventPayload, G as TierChangedPayload, H as RedemptionPayload, I as LoyaltyEvents, J as InProcessLoyaltyBus, K as TierOverrideLifecyclePayload, L as MemberLifecyclePayload, M as CampaignAwardedPayload, N as LoyaltyEventMap, O as TierOverrideCleared, P as LoyaltyEventName, R as MultiTierReferralAwardedPayload, S as ReferralApproved, T as ReferralRewarded, U as RedemptionReversedPayload, V as PointsExpiredPayload, W as ReferralPayload, Y as InProcessLoyaltyBusOptions, _ as PointsRedeemed, a as LoyaltyEventDefinition, b as RedemptionReserved, c as MemberDeactivated, d as MemberSuspended, f as MultiTierReferralAwarded, g as PointsExpiringSoon, h as PointsExpired, i as CampaignAwarded, j as loyaltyEventDefinitions, k as TierOverrideExpired, l as MemberEnrolled, m as PointsEarned, n as EventHandler, o as LoyaltyEventPayloadOf, p as PointsAdjusted, q as createEvent, r as EventTransport, s as LoyaltyEventSchema, t as DomainEvent, u as MemberReactivated, v as RedemptionConfirmed, w as ReferralRejected, x as RedemptionReversed, y as RedemptionReleased, z as PointsAdjustedPayload } from "../index-BmqGuj38.mjs";
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-C4jFHS7m.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,3 +1,3 @@
1
- import { C as TierOverrideExpired, E as InProcessLoyaltyBus, S as TierOverrideCleared, T as loyaltyEventDefinitions, _ as ReferralRecorded, a as MemberSuspended, b as TierDowngraded, c as PointsEarned, d as PointsRedeemed, f as RedemptionConfirmed, g as ReferralApproved, h as RedemptionReversed, i as MemberReactivated, l as PointsExpired, m as RedemptionReserved, n as MemberDeactivated, o as MultiTierReferralAwarded, p as RedemptionReleased, r as MemberEnrolled, s as PointsAdjusted, t as CampaignAwarded, u as PointsExpiringSoon, v as ReferralRejected, w as TierUpgraded, x as TierGraceStarted, y as ReferralRewarded } from "../events-BjzHSLBn.mjs";
1
+ import { C as TierOverrideExpired, E as InProcessLoyaltyBus, S as TierOverrideCleared, T as loyaltyEventDefinitions, _ as ReferralRecorded, a as MemberSuspended, b as TierDowngraded, c as PointsEarned, d as PointsRedeemed, f as RedemptionConfirmed, g as ReferralApproved, h as RedemptionReversed, i as MemberReactivated, l as PointsExpired, m as RedemptionReserved, n as MemberDeactivated, o as MultiTierReferralAwarded, p as RedemptionReleased, r as MemberEnrolled, s as PointsAdjusted, t as CampaignAwarded, u as PointsExpiringSoon, v as ReferralRejected, w as TierUpgraded, x as TierGraceStarted, y as ReferralRewarded } from "../events-BtZOdiPw.mjs";
2
2
  import { n as createEvent, t as LoyaltyEvents } from "../loyalty-events-Cyt9TwX6.mjs";
3
3
  export { CampaignAwarded, InProcessLoyaltyBus, LoyaltyEvents, MemberDeactivated, MemberEnrolled, MemberReactivated, MemberSuspended, MultiTierReferralAwarded, PointsAdjusted, PointsEarned, PointsExpired, PointsExpiringSoon, PointsRedeemed, RedemptionConfirmed, RedemptionReleased, RedemptionReserved, RedemptionReversed, ReferralApproved, ReferralRecorded, ReferralRejected, ReferralRewarded, TierDowngraded, TierGraceStarted, TierOverrideCleared, TierOverrideExpired, TierUpgraded, createEvent, loyaltyEventDefinitions };
@@ -34,39 +34,6 @@ var InProcessLoyaltyBus = class {
34
34
  };
35
35
  //#endregion
36
36
  //#region src/events/loyalty-event-catalog.ts
37
- /**
38
- * Loyalty event catalog — Zod-source-of-truth definitions for every
39
- * `loyalty.*` event.
40
- *
41
- * Each definition exposes:
42
- * - `.zodSchema` — source of truth, used by host code's `.safeParse()`
43
- * - `.schema` — JSON Schema derived via `z.toJSONSchema()`, consumed
44
- * by Arc's EventRegistry + OpenAPI plugin
45
- * - `.create(...)` — DomainEvent envelope builder, structurally compatible
46
- * with `@classytic/arc`'s `EventDefinitionOutput`
47
- *
48
- * Structurally compatible with Arc 2.10's `EventRegistry` — hosts register
49
- * `loyaltyEventDefinitions` directly, no adapter code. Loyalty does NOT
50
- * import from `@classytic/arc` (PACKAGE_RULES §11); compatibility is
51
- * purely structural.
52
- *
53
- * Payload schemas mirror the typed interfaces in
54
- * [loyalty-events.ts](./loyalty-events.ts). See PACKAGE_RULES §18.5 for
55
- * the pattern.
56
- *
57
- * @example Wiring into an Arc app
58
- * ```ts
59
- * import { createEventRegistry } from '@classytic/arc/events';
60
- * import { loyaltyEventDefinitions } from '@classytic/loyalty/events';
61
- *
62
- * const registry = createEventRegistry();
63
- * for (const def of loyaltyEventDefinitions) registry.register(def);
64
- *
65
- * const app = await createApp({
66
- * arcPlugins: { events: { registry, validateMode: 'reject' } },
67
- * });
68
- * ```
69
- */
70
37
  function defineLoyaltyEvent(input) {
71
38
  const { name, version = 1, description, zodSchema } = input;
72
39
  const def = {
@@ -1,7 +1,10 @@
1
- import { o as LoyaltyContext } from "./index-2izQQext.mjs";
1
+ import { o as LoyaltyContext } from "./index-BOWqBSWx.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
 
5
+ //#region src/events/helpers.d.ts
6
+ declare function createEvent$1<T>(type: string, payload: T, ctx?: LoyaltyContext, meta?: Partial<DomainEvent['meta']>): DomainEvent<T>;
7
+ //#endregion
5
8
  //#region src/events/in-process-bus.d.ts
6
9
  interface InProcessLoyaltyBusOptions {
7
10
  /** Logger for handler errors (default: console). */
@@ -19,169 +22,6 @@ declare class InProcessLoyaltyBus implements EventTransport {
19
22
  close(): Promise<void>;
20
23
  }
21
24
  //#endregion
22
- //#region src/events/helpers.d.ts
23
- declare function createEvent$1<T>(type: string, payload: T, ctx?: LoyaltyContext, meta?: Partial<DomainEvent['meta']>): DomainEvent<T>;
24
- //#endregion
25
- //#region src/events/loyalty-events.d.ts
26
- /**
27
- * Loyalty event name + payload map.
28
- *
29
- * Minimal surface. Loyalty emits events for its own lifecycle transitions
30
- * only — member, points ledger, tier, redemption, and referral.
31
- *
32
- * For registration with an arc-compatible event registry, see
33
- * `loyalty-event-catalog.ts` in this directory — it exposes each event as
34
- * a `LoyaltyEventDefinition` with a Zod payload schema + JSON Schema
35
- * derived via `z.toJSONSchema()` (PACKAGE_RULES §18.5).
36
- */
37
- declare const LoyaltyEvents: {
38
- readonly MEMBER_ENROLLED: "loyalty.member.enrolled";
39
- readonly MEMBER_DEACTIVATED: "loyalty.member.deactivated";
40
- readonly MEMBER_REACTIVATED: "loyalty.member.reactivated";
41
- readonly MEMBER_SUSPENDED: "loyalty.member.suspended";
42
- readonly POINTS_EARNED: "loyalty.points.earned";
43
- readonly POINTS_REDEEMED: "loyalty.points.redeemed";
44
- readonly POINTS_ADJUSTED: "loyalty.points.adjusted";
45
- readonly POINTS_EXPIRED: "loyalty.points.expired";
46
- readonly POINTS_EXPIRING_SOON: "loyalty.points.expiring_soon";
47
- readonly TIER_UPGRADED: "loyalty.tier.upgraded";
48
- readonly TIER_DOWNGRADED: "loyalty.tier.downgraded";
49
- readonly TIER_GRACE_STARTED: "loyalty.tier.grace_started";
50
- readonly TIER_OVERRIDE_CLEARED: "loyalty.tier.override_cleared";
51
- readonly TIER_OVERRIDE_EXPIRED: "loyalty.tier.override_expired";
52
- readonly REDEMPTION_RESERVED: "loyalty.redemption.reserved";
53
- readonly REDEMPTION_CONFIRMED: "loyalty.redemption.confirmed";
54
- readonly REDEMPTION_RELEASED: "loyalty.redemption.released";
55
- readonly REDEMPTION_REVERSED: "loyalty.redemption.reversed";
56
- readonly CAMPAIGN_AWARDED: "loyalty.campaign.awarded";
57
- readonly REFERRAL_RECORDED: "loyalty.referral.recorded";
58
- readonly REFERRAL_APPROVED: "loyalty.referral.approved";
59
- readonly REFERRAL_REJECTED: "loyalty.referral.rejected";
60
- readonly REFERRAL_REWARDED: "loyalty.referral.rewarded";
61
- readonly MULTI_TIER_REFERRAL_AWARDED: "loyalty.referral.multi_tier_awarded";
62
- };
63
- type LoyaltyEventName = (typeof LoyaltyEvents)[keyof typeof LoyaltyEvents];
64
- interface MemberLifecyclePayload {
65
- memberId: string;
66
- externalId: string;
67
- externalType: string;
68
- status: string;
69
- }
70
- interface PointsEarnedPayload {
71
- memberId: string;
72
- externalId: string;
73
- externalType: string;
74
- points: number;
75
- balanceAfter: number;
76
- transactionId: string;
77
- earningRuleName?: string;
78
- referenceType?: string;
79
- referenceId?: string;
80
- }
81
- interface PointsAdjustedPayload {
82
- memberId: string;
83
- externalId: string;
84
- points: number;
85
- balanceAfter: number;
86
- transactionId: string;
87
- description: string;
88
- }
89
- interface PointsExpiredPayload {
90
- membersAffected: number;
91
- pointsExpired: number;
92
- transactionCount: number;
93
- }
94
- interface TierChangedPayload {
95
- memberId: string;
96
- externalId: string;
97
- previousTier: string | null;
98
- newTier: string | null;
99
- lifetimePoints: number;
100
- }
101
- interface RedemptionPayload {
102
- memberId: string;
103
- externalId: string;
104
- redemptionId: string;
105
- points: number;
106
- discountAmount: number;
107
- ownerType: string;
108
- ownerId: string;
109
- }
110
- interface ReferralPayload {
111
- referralId: string;
112
- referrerId: string;
113
- refereeId: string;
114
- referralCode: string;
115
- status: string;
116
- referrerRewardPoints?: number;
117
- refereeRewardPoints?: number;
118
- }
119
- interface TierOverrideLifecyclePayload {
120
- memberId: string;
121
- externalId: string;
122
- tier: string;
123
- reason?: string;
124
- /** ISO string — Dates can't be JSON-schema'd. Present only on TTL-sweep path. */
125
- expiredAt?: string;
126
- }
127
- interface RedemptionReversedPayload {
128
- memberId: string;
129
- externalId: string;
130
- redemptionId: string;
131
- /** Points credited back to the member by the reversal. */
132
- pointsCredited: number;
133
- /** Original confirmed points on the redemption. */
134
- originalPoints: number;
135
- proportional: boolean;
136
- reason?: string;
137
- transactionId: string;
138
- }
139
- interface CampaignAwardedPayload {
140
- campaignId: string;
141
- memberCount: number;
142
- awarded: number;
143
- skipped: number;
144
- totalPoints: number;
145
- }
146
- interface MultiTierReferralAwardedPayload {
147
- referralId: string;
148
- refereeId: string;
149
- /** Awards keyed by ancestor depth (1 = direct referrer). */
150
- awards: Array<{
151
- memberId: string;
152
- depth: number;
153
- points: number;
154
- transactionId: string;
155
- }>;
156
- }
157
- interface LoyaltyEventMap {
158
- [LoyaltyEvents.MEMBER_ENROLLED]: MemberLifecyclePayload;
159
- [LoyaltyEvents.MEMBER_DEACTIVATED]: MemberLifecyclePayload;
160
- [LoyaltyEvents.MEMBER_REACTIVATED]: MemberLifecyclePayload;
161
- [LoyaltyEvents.MEMBER_SUSPENDED]: MemberLifecyclePayload;
162
- [LoyaltyEvents.POINTS_EARNED]: PointsEarnedPayload;
163
- [LoyaltyEvents.POINTS_REDEEMED]: PointsAdjustedPayload;
164
- [LoyaltyEvents.POINTS_ADJUSTED]: PointsAdjustedPayload;
165
- [LoyaltyEvents.POINTS_EXPIRED]: PointsExpiredPayload;
166
- [LoyaltyEvents.POINTS_EXPIRING_SOON]: PointsExpiredPayload;
167
- [LoyaltyEvents.TIER_UPGRADED]: TierChangedPayload;
168
- [LoyaltyEvents.TIER_DOWNGRADED]: TierChangedPayload;
169
- [LoyaltyEvents.TIER_GRACE_STARTED]: TierChangedPayload;
170
- [LoyaltyEvents.TIER_OVERRIDE_CLEARED]: TierOverrideLifecyclePayload;
171
- [LoyaltyEvents.TIER_OVERRIDE_EXPIRED]: TierOverrideLifecyclePayload;
172
- [LoyaltyEvents.REDEMPTION_RESERVED]: RedemptionPayload;
173
- [LoyaltyEvents.REDEMPTION_CONFIRMED]: RedemptionPayload;
174
- [LoyaltyEvents.REDEMPTION_RELEASED]: RedemptionPayload;
175
- [LoyaltyEvents.REDEMPTION_REVERSED]: RedemptionReversedPayload;
176
- [LoyaltyEvents.CAMPAIGN_AWARDED]: CampaignAwardedPayload;
177
- [LoyaltyEvents.REFERRAL_RECORDED]: ReferralPayload;
178
- [LoyaltyEvents.REFERRAL_APPROVED]: ReferralPayload;
179
- [LoyaltyEvents.REFERRAL_REJECTED]: ReferralPayload;
180
- [LoyaltyEvents.REFERRAL_REWARDED]: ReferralPayload;
181
- [LoyaltyEvents.MULTI_TIER_REFERRAL_AWARDED]: MultiTierReferralAwardedPayload;
182
- }
183
- type LoyaltyEventPayload<E extends LoyaltyEventName> = LoyaltyEventMap[E];
184
- //#endregion
185
25
  //#region src/events/loyalty-event-catalog.d.ts
186
26
  interface LoyaltyEventSchema {
187
27
  type: 'object';
@@ -397,4 +237,164 @@ declare const MultiTierReferralAwarded: LoyaltyEventDefinition<z.ZodObject<{
397
237
  */
398
238
  declare const loyaltyEventDefinitions: ReadonlyArray<LoyaltyEventDefinition>;
399
239
  //#endregion
400
- export { TierUpgraded as A, PointsEarnedPayload as B, ReferralRecorded as C, TierGraceStarted as D, TierDowngraded as E, LoyaltyEventPayload as F, TierChangedPayload as G, RedemptionPayload as H, LoyaltyEvents as I, InProcessLoyaltyBus as J, TierOverrideLifecyclePayload as K, MemberLifecyclePayload as L, CampaignAwardedPayload as M, LoyaltyEventMap as N, TierOverrideCleared as O, LoyaltyEventName as P, MultiTierReferralAwardedPayload as R, ReferralApproved as S, ReferralRewarded as T, RedemptionReversedPayload as U, PointsExpiredPayload as V, ReferralPayload as W, InProcessLoyaltyBusOptions as Y, PointsRedeemed as _, LoyaltyEventDefinition as a, RedemptionReserved as b, MemberDeactivated as c, MemberSuspended as d, MultiTierReferralAwarded as f, PointsExpiringSoon as g, PointsExpired as h, CampaignAwarded as i, loyaltyEventDefinitions as j, TierOverrideExpired as k, MemberEnrolled as l, PointsEarned as m, EventHandler$1 as n, LoyaltyEventPayloadOf as o, PointsAdjusted as p, createEvent$1 as q, EventTransport$1 as r, LoyaltyEventSchema as s, DomainEvent$1 as t, MemberReactivated as u, RedemptionConfirmed as v, ReferralRejected as w, RedemptionReversed as x, RedemptionReleased as y, PointsAdjustedPayload as z };
240
+ //#region src/events/loyalty-events.d.ts
241
+ /**
242
+ * Loyalty event name + payload map.
243
+ *
244
+ * Minimal surface. Loyalty emits events for its own lifecycle transitions
245
+ * only — member, points ledger, tier, redemption, and referral.
246
+ *
247
+ * For registration with an arc-compatible event registry, see
248
+ * `loyalty-event-catalog.ts` in this directory — it exposes each event as
249
+ * a `LoyaltyEventDefinition` with a Zod payload schema + JSON Schema
250
+ * derived via `z.toJSONSchema()` (PACKAGE_RULES §18.5).
251
+ */
252
+ declare const LoyaltyEvents: {
253
+ readonly MEMBER_ENROLLED: "loyalty.member.enrolled";
254
+ readonly MEMBER_DEACTIVATED: "loyalty.member.deactivated";
255
+ readonly MEMBER_REACTIVATED: "loyalty.member.reactivated";
256
+ readonly MEMBER_SUSPENDED: "loyalty.member.suspended";
257
+ readonly POINTS_EARNED: "loyalty.points.earned";
258
+ readonly POINTS_REDEEMED: "loyalty.points.redeemed";
259
+ readonly POINTS_ADJUSTED: "loyalty.points.adjusted";
260
+ readonly POINTS_EXPIRED: "loyalty.points.expired";
261
+ readonly POINTS_EXPIRING_SOON: "loyalty.points.expiring_soon";
262
+ readonly TIER_UPGRADED: "loyalty.tier.upgraded";
263
+ readonly TIER_DOWNGRADED: "loyalty.tier.downgraded";
264
+ readonly TIER_GRACE_STARTED: "loyalty.tier.grace_started";
265
+ readonly TIER_OVERRIDE_CLEARED: "loyalty.tier.override_cleared";
266
+ readonly TIER_OVERRIDE_EXPIRED: "loyalty.tier.override_expired";
267
+ readonly REDEMPTION_RESERVED: "loyalty.redemption.reserved";
268
+ readonly REDEMPTION_CONFIRMED: "loyalty.redemption.confirmed";
269
+ readonly REDEMPTION_RELEASED: "loyalty.redemption.released";
270
+ readonly REDEMPTION_REVERSED: "loyalty.redemption.reversed";
271
+ readonly CAMPAIGN_AWARDED: "loyalty.campaign.awarded";
272
+ readonly REFERRAL_RECORDED: "loyalty.referral.recorded";
273
+ readonly REFERRAL_APPROVED: "loyalty.referral.approved";
274
+ readonly REFERRAL_REJECTED: "loyalty.referral.rejected";
275
+ readonly REFERRAL_REWARDED: "loyalty.referral.rewarded";
276
+ readonly MULTI_TIER_REFERRAL_AWARDED: "loyalty.referral.multi_tier_awarded";
277
+ };
278
+ type LoyaltyEventName = (typeof LoyaltyEvents)[keyof typeof LoyaltyEvents];
279
+ interface MemberLifecyclePayload {
280
+ memberId: string;
281
+ externalId: string;
282
+ externalType: string;
283
+ status: string;
284
+ }
285
+ interface PointsEarnedPayload {
286
+ memberId: string;
287
+ externalId: string;
288
+ externalType: string;
289
+ points: number;
290
+ balanceAfter: number;
291
+ transactionId: string;
292
+ earningRuleName?: string;
293
+ referenceType?: string;
294
+ referenceId?: string;
295
+ }
296
+ interface PointsAdjustedPayload {
297
+ memberId: string;
298
+ externalId: string;
299
+ points: number;
300
+ balanceAfter: number;
301
+ transactionId: string;
302
+ description: string;
303
+ }
304
+ interface PointsExpiredPayload {
305
+ membersAffected: number;
306
+ pointsExpired: number;
307
+ transactionCount: number;
308
+ }
309
+ interface TierChangedPayload {
310
+ memberId: string;
311
+ externalId: string;
312
+ previousTier: string | null;
313
+ newTier: string | null;
314
+ lifetimePoints: number;
315
+ }
316
+ interface RedemptionPayload {
317
+ memberId: string;
318
+ externalId: string;
319
+ redemptionId: string;
320
+ points: number;
321
+ discountAmount: number;
322
+ ownerType: string;
323
+ ownerId: string;
324
+ }
325
+ interface ReferralPayload {
326
+ referralId: string;
327
+ referrerId: string;
328
+ refereeId: string;
329
+ referralCode: string;
330
+ status: string;
331
+ referrerRewardPoints?: number;
332
+ refereeRewardPoints?: number;
333
+ }
334
+ interface TierOverrideLifecyclePayload {
335
+ memberId: string;
336
+ externalId: string;
337
+ tier: string;
338
+ reason?: string;
339
+ /** ISO string — Dates can't be JSON-schema'd. Present only on TTL-sweep path. */
340
+ expiredAt?: string;
341
+ }
342
+ interface RedemptionReversedPayload {
343
+ memberId: string;
344
+ externalId: string;
345
+ redemptionId: string;
346
+ /** Points credited back to the member by the reversal. */
347
+ pointsCredited: number;
348
+ /** Original confirmed points on the redemption. */
349
+ originalPoints: number;
350
+ proportional: boolean;
351
+ reason?: string;
352
+ transactionId: string;
353
+ }
354
+ interface CampaignAwardedPayload {
355
+ campaignId: string;
356
+ memberCount: number;
357
+ awarded: number;
358
+ skipped: number;
359
+ totalPoints: number;
360
+ }
361
+ interface MultiTierReferralAwardedPayload {
362
+ referralId: string;
363
+ refereeId: string;
364
+ /** Awards keyed by ancestor depth (1 = direct referrer). */
365
+ awards: Array<{
366
+ memberId: string;
367
+ depth: number;
368
+ points: number;
369
+ transactionId: string;
370
+ }>;
371
+ }
372
+ interface LoyaltyEventMap {
373
+ [LoyaltyEvents.MEMBER_ENROLLED]: MemberLifecyclePayload;
374
+ [LoyaltyEvents.MEMBER_DEACTIVATED]: MemberLifecyclePayload;
375
+ [LoyaltyEvents.MEMBER_REACTIVATED]: MemberLifecyclePayload;
376
+ [LoyaltyEvents.MEMBER_SUSPENDED]: MemberLifecyclePayload;
377
+ [LoyaltyEvents.POINTS_EARNED]: PointsEarnedPayload;
378
+ [LoyaltyEvents.POINTS_REDEEMED]: PointsAdjustedPayload;
379
+ [LoyaltyEvents.POINTS_ADJUSTED]: PointsAdjustedPayload;
380
+ [LoyaltyEvents.POINTS_EXPIRED]: PointsExpiredPayload;
381
+ [LoyaltyEvents.POINTS_EXPIRING_SOON]: PointsExpiredPayload;
382
+ [LoyaltyEvents.TIER_UPGRADED]: TierChangedPayload;
383
+ [LoyaltyEvents.TIER_DOWNGRADED]: TierChangedPayload;
384
+ [LoyaltyEvents.TIER_GRACE_STARTED]: TierChangedPayload;
385
+ [LoyaltyEvents.TIER_OVERRIDE_CLEARED]: TierOverrideLifecyclePayload;
386
+ [LoyaltyEvents.TIER_OVERRIDE_EXPIRED]: TierOverrideLifecyclePayload;
387
+ [LoyaltyEvents.REDEMPTION_RESERVED]: RedemptionPayload;
388
+ [LoyaltyEvents.REDEMPTION_CONFIRMED]: RedemptionPayload;
389
+ [LoyaltyEvents.REDEMPTION_RELEASED]: RedemptionPayload;
390
+ [LoyaltyEvents.REDEMPTION_REVERSED]: RedemptionReversedPayload;
391
+ [LoyaltyEvents.CAMPAIGN_AWARDED]: CampaignAwardedPayload;
392
+ [LoyaltyEvents.REFERRAL_RECORDED]: ReferralPayload;
393
+ [LoyaltyEvents.REFERRAL_APPROVED]: ReferralPayload;
394
+ [LoyaltyEvents.REFERRAL_REJECTED]: ReferralPayload;
395
+ [LoyaltyEvents.REFERRAL_REWARDED]: ReferralPayload;
396
+ [LoyaltyEvents.MULTI_TIER_REFERRAL_AWARDED]: MultiTierReferralAwardedPayload;
397
+ }
398
+ type LoyaltyEventPayload<E extends LoyaltyEventName> = LoyaltyEventMap[E];
399
+ //#endregion
400
+ export { PointsExpired as A, ReferralRewarded as B, MemberDeactivated as C, MultiTierReferralAwarded as D, MemberSuspended as E, RedemptionReserved as F, TierUpgraded as G, TierGraceStarted as H, RedemptionReversed as I, InProcessLoyaltyBusOptions as J, loyaltyEventDefinitions as K, ReferralApproved as L, PointsRedeemed as M, RedemptionConfirmed as N, PointsAdjusted as O, RedemptionReleased as P, ReferralRecorded as R, LoyaltyEventSchema as S, MemberReactivated as T, TierOverrideCleared as U, TierDowngraded as V, TierOverrideExpired as W, createEvent$1 as Y, TierChangedPayload as _, LoyaltyEventMap as a, LoyaltyEventDefinition as b, LoyaltyEvents as c, PointsAdjustedPayload as d, PointsEarnedPayload as f, ReferralPayload as g, RedemptionReversedPayload as h, CampaignAwardedPayload as i, PointsExpiringSoon as j, PointsEarned as k, MemberLifecyclePayload as l, RedemptionPayload as m, EventHandler$1 as n, LoyaltyEventName as o, PointsExpiredPayload as p, InProcessLoyaltyBus as q, EventTransport$1 as r, LoyaltyEventPayload as s, DomainEvent$1 as t, MultiTierReferralAwardedPayload as u, TierOverrideLifecyclePayload as v, MemberEnrolled as w, LoyaltyEventPayloadOf as x, CampaignAwarded as y, ReferralRejected as z };
@@ -1,7 +1,7 @@
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-2izQQext.mjs";
3
- import { t as NotificationAdapter } from "./notification.port-9B5xlzxQ.mjs";
4
- import { c as ResolvedTenant, o as RepositoryPlugins, s as ResolvedConfig } from "./config-JYTMP1F7.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-BOWqBSWx.mjs";
3
+ import { t as NotificationAdapter } from "./notification.port-CJ9nXj0k.mjs";
4
+ import { c as ResolvedTenant, o as RepositoryPlugins, s as ResolvedConfig } from "./config-DoZPGBfW.mjs";
5
5
  import { LoyaltyModels } from "./models/index.mjs";
6
6
  import { EventTransport } from "@classytic/primitives/events";
7
7
  import { ClientSession, Model } from "mongoose";
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { A as TierUpgraded, B as PointsEarnedPayload, C as ReferralRecorded, D as TierGraceStarted, E as TierDowngraded, F as LoyaltyEventPayload, G as TierChangedPayload, H as RedemptionPayload, I as LoyaltyEvents, J as InProcessLoyaltyBus, L as MemberLifecyclePayload, N as LoyaltyEventMap, P as LoyaltyEventName, S as ReferralApproved, T as ReferralRewarded, V as PointsExpiredPayload, W as ReferralPayload, Y as InProcessLoyaltyBusOptions, _ as PointsRedeemed, a as LoyaltyEventDefinition, b as RedemptionReserved, c as MemberDeactivated, d as MemberSuspended, g as PointsExpiringSoon, h as PointsExpired, j as loyaltyEventDefinitions, l as MemberEnrolled, m as PointsEarned, o as LoyaltyEventPayloadOf, p as PointsAdjusted, q as createEvent, s as LoyaltyEventSchema, u as MemberReactivated, v as RedemptionConfirmed, w as ReferralRejected, y as RedemptionReleased, z as PointsAdjustedPayload } from "./index-BmqGuj38.mjs";
2
- 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-2izQQext.mjs";
3
- import { t as NotificationAdapter } from "./notification.port-9B5xlzxQ.mjs";
4
- import { c as ResolvedTenant, n as LoyaltyConfig, r as LoyaltyModelName, s as ResolvedConfig } from "./config-JYTMP1F7.mjs";
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-BOWqBSWx.mjs";
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-DoZPGBfW.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-C4jFHS7m.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-qI1WvtNg.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-ClPKmtxh.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,6 +1,6 @@
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-ObGUgcSH.mjs";
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-BjzHSLBn.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-DBSxe9st.mjs";
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
4
  import { n as createModels } from "./models-uhh9c-7k.mjs";
5
5
  import { n as createEvent, t as LoyaltyEvents } from "./loyalty-events-Cyt9TwX6.mjs";
6
6
  //#region src/index.ts
@@ -1,4 +1,4 @@
1
- import { c as ResolvedTenant, i as ModelName, r as LoyaltyModelName, t as IndexDefinition } from "../config-JYTMP1F7.mjs";
1
+ import { c as ResolvedTenant, i as ModelName, r as LoyaltyModelName, t as IndexDefinition } from "../config-DoZPGBfW.mjs";
2
2
  import * as _$mongoose from "mongoose";
3
3
  import { Connection, Model } from "mongoose";
4
4
 
@@ -1,4 +1,4 @@
1
- import { t as NotificationAdapter } from "../notification.port-9B5xlzxQ.mjs";
1
+ import { t as NotificationAdapter } from "../notification.port-CJ9nXj0k.mjs";
2
2
 
3
3
  //#region src/notifications/index.d.ts
4
4
  interface NotificationsAdapterConfig {
@@ -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-qI1WvtNg.mjs";
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-ClPKmtxh.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-ObGUgcSH.mjs";
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-DBSxe9st.mjs";
2
2
  export { EarningRuleRepository, MemberRepository, PointTransactionRepository, RedemptionRepository, ReferralRepository, TierDefinitionRepository, createRepositories };
@@ -153,16 +153,22 @@ function tenantCtx(tenant, tenantId) {
153
153
  * Copy the tenant id from the repo options into the write payload.
154
154
  *
155
155
  * Called from repository `create` / `createMany` overrides so the document
156
- * persists with the correct `organizationId` even when the host has opted
157
- * OUT of the auto-wired `multiTenantPlugin`. When the payload already has
158
- * the field (e.g. arc's `BaseController.create` pre-writes it), this is a
159
- * no-op.
156
+ * persists with the correct tenant id even when the host has opted OUT
157
+ * of the auto-wired `multiTenantPlugin`. The options object is populated
158
+ * by `tenantCtx()` which writes under `tenant.contextKey`, so the read
159
+ * here MUST use `contextKey` — not `tenantField`. They coincide in the
160
+ * default config (`organizationId === organizationId`) which masked the
161
+ * mismatch; with a divergent contextKey the copy silently never fired
162
+ * and writes landed without a tenant on the doc.
163
+ *
164
+ * When the payload already has the field (e.g. arc's `BaseController.create`
165
+ * pre-writes it under `tenantField`), this is a no-op.
160
166
  */
161
167
  function injectTenantIntoData(data, options, tenant) {
162
168
  const field = tenant.tenantField;
163
169
  if (!field) return;
164
170
  if (data[field] != null) return;
165
- const value = options?.[field];
171
+ const value = options?.[tenant.contextKey] ?? options?.[field];
166
172
  if (value != null) data[field] = value;
167
173
  }
168
174
  //#endregion
@@ -340,14 +346,10 @@ async function dispatchLoyaltyEvent(deps, event, ctx) {
340
346
  const saveOptions = {};
341
347
  if (ctx.session !== void 0) saveOptions.session = ctx.session;
342
348
  await deps.outbox.save(event, saveOptions);
343
- } catch (err) {
344
- console.error(`[loyalty] outbox.save failed for ${event.type}:`, err);
345
- }
349
+ } catch (_err) {}
346
350
  if (deps.events) try {
347
351
  await deps.events.publish(event);
348
- } catch (err) {
349
- console.error(`[loyalty] events.publish failed for ${event.type}:`, err);
350
- }
352
+ } catch (_err) {}
351
353
  }
352
354
  //#endregion
353
355
  //#region src/utils/code-generator.ts
@@ -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-2izQQext.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-JYTMP1F7.mjs";
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-BOWqBSWx.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-DoZPGBfW.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.0",
3
+ "version": "0.2.1",
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",
@@ -73,7 +73,9 @@
73
73
  "format": "biome format --write src/ tests/",
74
74
  "check": "biome check --write --unsafe src/ tests/",
75
75
  "prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build",
76
- "release": "npm run build && npm run typecheck && npm publish --access public"
76
+ "push": "classytic-push",
77
+ "release:tag": "node -e \"require('child_process').execSync('npm run push -- v'+require('./package.json').version,{stdio:'inherit'})\"",
78
+ "release": "npm run push -- main && npm run release:tag && npm publish"
77
79
  },
78
80
  "peerDependencies": {
79
81
  "@classytic/mongokit": ">=3.11.0",
@@ -84,6 +86,7 @@
84
86
  },
85
87
  "devDependencies": {
86
88
  "@biomejs/biome": "^2.4.9",
89
+ "@classytic/dev-tools": "^0.2.0",
87
90
  "@classytic/mongokit": ">=3.11.0",
88
91
  "@classytic/primitives": ">=0.1.0",
89
92
  "@classytic/repo-core": ">=0.2.0",