playkit-sdk 1.1.4-beta.4 → 1.2.1-beta.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * playkit-sdk v1.1.4-beta.4
2
+ * playkit-sdk v1.2.1-beta.1
3
3
  * PlayKit SDK for JavaScript
4
4
  * @license SEE LICENSE IN LICENSE
5
5
  */
@@ -24,6 +24,54 @@ class PlayKitError extends Error {
24
24
  }
25
25
  }
26
26
 
27
+ /**
28
+ * Chat and text generation types
29
+ */
30
+ /**
31
+ * Helper to convert NpcAction to ChatTool
32
+ */
33
+ function npcActionToTool(action) {
34
+ var _a;
35
+ const properties = {};
36
+ const required = [];
37
+ for (const param of action.parameters || []) {
38
+ const propDef = { description: param.description };
39
+ switch (param.type) {
40
+ case 'string':
41
+ propDef.type = 'string';
42
+ break;
43
+ case 'number':
44
+ propDef.type = 'number';
45
+ break;
46
+ case 'boolean':
47
+ propDef.type = 'boolean';
48
+ break;
49
+ case 'stringEnum':
50
+ propDef.type = 'string';
51
+ if ((_a = param.enumOptions) === null || _a === void 0 ? void 0 : _a.length) {
52
+ propDef.enum = param.enumOptions;
53
+ }
54
+ break;
55
+ }
56
+ properties[param.name] = propDef;
57
+ if (param.required !== false) {
58
+ required.push(param.name);
59
+ }
60
+ }
61
+ return {
62
+ type: 'function',
63
+ function: {
64
+ name: action.actionName,
65
+ description: action.description,
66
+ parameters: {
67
+ type: 'object',
68
+ properties,
69
+ required,
70
+ },
71
+ },
72
+ };
73
+ }
74
+
27
75
  /**
28
76
  * Token storage with encryption using Web Crypto API
29
77
  * Stores tokens in localStorage with AES-128-GCM encryption
@@ -408,84 +456,84 @@ class AuthFlowManager extends EventEmitter {
408
456
  // Create modal container
409
457
  this.modal = document.createElement('div');
410
458
  this.modal.className = 'playkit-auth-modal';
411
- this.modal.innerHTML = `
412
- <div class="playkit-auth-overlay"></div>
413
- <div class="playkit-auth-container">
414
- <!-- Identifier Panel -->
415
- <div class="playkit-auth-panel" id="playkit-identifier-panel">
416
- <div class="playkit-auth-header">
417
- <h2>${this.t('signIn')}</h2>
418
- <p>${this.t('signInSubtitle')}</p>
419
- </div>
420
-
421
- <div class="playkit-auth-toggle">
422
- <label class="playkit-toggle-option">
423
- <input type="radio" name="auth-type" value="email" checked>
424
- <span>${this.t('email')}</span>
425
- </label>
426
- <label class="playkit-toggle-option">
427
- <input type="radio" name="auth-type" value="phone">
428
- <span>${this.t('phone')}</span>
429
- </label>
430
- </div>
431
-
432
- <div class="playkit-auth-input-group">
433
- <div class="playkit-input-wrapper">
434
- <svg class="playkit-input-icon" id="playkit-identifier-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
435
- <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
436
- <polyline points="22,6 12,13 2,6"></polyline>
437
- </svg>
438
- <input
439
- type="text"
440
- id="playkit-identifier-input"
441
- placeholder="${this.t('emailPlaceholder')}"
442
- autocomplete="off"
443
- >
444
- </div>
445
- </div>
446
-
447
- <button class="playkit-auth-button" id="playkit-send-code-btn">
448
- ${this.t('sendCode')}
449
- </button>
450
-
451
- <div class="playkit-auth-error" id="playkit-error-text"></div>
452
- </div>
453
-
454
- <!-- Verification Panel -->
455
- <div class="playkit-auth-panel" id="playkit-verification-panel" style="display: none;">
456
- <div class="playkit-auth-header">
457
- <button class="playkit-back-button" id="playkit-back-btn">
458
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
459
- <path d="M19 12H5M12 19l-7-7 7-7"/>
460
- </svg>
461
- </button>
462
- <h2>${this.t('enterCode')}</h2>
463
- <p>${this.t('enterCodeSubtitle')} <span id="playkit-identifier-display"></span></p>
464
- </div>
465
-
466
- <div class="playkit-auth-input-group">
467
- <div class="playkit-code-inputs">
468
- <input type="number" maxlength="1" class="playkit-code-input" data-index="0">
469
- <input type="number" maxlength="1" class="playkit-code-input" data-index="1">
470
- <input type="number" maxlength="1" class="playkit-code-input" data-index="2">
471
- <input type="number" maxlength="1" class="playkit-code-input" data-index="3">
472
- <input type="number" maxlength="1" class="playkit-code-input" data-index="4">
473
- <input type="number" maxlength="1" class="playkit-code-input" data-index="5">
474
- </div>
475
- </div>
476
-
477
- <button class="playkit-auth-button" id="playkit-verify-btn">
478
- ${this.t('verify')}
479
- </button>
480
-
481
- <div class="playkit-auth-error" id="playkit-verify-error-text"></div>
482
- </div>
483
-
484
- <!-- Loading Overlay -->
485
- <div class="playkit-loading-overlay" id="playkit-loading-overlay" style="display: none;">
486
- <div class="playkit-spinner"></div>
487
- </div>
488
- </div>
459
+ this.modal.innerHTML = `
460
+ <div class="playkit-auth-overlay"></div>
461
+ <div class="playkit-auth-container">
462
+ <!-- Identifier Panel -->
463
+ <div class="playkit-auth-panel" id="playkit-identifier-panel">
464
+ <div class="playkit-auth-header">
465
+ <h2>${this.t('signIn')}</h2>
466
+ <p>${this.t('signInSubtitle')}</p>
467
+ </div>
468
+
469
+ <div class="playkit-auth-toggle">
470
+ <label class="playkit-toggle-option">
471
+ <input type="radio" name="auth-type" value="email" checked>
472
+ <span>${this.t('email')}</span>
473
+ </label>
474
+ <label class="playkit-toggle-option">
475
+ <input type="radio" name="auth-type" value="phone">
476
+ <span>${this.t('phone')}</span>
477
+ </label>
478
+ </div>
479
+
480
+ <div class="playkit-auth-input-group">
481
+ <div class="playkit-input-wrapper">
482
+ <svg class="playkit-input-icon" id="playkit-identifier-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
483
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
484
+ <polyline points="22,6 12,13 2,6"></polyline>
485
+ </svg>
486
+ <input
487
+ type="text"
488
+ id="playkit-identifier-input"
489
+ placeholder="${this.t('emailPlaceholder')}"
490
+ autocomplete="off"
491
+ >
492
+ </div>
493
+ </div>
494
+
495
+ <button class="playkit-auth-button" id="playkit-send-code-btn">
496
+ ${this.t('sendCode')}
497
+ </button>
498
+
499
+ <div class="playkit-auth-error" id="playkit-error-text"></div>
500
+ </div>
501
+
502
+ <!-- Verification Panel -->
503
+ <div class="playkit-auth-panel" id="playkit-verification-panel" style="display: none;">
504
+ <div class="playkit-auth-header">
505
+ <button class="playkit-back-button" id="playkit-back-btn">
506
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
507
+ <path d="M19 12H5M12 19l-7-7 7-7"/>
508
+ </svg>
509
+ </button>
510
+ <h2>${this.t('enterCode')}</h2>
511
+ <p>${this.t('enterCodeSubtitle')} <span id="playkit-identifier-display"></span></p>
512
+ </div>
513
+
514
+ <div class="playkit-auth-input-group">
515
+ <div class="playkit-code-inputs">
516
+ <input type="number" maxlength="1" class="playkit-code-input" data-index="0">
517
+ <input type="number" maxlength="1" class="playkit-code-input" data-index="1">
518
+ <input type="number" maxlength="1" class="playkit-code-input" data-index="2">
519
+ <input type="number" maxlength="1" class="playkit-code-input" data-index="3">
520
+ <input type="number" maxlength="1" class="playkit-code-input" data-index="4">
521
+ <input type="number" maxlength="1" class="playkit-code-input" data-index="5">
522
+ </div>
523
+ </div>
524
+
525
+ <button class="playkit-auth-button" id="playkit-verify-btn">
526
+ ${this.t('verify')}
527
+ </button>
528
+
529
+ <div class="playkit-auth-error" id="playkit-verify-error-text"></div>
530
+ </div>
531
+
532
+ <!-- Loading Overlay -->
533
+ <div class="playkit-loading-overlay" id="playkit-loading-overlay" style="display: none;">
534
+ <div class="playkit-spinner"></div>
535
+ </div>
536
+ </div>
489
537
  `;
490
538
  // Add styles and load VanillaOTP
491
539
  this.addStyles();
@@ -520,285 +568,285 @@ class AuthFlowManager extends EventEmitter {
520
568
  return;
521
569
  const style = document.createElement('style');
522
570
  style.id = styleId;
523
- style.textContent = `
524
- .playkit-auth-modal {
525
- position: fixed;
526
- top: 0;
527
- left: 0;
528
- right: 0;
529
- bottom: 0;
530
- z-index: 999999;
531
- display: flex;
532
- justify-content: center;
533
- align-items: center;
534
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
535
- }
536
-
537
- .playkit-auth-overlay {
538
- position: absolute;
539
- top: 0;
540
- left: 0;
541
- right: 0;
542
- bottom: 0;
543
- background: rgba(0, 0, 0, 0.48);
544
- backdrop-filter: blur(8px);
545
- }
546
-
547
- .playkit-auth-container {
548
- position: relative;
549
- background: #FFFFFF;
550
- border-radius: 4px;
551
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
552
- width: 90%;
553
- max-width: 420px;
554
- overflow: hidden;
555
- }
556
-
557
- .playkit-auth-panel {
558
- padding: 40px 32px;
559
- }
560
-
561
- .playkit-auth-header {
562
- text-align: center;
563
- margin-bottom: 32px;
564
- position: relative;
565
- }
566
-
567
- .playkit-auth-header h2 {
568
- margin: 0 0 8px 0;
569
- font-size: 28px;
570
- font-weight: 600;
571
- color: #000000;
572
- }
573
-
574
- .playkit-auth-header p {
575
- margin: 0;
576
- font-size: 14px;
577
- color: #666666;
578
- line-height: 1.5;
579
- }
580
-
581
- .playkit-back-button {
582
- position: absolute;
583
- left: 0;
584
- top: 0;
585
- background: transparent;
586
- border: none;
587
- cursor: pointer;
588
- padding: 4px;
589
- border-radius: 2px;
590
- color: #666666;
591
- transition: background-color 0.15s ease, color 0.15s ease;
592
- }
593
-
594
- .playkit-back-button:hover {
595
- background: #F6F6F6;
596
- color: #000000;
597
- }
598
-
599
- .playkit-auth-toggle {
600
- display: flex;
601
- background: #F6F6F6;
602
- border-radius: 2px;
603
- padding: 2px;
604
- margin-bottom: 24px;
605
- gap: 2px;
606
- }
607
-
608
- .playkit-toggle-option {
609
- flex: 1;
610
- display: flex;
611
- justify-content: center;
612
- align-items: center;
613
- padding: 10px 16px;
614
- border-radius: 2px;
615
- cursor: pointer;
616
- transition: background-color 0.15s ease;
617
- }
618
-
619
- .playkit-toggle-option input {
620
- display: none;
621
- }
622
-
623
- .playkit-toggle-option span {
624
- font-size: 14px;
625
- font-weight: 500;
626
- color: #666666;
627
- transition: color 0.15s ease;
628
- }
629
-
630
- .playkit-toggle-option input:checked + span {
631
- color: #FFFFFF;
632
- }
633
-
634
- .playkit-toggle-option:has(input:checked) {
635
- background: #276EF1;
636
- }
637
-
638
- .playkit-auth-input-group {
639
- margin-bottom: 24px;
640
- }
641
-
642
- .playkit-input-wrapper {
643
- position: relative;
644
- display: flex;
645
- align-items: center;
646
- }
647
-
648
- .playkit-input-icon {
649
- position: absolute;
650
- left: 12px;
651
- color: #999999;
652
- pointer-events: none;
653
- }
654
-
655
- .playkit-input-wrapper input {
656
- width: 100%;
657
- padding: 12px 12px 12px 44px;
658
- border: 1px solid #CCCCCC;
659
- border-radius: 2px;
660
- font-size: 14px;
661
- transition: border-color 0.15s ease, box-shadow 0.15s ease;
662
- box-sizing: border-box;
663
- background: #FFFFFF;
664
- }
665
-
666
- .playkit-input-wrapper input:hover {
667
- border-color: #999999;
668
- }
669
-
670
- .playkit-input-wrapper input:focus {
671
- outline: none;
672
- border-color: #276EF1;
673
- box-shadow: 0 0 0 3px rgba(39, 110, 241, 0.1);
674
- }
675
-
676
- .playkit-code-inputs {
677
- display: flex;
678
- gap: 8px;
679
- justify-content: center;
680
- }
681
-
682
- .playkit-code-input {
683
- width: 48px !important;
684
- height: 56px;
685
- text-align: center;
686
- font-size: 24px;
687
- font-weight: 600;
688
- border: 1px solid #CCCCCC !important;
689
- border-radius: 2px;
690
- padding: 0 !important;
691
- transition: border-color 0.15s ease, box-shadow 0.15s ease;
692
- background: #FFFFFF;
693
- -moz-appearance: textfield;
694
- }
695
-
696
- .playkit-code-input::-webkit-outer-spin-button,
697
- .playkit-code-input::-webkit-inner-spin-button {
698
- -webkit-appearance: none;
699
- margin: 0;
700
- }
701
-
702
- .playkit-code-input:hover {
703
- border-color: #999999 !important;
704
- }
705
-
706
- .playkit-code-input:focus {
707
- outline: none;
708
- border-color: #276EF1 !important;
709
- box-shadow: 0 0 0 3px rgba(39, 110, 241, 0.1);
710
- }
711
-
712
- .playkit-auth-button {
713
- width: 100%;
714
- padding: 12px 16px;
715
- background: #276EF1;
716
- color: #FFFFFF;
717
- border: none;
718
- border-radius: 2px;
719
- font-size: 14px;
720
- font-weight: 500;
721
- cursor: pointer;
722
- transition: background-color 0.15s ease;
723
- }
724
-
725
- .playkit-auth-button:hover:not(:disabled) {
726
- background: #174EB6;
727
- }
728
-
729
- .playkit-auth-button:active:not(:disabled) {
730
- background: #0F3A8A;
731
- }
732
-
733
- .playkit-auth-button:disabled {
734
- background: #CCCCCC;
735
- cursor: not-allowed;
736
- }
737
-
738
- .playkit-auth-error {
739
- margin-top: 16px;
740
- padding: 12px 16px;
741
- background: #FEF0F0;
742
- border: 1px solid #FDD;
743
- border-radius: 2px;
744
- color: #CC3333;
745
- font-size: 13px;
746
- text-align: left;
747
- display: none;
748
- }
749
-
750
- .playkit-auth-error.show {
751
- display: block;
752
- }
753
-
754
- .playkit-loading-overlay {
755
- position: absolute;
756
- top: 0;
757
- left: 0;
758
- right: 0;
759
- bottom: 0;
760
- background: rgba(255, 255, 255, 0.96);
761
- display: flex;
762
- justify-content: center;
763
- align-items: center;
764
- border-radius: 4px;
765
- }
766
-
767
- .playkit-spinner {
768
- width: 40px;
769
- height: 40px;
770
- border: 3px solid #F0F0F0;
771
- border-top: 3px solid #276EF1;
772
- border-radius: 50%;
773
- animation: playkit-spin 0.8s linear infinite;
774
- }
775
-
776
- @keyframes playkit-spin {
777
- 0% { transform: rotate(0deg); }
778
- 100% { transform: rotate(360deg); }
779
- }
780
-
781
- @media (max-width: 480px) {
782
- .playkit-auth-container {
783
- width: 95%;
784
- max-width: none;
785
- border-radius: 2px;
786
- }
787
-
788
- .playkit-auth-panel {
789
- padding: 32px 24px;
790
- }
791
-
792
- .playkit-code-input {
793
- width: 40px !important;
794
- height: 48px;
795
- font-size: 20px;
796
- }
797
-
798
- .playkit-code-inputs {
799
- gap: 6px;
800
- }
801
- }
571
+ style.textContent = `
572
+ .playkit-auth-modal {
573
+ position: fixed;
574
+ top: 0;
575
+ left: 0;
576
+ right: 0;
577
+ bottom: 0;
578
+ z-index: 999999;
579
+ display: flex;
580
+ justify-content: center;
581
+ align-items: center;
582
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
583
+ }
584
+
585
+ .playkit-auth-overlay {
586
+ position: absolute;
587
+ top: 0;
588
+ left: 0;
589
+ right: 0;
590
+ bottom: 0;
591
+ background: rgba(0, 0, 0, 0.48);
592
+ backdrop-filter: blur(8px);
593
+ }
594
+
595
+ .playkit-auth-container {
596
+ position: relative;
597
+ background: #FFFFFF;
598
+ border-radius: 4px;
599
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
600
+ width: 90%;
601
+ max-width: 420px;
602
+ overflow: hidden;
603
+ }
604
+
605
+ .playkit-auth-panel {
606
+ padding: 40px 32px;
607
+ }
608
+
609
+ .playkit-auth-header {
610
+ text-align: center;
611
+ margin-bottom: 32px;
612
+ position: relative;
613
+ }
614
+
615
+ .playkit-auth-header h2 {
616
+ margin: 0 0 8px 0;
617
+ font-size: 28px;
618
+ font-weight: 600;
619
+ color: #000000;
620
+ }
621
+
622
+ .playkit-auth-header p {
623
+ margin: 0;
624
+ font-size: 14px;
625
+ color: #666666;
626
+ line-height: 1.5;
627
+ }
628
+
629
+ .playkit-back-button {
630
+ position: absolute;
631
+ left: 0;
632
+ top: 0;
633
+ background: transparent;
634
+ border: none;
635
+ cursor: pointer;
636
+ padding: 4px;
637
+ border-radius: 2px;
638
+ color: #666666;
639
+ transition: background-color 0.15s ease, color 0.15s ease;
640
+ }
641
+
642
+ .playkit-back-button:hover {
643
+ background: #F6F6F6;
644
+ color: #000000;
645
+ }
646
+
647
+ .playkit-auth-toggle {
648
+ display: flex;
649
+ background: #F6F6F6;
650
+ border-radius: 2px;
651
+ padding: 2px;
652
+ margin-bottom: 24px;
653
+ gap: 2px;
654
+ }
655
+
656
+ .playkit-toggle-option {
657
+ flex: 1;
658
+ display: flex;
659
+ justify-content: center;
660
+ align-items: center;
661
+ padding: 10px 16px;
662
+ border-radius: 2px;
663
+ cursor: pointer;
664
+ transition: background-color 0.15s ease;
665
+ }
666
+
667
+ .playkit-toggle-option input {
668
+ display: none;
669
+ }
670
+
671
+ .playkit-toggle-option span {
672
+ font-size: 14px;
673
+ font-weight: 500;
674
+ color: #666666;
675
+ transition: color 0.15s ease;
676
+ }
677
+
678
+ .playkit-toggle-option input:checked + span {
679
+ color: #FFFFFF;
680
+ }
681
+
682
+ .playkit-toggle-option:has(input:checked) {
683
+ background: #276EF1;
684
+ }
685
+
686
+ .playkit-auth-input-group {
687
+ margin-bottom: 24px;
688
+ }
689
+
690
+ .playkit-input-wrapper {
691
+ position: relative;
692
+ display: flex;
693
+ align-items: center;
694
+ }
695
+
696
+ .playkit-input-icon {
697
+ position: absolute;
698
+ left: 12px;
699
+ color: #999999;
700
+ pointer-events: none;
701
+ }
702
+
703
+ .playkit-input-wrapper input {
704
+ width: 100%;
705
+ padding: 12px 12px 12px 44px;
706
+ border: 1px solid #CCCCCC;
707
+ border-radius: 2px;
708
+ font-size: 14px;
709
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
710
+ box-sizing: border-box;
711
+ background: #FFFFFF;
712
+ }
713
+
714
+ .playkit-input-wrapper input:hover {
715
+ border-color: #999999;
716
+ }
717
+
718
+ .playkit-input-wrapper input:focus {
719
+ outline: none;
720
+ border-color: #276EF1;
721
+ box-shadow: 0 0 0 3px rgba(39, 110, 241, 0.1);
722
+ }
723
+
724
+ .playkit-code-inputs {
725
+ display: flex;
726
+ gap: 8px;
727
+ justify-content: center;
728
+ }
729
+
730
+ .playkit-code-input {
731
+ width: 48px !important;
732
+ height: 56px;
733
+ text-align: center;
734
+ font-size: 24px;
735
+ font-weight: 600;
736
+ border: 1px solid #CCCCCC !important;
737
+ border-radius: 2px;
738
+ padding: 0 !important;
739
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
740
+ background: #FFFFFF;
741
+ -moz-appearance: textfield;
742
+ }
743
+
744
+ .playkit-code-input::-webkit-outer-spin-button,
745
+ .playkit-code-input::-webkit-inner-spin-button {
746
+ -webkit-appearance: none;
747
+ margin: 0;
748
+ }
749
+
750
+ .playkit-code-input:hover {
751
+ border-color: #999999 !important;
752
+ }
753
+
754
+ .playkit-code-input:focus {
755
+ outline: none;
756
+ border-color: #276EF1 !important;
757
+ box-shadow: 0 0 0 3px rgba(39, 110, 241, 0.1);
758
+ }
759
+
760
+ .playkit-auth-button {
761
+ width: 100%;
762
+ padding: 12px 16px;
763
+ background: #276EF1;
764
+ color: #FFFFFF;
765
+ border: none;
766
+ border-radius: 2px;
767
+ font-size: 14px;
768
+ font-weight: 500;
769
+ cursor: pointer;
770
+ transition: background-color 0.15s ease;
771
+ }
772
+
773
+ .playkit-auth-button:hover:not(:disabled) {
774
+ background: #174EB6;
775
+ }
776
+
777
+ .playkit-auth-button:active:not(:disabled) {
778
+ background: #0F3A8A;
779
+ }
780
+
781
+ .playkit-auth-button:disabled {
782
+ background: #CCCCCC;
783
+ cursor: not-allowed;
784
+ }
785
+
786
+ .playkit-auth-error {
787
+ margin-top: 16px;
788
+ padding: 12px 16px;
789
+ background: #FEF0F0;
790
+ border: 1px solid #FDD;
791
+ border-radius: 2px;
792
+ color: #CC3333;
793
+ font-size: 13px;
794
+ text-align: left;
795
+ display: none;
796
+ }
797
+
798
+ .playkit-auth-error.show {
799
+ display: block;
800
+ }
801
+
802
+ .playkit-loading-overlay {
803
+ position: absolute;
804
+ top: 0;
805
+ left: 0;
806
+ right: 0;
807
+ bottom: 0;
808
+ background: rgba(255, 255, 255, 0.96);
809
+ display: flex;
810
+ justify-content: center;
811
+ align-items: center;
812
+ border-radius: 4px;
813
+ }
814
+
815
+ .playkit-spinner {
816
+ width: 40px;
817
+ height: 40px;
818
+ border: 3px solid #F0F0F0;
819
+ border-top: 3px solid #276EF1;
820
+ border-radius: 50%;
821
+ animation: playkit-spin 0.8s linear infinite;
822
+ }
823
+
824
+ @keyframes playkit-spin {
825
+ 0% { transform: rotate(0deg); }
826
+ 100% { transform: rotate(360deg); }
827
+ }
828
+
829
+ @media (max-width: 480px) {
830
+ .playkit-auth-container {
831
+ width: 95%;
832
+ max-width: none;
833
+ border-radius: 2px;
834
+ }
835
+
836
+ .playkit-auth-panel {
837
+ padding: 32px 24px;
838
+ }
839
+
840
+ .playkit-code-input {
841
+ width: 40px !important;
842
+ height: 48px;
843
+ font-size: 20px;
844
+ }
845
+
846
+ .playkit-code-inputs {
847
+ gap: 6px;
848
+ }
849
+ }
802
850
  `;
803
851
  document.head.appendChild(style);
804
852
  }
@@ -819,14 +867,14 @@ class AuthFlowManager extends EventEmitter {
819
867
  : this.t('phonePlaceholder');
820
868
  // Update icon
821
869
  if (isEmail) {
822
- identifierIcon.innerHTML = `
823
- <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
824
- <polyline points="22,6 12,13 2,6"></polyline>
870
+ identifierIcon.innerHTML = `
871
+ <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
872
+ <polyline points="22,6 12,13 2,6"></polyline>
825
873
  `;
826
874
  }
827
875
  else {
828
- identifierIcon.innerHTML = `
829
- <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>
876
+ identifierIcon.innerHTML = `
877
+ <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>
830
878
  `;
831
879
  }
832
880
  };
@@ -1879,220 +1927,220 @@ class RechargeManager extends EventEmitter {
1879
1927
  return;
1880
1928
  }
1881
1929
  this.styleElement = document.createElement('style');
1882
- this.styleElement.textContent = `
1883
- .playkit-recharge-overlay {
1884
- position: fixed;
1885
- top: 0;
1886
- left: 0;
1887
- right: 0;
1888
- bottom: 0;
1889
- background-color: rgba(0, 0, 0, 0.5);
1890
- backdrop-filter: blur(4px);
1891
- display: flex;
1892
- justify-content: center;
1893
- align-items: center;
1894
- z-index: 999999;
1895
- animation: playkit-recharge-fadeIn 0.2s ease-out;
1896
- }
1897
-
1898
- @keyframes playkit-recharge-fadeIn {
1899
- from {
1900
- opacity: 0;
1901
- }
1902
- to {
1903
- opacity: 1;
1904
- }
1905
- }
1906
-
1907
- .playkit-recharge-modal {
1908
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1909
- border-radius: 16px;
1910
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
1911
- padding: 32px;
1912
- max-width: 400px;
1913
- width: 90%;
1914
- position: relative;
1915
- animation: playkit-recharge-slideUp 0.3s ease-out;
1916
- }
1917
-
1918
- @keyframes playkit-recharge-slideUp {
1919
- from {
1920
- transform: translateY(20px);
1921
- opacity: 0;
1922
- }
1923
- to {
1924
- transform: translateY(0);
1925
- opacity: 1;
1926
- }
1927
- }
1928
-
1929
- .playkit-recharge-title {
1930
- font-size: 24px;
1931
- font-weight: bold;
1932
- color: #ffffff;
1933
- margin: 0 0 16px 0;
1934
- text-align: center;
1935
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1936
- }
1937
-
1938
- .playkit-recharge-message {
1939
- font-size: 16px;
1940
- color: rgba(255, 255, 255, 0.9);
1941
- margin: 0 0 24px 0;
1942
- text-align: center;
1943
- line-height: 1.5;
1944
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1945
- }
1946
-
1947
- .playkit-recharge-balance {
1948
- background: rgba(255, 255, 255, 0.15);
1949
- border-radius: 12px;
1950
- padding: 16px;
1951
- margin: 0 0 24px 0;
1952
- text-align: center;
1953
- backdrop-filter: blur(10px);
1954
- }
1955
-
1956
- .playkit-recharge-balance-label {
1957
- font-size: 14px;
1958
- color: rgba(255, 255, 255, 0.8);
1959
- margin: 0 0 8px 0;
1960
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1961
- }
1962
-
1963
- .playkit-recharge-balance-value {
1964
- font-size: 32px;
1965
- font-weight: bold;
1966
- color: #ffffff;
1967
- margin: 0;
1968
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1969
- }
1970
-
1971
- .playkit-recharge-balance-unit {
1972
- font-size: 16px;
1973
- color: rgba(255, 255, 255, 0.8);
1974
- margin-left: 8px;
1975
- }
1976
-
1977
- .playkit-recharge-buttons {
1978
- display: flex;
1979
- gap: 12px;
1980
- justify-content: center;
1981
- }
1982
-
1983
- .playkit-recharge-button {
1984
- flex: 1;
1985
- padding: 12px 24px;
1986
- border: none;
1987
- border-radius: 8px;
1988
- font-size: 16px;
1989
- font-weight: 600;
1990
- cursor: pointer;
1991
- transition: all 0.2s ease;
1992
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1993
- }
1994
-
1995
- .playkit-recharge-button-primary {
1996
- background: #ffffff;
1997
- color: #667eea;
1998
- }
1999
-
2000
- .playkit-recharge-button-primary:hover {
2001
- transform: translateY(-2px);
2002
- box-shadow: 0 8px 16px rgba(255, 255, 255, 0.2);
2003
- }
2004
-
2005
- .playkit-recharge-button-primary:active {
2006
- transform: translateY(0);
2007
- }
2008
-
2009
- .playkit-recharge-button-secondary {
2010
- background: rgba(255, 255, 255, 0.15);
2011
- color: #ffffff;
2012
- border: 1px solid rgba(255, 255, 255, 0.3);
2013
- }
2014
-
2015
- .playkit-recharge-button-secondary:hover {
2016
- background: rgba(255, 255, 255, 0.25);
2017
- }
2018
-
2019
- .playkit-recharge-button-secondary:active {
2020
- background: rgba(255, 255, 255, 0.15);
2021
- }
2022
-
2023
- @media (max-width: 480px) {
2024
- .playkit-recharge-modal {
2025
- padding: 24px;
2026
- }
2027
-
2028
- .playkit-recharge-title {
2029
- font-size: 20px;
2030
- }
2031
-
2032
- .playkit-recharge-message {
2033
- font-size: 14px;
2034
- }
2035
-
2036
- .playkit-recharge-balance-value {
2037
- font-size: 28px;
2038
- }
2039
-
2040
- .playkit-recharge-buttons {
2041
- flex-direction: column;
2042
- }
2043
- }
2044
- `;
2045
- document.head.appendChild(this.styleElement);
2046
- }
2047
- /**
2048
- * Create the modal DOM structure
2049
- */
2050
- createModal(options) {
2051
- this.modalContainer = document.createElement('div');
2052
- this.modalContainer.className = 'playkit-recharge-overlay';
2053
- const modal = document.createElement('div');
2054
- modal.className = 'playkit-recharge-modal';
2055
- // Title
2056
- const title = document.createElement('h2');
2057
- title.className = 'playkit-recharge-title';
2058
- title.textContent = this.t('title');
2059
- modal.appendChild(title);
2060
- // Message
2061
- const message = document.createElement('p');
2062
- message.className = 'playkit-recharge-message';
2063
- message.textContent = options.message || this.t('message');
2064
- modal.appendChild(message);
2065
- // Balance display (if provided)
2066
- if (options.currentBalance !== undefined) {
2067
- const balanceContainer = document.createElement('div');
2068
- balanceContainer.className = 'playkit-recharge-balance';
2069
- const balanceLabel = document.createElement('div');
2070
- balanceLabel.className = 'playkit-recharge-balance-label';
2071
- balanceLabel.textContent = this.t('currentBalance');
2072
- balanceContainer.appendChild(balanceLabel);
2073
- const balanceValue = document.createElement('div');
2074
- balanceValue.className = 'playkit-recharge-balance-value';
2075
- balanceValue.innerHTML = `${options.currentBalance}<span class="playkit-recharge-balance-unit">${this.t('credits')}</span>`;
2076
- balanceContainer.appendChild(balanceValue);
2077
- modal.appendChild(balanceContainer);
2078
- }
2079
- // Buttons
2080
- const buttonsContainer = document.createElement('div');
2081
- buttonsContainer.className = 'playkit-recharge-buttons';
2082
- const rechargeButton = document.createElement('button');
2083
- rechargeButton.className = 'playkit-recharge-button playkit-recharge-button-primary';
2084
- rechargeButton.textContent = this.t('rechargeButton');
2085
- rechargeButton.addEventListener('click', () => {
2086
- this.openRechargeWindow();
2087
- this.destroy();
2088
- this.emit('recharge_modal_dismissed');
2089
- });
2090
- buttonsContainer.appendChild(rechargeButton);
2091
- const cancelButton = document.createElement('button');
2092
- cancelButton.className = 'playkit-recharge-button playkit-recharge-button-secondary playkit-recharge-cancel';
2093
- cancelButton.textContent = this.t('cancelButton');
2094
- buttonsContainer.appendChild(cancelButton);
2095
- modal.appendChild(buttonsContainer);
1930
+ this.styleElement.textContent = `
1931
+ .playkit-recharge-overlay {
1932
+ position: fixed;
1933
+ top: 0;
1934
+ left: 0;
1935
+ right: 0;
1936
+ bottom: 0;
1937
+ background-color: rgba(0, 0, 0, 0.5);
1938
+ backdrop-filter: blur(4px);
1939
+ display: flex;
1940
+ justify-content: center;
1941
+ align-items: center;
1942
+ z-index: 999999;
1943
+ animation: playkit-recharge-fadeIn 0.2s ease-out;
1944
+ }
1945
+
1946
+ @keyframes playkit-recharge-fadeIn {
1947
+ from {
1948
+ opacity: 0;
1949
+ }
1950
+ to {
1951
+ opacity: 1;
1952
+ }
1953
+ }
1954
+
1955
+ .playkit-recharge-modal {
1956
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1957
+ border-radius: 16px;
1958
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
1959
+ padding: 32px;
1960
+ max-width: 400px;
1961
+ width: 90%;
1962
+ position: relative;
1963
+ animation: playkit-recharge-slideUp 0.3s ease-out;
1964
+ }
1965
+
1966
+ @keyframes playkit-recharge-slideUp {
1967
+ from {
1968
+ transform: translateY(20px);
1969
+ opacity: 0;
1970
+ }
1971
+ to {
1972
+ transform: translateY(0);
1973
+ opacity: 1;
1974
+ }
1975
+ }
1976
+
1977
+ .playkit-recharge-title {
1978
+ font-size: 24px;
1979
+ font-weight: bold;
1980
+ color: #ffffff;
1981
+ margin: 0 0 16px 0;
1982
+ text-align: center;
1983
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1984
+ }
1985
+
1986
+ .playkit-recharge-message {
1987
+ font-size: 16px;
1988
+ color: rgba(255, 255, 255, 0.9);
1989
+ margin: 0 0 24px 0;
1990
+ text-align: center;
1991
+ line-height: 1.5;
1992
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
1993
+ }
1994
+
1995
+ .playkit-recharge-balance {
1996
+ background: rgba(255, 255, 255, 0.15);
1997
+ border-radius: 12px;
1998
+ padding: 16px;
1999
+ margin: 0 0 24px 0;
2000
+ text-align: center;
2001
+ backdrop-filter: blur(10px);
2002
+ }
2003
+
2004
+ .playkit-recharge-balance-label {
2005
+ font-size: 14px;
2006
+ color: rgba(255, 255, 255, 0.8);
2007
+ margin: 0 0 8px 0;
2008
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
2009
+ }
2010
+
2011
+ .playkit-recharge-balance-value {
2012
+ font-size: 32px;
2013
+ font-weight: bold;
2014
+ color: #ffffff;
2015
+ margin: 0;
2016
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
2017
+ }
2018
+
2019
+ .playkit-recharge-balance-unit {
2020
+ font-size: 16px;
2021
+ color: rgba(255, 255, 255, 0.8);
2022
+ margin-left: 8px;
2023
+ }
2024
+
2025
+ .playkit-recharge-buttons {
2026
+ display: flex;
2027
+ gap: 12px;
2028
+ justify-content: center;
2029
+ }
2030
+
2031
+ .playkit-recharge-button {
2032
+ flex: 1;
2033
+ padding: 12px 24px;
2034
+ border: none;
2035
+ border-radius: 8px;
2036
+ font-size: 16px;
2037
+ font-weight: 600;
2038
+ cursor: pointer;
2039
+ transition: all 0.2s ease;
2040
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
2041
+ }
2042
+
2043
+ .playkit-recharge-button-primary {
2044
+ background: #ffffff;
2045
+ color: #667eea;
2046
+ }
2047
+
2048
+ .playkit-recharge-button-primary:hover {
2049
+ transform: translateY(-2px);
2050
+ box-shadow: 0 8px 16px rgba(255, 255, 255, 0.2);
2051
+ }
2052
+
2053
+ .playkit-recharge-button-primary:active {
2054
+ transform: translateY(0);
2055
+ }
2056
+
2057
+ .playkit-recharge-button-secondary {
2058
+ background: rgba(255, 255, 255, 0.15);
2059
+ color: #ffffff;
2060
+ border: 1px solid rgba(255, 255, 255, 0.3);
2061
+ }
2062
+
2063
+ .playkit-recharge-button-secondary:hover {
2064
+ background: rgba(255, 255, 255, 0.25);
2065
+ }
2066
+
2067
+ .playkit-recharge-button-secondary:active {
2068
+ background: rgba(255, 255, 255, 0.15);
2069
+ }
2070
+
2071
+ @media (max-width: 480px) {
2072
+ .playkit-recharge-modal {
2073
+ padding: 24px;
2074
+ }
2075
+
2076
+ .playkit-recharge-title {
2077
+ font-size: 20px;
2078
+ }
2079
+
2080
+ .playkit-recharge-message {
2081
+ font-size: 14px;
2082
+ }
2083
+
2084
+ .playkit-recharge-balance-value {
2085
+ font-size: 28px;
2086
+ }
2087
+
2088
+ .playkit-recharge-buttons {
2089
+ flex-direction: column;
2090
+ }
2091
+ }
2092
+ `;
2093
+ document.head.appendChild(this.styleElement);
2094
+ }
2095
+ /**
2096
+ * Create the modal DOM structure
2097
+ */
2098
+ createModal(options) {
2099
+ this.modalContainer = document.createElement('div');
2100
+ this.modalContainer.className = 'playkit-recharge-overlay';
2101
+ const modal = document.createElement('div');
2102
+ modal.className = 'playkit-recharge-modal';
2103
+ // Title
2104
+ const title = document.createElement('h2');
2105
+ title.className = 'playkit-recharge-title';
2106
+ title.textContent = this.t('title');
2107
+ modal.appendChild(title);
2108
+ // Message
2109
+ const message = document.createElement('p');
2110
+ message.className = 'playkit-recharge-message';
2111
+ message.textContent = options.message || this.t('message');
2112
+ modal.appendChild(message);
2113
+ // Balance display (if provided)
2114
+ if (options.currentBalance !== undefined) {
2115
+ const balanceContainer = document.createElement('div');
2116
+ balanceContainer.className = 'playkit-recharge-balance';
2117
+ const balanceLabel = document.createElement('div');
2118
+ balanceLabel.className = 'playkit-recharge-balance-label';
2119
+ balanceLabel.textContent = this.t('currentBalance');
2120
+ balanceContainer.appendChild(balanceLabel);
2121
+ const balanceValue = document.createElement('div');
2122
+ balanceValue.className = 'playkit-recharge-balance-value';
2123
+ balanceValue.innerHTML = `${options.currentBalance}<span class="playkit-recharge-balance-unit">${this.t('credits')}</span>`;
2124
+ balanceContainer.appendChild(balanceValue);
2125
+ modal.appendChild(balanceContainer);
2126
+ }
2127
+ // Buttons
2128
+ const buttonsContainer = document.createElement('div');
2129
+ buttonsContainer.className = 'playkit-recharge-buttons';
2130
+ const rechargeButton = document.createElement('button');
2131
+ rechargeButton.className = 'playkit-recharge-button playkit-recharge-button-primary';
2132
+ rechargeButton.textContent = this.t('rechargeButton');
2133
+ rechargeButton.addEventListener('click', () => {
2134
+ this.openRechargeWindow();
2135
+ this.destroy();
2136
+ this.emit('recharge_modal_dismissed');
2137
+ });
2138
+ buttonsContainer.appendChild(rechargeButton);
2139
+ const cancelButton = document.createElement('button');
2140
+ cancelButton.className = 'playkit-recharge-button playkit-recharge-button-secondary playkit-recharge-cancel';
2141
+ cancelButton.textContent = this.t('cancelButton');
2142
+ buttonsContainer.appendChild(cancelButton);
2143
+ modal.appendChild(buttonsContainer);
2096
2144
  this.modalContainer.appendChild(modal);
2097
2145
  document.body.appendChild(this.modalContainer);
2098
2146
  }
