@hyve-sdk/js 1.5.1 → 2.1.1
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 +244 -718
- 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.mjs
CHANGED
|
@@ -24,7 +24,7 @@ var Logger = class _Logger {
|
|
|
24
24
|
}
|
|
25
25
|
} else if (typeof window !== "undefined") {
|
|
26
26
|
try {
|
|
27
|
-
enabled = process
|
|
27
|
+
enabled = process?.env.NODE_ENV !== "production";
|
|
28
28
|
} catch (e) {
|
|
29
29
|
enabled = true;
|
|
30
30
|
}
|
|
@@ -124,136 +124,15 @@ var Logger = class _Logger {
|
|
|
124
124
|
var logger = new Logger();
|
|
125
125
|
|
|
126
126
|
// src/utils/auth.ts
|
|
127
|
-
import { ethers } from "ethers";
|
|
128
127
|
function parseUrlParams(searchParams) {
|
|
129
128
|
const params = typeof searchParams === "string" ? new URLSearchParams(searchParams) : searchParams;
|
|
130
129
|
return {
|
|
131
|
-
signature: params.get("signature") || "",
|
|
132
|
-
message: params.get("message") || "",
|
|
133
130
|
gameStartTab: params.get("game_start_tab") || "",
|
|
134
|
-
hyveToken: params.get("hyve-token") || "",
|
|
135
131
|
platform: params.get("platform") || "",
|
|
136
132
|
hyveAccess: params.get("hyve-access") || "",
|
|
137
133
|
gameId: params.get("game-id") || ""
|
|
138
134
|
};
|
|
139
135
|
}
|
|
140
|
-
function validateSignature(signature, message) {
|
|
141
|
-
try {
|
|
142
|
-
const recoveredAddress = ethers.verifyMessage(message, signature);
|
|
143
|
-
return !!recoveredAddress;
|
|
144
|
-
} catch (error) {
|
|
145
|
-
logger.error("Signature validation error:", error);
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
function handleVerifyMessage(signature, message) {
|
|
150
|
-
try {
|
|
151
|
-
const metadata = JSON.parse(decodeURI(message));
|
|
152
|
-
if (!metadata.expiration || metadata.expiration < Date.now()) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
const userAddress = metadata.userId || metadata.address;
|
|
156
|
-
if (!userAddress) {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
const byteMessage = new TextEncoder().encode(message);
|
|
160
|
-
const addressThatSignedMessage = ethers.verifyMessage(
|
|
161
|
-
byteMessage,
|
|
162
|
-
signature
|
|
163
|
-
);
|
|
164
|
-
if (!addressThatSignedMessage) {
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
if (addressThatSignedMessage.toLowerCase() !== userAddress.toLowerCase()) {
|
|
168
|
-
return false;
|
|
169
|
-
}
|
|
170
|
-
return userAddress;
|
|
171
|
-
} catch (error) {
|
|
172
|
-
logger.error("Error verifying message:", error);
|
|
173
|
-
return false;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
function verifyHyveToken(hyveToken, maxAgeSec = 600) {
|
|
177
|
-
try {
|
|
178
|
-
const parts = hyveToken.split(".");
|
|
179
|
-
if (parts.length !== 4) {
|
|
180
|
-
logger.error(
|
|
181
|
-
"Invalid hyve-token format: expected 4 parts, got",
|
|
182
|
-
parts.length
|
|
183
|
-
);
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
const [signature, address, randomBase64, timestampStr] = parts;
|
|
187
|
-
if (!signature || !address || !randomBase64 || !timestampStr) {
|
|
188
|
-
logger.error("Missing hyve-token components");
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
const message = `${address}.${randomBase64}.${timestampStr}`;
|
|
192
|
-
const recoveredAddress = ethers.verifyMessage(message, signature);
|
|
193
|
-
if (recoveredAddress.toLowerCase() !== address.toLowerCase()) {
|
|
194
|
-
logger.error("Hyve-token signature verification failed");
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
const timestamp = parseInt(timestampStr, 10);
|
|
198
|
-
if (!Number.isFinite(timestamp)) {
|
|
199
|
-
logger.error("Invalid hyve-token timestamp");
|
|
200
|
-
return false;
|
|
201
|
-
}
|
|
202
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
203
|
-
if (now - timestamp > maxAgeSec) {
|
|
204
|
-
logger.error(
|
|
205
|
-
`Hyve-token expired (age: ${now - timestamp}s, max: ${maxAgeSec}s)`
|
|
206
|
-
);
|
|
207
|
-
return false;
|
|
208
|
-
}
|
|
209
|
-
return address;
|
|
210
|
-
} catch (error) {
|
|
211
|
-
logger.error("Hyve-token verification error:", error);
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
function verifyAuthentication(params, maxAgeSec = 600) {
|
|
216
|
-
if (params.hyveToken) {
|
|
217
|
-
const modernAddress = verifyHyveToken(params.hyveToken, maxAgeSec);
|
|
218
|
-
if (modernAddress) {
|
|
219
|
-
return {
|
|
220
|
-
isValid: true,
|
|
221
|
-
address: modernAddress,
|
|
222
|
-
method: "modern"
|
|
223
|
-
};
|
|
224
|
-
} else {
|
|
225
|
-
return {
|
|
226
|
-
isValid: false,
|
|
227
|
-
address: null,
|
|
228
|
-
method: "modern",
|
|
229
|
-
error: "Modern token verification failed"
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (params.signature && params.message) {
|
|
234
|
-
const legacyAddress = handleVerifyMessage(params.signature, params.message);
|
|
235
|
-
if (legacyAddress) {
|
|
236
|
-
return {
|
|
237
|
-
isValid: true,
|
|
238
|
-
address: legacyAddress,
|
|
239
|
-
method: "legacy"
|
|
240
|
-
};
|
|
241
|
-
} else {
|
|
242
|
-
return {
|
|
243
|
-
isValid: false,
|
|
244
|
-
address: null,
|
|
245
|
-
method: "legacy",
|
|
246
|
-
error: "Legacy token verification failed"
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return {
|
|
251
|
-
isValid: false,
|
|
252
|
-
address: null,
|
|
253
|
-
method: "none",
|
|
254
|
-
error: "No authentication tokens provided"
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
136
|
function isDomainAllowed(allowedDomains, hostname) {
|
|
258
137
|
logger.debug("Checking hostname:", hostname);
|
|
259
138
|
if (!allowedDomains) return true;
|
|
@@ -294,9 +173,7 @@ var NativeBridge = class {
|
|
|
294
173
|
* Checks if the app is running inside a React Native WebView
|
|
295
174
|
*/
|
|
296
175
|
static isNativeContext() {
|
|
297
|
-
|
|
298
|
-
console.log(`[NativeBridge] isNativeContext check: ${isNative}`);
|
|
299
|
-
return isNative;
|
|
176
|
+
return typeof window !== "undefined" && "ReactNativeWebView" in window;
|
|
300
177
|
}
|
|
301
178
|
/**
|
|
302
179
|
* Initializes the native bridge message listener
|
|
@@ -305,55 +182,37 @@ var NativeBridge = class {
|
|
|
305
182
|
static initialize() {
|
|
306
183
|
if (this.isInitialized) {
|
|
307
184
|
logger.debug("[NativeBridge] Already initialized");
|
|
308
|
-
console.log("[NativeBridge] \u26A0 Already initialized, skipping");
|
|
309
185
|
return;
|
|
310
186
|
}
|
|
311
187
|
if (typeof window === "undefined") {
|
|
312
188
|
logger.warn("[NativeBridge] Window not available, skipping initialization");
|
|
313
|
-
console.warn("[NativeBridge] \u26A0 Window not available, skipping initialization");
|
|
314
189
|
return;
|
|
315
190
|
}
|
|
316
|
-
const isInIframe = window !== window.parent;
|
|
317
|
-
console.log("[NativeBridge] ========== INITIALIZING ==========");
|
|
318
|
-
console.log(`[NativeBridge] Running in iframe: ${isInIframe}`);
|
|
319
|
-
console.log("[NativeBridge] Setting up message listeners on window and document");
|
|
320
191
|
const boundHandler = this.handleNativeMessage.bind(this);
|
|
321
192
|
window.addEventListener("message", boundHandler);
|
|
322
193
|
document.addEventListener("message", boundHandler);
|
|
323
|
-
if (isInIframe) {
|
|
324
|
-
console.log("[NativeBridge] Setting up parent window message listener for iframe context");
|
|
325
|
-
}
|
|
326
194
|
this.isInitialized = true;
|
|
327
|
-
console.log("[NativeBridge] \u2713 Event listeners attached to window and document");
|
|
328
|
-
console.log("[NativeBridge] \u2713 Initialized and ready to receive messages");
|
|
329
195
|
logger.info("[NativeBridge] Initialized and listening for native messages");
|
|
330
196
|
}
|
|
331
197
|
/**
|
|
332
198
|
* Handles incoming messages from React Native
|
|
333
199
|
*/
|
|
334
200
|
static handleNativeMessage(event) {
|
|
335
|
-
console.log("[NativeBridge] [HANDLER] handleNativeMessage called");
|
|
336
|
-
console.log("[NativeBridge] [HANDLER] Event source:", event.source === window ? "window" : "other");
|
|
337
|
-
console.log("[NativeBridge] [HANDLER] Event data:", event.data);
|
|
338
201
|
try {
|
|
339
202
|
let data;
|
|
340
203
|
if (typeof event.data === "string") {
|
|
341
204
|
try {
|
|
342
205
|
data = JSON.parse(event.data);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
logger.debug("[NativeBridge] Failed to parse message, not JSON:", event.data);
|
|
206
|
+
} catch {
|
|
207
|
+
logger.debug("[NativeBridge] Ignoring non-JSON message");
|
|
346
208
|
return;
|
|
347
209
|
}
|
|
348
210
|
} else if (typeof event.data === "object" && event.data !== null) {
|
|
349
211
|
data = event.data;
|
|
350
|
-
logger.debug("[NativeBridge] Received message object:", data);
|
|
351
212
|
} else {
|
|
352
|
-
logger.debug("[NativeBridge] Received invalid message type:", typeof event.data);
|
|
353
213
|
return;
|
|
354
214
|
}
|
|
355
|
-
if (!data
|
|
356
|
-
logger.debug("[NativeBridge] Received message without type, ignoring");
|
|
215
|
+
if (!data?.type) {
|
|
357
216
|
return;
|
|
358
217
|
}
|
|
359
218
|
const nativeResponseTypes = [
|
|
@@ -365,22 +224,16 @@ var NativeBridge = class {
|
|
|
365
224
|
"PURCHASE_ERROR" /* PURCHASE_ERROR */
|
|
366
225
|
];
|
|
367
226
|
if (!nativeResponseTypes.includes(data.type)) {
|
|
368
|
-
logger.debug(`[NativeBridge] Ignoring non-native-response message: ${data.type}`);
|
|
369
227
|
return;
|
|
370
228
|
}
|
|
371
|
-
console.log("[NativeBridge] [HANDLER] Message type:", data.type);
|
|
372
229
|
const handler = this.handlers.get(data.type);
|
|
373
230
|
if (handler) {
|
|
374
|
-
|
|
375
|
-
logger.info(`[NativeBridge] Handling message: ${data.type}`, data.payload);
|
|
231
|
+
logger.debug(`[NativeBridge] Handling message: ${data.type}`);
|
|
376
232
|
handler(data.payload);
|
|
377
|
-
console.log(`[NativeBridge] [HANDLER] \u2713 Handler completed for: ${data.type}`);
|
|
378
233
|
} else {
|
|
379
|
-
console.warn(`[NativeBridge] [HANDLER] \u26A0 No handler registered for: ${data.type}`);
|
|
380
234
|
logger.warn(`[NativeBridge] No handler registered for: ${data.type}`);
|
|
381
235
|
}
|
|
382
236
|
} catch (error) {
|
|
383
|
-
console.error("[NativeBridge] [HANDLER] \u274C Error handling native message:", error);
|
|
384
237
|
logger.error("[NativeBridge] Error handling native message:", error);
|
|
385
238
|
}
|
|
386
239
|
}
|
|
@@ -390,27 +243,15 @@ var NativeBridge = class {
|
|
|
390
243
|
* @param payload Optional payload data
|
|
391
244
|
*/
|
|
392
245
|
static send(type, payload) {
|
|
393
|
-
console.log(`[NativeBridge] [SEND] Attempting to send message: ${type}`);
|
|
394
246
|
if (!this.isNativeContext()) {
|
|
395
|
-
|
|
396
|
-
logger.debug(
|
|
397
|
-
`[NativeBridge] Not in native context, skipping message: ${type}`
|
|
398
|
-
);
|
|
247
|
+
logger.debug(`[NativeBridge] Not in native context, skipping message: ${type}`);
|
|
399
248
|
return;
|
|
400
249
|
}
|
|
401
|
-
console.log(`[NativeBridge] [SEND] \u2713 In native context, sending message`);
|
|
402
250
|
try {
|
|
403
|
-
const message = {
|
|
404
|
-
type,
|
|
405
|
-
payload,
|
|
406
|
-
timestamp: Date.now()
|
|
407
|
-
};
|
|
408
|
-
console.log(`[NativeBridge] [SEND] Message object:`, message);
|
|
251
|
+
const message = { type, payload, timestamp: Date.now() };
|
|
409
252
|
window.ReactNativeWebView.postMessage(JSON.stringify(message));
|
|
410
|
-
console.log(`[NativeBridge] [SEND] \u2713 Message sent to native: ${type}`);
|
|
411
253
|
logger.debug(`[NativeBridge] Sent message to native: ${type}`, payload);
|
|
412
254
|
} catch (error) {
|
|
413
|
-
console.error(`[NativeBridge] [SEND] \u274C\u274C Error sending message to native:`, error);
|
|
414
255
|
logger.error(`[NativeBridge] Error sending message to native:`, error);
|
|
415
256
|
}
|
|
416
257
|
}
|
|
@@ -420,10 +261,7 @@ var NativeBridge = class {
|
|
|
420
261
|
* @param handler Function to call when message is received
|
|
421
262
|
*/
|
|
422
263
|
static on(type, handler) {
|
|
423
|
-
console.log(`[NativeBridge] [ON] Registering handler for: ${type}`);
|
|
424
264
|
this.handlers.set(type, handler);
|
|
425
|
-
console.log(`[NativeBridge] [ON] \u2713 Handler registered. Total handlers:`, this.handlers.size);
|
|
426
|
-
console.log(`[NativeBridge] [ON] All registered types:`, Array.from(this.handlers.keys()));
|
|
427
265
|
logger.debug(`[NativeBridge] Registered handler for: ${type}`);
|
|
428
266
|
}
|
|
429
267
|
/**
|
|
@@ -573,7 +411,6 @@ function generateUUID() {
|
|
|
573
411
|
// src/services/ads.ts
|
|
574
412
|
var AdsService = class {
|
|
575
413
|
config = {
|
|
576
|
-
enabled: false,
|
|
577
414
|
sound: "on",
|
|
578
415
|
debug: false,
|
|
579
416
|
onBeforeAd: () => {
|
|
@@ -583,87 +420,69 @@ var AdsService = class {
|
|
|
583
420
|
onRewardEarned: () => {
|
|
584
421
|
}
|
|
585
422
|
};
|
|
586
|
-
|
|
423
|
+
// Cached init promise — ensures adConfig() is only called once
|
|
424
|
+
initPromise = null;
|
|
587
425
|
ready = false;
|
|
588
426
|
/**
|
|
589
|
-
*
|
|
590
|
-
*
|
|
427
|
+
* Optionally configure the ads service.
|
|
428
|
+
* Not required — ads work without calling this.
|
|
591
429
|
*/
|
|
592
430
|
configure(config) {
|
|
593
431
|
this.config = {
|
|
594
432
|
...this.config,
|
|
595
433
|
...config,
|
|
596
|
-
onBeforeAd: config.onBeforeAd
|
|
597
|
-
onAfterAd: config.onAfterAd
|
|
598
|
-
onRewardEarned: config.onRewardEarned
|
|
434
|
+
onBeforeAd: config.onBeforeAd ?? this.config.onBeforeAd,
|
|
435
|
+
onAfterAd: config.onAfterAd ?? this.config.onAfterAd,
|
|
436
|
+
onRewardEarned: config.onRewardEarned ?? this.config.onRewardEarned
|
|
599
437
|
};
|
|
600
438
|
if (this.config.debug) {
|
|
601
|
-
|
|
602
|
-
enabled: this.config.enabled,
|
|
603
|
-
sound: this.config.sound
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
if (this.config.enabled && !this.initialized) {
|
|
607
|
-
this.initialize();
|
|
439
|
+
logger.debug("[AdsService] Configuration updated:", { sound: this.config.sound });
|
|
608
440
|
}
|
|
609
441
|
}
|
|
610
442
|
/**
|
|
611
|
-
* Initialize the
|
|
443
|
+
* Initialize the Google H5 Ads system.
|
|
444
|
+
* Returns a cached promise — safe to call multiple times.
|
|
612
445
|
*/
|
|
613
446
|
initialize() {
|
|
614
|
-
if (this.
|
|
615
|
-
|
|
616
|
-
if (
|
|
617
|
-
console.log("[AdsService] Ads disabled, skipping initialization");
|
|
618
|
-
}
|
|
619
|
-
return;
|
|
620
|
-
}
|
|
621
|
-
if (!window.adConfig || !window.adBreak) {
|
|
622
|
-
console.warn("[AdsService] Google Ads SDK not found. Ads will not be available.");
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
if (this.config.debug) {
|
|
626
|
-
console.log("[AdsService] Initializing ads system...");
|
|
627
|
-
}
|
|
628
|
-
const googleConfig = {
|
|
629
|
-
sound: this.config.sound,
|
|
630
|
-
preloadAdBreaks: "on",
|
|
631
|
-
onReady: () => {
|
|
632
|
-
this.ready = true;
|
|
447
|
+
if (this.initPromise) return this.initPromise;
|
|
448
|
+
this.initPromise = new Promise((resolve) => {
|
|
449
|
+
if (!window.adConfig || !window.adBreak) {
|
|
633
450
|
if (this.config.debug) {
|
|
634
|
-
|
|
451
|
+
logger.debug("[AdsService] Google Ads SDK not found \u2014 ads unavailable");
|
|
635
452
|
}
|
|
453
|
+
resolve(false);
|
|
454
|
+
return;
|
|
636
455
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
456
|
+
if (this.config.debug) {
|
|
457
|
+
logger.debug("[AdsService] Initializing ads system...");
|
|
458
|
+
}
|
|
459
|
+
window.adConfig({
|
|
460
|
+
sound: this.config.sound,
|
|
461
|
+
preloadAdBreaks: "on",
|
|
462
|
+
onReady: () => {
|
|
463
|
+
this.ready = true;
|
|
464
|
+
if (this.config.debug) {
|
|
465
|
+
logger.debug("[AdsService] Ads ready");
|
|
466
|
+
}
|
|
467
|
+
resolve(true);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
setTimeout(() => resolve(false), 5e3);
|
|
471
|
+
});
|
|
472
|
+
return this.initPromise;
|
|
640
473
|
}
|
|
641
474
|
/**
|
|
642
|
-
* Show an ad
|
|
643
|
-
* Returns immediately if ads are disabled
|
|
475
|
+
* Show an ad. Auto-initializes on the first call.
|
|
476
|
+
* Returns immediately with success: false if ads are disabled or unavailable.
|
|
644
477
|
*/
|
|
645
478
|
async show(type) {
|
|
646
479
|
const requestedAt = Date.now();
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
console.log("[AdsService] Ads disabled, skipping ad request");
|
|
650
|
-
}
|
|
480
|
+
const ready = await this.initialize();
|
|
481
|
+
if (!ready || !window.adBreak) {
|
|
651
482
|
return {
|
|
652
483
|
success: false,
|
|
653
484
|
type,
|
|
654
|
-
error: new Error("Ads
|
|
655
|
-
requestedAt,
|
|
656
|
-
completedAt: Date.now()
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
if (!this.initialized) {
|
|
660
|
-
this.initialize();
|
|
661
|
-
}
|
|
662
|
-
if (!this.ready || !window.adBreak) {
|
|
663
|
-
return {
|
|
664
|
-
success: false,
|
|
665
|
-
type,
|
|
666
|
-
error: new Error("Ads not ready"),
|
|
485
|
+
error: new Error("Ads not available"),
|
|
667
486
|
requestedAt,
|
|
668
487
|
completedAt: Date.now()
|
|
669
488
|
};
|
|
@@ -671,7 +490,7 @@ var AdsService = class {
|
|
|
671
490
|
return this.showAdBreak(type);
|
|
672
491
|
}
|
|
673
492
|
/**
|
|
674
|
-
* Show an ad break
|
|
493
|
+
* Show an ad break via the Google H5 API.
|
|
675
494
|
*/
|
|
676
495
|
async showAdBreak(type) {
|
|
677
496
|
const requestedAt = Date.now();
|
|
@@ -679,74 +498,35 @@ var AdsService = class {
|
|
|
679
498
|
const googleType = type === "rewarded" ? "reward" : type === "preroll" ? "start" : "next";
|
|
680
499
|
const adName = `${type}-ad-${Date.now()}`;
|
|
681
500
|
if (this.config.debug) {
|
|
682
|
-
|
|
501
|
+
logger.debug(`[AdsService] Showing ${type} ad`);
|
|
683
502
|
}
|
|
684
503
|
this.config.onBeforeAd(type);
|
|
685
504
|
const adBreakConfig = {
|
|
686
505
|
type: googleType,
|
|
687
506
|
name: adName,
|
|
688
|
-
beforeAd: () => {
|
|
689
|
-
if (this.config.debug) {
|
|
690
|
-
console.log("[AdsService] Ad started");
|
|
691
|
-
}
|
|
692
|
-
},
|
|
693
507
|
afterAd: () => {
|
|
694
|
-
if (this.config.debug) {
|
|
695
|
-
console.log("[AdsService] Ad finished");
|
|
696
|
-
}
|
|
697
508
|
this.config.onAfterAd(type);
|
|
698
509
|
},
|
|
699
510
|
adBreakDone: (info) => {
|
|
700
511
|
const completedAt = Date.now();
|
|
701
|
-
|
|
702
|
-
if (type === "rewarded") {
|
|
703
|
-
success = info?.breakStatus === "viewed";
|
|
704
|
-
} else {
|
|
705
|
-
success = info?.breakStatus !== "error";
|
|
706
|
-
}
|
|
512
|
+
const success = type === "rewarded" ? info?.breakStatus === "viewed" : info?.breakStatus !== "error";
|
|
707
513
|
const error = info?.breakStatus === "error" && info?.error ? new Error(info.error) : void 0;
|
|
708
514
|
if (this.config.debug) {
|
|
709
|
-
|
|
710
|
-
success,
|
|
711
|
-
status: info?.breakStatus
|
|
712
|
-
});
|
|
515
|
+
logger.debug("[AdsService] Ad break done:", { success, status: info?.breakStatus });
|
|
713
516
|
}
|
|
714
|
-
|
|
715
|
-
success,
|
|
716
|
-
type,
|
|
717
|
-
error,
|
|
718
|
-
requestedAt,
|
|
719
|
-
completedAt
|
|
720
|
-
};
|
|
721
|
-
resolve(result);
|
|
517
|
+
resolve({ success, type, error, requestedAt, completedAt });
|
|
722
518
|
}
|
|
723
519
|
};
|
|
724
520
|
if (type === "rewarded") {
|
|
725
|
-
adBreakConfig.beforeReward = (showAdFn) =>
|
|
726
|
-
|
|
727
|
-
console.log("[AdsService] beforeReward callback");
|
|
728
|
-
}
|
|
729
|
-
showAdFn();
|
|
730
|
-
};
|
|
731
|
-
adBreakConfig.adViewed = () => {
|
|
732
|
-
if (this.config.debug) {
|
|
733
|
-
console.log("[AdsService] Rewarded ad watched successfully");
|
|
734
|
-
}
|
|
735
|
-
this.config.onRewardEarned();
|
|
736
|
-
};
|
|
737
|
-
adBreakConfig.adDismissed = () => {
|
|
738
|
-
if (this.config.debug) {
|
|
739
|
-
console.log("[AdsService] Rewarded ad dismissed");
|
|
740
|
-
}
|
|
741
|
-
};
|
|
521
|
+
adBreakConfig.beforeReward = (showAdFn) => showAdFn();
|
|
522
|
+
adBreakConfig.adViewed = () => this.config.onRewardEarned();
|
|
742
523
|
}
|
|
743
524
|
window.adBreak(adBreakConfig);
|
|
744
525
|
});
|
|
745
526
|
}
|
|
746
527
|
/**
|
|
747
528
|
* Returns the configured ad lifecycle callbacks.
|
|
748
|
-
* Used by platform-specific
|
|
749
|
-
* onBeforeAd / onAfterAd / onRewardEarned hooks that the Google H5 path uses.
|
|
529
|
+
* Used by platform-specific providers (e.g. Playgama) to fire the same hooks.
|
|
750
530
|
*/
|
|
751
531
|
getCallbacks() {
|
|
752
532
|
return {
|
|
@@ -756,16 +536,10 @@ var AdsService = class {
|
|
|
756
536
|
};
|
|
757
537
|
}
|
|
758
538
|
/**
|
|
759
|
-
* Check if ads are
|
|
760
|
-
*/
|
|
761
|
-
isEnabled() {
|
|
762
|
-
return this.config.enabled;
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* Check if ads are ready to show
|
|
539
|
+
* Check if ads have successfully initialized and are ready to show.
|
|
766
540
|
*/
|
|
767
541
|
isReady() {
|
|
768
|
-
return this.
|
|
542
|
+
return this.ready;
|
|
769
543
|
}
|
|
770
544
|
};
|
|
771
545
|
|
|
@@ -812,7 +586,7 @@ var PlaygamaService = class {
|
|
|
812
586
|
this.initialized = true;
|
|
813
587
|
return true;
|
|
814
588
|
} catch (error) {
|
|
815
|
-
|
|
589
|
+
logger.warn("[PlaygamaService] Failed to initialize:", error);
|
|
816
590
|
return false;
|
|
817
591
|
}
|
|
818
592
|
}
|
|
@@ -924,6 +698,176 @@ var PlaygamaService = class {
|
|
|
924
698
|
}
|
|
925
699
|
};
|
|
926
700
|
|
|
701
|
+
// src/services/crazygames.ts
|
|
702
|
+
var CRAZYGAMES_SDK_CDN = "https://sdk.crazygames.com/crazygames-sdk-v2.js";
|
|
703
|
+
var CrazyGamesService = class {
|
|
704
|
+
initialized = false;
|
|
705
|
+
/**
|
|
706
|
+
* Detects if the game is running on the CrazyGames platform.
|
|
707
|
+
* Games on CrazyGames run inside an iframe, so we check document.referrer
|
|
708
|
+
* and attempt to read the parent frame location.
|
|
709
|
+
*/
|
|
710
|
+
static isCrazyGamesDomain() {
|
|
711
|
+
try {
|
|
712
|
+
if (document.referrer.includes("crazygames.com")) {
|
|
713
|
+
return true;
|
|
714
|
+
}
|
|
715
|
+
if (window !== window.top) {
|
|
716
|
+
try {
|
|
717
|
+
if (window.parent.location.hostname.includes("crazygames.com")) {
|
|
718
|
+
return true;
|
|
719
|
+
}
|
|
720
|
+
} catch {
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
return false;
|
|
724
|
+
} catch {
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Loads the CrazyGames SDK from CDN and confirms the environment is 'crazygames'.
|
|
730
|
+
* Safe to call multiple times — resolves immediately if already initialized.
|
|
731
|
+
*/
|
|
732
|
+
async initialize() {
|
|
733
|
+
if (this.initialized) return true;
|
|
734
|
+
try {
|
|
735
|
+
await this.loadScript();
|
|
736
|
+
const sdk = window.CrazyGames?.SDK;
|
|
737
|
+
if (!sdk) {
|
|
738
|
+
logger.warn("[CrazyGamesService] SDK not found after script load");
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
const env = await sdk.getEnvironment();
|
|
742
|
+
if (env !== "crazygames" && env !== "local") {
|
|
743
|
+
logger.warn("[CrazyGamesService] Unexpected environment:", env);
|
|
744
|
+
return false;
|
|
745
|
+
}
|
|
746
|
+
this.initialized = true;
|
|
747
|
+
return true;
|
|
748
|
+
} catch (error) {
|
|
749
|
+
logger.warn("[CrazyGamesService] Failed to initialize:", error);
|
|
750
|
+
return false;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
isInitialized() {
|
|
754
|
+
return this.initialized;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Shows a midgame (interstitial) ad via the CrazyGames SDK.
|
|
758
|
+
*/
|
|
759
|
+
async showInterstitial(callbacks) {
|
|
760
|
+
const requestedAt = Date.now();
|
|
761
|
+
const sdk = window.CrazyGames?.SDK;
|
|
762
|
+
if (!this.initialized || !sdk) {
|
|
763
|
+
return {
|
|
764
|
+
success: false,
|
|
765
|
+
type: "interstitial",
|
|
766
|
+
error: new Error("CrazyGames SDK not initialized"),
|
|
767
|
+
requestedAt,
|
|
768
|
+
completedAt: Date.now()
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
return new Promise((resolve) => {
|
|
772
|
+
sdk.ad.requestAd("midgame", {
|
|
773
|
+
adStarted: () => {
|
|
774
|
+
callbacks?.onBeforeAd?.();
|
|
775
|
+
},
|
|
776
|
+
adFinished: () => {
|
|
777
|
+
callbacks?.onAfterAd?.();
|
|
778
|
+
resolve({ success: true, type: "interstitial", requestedAt, completedAt: Date.now() });
|
|
779
|
+
},
|
|
780
|
+
adError: (error) => {
|
|
781
|
+
callbacks?.onAfterAd?.();
|
|
782
|
+
resolve({
|
|
783
|
+
success: false,
|
|
784
|
+
type: "interstitial",
|
|
785
|
+
error: new Error(`CrazyGames interstitial ad error: ${error}`),
|
|
786
|
+
requestedAt,
|
|
787
|
+
completedAt: Date.now()
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Shows a rewarded ad via the CrazyGames SDK.
|
|
795
|
+
* Resolves with success: true only when adFinished fires (ad was fully watched).
|
|
796
|
+
*/
|
|
797
|
+
async showRewarded(callbacks) {
|
|
798
|
+
const requestedAt = Date.now();
|
|
799
|
+
const sdk = window.CrazyGames?.SDK;
|
|
800
|
+
if (!this.initialized || !sdk) {
|
|
801
|
+
return {
|
|
802
|
+
success: false,
|
|
803
|
+
type: "rewarded",
|
|
804
|
+
error: new Error("CrazyGames SDK not initialized"),
|
|
805
|
+
requestedAt,
|
|
806
|
+
completedAt: Date.now()
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
return new Promise((resolve) => {
|
|
810
|
+
sdk.ad.requestAd("rewarded", {
|
|
811
|
+
adStarted: () => {
|
|
812
|
+
callbacks?.onBeforeAd?.();
|
|
813
|
+
},
|
|
814
|
+
adFinished: () => {
|
|
815
|
+
callbacks?.onRewardEarned?.();
|
|
816
|
+
callbacks?.onAfterAd?.();
|
|
817
|
+
resolve({ success: true, type: "rewarded", requestedAt, completedAt: Date.now() });
|
|
818
|
+
},
|
|
819
|
+
adError: (error) => {
|
|
820
|
+
callbacks?.onAfterAd?.();
|
|
821
|
+
resolve({
|
|
822
|
+
success: false,
|
|
823
|
+
type: "rewarded",
|
|
824
|
+
error: new Error(`CrazyGames rewarded ad error: ${error}`),
|
|
825
|
+
requestedAt,
|
|
826
|
+
completedAt: Date.now()
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
});
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Notifies CrazyGames that gameplay has started.
|
|
834
|
+
* Call when the player actively begins or resumes playing.
|
|
835
|
+
*/
|
|
836
|
+
gameplayStart() {
|
|
837
|
+
if (!this.initialized) return;
|
|
838
|
+
window.CrazyGames?.SDK.game.gameplayStart();
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Notifies CrazyGames that gameplay has stopped.
|
|
842
|
+
* Call during menu access, level completion, or pausing.
|
|
843
|
+
*/
|
|
844
|
+
gameplayStop() {
|
|
845
|
+
if (!this.initialized) return;
|
|
846
|
+
window.CrazyGames?.SDK.game.gameplayStop();
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Triggers a celebration effect on the CrazyGames website.
|
|
850
|
+
* Use sparingly for significant achievements (boss defeat, personal record, etc.)
|
|
851
|
+
*/
|
|
852
|
+
happytime() {
|
|
853
|
+
if (!this.initialized) return;
|
|
854
|
+
window.CrazyGames?.SDK.game.happytime();
|
|
855
|
+
}
|
|
856
|
+
loadScript() {
|
|
857
|
+
return new Promise((resolve, reject) => {
|
|
858
|
+
if (window.CrazyGames?.SDK) {
|
|
859
|
+
resolve();
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
const script = document.createElement("script");
|
|
863
|
+
script.src = CRAZYGAMES_SDK_CDN;
|
|
864
|
+
script.onload = () => resolve();
|
|
865
|
+
script.onerror = () => reject(new Error("Failed to load CrazyGames SDK script"));
|
|
866
|
+
document.head.appendChild(script);
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
};
|
|
870
|
+
|
|
927
871
|
// src/services/billing.ts
|
|
928
872
|
var BillingPlatform = /* @__PURE__ */ ((BillingPlatform3) => {
|
|
929
873
|
BillingPlatform3["WEB"] = "web";
|
|
@@ -934,41 +878,28 @@ var BillingPlatform = /* @__PURE__ */ ((BillingPlatform3) => {
|
|
|
934
878
|
var BillingService = class {
|
|
935
879
|
config;
|
|
936
880
|
platform = "unknown" /* UNKNOWN */;
|
|
937
|
-
|
|
881
|
+
initPromise = null;
|
|
938
882
|
nativeAvailable = false;
|
|
939
|
-
products = [];
|
|
940
883
|
// Stripe instance for web payments
|
|
941
884
|
stripe = null;
|
|
942
885
|
checkoutElement = null;
|
|
943
886
|
// Callbacks for purchase events
|
|
944
887
|
onPurchaseCompleteCallback;
|
|
945
888
|
onPurchaseErrorCallback;
|
|
946
|
-
// Callback for logging (so external UI can capture logs)
|
|
947
|
-
onLogCallback;
|
|
948
889
|
constructor(config) {
|
|
949
890
|
this.config = config;
|
|
950
891
|
this.detectPlatform();
|
|
951
892
|
}
|
|
952
893
|
/**
|
|
953
|
-
*
|
|
954
|
-
* Useful for displaying logs in a UI
|
|
894
|
+
* Update billing configuration. Resets initialization so next call re-inits with new config.
|
|
955
895
|
*/
|
|
956
|
-
|
|
957
|
-
this.
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
const consoleMethod = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
964
|
-
if (data !== void 0) {
|
|
965
|
-
consoleMethod(message, data);
|
|
966
|
-
} else {
|
|
967
|
-
consoleMethod(message);
|
|
968
|
-
}
|
|
969
|
-
if (this.onLogCallback) {
|
|
970
|
-
this.onLogCallback(level, message, data);
|
|
971
|
-
}
|
|
896
|
+
configure(config) {
|
|
897
|
+
this.config = {
|
|
898
|
+
...this.config,
|
|
899
|
+
...config
|
|
900
|
+
};
|
|
901
|
+
this.initPromise = null;
|
|
902
|
+
logger.info("[BillingService] Configuration updated");
|
|
972
903
|
}
|
|
973
904
|
/**
|
|
974
905
|
* Detects if running on web or native platform
|
|
@@ -978,13 +909,13 @@ var BillingService = class {
|
|
|
978
909
|
const hasWindow = typeof window !== "undefined";
|
|
979
910
|
if (isNative) {
|
|
980
911
|
this.platform = "native" /* NATIVE */;
|
|
981
|
-
|
|
912
|
+
logger.info("[BillingService] Platform: NATIVE");
|
|
982
913
|
} else if (hasWindow) {
|
|
983
914
|
this.platform = "web" /* WEB */;
|
|
984
|
-
|
|
915
|
+
logger.info("[BillingService] Platform: WEB");
|
|
985
916
|
} else {
|
|
986
917
|
this.platform = "unknown" /* UNKNOWN */;
|
|
987
|
-
|
|
918
|
+
logger.warn("[BillingService] Platform: UNKNOWN");
|
|
988
919
|
}
|
|
989
920
|
}
|
|
990
921
|
/**
|
|
@@ -994,38 +925,40 @@ var BillingService = class {
|
|
|
994
925
|
return this.platform;
|
|
995
926
|
}
|
|
996
927
|
/**
|
|
997
|
-
* Initialize the billing service
|
|
998
|
-
*
|
|
928
|
+
* Initialize the billing service. Idempotent — returns cached promise on subsequent calls.
|
|
929
|
+
* Called automatically by getProducts() and purchase().
|
|
999
930
|
*/
|
|
1000
|
-
|
|
1001
|
-
if (this.
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
931
|
+
initialize() {
|
|
932
|
+
if (this.initPromise) return this.initPromise;
|
|
933
|
+
logger.info(`[BillingService] Initializing for ${this.platform} platform...`);
|
|
934
|
+
this.initPromise = (async () => {
|
|
935
|
+
try {
|
|
936
|
+
if (this.platform === "native" /* NATIVE */) {
|
|
937
|
+
return await this.initializeNative();
|
|
938
|
+
} else if (this.platform === "web" /* WEB */) {
|
|
939
|
+
return await this.initializeWeb();
|
|
940
|
+
}
|
|
941
|
+
logger.error("[BillingService] Cannot initialize: unknown platform");
|
|
942
|
+
return false;
|
|
943
|
+
} catch (error) {
|
|
944
|
+
logger.error("[BillingService] Initialization failed:", error?.message);
|
|
945
|
+
return false;
|
|
1010
946
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
} catch (error) {
|
|
1014
|
-
this.log("error", "[BillingService] Initialization failed:", error?.message);
|
|
1015
|
-
return false;
|
|
1016
|
-
}
|
|
947
|
+
})();
|
|
948
|
+
return this.initPromise;
|
|
1017
949
|
}
|
|
1018
950
|
/**
|
|
1019
951
|
* Initialize native billing
|
|
1020
952
|
*/
|
|
1021
953
|
async initializeNative() {
|
|
1022
954
|
return new Promise((resolve) => {
|
|
955
|
+
let resolved = false;
|
|
1023
956
|
try {
|
|
1024
957
|
NativeBridge.initialize();
|
|
1025
958
|
NativeBridge.on(
|
|
1026
959
|
"PURCHASE_COMPLETE" /* PURCHASE_COMPLETE */,
|
|
1027
960
|
(payload) => {
|
|
1028
|
-
|
|
961
|
+
logger.info("[BillingService] Purchase complete:", payload.productId);
|
|
1029
962
|
const result = {
|
|
1030
963
|
success: true,
|
|
1031
964
|
productId: payload.productId,
|
|
@@ -1040,7 +973,7 @@ var BillingService = class {
|
|
|
1040
973
|
NativeBridge.on(
|
|
1041
974
|
"PURCHASE_ERROR" /* PURCHASE_ERROR */,
|
|
1042
975
|
(payload) => {
|
|
1043
|
-
|
|
976
|
+
logger.error("[BillingService] Purchase error:", payload.message);
|
|
1044
977
|
const result = {
|
|
1045
978
|
success: false,
|
|
1046
979
|
productId: payload.productId || "unknown",
|
|
@@ -1058,8 +991,8 @@ var BillingService = class {
|
|
|
1058
991
|
"IAP_AVAILABILITY_RESULT" /* IAP_AVAILABILITY_RESULT */,
|
|
1059
992
|
(payload) => {
|
|
1060
993
|
this.nativeAvailable = payload.available;
|
|
1061
|
-
|
|
1062
|
-
|
|
994
|
+
logger.info(`[BillingService] Native billing ${payload.available ? "available" : "unavailable"}`);
|
|
995
|
+
resolved = true;
|
|
1063
996
|
resolve(payload.available);
|
|
1064
997
|
}
|
|
1065
998
|
);
|
|
@@ -1067,15 +1000,15 @@ var BillingService = class {
|
|
|
1067
1000
|
NativeBridge.checkIAPAvailability();
|
|
1068
1001
|
}, 100);
|
|
1069
1002
|
setTimeout(() => {
|
|
1070
|
-
if (!
|
|
1071
|
-
|
|
1072
|
-
|
|
1003
|
+
if (!resolved) {
|
|
1004
|
+
logger.warn("[BillingService] Native initialization timeout");
|
|
1005
|
+
resolved = true;
|
|
1073
1006
|
resolve(false);
|
|
1074
1007
|
}
|
|
1075
1008
|
}, 5e3);
|
|
1076
1009
|
} catch (error) {
|
|
1077
|
-
|
|
1078
|
-
|
|
1010
|
+
logger.error("[BillingService] Native initialization failed:", error?.message);
|
|
1011
|
+
resolved = true;
|
|
1079
1012
|
resolve(false);
|
|
1080
1013
|
}
|
|
1081
1014
|
});
|
|
@@ -1085,12 +1018,12 @@ var BillingService = class {
|
|
|
1085
1018
|
*/
|
|
1086
1019
|
async initializeWeb() {
|
|
1087
1020
|
if (!this.config.stripePublishableKey) {
|
|
1088
|
-
|
|
1021
|
+
logger.error("[BillingService] Stripe publishable key not provided");
|
|
1089
1022
|
return false;
|
|
1090
1023
|
}
|
|
1091
1024
|
try {
|
|
1092
1025
|
if (typeof window === "undefined") {
|
|
1093
|
-
|
|
1026
|
+
logger.error("[BillingService] Window is undefined (not in browser)");
|
|
1094
1027
|
return false;
|
|
1095
1028
|
}
|
|
1096
1029
|
if (!window.Stripe) {
|
|
@@ -1098,15 +1031,14 @@ var BillingService = class {
|
|
|
1098
1031
|
}
|
|
1099
1032
|
if (window.Stripe) {
|
|
1100
1033
|
this.stripe = window.Stripe(this.config.stripePublishableKey);
|
|
1101
|
-
|
|
1102
|
-
this.log("info", "[BillingService] Web billing initialized");
|
|
1034
|
+
logger.info("[BillingService] Web billing initialized");
|
|
1103
1035
|
return true;
|
|
1104
1036
|
} else {
|
|
1105
|
-
|
|
1037
|
+
logger.error("[BillingService] Stripe not available after loading");
|
|
1106
1038
|
return false;
|
|
1107
1039
|
}
|
|
1108
1040
|
} catch (error) {
|
|
1109
|
-
|
|
1041
|
+
logger.error("[BillingService] Stripe initialization failed:", error?.message);
|
|
1110
1042
|
return false;
|
|
1111
1043
|
}
|
|
1112
1044
|
}
|
|
@@ -1131,11 +1063,11 @@ var BillingService = class {
|
|
|
1131
1063
|
script.src = "https://js.stripe.com/v3/";
|
|
1132
1064
|
script.async = true;
|
|
1133
1065
|
script.onload = () => {
|
|
1134
|
-
|
|
1066
|
+
logger.info("[BillingService] Stripe.js loaded");
|
|
1135
1067
|
resolve();
|
|
1136
1068
|
};
|
|
1137
1069
|
script.onerror = () => {
|
|
1138
|
-
|
|
1070
|
+
logger.error("[BillingService] Failed to load Stripe.js");
|
|
1139
1071
|
reject(new Error("Failed to load Stripe.js"));
|
|
1140
1072
|
};
|
|
1141
1073
|
try {
|
|
@@ -1146,12 +1078,9 @@ var BillingService = class {
|
|
|
1146
1078
|
});
|
|
1147
1079
|
}
|
|
1148
1080
|
/**
|
|
1149
|
-
* Check if billing is available
|
|
1081
|
+
* Check if billing is available based on current config and platform state
|
|
1150
1082
|
*/
|
|
1151
1083
|
isAvailable() {
|
|
1152
|
-
if (!this.isInitialized) {
|
|
1153
|
-
return false;
|
|
1154
|
-
}
|
|
1155
1084
|
if (this.platform === "native" /* NATIVE */) {
|
|
1156
1085
|
return this.nativeAvailable;
|
|
1157
1086
|
} else if (this.platform === "web" /* WEB */) {
|
|
@@ -1160,12 +1089,10 @@ var BillingService = class {
|
|
|
1160
1089
|
return false;
|
|
1161
1090
|
}
|
|
1162
1091
|
/**
|
|
1163
|
-
* Get available products
|
|
1092
|
+
* Get available products. Auto-initializes on first call.
|
|
1164
1093
|
*/
|
|
1165
1094
|
async getProducts() {
|
|
1166
|
-
|
|
1167
|
-
throw new Error("BillingService not initialized. Call initialize() first.");
|
|
1168
|
-
}
|
|
1095
|
+
await this.initialize();
|
|
1169
1096
|
if (this.platform === "native" /* NATIVE */) {
|
|
1170
1097
|
return await this.getProductsNative();
|
|
1171
1098
|
} else if (this.platform === "web" /* WEB */) {
|
|
@@ -1177,38 +1104,31 @@ var BillingService = class {
|
|
|
1177
1104
|
* Get products from native IAP
|
|
1178
1105
|
*/
|
|
1179
1106
|
async getProductsNative() {
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
this.log("info", `[BillingService] Fetched ${this.products.length} native products`);
|
|
1206
|
-
resolve(this.products);
|
|
1207
|
-
}).catch((error) => {
|
|
1208
|
-
this.log("error", "[BillingService] Failed to fetch native products:", error?.message);
|
|
1209
|
-
reject(error);
|
|
1210
|
-
});
|
|
1211
|
-
});
|
|
1107
|
+
if (!this.config.gameId || !this.config.checkoutUrl) {
|
|
1108
|
+
const error = new Error("gameId and checkoutUrl required for native purchases");
|
|
1109
|
+
logger.error("[BillingService]", error.message);
|
|
1110
|
+
throw error;
|
|
1111
|
+
}
|
|
1112
|
+
const response = await fetch(
|
|
1113
|
+
`${this.config.checkoutUrl}/get-native-packages?game_id=${this.config.gameId}`
|
|
1114
|
+
);
|
|
1115
|
+
if (!response.ok) {
|
|
1116
|
+
throw new Error(`Failed to fetch native products: ${response.status}`);
|
|
1117
|
+
}
|
|
1118
|
+
const data = await response.json();
|
|
1119
|
+
if (!data.packages || !Array.isArray(data.packages)) {
|
|
1120
|
+
throw new Error("Invalid response format: missing packages array");
|
|
1121
|
+
}
|
|
1122
|
+
const products = data.packages.map((pkg) => ({
|
|
1123
|
+
productId: pkg.productId,
|
|
1124
|
+
title: pkg.package_name,
|
|
1125
|
+
description: `${pkg.game_name} - ${pkg.package_name}`,
|
|
1126
|
+
price: pkg.price_cents / 100,
|
|
1127
|
+
localizedPrice: pkg.price_display,
|
|
1128
|
+
currency: "USD"
|
|
1129
|
+
}));
|
|
1130
|
+
logger.info(`[BillingService] Fetched ${products.length} native products`);
|
|
1131
|
+
return products;
|
|
1212
1132
|
}
|
|
1213
1133
|
/**
|
|
1214
1134
|
* Get products from web API (Stripe)
|
|
@@ -1216,7 +1136,7 @@ var BillingService = class {
|
|
|
1216
1136
|
async getProductsWeb() {
|
|
1217
1137
|
if (!this.config.checkoutUrl || !this.config.gameId) {
|
|
1218
1138
|
const error = new Error("checkoutUrl and gameId required for web purchases");
|
|
1219
|
-
|
|
1139
|
+
logger.error("[BillingService]", error.message);
|
|
1220
1140
|
throw error;
|
|
1221
1141
|
}
|
|
1222
1142
|
try {
|
|
@@ -1229,7 +1149,7 @@ var BillingService = class {
|
|
|
1229
1149
|
if (!data.packages || !Array.isArray(data.packages)) {
|
|
1230
1150
|
throw new Error("Invalid response format: missing packages array");
|
|
1231
1151
|
}
|
|
1232
|
-
|
|
1152
|
+
const products = data.packages.map((pkg) => ({
|
|
1233
1153
|
productId: pkg.priceId || pkg.productId,
|
|
1234
1154
|
// Prefer priceId for Stripe
|
|
1235
1155
|
title: pkg.package_name,
|
|
@@ -1238,23 +1158,21 @@ var BillingService = class {
|
|
|
1238
1158
|
localizedPrice: pkg.price_display,
|
|
1239
1159
|
currency: "USD"
|
|
1240
1160
|
}));
|
|
1241
|
-
|
|
1242
|
-
return
|
|
1161
|
+
logger.info(`[BillingService] Fetched ${products.length} web products`);
|
|
1162
|
+
return products;
|
|
1243
1163
|
} catch (error) {
|
|
1244
|
-
|
|
1164
|
+
logger.error("[BillingService] Failed to fetch web products:", error?.message);
|
|
1245
1165
|
throw error;
|
|
1246
1166
|
}
|
|
1247
1167
|
}
|
|
1248
1168
|
/**
|
|
1249
|
-
* Purchase a product
|
|
1169
|
+
* Purchase a product. Auto-initializes on first call.
|
|
1250
1170
|
* @param productId - The product ID (priceId for web/Stripe, productId for native)
|
|
1251
1171
|
* @param options - Optional purchase options
|
|
1252
1172
|
* @param options.elementId - For web: DOM element ID to mount Stripe checkout (default: 'stripe-checkout-element')
|
|
1253
1173
|
*/
|
|
1254
1174
|
async purchase(productId, options) {
|
|
1255
|
-
|
|
1256
|
-
throw new Error("BillingService not initialized. Call initialize() first.");
|
|
1257
|
-
}
|
|
1175
|
+
await this.initialize();
|
|
1258
1176
|
if (!this.isAvailable()) {
|
|
1259
1177
|
throw new Error("Billing is not available on this platform");
|
|
1260
1178
|
}
|
|
@@ -1274,7 +1192,7 @@ var BillingService = class {
|
|
|
1274
1192
|
reject(new Error("userId is required for native purchases"));
|
|
1275
1193
|
return;
|
|
1276
1194
|
}
|
|
1277
|
-
|
|
1195
|
+
logger.info(`[BillingService] Purchasing: ${productId}`);
|
|
1278
1196
|
const previousCompleteCallback = this.onPurchaseCompleteCallback;
|
|
1279
1197
|
const previousErrorCallback = this.onPurchaseErrorCallback;
|
|
1280
1198
|
const cleanup = () => {
|
|
@@ -1348,14 +1266,14 @@ var BillingService = class {
|
|
|
1348
1266
|
throw new Error("No client_secret returned from checkout session");
|
|
1349
1267
|
}
|
|
1350
1268
|
await this.mountCheckoutElement(client_secret, elementId || "stripe-checkout-element");
|
|
1351
|
-
|
|
1269
|
+
logger.info(`[BillingService] Checkout session created: ${id}`);
|
|
1352
1270
|
return {
|
|
1353
1271
|
success: true,
|
|
1354
1272
|
productId,
|
|
1355
1273
|
transactionId: id
|
|
1356
1274
|
};
|
|
1357
1275
|
} catch (error) {
|
|
1358
|
-
|
|
1276
|
+
logger.error("[BillingService] Web purchase failed:", error?.message);
|
|
1359
1277
|
return {
|
|
1360
1278
|
success: false,
|
|
1361
1279
|
productId,
|
|
@@ -1377,7 +1295,7 @@ var BillingService = class {
|
|
|
1377
1295
|
}
|
|
1378
1296
|
try {
|
|
1379
1297
|
if (this.checkoutElement) {
|
|
1380
|
-
|
|
1298
|
+
logger.info("[BillingService] Unmounting existing checkout element");
|
|
1381
1299
|
this.unmountCheckoutElement();
|
|
1382
1300
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1383
1301
|
}
|
|
@@ -1386,15 +1304,15 @@ var BillingService = class {
|
|
|
1386
1304
|
throw new Error(`Element with id "${elementId}" not found in the DOM`);
|
|
1387
1305
|
}
|
|
1388
1306
|
container.innerHTML = "";
|
|
1389
|
-
|
|
1307
|
+
logger.info("[BillingService] Creating new checkout instance");
|
|
1390
1308
|
this.checkoutElement = await this.stripe.initEmbeddedCheckout({
|
|
1391
1309
|
clientSecret
|
|
1392
1310
|
});
|
|
1393
|
-
|
|
1311
|
+
logger.info("[BillingService] Mounting checkout element to DOM");
|
|
1394
1312
|
this.checkoutElement.mount(`#${elementId}`);
|
|
1395
1313
|
this.setupCheckoutEventListeners();
|
|
1396
1314
|
} catch (error) {
|
|
1397
|
-
|
|
1315
|
+
logger.error("[BillingService] Failed to mount checkout:", error?.message);
|
|
1398
1316
|
throw error;
|
|
1399
1317
|
}
|
|
1400
1318
|
}
|
|
@@ -1415,7 +1333,7 @@ var BillingService = class {
|
|
|
1415
1333
|
transactionId: sessionId || void 0
|
|
1416
1334
|
});
|
|
1417
1335
|
}
|
|
1418
|
-
|
|
1336
|
+
logger.info("[BillingService] Payment completed");
|
|
1419
1337
|
urlParams.delete("payment");
|
|
1420
1338
|
urlParams.delete("session_id");
|
|
1421
1339
|
const newUrl = `${window.location.pathname}${urlParams.toString() ? "?" + urlParams.toString() : ""}`;
|
|
@@ -1434,7 +1352,7 @@ var BillingService = class {
|
|
|
1434
1352
|
this.checkoutElement.destroy();
|
|
1435
1353
|
}
|
|
1436
1354
|
} catch (error) {
|
|
1437
|
-
|
|
1355
|
+
logger.warn("[BillingService] Error unmounting checkout element:", error?.message);
|
|
1438
1356
|
}
|
|
1439
1357
|
this.checkoutElement = null;
|
|
1440
1358
|
}
|
|
@@ -1462,9 +1380,8 @@ var BillingService = class {
|
|
|
1462
1380
|
NativeBridge.off("PURCHASE_ERROR" /* PURCHASE_ERROR */);
|
|
1463
1381
|
}
|
|
1464
1382
|
this.unmountCheckoutElement();
|
|
1465
|
-
this.
|
|
1383
|
+
this.initPromise = null;
|
|
1466
1384
|
this.nativeAvailable = false;
|
|
1467
|
-
this.products = [];
|
|
1468
1385
|
this.stripe = null;
|
|
1469
1386
|
this.onPurchaseCompleteCallback = void 0;
|
|
1470
1387
|
this.onPurchaseErrorCallback = void 0;
|
|
@@ -1637,10 +1554,9 @@ var HyveClient = class {
|
|
|
1637
1554
|
adsService;
|
|
1638
1555
|
playgamaService = null;
|
|
1639
1556
|
playgamaInitPromise = null;
|
|
1557
|
+
crazyGamesService = null;
|
|
1558
|
+
crazyGamesInitPromise = null;
|
|
1640
1559
|
billingService;
|
|
1641
|
-
billingConfig;
|
|
1642
|
-
// Store callbacks to preserve them when recreating BillingService
|
|
1643
|
-
billingCallbacks = {};
|
|
1644
1560
|
storageMode;
|
|
1645
1561
|
cloudStorageAdapter;
|
|
1646
1562
|
localStorageAdapter;
|
|
@@ -1671,13 +1587,28 @@ var HyveClient = class {
|
|
|
1671
1587
|
return success;
|
|
1672
1588
|
});
|
|
1673
1589
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1590
|
+
if (typeof window !== "undefined" && CrazyGamesService.isCrazyGamesDomain()) {
|
|
1591
|
+
this.crazyGamesService = new CrazyGamesService();
|
|
1592
|
+
this.crazyGamesInitPromise = this.crazyGamesService.initialize().then((success) => {
|
|
1593
|
+
logger.info("CrazyGames SDK initialized:", success);
|
|
1594
|
+
return success;
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1676
1597
|
this.storageMode = config?.storageMode || "cloud";
|
|
1677
1598
|
this.cloudStorageAdapter = new CloudStorageAdapter(
|
|
1678
1599
|
(endpoint, options) => this.callApi(endpoint, options)
|
|
1679
1600
|
);
|
|
1680
1601
|
this.localStorageAdapter = new LocalStorageAdapter(() => this.getUserId());
|
|
1602
|
+
if (typeof window !== "undefined") {
|
|
1603
|
+
this._parseUrlAuth();
|
|
1604
|
+
}
|
|
1605
|
+
const billingConfig = {
|
|
1606
|
+
checkoutUrl: this.apiBaseUrl,
|
|
1607
|
+
userId: this.userId ?? void 0,
|
|
1608
|
+
gameId: this.gameId ? Number(this.gameId) : void 0,
|
|
1609
|
+
...config?.billing
|
|
1610
|
+
};
|
|
1611
|
+
this.billingService = new BillingService(billingConfig);
|
|
1681
1612
|
const envSource = config?.isDev !== void 0 ? "explicit config" : "auto-detected from parent URL";
|
|
1682
1613
|
logger.info("==========================================");
|
|
1683
1614
|
logger.info("HyveClient Initialized");
|
|
@@ -1689,28 +1620,27 @@ var HyveClient = class {
|
|
|
1689
1620
|
`(${envSource})`
|
|
1690
1621
|
);
|
|
1691
1622
|
logger.info("API Base URL:", this.apiBaseUrl);
|
|
1692
|
-
logger.info("Ads enabled:", this.adsService.isEnabled());
|
|
1693
1623
|
logger.info("Playgama platform:", this.playgamaService !== null);
|
|
1624
|
+
logger.info("CrazyGames platform:", this.crazyGamesService !== null);
|
|
1694
1625
|
logger.info(
|
|
1695
1626
|
"Billing configured:",
|
|
1696
|
-
Object.keys(
|
|
1627
|
+
!!config?.billing && Object.keys(config.billing).length > 0
|
|
1697
1628
|
);
|
|
1698
1629
|
logger.info("Storage mode:", this.storageMode);
|
|
1630
|
+
logger.info("Authenticated:", this.jwtToken !== null);
|
|
1699
1631
|
logger.debug("Config:", {
|
|
1700
1632
|
isDev: this.telemetryConfig.isDev,
|
|
1701
1633
|
hasCustomApiUrl: !!config?.apiBaseUrl,
|
|
1702
|
-
|
|
1703
|
-
billingConfigured: Object.keys(this.billingConfig).length > 0,
|
|
1634
|
+
billingConfigured: !!config?.billing && Object.keys(config.billing).length > 0,
|
|
1704
1635
|
storageMode: this.storageMode
|
|
1705
1636
|
});
|
|
1706
1637
|
logger.info("==========================================");
|
|
1707
1638
|
}
|
|
1708
1639
|
/**
|
|
1709
|
-
*
|
|
1710
|
-
*
|
|
1711
|
-
* @returns Promise resolving to boolean indicating success
|
|
1640
|
+
* Parses JWT and game ID from the current window URL and stores them on the client.
|
|
1641
|
+
* Called automatically during construction.
|
|
1712
1642
|
*/
|
|
1713
|
-
|
|
1643
|
+
_parseUrlAuth(urlParams) {
|
|
1714
1644
|
try {
|
|
1715
1645
|
const params = urlParams ? parseUrlParams(urlParams) : parseUrlParams(window.location.search);
|
|
1716
1646
|
if (params.hyveAccess) {
|
|
@@ -1735,27 +1665,11 @@ var HyveClient = class {
|
|
|
1735
1665
|
}
|
|
1736
1666
|
if (this.jwtToken) {
|
|
1737
1667
|
logger.info("Authentication successful via JWT");
|
|
1738
|
-
return true;
|
|
1739
|
-
}
|
|
1740
|
-
const authResult = verifyAuthentication({
|
|
1741
|
-
hyveToken: params.hyveToken,
|
|
1742
|
-
signature: params.signature,
|
|
1743
|
-
message: params.message
|
|
1744
|
-
});
|
|
1745
|
-
if (authResult.isValid && authResult.address) {
|
|
1746
|
-
this.userId = authResult.address;
|
|
1747
|
-
logger.info("Authentication successful:", authResult.address);
|
|
1748
|
-
logger.info("Authentication method:", authResult.method);
|
|
1749
|
-
return true;
|
|
1750
1668
|
} else {
|
|
1751
|
-
logger.
|
|
1752
|
-
this.userId = null;
|
|
1753
|
-
return false;
|
|
1669
|
+
logger.info("No hyve-access JWT token in URL \u2014 unauthenticated");
|
|
1754
1670
|
}
|
|
1755
1671
|
} catch (error) {
|
|
1756
|
-
logger.error("
|
|
1757
|
-
this.userId = null;
|
|
1758
|
-
return false;
|
|
1672
|
+
logger.error("Error parsing URL auth:", error);
|
|
1759
1673
|
}
|
|
1760
1674
|
}
|
|
1761
1675
|
/**
|
|
@@ -1772,7 +1686,7 @@ var HyveClient = class {
|
|
|
1772
1686
|
*/
|
|
1773
1687
|
async sendTelemetry(eventLocation, eventCategory, eventAction, eventSubCategory, eventSubAction, eventDetails, platformId) {
|
|
1774
1688
|
if (!this.jwtToken) {
|
|
1775
|
-
logger.error("JWT token required.
|
|
1689
|
+
logger.error("JWT token required. Ensure hyve-access and game-id are present in the URL.");
|
|
1776
1690
|
return false;
|
|
1777
1691
|
}
|
|
1778
1692
|
if (!this.gameId) {
|
|
@@ -1844,7 +1758,7 @@ var HyveClient = class {
|
|
|
1844
1758
|
async callApi(endpoint, options = {}) {
|
|
1845
1759
|
if (!this.jwtToken) {
|
|
1846
1760
|
throw new Error(
|
|
1847
|
-
"No JWT token available.
|
|
1761
|
+
"No JWT token available. Ensure hyve-access and game-id are present in the URL."
|
|
1848
1762
|
);
|
|
1849
1763
|
}
|
|
1850
1764
|
try {
|
|
@@ -1974,6 +1888,13 @@ var HyveClient = class {
|
|
|
1974
1888
|
const storageMode = mode || this.storageMode;
|
|
1975
1889
|
return storageMode === "local" ? this.localStorageAdapter : this.cloudStorageAdapter;
|
|
1976
1890
|
}
|
|
1891
|
+
/**
|
|
1892
|
+
* Returns the current game ID or throws if not available.
|
|
1893
|
+
*/
|
|
1894
|
+
requireGameId() {
|
|
1895
|
+
const gameId = this.requireGameId();
|
|
1896
|
+
return gameId;
|
|
1897
|
+
}
|
|
1977
1898
|
/**
|
|
1978
1899
|
* Save persistent game data
|
|
1979
1900
|
* @param key Data key
|
|
@@ -1982,10 +1903,7 @@ var HyveClient = class {
|
|
|
1982
1903
|
* @returns Promise resolving to save response
|
|
1983
1904
|
*/
|
|
1984
1905
|
async saveGameData(key, value, storage) {
|
|
1985
|
-
const gameId = this.
|
|
1986
|
-
if (!gameId) {
|
|
1987
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
1988
|
-
}
|
|
1906
|
+
const gameId = this.requireGameId();
|
|
1989
1907
|
const storageMode = storage || this.storageMode;
|
|
1990
1908
|
logger.debug(`Saving game data to ${storageMode}: ${gameId}/${key}`);
|
|
1991
1909
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2000,10 +1918,7 @@ var HyveClient = class {
|
|
|
2000
1918
|
* @returns Promise resolving to save response
|
|
2001
1919
|
*/
|
|
2002
1920
|
async batchSaveGameData(items, storage) {
|
|
2003
|
-
const gameId = this.
|
|
2004
|
-
if (!gameId) {
|
|
2005
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2006
|
-
}
|
|
1921
|
+
const gameId = this.requireGameId();
|
|
2007
1922
|
const storageMode = storage || this.storageMode;
|
|
2008
1923
|
logger.debug(`Batch saving ${items.length} game data entries to ${storageMode} for game: ${gameId}`);
|
|
2009
1924
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2018,10 +1933,7 @@ var HyveClient = class {
|
|
|
2018
1933
|
* @returns Promise resolving to game data item or null if not found
|
|
2019
1934
|
*/
|
|
2020
1935
|
async getGameData(key, storage) {
|
|
2021
|
-
const gameId = this.
|
|
2022
|
-
if (!gameId) {
|
|
2023
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2024
|
-
}
|
|
1936
|
+
const gameId = this.requireGameId();
|
|
2025
1937
|
const storageMode = storage || this.storageMode;
|
|
2026
1938
|
logger.debug(`Getting game data from ${storageMode}: ${gameId}/${key}`);
|
|
2027
1939
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2040,10 +1952,7 @@ var HyveClient = class {
|
|
|
2040
1952
|
* @returns Promise resolving to array of game data items
|
|
2041
1953
|
*/
|
|
2042
1954
|
async getMultipleGameData(keys, storage) {
|
|
2043
|
-
const gameId = this.
|
|
2044
|
-
if (!gameId) {
|
|
2045
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2046
|
-
}
|
|
1955
|
+
const gameId = this.requireGameId();
|
|
2047
1956
|
const storageMode = storage || this.storageMode;
|
|
2048
1957
|
logger.debug(`Getting ${keys.length} game data entries from ${storageMode} for game: ${gameId}`);
|
|
2049
1958
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2058,10 +1967,7 @@ var HyveClient = class {
|
|
|
2058
1967
|
* @returns Promise resolving to boolean indicating if data was deleted
|
|
2059
1968
|
*/
|
|
2060
1969
|
async deleteGameData(key, storage) {
|
|
2061
|
-
const gameId = this.
|
|
2062
|
-
if (!gameId) {
|
|
2063
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2064
|
-
}
|
|
1970
|
+
const gameId = this.requireGameId();
|
|
2065
1971
|
const storageMode = storage || this.storageMode;
|
|
2066
1972
|
logger.debug(`Deleting game data from ${storageMode}: ${gameId}/${key}`);
|
|
2067
1973
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2080,10 +1986,7 @@ var HyveClient = class {
|
|
|
2080
1986
|
* @returns Promise resolving to number of entries deleted
|
|
2081
1987
|
*/
|
|
2082
1988
|
async deleteMultipleGameData(keys, storage) {
|
|
2083
|
-
const gameId = this.
|
|
2084
|
-
if (!gameId) {
|
|
2085
|
-
throw new Error("game-id is required for persistent storage. Call authenticateFromUrl first.");
|
|
2086
|
-
}
|
|
1989
|
+
const gameId = this.requireGameId();
|
|
2087
1990
|
const storageMode = storage || this.storageMode;
|
|
2088
1991
|
logger.debug(`Deleting ${keys.length} game data entries from ${storageMode} for game: ${gameId}`);
|
|
2089
1992
|
const adapter = this.getStorageAdapter(storage);
|
|
@@ -2120,6 +2023,25 @@ var HyveClient = class {
|
|
|
2120
2023
|
* @returns Promise resolving to ad result
|
|
2121
2024
|
*/
|
|
2122
2025
|
async showAd(type) {
|
|
2026
|
+
if (this.crazyGamesService) {
|
|
2027
|
+
if (this.crazyGamesInitPromise) {
|
|
2028
|
+
await this.crazyGamesInitPromise;
|
|
2029
|
+
}
|
|
2030
|
+
if (this.crazyGamesService.isInitialized()) {
|
|
2031
|
+
const { onBeforeAd, onAfterAd, onRewardEarned } = this.adsService.getCallbacks();
|
|
2032
|
+
if (type === "rewarded") {
|
|
2033
|
+
return this.crazyGamesService.showRewarded({
|
|
2034
|
+
onBeforeAd: () => onBeforeAd("rewarded"),
|
|
2035
|
+
onAfterAd: () => onAfterAd("rewarded"),
|
|
2036
|
+
onRewardEarned
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
return this.crazyGamesService.showInterstitial({
|
|
2040
|
+
onBeforeAd: () => onBeforeAd(type),
|
|
2041
|
+
onAfterAd: () => onAfterAd(type)
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2123
2045
|
if (this.playgamaService) {
|
|
2124
2046
|
if (this.playgamaInitPromise) {
|
|
2125
2047
|
await this.playgamaInitPromise;
|
|
@@ -2142,59 +2064,41 @@ var HyveClient = class {
|
|
|
2142
2064
|
return this.adsService.show(type);
|
|
2143
2065
|
}
|
|
2144
2066
|
/**
|
|
2145
|
-
*
|
|
2146
|
-
*
|
|
2067
|
+
* Notifies CrazyGames that gameplay has started.
|
|
2068
|
+
* No-op on other platforms.
|
|
2147
2069
|
*/
|
|
2148
|
-
|
|
2149
|
-
|
|
2070
|
+
async gameplayStart() {
|
|
2071
|
+
if (this.crazyGamesService) {
|
|
2072
|
+
if (this.crazyGamesInitPromise) await this.crazyGamesInitPromise;
|
|
2073
|
+
this.crazyGamesService.gameplayStart();
|
|
2074
|
+
}
|
|
2150
2075
|
}
|
|
2151
2076
|
/**
|
|
2152
|
-
*
|
|
2153
|
-
*
|
|
2077
|
+
* Notifies CrazyGames that gameplay has stopped.
|
|
2078
|
+
* No-op on other platforms.
|
|
2154
2079
|
*/
|
|
2155
|
-
|
|
2156
|
-
|
|
2080
|
+
async gameplayStop() {
|
|
2081
|
+
if (this.crazyGamesService) {
|
|
2082
|
+
if (this.crazyGamesInitPromise) await this.crazyGamesInitPromise;
|
|
2083
|
+
this.crazyGamesService.gameplayStop();
|
|
2084
|
+
}
|
|
2157
2085
|
}
|
|
2158
2086
|
/**
|
|
2159
|
-
*
|
|
2160
|
-
*
|
|
2087
|
+
* Triggers a celebration effect on the CrazyGames website for significant achievements.
|
|
2088
|
+
* No-op on other platforms.
|
|
2161
2089
|
*/
|
|
2162
|
-
|
|
2163
|
-
this.
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
}
|
|
2167
|
-
logger.info("Billing configuration updated");
|
|
2090
|
+
async happytime() {
|
|
2091
|
+
if (this.crazyGamesService) {
|
|
2092
|
+
if (this.crazyGamesInitPromise) await this.crazyGamesInitPromise;
|
|
2093
|
+
this.crazyGamesService.happytime();
|
|
2094
|
+
}
|
|
2168
2095
|
}
|
|
2169
2096
|
/**
|
|
2170
|
-
*
|
|
2171
|
-
*
|
|
2172
|
-
* @returns Promise resolving to boolean indicating success
|
|
2097
|
+
* Check if ads are ready to show
|
|
2098
|
+
* @returns Boolean indicating if ads have initialized successfully
|
|
2173
2099
|
*/
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
...this.billingConfig
|
|
2177
|
-
};
|
|
2178
|
-
if (!mergedConfig.userId && this.userId) {
|
|
2179
|
-
mergedConfig.userId = this.userId;
|
|
2180
|
-
}
|
|
2181
|
-
if (!mergedConfig.gameId && this.gameId) {
|
|
2182
|
-
mergedConfig.gameId = Number(this.gameId);
|
|
2183
|
-
}
|
|
2184
|
-
if (!mergedConfig.checkoutUrl) {
|
|
2185
|
-
mergedConfig.checkoutUrl = this.apiBaseUrl;
|
|
2186
|
-
}
|
|
2187
|
-
this.billingService = new BillingService(mergedConfig);
|
|
2188
|
-
if (this.billingCallbacks.onComplete) {
|
|
2189
|
-
this.billingService.onPurchaseComplete(this.billingCallbacks.onComplete);
|
|
2190
|
-
}
|
|
2191
|
-
if (this.billingCallbacks.onError) {
|
|
2192
|
-
this.billingService.onPurchaseError(this.billingCallbacks.onError);
|
|
2193
|
-
}
|
|
2194
|
-
if (this.billingCallbacks.onLog) {
|
|
2195
|
-
this.billingService.onLog(this.billingCallbacks.onLog);
|
|
2196
|
-
}
|
|
2197
|
-
return await this.billingService.initialize();
|
|
2100
|
+
areAdsReady() {
|
|
2101
|
+
return this.adsService.isReady();
|
|
2198
2102
|
}
|
|
2199
2103
|
/**
|
|
2200
2104
|
* Get the billing platform
|
|
@@ -2231,7 +2135,6 @@ var HyveClient = class {
|
|
|
2231
2135
|
* @param callback Function to call on purchase completion
|
|
2232
2136
|
*/
|
|
2233
2137
|
onPurchaseComplete(callback) {
|
|
2234
|
-
this.billingCallbacks.onComplete = callback;
|
|
2235
2138
|
this.billingService.onPurchaseComplete(callback);
|
|
2236
2139
|
}
|
|
2237
2140
|
/**
|
|
@@ -2239,7 +2142,6 @@ var HyveClient = class {
|
|
|
2239
2142
|
* @param callback Function to call on purchase error
|
|
2240
2143
|
*/
|
|
2241
2144
|
onPurchaseError(callback) {
|
|
2242
|
-
this.billingCallbacks.onError = callback;
|
|
2243
2145
|
this.billingService.onPurchaseError(callback);
|
|
2244
2146
|
}
|
|
2245
2147
|
/**
|
|
@@ -2248,20 +2150,13 @@ var HyveClient = class {
|
|
|
2248
2150
|
unmountBillingCheckout() {
|
|
2249
2151
|
this.billingService.unmountCheckoutElement();
|
|
2250
2152
|
}
|
|
2251
|
-
/**
|
|
2252
|
-
* Register a callback to receive billing logs
|
|
2253
|
-
* @param callback Function to call with log messages
|
|
2254
|
-
*/
|
|
2255
|
-
onBillingLog(callback) {
|
|
2256
|
-
this.billingCallbacks.onLog = callback;
|
|
2257
|
-
this.billingService.onLog(callback);
|
|
2258
|
-
}
|
|
2259
2153
|
};
|
|
2260
2154
|
export {
|
|
2261
2155
|
AdsService,
|
|
2262
2156
|
BillingPlatform,
|
|
2263
2157
|
BillingService,
|
|
2264
2158
|
CloudStorageAdapter,
|
|
2159
|
+
CrazyGamesService,
|
|
2265
2160
|
HyveClient,
|
|
2266
2161
|
LocalStorageAdapter,
|
|
2267
2162
|
Logger,
|
|
@@ -2269,11 +2164,7 @@ export {
|
|
|
2269
2164
|
NativeMessageType,
|
|
2270
2165
|
PlaygamaService,
|
|
2271
2166
|
generateUUID,
|
|
2272
|
-
handleVerifyMessage,
|
|
2273
2167
|
isDomainAllowed,
|
|
2274
2168
|
logger,
|
|
2275
|
-
parseUrlParams
|
|
2276
|
-
validateSignature,
|
|
2277
|
-
verifyAuthentication,
|
|
2278
|
-
verifyHyveToken
|
|
2169
|
+
parseUrlParams
|
|
2279
2170
|
};
|