@withwiz/coupon 0.1.0 → 0.3.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/dist/index.d.cts CHANGED
@@ -68,6 +68,24 @@ declare const LIMITS: {
68
68
  readonly PAGINATION_MAX_LIMIT: 200;
69
69
  readonly NAME_MAX_LENGTH: 200;
70
70
  readonly CURRENCY_LENGTH: 3;
71
+ /**
72
+ * [L] Caller-supplied identifier caps. Ids (coupon / campaign / cursor) are
73
+ * bounded by the audit log's `resourceId VarChar(64)`; `orderRef` by the
74
+ * redemption table's `VarChar(128)`. User / actor ids share the same bound
75
+ * so an unbounded string can never reach a Json or text column unchecked.
76
+ */
77
+ readonly ID_MAX_LENGTH: 64;
78
+ readonly USER_ID_MAX_LENGTH: 128;
79
+ readonly ORDER_REF_MAX_LENGTH: 128;
80
+ /** [L] Upper bound on serialized `metadata` (bytes of JSON text). */
81
+ readonly METADATA_MAX_BYTES: 16384;
82
+ /** [L] Per-list entry cap and per-entry length cap for eligibility rules. */
83
+ readonly ELIGIBILITY_MAX_ENTRIES: 1000;
84
+ readonly ELIGIBILITY_ENTRY_MAX_LENGTH: 128;
85
+ /** [L] Length cap for `context.plan / productId / categoryId`. */
86
+ readonly CONTEXT_VALUE_MAX_LENGTH: 128;
87
+ /** Upper bound for `duration.months` on a REPEATING discount. */
88
+ readonly DURATION_MAX_MONTHS: 36;
71
89
  };
72
90
  /**
73
91
  * Audit log action strings (stable identifiers).
@@ -91,17 +109,32 @@ type AuditAction = (typeof AUDIT_ACTION)[keyof typeof AUDIT_ACTION];
91
109
  * No Prisma generated types imported here (see contract §10 PrismaLike rule).
92
110
  */
93
111
 
112
+ /**
113
+ * How many billing cycles a discount applies to. Absent = ONCE.
114
+ * The package records it; applying it to recurring charges is the consumer's job
115
+ * (re-run `calculateDiscount` per cycle with the stored policy).
116
+ */
117
+ type DiscountDuration = {
118
+ kind: "ONCE";
119
+ } | {
120
+ kind: "REPEATING";
121
+ months: number;
122
+ } | {
123
+ kind: "FOREVER";
124
+ };
94
125
  type DiscountPolicy = {
95
126
  kind: "PERCENT";
96
127
  percent: number;
97
128
  maxDiscount?: number;
98
129
  minOrder?: number;
99
130
  currency?: string;
131
+ duration?: DiscountDuration;
100
132
  } | {
101
133
  kind: "FIXED";
102
134
  amount: number;
103
135
  currency: string;
104
136
  minOrder?: number;
137
+ duration?: DiscountDuration;
105
138
  };
