@stamprally/core 0.3.0 → 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.d.cts CHANGED
@@ -279,6 +279,8 @@ interface ClaimTicketOptions {
279
279
  readonly sequence?: number;
280
280
  }
281
281
  declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicketOptions): string;
282
+ /** Creates a one-time ticket for a successful reward consumption. */
283
+ declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
282
284
  declare function issueClaimTicketNumber(reward: RewardItem, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
283
285
 
284
286
  type StampRallyEvent = {
@@ -309,12 +311,14 @@ type RewardConsumeError = {
309
311
  readonly message: string;
310
312
  } | {
311
313
  readonly code: "EXPIRED";
314
+ readonly reason: "EXPIRED";
312
315
  readonly rewardId: string;
313
316
  } | {
314
317
  readonly code: "OUT_OF_STOCK";
315
318
  readonly rewardId: string;
316
319
  } | {
317
320
  readonly code: "USER_LIMIT_REACHED";
321
+ readonly reason: "LIMIT_EXCEEDED";
318
322
  readonly rewardId: string;
319
323
  } | {
320
324
  readonly code: "REWARD_NOT_FOUND";
@@ -489,4 +493,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
489
493
  declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
490
494
  declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
491
495
 
492
- export { CURRENT_RALLY_CONFIG_VERSION, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, type PublicRewardItem, type QrDetectorOptions, type RallyConfig, type RallyConfigValidationResult, type RallySnapshot, type RedemptionMethod, type Result, type RewardConsumeError, type RewardItem, type RewardState, type RewardStatus, type RewardType, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type StampCondition, type StampDefinition, type StampError, StampRallyClient, type StampRallyEvent, type StampRallyListener, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, THEME_PRESETS, type ThemePreset, type ThemePresetId, type TokenVerificationContext, type ValidationError, type VerificationContext, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSignedSnapshotToken, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySnapshotToken };
496
+ export { CURRENT_RALLY_CONFIG_VERSION, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, type PublicRewardItem, type QrDetectorOptions, type RallyConfig, type RallyConfigValidationResult, type RallySnapshot, type RedemptionMethod, type Result, type RewardConsumeError, type RewardItem, type RewardState, type RewardStatus, type RewardType, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type StampCondition, type StampDefinition, type StampError, StampRallyClient, type StampRallyEvent, type StampRallyListener, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, THEME_PRESETS, type ThemePreset, type ThemePresetId, type TokenVerificationContext, type ValidationError, type VerificationContext, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySnapshotToken };
package/dist/index.d.ts CHANGED
@@ -279,6 +279,8 @@ interface ClaimTicketOptions {
279
279
  readonly sequence?: number;
280
280
  }
281
281
  declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicketOptions): string;
282
+ /** Creates a one-time ticket for a successful reward consumption. */
283
+ declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
282
284
  declare function issueClaimTicketNumber(reward: RewardItem, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
283
285
 
284
286
  type StampRallyEvent = {
@@ -309,12 +311,14 @@ type RewardConsumeError = {
309
311
  readonly message: string;
310
312
  } | {
311
313
  readonly code: "EXPIRED";
314
+ readonly reason: "EXPIRED";
312
315
  readonly rewardId: string;
313
316
  } | {
314
317
  readonly code: "OUT_OF_STOCK";
315
318
  readonly rewardId: string;
316
319
  } | {
317
320
  readonly code: "USER_LIMIT_REACHED";
321
+ readonly reason: "LIMIT_EXCEEDED";
318
322
  readonly rewardId: string;
319
323
  } | {
320
324
  readonly code: "REWARD_NOT_FOUND";
@@ -489,4 +493,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
489
493
  declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
490
494
  declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
491
495
 
492
- export { CURRENT_RALLY_CONFIG_VERSION, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, type PublicRewardItem, type QrDetectorOptions, type RallyConfig, type RallyConfigValidationResult, type RallySnapshot, type RedemptionMethod, type Result, type RewardConsumeError, type RewardItem, type RewardState, type RewardStatus, type RewardType, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type StampCondition, type StampDefinition, type StampError, StampRallyClient, type StampRallyEvent, type StampRallyListener, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, THEME_PRESETS, type ThemePreset, type ThemePresetId, type TokenVerificationContext, type ValidationError, type VerificationContext, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSignedSnapshotToken, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySnapshotToken };
496
+ export { CURRENT_RALLY_CONFIG_VERSION, type CheckInContext, type CheckInErrorCode, type CheckInInput, type CheckInResult$1 as CheckInResult, type ClaimTicketOptions, type Clock, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, type ConsumeResult, type ConsumeRewardParams, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type PasscodeCondition, type ProcessStampValue, type PublicRallyConfig, type PublicRewardItem, type QrDetectorOptions, type RallyConfig, type RallyConfigValidationResult, type RallySnapshot, type RedemptionMethod, type Result, type RewardConsumeError, type RewardItem, type RewardState, type RewardStatus, type RewardType, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type StampCondition, type StampDefinition, type StampError, StampRallyClient, type StampRallyEvent, type StampRallyListener, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, THEME_PRESETS, type ThemePreset, type ThemePresetId, type TokenVerificationContext, type ValidationError, type VerificationContext, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySnapshotToken };
package/dist/index.js CHANGED
@@ -258,11 +258,27 @@ function hash(value) {
258
258
  }
259
259
  return result.toString(36).toUpperCase().padStart(7, "0");
260
260
  }
261
+ function createRandomHash() {
262
+ const cryptoApi2 = globalThis.crypto;
263
+ if (cryptoApi2 !== void 0 && typeof cryptoApi2.getRandomValues === "function") {
264
+ const values = new Uint32Array(2);
265
+ cryptoApi2.getRandomValues(values);
266
+ return Array.from(values, (value) => value.toString(36).toUpperCase().padStart(7, "0")).join(
267
+ ""
268
+ );
269
+ }
270
+ return `${Date.now().toString(36).toUpperCase()}${Math.random().toString(36).slice(2).toUpperCase()}`;
271
+ }
261
272
  function createClaimTicketNumber(rewardId, options = {}) {
262
273
  const issuedAt = options.issuedAt ?? "";
263
274
  const sequence = options.sequence ?? 0;
264
275
  return `SR-${hash(`${rewardId}|${issuedAt}|${sequence}`)}`;
265
276
  }
277
+ function createUniqueClaimTicketNumber(rewardId, issuedAt) {
278
+ const timestamp = Date.parse(issuedAt);
279
+ const timestampPart = Number.isNaN(timestamp) ? Date.now() : timestamp;
280
+ return `CLAIM-${rewardId}-${timestampPart}-${createRandomHash()}`;
281
+ }
266
282
  function issueClaimTicketNumber(reward, currentState, options = {}) {
267
283
  if (currentState.claimTicketNumber !== void 0) return currentState;
268
284
  const claimTicketNumber = reward.claimTicketNumber ?? createClaimTicketNumber(reward.id, options);
@@ -650,13 +666,16 @@ function consumeReward(params) {
650
666
  };
651
667
  }
652
668
  if (reward.validUntil !== void 0 && Date.parse(reward.validUntil) <= Date.parse(params.now)) {
653
- return { ok: false, error: { code: "EXPIRED", rewardId: reward.id } };
669
+ return { ok: false, error: { code: "EXPIRED", reason: "EXPIRED", rewardId: reward.id } };
654
670
  }
655
671
  if (reward.maxStock !== void 0 && (currentState.redeemedCount ?? 0) >= reward.maxStock) {
656
672
  return { ok: false, error: { code: "OUT_OF_STOCK", rewardId: reward.id } };
657
673
  }
658
674
  if (reward.limitPerUser !== void 0 && (params.userRedemptionCount ?? currentState.userRedemptionCount ?? 0) >= reward.limitPerUser) {
659
- return { ok: false, error: { code: "USER_LIMIT_REACHED", rewardId: reward.id } };
675
+ return {
676
+ ok: false,
677
+ error: { code: "USER_LIMIT_REACHED", reason: "LIMIT_EXCEEDED", rewardId: reward.id }
678
+ };
660
679
  }
661
680
  if (reward.redemptionMethod === "staff_passcode") {
662
681
  const passcodeResult = reward.staffPasscode === void 0 ? null : verifyPasscode(params.inputPasscode ?? "", { passcode: reward.staffPasscode });
@@ -680,6 +699,7 @@ function consumeReward(params) {
680
699
  ...currentState,
681
700
  status: "CONSUMED",
682
701
  consumedAt: params.now,
702
+ claimTicketNumber: createUniqueClaimTicketNumber(reward.id, params.now),
683
703
  ...reward.maxStock !== void 0 || params.userId !== void 0 || params.userRedemptionCount !== void 0 ? { redeemedCount: (currentState.redeemedCount ?? 0) + 1 } : {},
684
704
  ...params.userId === void 0 ? {} : { userRedemptionCount: (currentState.userRedemptionCount ?? 0) + 1 },
685
705
  ...params.staffId === void 0 ? {} : { consumedByStaffId: params.staffId }
@@ -1911,6 +1931,6 @@ async function verifySnapshotToken(token, secretKey, now = Date.now()) {
1911
1931
  }
1912
1932
  }
1913
1933
 
1914
- export { CURRENT_RALLY_CONFIG_VERSION, DEFAULT_SHEET_THEME, InMemoryStorage, IndexedDBAdapter, LocalStorageAdapter, StampRallyClient, StorageAdapterError, THEME_PRESETS, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSignedSnapshotToken, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySnapshotToken };
1934
+ export { CURRENT_RALLY_CONFIG_VERSION, DEFAULT_SHEET_THEME, InMemoryStorage, IndexedDBAdapter, LocalStorageAdapter, StampRallyClient, StorageAdapterError, THEME_PRESETS, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCheckIn, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, importProgressToken, isGeolocationSupported, isNfcSupported, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, migrateRallyConfig, normalizePasscode, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, stripSensitiveConfig, toLocalizedString, validateRallyConfig, verifyPasscode, verifySnapshotToken };
1915
1935
  //# sourceMappingURL=index.js.map
1916
1936
  //# sourceMappingURL=index.js.map