@arcadiasol/game-sdk 1.0.0 → 1.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 +63 -382
- package/dist/esm/api-client.d.ts +54 -0
- package/dist/esm/api-client.d.ts.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +410 -98
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/payment.d.ts +12 -3
- package/dist/esm/payment.d.ts.map +1 -1
- package/dist/esm/sdk.d.ts +2 -1
- package/dist/esm/sdk.d.ts.map +1 -1
- package/dist/esm/types.d.ts +16 -6
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/wallet.d.ts +4 -2
- package/dist/esm/wallet.d.ts.map +1 -1
- package/dist/umd/arcadia-game-sdk.js +410 -97
- package/dist/umd/arcadia-game-sdk.js.map +1 -1
- package/dist/umd/arcadia-game-sdk.min.js +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -229,45 +229,61 @@ class MessageHandler {
|
|
|
229
229
|
* Wallet address management
|
|
230
230
|
*/
|
|
231
231
|
class WalletManager {
|
|
232
|
-
constructor(messageHandler, isIframe) {
|
|
232
|
+
constructor(messageHandler, isIframe, apiClient) {
|
|
233
233
|
this.walletAddress = null;
|
|
234
234
|
this.walletConnected = false;
|
|
235
|
+
this.apiClient = null;
|
|
235
236
|
this.walletChangeCallbacks = [];
|
|
236
237
|
this.messageHandler = messageHandler;
|
|
237
238
|
this.isIframe = isIframe;
|
|
239
|
+
this.apiClient = apiClient || null;
|
|
238
240
|
}
|
|
239
241
|
/**
|
|
240
|
-
* Get wallet address from parent window
|
|
242
|
+
* Get wallet address from parent window (iframe) or API (non-iframe)
|
|
241
243
|
*/
|
|
242
244
|
async getWalletAddress() {
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
if (this.isIframe) {
|
|
246
|
+
// Iframe mode: use postMessage
|
|
247
|
+
try {
|
|
248
|
+
const response = await this.messageHandler.sendMessage(MessageType.GET_WALLET_ADDRESS);
|
|
249
|
+
this.walletAddress = response.walletAddress;
|
|
250
|
+
this.walletConnected = response.connected;
|
|
251
|
+
return this.walletAddress;
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
// If request fails, assume wallet not connected
|
|
255
|
+
this.walletAddress = null;
|
|
256
|
+
this.walletConnected = false;
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
251
259
|
}
|
|
252
|
-
|
|
253
|
-
//
|
|
254
|
-
this.
|
|
255
|
-
|
|
256
|
-
|
|
260
|
+
else {
|
|
261
|
+
// Non-iframe mode: use API
|
|
262
|
+
if (!this.apiClient) {
|
|
263
|
+
throw new Error('API client not initialized. Ensure apiBaseURL is configured in SDK config.');
|
|
264
|
+
}
|
|
265
|
+
try {
|
|
266
|
+
const response = await this.apiClient.getWalletAddress();
|
|
267
|
+
this.walletAddress = response.walletAddress;
|
|
268
|
+
this.walletConnected = response.connected;
|
|
269
|
+
return this.walletAddress;
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
this.walletAddress = null;
|
|
273
|
+
this.walletConnected = false;
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
257
276
|
}
|
|
258
277
|
}
|
|
259
278
|
/**
|
|
260
279
|
* Check if wallet is connected
|
|
261
280
|
*/
|
|
262
281
|
async isWalletConnected() {
|
|
263
|
-
if (!this.isIframe) {
|
|
264
|
-
return false;
|
|
265
|
-
}
|
|
266
282
|
// If we have cached address, return true
|
|
267
283
|
if (this.walletAddress) {
|
|
268
284
|
return true;
|
|
269
285
|
}
|
|
270
|
-
// Otherwise, fetch from parent
|
|
286
|
+
// Otherwise, fetch from parent (iframe) or API (non-iframe)
|
|
271
287
|
const address = await this.getWalletAddress();
|
|
272
288
|
return address !== null;
|
|
273
289
|
}
|
|
@@ -331,20 +347,22 @@ class WalletManager {
|
|
|
331
347
|
* Payment processing
|
|
332
348
|
*/
|
|
333
349
|
class PaymentManager {
|
|
334
|
-
constructor(gameId, isIframe, messageHandler, walletManager) {
|
|
350
|
+
constructor(gameId, isIframe, messageHandler, walletManager, apiClient) {
|
|
351
|
+
this.apiClient = null;
|
|
335
352
|
this.gameId = gameId;
|
|
336
353
|
this.isIframe = isIframe;
|
|
337
354
|
this.messageHandler = messageHandler;
|
|
338
355
|
this.walletManager = walletManager;
|
|
356
|
+
this.apiClient = apiClient || null;
|
|
339
357
|
}
|
|
340
358
|
/**
|
|
341
359
|
* Pay to play - one-time payment to access game
|
|
360
|
+
* @param amount - Payment amount
|
|
361
|
+
* @param token - Token type: 'SOL', 'USDC', or custom token symbol/mint address
|
|
362
|
+
* @param txSignature - Transaction signature (required for non-iframe mode)
|
|
342
363
|
*/
|
|
343
|
-
async payToPlay(amount, token) {
|
|
364
|
+
async payToPlay(amount, token, txSignature) {
|
|
344
365
|
this.validatePaymentParams(amount, token);
|
|
345
|
-
if (!this.isIframe) {
|
|
346
|
-
throw new NotInIframeError('payToPlay only works when the game is running in an Arcadia iframe');
|
|
347
|
-
}
|
|
348
366
|
// Check wallet connection
|
|
349
367
|
const isConnected = await this.walletManager.isWalletConnected();
|
|
350
368
|
if (!isConnected) {
|
|
@@ -355,47 +373,93 @@ class PaymentManager {
|
|
|
355
373
|
token,
|
|
356
374
|
type: 'pay_to_play',
|
|
357
375
|
gameId: this.gameId,
|
|
376
|
+
txSignature, // Optional for iframe mode, required for non-iframe
|
|
358
377
|
};
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
378
|
+
if (this.isIframe) {
|
|
379
|
+
// Iframe mode: use postMessage
|
|
380
|
+
try {
|
|
381
|
+
const response = await this.messageHandler.sendMessage(MessageType.PAYMENT_REQUEST, request);
|
|
382
|
+
if (!response.success) {
|
|
383
|
+
throw new PaymentFailedError(response.error || 'Payment failed', response.txSignature);
|
|
384
|
+
}
|
|
385
|
+
if (!response.txSignature) {
|
|
386
|
+
throw new PaymentFailedError('Payment succeeded but no transaction signature received');
|
|
387
|
+
}
|
|
388
|
+
if (!response.amount || !response.token || !response.timestamp) {
|
|
389
|
+
throw new PaymentFailedError('Payment succeeded but incomplete payment details received');
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
success: true,
|
|
393
|
+
txSignature: response.txSignature,
|
|
394
|
+
amount: response.amount,
|
|
395
|
+
token: response.token,
|
|
396
|
+
timestamp: response.timestamp,
|
|
397
|
+
purchaseId: response.purchaseId,
|
|
398
|
+
platformFee: response.platformFee,
|
|
399
|
+
developerAmount: response.developerAmount,
|
|
400
|
+
};
|
|
366
401
|
}
|
|
367
|
-
|
|
368
|
-
|
|
402
|
+
catch (error) {
|
|
403
|
+
if (error instanceof PaymentFailedError || error instanceof WalletNotConnectedError) {
|
|
404
|
+
throw error;
|
|
405
|
+
}
|
|
406
|
+
throw new PaymentFailedError(error instanceof Error ? error.message : 'Payment failed');
|
|
369
407
|
}
|
|
370
|
-
return {
|
|
371
|
-
success: true,
|
|
372
|
-
txSignature: response.txSignature,
|
|
373
|
-
amount: response.amount,
|
|
374
|
-
token: response.token,
|
|
375
|
-
timestamp: response.timestamp,
|
|
376
|
-
purchaseId: response.purchaseId,
|
|
377
|
-
platformFee: response.platformFee,
|
|
378
|
-
developerAmount: response.developerAmount,
|
|
379
|
-
};
|
|
380
408
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
409
|
+
else {
|
|
410
|
+
// Non-iframe mode: use API
|
|
411
|
+
if (!this.apiClient) {
|
|
412
|
+
throw new Error('API client not initialized. Ensure apiBaseURL is configured in SDK config.');
|
|
413
|
+
}
|
|
414
|
+
if (!txSignature) {
|
|
415
|
+
throw new PaymentFailedError('Transaction signature is required for non-iframe payments. ' +
|
|
416
|
+
'Please sign the transaction first and provide the signature.');
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
const response = await this.apiClient.sendPaymentRequest(this.gameId, {
|
|
420
|
+
...request,
|
|
421
|
+
txSignature,
|
|
422
|
+
});
|
|
423
|
+
if (!response.success) {
|
|
424
|
+
throw new PaymentFailedError(response.error || 'Payment failed', response.txSignature);
|
|
425
|
+
}
|
|
426
|
+
if (!response.txSignature) {
|
|
427
|
+
throw new PaymentFailedError('Payment succeeded but no transaction signature received');
|
|
428
|
+
}
|
|
429
|
+
if (!response.amount || !response.token || !response.timestamp) {
|
|
430
|
+
throw new PaymentFailedError('Payment succeeded but incomplete payment details received');
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
success: true,
|
|
434
|
+
txSignature: response.txSignature,
|
|
435
|
+
amount: response.amount,
|
|
436
|
+
token: response.token,
|
|
437
|
+
timestamp: response.timestamp,
|
|
438
|
+
purchaseId: response.purchaseId,
|
|
439
|
+
platformFee: response.platformFee,
|
|
440
|
+
developerAmount: response.developerAmount,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
if (error instanceof PaymentFailedError || error instanceof WalletNotConnectedError) {
|
|
445
|
+
throw error;
|
|
446
|
+
}
|
|
447
|
+
throw new PaymentFailedError(error instanceof Error ? error.message : 'Payment failed');
|
|
384
448
|
}
|
|
385
|
-
throw new PaymentFailedError(error instanceof Error ? error.message : 'Payment failed');
|
|
386
449
|
}
|
|
387
450
|
}
|
|
388
451
|
/**
|
|
389
452
|
* Purchase in-game item
|
|
453
|
+
* @param itemId - Item identifier
|
|
454
|
+
* @param amount - Payment amount
|
|
455
|
+
* @param token - Token type: 'SOL', 'USDC', or custom token symbol/mint address
|
|
456
|
+
* @param txSignature - Transaction signature (required for non-iframe mode)
|
|
390
457
|
*/
|
|
391
|
-
async purchaseItem(itemId, amount, token) {
|
|
458
|
+
async purchaseItem(itemId, amount, token, txSignature) {
|
|
392
459
|
this.validatePaymentParams(amount, token);
|
|
393
460
|
if (!itemId || typeof itemId !== 'string' || itemId.trim().length === 0) {
|
|
394
461
|
throw new Error('Item ID is required and must be a non-empty string');
|
|
395
462
|
}
|
|
396
|
-
if (!this.isIframe) {
|
|
397
|
-
throw new NotInIframeError('purchaseItem only works when the game is running in an Arcadia iframe');
|
|
398
|
-
}
|
|
399
463
|
// Check wallet connection
|
|
400
464
|
const isConnected = await this.walletManager.isWalletConnected();
|
|
401
465
|
if (!isConnected) {
|
|
@@ -407,34 +471,79 @@ class PaymentManager {
|
|
|
407
471
|
type: 'in_game_purchase',
|
|
408
472
|
gameId: this.gameId,
|
|
409
473
|
itemId: itemId.trim(),
|
|
474
|
+
txSignature, // Optional for iframe mode, required for non-iframe
|
|
410
475
|
};
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
476
|
+
if (this.isIframe) {
|
|
477
|
+
// Iframe mode: use postMessage
|
|
478
|
+
try {
|
|
479
|
+
const response = await this.messageHandler.sendMessage(MessageType.PAYMENT_REQUEST, request);
|
|
480
|
+
if (!response.success) {
|
|
481
|
+
throw new PaymentFailedError(response.error || 'Purchase failed', response.txSignature);
|
|
482
|
+
}
|
|
483
|
+
if (!response.txSignature) {
|
|
484
|
+
throw new PaymentFailedError('Purchase succeeded but no transaction signature received');
|
|
485
|
+
}
|
|
486
|
+
if (!response.amount || !response.token || !response.timestamp) {
|
|
487
|
+
throw new PaymentFailedError('Purchase succeeded but incomplete payment details received');
|
|
488
|
+
}
|
|
489
|
+
return {
|
|
490
|
+
success: true,
|
|
491
|
+
txSignature: response.txSignature,
|
|
492
|
+
amount: response.amount,
|
|
493
|
+
token: response.token,
|
|
494
|
+
timestamp: response.timestamp,
|
|
495
|
+
purchaseId: response.purchaseId,
|
|
496
|
+
platformFee: response.platformFee,
|
|
497
|
+
developerAmount: response.developerAmount,
|
|
498
|
+
};
|
|
418
499
|
}
|
|
419
|
-
|
|
420
|
-
|
|
500
|
+
catch (error) {
|
|
501
|
+
if (error instanceof PaymentFailedError || error instanceof WalletNotConnectedError) {
|
|
502
|
+
throw error;
|
|
503
|
+
}
|
|
504
|
+
throw new PaymentFailedError(error instanceof Error ? error.message : 'Purchase failed');
|
|
421
505
|
}
|
|
422
|
-
return {
|
|
423
|
-
success: true,
|
|
424
|
-
txSignature: response.txSignature,
|
|
425
|
-
amount: response.amount,
|
|
426
|
-
token: response.token,
|
|
427
|
-
timestamp: response.timestamp,
|
|
428
|
-
purchaseId: response.purchaseId,
|
|
429
|
-
platformFee: response.platformFee,
|
|
430
|
-
developerAmount: response.developerAmount,
|
|
431
|
-
};
|
|
432
506
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
507
|
+
else {
|
|
508
|
+
// Non-iframe mode: use API
|
|
509
|
+
if (!this.apiClient) {
|
|
510
|
+
throw new Error('API client not initialized. Ensure apiBaseURL is configured in SDK config.');
|
|
511
|
+
}
|
|
512
|
+
if (!txSignature) {
|
|
513
|
+
throw new PaymentFailedError('Transaction signature is required for non-iframe purchases. ' +
|
|
514
|
+
'Please sign the transaction first and provide the signature.');
|
|
515
|
+
}
|
|
516
|
+
try {
|
|
517
|
+
const response = await this.apiClient.sendPaymentRequest(this.gameId, {
|
|
518
|
+
...request,
|
|
519
|
+
txSignature,
|
|
520
|
+
});
|
|
521
|
+
if (!response.success) {
|
|
522
|
+
throw new PaymentFailedError(response.error || 'Purchase failed', response.txSignature);
|
|
523
|
+
}
|
|
524
|
+
if (!response.txSignature) {
|
|
525
|
+
throw new PaymentFailedError('Purchase succeeded but no transaction signature received');
|
|
526
|
+
}
|
|
527
|
+
if (!response.amount || !response.token || !response.timestamp) {
|
|
528
|
+
throw new PaymentFailedError('Purchase succeeded but incomplete payment details received');
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
success: true,
|
|
532
|
+
txSignature: response.txSignature,
|
|
533
|
+
amount: response.amount,
|
|
534
|
+
token: response.token,
|
|
535
|
+
timestamp: response.timestamp,
|
|
536
|
+
purchaseId: response.purchaseId,
|
|
537
|
+
platformFee: response.platformFee,
|
|
538
|
+
developerAmount: response.developerAmount,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
catch (error) {
|
|
542
|
+
if (error instanceof PaymentFailedError || error instanceof WalletNotConnectedError) {
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
throw new PaymentFailedError(error instanceof Error ? error.message : 'Purchase failed');
|
|
436
546
|
}
|
|
437
|
-
throw new PaymentFailedError(error instanceof Error ? error.message : 'Purchase failed');
|
|
438
547
|
}
|
|
439
548
|
}
|
|
440
549
|
/**
|
|
@@ -444,9 +553,180 @@ class PaymentManager {
|
|
|
444
553
|
if (typeof amount !== 'number' || isNaN(amount) || amount <= 0) {
|
|
445
554
|
throw new InvalidAmountError();
|
|
446
555
|
}
|
|
447
|
-
if (token !== '
|
|
556
|
+
if (!token || typeof token !== 'string' || token.trim().length === 0) {
|
|
448
557
|
throw new InvalidTokenError();
|
|
449
558
|
}
|
|
559
|
+
// SOL and USDC are always valid
|
|
560
|
+
// Custom tokens will be validated by the backend
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* API Client for non-iframe environments
|
|
566
|
+
* Handles direct REST API calls when SDK is not running in iframe
|
|
567
|
+
*/
|
|
568
|
+
class APIClient {
|
|
569
|
+
constructor(baseURL) {
|
|
570
|
+
this.authToken = null;
|
|
571
|
+
this.walletAddress = null;
|
|
572
|
+
// Use provided base URL or detect from environment
|
|
573
|
+
this.baseURL = baseURL || this.detectBaseURL();
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Detect Arcadia base URL from environment or use default
|
|
577
|
+
*/
|
|
578
|
+
detectBaseURL() {
|
|
579
|
+
// Check for explicit base URL in config
|
|
580
|
+
if (typeof window !== 'undefined' && window.ARCADIA_API_URL) {
|
|
581
|
+
return window.ARCADIA_API_URL;
|
|
582
|
+
}
|
|
583
|
+
// Try to detect from current page (if game is hosted on Arcadia subdomain)
|
|
584
|
+
if (typeof window !== 'undefined') {
|
|
585
|
+
const hostname = window.location.hostname;
|
|
586
|
+
// If on arcadia.com or subdomain, use same origin
|
|
587
|
+
if (hostname.includes('arcadia')) {
|
|
588
|
+
return `${window.location.protocol}//${hostname}`;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
// Default fallback (should be configured by developer)
|
|
592
|
+
return 'https://arcadia.com';
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Set authentication token (from wallet authentication)
|
|
596
|
+
*/
|
|
597
|
+
setAuthToken(token) {
|
|
598
|
+
this.authToken = token;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Set wallet address (for wallet-based auth)
|
|
602
|
+
*/
|
|
603
|
+
setWalletAddress(address) {
|
|
604
|
+
this.walletAddress = address;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Authenticate with wallet
|
|
608
|
+
* Returns auth token for subsequent API calls
|
|
609
|
+
*/
|
|
610
|
+
async authenticateWithWallet(walletAddress, signature, message) {
|
|
611
|
+
const response = await this.request('/api/auth/wallet/connect', {
|
|
612
|
+
method: 'POST',
|
|
613
|
+
body: {
|
|
614
|
+
walletAddress,
|
|
615
|
+
signature,
|
|
616
|
+
message,
|
|
617
|
+
},
|
|
618
|
+
});
|
|
619
|
+
// Store auth token from response
|
|
620
|
+
// Note: You may need to extract token from response based on your auth implementation
|
|
621
|
+
if (response.token) {
|
|
622
|
+
this.authToken = response.token;
|
|
623
|
+
}
|
|
624
|
+
return response;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Get wallet address (for non-iframe)
|
|
628
|
+
* Requires authentication
|
|
629
|
+
*/
|
|
630
|
+
async getWalletAddress() {
|
|
631
|
+
if (!this.authToken && !this.walletAddress) {
|
|
632
|
+
return {
|
|
633
|
+
walletAddress: null,
|
|
634
|
+
connected: false,
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
// If we have wallet address cached, return it
|
|
638
|
+
if (this.walletAddress) {
|
|
639
|
+
return {
|
|
640
|
+
walletAddress: this.walletAddress,
|
|
641
|
+
connected: true,
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
// Otherwise, fetch from profile endpoint
|
|
645
|
+
try {
|
|
646
|
+
const profile = await this.request('/api/profile', {
|
|
647
|
+
method: 'GET',
|
|
648
|
+
});
|
|
649
|
+
if (profile?.walletAddress) {
|
|
650
|
+
this.walletAddress = profile.walletAddress;
|
|
651
|
+
return {
|
|
652
|
+
walletAddress: profile.walletAddress,
|
|
653
|
+
connected: true,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
catch (error) {
|
|
658
|
+
console.warn('Failed to fetch wallet address:', error);
|
|
659
|
+
}
|
|
660
|
+
return {
|
|
661
|
+
walletAddress: null,
|
|
662
|
+
connected: false,
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Send payment request via API
|
|
667
|
+
*/
|
|
668
|
+
async sendPaymentRequest(gameId, request) {
|
|
669
|
+
const endpoint = request.type === 'pay_to_play'
|
|
670
|
+
? `/api/games/${gameId}/pay-to-play`
|
|
671
|
+
: `/api/games/${gameId}/purchase-item`;
|
|
672
|
+
return await this.request(endpoint, {
|
|
673
|
+
method: 'POST',
|
|
674
|
+
body: {
|
|
675
|
+
amount: request.amount,
|
|
676
|
+
token: request.token,
|
|
677
|
+
txSignature: request.txSignature, // App must provide this
|
|
678
|
+
itemId: request.itemId,
|
|
679
|
+
},
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Update playtime/stats
|
|
684
|
+
*/
|
|
685
|
+
async updatePlaytime(gameId, playtimeHours, status) {
|
|
686
|
+
await this.request('/api/library', {
|
|
687
|
+
method: 'POST',
|
|
688
|
+
body: {
|
|
689
|
+
gameId,
|
|
690
|
+
playtimeHours,
|
|
691
|
+
status: status || 'playing',
|
|
692
|
+
},
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Update online status
|
|
697
|
+
*/
|
|
698
|
+
async updateOnlineStatus(isOnline, gameId) {
|
|
699
|
+
await this.request('/api/online-status', {
|
|
700
|
+
method: 'POST',
|
|
701
|
+
body: {
|
|
702
|
+
isOnline,
|
|
703
|
+
gameId,
|
|
704
|
+
},
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Generic request method
|
|
709
|
+
*/
|
|
710
|
+
async request(endpoint, options = {}) {
|
|
711
|
+
const url = `${this.baseURL}${endpoint}`;
|
|
712
|
+
const headers = {
|
|
713
|
+
'Content-Type': 'application/json',
|
|
714
|
+
...options.headers,
|
|
715
|
+
};
|
|
716
|
+
// Add auth token if available
|
|
717
|
+
if (this.authToken) {
|
|
718
|
+
headers['Authorization'] = `Bearer ${this.authToken}`;
|
|
719
|
+
}
|
|
720
|
+
const response = await fetch(url, {
|
|
721
|
+
method: options.method || 'GET',
|
|
722
|
+
headers,
|
|
723
|
+
body: options.body ? JSON.stringify(options.body) : undefined,
|
|
724
|
+
});
|
|
725
|
+
if (!response.ok) {
|
|
726
|
+
const error = await response.json().catch(() => ({ error: 'Request failed' }));
|
|
727
|
+
throw new Error(error.error || `Request failed with status ${response.status}`);
|
|
728
|
+
}
|
|
729
|
+
return await response.json();
|
|
450
730
|
}
|
|
451
731
|
}
|
|
452
732
|
|
|
@@ -459,6 +739,7 @@ class ArcadiaSDK {
|
|
|
459
739
|
*/
|
|
460
740
|
constructor(config) {
|
|
461
741
|
this.initialized = false;
|
|
742
|
+
this.apiClient = null;
|
|
462
743
|
// Validate config
|
|
463
744
|
if (!config || !config.gameId || typeof config.gameId !== 'string' || config.gameId.trim().length === 0) {
|
|
464
745
|
throw new InvalidConfigError('gameId is required and must be a non-empty string');
|
|
@@ -473,42 +754,73 @@ class ArcadiaSDK {
|
|
|
473
754
|
// Initialize message handler
|
|
474
755
|
this.messageHandler = new MessageHandler(this.config.parentOrigin, this.config.timeout);
|
|
475
756
|
// Initialize managers
|
|
476
|
-
this.walletManager = new WalletManager(this.messageHandler, this.isIframe);
|
|
477
|
-
this.paymentManager = new PaymentManager(this.config.gameId, this.isIframe, this.messageHandler, this.walletManager);
|
|
757
|
+
this.walletManager = new WalletManager(this.messageHandler, this.isIframe, this.apiClient);
|
|
758
|
+
this.paymentManager = new PaymentManager(this.config.gameId, this.isIframe, this.messageHandler, this.walletManager, this.apiClient);
|
|
478
759
|
// Set up message listener if in iframe
|
|
479
760
|
if (this.isIframe) {
|
|
480
761
|
this.messageHandler.init();
|
|
481
762
|
this.setupMessageListener();
|
|
482
763
|
}
|
|
764
|
+
else {
|
|
765
|
+
// Initialize API client for non-iframe environments
|
|
766
|
+
this.apiClient = new APIClient(this.config.apiBaseURL);
|
|
767
|
+
// Set auth token if provided
|
|
768
|
+
if (this.config.authToken) {
|
|
769
|
+
this.apiClient.setAuthToken(this.config.authToken);
|
|
770
|
+
}
|
|
771
|
+
// Set wallet address if provided
|
|
772
|
+
if (this.config.walletAddress) {
|
|
773
|
+
this.apiClient.setWalletAddress(this.config.walletAddress);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
483
776
|
}
|
|
484
777
|
/**
|
|
485
|
-
* Initialize SDK and request initialization data from parent
|
|
778
|
+
* Initialize SDK and request initialization data from parent (iframe) or API (non-iframe)
|
|
486
779
|
*/
|
|
487
780
|
async init() {
|
|
488
781
|
if (this.initialized) {
|
|
489
782
|
return; // Already initialized
|
|
490
783
|
}
|
|
491
|
-
if (
|
|
492
|
-
//
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
this.
|
|
784
|
+
if (this.isIframe) {
|
|
785
|
+
// Iframe mode: use postMessage
|
|
786
|
+
try {
|
|
787
|
+
// Request initialization from parent
|
|
788
|
+
const initData = await this.messageHandler.sendMessage(MessageType.INIT_REQUEST);
|
|
789
|
+
// Update wallet status from init data
|
|
790
|
+
if (initData.wallet) {
|
|
791
|
+
this.walletManager.updateWalletStatus(initData.wallet);
|
|
792
|
+
}
|
|
793
|
+
// Notify parent that game is ready
|
|
794
|
+
this.messageHandler.sendOneWay(MessageType.GAME_READY);
|
|
795
|
+
this.initialized = true;
|
|
796
|
+
}
|
|
797
|
+
catch (error) {
|
|
798
|
+
// Initialization failed, but SDK can still be used
|
|
799
|
+
// Wallet functions will fetch on demand
|
|
800
|
+
this.initialized = true;
|
|
801
|
+
console.warn('SDK initialization failed:', error);
|
|
502
802
|
}
|
|
503
|
-
// Notify parent that game is ready
|
|
504
|
-
this.messageHandler.sendOneWay(MessageType.GAME_READY);
|
|
505
|
-
this.initialized = true;
|
|
506
803
|
}
|
|
507
|
-
|
|
508
|
-
//
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
804
|
+
else {
|
|
805
|
+
// Non-iframe mode: use API
|
|
806
|
+
if (!this.apiClient) {
|
|
807
|
+
throw new Error('API client not initialized. Ensure apiBaseURL is configured.');
|
|
808
|
+
}
|
|
809
|
+
try {
|
|
810
|
+
// Fetch wallet address from API
|
|
811
|
+
const walletResponse = await this.apiClient.getWalletAddress();
|
|
812
|
+
// Update wallet manager with API response
|
|
813
|
+
this.walletManager.updateWalletStatus({
|
|
814
|
+
connected: walletResponse.connected,
|
|
815
|
+
address: walletResponse.walletAddress,
|
|
816
|
+
});
|
|
817
|
+
this.initialized = true;
|
|
818
|
+
}
|
|
819
|
+
catch (error) {
|
|
820
|
+
// Initialization failed, but SDK can still be used
|
|
821
|
+
this.initialized = true;
|
|
822
|
+
console.warn('SDK API initialization failed:', error);
|
|
823
|
+
}
|
|
512
824
|
}
|
|
513
825
|
}
|
|
514
826
|
/**
|
|
@@ -613,5 +925,5 @@ class ArcadiaSDK {
|
|
|
613
925
|
*/
|
|
614
926
|
// Main SDK class
|
|
615
927
|
|
|
616
|
-
export { ArcadiaSDK, ArcadiaSDKError, InvalidAmountError, InvalidConfigError, InvalidTokenError, NotInIframeError, PaymentFailedError, TimeoutError, WalletNotConnectedError, ArcadiaSDK as default };
|
|
928
|
+
export { APIClient, ArcadiaSDK, ArcadiaSDKError, InvalidAmountError, InvalidConfigError, InvalidTokenError, NotInIframeError, PaymentFailedError, TimeoutError, WalletNotConnectedError, ArcadiaSDK as default };
|
|
617
929
|
//# sourceMappingURL=index.js.map
|