106
139
  type EligibilityRules = {
107
140
  allowedUserIds?: string[];
@@ -325,6 +358,13 @@ type CampaignIssueArgs = {
325
358
  codeLength?: number;
326
359
  maxAttempts?: number;
327
360
  actorId?: string;
361
+ /**
362
+ * Redemption limits stamped on each issued code. Unset = unlimited, which
363
+ * is rarely what a batch of unique codes wants: pass `maxRedemptions: 1`
364
+ * for single-use codes.
365
+ */
366
+ maxRedemptions?: number | null;
367
+ maxRedemptionsPerUser?: number | null;
328
368
  };
329
369
  type CampaignSummary = {
330
370
  id: string;
@@ -557,6 +597,15 @@ type CouponClientConfig = {
557
597
  * @example { coupon: "coupons" }
558
598
  */
559
599
  tables?: Partial<TableNameMap>;
600
+ /**
601
+ * Postgres schema that holds the coupon tables, used to qualify the
602
+ * `SELECT ... FOR UPDATE` row lock. Needed when the tables live outside
603
+ * `public` and the client uses a driver adapter (Prisma 7), whose raw
604
+ * queries resolve unqualified names through the connection's `search_path`.
605
+ *
606
+ * @example "billing"
607
+ */
608
+ schema?: string;
560
609
  };
561
610
  interface CouponClient {
562
611
  coupons: {
@@ -638,6 +687,8 @@ declare function validateDiscountPolicy(policy: DiscountPolicy): void;
638
687
  * Throws MinimumOrderNotMetError if subtotal < policy.minOrder.
639
688
  */
640
689
  declare function calculate(input: DiscountInput): DiscountBreakdown;
690
+ /** The effective duration of a policy. Policies without one apply ONCE. */
691
+ declare function resolveDuration(policy: DiscountPolicy): DiscountDuration;
641
692
 
642
693
  /**
643
694
  * Error taxonomy for @withwiz/coupon.
@@ -752,4 +803,4 @@ declare class TenantMismatchError extends CouponError {
752
803
  constructor(message?: string, ctx?: CouponErrorContext);
753
804
  }
754
805
 
755
- export { AUDIT_ACTION, type AuditAction, type AuditLog, type BulkIssuanceResult, CAMPAIGN_STATUS, COUPON_REJECT_REASON, COUPON_STATUS, type Campaign, CampaignCapacityExceededError, CampaignClosedError, type CampaignIssueArgs, type CampaignStatus, type CampaignSummary, type Coupon, CouponAlreadyRedeemedError, CouponArchivedError, type CouponClient, type CouponClientConfig, CouponError, type CouponEvent, type CouponEventHandler, CouponExhaustedError, CouponExpiredError, CouponInactiveError, type CouponLogger, type CouponModelKey, CouponNotFoundError, type CouponRejectReason, type CouponStatus, type CreateCampaignInput, type CreateCouponInput, CurrencyMismatchError, DEFAULT_MODEL_NAMES, type DiscountBreakdown, type DiscountInput, type DiscountPolicy, type EligibilityRules, IneligibleCategoryError, IneligiblePlanError, IneligibleProductError, IneligibleUserError, InvalidDateRangeError, InvalidDiscountPolicyError, InvalidModelNameError, type Issuance, type IssueBulkInput, type IssueCouponInput, LIMITS, type ListAuditLogsArgs, type ListCampaignsArgs, type ListCouponsArgs, type ListIssuancesArgs, type ListRedemptionsArgs, MinimumOrderNotMetError, type ModelNameMap, type Paged, PerUserLimitExceededError, type PrismaLike, type PrismaTxLike, type RedeemInput, type Redemption, type RedemptionResult, type TableNameMap, TenantMismatchError, type ValidateContext, type ValidateInput, ValidationError, type ValidationResult, calculate as calculateDiscount, createCouponClient, validateDiscountPolicy };
806
+ export { AUDIT_ACTION, type AuditAction, type AuditLog, type BulkIssuanceResult, CAMPAIGN_STATUS, COUPON_REJECT_REASON, COUPON_STATUS, type Campaign, CampaignCapacityExceededError, CampaignClosedError, type CampaignIssueArgs, type CampaignStatus, type CampaignSummary, type Coupon, CouponAlreadyRedeemedError, CouponArchivedError, type CouponClient, type CouponClientConfig, CouponError, type CouponEvent, type CouponEventHandler, CouponExhaustedError, CouponExpiredError, CouponInactiveError, type CouponLogger, type CouponModelKey, CouponNotFoundError, type CouponRejectReason, type CouponStatus, type CreateCampaignInput, type CreateCouponInput, CurrencyMismatchError, DEFAULT_MODEL_NAMES, type DiscountBreakdown, type DiscountDuration, type DiscountInput, type DiscountPolicy, type EligibilityRules, IneligibleCategoryError, IneligiblePlanError, IneligibleProductError, IneligibleUserError, InvalidDateRangeError, InvalidDiscountPolicyError, InvalidModelNameError, type Issuance, type IssueBulkInput, type IssueCouponInput, LIMITS, type ListAuditLogsArgs, type ListCampaignsArgs, type ListCouponsArgs, type ListIssuancesArgs, type ListRedemptionsArgs, MinimumOrderNotMetError, type ModelNameMap, type Paged, PerUserLimitExceededError, type PrismaLike, type PrismaTxLike, type RedeemInput, type Redemption, type RedemptionResult, type TableNameMap, TenantMismatchError, type ValidateContext, type ValidateInput, ValidationError, type ValidationResult, calculate as calculateDiscount, createCouponClient, resolveDuration, validateDiscountPolicy };
package/dist/index.d.ts CHANGED
@@ -68,6 +68,24 @@ declare const LIMITS: {
68
68
  readonly PAGINATION_MAX_LIMIT: 200;
69
69
  readonly NAME_MAX_LENGTH: 200;
70
70
  readonly CURRENCY_LENGTH: 3;
71
+ /**
72
+ * [L] Caller-supplied identifier caps. Ids (coupon / campaign / cursor) are
73
+ * bounded by the audit log's `resourceId VarChar(64)`; `orderRef` by the
74
+ * redemption table's `VarChar(128)`. User / actor ids share the same bound
75
+ * so an unbounded string can never reach a Json or text column unchecked.
76
+ */
77
+ readonly ID_MAX_LENGTH: 64;
78
+ readonly USER_ID_MAX_LENGTH: 128;
79
+ readonly ORDER_REF_MAX_LENGTH: 128;
80
+ /** [L] Upper bound on serialized `metadata` (bytes of JSON text). */
81
+ readonly METADATA_MAX_BYTES: 16384;
82
+ /** [L] Per-list entry cap and per-entry length cap for eligibility rules. */
83
+ readonly ELIGIBILITY_MAX_ENTRIES: 1000;
84
+ readonly ELIGIBILITY_ENTRY_MAX_LENGTH: 128;
85
+ /** [L] Length cap for `context.plan / productId / categoryId`. */
86
+ readonly CONTEXT_VALUE_MAX_LENGTH: 128;
87
+ /** Upper bound for `duration.months` on a REPEATING discount. */
88
+ readonly DURATION_MAX_MONTHS: 36;
71
89
  };
72
90
  /**
73
91
  * Audit log action strings (stable identifiers).
@@ -91,17 +109,32 @@ type AuditAction = (typeof AUDIT_ACTION)[keyof typeof AUDIT_ACTION];
91
109
  * No Prisma generated types imported here (see contract §10 PrismaLike rule).
92
110
  */
93
111
 
112
+ /**
113
+ * How many billing cycles a discount applies to. Absent = ONCE.
114
+ * The package records it; applying it to recurring charges is the consumer's job
115
+ * (re-run `calculateDiscount` per cycle with the stored policy).
116
+ */
117
+ type DiscountDuration = {
118
+ kind: "ONCE";
119
+ } | {
120
+ kind: "REPEATING";
121
+ months: number;
122
+ } | {
123
+ kind: "FOREVER";
124
+ };
94
125
  type DiscountPolicy = {
95
126
  kind: "PERCENT";
96
127
  percent: number;
97
128
  maxDiscount?: number;
98
129
  minOrder?: number;
99
130
  currency?: string;
131
+ duration?: DiscountDuration;
100
132
  } | {
101
133
  kind: "FIXED";
102
134
  amount: number;
103
135
  currency: string;
104
136
  minOrder?: number;
137
+ duration?: DiscountDuration;
105
138
  };
106
139
  type EligibilityRules = {
107
140
  allowedUserIds?: string[];
@@ -325,6 +358,13 @@ type CampaignIssueArgs = {
325
358
  codeLength?: number;
326
359
  maxAttempts?: number;
327
360
  actorId?: string;
361
+ /**
362
+ * Redemption limits stamped on each issued code. Unset = unlimited, which
363
+ * is rarely what a batch of unique codes wants: pass `maxRedemptions: 1`
364
+ * for single-use codes.
365
+ */
366
+ maxRedemptions?: number | null;
367
+ maxRedemptionsPerUser?: number | null;
328
368
  };
329
369
  type CampaignSummary = {
330
370
  id: string;
@@ -557,6 +597,15 @@ type CouponClientConfig = {
557
597
  * @example { coupon: "coupons" }
558
598
  */
559
599
  tables?: Partial<TableNameMap>;
600
+ /**
601
+ * Postgres schema that holds the coupon tables, used to qualify the
602
+ * `SELECT ... FOR UPDATE` row lock. Needed when the tables live outside
603
+ * `public` and the client uses a driver adapter (Prisma 7), whose raw
604
+ * queries resolve unqualified names through the connection's `search_path`.
605
+ *
606
+ * @example "billing"
607
+ */
608
+ schema?: string;
560
609
  };
561
610
  interface CouponClient {
562
611
  coupons: {
@@ -638,6 +687,8 @@ declare function validateDiscountPolicy(policy: DiscountPolicy): void;
638
687
  * Throws MinimumOrderNotMetError if subtotal < policy.minOrder.
639
688
  */
640
689
  declare function calculate(input: DiscountInput): DiscountBreakdown;
690
+ /** The effective duration of a policy. Policies without one apply ONCE. */
691
+ declare function resolveDuration(policy: DiscountPolicy): DiscountDuration;
641
692
 
642
693
  /**
643
694
  * Error taxonomy for @withwiz/coupon.
@@ -752,4 +803,4 @@ declare class TenantMismatchError extends CouponError {
752
803
  constructor(message?: string, ctx?: CouponErrorContext);
753
804
  }
754
805
 
755
- export { AUDIT_ACTION, type AuditAction, type AuditLog, type BulkIssuanceResult, CAMPAIGN_STATUS, COUPON_REJECT_REASON, COUPON_STATUS, type Campaign, CampaignCapacityExceededError, CampaignClosedError, type CampaignIssueArgs, type CampaignStatus, type CampaignSummary, type Coupon, CouponAlreadyRedeemedError, CouponArchivedError, type CouponClient, type CouponClientConfig, CouponError, type CouponEvent, type CouponEventHandler, CouponExhaustedError, CouponExpiredError, CouponInactiveError, type CouponLogger, type CouponModelKey, CouponNotFoundError, type CouponRejectReason, type CouponStatus, type CreateCampaignInput, type CreateCouponInput, CurrencyMismatchError, DEFAULT_MODEL_NAMES, type DiscountBreakdown, type DiscountInput, type DiscountPolicy, type EligibilityRules, IneligibleCategoryError, IneligiblePlanError, IneligibleProductError, IneligibleUserError, InvalidDateRangeError, InvalidDiscountPolicyError, InvalidModelNameError, type Issuance, type IssueBulkInput, type IssueCouponInput, LIMITS, type ListAuditLogsArgs, type ListCampaignsArgs, type ListCouponsArgs, type ListIssuancesArgs, type ListRedemptionsArgs, MinimumOrderNotMetError, type ModelNameMap, type Paged, PerUserLimitExceededError, type PrismaLike, type PrismaTxLike, type RedeemInput, type Redemption, type RedemptionResult, type TableNameMap, TenantMismatchError, type ValidateContext, type ValidateInput, ValidationError, type ValidationResult, calculate as calculateDiscount, createCouponClient, validateDiscountPolicy };
806
+ export { AUDIT_ACTION, type AuditAction, type AuditLog, type BulkIssuanceResult, CAMPAIGN_STATUS, COUPON_REJECT_REASON, COUPON_STATUS, type Campaign, CampaignCapacityExceededError, CampaignClosedError, type CampaignIssueArgs, type CampaignStatus, type CampaignSummary, type Coupon, CouponAlreadyRedeemedError, CouponArchivedError, type CouponClient, type CouponClientConfig, CouponError, type CouponEvent, type CouponEventHandler, CouponExhaustedError, CouponExpiredError, CouponInactiveError, type CouponLogger, type CouponModelKey, CouponNotFoundError, type CouponRejectReason, type CouponStatus, type CreateCampaignInput, type CreateCouponInput, CurrencyMismatchError, DEFAULT_MODEL_NAMES, type DiscountBreakdown, type DiscountDuration, type DiscountInput, type DiscountPolicy, type EligibilityRules, IneligibleCategoryError, IneligiblePlanError, IneligibleProductError, IneligibleUserError, InvalidDateRangeError, InvalidDiscountPolicyError, InvalidModelNameError, type Issuance, type IssueBulkInput, type IssueCouponInput, LIMITS, type ListAuditLogsArgs, type ListCampaignsArgs, type ListCouponsArgs, type ListIssuancesArgs, type ListRedemptionsArgs, MinimumOrderNotMetError, type ModelNameMap, type Paged, PerUserLimitExceededError, type PrismaLike, type PrismaTxLike, type RedeemInput, type Redemption, type RedemptionResult, type TableNameMap, TenantMismatchError, type ValidateContext, type ValidateInput, ValidationError, type ValidationResult, calculate as calculateDiscount, createCouponClient, resolveDuration, validateDiscountPolicy };