@stamprally/core 0.17.0 → 0.19.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
@@ -99,7 +99,6 @@ type RedemptionMethod = "manual_slide" | "staff_passcode" | "view_only" | "serve
99
99
  type InventoryAggregationMode = "shared" | "per_reward";
100
100
  type RallyInventory = Readonly<Record<string, number>> & {
101
101
  readonly sharedStock?: number;
102
- readonly global?: number;
103
102
  };
104
103
  interface RallyInventoryState {
105
104
  readonly sharedRemaining?: number;
@@ -118,6 +117,10 @@ interface Reward<TLocale extends string = string> {
118
117
  readonly validUntil?: string;
119
118
  readonly stockLimit?: number;
120
119
  readonly userClaimLimit?: number;
120
+ /** Explicit primary inventory key. Defaults to the reward id. */
121
+ readonly stockKey?: string;
122
+ /** Optional second inventory bucket that must be decremented atomically. */
123
+ readonly secondaryStockKey?: string;
121
124
  }
122
125
  type PublicReward<TLocale extends string = string> = Omit<Reward<TLocale>, "digitalContentUrl" | "staffPasscode">;
123
126
  interface AdminRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
@@ -333,13 +336,9 @@ declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicket
333
336
  declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
334
337
  declare function issueClaimTicketNumber(reward: Reward, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
335
338
 
336
- type ConflictResolutionPolicy = "authoritative_replay" | "server_wins" | "merge";
337
- interface MergeConflictOptions {
338
- /** `merge` is retained for compatibility; synchronization paths use `authoritative_replay`. */
339
- readonly policy: ConflictResolutionPolicy;
340
- }
341
- /** Resolves a server/local state conflict without mutating either input state. */
342
- declare function resolveRallyStateConflict(serverState: UserRallyState, localState: UserRallyState, options?: MergeConflictOptions): UserRallyState;
339
+ type ConflictResolutionPolicy = "authoritative_replay";
340
+ /** Uses the server snapshot as the immutable replay baseline. */
341
+ declare function resolveRallyStateConflict(serverState: UserRallyState, _localState: UserRallyState): UserRallyState;
343
342
 
344
343
  type RewardConsumeError = {
345
344
  readonly code: "NOT_AVAILABLE" | "ALREADY_CONSUMED" | "OUT_OF_STOCK" | "REWARD_NOT_FOUND";
@@ -377,20 +376,23 @@ declare function processStamp(state: StampRallyState, config: AdminRallyConfig,
377
376
 
378
377
  type QueueOperationStatus = "PENDING" | "IN_FLIGHT" | "ACCEPTED" | "REJECTED_PERMANENT" | "FAILED_RETRYABLE";
379
378
  type OfflineQueueCapability = "indexeddb" | "localstorage" | "memory" | "custom";
379
+ type OfflineStorageCapability = OfflineQueueCapability | "volatile_single_tab";
380
380
  type OfflineOperation = {
381
381
  readonly kind: "checkIn";
382
382
  readonly request: CheckInRequest;
383
+ readonly optimisticState?: UserRallyState;
383
384
  readonly status?: QueueOperationStatus;
384
385
  readonly attempts?: number;
385
386
  } | {
386
387
  readonly kind: "claimReward";
387
388
  readonly request: ClaimRequest;
389
+ readonly optimisticState?: UserRallyState;
388
390
  readonly status?: QueueOperationStatus;
389
391
  readonly attempts?: number;
390
392
  };
391
393
  type OfflineResult = CheckInResult | ClaimResult | UserRallyState;
392
394
  type SyncState = "idle" | "syncing" | "error";
393
- type SyncConflictPolicy = ConflictResolutionPolicy;
395
+ type SyncConflictPolicy = "authoritative_replay";
394
396
  interface OfflineConflictResult {
395
397
  readonly conflict: true;
396
398
  readonly localState: UserRallyState;
@@ -402,6 +404,12 @@ interface OfflineQueueStorage {
402
404
  loadRejectedHistory?(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
403
405
  saveRejectedHistory?(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
404
406
  }
407
+ interface OfflineQueueCapabilityWarning {
408
+ readonly type: "STORAGE_CAPABILITY_WARNING";
409
+ readonly storageCapability: "volatile_single_tab" | "memory";
410
+ readonly isStoragePersistent: boolean;
411
+ readonly message: string;
412
+ }
405
413
  interface OfflineQueueOptions {
406
414
  readonly storage?: OfflineQueueStorage;
407
415
  readonly storageLike?: {
@@ -415,8 +423,6 @@ interface OfflineQueueOptions {
415
423
  /** User scope used by the default durable key. */
416
424
  readonly userId?: string | null;
417
425
  readonly databaseName?: string;
418
- readonly conflictPolicy?: SyncConflictPolicy;
419
- readonly onSyncConflict?: SyncConflictPolicy | ((context: OfflineConflict) => SyncConflictPolicy | Promise<SyncConflictPolicy>);
420
426
  /** Enables storage-event/BroadcastChannel synchronization when browser APIs exist. */
421
427
  readonly synchronizeInstances?: boolean;
422
428
  readonly retryOptions?: SyncRetryOptions;
@@ -429,11 +435,6 @@ interface SyncRetryOptions {
429
435
  readonly initialIntervalMs?: number;
430
436
  readonly backoffMultiplier?: number;
431
437
  }
432
- interface OfflineConflict {
433
- readonly operation: OfflineOperation;
434
- readonly localState: UserRallyState;
435
- readonly serverState: UserRallyState;
436
- }
437
438
  type OfflineSender = (operation: OfflineOperation) => Promise<OfflineResult | OfflineConflictResult | OfflineOperationResponse>;
438
439
  type OfflineOperationStatus = QueueOperationStatus | "REJECTED" | "RETRYABLE_ERROR";
439
440
  type OfflineOperationLifecycleStatus = QueueOperationStatus;
@@ -502,15 +503,18 @@ declare class OfflineQueue {
502
503
  get syncState(): SyncState;
503
504
  get pendingCount(): number;
504
505
  get queueCapability(): OfflineQueueCapability;
506
+ get storageCapability(): OfflineStorageCapability;
507
+ get isStoragePersistent(): boolean;
505
508
  get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
506
509
  get error(): Error | null;
507
510
  get operations(): ReadonlyArray<OfflineOperation>;
508
- get conflictPolicy(): SyncConflictPolicy;
509
511
  get storageKey(): string;
510
512
  get rallyId(): string | undefined;
511
513
  get userId(): string | null;
512
514
  setSyncResultListener(listener: OfflineSyncResultListener | undefined): void;
513
515
  setChangeListener(listener: OfflineQueueChangeListener | undefined): void;
516
+ setCapabilityWarningListener(listener: ((event: OfflineQueueCapabilityWarning) => void) | undefined): void;
517
+ setReplayConfig(config: AdminRallyConfig | PublicRallyConfig): void;
514
518
  initialize(): Promise<void>;
515
519
  /** Releases browser listeners when the queue is no longer used. */
516
520
  dispose(): void;
@@ -519,8 +523,8 @@ declare class OfflineQueue {
519
523
  switchUser(newUserId: string | null): Promise<void>;
520
524
  setSender(sender: OfflineSender): void;
521
525
  enqueue(operation: OfflineOperation): Promise<void>;
522
- enqueueCheckIn(request: CheckInRequest): Promise<void>;
523
- enqueueClaimReward(request: ClaimRequest): Promise<void>;
526
+ enqueueCheckIn(request: CheckInRequest, optimisticState?: UserRallyState): Promise<void>;
527
+ enqueueClaimReward(request: ClaimRequest, optimisticState?: UserRallyState): Promise<void>;
524
528
  clear(): Promise<void>;
525
529
  discardRejected(operationId: string): Promise<boolean>;
526
530
  retryRejected(operationId: string): Promise<boolean>;
@@ -529,7 +533,6 @@ declare class OfflineQueue {
529
533
  clearRejectedHistory(): Promise<void>;
530
534
  sync(sender?: OfflineSender | undefined): Promise<void>;
531
535
  retrySync(sender?: OfflineSender | undefined): Promise<void>;
532
- resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<UserRallyState>;
533
536
  }
534
537
 
535
538
  interface StampStorage {
@@ -650,6 +653,9 @@ type ClientEvent = {
650
653
  } | {
651
654
  readonly type: "syncLifecycle";
652
655
  readonly event: SyncLifecycleEvent;
656
+ } | {
657
+ readonly type: "storageCapabilityWarning";
658
+ readonly warning: OfflineQueueCapabilityWarning;
653
659
  } | {
654
660
  readonly type: "error";
655
661
  readonly error: ClientError | OfflineOperationError;
@@ -717,9 +723,6 @@ interface ClientOptions {
717
723
  readonly userId?: string | null;
718
724
  readonly anonymousSessionId?: string;
719
725
  readonly offlineQueue?: OfflineQueue;
720
- readonly conflictResolutionPolicy?: ConflictResolutionPolicy;
721
- /** Alias for conflictResolutionPolicy. */
722
- readonly conflictPolicy?: ConflictResolutionPolicy;
723
726
  }
724
727
  type StorageOrOptions = StampStorage | ClientOptions;
725
728
  declare class StampRallyClient {
@@ -734,6 +737,8 @@ declare class StampRallyClient {
734
737
  get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
735
738
  getSyncRevision(): number;
736
739
  get queueCapability(): OfflineQueueCapability;
740
+ get storageCapability(): OfflineStorageCapability;
741
+ get isStoragePersistent(): boolean;
737
742
  discardRejected(operationId: string): Promise<boolean>;
738
743
  retryRejected(operationId: string): Promise<boolean>;
739
744
  dismissRejectedOperation(operationId: string): Promise<boolean>;
@@ -755,6 +760,20 @@ declare class StampRallyClient {
755
760
  restore(state: UserRallyState): Promise<UserRallyState>;
756
761
  }
757
762
 
763
+ interface RebuildUserStateOptions {
764
+ readonly baseline: UserRallyState;
765
+ readonly operations: ReadonlyArray<OfflineOperation>;
766
+ readonly config?: AdminRallyConfig | PublicRallyConfig;
767
+ }
768
+ interface RebuildUserStateResult {
769
+ readonly state: UserRallyState;
770
+ readonly rejectedOperationIds: ReadonlyArray<string>;
771
+ }
772
+ /** Replays the durable operation log on top of a server-confirmed baseline. */
773
+ declare function rebuildUserStateFromLog(baseline: UserRallyState, operations: ReadonlyArray<OfflineOperation>, config?: AdminRallyConfig | PublicRallyConfig): UserRallyState;
774
+ declare function rebuildUserStateFromLog(options: RebuildUserStateOptions): UserRallyState;
775
+ declare function rebuildUserStateLog(baseline: UserRallyState, operations: ReadonlyArray<OfflineOperation>, config?: AdminRallyConfig | PublicRallyConfig): RebuildUserStateResult;
776
+
758
777
  type SecureTokenSecretKey = string | Uint8Array;
759
778
  interface SecureTokenOptions {
760
779
  readonly encrypt?: boolean;
@@ -860,4 +879,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
860
879
  declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
861
880
  declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
862
881
 
863
- export { type AdminRallyConfig, type CheckInCondition, type CheckInOptions, type CheckInRequest, type CheckInResult, type CheckInSuccess, type ClaimOptions, type ClaimRequest, type ClaimResult, type ClaimSuccess, type ClaimTicketOptions, type ClientError, type ClientEvent, type ClientEventListener, type ClientListener, type ClientOptions, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, ConfigValidationError, type ConflictResolutionPolicy, type ConsumeResult, type ConsumeRewardParams, type CustomValidationContext, type CustomValidator, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, type IndexedDBOfflineQueueOptions, IndexedDBOfflineQueueStorage, type InventoryAggregationMode, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type MergeConflictOptions, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflict, type OfflineConflictResult, type OfflineOperation, type OfflineOperationError, type OfflineOperationLifecycleStatus, type OfflineOperationResponse, type OfflineOperationStatus, OfflineQueue, type OfflineQueueCapability, type OfflineQueueChangeListener, type OfflineQueueOptions, type OfflineQueueStorage, type OfflineResult, type OfflineSender, type OfflineSyncResultEvent, type OfflineSyncResultListener, type ParseResult, type PasscodeCondition$1 as PasscodeCondition, type ProcessStampValue, type PublicCheckInCondition, type PublicConfigSafety, type PublicRallyConfig, type PublicReward, type PublicSpotItem, type QrDetectorOptions, type QrVerificationContext, type QueueOperationStatus, type RallyConfig, type RallyInventory, type RallyInventoryState, type RallySnapshot, type RedemptionMethod, type RejectedOperation, type RejectedOperationHistoryEntry, type Result, type Reward, type RewardConsumeError, type RewardState, type RewardStatus, type RewardType, type RewardUnlockCondition, type SecureTokenError, type SecureTokenErrorCode, type SecureTokenOptions, type SecureTokenPayload, type SecureTokenSecretKey, type SecureTokenVerification, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type SpotStatus, type StampError, StampRallyClient, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, type SyncAdapter, type SyncConflictPolicy, type SyncEventListener, type SyncLifecycleEvent, type SyncRetryOptions, type SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createAnonymousSessionId, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, evaluateSpotStatus, exportProgressToken, getCurrentGeoContext, getOrderedSpots, getSpotStatus, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, offlineOperationId, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, resolveRallyStateConflict, rollbackOptimisticOperation, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, validateRallyConfigRelations, verifyPasscode, verifySecureToken, verifySnapshotToken };
882
+ export { type AdminRallyConfig, type CheckInCondition, type CheckInOptions, type CheckInRequest, type CheckInResult, type CheckInSuccess, type ClaimOptions, type ClaimRequest, type ClaimResult, type ClaimSuccess, type ClaimTicketOptions, type ClientError, type ClientEvent, type ClientEventListener, type ClientListener, type ClientOptions, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, ConfigValidationError, type ConflictResolutionPolicy, type ConsumeResult, type ConsumeRewardParams, type CustomValidationContext, type CustomValidator, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, type IndexedDBOfflineQueueOptions, IndexedDBOfflineQueueStorage, type InventoryAggregationMode, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflictResult, type OfflineOperation, type OfflineOperationError, type OfflineOperationLifecycleStatus, type OfflineOperationResponse, type OfflineOperationStatus, OfflineQueue, type OfflineQueueCapability, type OfflineQueueCapabilityWarning, type OfflineQueueChangeListener, type OfflineQueueOptions, type OfflineQueueStorage, type OfflineResult, type OfflineSender, type OfflineStorageCapability, type OfflineSyncResultEvent, type OfflineSyncResultListener, type ParseResult, type PasscodeCondition$1 as PasscodeCondition, type ProcessStampValue, type PublicCheckInCondition, type PublicConfigSafety, type PublicRallyConfig, type PublicReward, type PublicSpotItem, type QrDetectorOptions, type QrVerificationContext, type QueueOperationStatus, type RallyConfig, type RallyInventory, type RallyInventoryState, type RallySnapshot, type RebuildUserStateOptions, type RebuildUserStateResult, type RedemptionMethod, type RejectedOperation, type RejectedOperationHistoryEntry, type Result, type Reward, type RewardConsumeError, type RewardState, type RewardStatus, type RewardType, type RewardUnlockCondition, type SecureTokenError, type SecureTokenErrorCode, type SecureTokenOptions, type SecureTokenPayload, type SecureTokenSecretKey, type SecureTokenVerification, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type SpotStatus, type StampError, StampRallyClient, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, type SyncAdapter, type SyncConflictPolicy, type SyncEventListener, type SyncLifecycleEvent, type SyncRetryOptions, type SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createAnonymousSessionId, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, evaluateSpotStatus, exportProgressToken, getCurrentGeoContext, getOrderedSpots, getSpotStatus, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, offlineOperationId, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, rebuildUserStateFromLog, rebuildUserStateLog, reconcileRewardStates, resolveLocalizedText, resolveRallyStateConflict, rollbackOptimisticOperation, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, validateRallyConfigRelations, verifyPasscode, verifySecureToken, verifySnapshotToken };
package/dist/index.d.ts CHANGED
@@ -99,7 +99,6 @@ type RedemptionMethod = "manual_slide" | "staff_passcode" | "view_only" | "serve
99
99
  type InventoryAggregationMode = "shared" | "per_reward";
100
100
  type RallyInventory = Readonly<Record<string, number>> & {
101
101
  readonly sharedStock?: number;
102
- readonly global?: number;
103
102
  };
104
103
  interface RallyInventoryState {
105
104
  readonly sharedRemaining?: number;
@@ -118,6 +117,10 @@ interface Reward<TLocale extends string = string> {
118
117
  readonly validUntil?: string;
119
118
  readonly stockLimit?: number;
120
119
  readonly userClaimLimit?: number;
120
+ /** Explicit primary inventory key. Defaults to the reward id. */
121
+ readonly stockKey?: string;
122
+ /** Optional second inventory bucket that must be decremented atomically. */
123
+ readonly secondaryStockKey?: string;
121
124
  }
122
125
  type PublicReward<TLocale extends string = string> = Omit<Reward<TLocale>, "digitalContentUrl" | "staffPasscode">;
123
126
  interface AdminRallyConfig<TLocale extends string = string, TMeta extends Record<string, unknown> = Record<string, unknown>> {
@@ -333,13 +336,9 @@ declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicket
333
336
  declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
334
337
  declare function issueClaimTicketNumber(reward: Reward, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
335
338
 
336
- type ConflictResolutionPolicy = "authoritative_replay" | "server_wins" | "merge";
337
- interface MergeConflictOptions {
338
- /** `merge` is retained for compatibility; synchronization paths use `authoritative_replay`. */
339
- readonly policy: ConflictResolutionPolicy;
340
- }
341
- /** Resolves a server/local state conflict without mutating either input state. */
342
- declare function resolveRallyStateConflict(serverState: UserRallyState, localState: UserRallyState, options?: MergeConflictOptions): UserRallyState;
339
+ type ConflictResolutionPolicy = "authoritative_replay";
340
+ /** Uses the server snapshot as the immutable replay baseline. */
341
+ declare function resolveRallyStateConflict(serverState: UserRallyState, _localState: UserRallyState): UserRallyState;
343
342
 
344
343
  type RewardConsumeError = {
345
344
  readonly code: "NOT_AVAILABLE" | "ALREADY_CONSUMED" | "OUT_OF_STOCK" | "REWARD_NOT_FOUND";
@@ -377,20 +376,23 @@ declare function processStamp(state: StampRallyState, config: AdminRallyConfig,
377
376
 
378
377
  type QueueOperationStatus = "PENDING" | "IN_FLIGHT" | "ACCEPTED" | "REJECTED_PERMANENT" | "FAILED_RETRYABLE";
379
378
  type OfflineQueueCapability = "indexeddb" | "localstorage" | "memory" | "custom";
379
+ type OfflineStorageCapability = OfflineQueueCapability | "volatile_single_tab";
380
380
  type OfflineOperation = {
381
381
  readonly kind: "checkIn";
382
382
  readonly request: CheckInRequest;
383
+ readonly optimisticState?: UserRallyState;
383
384
  readonly status?: QueueOperationStatus;
384
385
  readonly attempts?: number;
385
386
  } | {
386
387
  readonly kind: "claimReward";
387
388
  readonly request: ClaimRequest;
389
+ readonly optimisticState?: UserRallyState;
388
390
  readonly status?: QueueOperationStatus;
389
391
  readonly attempts?: number;
390
392
  };
391
393
  type OfflineResult = CheckInResult | ClaimResult | UserRallyState;
392
394
  type SyncState = "idle" | "syncing" | "error";
393
- type SyncConflictPolicy = ConflictResolutionPolicy;
395
+ type SyncConflictPolicy = "authoritative_replay";
394
396
  interface OfflineConflictResult {
395
397
  readonly conflict: true;
396
398
  readonly localState: UserRallyState;
@@ -402,6 +404,12 @@ interface OfflineQueueStorage {
402
404
  loadRejectedHistory?(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
403
405
  saveRejectedHistory?(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
404
406
  }
407
+ interface OfflineQueueCapabilityWarning {
408
+ readonly type: "STORAGE_CAPABILITY_WARNING";
409
+ readonly storageCapability: "volatile_single_tab" | "memory";
410
+ readonly isStoragePersistent: boolean;
411
+ readonly message: string;
412
+ }
405
413
  interface OfflineQueueOptions {
406
414
  readonly storage?: OfflineQueueStorage;
407
415
  readonly storageLike?: {
@@ -415,8 +423,6 @@ interface OfflineQueueOptions {
415
423
  /** User scope used by the default durable key. */
416
424
  readonly userId?: string | null;
417
425
  readonly databaseName?: string;
418
- readonly conflictPolicy?: SyncConflictPolicy;
419
- readonly onSyncConflict?: SyncConflictPolicy | ((context: OfflineConflict) => SyncConflictPolicy | Promise<SyncConflictPolicy>);
420
426
  /** Enables storage-event/BroadcastChannel synchronization when browser APIs exist. */
421
427
  readonly synchronizeInstances?: boolean;
422
428
  readonly retryOptions?: SyncRetryOptions;
@@ -429,11 +435,6 @@ interface SyncRetryOptions {
429
435
  readonly initialIntervalMs?: number;
430
436
  readonly backoffMultiplier?: number;
431
437
  }
432
- interface OfflineConflict {
433
- readonly operation: OfflineOperation;
434
- readonly localState: UserRallyState;
435
- readonly serverState: UserRallyState;
436
- }
437
438
  type OfflineSender = (operation: OfflineOperation) => Promise<OfflineResult | OfflineConflictResult | OfflineOperationResponse>;
438
439
  type OfflineOperationStatus = QueueOperationStatus | "REJECTED" | "RETRYABLE_ERROR";
439
440
  type OfflineOperationLifecycleStatus = QueueOperationStatus;
@@ -502,15 +503,18 @@ declare class OfflineQueue {
502
503
  get syncState(): SyncState;
503
504
  get pendingCount(): number;
504
505
  get queueCapability(): OfflineQueueCapability;
506
+ get storageCapability(): OfflineStorageCapability;
507
+ get isStoragePersistent(): boolean;
505
508
  get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
506
509
  get error(): Error | null;
507
510
  get operations(): ReadonlyArray<OfflineOperation>;
508
- get conflictPolicy(): SyncConflictPolicy;
509
511
  get storageKey(): string;
510
512
  get rallyId(): string | undefined;
511
513
  get userId(): string | null;
512
514
  setSyncResultListener(listener: OfflineSyncResultListener | undefined): void;
513
515
  setChangeListener(listener: OfflineQueueChangeListener | undefined): void;
516
+ setCapabilityWarningListener(listener: ((event: OfflineQueueCapabilityWarning) => void) | undefined): void;
517
+ setReplayConfig(config: AdminRallyConfig | PublicRallyConfig): void;
514
518
  initialize(): Promise<void>;
515
519
  /** Releases browser listeners when the queue is no longer used. */
516
520
  dispose(): void;
@@ -519,8 +523,8 @@ declare class OfflineQueue {
519
523
  switchUser(newUserId: string | null): Promise<void>;
520
524
  setSender(sender: OfflineSender): void;
521
525
  enqueue(operation: OfflineOperation): Promise<void>;
522
- enqueueCheckIn(request: CheckInRequest): Promise<void>;
523
- enqueueClaimReward(request: ClaimRequest): Promise<void>;
526
+ enqueueCheckIn(request: CheckInRequest, optimisticState?: UserRallyState): Promise<void>;
527
+ enqueueClaimReward(request: ClaimRequest, optimisticState?: UserRallyState): Promise<void>;
524
528
  clear(): Promise<void>;
525
529
  discardRejected(operationId: string): Promise<boolean>;
526
530
  retryRejected(operationId: string): Promise<boolean>;
@@ -529,7 +533,6 @@ declare class OfflineQueue {
529
533
  clearRejectedHistory(): Promise<void>;
530
534
  sync(sender?: OfflineSender | undefined): Promise<void>;
531
535
  retrySync(sender?: OfflineSender | undefined): Promise<void>;
532
- resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<UserRallyState>;
533
536
  }
534
537
 
535
538
  interface StampStorage {
@@ -650,6 +653,9 @@ type ClientEvent = {
650
653
  } | {
651
654
  readonly type: "syncLifecycle";
652
655
  readonly event: SyncLifecycleEvent;
656
+ } | {
657
+ readonly type: "storageCapabilityWarning";
658
+ readonly warning: OfflineQueueCapabilityWarning;
653
659
  } | {
654
660
  readonly type: "error";
655
661
  readonly error: ClientError | OfflineOperationError;
@@ -717,9 +723,6 @@ interface ClientOptions {
717
723
  readonly userId?: string | null;
718
724
  readonly anonymousSessionId?: string;
719
725
  readonly offlineQueue?: OfflineQueue;
720
- readonly conflictResolutionPolicy?: ConflictResolutionPolicy;
721
- /** Alias for conflictResolutionPolicy. */
722
- readonly conflictPolicy?: ConflictResolutionPolicy;
723
726
  }
724
727
  type StorageOrOptions = StampStorage | ClientOptions;
725
728
  declare class StampRallyClient {
@@ -734,6 +737,8 @@ declare class StampRallyClient {
734
737
  get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
735
738
  getSyncRevision(): number;
736
739
  get queueCapability(): OfflineQueueCapability;
740
+ get storageCapability(): OfflineStorageCapability;
741
+ get isStoragePersistent(): boolean;
737
742
  discardRejected(operationId: string): Promise<boolean>;
738
743
  retryRejected(operationId: string): Promise<boolean>;
739
744
  dismissRejectedOperation(operationId: string): Promise<boolean>;
@@ -755,6 +760,20 @@ declare class StampRallyClient {
755
760
  restore(state: UserRallyState): Promise<UserRallyState>;
756
761
  }
757
762
 
763
+ interface RebuildUserStateOptions {
764
+ readonly baseline: UserRallyState;
765
+ readonly operations: ReadonlyArray<OfflineOperation>;
766
+ readonly config?: AdminRallyConfig | PublicRallyConfig;
767
+ }
768
+ interface RebuildUserStateResult {
769
+ readonly state: UserRallyState;
770
+ readonly rejectedOperationIds: ReadonlyArray<string>;
771
+ }
772
+ /** Replays the durable operation log on top of a server-confirmed baseline. */
773
+ declare function rebuildUserStateFromLog(baseline: UserRallyState, operations: ReadonlyArray<OfflineOperation>, config?: AdminRallyConfig | PublicRallyConfig): UserRallyState;
774
+ declare function rebuildUserStateFromLog(options: RebuildUserStateOptions): UserRallyState;
775
+ declare function rebuildUserStateLog(baseline: UserRallyState, operations: ReadonlyArray<OfflineOperation>, config?: AdminRallyConfig | PublicRallyConfig): RebuildUserStateResult;
776
+
758
777
  type SecureTokenSecretKey = string | Uint8Array;
759
778
  interface SecureTokenOptions {
760
779
  readonly encrypt?: boolean;
@@ -860,4 +879,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
860
879
  declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
861
880
  declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
862
881
 
863
- export { type AdminRallyConfig, type CheckInCondition, type CheckInOptions, type CheckInRequest, type CheckInResult, type CheckInSuccess, type ClaimOptions, type ClaimRequest, type ClaimResult, type ClaimSuccess, type ClaimTicketOptions, type ClientError, type ClientEvent, type ClientEventListener, type ClientListener, type ClientOptions, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, ConfigValidationError, type ConflictResolutionPolicy, type ConsumeResult, type ConsumeRewardParams, type CustomValidationContext, type CustomValidator, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, type IndexedDBOfflineQueueOptions, IndexedDBOfflineQueueStorage, type InventoryAggregationMode, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type MergeConflictOptions, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflict, type OfflineConflictResult, type OfflineOperation, type OfflineOperationError, type OfflineOperationLifecycleStatus, type OfflineOperationResponse, type OfflineOperationStatus, OfflineQueue, type OfflineQueueCapability, type OfflineQueueChangeListener, type OfflineQueueOptions, type OfflineQueueStorage, type OfflineResult, type OfflineSender, type OfflineSyncResultEvent, type OfflineSyncResultListener, type ParseResult, type PasscodeCondition$1 as PasscodeCondition, type ProcessStampValue, type PublicCheckInCondition, type PublicConfigSafety, type PublicRallyConfig, type PublicReward, type PublicSpotItem, type QrDetectorOptions, type QrVerificationContext, type QueueOperationStatus, type RallyConfig, type RallyInventory, type RallyInventoryState, type RallySnapshot, type RedemptionMethod, type RejectedOperation, type RejectedOperationHistoryEntry, type Result, type Reward, type RewardConsumeError, type RewardState, type RewardStatus, type RewardType, type RewardUnlockCondition, type SecureTokenError, type SecureTokenErrorCode, type SecureTokenOptions, type SecureTokenPayload, type SecureTokenSecretKey, type SecureTokenVerification, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type SpotStatus, type StampError, StampRallyClient, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, type SyncAdapter, type SyncConflictPolicy, type SyncEventListener, type SyncLifecycleEvent, type SyncRetryOptions, type SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createAnonymousSessionId, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, evaluateSpotStatus, exportProgressToken, getCurrentGeoContext, getOrderedSpots, getSpotStatus, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, offlineOperationId, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, resolveRallyStateConflict, rollbackOptimisticOperation, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, validateRallyConfigRelations, verifyPasscode, verifySecureToken, verifySnapshotToken };
882
+ export { type AdminRallyConfig, type CheckInCondition, type CheckInOptions, type CheckInRequest, type CheckInResult, type CheckInSuccess, type ClaimOptions, type ClaimRequest, type ClaimResult, type ClaimSuccess, type ClaimTicketOptions, type ClientError, type ClientEvent, type ClientEventListener, type ClientListener, type ClientOptions, type CompositeConditionFailure, type ConditionMatch, type ConditionMismatch, ConfigValidationError, type ConflictResolutionPolicy, type ConsumeResult, type ConsumeRewardParams, type CustomValidationContext, type CustomValidator, DEFAULT_SHEET_THEME, type DetectorError, type DetectorErrorCode, type DetectorKind, type DetectorResult, type ExternalReference, type FontFamily, type GeoDetectorOptions, type GeoVerificationContext, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, type IndexedDBAdapterOptions, type IndexedDBOfflineQueueOptions, IndexedDBOfflineQueueStorage, type InventoryAggregationMode, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflictResult, type OfflineOperation, type OfflineOperationError, type OfflineOperationLifecycleStatus, type OfflineOperationResponse, type OfflineOperationStatus, OfflineQueue, type OfflineQueueCapability, type OfflineQueueCapabilityWarning, type OfflineQueueChangeListener, type OfflineQueueOptions, type OfflineQueueStorage, type OfflineResult, type OfflineSender, type OfflineStorageCapability, type OfflineSyncResultEvent, type OfflineSyncResultListener, type ParseResult, type PasscodeCondition$1 as PasscodeCondition, type ProcessStampValue, type PublicCheckInCondition, type PublicConfigSafety, type PublicRallyConfig, type PublicReward, type PublicSpotItem, type QrDetectorOptions, type QrVerificationContext, type QueueOperationStatus, type RallyConfig, type RallyInventory, type RallyInventoryState, type RallySnapshot, type RebuildUserStateOptions, type RebuildUserStateResult, type RedemptionMethod, type RejectedOperation, type RejectedOperationHistoryEntry, type Result, type Reward, type RewardConsumeError, type RewardState, type RewardStatus, type RewardType, type RewardUnlockCondition, type SecureTokenError, type SecureTokenErrorCode, type SecureTokenOptions, type SecureTokenPayload, type SecureTokenSecretKey, type SecureTokenVerification, type SheetTheme, type SlotShape, type SnapshotSecretKey, type SnapshotTokenError, type SnapshotTokenErrorCode, type SnapshotTokenPayload, type SnapshotTokenVerification, type SpotItem, type SpotStatus, type StampError, StampRallyClient, type StampRallyProgress, type StampRallyState, type StampRecord, type StampStorage, StorageAdapterError, type StorageAdapterErrorCode, type StorageLike, type StorageOperation, type StorageWarningHandler, type SupportedLocale, type SyncAdapter, type SyncConflictPolicy, type SyncEventListener, type SyncLifecycleEvent, type SyncRetryOptions, type SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createAnonymousSessionId, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, evaluateSpotStatus, exportProgressToken, getCurrentGeoContext, getOrderedSpots, getSpotStatus, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, offlineOperationId, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, rebuildUserStateFromLog, rebuildUserStateLog, reconcileRewardStates, resolveLocalizedText, resolveRallyStateConflict, rollbackOptimisticOperation, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, validateRallyConfigRelations, verifyPasscode, verifySecureToken, verifySnapshotToken };