capybara-game-sdk 0.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/dist/index.d.mts +246 -0
- package/dist/index.d.ts +246 -0
- package/dist/index.js +698 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +690 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
// src/AuthModule.ts
|
|
6
|
+
var AuthModule = class {
|
|
7
|
+
constructor(bridge) {
|
|
8
|
+
this.bridge = bridge;
|
|
9
|
+
this.currentUser = null;
|
|
10
|
+
this.authChangeListeners = /* @__PURE__ */ new Set();
|
|
11
|
+
this.initialize();
|
|
12
|
+
}
|
|
13
|
+
async initialize() {
|
|
14
|
+
this.currentUser = await this.bridge.getCurrentUser();
|
|
15
|
+
this.bridge.on("auth_changed", (user) => {
|
|
16
|
+
this.currentUser = user;
|
|
17
|
+
this.notifyAuthChange();
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
notifyAuthChange() {
|
|
21
|
+
this.authChangeListeners.forEach((listener) => {
|
|
22
|
+
try {
|
|
23
|
+
listener(this.currentUser);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error("Error in auth change listener:", error);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the currently authenticated user
|
|
31
|
+
*/
|
|
32
|
+
async getCurrentUser() {
|
|
33
|
+
if (!this.currentUser) {
|
|
34
|
+
this.currentUser = await this.bridge.getCurrentUser();
|
|
35
|
+
}
|
|
36
|
+
return this.currentUser;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get bearer token for the authenticated user
|
|
40
|
+
*/
|
|
41
|
+
async getBearerToken() {
|
|
42
|
+
return await this.bridge.getBearerToken();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Request user authentication (triggers parent app UI)
|
|
46
|
+
*/
|
|
47
|
+
async requestLogin() {
|
|
48
|
+
await this.bridge.requestLogin();
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
50
|
+
this.currentUser = await this.bridge.getCurrentUser();
|
|
51
|
+
this.notifyAuthChange();
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Logout the current user
|
|
55
|
+
*/
|
|
56
|
+
async logout() {
|
|
57
|
+
await this.bridge.logout();
|
|
58
|
+
this.currentUser = null;
|
|
59
|
+
this.notifyAuthChange();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Listen for authentication state changes
|
|
63
|
+
*/
|
|
64
|
+
onAuthChange(callback) {
|
|
65
|
+
this.authChangeListeners.add(callback);
|
|
66
|
+
callback(this.currentUser);
|
|
67
|
+
return () => {
|
|
68
|
+
this.authChangeListeners.delete(callback);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if user is authenticated
|
|
73
|
+
*/
|
|
74
|
+
isAuthenticated() {
|
|
75
|
+
return this.currentUser !== null;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// src/ParentBridge.ts
|
|
80
|
+
var ParentBridge = class {
|
|
81
|
+
constructor(allowedOrigins = ["*"]) {
|
|
82
|
+
this.messageHandlers = /* @__PURE__ */ new Map();
|
|
83
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
84
|
+
this.requestIdCounter = 0;
|
|
85
|
+
this.allowedOrigins = new Set(allowedOrigins);
|
|
86
|
+
this.setupMessageListener();
|
|
87
|
+
}
|
|
88
|
+
setupMessageListener() {
|
|
89
|
+
window.addEventListener("message", (event) => {
|
|
90
|
+
if (this.allowedOrigins.size > 0 && !this.allowedOrigins.has("*") && !this.allowedOrigins.has(event.origin)) {
|
|
91
|
+
console.warn(
|
|
92
|
+
"Rejected message from unauthorized origin:",
|
|
93
|
+
event.origin
|
|
94
|
+
);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const message = event.data;
|
|
98
|
+
if (!message || typeof message !== "object" || !message.type) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const requestId = message.requestId;
|
|
102
|
+
if (requestId && this.pendingRequests.has(requestId)) {
|
|
103
|
+
const { resolve, reject } = this.pendingRequests.get(requestId);
|
|
104
|
+
this.pendingRequests.delete(requestId);
|
|
105
|
+
if (message.error) {
|
|
106
|
+
reject(new Error(message.error));
|
|
107
|
+
} else {
|
|
108
|
+
resolve(message.data);
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const handler = this.messageHandlers.get(message.type);
|
|
113
|
+
if (handler) {
|
|
114
|
+
handler(message.data);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Send a message to parent and wait for response
|
|
120
|
+
*/
|
|
121
|
+
sendRequest(type, data) {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const requestId = `req_${this.requestIdCounter++}_${Date.now()}`;
|
|
124
|
+
this.pendingRequests.set(requestId, { resolve, reject });
|
|
125
|
+
const message = {
|
|
126
|
+
type,
|
|
127
|
+
data,
|
|
128
|
+
requestId
|
|
129
|
+
};
|
|
130
|
+
window.parent.postMessage(message, "*");
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
if (this.pendingRequests.has(requestId)) {
|
|
133
|
+
this.pendingRequests.delete(requestId);
|
|
134
|
+
reject(new Error("Request timeout"));
|
|
135
|
+
}
|
|
136
|
+
}, 3e4);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Send a message to parent without expecting a response
|
|
141
|
+
*/
|
|
142
|
+
sendMessage(type, data) {
|
|
143
|
+
const message = {
|
|
144
|
+
type,
|
|
145
|
+
data
|
|
146
|
+
};
|
|
147
|
+
window.parent.postMessage(message, "*");
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Listen for messages from parent
|
|
151
|
+
*/
|
|
152
|
+
on(type, handler) {
|
|
153
|
+
this.messageHandlers.set(type, handler);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Remove message listener
|
|
157
|
+
*/
|
|
158
|
+
off(type) {
|
|
159
|
+
this.messageHandlers.delete(type);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get current authenticated user
|
|
163
|
+
*/
|
|
164
|
+
async getCurrentUser() {
|
|
165
|
+
try {
|
|
166
|
+
return await this.sendRequest("get_user");
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error("Failed to get current user:", error);
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Request user to login (triggers parent app UI)
|
|
174
|
+
*/
|
|
175
|
+
async requestLogin() {
|
|
176
|
+
return this.sendRequest("request_login");
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Logout current user
|
|
180
|
+
*/
|
|
181
|
+
async logout() {
|
|
182
|
+
return this.sendRequest("logout");
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Get bearer token for authenticated user
|
|
186
|
+
*/
|
|
187
|
+
async getBearerToken() {
|
|
188
|
+
try {
|
|
189
|
+
return await this.sendRequest("get_bearer_token");
|
|
190
|
+
} catch (error) {
|
|
191
|
+
console.error("Failed to get bearer token:", error);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get user's credit balance
|
|
197
|
+
*/
|
|
198
|
+
async getBalance() {
|
|
199
|
+
return this.sendRequest("get_balance");
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Charge credits from user's balance
|
|
203
|
+
*/
|
|
204
|
+
async chargeCredits(amount, description) {
|
|
205
|
+
return this.sendRequest("charge_credits", {
|
|
206
|
+
amount,
|
|
207
|
+
description
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Notify parent that SDK is ready
|
|
212
|
+
*/
|
|
213
|
+
notifyReady() {
|
|
214
|
+
this.sendMessage("ready");
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// src/PaymentsModule.ts
|
|
219
|
+
var PaymentsModule = class {
|
|
220
|
+
constructor(bridge, auth, devMode) {
|
|
221
|
+
this.bridge = bridge;
|
|
222
|
+
this.auth = auth;
|
|
223
|
+
this.devMode = devMode;
|
|
224
|
+
this.currentBalance = { credits: 0 };
|
|
225
|
+
this.balanceChangeListeners = /* @__PURE__ */ new Set();
|
|
226
|
+
this.transactions = [];
|
|
227
|
+
this.initialize();
|
|
228
|
+
}
|
|
229
|
+
async initialize() {
|
|
230
|
+
if (this.auth.isAuthenticated()) {
|
|
231
|
+
await this.refreshBalance();
|
|
232
|
+
}
|
|
233
|
+
this.auth.onAuthChange(async (user) => {
|
|
234
|
+
if (user) {
|
|
235
|
+
await this.refreshBalance();
|
|
236
|
+
} else {
|
|
237
|
+
this.currentBalance = { credits: 0 };
|
|
238
|
+
this.notifyBalanceChange();
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
this.bridge.on("balance_updated", (balance) => {
|
|
242
|
+
this.currentBalance = balance;
|
|
243
|
+
this.notifyBalanceChange();
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
async refreshBalance() {
|
|
247
|
+
try {
|
|
248
|
+
this.currentBalance = await this.bridge.getBalance();
|
|
249
|
+
this.notifyBalanceChange();
|
|
250
|
+
} catch (error) {
|
|
251
|
+
console.error("Failed to refresh balance:", error);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
notifyBalanceChange() {
|
|
255
|
+
this.balanceChangeListeners.forEach((listener) => {
|
|
256
|
+
try {
|
|
257
|
+
listener(this.currentBalance);
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error("Error in balance change listener:", error);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Get the current credit balance
|
|
265
|
+
*/
|
|
266
|
+
async getBalance() {
|
|
267
|
+
if (!this.auth.isAuthenticated()) {
|
|
268
|
+
throw new Error("User must be authenticated to check balance");
|
|
269
|
+
}
|
|
270
|
+
if (this.devMode) {
|
|
271
|
+
return { credits: 999999 };
|
|
272
|
+
}
|
|
273
|
+
await this.refreshBalance();
|
|
274
|
+
return this.currentBalance;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Charge credits from the user's balance
|
|
278
|
+
* In dev mode, this is a no-op (free)
|
|
279
|
+
*/
|
|
280
|
+
async charge(amount, description) {
|
|
281
|
+
if (!this.auth.isAuthenticated()) {
|
|
282
|
+
throw new Error("User must be authenticated to make payments");
|
|
283
|
+
}
|
|
284
|
+
if (amount <= 0) {
|
|
285
|
+
throw new Error("Amount must be greater than 0");
|
|
286
|
+
}
|
|
287
|
+
if (this.devMode) {
|
|
288
|
+
console.warn(
|
|
289
|
+
`Dev mode: Charging ${amount} credits for "${description}" - no actual charge applied.`
|
|
290
|
+
);
|
|
291
|
+
return {
|
|
292
|
+
success: true,
|
|
293
|
+
newBalance: 999999
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
const result = await this.bridge.chargeCredits(amount, description);
|
|
298
|
+
if (result.success) {
|
|
299
|
+
this.currentBalance = { credits: result.newBalance };
|
|
300
|
+
this.notifyBalanceChange();
|
|
301
|
+
this.transactions.push({
|
|
302
|
+
amount: -amount,
|
|
303
|
+
description,
|
|
304
|
+
timestamp: Date.now()
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
return result;
|
|
308
|
+
} catch (error) {
|
|
309
|
+
return {
|
|
310
|
+
success: false,
|
|
311
|
+
newBalance: this.currentBalance.credits,
|
|
312
|
+
error: error instanceof Error ? error.message : "Failed to charge credits"
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Listen for balance changes
|
|
318
|
+
*/
|
|
319
|
+
onBalanceChange(callback) {
|
|
320
|
+
this.balanceChangeListeners.add(callback);
|
|
321
|
+
callback(this.currentBalance);
|
|
322
|
+
return () => {
|
|
323
|
+
this.balanceChangeListeners.delete(callback);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Get transaction history
|
|
328
|
+
* Note: This only includes transactions made during the current session
|
|
329
|
+
* For full history, the parent app should provide an API
|
|
330
|
+
*/
|
|
331
|
+
async getHistory() {
|
|
332
|
+
return [...this.transactions];
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Gift credits to another user (requires server-side implementation)
|
|
336
|
+
*/
|
|
337
|
+
async giftCredits(userId, amount, description) {
|
|
338
|
+
throw new Error("Gift credits not yet implemented");
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Set development mode
|
|
342
|
+
*/
|
|
343
|
+
setDevMode(enabled) {
|
|
344
|
+
this.devMode = enabled;
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// src/GameSDK.ts
|
|
349
|
+
var _GameSDK = class _GameSDK {
|
|
350
|
+
constructor(config) {
|
|
351
|
+
this.config = config;
|
|
352
|
+
this.gameId = config.gameId;
|
|
353
|
+
this.bridge = new ParentBridge();
|
|
354
|
+
this.auth = new AuthModule(this.bridge);
|
|
355
|
+
this.payments = new PaymentsModule(
|
|
356
|
+
this.bridge,
|
|
357
|
+
this.auth,
|
|
358
|
+
config.devMode || false
|
|
359
|
+
);
|
|
360
|
+
this.bridge.notifyReady();
|
|
361
|
+
if (config.onReady) {
|
|
362
|
+
setTimeout(config.onReady, 0);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Initialize the Game SDK
|
|
367
|
+
*/
|
|
368
|
+
static async init(config) {
|
|
369
|
+
if (_GameSDK.instance) {
|
|
370
|
+
console.warn("GameSDK already initialized. Returning existing instance.");
|
|
371
|
+
return _GameSDK.instance;
|
|
372
|
+
}
|
|
373
|
+
if (!config.gameId) {
|
|
374
|
+
throw new Error("gameId is required");
|
|
375
|
+
}
|
|
376
|
+
_GameSDK.instance = new _GameSDK(config);
|
|
377
|
+
return _GameSDK.instance;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Get the current SDK instance
|
|
381
|
+
*/
|
|
382
|
+
static getInstance() {
|
|
383
|
+
if (!_GameSDK.instance) {
|
|
384
|
+
throw new Error("GameSDK not initialized. Call GameSDK.init() first.");
|
|
385
|
+
}
|
|
386
|
+
return _GameSDK.instance;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Set development mode
|
|
390
|
+
*/
|
|
391
|
+
setDevMode(enabled) {
|
|
392
|
+
this.config.devMode = enabled;
|
|
393
|
+
this.payments.setDevMode(enabled);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Get SDK configuration
|
|
397
|
+
*/
|
|
398
|
+
getConfig() {
|
|
399
|
+
return { ...this.config };
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Clean up SDK resources
|
|
403
|
+
*/
|
|
404
|
+
async destroy() {
|
|
405
|
+
_GameSDK.instance = null;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
_GameSDK.instance = null;
|
|
409
|
+
var GameSDK = _GameSDK;
|
|
410
|
+
|
|
411
|
+
// src/ApiClient.ts
|
|
412
|
+
var API_BASE_URL = "https://api.gamesdk.com";
|
|
413
|
+
var ApiClient = class {
|
|
414
|
+
constructor(auth) {
|
|
415
|
+
this.auth = auth;
|
|
416
|
+
}
|
|
417
|
+
async getHeaders() {
|
|
418
|
+
const token = await this.auth.getBearerToken();
|
|
419
|
+
return {
|
|
420
|
+
"Content-Type": "application/json",
|
|
421
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
async makeRequest(endpoint, options = {}) {
|
|
425
|
+
const url = `${API_BASE_URL}${endpoint}`;
|
|
426
|
+
const headers = await this.getHeaders();
|
|
427
|
+
const response = await fetch(url, {
|
|
428
|
+
...options,
|
|
429
|
+
headers: {
|
|
430
|
+
...headers,
|
|
431
|
+
...options.headers
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
if (!response.ok) {
|
|
435
|
+
throw new Error(
|
|
436
|
+
`API request failed: ${response.status} ${response.statusText}`
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
return response.json();
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Save game data to the server
|
|
443
|
+
*/
|
|
444
|
+
async saveGameData(gameId, data) {
|
|
445
|
+
await this.makeRequest("/api/storage/save", {
|
|
446
|
+
method: "POST",
|
|
447
|
+
body: JSON.stringify({ gameId, data })
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Load game data from the server
|
|
452
|
+
*/
|
|
453
|
+
async loadGameData(gameId) {
|
|
454
|
+
try {
|
|
455
|
+
const result = await this.makeRequest(
|
|
456
|
+
"/api/storage/load",
|
|
457
|
+
{
|
|
458
|
+
method: "GET"
|
|
459
|
+
}
|
|
460
|
+
);
|
|
461
|
+
return result.data;
|
|
462
|
+
} catch (error) {
|
|
463
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
throw error;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Clear game data from the server
|
|
471
|
+
*/
|
|
472
|
+
async clearGameData(gameId) {
|
|
473
|
+
await this.makeRequest("/api/storage/clear", {
|
|
474
|
+
method: "DELETE"
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Check if game data exists on the server
|
|
479
|
+
*/
|
|
480
|
+
async gameDataExists(gameId) {
|
|
481
|
+
try {
|
|
482
|
+
await this.makeRequest("/api/storage/exists", {
|
|
483
|
+
method: "GET"
|
|
484
|
+
});
|
|
485
|
+
return true;
|
|
486
|
+
} catch (error) {
|
|
487
|
+
if (error instanceof Error && error.message.includes("404")) {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
throw error;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Get the size of stored game data
|
|
495
|
+
*/
|
|
496
|
+
async getGameDataSize(gameId) {
|
|
497
|
+
const result = await this.makeRequest(
|
|
498
|
+
"/api/storage/size",
|
|
499
|
+
{
|
|
500
|
+
method: "GET"
|
|
501
|
+
}
|
|
502
|
+
);
|
|
503
|
+
return result.size;
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
// src/StorageModule.ts
|
|
508
|
+
var StorageModule = class {
|
|
509
|
+
constructor(gameId, auth) {
|
|
510
|
+
this.auth = auth;
|
|
511
|
+
this.gameId = gameId;
|
|
512
|
+
this.apiClient = new ApiClient(auth);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Save data to storage
|
|
516
|
+
* Data is automatically scoped to current user and game
|
|
517
|
+
* Maximum size: 5MB
|
|
518
|
+
*/
|
|
519
|
+
async save(data) {
|
|
520
|
+
try {
|
|
521
|
+
const serialized = JSON.stringify(data);
|
|
522
|
+
const sizeInBytes = new Blob([serialized]).size;
|
|
523
|
+
if (sizeInBytes > 5 * 1024 * 1024) {
|
|
524
|
+
throw new Error("Storage limit exceeded: Maximum 5MB allowed");
|
|
525
|
+
}
|
|
526
|
+
await this.apiClient.saveGameData(this.gameId, data);
|
|
527
|
+
} catch (error) {
|
|
528
|
+
if (error instanceof Error) {
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
531
|
+
throw new Error("Failed to save data to storage");
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Load data from storage
|
|
536
|
+
* Returns null if no data exists
|
|
537
|
+
*/
|
|
538
|
+
async load() {
|
|
539
|
+
try {
|
|
540
|
+
return await this.apiClient.loadGameData(this.gameId);
|
|
541
|
+
} catch (error) {
|
|
542
|
+
console.error("Failed to load data from storage:", error);
|
|
543
|
+
return null;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Clear all stored data for current user and game
|
|
548
|
+
*/
|
|
549
|
+
async clear() {
|
|
550
|
+
try {
|
|
551
|
+
await this.apiClient.clearGameData(this.gameId);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
console.error("Failed to clear storage:", error);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Check if data exists in storage
|
|
558
|
+
*/
|
|
559
|
+
async exists() {
|
|
560
|
+
return this.apiClient.gameDataExists(this.gameId);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Get the size of stored data in bytes
|
|
564
|
+
*/
|
|
565
|
+
async getSize() {
|
|
566
|
+
try {
|
|
567
|
+
return await this.apiClient.getGameDataSize(this.gameId);
|
|
568
|
+
} catch (error) {
|
|
569
|
+
return 0;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
function useGameSDK(config) {
|
|
574
|
+
const [sdk, setSDK] = react.useState(null);
|
|
575
|
+
const [isReady, setIsReady] = react.useState(false);
|
|
576
|
+
const [error, setError] = react.useState(null);
|
|
577
|
+
react.useEffect(() => {
|
|
578
|
+
let mounted = true;
|
|
579
|
+
const initSDK = async () => {
|
|
580
|
+
try {
|
|
581
|
+
const configWithReady = {
|
|
582
|
+
...config,
|
|
583
|
+
onReady: () => {
|
|
584
|
+
if (mounted) {
|
|
585
|
+
setIsReady(true);
|
|
586
|
+
config.onReady?.();
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
const instance = await GameSDK.init(configWithReady);
|
|
591
|
+
if (mounted) {
|
|
592
|
+
setSDK(instance);
|
|
593
|
+
}
|
|
594
|
+
} catch (err) {
|
|
595
|
+
if (mounted) {
|
|
596
|
+
setError(
|
|
597
|
+
err instanceof Error ? err : new Error("Failed to initialize SDK")
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
initSDK();
|
|
603
|
+
return () => {
|
|
604
|
+
mounted = false;
|
|
605
|
+
};
|
|
606
|
+
}, [config.gameId]);
|
|
607
|
+
return { sdk, isReady, error };
|
|
608
|
+
}
|
|
609
|
+
function useAuth() {
|
|
610
|
+
const sdk = GameSDK.getInstance();
|
|
611
|
+
const [user, setUser] = react.useState(null);
|
|
612
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
613
|
+
react.useEffect(() => {
|
|
614
|
+
let mounted = true;
|
|
615
|
+
const loadUser = async () => {
|
|
616
|
+
const currentUser = await sdk.auth.getCurrentUser();
|
|
617
|
+
if (mounted) {
|
|
618
|
+
setUser(currentUser);
|
|
619
|
+
setIsLoading(false);
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
loadUser();
|
|
623
|
+
const unsubscribe = sdk.auth.onAuthChange((newUser) => {
|
|
624
|
+
if (mounted) {
|
|
625
|
+
setUser(newUser);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
return () => {
|
|
629
|
+
mounted = false;
|
|
630
|
+
unsubscribe();
|
|
631
|
+
};
|
|
632
|
+
}, [sdk]);
|
|
633
|
+
const login = react.useCallback(async () => {
|
|
634
|
+
await sdk.auth.requestLogin();
|
|
635
|
+
}, [sdk]);
|
|
636
|
+
const logout = react.useCallback(async () => {
|
|
637
|
+
await sdk.auth.logout();
|
|
638
|
+
}, [sdk]);
|
|
639
|
+
return {
|
|
640
|
+
user,
|
|
641
|
+
isLoading,
|
|
642
|
+
isAuthenticated: !!user,
|
|
643
|
+
login,
|
|
644
|
+
logout
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
function useCredits() {
|
|
648
|
+
const sdk = GameSDK.getInstance();
|
|
649
|
+
const [balance, setBalance] = react.useState({ credits: 0 });
|
|
650
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
651
|
+
react.useEffect(() => {
|
|
652
|
+
let mounted = true;
|
|
653
|
+
const loadBalance = async () => {
|
|
654
|
+
try {
|
|
655
|
+
const currentBalance = await sdk.payments.getBalance();
|
|
656
|
+
if (mounted) {
|
|
657
|
+
setBalance(currentBalance);
|
|
658
|
+
setIsLoading(false);
|
|
659
|
+
}
|
|
660
|
+
} catch (error) {
|
|
661
|
+
if (mounted) {
|
|
662
|
+
setIsLoading(false);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
loadBalance();
|
|
667
|
+
const unsubscribe = sdk.payments.onBalanceChange((newBalance) => {
|
|
668
|
+
if (mounted) {
|
|
669
|
+
setBalance(newBalance);
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
return () => {
|
|
673
|
+
mounted = false;
|
|
674
|
+
unsubscribe();
|
|
675
|
+
};
|
|
676
|
+
}, [sdk]);
|
|
677
|
+
const charge = react.useCallback(
|
|
678
|
+
async (amount, description) => {
|
|
679
|
+
return await sdk.payments.charge(amount, description);
|
|
680
|
+
},
|
|
681
|
+
[sdk]
|
|
682
|
+
);
|
|
683
|
+
return {
|
|
684
|
+
balance: balance.credits,
|
|
685
|
+
isLoading,
|
|
686
|
+
charge
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
exports.AuthModule = AuthModule;
|
|
691
|
+
exports.GameSDK = GameSDK;
|
|
692
|
+
exports.PaymentsModule = PaymentsModule;
|
|
693
|
+
exports.StorageModule = StorageModule;
|
|
694
|
+
exports.useAuth = useAuth;
|
|
695
|
+
exports.useCredits = useCredits;
|
|
696
|
+
exports.useGameSDK = useGameSDK;
|
|
697
|
+
//# sourceMappingURL=index.js.map
|
|
698
|
+
//# sourceMappingURL=index.js.map
|