@hyve-sdk/js 1.5.1 → 2.1.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 +169 -658
- package/dist/index.d.mts +141 -139
- package/dist/index.d.ts +141 -139
- package/dist/index.js +414 -526
- package/dist/index.mjs +409 -518
- package/dist/react.d.mts +453 -0
- package/dist/react.d.ts +453 -0
- package/dist/react.js +2173 -0
- package/dist/react.mjs +2151 -0
- package/package.json +30 -15
package/dist/index.js
CHANGED
|
@@ -18,12 +18,13 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
23
|
AdsService: () => AdsService,
|
|
24
24
|
BillingPlatform: () => BillingPlatform,
|
|
25
25
|
BillingService: () => BillingService,
|
|
26
26
|
CloudStorageAdapter: () => CloudStorageAdapter,
|
|
27
|
+
CrazyGamesService: () => CrazyGamesService,
|
|
27
28
|
HyveClient: () => HyveClient,
|
|
28
29
|
LocalStorageAdapter: () => LocalStorageAdapter,
|
|
29
30
|
Logger: () => Logger,
|
|
@@ -31,15 +32,11 @@ __export(index_exports, {
|
|
|
31
32
|
NativeMessageType: () => NativeMessageType,
|
|
32
33
|
PlaygamaService: () => PlaygamaService,
|
|
33
34
|
generateUUID: () => generateUUID,
|
|
34
|
-
handleVerifyMessage: () => handleVerifyMessage,
|
|
35
35
|
isDomainAllowed: () => isDomainAllowed,
|
|
36
36
|
logger: () => logger,
|
|
37
|
-
parseUrlParams: () => parseUrlParams
|
|
38
|
-
validateSignature: () => validateSignature,
|
|
39
|
-
verifyAuthentication: () => verifyAuthentication,
|
|
40
|
-
verifyHyveToken: () => verifyHyveToken
|
|
37
|
+
parseUrlParams: () => parseUrlParams
|
|
41
38
|
});
|
|
42
|
-
module.exports = __toCommonJS(
|
|
39
|
+
module.exports = __toCommonJS(src_exports);
|
|
43
40
|
|
|
44
41
|
// src/utils/index.ts
|
|
45
42
|
var import_uuid = require("uuid");
|
|
@@ -67,7 +64,7 @@ var Logger = class _Logger {
|
|
|
67
64
|
}
|
|
68
65
|
} else if (typeof window !== "undefined") {
|
|
69
66
|
try {
|
|
70
|
-
enabled = process
|
|
67
|
+
enabled = process?.env.NODE_ENV !== "production";
|
|
71
68
|
} catch (e) {
|
|
72
69
|
enabled = true;
|
|
73
70
|
}
|
|
@@ -167,136 +164,15 @@ var Logger = class _Logger {
|
|
|
167
164
|
var logger = new Logger();
|
|
168
165
|
|
|
169
166
|
// src/utils/auth.ts
|
|
170
|
-
var import_ethers = require("ethers");
|
|
171
167
|
function parseUrlParams(searchParams) {
|
|
172
168
|
const params = typeof searchParams === "string" ? new URLSearchParams(searchParams) : searchParams;
|
|
173
169
|
return {
|
|
174
|
-
signature: params.get("signature") || "",
|
|
175
|
-
message: params.get("message") || "",
|
|
176
170
|
gameStartTab: params.get("game_start_tab") || "",
|
|
177
|
-
hyveToken: params.get("hyve-token") || "",
|
|
178
171
|
platform: params.get("platform") || "",
|
|
179
172
|
hyveAccess: params.get("hyve-access") || "",
|
|
180
173
|
gameId: params.get("game-id") || ""
|
|
181
174
|
};
|
|
182
175
|
}
|
|
183
|
-
function validateSignature(signature, message) {
|
|
184
|
-
try {
|
|
185
|
-
const recoveredAddress = import_ethers.ethers.verifyMessage(message, signature);
|
|
186
|
-
return !!recoveredAddress;
|
|
187
|
-
} catch (error) {
|
|
188
|
-
logger.error("Signature validation error:", error);
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
function handleVerifyMessage(signature, message) {
|
|
193
|
-
try {
|
|
194
|
-
const metadata = JSON.parse(decodeURI(message));
|
|
195
|
-
if (!metadata.expiration || metadata.expiration < Date.now()) {
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
const userAddress = metadata.userId || metadata.address;
|
|
199
|
-
if (!userAddress) {
|
|
200
|
-
return false;
|
|
201
|
-
}
|
|
202
|
-
const byteMessage = new TextEncoder().encode(message);
|
|
203
|
-
const addressThatSignedMessage = import_ethers.ethers.verifyMessage(
|
|
204
|
-
byteMessage,
|
|
205
|
-
signature
|
|
206
|
-
);
|
|
207
|
-
if (!addressThatSignedMessage) {
|
|
208
|
-
return false;
|
|
209
|
-
}
|
|
210
|
-
if (addressThatSignedMessage.toLowerCase() !== userAddress.toLowerCase()) {
|
|
211
|
-
return false;
|
|
212
|
-
}
|
|
213
|
-
return userAddress;
|
|
214
|
-
} catch (error) {
|
|
215
|
-
logger.error("Error verifying message:", error);
|
|
216
|
-
return false;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
function verifyHyveToken(hyveToken, maxAgeSec = 600) {
|
|
220
|
-
try {
|
|
221
|
-
const parts = hyveToken.split(".");
|
|
222
|
-
if (parts.length !== 4) {
|
|
223
|
-
logger.error(
|
|
224
|
-
"Invalid hyve-token format: expected 4 parts, got",
|
|
225
|
-
parts.length
|
|
226
|
-
);
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
const [signature, address, randomBase64, timestampStr] = parts;
|
|
230
|
-
if (!signature || !address || !randomBase64 || !timestampStr) {
|
|
231
|
-
logger.error("Missing hyve-token components");
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
const message = `${address}.${randomBase64}.${timestampStr}`;
|
|
235
|
-
const recoveredAddress = import_ethers.ethers.verifyMessage(message, signature);
|
|
236
|
-
if (recoveredAddress.toLowerCase() !== address.toLowerCase()) {
|
|
237
|
-
logger.error("Hyve-token signature verification failed");
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
const timestamp = parseInt(timestampStr, 10);
|
|
241
|
-
if (!Number.isFinite(timestamp)) {
|
|
242
|
-
logger.error("Invalid hyve-token timestamp");
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
246
|
-
if (now - timestamp > maxAgeSec) {
|
|
247
|
-
logger.error(
|
|
248
|
-
`Hyve-token expired (age: ${now - timestamp}s, max: ${maxAgeSec}s)`
|
|
249
|
-
);
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
return address;
|
|
253
|
-
} catch (error) {
|
|
254
|
-
logger.error("Hyve-token verification error:", error);
|
|
255
|
-
return false;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
function verifyAuthentication(params, maxAgeSec = 600) {
|
|
259
|
-
if (params.hyveToken) {
|
|
260
|
-
const modernAddress = verifyHyveToken(params.hyveToken, maxAgeSec);
|
|
261
|
-
if (modernAddress) {
|
|
262
|
-
return {
|
|
263
|
-
isValid: true,
|
|
264
|
-
address: modernAddress,
|
|
265
|
-
method: "modern"
|
|
266
|
-
};
|
|
267
|
-
} else {
|
|
268
|
-
return {
|
|
269
|
-
isValid: false,
|
|
270
|
-
address: null,
|
|
271
|
-
method: "modern",
|
|
272
|
-
error: "Modern token verification failed"
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (params.signature && params.message) {
|
|
277
|
-
const legacyAddress = handleVerifyMessage(params.signature, params.message);
|
|
278
|
-
if (legacyAddress) {
|
|
279
|
-
return {
|
|
280
|
-
isValid: true,
|
|
281
|
-
address: legacyAddress,
|
|
282
|
-
method: "legacy"
|
|
283
|
-
};
|
|
284
|
-
} else {
|
|
285
|
-
return {
|
|
286
|
-
isValid: false,
|
|
287
|
-
address: null,
|
|
288
|
-
method: "legacy",
|
|
289
|
-
error: "Legacy token verification failed"
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return {
|
|
294
|
-
isValid: false,
|
|
295
|
-
address: null,
|
|
296
|
-
method: "none",
|
|
297
|
-
error: "No authentication tokens provided"
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
176
|
function isDomainAllowed(allowedDomains, hostname) {
|
|
301
177
|
logger.debug("Checking hostname:", hostname);
|
|
302
178
|
if (!allowedDomains) return true;
|
|
@@ -337,9 +213,7 @@ var NativeBridge = class {
|
|
|
337
213
|
* Checks if the app is running inside a React Native WebView
|
|
338
214
|
*/
|
|
339
215
|
static isNativeContext() {
|
|
340
|
-
|
|
341
|
-
console.log(`[NativeBridge] isNativeContext check: ${isNative}`);
|
|
342
|
-
return isNative;
|
|
216
|
+
return typeof window !== "undefined" && "ReactNativeWebView" in window;
|
|
343
217
|
}
|
|
344
218
|
/**
|
|
345
219
|
* Initializes the native bridge message listener
|
|
@@ -348,55 +222,37 @@ var NativeBridge = class {
|
|
|
348
222
|
static initialize() {
|
|
349
223
|
if (this.isInitialized) {
|
|
350
224
|
logger.debug("[NativeBridge] Already initialized");
|
|
351
|
-
console.log("[NativeBridge] \u26A0 Already initialized, skipping");
|
|
352
225
|
return;
|
|
353
226
|
}
|
|
354
227
|
if (typeof window === "undefined") {
|
|
355
228
|
logger.warn("[NativeBridge] Window not available, skipping initialization");
|
|
356
|
-
console.warn("[NativeBridge] \u26A0 Window not available, skipping initialization");
|
|
357
229
|
return;
|
|
358
230
|
}
|
|
359
|
-
const isInIframe = window !== window.parent;
|
|
360
|
-
console.log("[NativeBridge] ========== INITIALIZING ==========");
|
|
361
|
-
console.log(`[NativeBridge] Running in iframe: ${isInIframe}`);
|
|
362
|
-
console.log("[NativeBridge] Setting up message listeners on window and document");
|
|
363
231
|
const boundHandler = this.handleNativeMessage.bind(this);
|
|
364
232
|
window.addEventListener("message", boundHandler);
|
|
365
233
|
document.addEventListener("message", boundHandler);
|
|
366
|
-
if (isInIframe) {
|
|
367
|
-
console.log("[NativeBridge] Setting up parent window message listener for iframe context");
|
|
368
|
-
}
|
|
369
234
|
this.isInitialized = true;
|
|
370
|
-
console.log("[NativeBridge] \u2713 Event listeners attached to window and document");
|
|
371
|
-
console.log("[NativeBridge] \u2713 Initialized and ready to receive messages");
|
|
372
235
|
logger.info("[NativeBridge] Initialized and listening for native messages");
|
|
373
236
|
}
|
|
374
237
|
/**
|
|
375
238
|
* Handles incoming messages from React Native
|
|
376
239
|
*/
|
|
377
240
|
static handleNativeMessage(event) {
|
|
378
|
-
console.log("[NativeBridge] [HANDLER] handleNativeMessage called");
|
|
379
|
-
console.log("[NativeBridge] [HANDLER] Event source:", event.source === window ? "window" : "other");
|
|
380
|
-
console.log("[NativeBridge] [HANDLER] Event data:", event.data);
|
|
381
241
|
try {
|
|
382
242
|
let data;
|
|
383
243
|
if (typeof event.data === "string") {
|
|
384
244
|
try {
|
|
385
245
|
data = JSON.parse(event.data);
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
logger.debug("[NativeBridge] Failed to parse message, not JSON:", event.data);
|
|
246
|
+
} catch {
|
|
247
|
+
logger.debug("[NativeBridge] Ignoring non-JSON message");
|
|
389
248
|
return;
|
|
390
249
|
}
|
|
391
250
|
} else if (typeof event.data === "object" && event.data !== null) {
|
|
392
251
|
data = event.data;
|
|
393
|
-
logger.debug("[NativeBridge] Received message object:", data);
|
|
394
252
|
} else {
|
|
395
|
-
logger.debug("[NativeBridge] Received invalid message type:", typeof event.data);
|
|
396
253
|
return;
|
|
397
254
|
}
|
|
398
|
-
if (!data
|
|
399
|
-
logger.debug("[NativeBridge] Received message without type, ignoring");
|
|
255
|
+
if (!data?.type) {
|
|
400
256
|
return;
|
|
401
257
|
}
|
|
402
258
|
const nativeResponseTypes = [
|
|
@@ -408,22 +264,16 @@ var NativeBridge = class {
|
|
|
408
264
|
"PURCHASE_ERROR" /* PURCHASE_ERROR */
|
|
409
265
|
];
|
|
410
266
|
if (!nativeResponseTypes.includes(data.type)) {
|
|
411
|
-
logger.debug(`[NativeBridge] Ignoring non-native-response message: ${data.type}`);
|
|
412
267
|
return;
|
|
413
268
|
}
|
|
414
|
-
console.log("[NativeBridge] [HANDLER] Message type:", data.type);
|
|
415
269
|
const handler = this.handlers.get(data.type);
|
|
416
270
|
if (handler) {
|
|
417
|
-
|
|
418
|
-
logger.info(`[NativeBridge] Handling message: ${data.type}`, data.payload);
|
|
271
|
+
logger.debug(`[NativeBridge] Handling message: ${data.type}`);
|
|
419
272
|
handler(data.payload);
|
|
420
|
-
console.log(`[NativeBridge] [HANDLER] \u2713 Handler completed for: ${data.type}`);
|
|
421
273
|
} else {
|
|
422
|
-
console.warn(`[NativeBridge] [HANDLER] \u26A0 No handler registered for: ${data.type}`);
|
|
423
274
|
logger.warn(`[NativeBridge] No handler registered for: ${data.type}`);
|
|
424
275
|
}
|
|
425
276
|
} catch (error) {
|
|
426
|
-
console.error("[NativeBridge] [HANDLER] \u274C Error handling native message:", error);
|
|
427
277
|
logger.error("[NativeBridge] Error handling native message:", error);
|
|
428
278
|
}
|
|
429
279
|
}
|
|
@@ -433,27 +283,15 @@ var NativeBridge = class {
|
|
|
433
283
|
* @param payload Optional payload data
|
|
434
284
|
*/
|
|
435
285
|
static send(type, payload) {
|
|
436
|
-
console.log(`[NativeBridge] [SEND] Attempting to send message: ${type}`);
|
|
437
286
|
if (!this.isNativeContext()) {
|
|
438
|
-
|
|
439
|
-
logger.debug(
|
|
440
|
-
`[NativeBridge] Not in native context, skipping message: ${type}`
|
|
441
|
-
);
|
|
287
|
+
logger.debug(`[NativeBridge] Not in native context, skipping message: ${type}`);
|
|
442
288
|
return;
|
|
443
289
|
}
|
|
444
|
-
console.log(`[NativeBridge] [SEND] \u2713 In native context, sending message`);
|
|
445
290
|
try {
|
|
446
|
-
const message = {
|
|
447
|
-
type,
|
|
448
|
-
payload,
|
|
449
|
-
timestamp: Date.now()
|
|
450
|
-
};
|
|
451
|
-
console.log(`[NativeBridge] [SEND] Message object:`, message);
|
|
291
|
+
const message = { type, payload, timestamp: Date.now() };
|
|
452
292
|
window.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
453
|
-
console.log(`[NativeBridge] [SEND] \u2713 Message sent to native: ${type}`);
|
|
454
293
|
logger.debug(`[NativeBridge] Sent message to native: ${type}`, payload);
|
|
455
294
|
} catch (error) {
|
|
456
|
-
console.error(`[NativeBridge] [SEND] \u274C\u274C Error sending message to native:`, error);
|
|
457
295
|
logger.error(`[NativeBridge] Error sending message to native:`, error);
|
|
458
296
|
}
|
|
459
297
|
}
|
|
@@ -463,10 +301,7 @@ var NativeBridge = class {
|
|
|
463
301
|
* @param handler Function to call when message is received
|
|
464
302
|
*/
|
|
465
303
|
static on(type, handler) {
|
|
466
|
-
console.log(`[NativeBridge] [ON] Registering handler for: ${type}`);
|
|
467
304
|
this.handlers.set(type, handler);
|
|
468
|
-
console.log(`[NativeBridge] [ON] \u2713 Handler registered. Total handlers:`, this.handlers.size);
|
|
469
|
-
console.log(`[NativeBridge] [ON] All registered types:`, Array.from(this.handlers.keys()));
|
|
470
305
|
logger.debug(`[NativeBridge] Registered handler for: ${type}`);
|
|
471
306
|
}
|
|
472
307
|
/**
|
|
@@ -616,7 +451,6 @@ function generateUUID() {
|
|
|
616
451
|
// src/services/ads.ts
|
|
617
452
|
var AdsService = class {
|
|
618
453
|
config = {
|
|
619
|
-
enabled: false,
|
|
620
454
|
sound: "on",
|
|
621
455
|
debug: false,
|
|
622
456
|
onBeforeAd: () => {
|
|
@@ -626,87 +460,69 @@ var AdsService = class {
|
|
|
626
460
|
onRewardEarned: () => {
|
|
627
461
|
}
|
|
628
462
|
};
|
|
629
|
-
|
|
463
|
+
// Cached init promise — ensures adConfig() is only called once
|
|
464
|
+
initPromise = null;
|
|
630
465
|
ready = false;
|
|
631
466
|
/**
|
|
632
|
-
*
|
|
633
|
-
*
|
|
467
|
+
* Optionally configure the ads service.
|
|
468
|
+
* Not required — ads work without calling this.
|
|
634
469
|
*/
|
|
635
470
|
configure(config) {
|
|
636
471
|
this.config = {
|
|
637
472
|
...this.config,
|
|
638
473
|
...config,
|
|
639
|
-
onBeforeAd: config.onBeforeAd
|
|
640
|
-
onAfterAd: config.onAfterAd
|
|
641
|
-
onRewardEarned: config.onRewardEarned
|
|
474
|
+
onBeforeAd: config.onBeforeAd ?? this.config.onBeforeAd,
|
|
475
|
+
onAfterAd: config.onAfterAd ?? this.config.onAfterAd,
|
|
476
|
+
onRewardEarned: config.onRewardEarned ?? this.config.onRewardEarned
|
|
642
477
|
};
|
|
643
478
|
if (this.config.debug) {
|
|
644
|
-
|
|
645
|
-
enabled: this.config.enabled,
|
|
646
|
-
sound: this.config.sound
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
if (this.config.enabled && !this.initialized) {
|
|
650
|
-
this.initialize();
|
|
479
|
+
logger.debug("[AdsService] Configuration updated:", { sound: this.config.sound });
|
|
651
480
|
}
|
|
652
481
|
}
|
|
653
482
|
/**
|
|
654
|
-
* Initialize the
|
|
483
|
+
* Initialize the Google H5 Ads system.
|
|
484
|
+
* Returns a cached promise — safe to call multiple times.
|
|
655
485
|
*/
|
|
656
486
|
initialize() {
|
|
657
|
-
if (this.
|
|
658
|
-
|
|
659
|
-
if (
|
|
660
|
-
console.log("[AdsService] Ads disabled, skipping initialization");
|
|
661
|
-
}
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
if (!window.adConfig || !window.adBreak) {
|
|
665
|
-
console.warn("[AdsService] Google Ads SDK not found. Ads will not be available.");
|
|
666
|
-
return;
|
|
667
|
-
}
|
|
668
|
-
if (this.config.debug) {
|
|
669
|
-
console.log("[AdsService] Initializing ads system...");
|
|
670
|
-
}
|
|
671
|
-
const googleConfig = {
|
|
672
|
-
sound: this.config.sound,
|
|
673
|
-
preloadAdBreaks: "on",
|
|
674
|
-
onReady: () => {
|
|
675
|
-
this.ready = true;
|
|
487
|
+
if (this.initPromise) return this.initPromise;
|
|
488
|
+
this.initPromise = new Promise((resolve) => {
|
|
489
|
+
if (!window.adConfig || !window.adBreak) {
|
|
676
490
|
if (this.config.debug) {
|
|
677
|
-
|
|
491
|
+
logger.debug("[AdsService] Google Ads SDK not found \u2014 ads unavailable");
|
|
678
492
|
}
|
|
493
|
+
resolve(false);
|
|
494
|
+
return;
|
|
679
495
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
496
|
+
if (this.config.debug) {
|
|
497
|
+
logger.debug("[AdsService] Initializing ads system...");
|
|
498
|
+
}
|
|
499
|
+
window.adConfig({
|
|
500
|
+
sound: this.config.sound,
|
|
501
|
+
preloadAdBreaks: "on",
|
|
502
|
+
onReady: () => {
|
|
503
|
+
this.ready = true;
|
|
504
|
+
if (this.config.debug) {
|
|
505
|
+
logger.debug("[AdsService] Ads ready");
|
|
506
|
+
}
|
|
507
|
+
resolve(true);
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
setTimeout(() => resolve(false), 5e3);
|
|
511
|
+
});
|
|
512
|
+
return this.initPromise;
|
|
683
513
|
}
|
|
684
514
|
/**
|
|
685
|
-
* Show an ad
|
|
686
|
-
* Returns immediately if ads are disabled
|
|
515
|
+
* Show an ad. Auto-initializes on the first call.
|
|
516
|
+
* Returns immediately with success: false if ads are disabled or unavailable.
|
|
687
517
|
*/
|
|
688
518
|
async show(type) {
|
|
689
519
|
const requestedAt = Date.now();
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
console.log("[AdsService] Ads disabled, skipping ad request");
|
|
693
|
-
}
|
|
520
|
+
const ready = await this.initialize();
|
|
521
|
+
if (!ready || !window.adBreak) {
|
|
694
522
|
return {
|
|
695
523
|
success: false,
|
|
696
524
|
type,
|
|
697
|
-
error: new Error("Ads
|
|
698
|
-
requestedAt,
|
|
699
|
-
completedAt: Date.now()
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
if (!this.initialized) {
|
|
703
|
-
this.initialize();
|
|
704
|
-
}
|
|
705
|
-
if (!this.ready || !window.adBreak) {
|
|
706
|
-
return {
|
|
707
|
-
success: false,
|
|
708
|
-
type,
|
|
709
|
-
error: new Error("Ads not ready"),
|
|
525
|
+
error: new Error("Ads not available"),
|
|
710
526
|
requestedAt,
|
|
711
527
|
completedAt: Date.now()
|
|
712
528
|
};
|
|
@@ -714,7 +530,7 @@ var AdsService = class {
|
|
|
714
530
|
return this.showAdBreak(type);
|
|
715
531
|
}
|
|
716
532
|
/**
|
|
717
|
-
* Show an ad break
|
|
533
|
+
* Show an ad break via the Google H5 API.
|
|
718
534
|
*/
|
|
719
535
|
async showAdBreak(type) {
|
|
720
536
|
const requestedAt = Date.now();
|
|
@@ -722,74 +538,35 @@ var AdsService = class {
|
|
|
722
538
|
const googleType = type === "rewarded" ? "reward" : type === "preroll" ? "start" : "next";
|
|
723
539
|
const adName = `${type}-ad-${Date.now()}`;
|
|
724
540
|
if (this.config.debug) {
|
|
725
|
-
|
|
541
|
+
logger.debug(`[AdsService] Showing ${type} ad`);
|
|
726
542
|
}
|
|
727
543
|
this.config.onBeforeAd(type);
|
|
728
544
|
const adBreakConfig = {
|
|
729
545
|
type: googleType,
|
|
730
546
|
name: adName,
|
|
731
|
-
beforeAd: () => {
|
|
732
|
-
if (this.config.debug) {
|
|
733
|
-
console.log("[AdsService] Ad started");
|
|
734
|
-
}
|
|
735
|
-
},
|
|
736
547
|
afterAd: () => {
|
|
737
|
-
if (this.config.debug) {
|
|
738
|
-
console.log("[AdsService] Ad finished");
|
|
739
|
-
}
|
|
740
548
|
this.config.onAfterAd(type);
|
|
741
549
|
},
|
|
742
550
|
adBreakDone: (info) => {
|
|
743
551
|
const completedAt = Date.now();
|
|
744
|
-
|
|
745
|
-
if (type === "rewarded") {
|
|
746
|
-
success = info?.breakStatus === "viewed";
|
|
747
|
-
} else {
|
|
748
|
-
success = info?.breakStatus !== "error";
|
|
749
|
-
}
|
|
552
|
+
const success = type === "rewarded" ? info?.breakStatus === "viewed" : info?.breakStatus !== "error";
|
|
750
553
|
const error = info?.breakStatus === "error" && info?.error ? new Error(info.error) : void 0;
|
|
751
554
|
if (this.config.debug) {
|
|
752
|
-
|
|
753
|
-
success,
|
|
754
|
-
status: info?.breakStatus
|
|
755
|
-
});
|
|
555
|
+
logger.debug("[AdsService] Ad break done:", { success, status: info?.breakStatus });
|
|
756
556
|
}
|
|
757
|
-
|
|
758
|
-
success,
|
|
759
|
-
type,
|
|
760
|
-
error,
|
|
761
|
-
requestedAt,
|
|
762
|
-
completedAt
|
|
763
|
-
};
|
|
764
|
-
resolve(result);
|
|
557
|
+
resolve({ success, type, error, requestedAt, completedAt });
|
|
765
558
|
}
|
|
766
559
|
};
|
|
767
560
|
if (type === "rewarded") {
|
|
768
|
-
adBreakConfig.beforeReward = (showAdFn) =>
|
|
769
|
-
|
|
770
|
-
console.log("[AdsService] beforeReward callback");
|
|
771
|
-
}
|
|
772
|
-
showAdFn();
|
|
773
|
-
};
|
|
774
|
-
adBreakConfig.adViewed = () => {
|
|
775
|
-
if (this.config.debug) {
|
|
776
|
-
console.log("[AdsService] Rewarded ad watched successfully");
|
|
777
|
-
}
|
|
778
|
-
this.config.onRewardEarned();
|
|
779
|
-
};
|
|
780
|
-
adBreakConfig.adDismissed = () => {
|
|
781
|
-
if (this.config.debug) {
|
|
782
|
-
console.log("[AdsService] Rewarded ad dismissed");
|
|
783
|
-
}
|
|
784
|
-
};
|
|
561
|
+
adBreakConfig.beforeReward = (showAdFn) => showAdFn();
|
|
562
|
+
adBreakConfig.adViewed = () => this.config.onRewardEarned();
|
|
785
563
|
}
|
|
786
564
|
window.adBreak(adBreakConfig);
|
|
787
565
|
});
|
|
788
566
|
}
|
|
789
567
|
/**
|
|
790
568
|
* Returns the configured ad lifecycle callbacks.
|
|
791
|
-
* Used by platform-specific
|
|
792
|
-
* onBeforeAd / onAfterAd / onRewardEarned hooks that the Google H5 path uses.
|
|
569
|
+
* Used by platform-specific providers (e.g. Playgama) to fire the same hooks.
|
|
793
570
|
*/
|
|
794
571
|
getCallbacks() {
|
|
795
572
|
return {
|
|
@@ -799,16 +576,10 @@ var AdsService = class {
|
|
|
799
576
|
};
|
|
800
577
|
}
|
|
801
578
|
/**
|
|
802
|
-
* Check if ads are
|
|
803
|
-
*/
|
|
804
|
-
isEnabled() {
|
|
805
|
-
return this.config.enabled;
|
|
806
|
-
}
|
|
807
|
-
/**
|
|
808
|
-
* Check if ads are ready to show
|
|
579
|
+
* Check if ads have successfully initialized and are ready to show.
|
|
809
580
|
*/
|
|
810
581
|
isReady() {
|
|
811
|
-
return this.
|
|
582
|
+
return this.ready;
|
|
812
583
|
}
|
|
813
584
|
};
|
|
814
585
|
|
|
@@ -855,7 +626,7 @@ var PlaygamaService = class {
|
|
|
855
626
|
this.initialized = true;
|
|
856
627
|
return true;
|
|
857
628
|
} catch (error) {
|
|
858
|
-
|
|
629
|
+
logger.warn("[PlaygamaService] Failed to initialize:", error);
|
|
859
630
|
return false;
|
|
860
631
|
}
|
|
861
632
|
}
|
|
@@ -967,6 +738,176 @@ var PlaygamaService = class {
|
|
|
967
738
|
}
|
|
968
739
|
};
|
|
969
740
|
|
|
741
|
+
// src/services/crazygames.ts
|
|
742
|
+
var CRAZYGAMES_SDK_CDN = "https://sdk.crazygames.com/crazygames-sdk-v2.js";
|
|
743
|
+
var CrazyGamesService = class {
|
|
744
|
+
initialized = false;
|
|
745
|
+
/**
|
|
746
|
+
* Detects if the game is running on the CrazyGames platform.
|
|
747
|
+
* Games on CrazyGames run inside an iframe, so we check document.referrer
|
|
748
|
+
* and attempt to read the parent frame location.
|
|
749
|
+
*/
|
|
750
|
+
static isCrazyGamesDomain() {
|
|
751
|
+
try {
|
|
752
|
+
if (document.referrer.includes("crazygames.com")) {
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
if (window !== window.top) {
|
|
756
|
+
try {
|
|
757
|
+
if (window.parent.location.hostname.includes("crazygames.com")) {
|
|
758
|
+
return true;
|
|
759
|
+
}
|
|
760
|
+
} catch {
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
return false;
|
|
764
|
+
} catch {
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* Loads the CrazyGames SDK from CDN and confirms the environment is 'crazygames'.
|
|
770
|
+
* Safe to call multiple times — resolves immediately if already initialized.
|
|
771
|
+
*/
|
|
772
|
+
async initialize() {
|
|
773
|
+
if (this.initialized) return true;
|
|
774
|
+
try {
|
|
775
|
+
await this.loadScript();
|
|
776
|
+
const sdk = window.CrazyGames?.SDK;
|
|
777
|
+
if (!sdk) {
|
|
778
|
+
logger.warn("[CrazyGamesService] SDK not found after script load");
|
|
779
|
+
return false;
|
|
780
|
+
}
|
|
781
|
+
const env = await sdk.getEnvironment();
|
|
782
|
+
if (env !== "crazygames" && env !== "local") {
|
|
783
|
+
logger.warn("[CrazyGamesService] Unexpected environment:", env);
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
this.initialized = true;
|
|
787
|
+
return true;
|
|
788
|
+
} catch (error) {
|
|
789
|
+
logger.warn("[CrazyGamesService] Failed to initialize:", error);
|
|
790
|
+
return false;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
isInitialized() {
|
|
794
|
+
return this.initialized;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Shows a midgame (interstitial) ad via the CrazyGames SDK.
|
|
798
|
+
*/
|
|
799
|
+
async showInterstitial(callbacks) {
|
|
800
|
+
const requestedAt = Date.now();
|
|
801
|
+
const sdk = window.CrazyGames?.SDK;
|
|
802
|
+
if (!this.initialized || !sdk) {
|
|
803
|
+
return {
|
|
804
|
+
success: false,
|
|
805
|
+
type: "interstitial",
|
|
806
|
+
error: new Error("CrazyGames SDK not initialized"),
|
|
807
|
+
requestedAt,
|
|
808
|
+
completedAt: Date.now()
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
return new Promise((resolve) => {
|
|
812
|
+
sdk.ad.requestAd("midgame", {
|
|
813
|
+
adStarted: () => {
|
|
814
|
+
callbacks?.onBeforeAd?.();
|
|
815
|
+
},
|
|
816
|
+
adFinished: () => {
|
|
817
|
+
callbacks?.onAfterAd?.();
|
|
818
|
+
resolve({ success: true, type: "interstitial", requestedAt, completedAt: Date.now() });
|
|
819
|
+
},
|
|
820
|
+
adError: (error) => {
|
|
821
|
+
callbacks?.onAfterAd?.();
|
|
822
|
+
resolve({
|
|
823
|
+
success: false,
|
|
824
|
+
type: "interstitial",
|
|
825
|
+
error: new Error(`CrazyGames interstitial ad error: ${error}`),
|
|
826
|
+
requestedAt,
|
|
827
|
+
completedAt: Date.now()
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Shows a rewarded ad via the CrazyGames SDK.
|
|
835
|
+
* Resolves with success: true only when adFinished fires (ad was fully watched).
|
|
836
|
+
*/
|
|
837
|
+
async showRewarded(callbacks) {
|
|
838
|
+
const requestedAt = Date.now();
|
|
839
|
+
const sdk = window.CrazyGames?.SDK;
|
|
840
|
+
if (!this.initialized || !sdk) {
|
|
841
|
+
return {
|
|
842
|
+
success: false,
|
|
843
|
+
type: "rewarded",
|
|
844
|
+
error: new Error("CrazyGames SDK not initialized"),
|
|
845
|
+
requestedAt,
|
|
846
|
+
completedAt: Date.now()
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
return new Promise((resolve) => {
|
|
850
|
+
sdk.ad.requestAd("rewarded", {
|
|
851
|
+
adStarted: () => {
|
|
852
|
+
callbacks?.onBeforeAd?.();
|
|
853
|
+
},
|
|
854
|
+
adFinished: () => {
|
|
855
|
+
callbacks?.onRewardEarned?.();
|
|
856
|
+
callbacks?.onAfterAd?.();
|
|
857
|
+
resolve({ success: true, type: "rewarded", requestedAt, completedAt: Date.now() });
|
|
858
|
+
},
|
|
859
|
+
adError: (error) => {
|
|
860
|
+
callbacks?.onAfterAd?.();
|
|
861
|
+
resolve({
|
|
862
|
+
success: false,
|
|
863
|
+
type: "rewarded",
|
|
864
|
+
error: new Error(`CrazyGames rewarded ad error: ${error}`),
|
|
865
|
+
requestedAt,
|
|
866
|
+
completedAt: Date.now()
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Notifies CrazyGames that gameplay has started.
|
|
874
|
+
* Call when the player actively begins or resumes playing.
|
|
875
|
+
*/
|
|
876
|
+
gameplayStart() {
|
|
877
|
+
if (!this.initialized) return;
|
|
878
|
+
window.CrazyGames?.SDK.game.gameplayStart();
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Notifies CrazyGames that gameplay has stopped.
|
|
882
|
+
* Call during menu access, level completion, or pausing.
|
|
883
|
+
*/
|
|
884
|
+
gameplayStop() {
|
|
885
|
+
if (!this.initialized) return;
|
|
886
|
+
window.CrazyGames?.SDK.game.gameplayStop();
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Triggers a celebration effect on the CrazyGames website.
|
|
890
|
+
* Use sparingly for significant achievements (boss defeat, personal record, etc.)
|
|
891
|
+
*/
|
|
892
|
+
happytime() {
|
|
893
|
+
if (!this.initialized) return;
|
|
894
|
+
window.CrazyGames?.SDK.game.happytime();
|
|
895
|
+
}
|
|
896
|
+
loadScript() {
|
|
897
|
+
return new Promise((resolve, reject) => {
|
|
898
|
+
if (window.CrazyGames?.SDK) {
|
|
899
|
+
resolve();
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
const script = document.createElement("script");
|
|
903
|
+
script.src = CRAZYGAMES_SDK_CDN;
|
|
904
|
+
script.onload = () => resolve();
|
|
905
|
+
script.onerror = () => reject(new Error("Failed to load CrazyGames SDK script"));
|
|
906
|
+
document.head.appendChild(script);
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
|
|
970
911
|
// src/services/billing.ts
|
|
971
912
|
var BillingPlatform = /* @__PURE__ */ ((BillingPlatform3) => {
|
|
972
913
|
BillingPlatform3["WEB"] = "web";
|
|
@@ -977,41 +918,28 @@ var BillingPlatform = /* @__PURE__ */ ((BillingPlatform3) => {
|
|
|
977
918
|
var BillingService = class {
|
|
978
919
|
config;
|
|
979
920
|
platform = "unknown" /* UNKNOWN */;
|
|
980
|
-
|
|
921
|
+
initPromise = null;
|
|
981
922
|
nativeAvailable = false;
|
|
982
|
-
products = [];
|
|
983
923
|
// Stripe instance for web payments
|
|
984
924
|
stripe = null;
|
|
985
925
|
checkoutElement = null;
|
|
986
926
|
// Callbacks for purchase events
|
|
987
927
|
onPurchaseCompleteCallback;
|
|
988
928
|
onPurchaseErrorCallback;
|
|
989
|
-
// Callback for logging (so external UI can capture logs)
|
|
990
|
-
onLogCallback;
|
|
991
929
|
constructor(config) {
|
|
992
930
|
this.config = config;
|
|
993
931
|
this.detectPlatform();
|
|
994
932
|
}
|
|
995
933
|
/**
|
|
996
|
-
*
|
|
997
|
-
* Useful for displaying logs in a UI
|
|
934
|
+
* Update billing configuration. Resets initialization so next call re-inits with new config.
|
|
998
935
|
*/
|
|
999
|
-
|
|
1000
|
-
this.
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
const consoleMethod = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
1007
|
-
if (data !== void 0) {
|
|
1008
|
-
consoleMethod(message, data);
|
|
1009
|
-
} else {
|
|
1010
|
-
consoleMethod(message);
|
|
1011
|
-
}
|
|
1012
|
-
if (this.onLogCallback) {
|
|
1013
|
-
this.onLogCallback(level, message, data);
|
|
1014
|
-
}
|
|
936
|
+
configure(config) {
|
|
937
|
+
this.config = {
|
|
938
|
+
...this.config,
|
|
939
|
+
...config
|
|
940
|
+
};
|
|
941
|
+
this.initPromise = null;
|
|
942
|
+
logger.info("[BillingService] Configuration updated");
|
|
1015
943
|
}
|
|
1016
944
|
/**
|
|
1017
945
|
* Detects if running on web or native platform
|
|
@@ -1021,13 +949,13 @@ var BillingService = class {
|
|
|
1021
949
|
const hasWindow = typeof window !== "undefined";
|
|
1022
950
|
if (isNative) {
|
|
1023
951
|
this.platform = "native" /* NATIVE */;
|
|
1024
|
-
|
|
952
|
+
logger.info("[BillingService] Platform: NATIVE");
|
|
1025
953
|
} else if (hasWindow) {
|
|
1026
954
|
this.platform = "web" /* WEB */;
|
|
1027
|
-
|
|
955
|
+
logger.info("[BillingService] Platform: WEB");
|
|
1028
956
|
} else {
|
|
1029
957
|
this.platform = "unknown" /* UNKNOWN */;
|
|
1030
|
-
|
|
958
|
+
logger.warn("[BillingService] Platform: UNKNOWN");
|
|
1031
959
|
}
|
|
1032
960
|
}
|
|
1033
961
|
/**
|
|
@@ -1037,38 +965,40 @@ var BillingService = class {
|
|
|
1037
965
|
return this.platform;
|
|
1038
966
|
}
|
|
1039
967
|
/**
|
|
1040
|
-
* Initialize the billing service
|
|
1041
|
-
*
|
|
968
|
+
* Initialize the billing service. Idempotent — returns cached promise on subsequent calls.
|
|
969
|
+
* Called automatically by getProducts() and purchase().
|
|
1042
970
|
*/
|
|
1043
|
-
|
|
1044
|
-
if (this.
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
971
|
+
initialize() {
|
|
972
|
+
if (this.initPromise) return this.initPromise;
|
|
973
|
+
logger.info(`[BillingService] Initializing for ${this.platform} platform...`);
|
|
974
|
+
this.initPromise = (async () => {
|
|
975
|
+
try {
|
|
976
|
+
if (this.platform === "native" /* NATIVE */) {
|
|
977
|
+
return await this.initializeNative();
|
|
978
|
+
} else if (this.platform === "web" /* WEB */) {
|
|
979
|
+
return await this.initializeWeb();
|
|
980
|
+
}
|
|
981
|
+
logger.error("[BillingService] Cannot initialize: unknown platform");
|
|
982
|
+
return false;
|
|
983
|
+
} catch (error) {
|
|
984
|
+
logger.error("[BillingService] Initialization failed:", error?.message);
|
|
985
|
+
return false;
|
|
1053
986
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
} catch (error) {
|
|
1057
|
-
this.log("error", "[BillingService] Initialization failed:", error?.message);
|
|
1058
|
-
return false;
|
|
1059
|
-
}
|
|
987
|
+
})();
|
|
988
|
+
return this.initPromise;
|
|
1060
989
|
}
|
|
1061
990
|
/**
|
|
1062
991
|
* Initialize native billing
|
|
1063
992
|
*/
|
|
1064
993
|
async initializeNative() {
|
|
1065
994
|
return new Promise((resolve) => {
|
|
995
|
+
let resolved = false;
|
|
1066
996
|
try {
|
|
1067
997
|
NativeBridge.initialize();
|
|
1068
998
|
NativeBridge.on(
|
|
1069
999
|
"PURCHASE_COMPLETE" /* PURCHASE_COMPLETE */,
|
|
1070
1000
|
(payload) => {
|
|
1071
|
-
|
|
1001
|
+
logger.info("[BillingService] Purchase complete:", payload.productId);
|
|
1072
1002
|
const result = {
|
|
1073
1003
|
success: true,
|
|
1074
1004
|
productId: payload.productId,
|
|
@@ -1083,7 +1013,7 @@ var BillingService = class {
|
|
|
1083
1013
|
NativeBridge.on(
|
|
1084
1014
|
"PURCHASE_ERROR" /* PURCHASE_ERROR */,
|
|
1085
1015
|
(payload) => {
|
|
1086
|
-
|
|
1016
|
+
logger.error("[BillingService] Purchase error:", payload.message);
|
|
1087
1017
|
const result = {
|
|
1088
1018
|
success: false,
|
|
1089
1019
|
productId: payload.productId || "unknown",
|
|
@@ -1101,8 +1031,8 @@ var BillingService = class {
|
|
|
1101
1031
|
"IAP_AVAILABILITY_RESULT" /* IAP_AVAILABILITY_RESULT */,
|
|
1102
1032
|
(payload) => {
|
|
1103
1033
|
this.nativeAvailable = payload.available;
|
|
1104
|
-
|
|
1105
|
-
|
|
1034
|
+
logger.info(`[BillingService] Native billing ${payload.available ? "available" : "unavailable"}`);
|
|
1035
|
+
resolved = true;
|
|
1106
1036
|
resolve(payload.available);
|
|
1107
1037
|
}
|
|
1108
1038
|
);
|
|
@@ -1110,15 +1040,15 @@ var BillingService = class {
|
|
|
1110
1040
|
NativeBridge.checkIAPAvailability();
|
|
1111
1041
|
}, 100);
|
|
1112
1042
|
setTimeout(() => {
|
|
1113
|
-
if (!
|
|
1114
|
-
|
|
1115
|
-
|
|
1043
|
+
if (!resolved) {
|
|
1044
|
+
logger.warn("[BillingService] Native initialization timeout");
|
|
1045
|
+
resolved = true;
|
|
1116
1046
|
resolve(false);
|
|
1117
1047
|
}
|
|
1118
1048
|
}, 5e3);
|
|
1119
1049
|
} catch (error) {
|
|
1120
|
-
|
|
1121
|
-
|
|
1050
|
+
logger.error("[BillingService] Native initialization failed:", error?.message);
|
|
1051
|
+
resolved = true;
|
|
1122
1052
|
resolve(false);
|
|
1123
1053
|
}
|
|
1124
1054
|
});
|
|
@@ -1128,12 +1058,12 @@ var BillingService = class {
|
|
|
1128
1058
|
*/
|
|
1129
1059
|
async initializeWeb() {
|
|
1130
1060
|
if (!this.config.stripePublishableKey) {
|
|
1131
|
-
|
|
1061
|
+
logger.error("[BillingService] Stripe publishable key not provided");
|
|
1132
1062
|
return false;
|
|
1133
1063
|
}
|
|
1134
1064
|
try {
|
|
1135
1065
|
if (typeof window === "undefined") {
|
|
1136
|
-
|
|
1066
|
+
logger.error("[BillingService] Window is undefined (not in browser)");
|
|
1137
1067
|
return false;
|
|
1138
1068
|
}
|
|
1139
1069
|
if (!window.Stripe) {
|
|
@@ -1141,15 +1071,14 @@ var BillingService = class {
|
|
|
1141
1071
|
}
|
|
1142
1072
|
if (window.Stripe) {
|
|
1143
1073
|
this.stripe = window.Stripe(this.config.stripePublishableKey);
|
|
1144
|
-
|
|
1145
|
-
this.log("info", "[BillingService] Web billing initialized");
|
|
1074
|
+
logger.info("[BillingService] Web billing initialized");
|
|
1146
1075
|
return true;
|
|
1147
1076
|
} else {
|
|
1148
|
-
|
|
1077
|
+
logger.error("[BillingService] Stripe not available after loading");
|
|
1149
1078
|
return false;
|
|
1150
1079
|
}
|
|
1151
1080
|
} catch (error) {
|
|
1152
|
-
|
|
1081
|
+
logger.error("[BillingService] Stripe initialization failed:", error?.message);
|
|
1153
1082
|
return false;
|
|
1154
1083
|
}
|
|
1155
1084
|
}
|
|
@@ -1174,11 +1103,11 @@ var BillingService = class {
|
|
|
1174
1103
|
script.src = "https://js.stripe.com/v3/";
|
|
1175
1104
|
script.async = true;
|
|
1176
1105
|
script.onload = () => {
|
|
1177
|
-
|
|
1106
|
+
logger.info("[BillingService] Stripe.js loaded");
|
|
1178
1107
|
resolve();
|
|
1179
1108
|
};
|
|
1180
1109
|
script.onerror = () => {
|
|
1181
|
-
|
|
1110
|
+
logger.error("[BillingService] Failed to load Stripe.js");
|
|
1182
1111
|
reject(new Error("Failed to load Stripe.js"));
|
|
1183
1112
|
};
|
|
1184
1113
|
try {
|
|
@@ -1189,12 +1118,9 @@ var BillingService = class {
|
|
|
1189
1118
|
});
|
|
1190
1119
|
}
|
|
1191
1120
|
/**
|
|
1192
|
-
* Check if billing is available
|
|
1121
|
+
* Check if billing is available based on current config and platform state
|
|
1193
1122
|
*/
|
|
1194
1123
|
isAvailable() {
|
|
1195
|
-
if (!this.isInitialized) {
|
|
1196
|
-
return false;
|
|
1197
|
-
}
|
|
1198
1124
|
if (this.platform === "native" /* NATIVE */) {
|
|
1199
1125
|
return this.nativeAvailable;
|
|
1200
1126
|
} else if (this.platform === "web" /* WEB */) {
|
|
@@ -1203,12 +1129,10 @@ var BillingService = class {
|
|
|
1203
1129
|
return false;
|
|
1204
1130
|
}
|
|
1205
1131
|
/**
|
|
1206
|
-
* Get available products
|
|
1132
|
+
* Get available products. Auto-initializes on first call.
|
|
1207
1133
|
*/
|
|
1208
1134
|
async getProducts() {
|
|
1209
|
-
|
|
1210
|
-
throw new Error("BillingService not initialized. Call initialize() first.");
|
|
1211
|
-
}
|
|
1135
|
+
await this.initialize();
|
|
1212
1136
|
if (this.platform === "native" /* NATIVE */) {
|
|
1213
1137
|
return await this.getProductsNative();
|
|
1214
1138
|
} else if (this.platform === "web" /* WEB */) {
|
|
@@ -1220,38 +1144,31 @@ var BillingService = class {
|
|
|
1220
1144
|
* Get products from native IAP
|
|
1221
1145
|
*/
|
|
1222
1146
|
async getProductsNative() {
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
this.log("info", `[BillingService] Fetched ${this.products.length} native products`);
|
|
1249
|
-
resolve(this.products);
|
|
1250
|
-
}).catch((error) => {
|
|
1251
|
-
this.log("error", "[BillingService] Failed to fetch native products:", error?.message);
|
|
1252
|
-
reject(error);
|
|
1253
|
-
});
|
|
1254
|
-
});
|
|
1147
|
+
if (!this.config.gameId || !this.config.checkoutUrl) {
|
|
1148
|
+
const error = new Error("gameId and checkoutUrl required for native purchases");
|
|
1149
|
+
logger.error("[BillingService]", error.message);
|
|
1150
|
+
throw error;
|
|
1151
|
+
}
|
|
1152
|
+
const response = await fetch(
|
|
1153
|
+
`${this.config.checkoutUrl}/get-native-packages?game_id=${this.config.gameId}`
|
|
1154
|
+
);
|
|
1155
|
+
if (!response.ok) {
|
|
1156
|
+
throw new Error(`Failed to fetch native products: ${response.status}`);
|
|
1157
|
+
}
|
|
1158
|
+
const data = await response.json();
|
|
1159
|
+
if (!data.packages || !Array.isArray(data.packages)) {
|
|
1160
|
+
throw new Error("Invalid response format: missing packages array");
|
|
1161
|
+
}
|
|
1162
|
+
const products = data.packages.map((pkg) => ({
|
|
1163
|
+
productId: pkg.productId,
|
|
1164
|
+
title: pkg.package_name,
|
|
1165
|
+
description: `${pkg.game_name} - ${pkg.package_name}`,
|
|
1166
|
+
price: pkg.price_cents / 100,
|
|
1167
|
+
localizedPrice: pkg.price_display,
|
|
1168
|
+
currency: "USD"
|
|
1169
|
+
}));
|
|
1170
|
+
logger.info(`[BillingService] Fetched ${products.length} native products`);
|
|
1171
|
+
return products;
|
|
1255
1172
|
}
|
|
1256
1173
|
/**
|
|
1257
1174
|
* Get products from web API (Stripe)
|
|
@@ -1259,7 +1176,7 @@ var BillingService = class {
|
|
|
1259
1176
|
async getProductsWeb() {
|
|
1260
1177
|
if (!this.config.checkoutUrl || !this.config.gameId) {
|
|
1261
1178
|
const error = new Error("checkoutUrl and gameId required for web purchases");
|
|
1262
|
-
|
|
1179
|
+
logger.error("[BillingService]", error.message);
|
|
1263
1180
|
throw error;
|
|
1264
1181
|
}
|
|
1265
1182
|
try {
|
|
@@ -1272,7 +1189,7 @@ var BillingService = class {
|
|
|
1272
1189
|
if (!data.packages || !Array.isArray(data.packages)) {
|
|
1273
1190
|
throw new Error("Invalid response format: missing packages array");
|
|
1274
1191
|
}
|
|
1275
|
-
|
|
1192
|
+
const products = data.packages.map((pkg) => ({
|
|
1276
1193
|
productId: pkg.priceId || pkg.productId,
|
|
1277
1194
|
// Prefer priceId for Stripe
|
|
1278
1195
|
title: pkg.package_name,
|
|
@@ -1281,23 +1198,21 @@ var BillingService = class {
|
|
|
1281
1198
|
localizedPrice: pkg.price_display,
|
|
1282
1199
|
currency: "USD"
|
|
1283
1200
|
}));
|
|
1284
|
-
|
|
1285
|
-
return
|
|
1201
|
+
logger.info(`[BillingService] Fetched ${products.length} web products`);
|
|
1202
|
+
return products;
|
|
1286
1203
|
} catch (error) {
|
|
1287
|
-
|
|
1204
|
+
logger.error("[BillingService] Failed to fetch web products:", error?.message);
|
|
1288
1205
|
throw error;
|
|
1289
1206
|
}
|
|
1290
1207
|
}
|
|
1291
1208
|
/**
|
|
1292
|
-
* Purchase a product
|
|
1209
|
+
* Purchase a product. Auto-initializes on first call.
|
|
1293
1210
|
* @param productId - The product ID (priceId for web/Stripe, productId for native)
|
|
1294
1211
|
* @param options - Optional purchase options
|
|
1295
1212
|
* @param options.elementId - For web: DOM element ID to mount Stripe checkout (default: 'stripe-checkout-element')
|
|
1296
1213
|
*/
|
|
1297
1214
|
async purchase(productId, options) {
|
|
1298
|
-
|
|
1299
|
-
throw new Error("BillingService not initialized. Call initialize() first.");
|
|
1300
|
-
}
|
|
1215
|
+
await this.initialize();
|
|
1301
1216
|
if (!this.isAvailable()) {
|
|
1302
1217
|
throw new Error("Billing is not available on this platform");
|
|
1303
1218
|
}
|
|
@@ -1317,7 +1232,7 @@ var BillingService = class {
|
|
|
1317
1232
|
reject(new Error("userId is required for native purchases"));
|
|
1318
1233
|
return;
|
|
1319
1234
|
}
|
|
1320
|
-
|
|
1235
|
+
logger.info(`[BillingService] Purchasing: ${productId}`);
|
|
1321
1236
|
const previousCompleteCallback = this.onPurchaseCompleteCallback;
|
|
1322
1237
|
const previousErrorCallback = this.onPurchaseErrorCallback;
|
|
1323
1238
|
const cleanup = () => {
|
|
@@ -1391,14 +1306,14 @@ var BillingService = class {
|
|
|
1391
1306
|
throw new Error("No client_secret returned from checkout session");
|
|
1392
1307
|
}
|
|
1393
1308
|
await this.mountCheckoutElement(client_secret, elementId || "stripe-checkout-element");
|
|
1394
|
-
|
|
1309
|
+
logger.info(`[BillingService] Checkout session created: ${id}`);
|
|
1395
1310
|
return {
|
|
1396
1311
|
success: true,
|
|
1397
1312
|
productId,
|
|
1398
1313
|
transactionId: id
|
|
1399
1314
|
};
|
|
1400
1315
|
} catch (error) {
|
|
1401
|
-
|
|
1316
|
+
logger.error("[BillingService] Web purchase failed:", error?.message);
|
|
1402
1317
|
return {
|
|
1403
1318
|
success: false,
|
|
1404
1319
|
productId,
|
|
@@ -1420,7 +1335,7 @@ var BillingService = class {
|
|
|
1420
1335
|
}
|
|
1421
1336
|
try {
|
|
1422
1337
|
if (this.checkoutElement) {
|
|
1423
|
-
|
|
1338
|
+
logger.info("[BillingService] Unmounting existing checkout element");
|
|
1424
1339
|
this.unmountCheckoutElement();
|
|
1425
1340
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1426
1341
|
}
|
|
@@ -1429,15 +1344,15 @@ var BillingService = class {
|
|
|
1429
1344
|
throw new Error(`Element with id "${elementId}" not found in the DOM`);
|
|
1430
1345
|
}
|
|
1431
1346
|
container.innerHTML = "";
|
|
1432
|
-
|
|
1347
|
+
logger.info("[BillingService] Creating new checkout instance");
|
|
1433
1348
|
this.checkoutElement = await this.stripe.initEmbeddedCheckout({
|
|
1434
1349
|
clientSecret
|
|
1435
1350
|
});
|
|
1436
|
-
|
|
1351
|
+
logger.info("[BillingService] Mounting checkout element to DOM");
|
|
1437
1352
|
this.checkoutElement.mount(`#${elementId}`);
|
|
1438
1353
|
this.setupCheckoutEventListeners();
|
|
1439
1354
|
} catch (error) {
|
|
1440
|
-
|
|
1355
|
+
logger.error("[BillingService] Failed to mount checkout:", error?.message);
|
|
1441
1356
|
throw error;
|
|
1442
1357
|
}
|
|
1443
1358
|
}
|
|
@@ -1458,7 +1373,7 @@ var BillingService = class {
|
|
|
1458
1373
|
transactionId: sessionId || void 0
|
|
1459
1374
|
});
|
|
1460
1375
|
}
|
|
1461
|
-
|
|
1376
|
+
logger.info("[BillingService] Payment completed");
|
|
1462
1377
|
urlParams.delete("payment");
|
|
1463
1378
|
urlParams.delete("session_id");
|
|
1464
1379
|
const newUrl = `${window.location.pathname}${urlParams.toString() ? "?" + urlParams.toString() : ""}`;
|
|
@@ -1477,7 +1392,7 @@ var BillingService = class {
|
|
|
1477
1392
|
this.checkoutElement.destroy();
|
|
1478
1393
|
}
|
|
1479
1394
|
} catch (error) {
|
|
1480
|
-
|
|
1395
|
+
logger.warn("[BillingService] Error unmounting checkout element:", error?.message);
|
|
1481
1396
|
}
|
|
1482
1397
|
this.checkoutElement = null;
|
|
1483
1398
|
}
|
|
@@ -1505,9 +1420,8 @@ var BillingService = class {
|
|
|
1505
1420
|
NativeBridge.off("PURCHASE_ERROR" /* PURCHASE_ERROR */);
|
|
1506
1421
|
}
|
|
1507
1422
|
this.unmountCheckoutElement();
|
|
1508
|
-
this.
|
|
1423
|
+
this.initPromise = null;
|
|
1509
1424
|
this.nativeAvailable = false;
|
|
1510
|
-
this.products = [];
|
|
1511
1425
|
this.stripe = null;
|
|
1512
1426
|
this.onPurchaseCompleteCallback = void 0;
|
|
1513
1427
|
this.onPurchaseErrorCallback = void 0;
|
|
@@ -1680,10 +1594,9 @@ var HyveClient = class {
|
|
|
1680
1594
|
adsService;
|
|
1681
1595
|
playgamaService = null;
|
|
1682
1596
|
playgamaInitPromise = null;
|
|
1597
|
+
crazyGamesService = null;
|
|
1598
|
+
crazyGamesInitPromise = null;
|
|
1683
1599
|
billingService;
|
|
1684
|
-
billingConfig;
|
|
1685
|
-
// Store callbacks to preserve them when recreating BillingService
|
|
1686
|
-
billingCallbacks = {};
|
|
1687
1600
|
storageMode;
|
|
1688
1601
|
cloudStorageAdapter;
|
|
1689
1602
|
localStorageAdapter;
|
|
@@ -1714,13 +1627,28 @@ var HyveClient = class {
|
|
|
1714
1627
|
return success;
|
|
1715
1628
|
});
|
|
1716
1629
|
}
|
|
1717
|
-
|
|
1718
|
-
|
|
1630
|
+
if (typeof window !== "undefined" && CrazyGamesService.isCrazyGamesDomain()) {
|
|
1631
|
+
this.crazyGamesService = new CrazyGamesService();
|
|
1632
|
+
this.crazyGamesInitPromise = this.crazyGamesService.initialize().then((success) => {
|
|
1633
|
+
logger.info("CrazyGames SDK initialized:", success);
|
|
1634
|
+
return success;
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1719
1637
|
this.storageMode = config?.storageMode || "cloud";
|
|
1720
1638
|
this.cloudStorageAdapter = new CloudStorageAdapter(
|
|
1721
1639
|
(endpoint, options) => this.callApi(endpoint, options)
|
|
1722
1640
|
);
|
|
1723
1641
|
this.localStorageAdapter = new LocalStorageAdapter(() => this.getUserId());
|
|
1642
|
+
if (typeof window !== "undefined") {
|
|
1643
|
+
this._parseUrlAuth();
|
|
1644
|
+
}
|
|
1645
|
+
const billingConfig = {
|
|
1646
|
+
checkoutUrl: this.apiBaseUrl,
|
|
1647
|
+
userId: this.userId ?? void 0,
|
|
1648
|
+
gameId: this.gameId ? Number(this.gameId) : void 0,
|
|
1649
|
+
...config?.billing
|
|
1650
|
+
};
|
|
1651
|
+
this.billingService = new BillingService(billingConfig);
|
|
1724
1652
|
const envSource = config?.isDev !== void 0 ? "explicit config" : "auto-detected from parent URL";
|
|
1725
1653
|
logger.info("==========================================");
|
|
1726
1654
|
logger.info("HyveClient Initialized");
|
|
@@ -1732,28 +1660,27 @@ var HyveClient = class {
|
|
|
1732
1660
|
`(${envSource})`
|
|
1733
1661
|
);
|
|
1734
1662
|
logger.info("API Base URL:", this.apiBaseUrl);
|
|
1735
|
-
logger.info("Ads enabled:", this.adsService.isEnabled());
|
|
1736
1663
|
logger.info("Playgama platform:", this.playgamaService !== null);
|
|
1664
|
+
logger.info("CrazyGames platform:", this.crazyGamesService !== null);
|
|
1737
1665
|
logger.info(
|
|
1738
1666
|
"Billing configured:",
|
|
1739
|
-
Object.keys(
|
|
1667
|
+
!!config?.billing && Object.keys(config.billing).length > 0
|
|
1740
1668
|
);
|
|
1741
1669
|
logger.info("Storage mode:", this.storageMode);
|
|
1670
|
+
logger.info("Authenticated:", this.jwtToken !== null);
|
|
1742
1671
|
logger.debug("Config:", {
|
|
1743
1672
|
isDev: this.telemetryConfig.isDev,
|
|
1744
1673
|
hasCustomApiUrl: !!config?.apiBaseUrl,
|
|
1745
|
-
|
|
1746
|
-
billingConfigured: Object.keys(this.billingConfig).length > 0,
|
|
1674
|
+
billingConfigured: !!config?.billing && Object.keys(config.billing).length > 0,
|
|
1747
1675
|
storageMode: this.storageMode
|
|
1748
1676
|
});
|
|
1749
1677
|
logger.info("==========================================");
|
|
1750
1678
|
}
|
|
1751
1679
|
/**
|
|
1752
|
-
*
|
|
1753
|
-
*
|
|
1754
|
-
* @returns Promise resolving to boolean indicating success
|
|
1680
|
+
* Parses JWT and game ID from the current window URL and stores them on the client.
|
|
1681
|
+
* Called automatically during construction.
|
|
1755
1682
|
*/
|
|
1756
|
-
|
|
1683
|
+
_parseUrlAuth(urlParams) {
|
|
1757
1684
|
try {
|
|
1758
1685
|
const params = urlParams ? parseUrlParams(urlParams) : parseUrlParams(window.location.search);
|
|
1759
1686
|
if (params.hyveAccess) {
|
|
@@ -1778,27 +1705,11 @@ var HyveClient = class {
|
|
|
1778
1705
|
}
|
|
1779
1706
|
if (this.jwtToken) {
|
|
1780
1707
|
logger.info("Authentication successful via JWT");
|
|
1781
|
-
return true;
|
|
1782
|
-
}
|
|
1783
|
-
const authResult = verifyAuthentication({
|
|
1784
|
-
hyveToken: params.hyveToken,
|
|
1785
|
-
signature: params.signature,
|
|
1786
|
-
message: params.message
|
|
1787
|
-
});
|
|
1788
|
-
if (authResult.isValid && authResult.address) {
|
|
1789
|
-
this.userId = authResult.address;
|
|
1790
|
-
logger.info("Authentication successful:", authResult.address);
|
|
1791
|
-
logger.info("Authentication method:", authResult.method);
|
|
1792
|
-
return true;
|
|
1793
1708
|
} else {
|
|
1794
|
-
logger.
|
|
1795
|
-
this.userId = null;
|
|
1796
|
-
return false;
|
|
1709
|
+
logger.info("No hyve-access JWT token in URL \u2014 unauthenticated");
|
|
1797
1710
|
}
|
|
1798
1711
|
} catch (error) {
|
|
1799
|
-
logger.error("
|
|
1800
|
-
this.userId = null;
|
|
1801
|
-
return false;
|
|
1712
|
+
logger.error("Error parsing URL auth:", error);
|
|
1802
1713
|
}
|
|
1803
1714
|
}
|
|
1804
1715
|
/**
|
|
@@ -1815,7 +1726,7 @@ var HyveClient = class {
|
|
|
1815
1726
|
*/
|
|
1816
1727
|
async sendTelemetry(eventLocation, eventCategory, eventAction, eventSubCategory, eventSubAction, eventDetails, platformId) {
|
|
1817
1728
|
if (!this.jwtToken) {
|
|
1818
|
-
logger.error("JWT token required.
|
|
1729
|
+
logger.error("JWT token required. Ensure hyve-access and game-id are present in the URL.");
|
|
1819
1730
|
return false;
|
|
1820
1731
|
}
|
|
1821
1732
|
if (!this.gameId) {
|
|
@@ -1887,7 +1798,7 @@ var HyveClient = class {
|
|
|
1887
1798
|
async callApi(endpoint, options = {}) {
|
|
1888
1799
|
if (!this.jwtToken) {
|
|
1889
1800
|
throw new Error(
|
|
1890
|
-
"No JWT token available.
|
|
1801
|
+
"No JWT token available. Ensure hyve-access and game-id are present in the URL."
|
|
1891
1802
|
);
|
|
1892
1803
|
}
|
|
1893
1804
|
try {
|
|
@@ -2017,6 +1928,13 @@ var HyveClient = class {
|
|
|
2017
1928
|
const storageMode = mode || this.storageMode;
|
|
2018
1929
|
return storageMode === "local" ? this.localStorageAdapter : this.cloudStorageAdapter;
|
|
2019
1930
|
}
|
|
1931
|
+
/**
|
|
1932
|
+
* Returns the current game ID or throws if not available.
|
|
1933
|
+
*/
|
|
1934
|
+
requireGameId() {
|
|
1935
|
+
const gameId = this.requireGameId();
|
|
1936
|
+
return gameId;
|
|
1937
|
+
}
|
|
2020
1938
|
/**
|
|
2021
1939
|
* Save persistent game data
|
|
2022
1940
|
* @param key Data key
|
|
@@ -2025,10 +1943,7 @@ var HyveClient = class {
|
|
|
2025
1943
|
* @returns Promise resolving to save response
|
|
2026
1944
|
*/
|
|
2027
1945
|
async saveGameData(key, value, storage) {
|
|
2028
|
-
const gameId = this.
|
|
2029
|
-
if (!gameId) {
|
|
2030
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2031
|
-
}
|
|
1946
|
+
const gameId = this.requireGameId();
|
|
2032
1947
|
const storageMode = storage || this.storageMode;
|
|
2033
1948
|
logger.debug(`Saving game data to ${storageMode}: ${gameId}/${key}`);
|
|
2034
1949
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2043,10 +1958,7 @@ var HyveClient = class {
|
|
|
2043
1958
|
* @returns Promise resolving to save response
|
|
2044
1959
|
*/
|
|
2045
1960
|
async batchSaveGameData(items, storage) {
|
|
2046
|
-
const gameId = this.
|
|
2047
|
-
if (!gameId) {
|
|
2048
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2049
|
-
}
|
|
1961
|
+
const gameId = this.requireGameId();
|
|
2050
1962
|
const storageMode = storage || this.storageMode;
|
|
2051
1963
|
logger.debug(`Batch saving ${items.length} game data entries to ${storageMode} for game: ${gameId}`);
|
|
2052
1964
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2061,10 +1973,7 @@ var HyveClient = class {
|
|
|
2061
1973
|
* @returns Promise resolving to game data item or null if not found
|
|
2062
1974
|
*/
|
|
2063
1975
|
async getGameData(key, storage) {
|
|
2064
|
-
const gameId = this.
|
|
2065
|
-
if (!gameId) {
|
|
2066
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2067
|
-
}
|
|
1976
|
+
const gameId = this.requireGameId();
|
|
2068
1977
|
const storageMode = storage || this.storageMode;
|
|
2069
1978
|
logger.debug(`Getting game data from ${storageMode}: ${gameId}/${key}`);
|
|
2070
1979
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2083,10 +1992,7 @@ var HyveClient = class {
|
|
|
2083
1992
|
* @returns Promise resolving to array of game data items
|
|
2084
1993
|
*/
|
|
2085
1994
|
async getMultipleGameData(keys, storage) {
|
|
2086
|
-
const gameId = this.
|
|
2087
|
-
if (!gameId) {
|
|
2088
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2089
|
-
}
|
|
1995
|
+
const gameId = this.requireGameId();
|
|
2090
1996
|
const storageMode = storage || this.storageMode;
|
|
2091
1997
|
logger.debug(`Getting ${keys.length} game data entries from ${storageMode} for game: ${gameId}`);
|
|
2092
1998
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2101,10 +2007,7 @@ var HyveClient = class {
|
|
|
2101
2007
|
* @returns Promise resolving to boolean indicating if data was deleted
|
|
2102
2008
|
*/
|
|
2103
2009
|
async deleteGameData(key, storage) {
|
|
2104
|
-
const gameId = this.
|
|
2105
|
-
if (!gameId) {
|
|
2106
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2107
|
-
}
|
|
2010
|
+
const gameId = this.requireGameId();
|
|
2108
2011
|
const storageMode = storage || this.storageMode;
|
|
2109
2012
|
logger.debug(`Deleting game data from ${storageMode}: ${gameId}/${key}`);
|
|
2110
2013
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2123,10 +2026,7 @@ var HyveClient = class {
|
|
|
2123
2026
|
* @returns Promise resolving to number of entries deleted
|
|
2124
2027
|
*/
|
|
2125
2028
|
async deleteMultipleGameData(keys, storage) {
|
|
2126
|
-
const gameId = this.
|
|
2127
|
-
if (!gameId) {
|
|
2128
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2129
|
-
}
|
|
2029
|
+
const gameId = this.requireGameId();
|
|
2130
2030
|
const storageMode = storage || this.storageMode;
|
|
2131
2031
|
logger.debug(`Deleting ${keys.length} game data entries from ${storageMode} for game: ${gameId}`);
|
|
2132
2032
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2163,6 +2063,25 @@ var HyveClient = class {
|
|
|
2163
2063
|
* @returns Promise resolving to ad result
|
|
2164
2064
|
*/
|
|
2165
2065
|
async showAd(type) {
|
|
2066
|
+
if (this.crazyGamesService) {
|
|
2067
|
+
if (this.crazyGamesInitPromise) {
|
|
2068
|
+
await this.crazyGamesInitPromise;
|
|
2069
|
+
}
|
|
2070
|
+
if (this.crazyGamesService.isInitialized()) {
|
|
2071
|
+
const { onBeforeAd, onAfterAd, onRewardEarned } = this.adsService.getCallbacks();
|
|
2072
|
+
if (type === "rewarded") {
|
|
2073
|
+
return this.crazyGamesService.showRewarded({
|
|
2074
|
+
onBeforeAd: () => onBeforeAd("rewarded"),
|
|
2075
|
+
onAfterAd: () => onAfterAd("rewarded"),
|
|
2076
|
+
onRewardEarned
|
|
2077
|
+
});
|
|
2078
|
+
}
|
|
2079
|
+
return this.crazyGamesService.showInterstitial({
|
|
2080
|
+
onBeforeAd: () => onBeforeAd(type),
|
|
2081
|
+
onAfterAd: () => onAfterAd(type)
|
|
2082
|
+
});
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2166
2085
|
if (this.playgamaService) {
|
|
2167
2086
|
if (this.playgamaInitPromise) {
|
|
2168
2087
|
await this.playgamaInitPromise;
|
|
@@ -2185,59 +2104,41 @@ var HyveClient = class {
|
|
|
2185
2104
|
return this.adsService.show(type);
|
|
2186
2105
|
}
|
|
2187
2106
|
/**
|
|
2188
|
-
*
|
|
2189
|
-
*
|
|
2107
|
+
* Notifies CrazyGames that gameplay has started.
|
|
2108
|
+
* No-op on other platforms.
|
|
2190
2109
|
*/
|
|
2191
|
-
|
|
2192
|
-
|
|
2110
|
+
async gameplayStart() {
|
|
2111
|
+
if (this.crazyGamesService) {
|
|
2112
|
+
if (this.crazyGamesInitPromise) await this.crazyGamesInitPromise;
|
|
2113
|
+
this.crazyGamesService.gameplayStart();
|
|
2114
|
+
}
|
|
2193
2115
|
}
|
|
2194
2116
|
/**
|
|
2195
|
-
*
|
|
2196
|
-
*
|
|
2117
|
+
* Notifies CrazyGames that gameplay has stopped.
|
|
2118
|
+
* No-op on other platforms.
|
|
2197
2119
|
*/
|
|
2198
|
-
|
|
2199
|
-
|
|
2120
|
+
async gameplayStop() {
|
|
2121
|
+
if (this.crazyGamesService) {
|
|
2122
|
+
if (this.crazyGamesInitPromise) await this.crazyGamesInitPromise;
|
|
2123
|
+
this.crazyGamesService.gameplayStop();
|
|
2124
|
+
}
|
|
2200
2125
|
}
|
|
2201
2126
|
/**
|
|
2202
|
-
*
|
|
2203
|
-
*
|
|
2127
|
+
* Triggers a celebration effect on the CrazyGames website for significant achievements.
|
|
2128
|
+
* No-op on other platforms.
|
|
2204
2129
|
*/
|
|
2205
|
-
|
|
2206
|
-
this.
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
}
|
|
2210
|
-
logger.info("Billing configuration updated");
|
|
2130
|
+
async happytime() {
|
|
2131
|
+
if (this.crazyGamesService) {
|
|
2132
|
+
if (this.crazyGamesInitPromise) await this.crazyGamesInitPromise;
|
|
2133
|
+
this.crazyGamesService.happytime();
|
|
2134
|
+
}
|
|
2211
2135
|
}
|
|
2212
2136
|
/**
|
|
2213
|
-
*
|
|
2214
|
-
*
|
|
2215
|
-
* @returns Promise resolving to boolean indicating success
|
|
2137
|
+
* Check if ads are ready to show
|
|
2138
|
+
* @returns Boolean indicating if ads have initialized successfully
|
|
2216
2139
|
*/
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
...this.billingConfig
|
|
2220
|
-
};
|
|
2221
|
-
if (!mergedConfig.userId && this.userId) {
|
|
2222
|
-
mergedConfig.userId = this.userId;
|
|
2223
|
-
}
|
|
2224
|
-
if (!mergedConfig.gameId && this.gameId) {
|
|
2225
|
-
mergedConfig.gameId = Number(this.gameId);
|
|
2226
|
-
}
|
|
2227
|
-
if (!mergedConfig.checkoutUrl) {
|
|
2228
|
-
mergedConfig.checkoutUrl = this.apiBaseUrl;
|
|
2229
|
-
}
|
|
2230
|
-
this.billingService = new BillingService(mergedConfig);
|
|
2231
|
-
if (this.billingCallbacks.onComplete) {
|
|
2232
|
-
this.billingService.onPurchaseComplete(this.billingCallbacks.onComplete);
|
|
2233
|
-
}
|
|
2234
|
-
if (this.billingCallbacks.onError) {
|
|
2235
|
-
this.billingService.onPurchaseError(this.billingCallbacks.onError);
|
|
2236
|
-
}
|
|
2237
|
-
if (this.billingCallbacks.onLog) {
|
|
2238
|
-
this.billingService.onLog(this.billingCallbacks.onLog);
|
|
2239
|
-
}
|
|
2240
|
-
return await this.billingService.initialize();
|
|
2140
|
+
areAdsReady() {
|
|
2141
|
+
return this.adsService.isReady();
|
|
2241
2142
|
}
|
|
2242
2143
|
/**
|
|
2243
2144
|
* Get the billing platform
|
|
@@ -2274,7 +2175,6 @@ var HyveClient = class {
|
|
|
2274
2175
|
* @param callback Function to call on purchase completion
|
|
2275
2176
|
*/
|
|
2276
2177
|
onPurchaseComplete(callback) {
|
|
2277
|
-
this.billingCallbacks.onComplete = callback;
|
|
2278
2178
|
this.billingService.onPurchaseComplete(callback);
|
|
2279
2179
|
}
|
|
2280
2180
|
/**
|
|
@@ -2282,7 +2182,6 @@ var HyveClient = class {
|
|
|
2282
2182
|
* @param callback Function to call on purchase error
|
|
2283
2183
|
*/
|
|
2284
2184
|
onPurchaseError(callback) {
|
|
2285
|
-
this.billingCallbacks.onError = callback;
|
|
2286
2185
|
this.billingService.onPurchaseError(callback);
|
|
2287
2186
|
}
|
|
2288
2187
|
/**
|
|
@@ -2291,14 +2190,6 @@ var HyveClient = class {
|
|
|
2291
2190
|
unmountBillingCheckout() {
|
|
2292
2191
|
this.billingService.unmountCheckoutElement();
|
|
2293
2192
|
}
|
|
2294
|
-
/**
|
|
2295
|
-
* Register a callback to receive billing logs
|
|
2296
|
-
* @param callback Function to call with log messages
|
|
2297
|
-
*/
|
|
2298
|
-
onBillingLog(callback) {
|
|
2299
|
-
this.billingCallbacks.onLog = callback;
|
|
2300
|
-
this.billingService.onLog(callback);
|
|
2301
|
-
}
|
|
2302
2193
|
};
|
|
2303
2194
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2304
2195
|
0 && (module.exports = {
|
|
@@ -2306,6 +2197,7 @@ var HyveClient = class {
|
|
|
2306
2197
|
BillingPlatform,
|
|
2307
2198
|
BillingService,
|
|
2308
2199
|
CloudStorageAdapter,
|
|
2200
|
+
CrazyGamesService,
|
|
2309
2201
|
HyveClient,
|
|
2310
2202
|
LocalStorageAdapter,
|
|
2311
2203
|
Logger,
|
|
@@ -2313,11 +2205,7 @@ var HyveClient = class {
|
|
|
2313
2205
|
NativeMessageType,
|
|
2314
2206
|
PlaygamaService,
|
|
2315
2207
|
generateUUID,
|
|
2316
|
-
handleVerifyMessage,
|
|
2317
2208
|
isDomainAllowed,
|
|
2318
2209
|
logger,
|
|
2319
|
-
parseUrlParams
|
|
2320
|
-
validateSignature,
|
|
2321
|
-
verifyAuthentication,
|
|
2322
|
-
verifyHyveToken
|
|
2210
|
+
parseUrlParams
|
|
2323
2211
|
});
|