@@ -2122,6 +2170,7 @@ class RechargeManager extends EventEmitter {
2122
2170
  */
2123
2171
  const DEFAULT_BASE_URL$2 = 'https://playkit.agentlandlab.com';
2124
2172
  const PLAYER_INFO_ENDPOINT = '/api/external/player-info';
2173
+ const SET_NICKNAME_ENDPOINT = '/api/external/set-game-player-nickname';
2125
2174
  class PlayerClient extends EventEmitter {
2126
2175
  constructor(authManager, config, rechargeConfig = {}) {
2127
2176
  var _a, _b, _c;
@@ -2142,6 +2191,7 @@ class PlayerClient extends EventEmitter {
2142
2191
  * Get player information
2143
2192
  */
2144
2193
  async getPlayerInfo() {
2194
+ var _a;
2145
2195
  const token = this.authManager.getToken();
2146
2196
  if (!token) {
2147
2197
  throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
@@ -2179,6 +2229,7 @@ class PlayerClient extends EventEmitter {
2179
2229
  this.playerInfo = {
2180
2230
  userId: data.userId,
2181
2231
  credits: data.credits,
2232
+ nickname: (_a = data.nickname) !== null && _a !== void 0 ? _a : null,
2182
2233
  };
2183
2234
  this.emit('player_info_updated', this.playerInfo);
2184
2235
  return this.playerInfo;
@@ -2200,6 +2251,70 @@ class PlayerClient extends EventEmitter {
2200
2251
  async refreshPlayerInfo() {
2201
2252
  return this.getPlayerInfo();
2202
2253
  }
2254
+ /**
2255
+ * Get player's nickname
2256
+ * Returns the cached nickname from playerInfo, or null if not set
2257
+ */
2258
+ getNickname() {
2259
+ var _a, _b;
2260
+ return (_b = (_a = this.playerInfo) === null || _a === void 0 ? void 0 : _a.nickname) !== null && _b !== void 0 ? _b : null;
2261
+ }
2262
+ /**
2263
+ * Set player's nickname for the current game
2264
+ * Requires a game-specific player token (not a global token or developer token)
2265
+ * @param nickname - Nickname to set (1-16 characters, letters/numbers/Chinese/underscores/spaces only)
2266
+ * @returns The set nickname response
2267
+ * @throws PlayKitError if nickname is invalid, moderation fails, or token type is wrong
2268
+ */
2269
+ async setNickname(nickname) {
2270
+ const token = this.authManager.getToken();
2271
+ if (!token) {
2272
+ throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
2273
+ }
2274
+ // Developer tokens cannot set nicknames
2275
+ const authState = this.authManager.getAuthState();
2276
+ if (authState.tokenType === 'developer') {
2277
+ throw new PlayKitError('Developer tokens cannot set nicknames. Use a player token.', 'INVALID_TOKEN_TYPE');
2278
+ }
2279
+ // Validate nickname locally first
2280
+ if (!nickname || typeof nickname !== 'string') {
2281
+ throw new PlayKitError('Nickname is required', 'NICKNAME_REQUIRED');
2282
+ }
2283
+ const trimmed = nickname.trim();
2284
+ if (trimmed.length === 0) {
2285
+ throw new PlayKitError('Nickname cannot be empty', 'INVALID_NICKNAME');
2286
+ }
2287
+ if (trimmed.length > 16) {
2288
+ throw new PlayKitError('Nickname must be 16 characters or less', 'INVALID_NICKNAME');
2289
+ }
2290
+ try {
2291
+ const response = await fetch(`${this.baseURL}${SET_NICKNAME_ENDPOINT}`, {
2292
+ method: 'POST',
2293
+ headers: {
2294
+ Authorization: `Bearer ${token}`,
2295
+ 'Content-Type': 'application/json',
2296
+ },
2297
+ body: JSON.stringify({ nickname: trimmed }),
2298
+ });
2299
+ if (!response.ok) {
2300
+ const error = await response.json().catch(() => ({ error: { message: 'Failed to set nickname' } }));
2301
+ const errorObj = error.error || error;
2302
+ throw new PlayKitError(errorObj.message || 'Failed to set nickname', errorObj.code, response.status);
2303
+ }
2304
+ const data = await response.json();
2305
+ // Update cached player info with new nickname
2306
+ if (this.playerInfo) {
2307
+ this.playerInfo.nickname = data.nickname;
2308
+ this.emit('player_info_updated', this.playerInfo);
2309
+ }
2310
+ this.emit('nickname_changed', data.nickname);
2311
+ return data;
2312
+ }
2313
+ catch (error) {
2314
+ this.emit('error', error);
2315
+ throw error;
2316
+ }
2317
+ }
2203
2318
  /**
2204
2319
  * Initialize recharge manager
2205
2320
  */
@@ -2460,30 +2575,199 @@ class ChatProvider {
2460
2575
  throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_STREAM_ERROR');
2461
2576
  }
2462
2577
  }
2578
+ /**
2579
+ * Make a chat completion request with tools (non-streaming)
2580
+ */
2581
+ async chatCompletionWithTools(chatConfig) {
2582
+ var _a, _b;
2583
+ const token = this.authManager.getToken();
2584
+ if (!token) {
2585
+ throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
2586
+ }
2587
+ const model = chatConfig.model || this.config.defaultChatModel || 'gpt-4o-mini';
2588
+ const endpoint = `/ai/${this.config.gameId}/v1/chat`;
2589
+ const requestBody = {
2590
+ model,
2591
+ messages: chatConfig.messages,
2592
+ temperature: (_a = chatConfig.temperature) !== null && _a !== void 0 ? _a : 0.7,
2593
+ stream: false,
2594
+ max_tokens: chatConfig.maxTokens || null,
2595
+ seed: chatConfig.seed || null,
2596
+ stop: chatConfig.stop || null,
2597
+ top_p: chatConfig.topP || null,
2598
+ };
2599
+ // Add tools if provided
2600
+ if ((_b = chatConfig.tools) === null || _b === void 0 ? void 0 : _b.length) {
2601
+ requestBody.tools = chatConfig.tools;
2602
+ }
2603
+ if (chatConfig.tool_choice) {
2604
+ requestBody.tool_choice = chatConfig.tool_choice;
2605
+ }
2606
+ try {
2607
+ const response = await fetch(`${this.baseURL}${endpoint}`, {
2608
+ method: 'POST',
2609
+ headers: {
2610
+ Authorization: `Bearer ${token}`,
2611
+ 'Content-Type': 'application/json',
2612
+ },
2613
+ body: JSON.stringify(requestBody),
2614
+ });
2615
+ if (!response.ok) {
2616
+ const error = await response.json().catch(() => ({ message: 'Chat request failed' }));
2617
+ const playKitError = new PlayKitError(error.message || 'Chat request failed', error.code, response.status);
2618
+ if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
2619
+ if (this.playerClient) {
2620
+ await this.playerClient.handleInsufficientCredits(playKitError);
2621
+ }
2622
+ }
2623
+ throw playKitError;
2624
+ }
2625
+ const result = await response.json();
2626
+ if (this.playerClient) {
2627
+ this.playerClient.checkBalanceAfterApiCall().catch(() => { });
2628
+ }
2629
+ return result;
2630
+ }
2631
+ catch (error) {
2632
+ if (error instanceof PlayKitError) {
2633
+ throw error;
2634
+ }
2635
+ throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_ERROR');
2636
+ }
2637
+ }
2638
+ /**
2639
+ * Make a streaming chat completion request with tools
2640
+ */
2641
+ async chatCompletionWithToolsStream(chatConfig) {
2642
+ var _a, _b;
2643
+ const token = this.authManager.getToken();
2644
+ if (!token) {
2645
+ throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
2646
+ }
2647
+ const model = chatConfig.model || this.config.defaultChatModel || 'gpt-4o-mini';
2648
+ const endpoint = `/ai/${this.config.gameId}/v1/chat`;
2649
+ const requestBody = {
2650
+ model,
2651
+ messages: chatConfig.messages,
2652
+ temperature: (_a = chatConfig.temperature) !== null && _a !== void 0 ? _a : 0.7,
2653
+ stream: true,
2654
+ max_tokens: chatConfig.maxTokens || null,
2655
+ seed: chatConfig.seed || null,
2656
+ stop: chatConfig.stop || null,
2657
+ top_p: chatConfig.topP || null,
2658
+ };
2659
+ // Add tools if provided
2660
+ if ((_b = chatConfig.tools) === null || _b === void 0 ? void 0 : _b.length) {
2661
+ requestBody.tools = chatConfig.tools;
2662
+ }
2663
+ if (chatConfig.tool_choice) {
2664
+ requestBody.tool_choice = chatConfig.tool_choice;
2665
+ }
2666
+ try {
2667
+ const response = await fetch(`${this.baseURL}${endpoint}`, {
2668
+ method: 'POST',
2669
+ headers: {
2670
+ Authorization: `Bearer ${token}`,
2671
+ 'Content-Type': 'application/json',
2672
+ },
2673
+ body: JSON.stringify(requestBody),
2674
+ });
2675
+ if (!response.ok) {
2676
+ const error = await response.json().catch(() => ({ message: 'Chat stream request failed' }));
2677
+ const playKitError = new PlayKitError(error.message || 'Chat stream request failed', error.code, response.status);
2678
+ if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
2679
+ if (this.playerClient) {
2680
+ await this.playerClient.handleInsufficientCredits(playKitError);
2681
+ }
2682
+ }
2683
+ throw playKitError;
2684
+ }
2685
+ if (!response.body) {
2686
+ throw new PlayKitError('Response body is null', 'NO_RESPONSE_BODY');
2687
+ }
2688
+ if (this.playerClient) {
2689
+ this.playerClient.checkBalanceAfterApiCall().catch(() => { });
2690
+ }
2691
+ return response.body.getReader();
2692
+ }
2693
+ catch (error) {
2694
+ if (error instanceof PlayKitError) {
2695
+ throw error;
2696
+ }
2697
+ throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'CHAT_STREAM_ERROR');
2698
+ }
2699
+ }
2463
2700
  /**
2464
2701
  * Generate structured output using JSON schema
2702
+ * Uses the /chat endpoint with response_format for structured output
2465
2703
  */
2466
- async generateStructured(schemaName, prompt, model, temperature) {
2704
+ async generateStructured(schemaName, prompt, model, temperature, schema, schemaDescription) {
2467
2705
  var _a;
2706
+ const token = this.authManager.getToken();
2707
+ if (!token) {
2708
+ throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
2709
+ }
2710
+ const modelToUse = model || this.config.defaultChatModel || 'gpt-4o-mini';
2711
+ const endpoint = `/ai/${this.config.gameId}/v1/chat`;
2468
2712
  const messages = [{ role: 'user', content: prompt }];
2469
- const chatConfig = {
2713
+ const requestBody = {
2714
+ model: modelToUse,
2470
2715
  messages,
2471
- model: model || this.config.defaultChatModel,
2472
2716
  temperature: temperature !== null && temperature !== void 0 ? temperature : 0.7,
2717
+ stream: false,
2473
2718
  };
2474
- // Add schema information to the request
2475
- // (Implementation depends on how the API handles structured output)
2476
- const response = await this.chatCompletion(chatConfig);
2477
- // Parse the response content as JSON
2478
- const content = (_a = response.choices[0]) === null || _a === void 0 ? void 0 : _a.message.content;
2479
- if (!content) {
2480
- throw new PlayKitError('No content in response', 'NO_CONTENT');
2719
+ // Add response_format with json_schema if schema is provided
2720
+ if (schema) {
2721
+ requestBody.response_format = {
2722
+ type: 'json_schema',
2723
+ json_schema: {
2724
+ name: schemaName,
2725
+ description: schemaDescription || '',
2726
+ schema: schema,
2727
+ strict: true,
2728
+ },
2729
+ };
2481
2730
  }
2482
2731
  try {
2483
- return JSON.parse(content);
2732
+ const response = await fetch(`${this.baseURL}${endpoint}`, {
2733
+ method: 'POST',
2734
+ headers: {
2735
+ Authorization: `Bearer ${token}`,
2736
+ 'Content-Type': 'application/json',
2737
+ },
2738
+ body: JSON.stringify(requestBody),
2739
+ });
2740
+ if (!response.ok) {
2741
+ const error = await response.json().catch(() => ({ message: 'Structured generation failed' }));
2742
+ const playKitError = new PlayKitError(error.message || 'Structured generation failed', error.code, response.status);
2743
+ if (error.code === 'INSUFFICIENT_CREDITS' || response.status === 402) {
2744
+ if (this.playerClient) {
2745
+ await this.playerClient.handleInsufficientCredits(playKitError);
2746
+ }
2747
+ }
2748
+ throw playKitError;
2749
+ }
2750
+ const result = await response.json();
2751
+ if (this.playerClient) {
2752
+ this.playerClient.checkBalanceAfterApiCall().catch(() => { });
2753
+ }
2754
+ // Parse the response content as JSON
2755
+ const content = (_a = result.choices[0]) === null || _a === void 0 ? void 0 : _a.message.content;
2756
+ if (!content) {
2757
+ throw new PlayKitError('No content in response', 'NO_CONTENT');
2758
+ }
2759
+ try {
2760
+ return JSON.parse(content);
2761
+ }
2762
+ catch (parseError) {
2763
+ throw new PlayKitError('Failed to parse structured output', 'PARSE_ERROR');
2764
+ }
2484
2765
  }
2485
2766
  catch (error) {
2486
- throw new PlayKitError('Failed to parse structured output', 'PARSE_ERROR');
2767
+ if (error instanceof PlayKitError) {
2768
+ throw error;
2769
+ }
2770
+ throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'STRUCTURED_GENERATION_ERROR');
2487
2771
  }
2488
2772
  }
2489
2773
  }
@@ -2839,6 +3123,56 @@ class ChatClient {
2839
3123
  onComplete,
2840
3124
  });
2841
3125
  }
3126
+ /**
3127
+ * Generate text with tool calling support (non-streaming)
3128
+ */
3129
+ async textGenerationWithTools(config) {
3130
+ const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
3131
+ const response = await this.provider.chatCompletionWithTools(chatConfig);
3132
+ const choice = response.choices[0];
3133
+ if (!choice) {
3134
+ throw new Error('No choices in response');
3135
+ }
3136
+ return {
3137
+ content: choice.message.content || '',
3138
+ model: response.model,
3139
+ finishReason: choice.finish_reason,
3140
+ usage: response.usage
3141
+ ? {
3142
+ promptTokens: response.usage.prompt_tokens,
3143
+ completionTokens: response.usage.completion_tokens,
3144
+ totalTokens: response.usage.total_tokens,
3145
+ }
3146
+ : undefined,
3147
+ id: response.id,
3148
+ created: response.created,
3149
+ tool_calls: choice.message.tool_calls,
3150
+ };
3151
+ }
3152
+ /**
3153
+ * Generate text with tool calling support (streaming)
3154
+ * Text streams first, complete result with tool_calls returned in onComplete
3155
+ */
3156
+ async textGenerationWithToolsStream(config) {
3157
+ const chatConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model });
3158
+ const reader = await this.provider.chatCompletionWithToolsStream(chatConfig);
3159
+ let fullContent = '';
3160
+ let toolCalls = [];
3161
+ await StreamParser.streamWithCallbacks(reader, (chunk) => {
3162
+ fullContent += chunk;
3163
+ config.onChunk(chunk);
3164
+ }, () => {
3165
+ // On complete, provide full result
3166
+ if (config.onComplete) {
3167
+ config.onComplete({
3168
+ content: fullContent,
3169
+ model: chatConfig.model || this.model,
3170
+ finishReason: toolCalls.length > 0 ? 'tool_calls' : 'stop',
3171
+ tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
3172
+ });
3173
+ }
3174
+ }, config.onError);
3175
+ }
2842
3176
  }
