@stamprally/core 0.2.1 → 0.4.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.cjs CHANGED
@@ -260,11 +260,27 @@ function hash(value) {
260
260
  }
261
261
  return result.toString(36).toUpperCase().padStart(7, "0");
262
262
  }
263
+ function createRandomHash() {
264
+ const cryptoApi2 = globalThis.crypto;
265
+ if (cryptoApi2 !== void 0 && typeof cryptoApi2.getRandomValues === "function") {
266
+ const values = new Uint32Array(2);
267
+ cryptoApi2.getRandomValues(values);
268
+ return Array.from(values, (value) => value.toString(36).toUpperCase().padStart(7, "0")).join(
269
+ ""
270
+ );
271
+ }
272
+ return `${Date.now().toString(36).toUpperCase()}${Math.random().toString(36).slice(2).toUpperCase()}`;
273
+ }
263
274
  function createClaimTicketNumber(rewardId, options = {}) {
264
275
  const issuedAt = options.issuedAt ?? "";
265
276
  const sequence = options.sequence ?? 0;
266
277
  return `SR-${hash(`${rewardId}|${issuedAt}|${sequence}`)}`;
267
278
  }
279
+ function createUniqueClaimTicketNumber(rewardId, issuedAt) {
280
+ const timestamp = Date.parse(issuedAt);
281
+ const timestampPart = Number.isNaN(timestamp) ? Date.now() : timestamp;
282
+ return `CLAIM-${rewardId}-${timestampPart}-${createRandomHash()}`;
283
+ }
268
284
  function issueClaimTicketNumber(reward, currentState, options = {}) {
269
285
  if (currentState.claimTicketNumber !== void 0) return currentState;
270
286
  const claimTicketNumber = reward.claimTicketNumber ?? createClaimTicketNumber(reward.id, options);
@@ -652,13 +668,16 @@ function consumeReward(params) {
652
668
  };
653
669
  }
654
670
  if (reward.validUntil !== void 0 && Date.parse(reward.validUntil) <= Date.parse(params.now)) {
655
- return { ok: false, error: { code: "EXPIRED", rewardId: reward.id } };
671
+ return { ok: false, error: { code: "EXPIRED", reason: "EXPIRED", rewardId: reward.id } };
656
672
  }
657
673
  if (reward.maxStock !== void 0 && (currentState.redeemedCount ?? 0) >= reward.maxStock) {
658
674
  return { ok: false, error: { code: "OUT_OF_STOCK", rewardId: reward.id } };
659
675
  }
660
676
  if (reward.limitPerUser !== void 0 && (params.userRedemptionCount ?? currentState.userRedemptionCount ?? 0) >= reward.limitPerUser) {
661
- return { ok: false, error: { code: "USER_LIMIT_REACHED", rewardId: reward.id } };
677
+ return {
678
+ ok: false,
679
+ error: { code: "USER_LIMIT_REACHED", reason: "LIMIT_EXCEEDED", rewardId: reward.id }
680
+ };
662
681
  }
663
682
  if (reward.redemptionMethod === "staff_passcode") {
664
683
  const passcodeResult = reward.staffPasscode === void 0 ? null : verifyPasscode(params.inputPasscode ?? "", { passcode: reward.staffPasscode });
@@ -682,6 +701,7 @@ function consumeReward(params) {
682
701
  ...currentState,
683
702
  status: "CONSUMED",
684
703
  consumedAt: params.now,
704
+ claimTicketNumber: createUniqueClaimTicketNumber(reward.id, params.now),
685
705
  ...reward.maxStock !== void 0 || params.userId !== void 0 || params.userRedemptionCount !== void 0 ? { redeemedCount: (currentState.redeemedCount ?? 0) + 1 } : {},
686
706
  ...params.userId === void 0 ? {} : { userRedemptionCount: (currentState.userRedemptionCount ?? 0) + 1 },
687
707
  ...params.staffId === void 0 ? {} : { consumedByStaffId: params.staffId }
@@ -1926,6 +1946,7 @@ exports.calculateProgress = calculateProgress;
1926
1946
  exports.consumeReward = consumeReward;
1927
1947
  exports.createClaimTicketNumber = createClaimTicketNumber;
1928
1948
  exports.createSignedSnapshotToken = createSignedSnapshotToken;
1949
+ exports.createUniqueClaimTicketNumber = createUniqueClaimTicketNumber;
1929
1950
  exports.evaluateCheckIn = evaluateCheckIn;
1930
1951
  exports.evaluateCondition = evaluateCondition;
1931
1952
  exports.evaluateConditionDetailed = evaluateConditionDetailed;