@stamprally/core 0.15.0 → 0.17.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/README.md +6 -6
- package/dist/index.cjs +1049 -678
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -7
- package/dist/index.d.ts +75 -7
- package/dist/index.js +1048 -679
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -99,6 +99,7 @@ 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;
|
|
102
103
|
};
|
|
103
104
|
interface RallyInventoryState {
|
|
104
105
|
readonly sharedRemaining?: number;
|
|
@@ -332,8 +333,10 @@ declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicket
|
|
|
332
333
|
declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
|
|
333
334
|
declare function issueClaimTicketNumber(reward: Reward, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
|
|
334
335
|
|
|
336
|
+
type ConflictResolutionPolicy = "authoritative_replay" | "server_wins" | "merge";
|
|
335
337
|
interface MergeConflictOptions {
|
|
336
|
-
|
|
338
|
+
/** `merge` is retained for compatibility; synchronization paths use `authoritative_replay`. */
|
|
339
|
+
readonly policy: ConflictResolutionPolicy;
|
|
337
340
|
}
|
|
338
341
|
/** Resolves a server/local state conflict without mutating either input state. */
|
|
339
342
|
declare function resolveRallyStateConflict(serverState: UserRallyState, localState: UserRallyState, options?: MergeConflictOptions): UserRallyState;
|
|
@@ -372,20 +375,22 @@ interface ProcessStampValue {
|
|
|
372
375
|
}
|
|
373
376
|
declare function processStamp(state: StampRallyState, config: AdminRallyConfig, spotId: string, context: VerificationContext, now: string): Result<ProcessStampValue, StampError>;
|
|
374
377
|
|
|
378
|
+
type QueueOperationStatus = "PENDING" | "IN_FLIGHT" | "ACCEPTED" | "REJECTED_PERMANENT" | "FAILED_RETRYABLE";
|
|
379
|
+
type OfflineQueueCapability = "indexeddb" | "localstorage" | "memory" | "custom";
|
|
375
380
|
type OfflineOperation = {
|
|
376
381
|
readonly kind: "checkIn";
|
|
377
382
|
readonly request: CheckInRequest;
|
|
378
|
-
readonly status?:
|
|
383
|
+
readonly status?: QueueOperationStatus;
|
|
379
384
|
readonly attempts?: number;
|
|
380
385
|
} | {
|
|
381
386
|
readonly kind: "claimReward";
|
|
382
387
|
readonly request: ClaimRequest;
|
|
383
|
-
readonly status?:
|
|
388
|
+
readonly status?: QueueOperationStatus;
|
|
384
389
|
readonly attempts?: number;
|
|
385
390
|
};
|
|
386
391
|
type OfflineResult = CheckInResult | ClaimResult | UserRallyState;
|
|
387
392
|
type SyncState = "idle" | "syncing" | "error";
|
|
388
|
-
type SyncConflictPolicy =
|
|
393
|
+
type SyncConflictPolicy = ConflictResolutionPolicy;
|
|
389
394
|
interface OfflineConflictResult {
|
|
390
395
|
readonly conflict: true;
|
|
391
396
|
readonly localState: UserRallyState;
|
|
@@ -394,6 +399,8 @@ interface OfflineConflictResult {
|
|
|
394
399
|
interface OfflineQueueStorage {
|
|
395
400
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
396
401
|
save(key: string, operations: ReadonlyArray<OfflineOperation>): Promise<void>;
|
|
402
|
+
loadRejectedHistory?(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
|
|
403
|
+
saveRejectedHistory?(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
|
|
397
404
|
}
|
|
398
405
|
interface OfflineQueueOptions {
|
|
399
406
|
readonly storage?: OfflineQueueStorage;
|
|
@@ -428,13 +435,21 @@ interface OfflineConflict {
|
|
|
428
435
|
readonly serverState: UserRallyState;
|
|
429
436
|
}
|
|
430
437
|
type OfflineSender = (operation: OfflineOperation) => Promise<OfflineResult | OfflineConflictResult | OfflineOperationResponse>;
|
|
431
|
-
type OfflineOperationStatus =
|
|
432
|
-
type OfflineOperationLifecycleStatus =
|
|
438
|
+
type OfflineOperationStatus = QueueOperationStatus | "REJECTED" | "RETRYABLE_ERROR";
|
|
439
|
+
type OfflineOperationLifecycleStatus = QueueOperationStatus;
|
|
433
440
|
interface OfflineOperationError {
|
|
434
441
|
readonly code: string;
|
|
435
442
|
readonly message: string;
|
|
436
443
|
readonly [key: string]: unknown;
|
|
437
444
|
}
|
|
445
|
+
interface RejectedOperationHistoryEntry {
|
|
446
|
+
readonly operation: OfflineOperation;
|
|
447
|
+
readonly reason: OfflineOperationError;
|
|
448
|
+
readonly errorCode: string;
|
|
449
|
+
readonly rejectedAt: string;
|
|
450
|
+
readonly attempts: number;
|
|
451
|
+
}
|
|
452
|
+
type RejectedOperation = RejectedOperationHistoryEntry;
|
|
438
453
|
type OfflineOperationResponse = {
|
|
439
454
|
readonly status: "ACCEPTED";
|
|
440
455
|
readonly result?: OfflineResult | OfflineConflictResult;
|
|
@@ -457,10 +472,15 @@ interface OfflineSyncResultEvent {
|
|
|
457
472
|
readonly state?: UserRallyState;
|
|
458
473
|
}
|
|
459
474
|
type OfflineSyncResultListener = (event: OfflineSyncResultEvent) => void | Promise<void>;
|
|
475
|
+
type OfflineQueueChangeListener = () => void;
|
|
476
|
+
/** Removes only an operation's optimistic changes without mutating its inputs. */
|
|
477
|
+
declare function rollbackOptimisticOperation(state: UserRallyState, operation: OfflineOperation): UserRallyState;
|
|
460
478
|
declare class MemoryQueueStorage implements OfflineQueueStorage {
|
|
461
479
|
#private;
|
|
462
480
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
463
481
|
save(key: string, operations: ReadonlyArray<OfflineOperation>): Promise<void>;
|
|
482
|
+
loadRejectedHistory(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
|
|
483
|
+
saveRejectedHistory(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
|
|
464
484
|
}
|
|
465
485
|
interface IndexedDBOfflineQueueOptions {
|
|
466
486
|
readonly indexedDB?: IDBFactory | null;
|
|
@@ -471,13 +491,18 @@ declare class IndexedDBOfflineQueueStorage implements OfflineQueueStorage {
|
|
|
471
491
|
constructor(options?: IndexedDBOfflineQueueOptions);
|
|
472
492
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
473
493
|
save(key: string, operations: ReadonlyArray<OfflineOperation>): Promise<void>;
|
|
494
|
+
loadRejectedHistory(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
|
|
495
|
+
saveRejectedHistory(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
|
|
474
496
|
}
|
|
497
|
+
declare function offlineOperationId(operation: OfflineOperation): string;
|
|
475
498
|
/** Durable, sequential retry queue for operations created while disconnected. */
|
|
476
499
|
declare class OfflineQueue {
|
|
477
500
|
#private;
|
|
478
501
|
constructor(options?: OfflineQueueOptions);
|
|
479
502
|
get syncState(): SyncState;
|
|
480
503
|
get pendingCount(): number;
|
|
504
|
+
get queueCapability(): OfflineQueueCapability;
|
|
505
|
+
get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
|
|
481
506
|
get error(): Error | null;
|
|
482
507
|
get operations(): ReadonlyArray<OfflineOperation>;
|
|
483
508
|
get conflictPolicy(): SyncConflictPolicy;
|
|
@@ -485,6 +510,7 @@ declare class OfflineQueue {
|
|
|
485
510
|
get rallyId(): string | undefined;
|
|
486
511
|
get userId(): string | null;
|
|
487
512
|
setSyncResultListener(listener: OfflineSyncResultListener | undefined): void;
|
|
513
|
+
setChangeListener(listener: OfflineQueueChangeListener | undefined): void;
|
|
488
514
|
initialize(): Promise<void>;
|
|
489
515
|
/** Releases browser listeners when the queue is no longer used. */
|
|
490
516
|
dispose(): void;
|
|
@@ -496,6 +522,11 @@ declare class OfflineQueue {
|
|
|
496
522
|
enqueueCheckIn(request: CheckInRequest): Promise<void>;
|
|
497
523
|
enqueueClaimReward(request: ClaimRequest): Promise<void>;
|
|
498
524
|
clear(): Promise<void>;
|
|
525
|
+
discardRejected(operationId: string): Promise<boolean>;
|
|
526
|
+
retryRejected(operationId: string): Promise<boolean>;
|
|
527
|
+
discardRejectedOperation(operationId: string): Promise<boolean>;
|
|
528
|
+
retryRejectedOperation(operationId: string): Promise<boolean>;
|
|
529
|
+
clearRejectedHistory(): Promise<void>;
|
|
499
530
|
sync(sender?: OfflineSender | undefined): Promise<void>;
|
|
500
531
|
retrySync(sender?: OfflineSender | undefined): Promise<void>;
|
|
501
532
|
resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<UserRallyState>;
|
|
@@ -616,12 +647,37 @@ type ClientEvent = {
|
|
|
616
647
|
} | {
|
|
617
648
|
readonly type: "sync";
|
|
618
649
|
readonly state: UserRallyState;
|
|
650
|
+
} | {
|
|
651
|
+
readonly type: "syncLifecycle";
|
|
652
|
+
readonly event: SyncLifecycleEvent;
|
|
619
653
|
} | {
|
|
620
654
|
readonly type: "error";
|
|
621
655
|
readonly error: ClientError | OfflineOperationError;
|
|
622
656
|
};
|
|
623
657
|
type ClientListener = (state: UserRallyState) => void;
|
|
624
658
|
type ClientEventListener = (event: ClientEvent) => void;
|
|
659
|
+
type SyncLifecycleEvent = {
|
|
660
|
+
readonly type: "SYNC_STARTED";
|
|
661
|
+
} | {
|
|
662
|
+
readonly type: "OPERATION_ACCEPTED";
|
|
663
|
+
readonly operationId: string;
|
|
664
|
+
readonly resourceId: string;
|
|
665
|
+
} | {
|
|
666
|
+
readonly type: "OPERATION_ROLLED_BACK";
|
|
667
|
+
readonly operationId: string;
|
|
668
|
+
readonly resourceId: string;
|
|
669
|
+
readonly reason: string;
|
|
670
|
+
readonly errorCode: string;
|
|
671
|
+
} | {
|
|
672
|
+
readonly type: "OPERATION_RETRYABLE_ERROR";
|
|
673
|
+
readonly operationId: string;
|
|
674
|
+
readonly error: string;
|
|
675
|
+
} | {
|
|
676
|
+
readonly type: "SYNC_COMPLETED";
|
|
677
|
+
readonly totalProcessed: number;
|
|
678
|
+
readonly failedCount: number;
|
|
679
|
+
};
|
|
680
|
+
type SyncEventListener = (event: SyncLifecycleEvent) => void;
|
|
625
681
|
interface CheckInRequest {
|
|
626
682
|
readonly rallyId: string;
|
|
627
683
|
readonly userId: string | null;
|
|
@@ -661,6 +717,9 @@ interface ClientOptions {
|
|
|
661
717
|
readonly userId?: string | null;
|
|
662
718
|
readonly anonymousSessionId?: string;
|
|
663
719
|
readonly offlineQueue?: OfflineQueue;
|
|
720
|
+
readonly conflictResolutionPolicy?: ConflictResolutionPolicy;
|
|
721
|
+
/** Alias for conflictResolutionPolicy. */
|
|
722
|
+
readonly conflictPolicy?: ConflictResolutionPolicy;
|
|
664
723
|
}
|
|
665
724
|
type StorageOrOptions = StampStorage | ClientOptions;
|
|
666
725
|
declare class StampRallyClient {
|
|
@@ -672,8 +731,17 @@ declare class StampRallyClient {
|
|
|
672
731
|
getAnonymousSessionId(): string;
|
|
673
732
|
get syncState(): SyncState;
|
|
674
733
|
get pendingCount(): number;
|
|
734
|
+
get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
|
|
735
|
+
getSyncRevision(): number;
|
|
736
|
+
get queueCapability(): OfflineQueueCapability;
|
|
737
|
+
discardRejected(operationId: string): Promise<boolean>;
|
|
738
|
+
retryRejected(operationId: string): Promise<boolean>;
|
|
739
|
+
dismissRejectedOperation(operationId: string): Promise<boolean>;
|
|
740
|
+
retryOperation(operationId: string): Promise<boolean>;
|
|
675
741
|
subscribe(listener: ClientListener): () => void;
|
|
676
742
|
subscribeEvents(listener: ClientEventListener): () => void;
|
|
743
|
+
subscribeSyncEvents(listener: SyncEventListener): () => void;
|
|
744
|
+
subscribeSyncState(listener: () => void): () => void;
|
|
677
745
|
init(): Promise<UserRallyState>;
|
|
678
746
|
initialize(): Promise<UserRallyState>;
|
|
679
747
|
switchUser(newUserId: string | null): Promise<UserRallyState>;
|
|
@@ -792,4 +860,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
|
|
|
792
860
|
declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
|
|
793
861
|
declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
|
|
794
862
|
|
|
795
|
-
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 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 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 RallyConfig, type RallyInventory, type RallyInventoryState, type RallySnapshot, type RedemptionMethod, 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 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, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, resolveRallyStateConflict, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, validateRallyConfigRelations, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -99,6 +99,7 @@ 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;
|
|
102
103
|
};
|
|
103
104
|
interface RallyInventoryState {
|
|
104
105
|
readonly sharedRemaining?: number;
|
|
@@ -332,8 +333,10 @@ declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicket
|
|
|
332
333
|
declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
|
|
333
334
|
declare function issueClaimTicketNumber(reward: Reward, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
|
|
334
335
|
|
|
336
|
+
type ConflictResolutionPolicy = "authoritative_replay" | "server_wins" | "merge";
|
|
335
337
|
interface MergeConflictOptions {
|
|
336
|
-
|
|
338
|
+
/** `merge` is retained for compatibility; synchronization paths use `authoritative_replay`. */
|
|
339
|
+
readonly policy: ConflictResolutionPolicy;
|
|
337
340
|
}
|
|
338
341
|
/** Resolves a server/local state conflict without mutating either input state. */
|
|
339
342
|
declare function resolveRallyStateConflict(serverState: UserRallyState, localState: UserRallyState, options?: MergeConflictOptions): UserRallyState;
|
|
@@ -372,20 +375,22 @@ interface ProcessStampValue {
|
|
|
372
375
|
}
|
|
373
376
|
declare function processStamp(state: StampRallyState, config: AdminRallyConfig, spotId: string, context: VerificationContext, now: string): Result<ProcessStampValue, StampError>;
|
|
374
377
|
|
|
378
|
+
type QueueOperationStatus = "PENDING" | "IN_FLIGHT" | "ACCEPTED" | "REJECTED_PERMANENT" | "FAILED_RETRYABLE";
|
|
379
|
+
type OfflineQueueCapability = "indexeddb" | "localstorage" | "memory" | "custom";
|
|
375
380
|
type OfflineOperation = {
|
|
376
381
|
readonly kind: "checkIn";
|
|
377
382
|
readonly request: CheckInRequest;
|
|
378
|
-
readonly status?:
|
|
383
|
+
readonly status?: QueueOperationStatus;
|
|
379
384
|
readonly attempts?: number;
|
|
380
385
|
} | {
|
|
381
386
|
readonly kind: "claimReward";
|
|
382
387
|
readonly request: ClaimRequest;
|
|
383
|
-
readonly status?:
|
|
388
|
+
readonly status?: QueueOperationStatus;
|
|
384
389
|
readonly attempts?: number;
|
|
385
390
|
};
|
|
386
391
|
type OfflineResult = CheckInResult | ClaimResult | UserRallyState;
|
|
387
392
|
type SyncState = "idle" | "syncing" | "error";
|
|
388
|
-
type SyncConflictPolicy =
|
|
393
|
+
type SyncConflictPolicy = ConflictResolutionPolicy;
|
|
389
394
|
interface OfflineConflictResult {
|
|
390
395
|
readonly conflict: true;
|
|
391
396
|
readonly localState: UserRallyState;
|
|
@@ -394,6 +399,8 @@ interface OfflineConflictResult {
|
|
|
394
399
|
interface OfflineQueueStorage {
|
|
395
400
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
396
401
|
save(key: string, operations: ReadonlyArray<OfflineOperation>): Promise<void>;
|
|
402
|
+
loadRejectedHistory?(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
|
|
403
|
+
saveRejectedHistory?(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
|
|
397
404
|
}
|
|
398
405
|
interface OfflineQueueOptions {
|
|
399
406
|
readonly storage?: OfflineQueueStorage;
|
|
@@ -428,13 +435,21 @@ interface OfflineConflict {
|
|
|
428
435
|
readonly serverState: UserRallyState;
|
|
429
436
|
}
|
|
430
437
|
type OfflineSender = (operation: OfflineOperation) => Promise<OfflineResult | OfflineConflictResult | OfflineOperationResponse>;
|
|
431
|
-
type OfflineOperationStatus =
|
|
432
|
-
type OfflineOperationLifecycleStatus =
|
|
438
|
+
type OfflineOperationStatus = QueueOperationStatus | "REJECTED" | "RETRYABLE_ERROR";
|
|
439
|
+
type OfflineOperationLifecycleStatus = QueueOperationStatus;
|
|
433
440
|
interface OfflineOperationError {
|
|
434
441
|
readonly code: string;
|
|
435
442
|
readonly message: string;
|
|
436
443
|
readonly [key: string]: unknown;
|
|
437
444
|
}
|
|
445
|
+
interface RejectedOperationHistoryEntry {
|
|
446
|
+
readonly operation: OfflineOperation;
|
|
447
|
+
readonly reason: OfflineOperationError;
|
|
448
|
+
readonly errorCode: string;
|
|
449
|
+
readonly rejectedAt: string;
|
|
450
|
+
readonly attempts: number;
|
|
451
|
+
}
|
|
452
|
+
type RejectedOperation = RejectedOperationHistoryEntry;
|
|
438
453
|
type OfflineOperationResponse = {
|
|
439
454
|
readonly status: "ACCEPTED";
|
|
440
455
|
readonly result?: OfflineResult | OfflineConflictResult;
|
|
@@ -457,10 +472,15 @@ interface OfflineSyncResultEvent {
|
|
|
457
472
|
readonly state?: UserRallyState;
|
|
458
473
|
}
|
|
459
474
|
type OfflineSyncResultListener = (event: OfflineSyncResultEvent) => void | Promise<void>;
|
|
475
|
+
type OfflineQueueChangeListener = () => void;
|
|
476
|
+
/** Removes only an operation's optimistic changes without mutating its inputs. */
|
|
477
|
+
declare function rollbackOptimisticOperation(state: UserRallyState, operation: OfflineOperation): UserRallyState;
|
|
460
478
|
declare class MemoryQueueStorage implements OfflineQueueStorage {
|
|
461
479
|
#private;
|
|
462
480
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
463
481
|
save(key: string, operations: ReadonlyArray<OfflineOperation>): Promise<void>;
|
|
482
|
+
loadRejectedHistory(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
|
|
483
|
+
saveRejectedHistory(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
|
|
464
484
|
}
|
|
465
485
|
interface IndexedDBOfflineQueueOptions {
|
|
466
486
|
readonly indexedDB?: IDBFactory | null;
|
|
@@ -471,13 +491,18 @@ declare class IndexedDBOfflineQueueStorage implements OfflineQueueStorage {
|
|
|
471
491
|
constructor(options?: IndexedDBOfflineQueueOptions);
|
|
472
492
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
473
493
|
save(key: string, operations: ReadonlyArray<OfflineOperation>): Promise<void>;
|
|
494
|
+
loadRejectedHistory(key: string): Promise<ReadonlyArray<RejectedOperationHistoryEntry>>;
|
|
495
|
+
saveRejectedHistory(key: string, history: ReadonlyArray<RejectedOperationHistoryEntry>): Promise<void>;
|
|
474
496
|
}
|
|
497
|
+
declare function offlineOperationId(operation: OfflineOperation): string;
|
|
475
498
|
/** Durable, sequential retry queue for operations created while disconnected. */
|
|
476
499
|
declare class OfflineQueue {
|
|
477
500
|
#private;
|
|
478
501
|
constructor(options?: OfflineQueueOptions);
|
|
479
502
|
get syncState(): SyncState;
|
|
480
503
|
get pendingCount(): number;
|
|
504
|
+
get queueCapability(): OfflineQueueCapability;
|
|
505
|
+
get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
|
|
481
506
|
get error(): Error | null;
|
|
482
507
|
get operations(): ReadonlyArray<OfflineOperation>;
|
|
483
508
|
get conflictPolicy(): SyncConflictPolicy;
|
|
@@ -485,6 +510,7 @@ declare class OfflineQueue {
|
|
|
485
510
|
get rallyId(): string | undefined;
|
|
486
511
|
get userId(): string | null;
|
|
487
512
|
setSyncResultListener(listener: OfflineSyncResultListener | undefined): void;
|
|
513
|
+
setChangeListener(listener: OfflineQueueChangeListener | undefined): void;
|
|
488
514
|
initialize(): Promise<void>;
|
|
489
515
|
/** Releases browser listeners when the queue is no longer used. */
|
|
490
516
|
dispose(): void;
|
|
@@ -496,6 +522,11 @@ declare class OfflineQueue {
|
|
|
496
522
|
enqueueCheckIn(request: CheckInRequest): Promise<void>;
|
|
497
523
|
enqueueClaimReward(request: ClaimRequest): Promise<void>;
|
|
498
524
|
clear(): Promise<void>;
|
|
525
|
+
discardRejected(operationId: string): Promise<boolean>;
|
|
526
|
+
retryRejected(operationId: string): Promise<boolean>;
|
|
527
|
+
discardRejectedOperation(operationId: string): Promise<boolean>;
|
|
528
|
+
retryRejectedOperation(operationId: string): Promise<boolean>;
|
|
529
|
+
clearRejectedHistory(): Promise<void>;
|
|
499
530
|
sync(sender?: OfflineSender | undefined): Promise<void>;
|
|
500
531
|
retrySync(sender?: OfflineSender | undefined): Promise<void>;
|
|
501
532
|
resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<UserRallyState>;
|
|
@@ -616,12 +647,37 @@ type ClientEvent = {
|
|
|
616
647
|
} | {
|
|
617
648
|
readonly type: "sync";
|
|
618
649
|
readonly state: UserRallyState;
|
|
650
|
+
} | {
|
|
651
|
+
readonly type: "syncLifecycle";
|
|
652
|
+
readonly event: SyncLifecycleEvent;
|
|
619
653
|
} | {
|
|
620
654
|
readonly type: "error";
|
|
621
655
|
readonly error: ClientError | OfflineOperationError;
|
|
622
656
|
};
|
|
623
657
|
type ClientListener = (state: UserRallyState) => void;
|
|
624
658
|
type ClientEventListener = (event: ClientEvent) => void;
|
|
659
|
+
type SyncLifecycleEvent = {
|
|
660
|
+
readonly type: "SYNC_STARTED";
|
|
661
|
+
} | {
|
|
662
|
+
readonly type: "OPERATION_ACCEPTED";
|
|
663
|
+
readonly operationId: string;
|
|
664
|
+
readonly resourceId: string;
|
|
665
|
+
} | {
|
|
666
|
+
readonly type: "OPERATION_ROLLED_BACK";
|
|
667
|
+
readonly operationId: string;
|
|
668
|
+
readonly resourceId: string;
|
|
669
|
+
readonly reason: string;
|
|
670
|
+
readonly errorCode: string;
|
|
671
|
+
} | {
|
|
672
|
+
readonly type: "OPERATION_RETRYABLE_ERROR";
|
|
673
|
+
readonly operationId: string;
|
|
674
|
+
readonly error: string;
|
|
675
|
+
} | {
|
|
676
|
+
readonly type: "SYNC_COMPLETED";
|
|
677
|
+
readonly totalProcessed: number;
|
|
678
|
+
readonly failedCount: number;
|
|
679
|
+
};
|
|
680
|
+
type SyncEventListener = (event: SyncLifecycleEvent) => void;
|
|
625
681
|
interface CheckInRequest {
|
|
626
682
|
readonly rallyId: string;
|
|
627
683
|
readonly userId: string | null;
|
|
@@ -661,6 +717,9 @@ interface ClientOptions {
|
|
|
661
717
|
readonly userId?: string | null;
|
|
662
718
|
readonly anonymousSessionId?: string;
|
|
663
719
|
readonly offlineQueue?: OfflineQueue;
|
|
720
|
+
readonly conflictResolutionPolicy?: ConflictResolutionPolicy;
|
|
721
|
+
/** Alias for conflictResolutionPolicy. */
|
|
722
|
+
readonly conflictPolicy?: ConflictResolutionPolicy;
|
|
664
723
|
}
|
|
665
724
|
type StorageOrOptions = StampStorage | ClientOptions;
|
|
666
725
|
declare class StampRallyClient {
|
|
@@ -672,8 +731,17 @@ declare class StampRallyClient {
|
|
|
672
731
|
getAnonymousSessionId(): string;
|
|
673
732
|
get syncState(): SyncState;
|
|
674
733
|
get pendingCount(): number;
|
|
734
|
+
get rejectedHistory(): ReadonlyArray<RejectedOperationHistoryEntry>;
|
|
735
|
+
getSyncRevision(): number;
|
|
736
|
+
get queueCapability(): OfflineQueueCapability;
|
|
737
|
+
discardRejected(operationId: string): Promise<boolean>;
|
|
738
|
+
retryRejected(operationId: string): Promise<boolean>;
|
|
739
|
+
dismissRejectedOperation(operationId: string): Promise<boolean>;
|
|
740
|
+
retryOperation(operationId: string): Promise<boolean>;
|
|
675
741
|
subscribe(listener: ClientListener): () => void;
|
|
676
742
|
subscribeEvents(listener: ClientEventListener): () => void;
|
|
743
|
+
subscribeSyncEvents(listener: SyncEventListener): () => void;
|
|
744
|
+
subscribeSyncState(listener: () => void): () => void;
|
|
677
745
|
init(): Promise<UserRallyState>;
|
|
678
746
|
initialize(): Promise<UserRallyState>;
|
|
679
747
|
switchUser(newUserId: string | null): Promise<UserRallyState>;
|
|
@@ -792,4 +860,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
|
|
|
792
860
|
declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
|
|
793
861
|
declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
|
|
794
862
|
|
|
795
|
-
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 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 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 RallyConfig, type RallyInventory, type RallyInventoryState, type RallySnapshot, type RedemptionMethod, 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 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, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, resolveRallyStateConflict, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, validateRallyConfigRelations, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
|
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 };
|