achievements-engine 1.0.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 +363 -0
- package/dist/index.cjs +1699 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +635 -0
- package/dist/index.esm.js +1677 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +1672 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +1705 -0
- package/dist/index.umd.js.map +1 -0
- package/package.json +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight, type-safe event emitter for the achievements engine
|
|
3
|
+
* Zero dependencies, memory-leak safe implementation
|
|
4
|
+
*/
|
|
5
|
+
type EventHandler$1<T = any> = (data: T) => void;
|
|
6
|
+
type UnsubscribeFn = () => void;
|
|
7
|
+
declare class EventEmitter {
|
|
8
|
+
private listeners;
|
|
9
|
+
private onceListeners;
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Subscribe to an event
|
|
13
|
+
* @param event - Event name
|
|
14
|
+
* @param handler - Event handler function
|
|
15
|
+
* @returns Unsubscribe function
|
|
16
|
+
*/
|
|
17
|
+
on<T = any>(event: string, handler: EventHandler$1<T>): UnsubscribeFn;
|
|
18
|
+
/**
|
|
19
|
+
* Subscribe to an event once (auto-unsubscribes after first emission)
|
|
20
|
+
* @param event - Event name
|
|
21
|
+
* @param handler - Event handler function
|
|
22
|
+
* @returns Unsubscribe function
|
|
23
|
+
*/
|
|
24
|
+
once<T = any>(event: string, handler: EventHandler$1<T>): UnsubscribeFn;
|
|
25
|
+
/**
|
|
26
|
+
* Unsubscribe from an event
|
|
27
|
+
* @param event - Event name
|
|
28
|
+
* @param handler - Event handler function to remove
|
|
29
|
+
*/
|
|
30
|
+
off<T = any>(event: string, handler: EventHandler$1<T>): void;
|
|
31
|
+
/**
|
|
32
|
+
* Emit an event to all subscribers
|
|
33
|
+
* @param event - Event name
|
|
34
|
+
* @param data - Event payload
|
|
35
|
+
*/
|
|
36
|
+
emit<T = any>(event: string, data?: T): void;
|
|
37
|
+
/**
|
|
38
|
+
* Remove all listeners for a specific event, or all events if no event specified
|
|
39
|
+
* @param event - Optional event name. If not provided, removes all listeners.
|
|
40
|
+
*/
|
|
41
|
+
removeAllListeners(event?: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Get the number of listeners for an event
|
|
44
|
+
* @param event - Event name
|
|
45
|
+
* @returns Number of listeners
|
|
46
|
+
*/
|
|
47
|
+
listenerCount(event: string): number;
|
|
48
|
+
/**
|
|
49
|
+
* Get all event names that have listeners
|
|
50
|
+
* @returns Array of event names
|
|
51
|
+
*/
|
|
52
|
+
eventNames(): string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Type definitions for the achievements engine
|
|
57
|
+
* Framework-agnostic achievement system types
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
type AchievementMetricValue = number | string | boolean | Date | null | undefined;
|
|
61
|
+
type AchievementMetricArrayValue = AchievementMetricValue | AchievementMetricValue[];
|
|
62
|
+
interface AchievementMetrics {
|
|
63
|
+
[key: string]: AchievementMetricValue[];
|
|
64
|
+
}
|
|
65
|
+
interface AchievementDetails {
|
|
66
|
+
achievementId: string;
|
|
67
|
+
achievementTitle: string;
|
|
68
|
+
achievementDescription: string;
|
|
69
|
+
achievementIconKey?: string;
|
|
70
|
+
}
|
|
71
|
+
interface AchievementWithStatus extends AchievementDetails {
|
|
72
|
+
isUnlocked: boolean;
|
|
73
|
+
}
|
|
74
|
+
interface AchievementCondition {
|
|
75
|
+
isConditionMet: (value: AchievementMetricArrayValue, state: AchievementState) => boolean;
|
|
76
|
+
achievementDetails: AchievementDetails | AchievementWithStatus;
|
|
77
|
+
}
|
|
78
|
+
interface AchievementConfiguration {
|
|
79
|
+
[key: string]: AchievementCondition[];
|
|
80
|
+
}
|
|
81
|
+
interface SimpleAchievementDetails {
|
|
82
|
+
title: string;
|
|
83
|
+
description?: string;
|
|
84
|
+
icon?: string;
|
|
85
|
+
}
|
|
86
|
+
interface CustomAchievementDetails extends SimpleAchievementDetails {
|
|
87
|
+
condition: (metrics: Record<string, any>) => boolean;
|
|
88
|
+
}
|
|
89
|
+
interface SimpleAchievementConfig {
|
|
90
|
+
[metric: string]: {
|
|
91
|
+
[threshold: string]: SimpleAchievementDetails | CustomAchievementDetails;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
type AchievementConfigurationType = AchievementConfiguration | SimpleAchievementConfig;
|
|
95
|
+
interface InitialAchievementMetrics {
|
|
96
|
+
[key: string]: AchievementMetricValue;
|
|
97
|
+
}
|
|
98
|
+
interface AchievementState {
|
|
99
|
+
metrics: AchievementMetrics;
|
|
100
|
+
unlockedAchievements: string[];
|
|
101
|
+
}
|
|
102
|
+
interface AchievementStorage {
|
|
103
|
+
getMetrics(): AchievementMetrics;
|
|
104
|
+
setMetrics(metrics: AchievementMetrics): void;
|
|
105
|
+
getUnlockedAchievements(): string[];
|
|
106
|
+
setUnlockedAchievements(achievements: string[]): void;
|
|
107
|
+
clear(): void;
|
|
108
|
+
}
|
|
109
|
+
interface AsyncAchievementStorage {
|
|
110
|
+
getMetrics(): Promise<AchievementMetrics>;
|
|
111
|
+
setMetrics(metrics: AchievementMetrics): Promise<void>;
|
|
112
|
+
getUnlockedAchievements(): Promise<string[]>;
|
|
113
|
+
setUnlockedAchievements(achievements: string[]): Promise<void>;
|
|
114
|
+
clear(): Promise<void>;
|
|
115
|
+
}
|
|
116
|
+
type AnyAchievementStorage = AchievementStorage | AsyncAchievementStorage;
|
|
117
|
+
declare function isAsyncStorage(storage: AnyAchievementStorage): storage is AsyncAchievementStorage;
|
|
118
|
+
declare enum StorageType {
|
|
119
|
+
Local = "local",// Synchronous localStorage
|
|
120
|
+
Memory = "memory",// Synchronous in-memory storage
|
|
121
|
+
IndexedDB = "indexeddb",// Asynchronous IndexedDB storage
|
|
122
|
+
RestAPI = "restapi"
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Event types emitted by the engine
|
|
126
|
+
*/
|
|
127
|
+
type EngineEvent = 'achievement:unlocked' | 'metric:updated' | 'state:changed' | 'error';
|
|
128
|
+
/**
|
|
129
|
+
* Event payload when an achievement is unlocked
|
|
130
|
+
*/
|
|
131
|
+
interface AchievementUnlockedEvent {
|
|
132
|
+
achievementId: string;
|
|
133
|
+
achievementTitle: string;
|
|
134
|
+
achievementDescription: string;
|
|
135
|
+
achievementIconKey?: string;
|
|
136
|
+
timestamp: number;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Event payload when a metric is updated
|
|
140
|
+
*/
|
|
141
|
+
interface MetricUpdatedEvent {
|
|
142
|
+
metric: string;
|
|
143
|
+
oldValue: any;
|
|
144
|
+
newValue: any;
|
|
145
|
+
timestamp: number;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Event payload when overall state changes
|
|
149
|
+
*/
|
|
150
|
+
interface StateChangedEvent {
|
|
151
|
+
metrics: AchievementMetrics;
|
|
152
|
+
unlocked: string[];
|
|
153
|
+
timestamp: number;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Event payload when an error occurs
|
|
157
|
+
*/
|
|
158
|
+
interface ErrorEvent {
|
|
159
|
+
error: Error;
|
|
160
|
+
context?: string;
|
|
161
|
+
timestamp: number;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Event handler type
|
|
165
|
+
*/
|
|
166
|
+
type EventHandler<T = any> = (data: T) => void;
|
|
167
|
+
/**
|
|
168
|
+
* Metric updater function for custom event-to-metric mapping
|
|
169
|
+
*/
|
|
170
|
+
type MetricUpdater = (eventData: any, currentMetrics: Record<string, any>) => Record<string, any>;
|
|
171
|
+
/**
|
|
172
|
+
* Event mapping configuration
|
|
173
|
+
* Maps event names to either:
|
|
174
|
+
* - String (metric name) for direct 1:1 mapping
|
|
175
|
+
* - MetricUpdater function for custom transformation
|
|
176
|
+
*/
|
|
177
|
+
interface EventMapping {
|
|
178
|
+
[eventName: string]: string | MetricUpdater;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* REST API storage configuration
|
|
182
|
+
*/
|
|
183
|
+
interface RestApiStorageConfig$1 {
|
|
184
|
+
baseUrl: string;
|
|
185
|
+
userId: string;
|
|
186
|
+
headers?: Record<string, string>;
|
|
187
|
+
timeout?: number;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Configuration for the Achievement Engine
|
|
191
|
+
*/
|
|
192
|
+
interface EngineConfig {
|
|
193
|
+
/**
|
|
194
|
+
* Achievement configuration (Simple or Complex API format)
|
|
195
|
+
*/
|
|
196
|
+
achievements: AchievementConfigurationType;
|
|
197
|
+
/**
|
|
198
|
+
* Storage implementation or storage type
|
|
199
|
+
* Defaults to memory storage
|
|
200
|
+
*/
|
|
201
|
+
storage?: AchievementStorage | AsyncAchievementStorage | StorageType;
|
|
202
|
+
/**
|
|
203
|
+
* Optional event-to-metric mapping
|
|
204
|
+
* Enables event-based tracking with emit()
|
|
205
|
+
*/
|
|
206
|
+
eventMapping?: EventMapping;
|
|
207
|
+
/**
|
|
208
|
+
* Error handler for async operations and achievement errors
|
|
209
|
+
*/
|
|
210
|
+
onError?: (error: Error) => void;
|
|
211
|
+
/**
|
|
212
|
+
* REST API configuration (required if using StorageType.RestAPI)
|
|
213
|
+
*/
|
|
214
|
+
restApiConfig?: RestApiStorageConfig$1;
|
|
215
|
+
}
|
|
216
|
+
interface ImportOptions$1 {
|
|
217
|
+
merge?: boolean;
|
|
218
|
+
overwrite?: boolean;
|
|
219
|
+
validateConfig?: boolean;
|
|
220
|
+
expectedConfigHash?: string;
|
|
221
|
+
}
|
|
222
|
+
interface ImportResult$1 {
|
|
223
|
+
success: boolean;
|
|
224
|
+
errors?: string[];
|
|
225
|
+
warnings?: string[];
|
|
226
|
+
mergedMetrics?: AchievementMetrics;
|
|
227
|
+
mergedUnlocked?: string[];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Public API surface of the AchievementEngine
|
|
231
|
+
* This type represents the stable, supported API for external consumers
|
|
232
|
+
* Derived from the AchievementEngine class to prevent duplication
|
|
233
|
+
*/
|
|
234
|
+
type AchievementEngineApi = Pick<AchievementEngine, 'emit' | 'update' | 'on' | 'once' | 'off' | 'getMetrics' | 'getUnlocked' | 'getAllAchievements' | 'reset' | 'export' | 'import'>;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* AchievementEngine - Framework-agnostic achievement system
|
|
238
|
+
* Event-based core with support for multiple storage backends
|
|
239
|
+
*/
|
|
240
|
+
|
|
241
|
+
declare class AchievementEngine extends EventEmitter {
|
|
242
|
+
private config;
|
|
243
|
+
private achievements;
|
|
244
|
+
private storage;
|
|
245
|
+
private metrics;
|
|
246
|
+
private unlockedAchievements;
|
|
247
|
+
private configHash;
|
|
248
|
+
constructor(config: EngineConfig);
|
|
249
|
+
/**
|
|
250
|
+
* Initialize storage based on configuration
|
|
251
|
+
*/
|
|
252
|
+
private initializeStorage;
|
|
253
|
+
/**
|
|
254
|
+
* Load state from storage
|
|
255
|
+
*/
|
|
256
|
+
private loadFromStorage;
|
|
257
|
+
/**
|
|
258
|
+
* Save state to storage
|
|
259
|
+
*/
|
|
260
|
+
private saveToStorage;
|
|
261
|
+
/**
|
|
262
|
+
* Handle errors with optional callback
|
|
263
|
+
*/
|
|
264
|
+
private handleError;
|
|
265
|
+
/**
|
|
266
|
+
* Emit a custom event and optionally update metrics based on event mapping
|
|
267
|
+
* @param eventName - Name of the event
|
|
268
|
+
* @param data - Event data
|
|
269
|
+
*/
|
|
270
|
+
emit<T = any>(eventName: string, data?: T): void;
|
|
271
|
+
/**
|
|
272
|
+
* Update metrics and evaluate achievements
|
|
273
|
+
* @param newMetrics - Metrics to update
|
|
274
|
+
*/
|
|
275
|
+
update(newMetrics: Record<string, any>): void;
|
|
276
|
+
/**
|
|
277
|
+
* Evaluate all achievements and unlock any newly met conditions
|
|
278
|
+
* This is the core evaluation logic extracted from AchievementProvider
|
|
279
|
+
*/
|
|
280
|
+
private evaluateAchievements;
|
|
281
|
+
/**
|
|
282
|
+
* Get metrics in array format (for backward compatibility with storage)
|
|
283
|
+
*/
|
|
284
|
+
private getMetricsAsArray;
|
|
285
|
+
/**
|
|
286
|
+
* Get current metrics (readonly to prevent external modification)
|
|
287
|
+
*/
|
|
288
|
+
getMetrics(): Readonly<Record<string, any>>;
|
|
289
|
+
/**
|
|
290
|
+
* Get unlocked achievement IDs (readonly)
|
|
291
|
+
*/
|
|
292
|
+
getUnlocked(): readonly string[];
|
|
293
|
+
/**
|
|
294
|
+
* Get all achievements with their unlock status
|
|
295
|
+
*/
|
|
296
|
+
getAllAchievements(): AchievementWithStatus[];
|
|
297
|
+
/**
|
|
298
|
+
* Reset all achievement data
|
|
299
|
+
*/
|
|
300
|
+
reset(): void;
|
|
301
|
+
/**
|
|
302
|
+
* Clean up resources and event listeners
|
|
303
|
+
*/
|
|
304
|
+
destroy(): void;
|
|
305
|
+
/**
|
|
306
|
+
* Export achievement data as JSON string
|
|
307
|
+
*/
|
|
308
|
+
export(): string;
|
|
309
|
+
/**
|
|
310
|
+
* Import achievement data from JSON string
|
|
311
|
+
* @param jsonString - Exported achievement data
|
|
312
|
+
* @param options - Import options
|
|
313
|
+
*/
|
|
314
|
+
import(jsonString: string, options?: ImportOptions$1): ImportResult$1;
|
|
315
|
+
/**
|
|
316
|
+
* Subscribe to engine events
|
|
317
|
+
* @param event - Event name
|
|
318
|
+
* @param handler - Event handler
|
|
319
|
+
*/
|
|
320
|
+
on(event: EngineEvent, handler: (data: any) => void): UnsubscribeFn;
|
|
321
|
+
/**
|
|
322
|
+
* Subscribe to an event once
|
|
323
|
+
* @param event - Event name
|
|
324
|
+
* @param handler - Event handler
|
|
325
|
+
*/
|
|
326
|
+
once(event: EngineEvent, handler: (data: any) => void): UnsubscribeFn;
|
|
327
|
+
/**
|
|
328
|
+
* Unsubscribe from an event
|
|
329
|
+
* @param event - Event name
|
|
330
|
+
* @param handler - Event handler
|
|
331
|
+
*/
|
|
332
|
+
off(event: EngineEvent, handler: (data: any) => void): void;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
declare class LocalStorage implements AchievementStorage {
|
|
336
|
+
private storageKey;
|
|
337
|
+
constructor(storageKey: string);
|
|
338
|
+
private serializeValue;
|
|
339
|
+
private deserializeValue;
|
|
340
|
+
private serializeMetrics;
|
|
341
|
+
private deserializeMetrics;
|
|
342
|
+
private getStorageData;
|
|
343
|
+
private setStorageData;
|
|
344
|
+
getMetrics(): AchievementMetrics;
|
|
345
|
+
setMetrics(metrics: AchievementMetrics): void;
|
|
346
|
+
getUnlockedAchievements(): string[];
|
|
347
|
+
setUnlockedAchievements(achievements: string[]): void;
|
|
348
|
+
clear(): void;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
declare class MemoryStorage implements AchievementStorage {
|
|
352
|
+
private metrics;
|
|
353
|
+
private unlockedAchievements;
|
|
354
|
+
constructor();
|
|
355
|
+
getMetrics(): AchievementMetrics;
|
|
356
|
+
setMetrics(metrics: AchievementMetrics): void;
|
|
357
|
+
getUnlockedAchievements(): string[];
|
|
358
|
+
setUnlockedAchievements(achievements: string[]): void;
|
|
359
|
+
clear(): void;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
declare class IndexedDBStorage implements AsyncAchievementStorage {
|
|
363
|
+
private dbName;
|
|
364
|
+
private storeName;
|
|
365
|
+
private db;
|
|
366
|
+
private initPromise;
|
|
367
|
+
constructor(dbName?: string);
|
|
368
|
+
/**
|
|
369
|
+
* Initialize IndexedDB database and object store
|
|
370
|
+
*/
|
|
371
|
+
private initDB;
|
|
372
|
+
/**
|
|
373
|
+
* Generic get operation from IndexedDB
|
|
374
|
+
*/
|
|
375
|
+
private get;
|
|
376
|
+
/**
|
|
377
|
+
* Generic set operation to IndexedDB
|
|
378
|
+
*/
|
|
379
|
+
private set;
|
|
380
|
+
/**
|
|
381
|
+
* Delete operation from IndexedDB
|
|
382
|
+
*/
|
|
383
|
+
private delete;
|
|
384
|
+
getMetrics(): Promise<AchievementMetrics>;
|
|
385
|
+
setMetrics(metrics: AchievementMetrics): Promise<void>;
|
|
386
|
+
getUnlockedAchievements(): Promise<string[]>;
|
|
387
|
+
setUnlockedAchievements(achievements: string[]): Promise<void>;
|
|
388
|
+
clear(): Promise<void>;
|
|
389
|
+
/**
|
|
390
|
+
* Close the database connection
|
|
391
|
+
*/
|
|
392
|
+
close(): void;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
interface RestApiStorageConfig {
|
|
396
|
+
baseUrl: string;
|
|
397
|
+
userId: string;
|
|
398
|
+
headers?: Record<string, string>;
|
|
399
|
+
timeout?: number;
|
|
400
|
+
}
|
|
401
|
+
declare class RestApiStorage implements AsyncAchievementStorage {
|
|
402
|
+
private config;
|
|
403
|
+
constructor(config: RestApiStorageConfig);
|
|
404
|
+
/**
|
|
405
|
+
* Generic fetch wrapper with timeout and error handling
|
|
406
|
+
*/
|
|
407
|
+
private fetchWithTimeout;
|
|
408
|
+
getMetrics(): Promise<AchievementMetrics>;
|
|
409
|
+
setMetrics(metrics: AchievementMetrics): Promise<void>;
|
|
410
|
+
getUnlockedAchievements(): Promise<string[]>;
|
|
411
|
+
setUnlockedAchievements(achievements: string[]): Promise<void>;
|
|
412
|
+
clear(): Promise<void>;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Base error class for all achievement-related errors
|
|
417
|
+
*/
|
|
418
|
+
declare class AchievementError extends Error {
|
|
419
|
+
code: string;
|
|
420
|
+
recoverable: boolean;
|
|
421
|
+
remedy?: string | undefined;
|
|
422
|
+
constructor(message: string, code: string, recoverable: boolean, remedy?: string | undefined);
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Error thrown when browser storage quota is exceeded
|
|
426
|
+
*/
|
|
427
|
+
declare class StorageQuotaError extends AchievementError {
|
|
428
|
+
bytesNeeded: number;
|
|
429
|
+
constructor(bytesNeeded: number);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Error thrown when imported data fails validation
|
|
433
|
+
*/
|
|
434
|
+
declare class ImportValidationError extends AchievementError {
|
|
435
|
+
validationErrors: string[];
|
|
436
|
+
constructor(validationErrors: string[]);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Error thrown when storage operations fail
|
|
440
|
+
*/
|
|
441
|
+
declare class StorageError extends AchievementError {
|
|
442
|
+
originalError?: Error | undefined;
|
|
443
|
+
constructor(message: string, originalError?: Error | undefined);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Error thrown when configuration is invalid
|
|
447
|
+
*/
|
|
448
|
+
declare class ConfigurationError extends AchievementError {
|
|
449
|
+
constructor(message: string);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Error thrown when network sync operations fail
|
|
453
|
+
*/
|
|
454
|
+
declare class SyncError extends AchievementError {
|
|
455
|
+
readonly statusCode?: number;
|
|
456
|
+
readonly timeout?: number;
|
|
457
|
+
constructor(message: string, details?: {
|
|
458
|
+
statusCode?: number;
|
|
459
|
+
timeout?: number;
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Type guard to check if an error is an AchievementError
|
|
464
|
+
*/
|
|
465
|
+
declare function isAchievementError(error: unknown): error is AchievementError;
|
|
466
|
+
/**
|
|
467
|
+
* Type guard to check if an error is recoverable
|
|
468
|
+
*/
|
|
469
|
+
declare function isRecoverableError(error: unknown): boolean;
|
|
470
|
+
|
|
471
|
+
declare class AsyncStorageAdapter implements AchievementStorage {
|
|
472
|
+
private asyncStorage;
|
|
473
|
+
private cache;
|
|
474
|
+
private pendingWrites;
|
|
475
|
+
private onError?;
|
|
476
|
+
constructor(asyncStorage: AsyncAchievementStorage, options?: {
|
|
477
|
+
onError?: (error: AchievementError) => void;
|
|
478
|
+
});
|
|
479
|
+
/**
|
|
480
|
+
* Initialize cache by loading from async storage
|
|
481
|
+
* This happens in the background during construction
|
|
482
|
+
*/
|
|
483
|
+
private initializeCache;
|
|
484
|
+
/**
|
|
485
|
+
* Wait for cache to be loaded (used internally)
|
|
486
|
+
* Returns immediately if already loaded, otherwise waits
|
|
487
|
+
*/
|
|
488
|
+
private ensureCacheLoaded;
|
|
489
|
+
/**
|
|
490
|
+
* SYNC READ: Returns cached metrics immediately
|
|
491
|
+
* Cache is loaded eagerly during construction
|
|
492
|
+
*/
|
|
493
|
+
getMetrics(): AchievementMetrics;
|
|
494
|
+
/**
|
|
495
|
+
* SYNC WRITE: Updates cache immediately, writes to storage in background
|
|
496
|
+
* Uses optimistic updates - assumes write will succeed
|
|
497
|
+
*/
|
|
498
|
+
setMetrics(metrics: AchievementMetrics): void;
|
|
499
|
+
/**
|
|
500
|
+
* SYNC READ: Returns cached unlocked achievements immediately
|
|
501
|
+
*/
|
|
502
|
+
getUnlockedAchievements(): string[];
|
|
503
|
+
/**
|
|
504
|
+
* SYNC WRITE: Updates cache immediately, writes to storage in background
|
|
505
|
+
*/
|
|
506
|
+
setUnlockedAchievements(achievements: string[]): void;
|
|
507
|
+
/**
|
|
508
|
+
* SYNC CLEAR: Clears cache immediately, clears storage in background
|
|
509
|
+
*/
|
|
510
|
+
clear(): void;
|
|
511
|
+
/**
|
|
512
|
+
* Wait for all pending writes to complete (useful for testing/cleanup)
|
|
513
|
+
* NOT part of AchievementStorage interface - utility method
|
|
514
|
+
*/
|
|
515
|
+
flush(): Promise<void>;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
interface QueuedOperation {
|
|
519
|
+
id: string;
|
|
520
|
+
type: 'setMetrics' | 'setUnlockedAchievements' | 'clear';
|
|
521
|
+
data?: any;
|
|
522
|
+
timestamp: number;
|
|
523
|
+
}
|
|
524
|
+
declare class OfflineQueueStorage implements AsyncAchievementStorage {
|
|
525
|
+
private innerStorage;
|
|
526
|
+
private queue;
|
|
527
|
+
private isOnline;
|
|
528
|
+
private isSyncing;
|
|
529
|
+
private queueStorageKey;
|
|
530
|
+
constructor(innerStorage: AsyncAchievementStorage);
|
|
531
|
+
private loadQueue;
|
|
532
|
+
private saveQueue;
|
|
533
|
+
private handleOnline;
|
|
534
|
+
private handleOffline;
|
|
535
|
+
private processQueue;
|
|
536
|
+
private queueOperation;
|
|
537
|
+
getMetrics(): Promise<AchievementMetrics>;
|
|
538
|
+
setMetrics(metrics: AchievementMetrics): Promise<void>;
|
|
539
|
+
getUnlockedAchievements(): Promise<string[]>;
|
|
540
|
+
setUnlockedAchievements(achievements: string[]): Promise<void>;
|
|
541
|
+
clear(): Promise<void>;
|
|
542
|
+
/**
|
|
543
|
+
* Manually trigger queue processing (useful for testing)
|
|
544
|
+
*/
|
|
545
|
+
sync(): Promise<void>;
|
|
546
|
+
/**
|
|
547
|
+
* Get current queue status (useful for debugging)
|
|
548
|
+
*/
|
|
549
|
+
getQueueStatus(): {
|
|
550
|
+
pending: number;
|
|
551
|
+
operations: QueuedOperation[];
|
|
552
|
+
};
|
|
553
|
+
/**
|
|
554
|
+
* Cleanup listeners (call on unmount)
|
|
555
|
+
*/
|
|
556
|
+
destroy(): void;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
declare function normalizeAchievements(config: AchievementConfigurationType): AchievementConfiguration;
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Exports achievement data to a JSON string
|
|
563
|
+
*
|
|
564
|
+
* @param metrics - Current achievement metrics
|
|
565
|
+
* @param unlocked - Array of unlocked achievement IDs
|
|
566
|
+
* @param configHash - Optional hash of achievement configuration for validation
|
|
567
|
+
* @returns JSON string containing all achievement data
|
|
568
|
+
*
|
|
569
|
+
* @example
|
|
570
|
+
* ```typescript
|
|
571
|
+
* const json = exportAchievementData(_metrics, ['score_100', 'level_5']);
|
|
572
|
+
* // Save json to file or send to server
|
|
573
|
+
* ```
|
|
574
|
+
*/
|
|
575
|
+
declare function exportAchievementData(metrics: AchievementMetrics, unlocked: string[], configHash?: string): string;
|
|
576
|
+
/**
|
|
577
|
+
* Creates a simple hash of the achievement configuration
|
|
578
|
+
* Used to validate that imported data matches the current configuration
|
|
579
|
+
*
|
|
580
|
+
* @param config - Achievement configuration object
|
|
581
|
+
* @returns Simple hash string
|
|
582
|
+
*/
|
|
583
|
+
declare function createConfigHash(config: any): string;
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Options for importing achievement data
|
|
587
|
+
*/
|
|
588
|
+
interface ImportOptions {
|
|
589
|
+
/** Strategy for merging imported data with existing data */
|
|
590
|
+
mergeStrategy?: 'replace' | 'merge' | 'preserve';
|
|
591
|
+
/** Whether to validate the imported data */
|
|
592
|
+
validate?: boolean;
|
|
593
|
+
/** Optional config hash to validate against */
|
|
594
|
+
expectedConfigHash?: string;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Result of an import operation
|
|
598
|
+
*/
|
|
599
|
+
interface ImportResult {
|
|
600
|
+
success: boolean;
|
|
601
|
+
imported: {
|
|
602
|
+
metrics: number;
|
|
603
|
+
achievements: number;
|
|
604
|
+
};
|
|
605
|
+
errors?: string[];
|
|
606
|
+
warnings?: string[];
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Imports achievement data from a JSON string
|
|
610
|
+
*
|
|
611
|
+
* @param jsonString - JSON string containing exported achievement data
|
|
612
|
+
* @param currentMetrics - Current metrics state
|
|
613
|
+
* @param currentUnlocked - Current unlocked achievements
|
|
614
|
+
* @param options - Import options
|
|
615
|
+
* @returns Import result with success status and any errors
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* ```typescript
|
|
619
|
+
* const result = importAchievementData(
|
|
620
|
+
* jsonString,
|
|
621
|
+
* currentMetrics,
|
|
622
|
+
* currentUnlocked,
|
|
623
|
+
* { mergeStrategy: 'merge', validate: true }
|
|
624
|
+
* );
|
|
625
|
+
*
|
|
626
|
+
* if (result.success) {
|
|
627
|
+
* console.log(`Imported ${result.imported.achievements} achievements`);
|
|
628
|
+
* } else {
|
|
629
|
+
* console.error('Import failed:', result.errors);
|
|
630
|
+
* }
|
|
631
|
+
* ```
|
|
632
|
+
*/
|
|
633
|
+
declare function importAchievementData(jsonString: string, currentMetrics: AchievementMetrics, currentUnlocked: string[], options?: ImportOptions): ImportResult;
|
|
634
|
+
|
|
635
|
+
export { AchievementCondition, AchievementConfiguration, AchievementConfigurationType, AchievementDetails, AchievementEngine, AchievementEngineApi, AchievementError, AchievementMetricArrayValue, AchievementMetricValue, AchievementMetrics, AchievementState, AchievementStorage, AchievementUnlockedEvent, AchievementWithStatus, AnyAchievementStorage, AsyncAchievementStorage, AsyncStorageAdapter, ConfigurationError, CustomAchievementDetails, EngineConfig, EngineEvent, ErrorEvent, EventEmitter, EventHandler, EventMapping, ImportOptions$1 as ImportOptions, ImportResult$1 as ImportResult, ImportValidationError, IndexedDBStorage, InitialAchievementMetrics, LocalStorage, MemoryStorage, MetricUpdatedEvent, MetricUpdater, OfflineQueueStorage, RestApiStorage, RestApiStorageConfig$1 as RestApiStorageConfig, SimpleAchievementConfig, SimpleAchievementDetails, StateChangedEvent, StorageError, StorageQuotaError, StorageType, SyncError, UnsubscribeFn, createConfigHash, exportAchievementData, importAchievementData, isAchievementError, isAsyncStorage, isRecoverableError, normalizeAchievements };
|