@stamprally/core 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +78 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +78 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -313,6 +313,12 @@ declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicket
|
|
|
313
313
|
declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
|
|
314
314
|
declare function issueClaimTicketNumber(reward: Reward, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
|
|
315
315
|
|
|
316
|
+
interface MergeConflictOptions {
|
|
317
|
+
readonly policy: "server_wins" | "merge";
|
|
318
|
+
}
|
|
319
|
+
/** Resolves a server/local state conflict without mutating either input state. */
|
|
320
|
+
declare function resolveRallyStateConflict(serverState: UserRallyState, localState: UserRallyState, options?: MergeConflictOptions): UserRallyState;
|
|
321
|
+
|
|
316
322
|
type RewardConsumeError = {
|
|
317
323
|
readonly code: "NOT_AVAILABLE" | "ALREADY_CONSUMED" | "OUT_OF_STOCK" | "REWARD_NOT_FOUND";
|
|
318
324
|
readonly rewardId: string;
|
|
@@ -384,6 +390,12 @@ interface OfflineConflict {
|
|
|
384
390
|
readonly serverState: UserRallyState;
|
|
385
391
|
}
|
|
386
392
|
type OfflineSender = (operation: OfflineOperation) => Promise<OfflineResult | OfflineConflictResult>;
|
|
393
|
+
interface OfflineSyncResultEvent {
|
|
394
|
+
readonly operation: OfflineOperation;
|
|
395
|
+
readonly result: OfflineResult | OfflineConflictResult;
|
|
396
|
+
readonly state?: UserRallyState;
|
|
397
|
+
}
|
|
398
|
+
type OfflineSyncResultListener = (event: OfflineSyncResultEvent) => void | Promise<void>;
|
|
387
399
|
declare class MemoryQueueStorage implements OfflineQueueStorage {
|
|
388
400
|
#private;
|
|
389
401
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
@@ -407,6 +419,8 @@ declare class OfflineQueue {
|
|
|
407
419
|
get pendingCount(): number;
|
|
408
420
|
get error(): Error | null;
|
|
409
421
|
get operations(): ReadonlyArray<OfflineOperation>;
|
|
422
|
+
get conflictPolicy(): SyncConflictPolicy;
|
|
423
|
+
setSyncResultListener(listener: OfflineSyncResultListener | undefined): void;
|
|
410
424
|
initialize(): Promise<void>;
|
|
411
425
|
setSender(sender: OfflineSender): void;
|
|
412
426
|
enqueue(operation: OfflineOperation): Promise<void>;
|
|
@@ -415,7 +429,7 @@ declare class OfflineQueue {
|
|
|
415
429
|
clear(): Promise<void>;
|
|
416
430
|
sync(sender?: OfflineSender | undefined): Promise<void>;
|
|
417
431
|
retrySync(sender?: OfflineSender | undefined): Promise<void>;
|
|
418
|
-
resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<
|
|
432
|
+
resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<UserRallyState>;
|
|
419
433
|
}
|
|
420
434
|
|
|
421
435
|
interface StampStorage {
|
|
@@ -703,4 +717,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
|
|
|
703
717
|
declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
|
|
704
718
|
declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
|
|
705
719
|
|
|
706
|
-
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, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflict, type OfflineConflictResult, type OfflineOperation, OfflineQueue, type OfflineQueueOptions, type OfflineQueueStorage, type OfflineResult, type OfflineSender, 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 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 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 SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, getOrderedSpots, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
|
720
|
+
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, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type MergeConflictOptions, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflict, type OfflineConflictResult, type OfflineOperation, 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 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 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 SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, getOrderedSpots, 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, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
package/dist/index.d.ts
CHANGED
|
@@ -313,6 +313,12 @@ declare function createClaimTicketNumber(rewardId: string, options?: ClaimTicket
|
|
|
313
313
|
declare function createUniqueClaimTicketNumber(rewardId: string, issuedAt: string): string;
|
|
314
314
|
declare function issueClaimTicketNumber(reward: Reward, currentState: RewardState, options?: ClaimTicketOptions): RewardState;
|
|
315
315
|
|
|
316
|
+
interface MergeConflictOptions {
|
|
317
|
+
readonly policy: "server_wins" | "merge";
|
|
318
|
+
}
|
|
319
|
+
/** Resolves a server/local state conflict without mutating either input state. */
|
|
320
|
+
declare function resolveRallyStateConflict(serverState: UserRallyState, localState: UserRallyState, options?: MergeConflictOptions): UserRallyState;
|
|
321
|
+
|
|
316
322
|
type RewardConsumeError = {
|
|
317
323
|
readonly code: "NOT_AVAILABLE" | "ALREADY_CONSUMED" | "OUT_OF_STOCK" | "REWARD_NOT_FOUND";
|
|
318
324
|
readonly rewardId: string;
|
|
@@ -384,6 +390,12 @@ interface OfflineConflict {
|
|
|
384
390
|
readonly serverState: UserRallyState;
|
|
385
391
|
}
|
|
386
392
|
type OfflineSender = (operation: OfflineOperation) => Promise<OfflineResult | OfflineConflictResult>;
|
|
393
|
+
interface OfflineSyncResultEvent {
|
|
394
|
+
readonly operation: OfflineOperation;
|
|
395
|
+
readonly result: OfflineResult | OfflineConflictResult;
|
|
396
|
+
readonly state?: UserRallyState;
|
|
397
|
+
}
|
|
398
|
+
type OfflineSyncResultListener = (event: OfflineSyncResultEvent) => void | Promise<void>;
|
|
387
399
|
declare class MemoryQueueStorage implements OfflineQueueStorage {
|
|
388
400
|
#private;
|
|
389
401
|
load(key: string): Promise<ReadonlyArray<OfflineOperation>>;
|
|
@@ -407,6 +419,8 @@ declare class OfflineQueue {
|
|
|
407
419
|
get pendingCount(): number;
|
|
408
420
|
get error(): Error | null;
|
|
409
421
|
get operations(): ReadonlyArray<OfflineOperation>;
|
|
422
|
+
get conflictPolicy(): SyncConflictPolicy;
|
|
423
|
+
setSyncResultListener(listener: OfflineSyncResultListener | undefined): void;
|
|
410
424
|
initialize(): Promise<void>;
|
|
411
425
|
setSender(sender: OfflineSender): void;
|
|
412
426
|
enqueue(operation: OfflineOperation): Promise<void>;
|
|
@@ -415,7 +429,7 @@ declare class OfflineQueue {
|
|
|
415
429
|
clear(): Promise<void>;
|
|
416
430
|
sync(sender?: OfflineSender | undefined): Promise<void>;
|
|
417
431
|
retrySync(sender?: OfflineSender | undefined): Promise<void>;
|
|
418
|
-
resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<
|
|
432
|
+
resolveConflict(operation: OfflineOperation, localState: UserRallyState, serverState: UserRallyState): Promise<UserRallyState>;
|
|
419
433
|
}
|
|
420
434
|
|
|
421
435
|
interface StampStorage {
|
|
@@ -703,4 +717,4 @@ type SnapshotTokenVerification<T extends SnapshotTokenPayload = SnapshotTokenPay
|
|
|
703
717
|
declare function createSignedSnapshotToken<T extends SnapshotTokenPayload>(payload: T, secretKey: SnapshotSecretKey): Promise<string>;
|
|
704
718
|
declare function verifySnapshotToken<T extends SnapshotTokenPayload = SnapshotTokenPayload>(token: string, secretKey: SnapshotSecretKey, now?: number): Promise<SnapshotTokenVerification<T>>;
|
|
705
719
|
|
|
706
|
-
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, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflict, type OfflineConflictResult, type OfflineOperation, OfflineQueue, type OfflineQueueOptions, type OfflineQueueStorage, type OfflineResult, type OfflineSender, 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 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 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 SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, getOrderedSpots, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
|
720
|
+
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, LocalStorageAdapter, type LocalStorageAdapterOptions, type LocalStorageFailureMode, type LocaleDictionary, type LocalizedString, type LocalizedText, type MergeConflictOptions, type NfcDetectorOptions, type NfcVerificationContext, type OfflineConflict, type OfflineConflictResult, type OfflineOperation, 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 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 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 SyncState, THEME_PRESETS, type ThemePreset, type ThemePresetId, type UserRallyState, type ValidationError, type Validator, type VerificationContext, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, getOrderedSpots, 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, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
package/dist/index.js
CHANGED
|
@@ -97,6 +97,47 @@ function issueClaimTicketNumber(reward2, currentState, options = {}) {
|
|
|
97
97
|
return { ...currentState, claimTicketNumber };
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
// src/engine/sync.ts
|
|
101
|
+
function latestTimestamp(serverTimestamp, localTimestamp) {
|
|
102
|
+
const serverTime = Date.parse(serverTimestamp);
|
|
103
|
+
const localTime = Date.parse(localTimestamp);
|
|
104
|
+
if (!Number.isNaN(serverTime) && !Number.isNaN(localTime))
|
|
105
|
+
return serverTime >= localTime ? serverTimestamp : localTimestamp;
|
|
106
|
+
if (!Number.isNaN(serverTime)) return serverTimestamp;
|
|
107
|
+
if (!Number.isNaN(localTime)) return localTimestamp;
|
|
108
|
+
return serverTimestamp >= localTimestamp ? serverTimestamp : localTimestamp;
|
|
109
|
+
}
|
|
110
|
+
function mergeRewardStates(serverRewards, localRewards) {
|
|
111
|
+
const merged = new Map(serverRewards.map((reward2) => [reward2.rewardId, reward2]));
|
|
112
|
+
for (const localReward of localRewards) {
|
|
113
|
+
const serverReward = merged.get(localReward.rewardId);
|
|
114
|
+
if (serverReward === void 0) {
|
|
115
|
+
merged.set(localReward.rewardId, localReward);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (localReward.status === "CONSUMED" && serverReward.status !== "CONSUMED")
|
|
119
|
+
merged.set(localReward.rewardId, localReward);
|
|
120
|
+
}
|
|
121
|
+
return [...merged.values()];
|
|
122
|
+
}
|
|
123
|
+
function resolveRallyStateConflict(serverState, localState, options = { policy: "merge" }) {
|
|
124
|
+
if (options.policy === "server_wins") return serverState;
|
|
125
|
+
const records = [...serverState.records];
|
|
126
|
+
const knownStamps = new Set(records.map((record) => record.stampId));
|
|
127
|
+
for (const record of localState.records) {
|
|
128
|
+
if (!knownStamps.has(record.stampId)) {
|
|
129
|
+
records.push(record);
|
|
130
|
+
knownStamps.add(record.stampId);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
...serverState,
|
|
135
|
+
records,
|
|
136
|
+
rewards: mergeRewardStates(serverState.rewards, localState.rewards),
|
|
137
|
+
updatedAt: latestTimestamp(serverState.updatedAt, localState.updatedAt)
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
100
141
|
// src/detectors/types.ts
|
|
101
142
|
function createDetectorError(detector, code, message, cause) {
|
|
102
143
|
return cause === void 0 ? { detector, code, message } : { detector, code, message, cause };
|
|
@@ -998,6 +1039,7 @@ var StampRallyClient = class {
|
|
|
998
1039
|
this.#storage = this.#options.storage ?? new InMemoryStorage();
|
|
999
1040
|
this.#userId = this.#options.userId ?? null;
|
|
1000
1041
|
this.#offlineQueue = this.#options.offlineQueue;
|
|
1042
|
+
this.#offlineQueue?.setSyncResultListener((event) => this.#handleOfflineSyncResult(event));
|
|
1001
1043
|
}
|
|
1002
1044
|
getConfig() {
|
|
1003
1045
|
return this.#config;
|
|
@@ -1215,12 +1257,19 @@ var StampRallyClient = class {
|
|
|
1215
1257
|
});
|
|
1216
1258
|
}
|
|
1217
1259
|
if (adapter?.sync === void 0) {
|
|
1218
|
-
this.#emitEvent({ type: "sync", state: current });
|
|
1260
|
+
this.#emitEvent({ type: "sync", state: this.#state ?? current });
|
|
1219
1261
|
return;
|
|
1220
1262
|
}
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
|
|
1263
|
+
const serverState = await adapter.sync({
|
|
1264
|
+
rallyId: this.#config.id,
|
|
1265
|
+
userId: this.#userId,
|
|
1266
|
+
state: this.#state ?? current
|
|
1267
|
+
});
|
|
1268
|
+
const localState = this.#state ?? current;
|
|
1269
|
+
const merged = this.#offlineQueue === void 0 ? serverState : resolveRallyStateConflict(serverState, localState, {
|
|
1270
|
+
policy: this.#offlineQueue.conflictPolicy
|
|
1271
|
+
});
|
|
1272
|
+
const next = this.#reconcile(merged);
|
|
1224
1273
|
await this.#storage.save(next);
|
|
1225
1274
|
this.#state = next;
|
|
1226
1275
|
this.#emit(next);
|
|
@@ -1280,6 +1329,16 @@ var StampRallyClient = class {
|
|
|
1280
1329
|
)
|
|
1281
1330
|
};
|
|
1282
1331
|
}
|
|
1332
|
+
async #handleOfflineSyncResult(event) {
|
|
1333
|
+
if (event.state !== void 0) {
|
|
1334
|
+
const next = this.#reconcile(event.state);
|
|
1335
|
+
await this.#storage.save(next);
|
|
1336
|
+
this.#state = next;
|
|
1337
|
+
this.#emit(next);
|
|
1338
|
+
}
|
|
1339
|
+
if ("ok" in event.result && !event.result.ok)
|
|
1340
|
+
this.#emitEvent({ type: "error", error: event.result.error });
|
|
1341
|
+
}
|
|
1283
1342
|
#now() {
|
|
1284
1343
|
return this.#options.clock?.() ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1285
1344
|
}
|
|
@@ -1416,6 +1475,7 @@ var OfflineQueue = class {
|
|
|
1416
1475
|
#error = null;
|
|
1417
1476
|
#sender;
|
|
1418
1477
|
#syncPromise = null;
|
|
1478
|
+
#syncResultListener;
|
|
1419
1479
|
constructor(options = {}) {
|
|
1420
1480
|
if (options.storage !== void 0) this.#storage = options.storage;
|
|
1421
1481
|
else if (options.storageLike !== void 0 && options.storageLike !== null)
|
|
@@ -1437,6 +1497,12 @@ var OfflineQueue = class {
|
|
|
1437
1497
|
get operations() {
|
|
1438
1498
|
return this.#operations;
|
|
1439
1499
|
}
|
|
1500
|
+
get conflictPolicy() {
|
|
1501
|
+
return this.#conflictPolicy;
|
|
1502
|
+
}
|
|
1503
|
+
setSyncResultListener(listener) {
|
|
1504
|
+
this.#syncResultListener = listener;
|
|
1505
|
+
}
|
|
1440
1506
|
async initialize() {
|
|
1441
1507
|
if (this.#loaded) return;
|
|
1442
1508
|
this.#operations = [...await this.#storage.load(this.#key)];
|
|
@@ -1489,8 +1555,12 @@ var OfflineQueue = class {
|
|
|
1489
1555
|
} catch (cause) {
|
|
1490
1556
|
throw cause instanceof Error ? cause : new Error(String(cause));
|
|
1491
1557
|
}
|
|
1492
|
-
|
|
1493
|
-
|
|
1558
|
+
const state = "conflict" in result && result.conflict === true ? await this.resolveConflict(operation, result.localState, result.serverState) : "ok" in result && result.ok ? result.value.state : void 0;
|
|
1559
|
+
await this.#syncResultListener?.({
|
|
1560
|
+
operation,
|
|
1561
|
+
result,
|
|
1562
|
+
...state === void 0 ? {} : { state }
|
|
1563
|
+
});
|
|
1494
1564
|
this.#operations = this.#operations.slice(1);
|
|
1495
1565
|
await this.#storage.save(this.#key, this.#operations);
|
|
1496
1566
|
}
|
|
@@ -1504,9 +1574,7 @@ var OfflineQueue = class {
|
|
|
1504
1574
|
async resolveConflict(operation, localState, serverState) {
|
|
1505
1575
|
const configured = this.#onSyncConflict;
|
|
1506
1576
|
const policy = (typeof configured === "function" ? await configured({ operation, localState, serverState }) : configured) ?? this.#conflictPolicy;
|
|
1507
|
-
|
|
1508
|
-
return;
|
|
1509
|
-
}
|
|
1577
|
+
return resolveRallyStateConflict(serverState, localState, { policy });
|
|
1510
1578
|
}
|
|
1511
1579
|
};
|
|
1512
1580
|
|
|
@@ -2395,6 +2463,6 @@ async function verifySnapshotToken(token, secretKey, now = Date.now()) {
|
|
|
2395
2463
|
}
|
|
2396
2464
|
}
|
|
2397
2465
|
|
|
2398
|
-
export { ConfigValidationError, DEFAULT_SHEET_THEME, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, IndexedDBOfflineQueueStorage, LocalStorageAdapter, OfflineQueue, StampRallyClient, StorageAdapterError, THEME_PRESETS, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, getOrderedSpots, importProgressToken, isGeolocationSupported, isNfcSupported, isPublicConfig, isQrSupported, isRewardState, isStampRallyState, issueClaimTicketNumber, normalizePasscode, parseAdminConfig, parsePublicConfig, processStamp, readNfcContext, readQrContext, reconcileRewardStates, resolveLocalizedText, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
|
2466
|
+
export { ConfigValidationError, DEFAULT_SHEET_THEME, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, IndexedDBOfflineQueueStorage, LocalStorageAdapter, OfflineQueue, StampRallyClient, StorageAdapterError, THEME_PRESETS, assertPublicConfig, calculateDistanceMeters, calculateProgress, consumeReward, createClaimTicketNumber, createSecureToken, createSignedSnapshotToken, createUniqueClaimTicketNumber, evaluateCondition, evaluateConditionDetailed, exportProgressToken, getCurrentGeoContext, getOrderedSpots, 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, verifyPasscode, verifySecureToken, verifySnapshotToken };
|
|
2399
2467
|
//# sourceMappingURL=index.js.map
|
|
2400
2468
|
//# sourceMappingURL=index.js.map
|