@stamprally/core 0.15.0 → 0.16.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.js CHANGED
@@ -1135,6 +1135,18 @@ var StampRallyClient = class {
1135
1135
  get pendingCount() {
1136
1136
  return this.#offlineQueue?.pendingCount ?? 0;
1137
1137
  }
1138
+ get rejectedHistory() {
1139
+ return this.#offlineQueue?.rejectedHistory ?? [];
1140
+ }
1141
+ get queueCapability() {
1142
+ return this.#offlineQueue?.queueCapability ?? "custom";
1143
+ }
1144
+ discardRejected(operationId) {
1145
+ return this.#offlineQueue?.discardRejected(operationId) ?? Promise.resolve(false);
1146
+ }
1147
+ retryRejected(operationId) {
1148
+ return this.#offlineQueue?.retryRejected(operationId) ?? Promise.resolve(false);
1149
+ }
1138
1150
  subscribe(listener) {
1139
1151
  this.#listeners.add(listener);
1140
1152
  return () => this.#listeners.delete(listener);
@@ -1457,12 +1469,19 @@ var StampRallyClient = class {
1457
1469
  // src/client/offlineQueue.ts
1458
1470
  var MemoryQueueStorage = class {
1459
1471
  #values = /* @__PURE__ */ new Map();
1472
+ #rejected = /* @__PURE__ */ new Map();
1460
1473
  async load(key) {
1461
1474
  return this.#values.get(key) ?? [];
1462
1475
  }
1463
1476
  async save(key, operations) {
1464
1477
  this.#values.set(key, structuredClone(operations));
1465
1478
  }
1479
+ async loadRejectedHistory(key) {
1480
+ return this.#rejected.get(key) ?? [];
1481
+ }
1482
+ async saveRejectedHistory(key, history) {
1483
+ this.#rejected.set(key, structuredClone(history));
1484
+ }
1466
1485
  };
1467
1486
  var LocalStorageQueueStorage = class {
1468
1487
  constructor(storage) {
@@ -1482,6 +1501,19 @@ var LocalStorageQueueStorage = class {
1482
1501
  async save(key, operations) {
1483
1502
  this.storage.setItem(key, JSON.stringify(operations));
1484
1503
  }
1504
+ async loadRejectedHistory(key) {
1505
+ const value = this.storage.getItem(`${key}:rejected-history`);
1506
+ if (value === null) return [];
1507
+ try {
1508
+ const parsed = JSON.parse(value);
1509
+ return Array.isArray(parsed) ? parsed : [];
1510
+ } catch {
1511
+ return [];
1512
+ }
1513
+ }
1514
+ async saveRejectedHistory(key, history) {
1515
+ this.storage.setItem(`${key}:rejected-history`, JSON.stringify(history));
1516
+ }
1485
1517
  };
1486
1518
  var IndexedDBOfflineQueueStorage = class {
1487
1519
  #providedFactory;
@@ -1509,6 +1541,26 @@ var IndexedDBOfflineQueueStorage = class {
1509
1541
  transaction.onabort = () => reject(transaction.error ?? new Error("Offline queue write aborted."));
1510
1542
  });
1511
1543
  }
1544
+ async loadRejectedHistory(key) {
1545
+ const database = await this.#open();
1546
+ return new Promise((resolve, reject) => {
1547
+ const request = database.transaction("operations", "readonly").objectStore("operations").get(`${key}:rejected-history`);
1548
+ request.onsuccess = () => resolve(
1549
+ Array.isArray(request.result) ? request.result : []
1550
+ );
1551
+ request.onerror = () => reject(request.error ?? new Error("Failed to read rejected operation history."));
1552
+ });
1553
+ }
1554
+ async saveRejectedHistory(key, history) {
1555
+ const database = await this.#open();
1556
+ return new Promise((resolve, reject) => {
1557
+ const transaction = database.transaction("operations", "readwrite");
1558
+ transaction.objectStore("operations").put(structuredClone(history), `${key}:rejected-history`);
1559
+ transaction.oncomplete = () => resolve();
1560
+ transaction.onerror = () => reject(transaction.error ?? new Error("Failed to save rejected operation history."));
1561
+ transaction.onabort = () => reject(transaction.error ?? new Error("Rejected operation history write aborted."));
1562
+ });
1563
+ }
1512
1564
  #open() {
1513
1565
  if (this.#databasePromise !== null) return this.#databasePromise;
1514
1566
  let factory = this.#providedFactory;
@@ -1531,22 +1583,35 @@ var IndexedDBOfflineQueueStorage = class {
1531
1583
  return this.#databasePromise;
1532
1584
  }
1533
1585
  };
1586
+ function availableLocalStorage() {
1587
+ try {
1588
+ const storage = globalThis.localStorage;
1589
+ return storage ?? null;
1590
+ } catch {
1591
+ return null;
1592
+ }
1593
+ }
1534
1594
  function defaultStorage(databaseName) {
1535
1595
  try {
1536
1596
  const indexedDB = globalThis.indexedDB;
1537
1597
  if (indexedDB !== void 0)
1538
- return new IndexedDBOfflineQueueStorage({
1539
- indexedDB,
1540
- ...databaseName === void 0 ? {} : { databaseName }
1541
- });
1542
- const storage = globalThis.localStorage;
1543
- if (storage !== void 0 && storage !== null) return new LocalStorageQueueStorage(storage);
1598
+ return {
1599
+ storage: new IndexedDBOfflineQueueStorage({
1600
+ indexedDB,
1601
+ ...databaseName === void 0 ? {} : { databaseName }
1602
+ }),
1603
+ capability: "indexeddb"
1604
+ };
1605
+ const storage = availableLocalStorage();
1606
+ if (storage !== void 0 && storage !== null)
1607
+ return { storage: new LocalStorageQueueStorage(storage), capability: "localstorage" };
1544
1608
  } catch {
1545
1609
  }
1546
- return new MemoryQueueStorage();
1610
+ return { storage: new MemoryQueueStorage(), capability: "memory" };
1547
1611
  }
1548
- function operationId(operation) {
1549
- return operation.kind === "checkIn" ? `checkIn:${operation.request.rallyId}:${operation.request.userId ?? "anonymous"}:${operation.request.idempotencyKey}` : `claimReward:${operation.request.rallyId}:${operation.request.userId ?? "anonymous"}:${operation.request.idempotencyKey}`;
1612
+ function offlineOperationId(operation) {
1613
+ const identity = operation.request.userId ?? operation.request.anonymousSessionId ?? "anonymous";
1614
+ return operation.kind === "checkIn" ? `checkIn:${operation.request.rallyId}:${identity}:${operation.request.idempotencyKey}` : `claimReward:${operation.request.rallyId}:${identity}:${operation.request.idempotencyKey}`;
1550
1615
  }
1551
1616
  function requestScope(operation) {
1552
1617
  return {
@@ -1576,12 +1641,14 @@ function randomId() {
1576
1641
  }
1577
1642
  var OfflineQueue = class {
1578
1643
  #storage;
1644
+ #queueCapability;
1579
1645
  #configuredKey;
1580
1646
  #rallyId;
1581
1647
  #userId;
1582
1648
  #conflictPolicy;
1583
1649
  #onSyncConflict;
1584
1650
  #operations = [];
1651
+ #rejectedHistory = [];
1585
1652
  #loaded = false;
1586
1653
  #state = "idle";
1587
1654
  #error = null;
@@ -1592,13 +1659,22 @@ var OfflineQueue = class {
1592
1659
  #retryOptions;
1593
1660
  #instanceId = randomId();
1594
1661
  #lockStorage;
1662
+ #observedLocks = /* @__PURE__ */ new Map();
1663
+ #warnedMemoryLock = false;
1595
1664
  #storageListener;
1596
1665
  #channel = null;
1597
1666
  constructor(options = {}) {
1598
- if (options.storage !== void 0) this.#storage = options.storage;
1599
- else if (options.storageLike !== void 0 && options.storageLike !== null)
1667
+ if (options.storage !== void 0) {
1668
+ this.#storage = options.storage;
1669
+ this.#queueCapability = "custom";
1670
+ } else if (options.storageLike !== void 0 && options.storageLike !== null) {
1600
1671
  this.#storage = new LocalStorageQueueStorage(options.storageLike);
1601
- else this.#storage = defaultStorage(options.databaseName);
1672
+ this.#queueCapability = "localstorage";
1673
+ } else {
1674
+ const selected = defaultStorage(options.databaseName);
1675
+ this.#storage = selected.storage;
1676
+ this.#queueCapability = selected.capability;
1677
+ }
1602
1678
  this.#configuredKey = options.key;
1603
1679
  this.#rallyId = options.rallyId;
1604
1680
  this.#userId = options.userId ?? null;
@@ -1614,7 +1690,7 @@ var OfflineQueue = class {
1614
1690
  initialIntervalMs: Math.max(0, retryOptions.initialIntervalMs),
1615
1691
  backoffMultiplier: Math.max(1, retryOptions.backoffMultiplier)
1616
1692
  };
1617
- this.#lockStorage = options.storageLike ?? globalThis.localStorage ?? null;
1693
+ this.#lockStorage = options.storageLike ?? availableLocalStorage();
1618
1694
  if (this.#synchronizeInstances) this.#subscribeToExternalChanges();
1619
1695
  }
1620
1696
  get syncState() {
@@ -1623,6 +1699,12 @@ var OfflineQueue = class {
1623
1699
  get pendingCount() {
1624
1700
  return this.#operations.length;
1625
1701
  }
1702
+ get queueCapability() {
1703
+ return this.#queueCapability;
1704
+ }
1705
+ get rejectedHistory() {
1706
+ return this.#rejectedHistory;
1707
+ }
1626
1708
  get error() {
1627
1709
  return this.#error;
1628
1710
  }
@@ -1646,7 +1728,20 @@ var OfflineQueue = class {
1646
1728
  }
1647
1729
  async initialize() {
1648
1730
  if (this.#loaded) return;
1649
- this.#operations = (await this.#storage.load(this.#storageKey())).map(normalizeOperation);
1731
+ try {
1732
+ const key = this.#storageKey();
1733
+ this.#operations = (await this.#storage.load(key)).map(normalizeOperation);
1734
+ this.#rejectedHistory = (await this.#storage.loadRejectedHistory?.(key))?.map(normalizeRejectedHistory) ?? [];
1735
+ } catch (error) {
1736
+ if (this.#queueCapability === "memory") throw error;
1737
+ this.#storage = new MemoryQueueStorage();
1738
+ this.#queueCapability = "memory";
1739
+ this.#operations = [];
1740
+ this.#rejectedHistory = [];
1741
+ this.#warnMemoryLock(
1742
+ `Offline queue persistence is unavailable; queued data can be lost after reload (${String(error)}).`
1743
+ );
1744
+ }
1650
1745
  this.#loaded = true;
1651
1746
  }
1652
1747
  /** Releases browser listeners when the queue is no longer used. */
@@ -1689,8 +1784,8 @@ var OfflineQueue = class {
1689
1784
  throw new Error("Offline operation belongs to another rally or user queue.");
1690
1785
  }
1691
1786
  await this.initialize();
1692
- const id2 = operationId(operation);
1693
- if (this.#operations.some((item) => operationId(item) === id2)) return;
1787
+ const id2 = offlineOperationId(operation);
1788
+ if (this.#operations.some((item) => offlineOperationId(item) === id2)) return;
1694
1789
  this.#operations = [...this.#operations, { ...operation, status: "PENDING", attempts: 0 }];
1695
1790
  await this.#storage.save(this.#storageKey(), this.#operations);
1696
1791
  this.#announceChange();
@@ -1707,6 +1802,47 @@ var OfflineQueue = class {
1707
1802
  await this.#storage.save(this.#storageKey(), this.#operations);
1708
1803
  this.#announceChange();
1709
1804
  }
1805
+ async discardRejected(operationId) {
1806
+ await this.initialize();
1807
+ const next = this.#rejectedHistory.filter(
1808
+ (entry) => offlineOperationId(entry.operation) !== operationId
1809
+ );
1810
+ if (next.length === this.#rejectedHistory.length) return false;
1811
+ this.#rejectedHistory = next;
1812
+ await this.#saveRejectedHistory();
1813
+ this.#announceChange();
1814
+ return true;
1815
+ }
1816
+ async retryRejected(operationId) {
1817
+ await this.initialize();
1818
+ const entry = this.#rejectedHistory.find(
1819
+ (candidate) => offlineOperationId(candidate.operation) === operationId
1820
+ );
1821
+ if (entry === void 0) return false;
1822
+ if (!this.#operations.some((operation) => offlineOperationId(operation) === operationId))
1823
+ this.#operations = [
1824
+ ...this.#operations,
1825
+ { ...entry.operation, status: "PENDING", attempts: 0 }
1826
+ ];
1827
+ this.#rejectedHistory = this.#rejectedHistory.filter((candidate) => candidate !== entry);
1828
+ await this.#storage.save(this.#storageKey(), this.#operations);
1829
+ await this.#saveRejectedHistory();
1830
+ this.#announceChange();
1831
+ return true;
1832
+ }
1833
+ async discardRejectedOperation(operationId) {
1834
+ return this.discardRejected(operationId);
1835
+ }
1836
+ async retryRejectedOperation(operationId) {
1837
+ return this.retryRejected(operationId);
1838
+ }
1839
+ async clearRejectedHistory() {
1840
+ await this.initialize();
1841
+ if (this.#rejectedHistory.length === 0) return;
1842
+ this.#rejectedHistory = [];
1843
+ await this.#saveRejectedHistory();
1844
+ this.#announceChange();
1845
+ }
1710
1846
  async sync(sender = this.#sender) {
1711
1847
  await this.initialize();
1712
1848
  if (sender === void 0) throw new Error("OfflineQueue.sync requires a sender.");
@@ -1722,7 +1858,7 @@ var OfflineQueue = class {
1722
1858
  }
1723
1859
  async #run(sender) {
1724
1860
  const locks = globalThis.navigator?.locks;
1725
- if (locks !== void 0) {
1861
+ if (locks !== void 0 && typeof locks.request === "function") {
1726
1862
  let callbackStarted = false;
1727
1863
  try {
1728
1864
  const acquired = await locks.request(
@@ -1745,6 +1881,10 @@ var OfflineQueue = class {
1745
1881
  if (callbackStarted) throw error;
1746
1882
  }
1747
1883
  }
1884
+ if (this.#lockStorage === null)
1885
+ this.#warnMemoryLock(
1886
+ "No cross-tab storage lock is available; offline sync is single-tab only."
1887
+ );
1748
1888
  await this.#runWithStorageLock(sender);
1749
1889
  }
1750
1890
  async #runWithStorageLock(sender) {
@@ -1775,20 +1915,38 @@ var OfflineQueue = class {
1775
1915
  const error2 = errorValue(response.error ?? response.reason, "RETRYABLE_ERROR");
1776
1916
  await this.#updateOperationStatus("PENDING", attempt + 1);
1777
1917
  await this.#syncResultListener?.({ operation, status: response.status, error: error2 });
1778
- if (attempt >= this.#retryOptions.maxRetries) throw new Error(error2.message);
1918
+ if (attempt >= this.#retryOptions.maxRetries) {
1919
+ await this.#updateOperationStatus("FAILED_RETRYABLE", attempt + 1);
1920
+ throw new Error(error2.message);
1921
+ }
1779
1922
  const interval = this.#retryOptions.initialIntervalMs * this.#retryOptions.backoffMultiplier ** attempt;
1780
1923
  await new Promise((resolve) => setTimeout(resolve, Math.max(0, interval)));
1781
1924
  attempt += 1;
1782
1925
  }
1783
1926
  const result = response.result;
1784
- const state = response.state ?? (result !== void 0 && "conflict" in result && result.conflict === true ? await this.resolveConflict(operation, result.localState, result.serverState) : result !== void 0 && "ok" in result && result.ok ? result.value.state : void 0);
1785
- const error = response.status === "REJECTED_PERMANENT" ? errorValue(response.error ?? response.reason, "REJECTED_PERMANENT") : void 0;
1927
+ const state = response.state ?? (result !== void 0 && "conflict" in result && result.conflict === true ? result.serverState : result !== void 0 && "ok" in result && result.ok ? result.value.state : void 0);
1928
+ const error = response.status === "REJECTED_PERMANENT" ? errorValue(
1929
+ response.error ?? response.reason ?? (result !== void 0 && "ok" in result && !result.ok ? result.error : void 0),
1930
+ "REJECTED_PERMANENT"
1931
+ ) : void 0;
1786
1932
  await this.#updateOperationStatus(
1787
- response.status === "ACCEPTED" ? "ACCEPTED" : "REJECTED",
1933
+ response.status === "ACCEPTED" ? "ACCEPTED" : "REJECTED_PERMANENT",
1788
1934
  attempt + 1
1789
1935
  );
1790
- const fallbackState = response.status === "REJECTED_PERMANENT" ? operation.request.state : void 0;
1791
- const eventState = state ?? fallbackState;
1936
+ const eventState = state;
1937
+ if (response.status === "REJECTED_PERMANENT" && error !== void 0) {
1938
+ this.#rejectedHistory = [
1939
+ ...this.#rejectedHistory,
1940
+ {
1941
+ operation: { ...operation, status: "REJECTED_PERMANENT", attempts: attempt + 1 },
1942
+ reason: error,
1943
+ errorCode: error.code,
1944
+ rejectedAt: (/* @__PURE__ */ new Date()).toISOString(),
1945
+ attempts: attempt + 1
1946
+ }
1947
+ ];
1948
+ await this.#saveRejectedHistory();
1949
+ }
1792
1950
  this.#operations = this.#operations.slice(1);
1793
1951
  await this.#storage.save(this.#storageKey(), this.#operations);
1794
1952
  this.#announceChange();
@@ -1820,7 +1978,8 @@ var OfflineQueue = class {
1820
1978
  const windowLike = globalThis.window;
1821
1979
  if (windowLike !== void 0) {
1822
1980
  this.#storageListener = (event) => {
1823
- if (event.key === this.#storageKey()) void this.#reloadFromStorage();
1981
+ if (event.key === this.#storageKey() || event.key === `${this.#storageKey()}:rejected-history`)
1982
+ void this.#reloadFromStorage();
1824
1983
  };
1825
1984
  windowLike.addEventListener("storage", this.#storageListener);
1826
1985
  }
@@ -1829,6 +1988,20 @@ var OfflineQueue = class {
1829
1988
  try {
1830
1989
  this.#channel = new Channel("stamprally:queue-sync");
1831
1990
  this.#channel.addEventListener("message", (event) => {
1991
+ if (typeof event.data === "object" && event.data !== null) {
1992
+ const data = event.data;
1993
+ if (data.type === "lock" && data.lockKey === this.#lockKey()) {
1994
+ this.#observedLocks.set(data.lockKey, {
1995
+ owner: typeof data.owner === "string" ? data.owner : "unknown",
1996
+ expiresAt: typeof data.expiresAt === "number" ? data.expiresAt : 0
1997
+ });
1998
+ return;
1999
+ }
2000
+ if (data.type === "unlock" && data.lockKey === this.#lockKey()) {
2001
+ this.#observedLocks.delete(data.lockKey);
2002
+ return;
2003
+ }
2004
+ }
1832
2005
  if (typeof event.data === "object" && event.data !== null && "key" in event.data && event.data.key === this.#storageKey())
1833
2006
  void this.#reloadFromStorage();
1834
2007
  });
@@ -1838,12 +2011,18 @@ var OfflineQueue = class {
1838
2011
  }
1839
2012
  }
1840
2013
  #announceChange() {
1841
- this.#channel?.postMessage({ key: this.#storageKey(), owner: this.#instanceId });
2014
+ this.#channel?.postMessage({
2015
+ type: "change",
2016
+ key: this.#storageKey(),
2017
+ owner: this.#instanceId
2018
+ });
1842
2019
  }
1843
2020
  async #reloadFromStorage() {
1844
2021
  if (this.#state === "syncing") return;
1845
2022
  try {
1846
- this.#operations = (await this.#storage.load(this.#storageKey())).map(normalizeOperation);
2023
+ const key = this.#storageKey();
2024
+ this.#operations = (await this.#storage.load(key)).map(normalizeOperation);
2025
+ this.#rejectedHistory = (await this.#storage.loadRejectedHistory?.(key))?.map(normalizeRejectedHistory) ?? this.#rejectedHistory;
1847
2026
  this.#loaded = true;
1848
2027
  } catch {
1849
2028
  }
@@ -1857,6 +2036,9 @@ var OfflineQueue = class {
1857
2036
  const local = syncLocks.get(key);
1858
2037
  if (local !== void 0 && local.expiresAt > now && local.owner !== this.#instanceId)
1859
2038
  return false;
2039
+ const observed = this.#observedLocks.get(key);
2040
+ if (observed !== void 0 && observed.expiresAt > now && observed.owner !== this.#instanceId)
2041
+ return false;
1860
2042
  if (this.#lockStorage !== null) {
1861
2043
  try {
1862
2044
  const existing = this.#lockStorage.getItem(key);
@@ -1869,7 +2051,14 @@ var OfflineQueue = class {
1869
2051
  key,
1870
2052
  JSON.stringify({ owner: this.#instanceId, expiresAt: now + SYNC_LOCK_TTL_MS })
1871
2053
  );
2054
+ this.#channel?.postMessage({
2055
+ type: "lock",
2056
+ lockKey: key,
2057
+ owner: this.#instanceId,
2058
+ expiresAt: now + SYNC_LOCK_TTL_MS
2059
+ });
1872
2060
  } catch {
2061
+ this.#warnMemoryLock("Persistent lock access failed; offline sync is single-tab only.");
1873
2062
  }
1874
2063
  }
1875
2064
  syncLocks.set(key, { owner: this.#instanceId, expiresAt: now + SYNC_LOCK_TTL_MS });
@@ -1884,6 +2073,7 @@ var OfflineQueue = class {
1884
2073
  const value = this.#lockStorage.getItem(key);
1885
2074
  if (value !== null && JSON.parse(value).owner === this.#instanceId)
1886
2075
  this.#lockStorage.removeItem?.(key);
2076
+ this.#channel?.postMessage({ type: "unlock", lockKey: key, owner: this.#instanceId });
1887
2077
  } catch {
1888
2078
  }
1889
2079
  }
@@ -1912,14 +2102,33 @@ var OfflineQueue = class {
1912
2102
  const policy = (typeof configured === "function" ? await configured({ operation, localState, serverState }) : configured) ?? this.#conflictPolicy;
1913
2103
  return resolveRallyStateConflict(serverState, localState, { policy });
1914
2104
  }
2105
+ async #saveRejectedHistory() {
2106
+ await this.#storage.saveRejectedHistory?.(this.#storageKey(), this.#rejectedHistory);
2107
+ }
2108
+ #warnMemoryLock(message) {
2109
+ if (this.#warnedMemoryLock) return;
2110
+ this.#warnedMemoryLock = true;
2111
+ console.warn(`[@stamprally/core] ${message}`);
2112
+ }
1915
2113
  };
1916
2114
  function normalizeOperation(operation) {
2115
+ const status = operation.status;
1917
2116
  return {
1918
2117
  ...operation,
1919
- status: operation.status === "IN_FLIGHT" ? "PENDING" : operation.status ?? "PENDING",
2118
+ status: status === "IN_FLIGHT" || status === "REJECTED" ? "PENDING" : status === "RETRYABLE_ERROR" ? "FAILED_RETRYABLE" : operation.status ?? "PENDING",
1920
2119
  attempts: operation.attempts ?? 0
1921
2120
  };
1922
2121
  }
2122
+ function normalizeRejectedHistory(entry) {
2123
+ return {
2124
+ ...entry,
2125
+ operation: normalizeOperation(entry.operation),
2126
+ reason: errorValue(entry.reason, "REJECTED_PERMANENT"),
2127
+ errorCode: entry.errorCode || entry.reason.code,
2128
+ rejectedAt: entry.rejectedAt || (/* @__PURE__ */ new Date(0)).toISOString(),
2129
+ attempts: entry.attempts ?? entry.operation.attempts ?? 0
2130
+ };
2131
+ }
1923
2132
 
1924
2133
  // src/crypto/token.ts
1925
2134
  var encoder = new TextEncoder();
@@ -2900,6 +3109,6 @@ async function verifySnapshotToken(token, secretKey, now = Date.now()) {
2900
3109
  }
2901
3110
  }
2902
3111
 
2903
- export { ConfigValidationError, DEFAULT_SHEET_THEME, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, IndexedDBOfflineQueueStorage, LocalStorageAdapter, OfflineQueue, StampRallyClient, StorageAdapterError, THEME_PRESETS, 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 };
3112
+ export { ConfigValidationError, DEFAULT_SHEET_THEME, MemoryQueueStorage as InMemoryOfflineQueueStorage, InMemoryStorage, IndexedDBAdapter, IndexedDBOfflineQueueStorage, LocalStorageAdapter, OfflineQueue, StampRallyClient, StorageAdapterError, THEME_PRESETS, 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, safeParseAdminConfig, safeParsePublicConfig, sanitizeAdminConfig, storageKey, toLocalizedString, toPublicConfig, updateLocalizedField, validatePublicConfigSafety, validateRallyConfigRelations, verifyPasscode, verifySecureToken, verifySnapshotToken };
2904
3113
  //# sourceMappingURL=index.js.map
2905
3114
  //# sourceMappingURL=index.js.map