2843
3177
 
2844
3178
  /**
@@ -2988,8 +3322,10 @@ class NPCClient extends EventEmitter {
2988
3322
  }
2989
3323
  /**
2990
3324
  * Talk with structured output
3325
+ * @deprecated Use talkWithActions instead for NPC decision-making with actions
2991
3326
  */
2992
3327
  async talkStructured(message, schemaName) {
3328
+ console.warn('[NPCClient] talkStructured is deprecated. Use talkWithActions instead for NPC decision-making with actions.');
2993
3329
  // Add user message to history
2994
3330
  const userMessage = { role: 'user', content: message };
2995
3331
  this.history.push(userMessage);
@@ -3009,6 +3345,153 @@ class NPCClient extends EventEmitter {
3009
3345
  this.trimHistory();
3010
3346
  return result;
3011
3347
  }
3348
+ /**
3349
+ * Talk to the NPC with available actions (non-streaming)
3350
+ * @param message The message to send
3351
+ * @param actions List of actions the NPC can perform
3352
+ * @returns Response containing text and any action calls
3353
+ */
3354
+ async talkWithActions(message, actions) {
3355
+ // Add user message to history
3356
+ const userMessage = { role: 'user', content: message };
3357
+ this.history.push(userMessage);
3358
+ // Convert NpcActions to ChatTools
3359
+ const tools = actions
3360
+ .filter(a => a && a.enabled !== false)
3361
+ .map(a => npcActionToTool(a));
3362
+ // Build messages array with system prompt
3363
+ const messages = [
3364
+ { role: 'system', content: this.systemPrompt },
3365
+ ...this.history,
3366
+ ];
3367
+ // Generate response with tools
3368
+ const result = await this.chatClient.textGenerationWithTools({
3369
+ messages,
3370
+ temperature: this.temperature,
3371
+ tools,
3372
+ tool_choice: 'auto',
3373
+ });
3374
+ // Build response
3375
+ const response = {
3376
+ text: result.content || '',
3377
+ actionCalls: [],
3378
+ hasActions: false,
3379
+ };
3380
+ // Extract tool calls if any
3381
+ if (result.tool_calls) {
3382
+ response.actionCalls = result.tool_calls.map(tc => ({
3383
+ id: tc.id,
3384
+ actionName: tc.function.name,
3385
+ arguments: this.parseToolArguments(tc.function.arguments),
3386
+ }));
3387
+ response.hasActions = response.actionCalls.length > 0;
3388
+ }
3389
+ // Add assistant response to history
3390
+ const assistantMessage = {
3391
+ role: 'assistant',
3392
+ content: response.text,
3393
+ tool_calls: result.tool_calls,
3394
+ };
3395
+ this.history.push(assistantMessage);
3396
+ this.trimHistory();
3397
+ this.emit('response', response.text);
3398
+ if (response.hasActions) {
3399
+ this.emit('actions', response.actionCalls);
3400
+ }
3401
+ return response;
3402
+ }
3403
+ /**
3404
+ * Talk to the NPC with actions (streaming)
3405
+ * Text streams first, action calls are returned in onComplete
3406
+ */
3407
+ async talkWithActionsStream(message, actions, onChunk, onComplete) {
3408
+ // Add user message to history
3409
+ const userMessage = { role: 'user', content: message };
3410
+ this.history.push(userMessage);
3411
+ // Convert NpcActions to ChatTools
3412
+ const tools = actions
3413
+ .filter(a => a && a.enabled !== false)
3414
+ .map(a => npcActionToTool(a));
3415
+ // Build messages array with system prompt
3416
+ const messages = [
3417
+ { role: 'system', content: this.systemPrompt },
3418
+ ...this.history,
3419
+ ];
3420
+ // Generate response with tools (streaming)
3421
+ await this.chatClient.textGenerationWithToolsStream({
3422
+ messages,
3423
+ temperature: this.temperature,
3424
+ tools,
3425
+ tool_choice: 'auto',
3426
+ onChunk,
3427
+ onComplete: (result) => {
3428
+ // Build response
3429
+ const response = {
3430
+ text: result.content || '',
3431
+ actionCalls: [],
3432
+ hasActions: false,
3433
+ };
3434
+ // Extract tool calls if any
3435
+ if (result.tool_calls) {
3436
+ response.actionCalls = result.tool_calls.map(tc => ({
3437
+ id: tc.id,
3438
+ actionName: tc.function.name,
3439
+ arguments: this.parseToolArguments(tc.function.arguments),
3440
+ }));
3441
+ response.hasActions = response.actionCalls.length > 0;
3442
+ }
3443
+ // Add assistant response to history
3444
+ const assistantMessage = {
3445
+ role: 'assistant',
3446
+ content: response.text,
3447
+ tool_calls: result.tool_calls,
3448
+ };
3449
+ this.history.push(assistantMessage);
3450
+ this.trimHistory();
3451
+ this.emit('response', response.text);
3452
+ if (response.hasActions) {
3453
+ this.emit('actions', response.actionCalls);
3454
+ }
3455
+ if (onComplete) {
3456
+ onComplete(response);
3457
+ }
3458
+ },
3459
+ });
3460
+ }
3461
+ /**
3462
+ * Report action results back to the conversation
3463
+ * Call this after executing actions to let the NPC know the results
3464
+ */
3465
+ reportActionResults(results) {
3466
+ for (const [callId, result] of Object.entries(results)) {
3467
+ this.history.push({
3468
+ role: 'tool',
3469
+ tool_call_id: callId,
3470
+ content: result,
3471
+ });
3472
+ }
3473
+ }
3474
+ /**
3475
+ * Report a single action result
3476
+ */
3477
+ reportActionResult(callId, result) {
3478
+ this.history.push({
3479
+ role: 'tool',
3480
+ tool_call_id: callId,
3481
+ content: result,
3482
+ });
3483
+ }
3484
+ /**
3485
+ * Parse tool arguments from JSON string
3486
+ */
3487
+ parseToolArguments(args) {
3488
+ try {
3489
+ return JSON.parse(args);
3490
+ }
3491
+ catch (_a) {
3492
+ return {};
3493
+ }
3494
+ }
3012
3495
  /**
3013
3496
  * Get conversation history
3014
3497
  */
@@ -3195,20 +3678,20 @@ class PlayKitSDK extends EventEmitter {
3195
3678
  // Create indicator element
3196
3679
  this.devTokenIndicator = document.createElement('div');
3197
3680
  this.devTokenIndicator.textContent = 'DeveloperToken';
3198
- this.devTokenIndicator.style.cssText = `
3199
- position: fixed;
3200
- top: 10px;
3201
- left: 10px;
3202
- background-color: #dc2626;
3203
- color: white;
3204
- padding: 4px 12px;
3205
- border-radius: 4px;
3206
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
3207
- font-size: 12px;
3208
- font-weight: 600;
3209
- z-index: 999999;
3210
- pointer-events: none;
3211
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
3681
+ this.devTokenIndicator.style.cssText = `
3682
+ position: fixed;
3683
+ top: 10px;
3684
+ left: 10px;
3685
+ background-color: #dc2626;
3686
+ color: white;
3687
+ padding: 4px 12px;
3688
+ border-radius: 4px;
3689
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
3690
+ font-size: 12px;
3691
+ font-weight: 600;
3692
+ z-index: 999999;
3693
+ pointer-events: none;
3694
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
3212
3695
  `;
3213
3696
  document.body.appendChild(this.devTokenIndicator);
3214
3697
  }