playkit-sdk 1.4.0 → 1.6.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 +7 -0
- package/dist/playkit-sdk.cjs.js +242 -1022
- package/dist/playkit-sdk.cjs.js.map +1 -1
- package/dist/playkit-sdk.d.ts +304 -309
- package/dist/playkit-sdk.esm.js +243 -1022
- package/dist/playkit-sdk.esm.js.map +1 -1
- package/dist/playkit-sdk.umd.js +242 -1022
- package/dist/playkit-sdk.umd.js.map +1 -1
- package/package.json +4 -4
package/dist/playkit-sdk.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* playkit-sdk v1.
|
|
2
|
+
* playkit-sdk v1.6.0
|
|
3
3
|
* PlayKit SDK for JavaScript
|
|
4
4
|
* @license SEE LICENSE IN LICENSE
|
|
5
5
|
*/
|
|
@@ -47,6 +47,48 @@ function createMultimodalMessage(role, text, images, audios) {
|
|
|
47
47
|
}
|
|
48
48
|
return { role, content };
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Convert an OpenAI-compatible tool call returned by the API into the canonical
|
|
52
|
+
* PlayKit message content part used for future requests.
|
|
53
|
+
*/
|
|
54
|
+
function createToolCallContentPart(toolCall) {
|
|
55
|
+
var _a;
|
|
56
|
+
let input = {};
|
|
57
|
+
const args = (_a = toolCall.function) === null || _a === void 0 ? void 0 : _a.arguments;
|
|
58
|
+
if (typeof args === 'string' && args.trim()) {
|
|
59
|
+
try {
|
|
60
|
+
input = JSON.parse(args);
|
|
61
|
+
}
|
|
62
|
+
catch (_b) {
|
|
63
|
+
input = args;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
type: 'tool-call',
|
|
68
|
+
toolCallId: toolCall.id,
|
|
69
|
+
toolName: toolCall.function.name,
|
|
70
|
+
input,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create a canonical PlayKit tool-result content part.
|
|
75
|
+
*/
|
|
76
|
+
function createToolResultContentPart(toolCallId, toolName, result) {
|
|
77
|
+
if (typeof result === 'string') {
|
|
78
|
+
return {
|
|
79
|
+
type: 'tool-result',
|
|
80
|
+
toolCallId,
|
|
81
|
+
toolName,
|
|
82
|
+
output: { type: 'text', value: result },
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
type: 'tool-result',
|
|
87
|
+
toolCallId,
|
|
88
|
+
toolName,
|
|
89
|
+
output: { type: 'json', value: result },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
50
92
|
/**
|
|
51
93
|
* Error types that can be thrown by the SDK
|
|
52
94
|
*/
|
|
@@ -830,7 +872,7 @@ class TokenStorage {
|
|
|
830
872
|
}
|
|
831
873
|
|
|
832
874
|
const SDK_TYPE = 'Javascript';
|
|
833
|
-
const SDK_VERSION = '"1.
|
|
875
|
+
const SDK_VERSION = '"1.6.0"';
|
|
834
876
|
function getSDKHeaders() {
|
|
835
877
|
return {
|
|
836
878
|
'X-SDK-Type': SDK_TYPE,
|
|
@@ -838,867 +880,6 @@ function getSDKHeaders() {
|
|
|
838
880
|
};
|
|
839
881
|
}
|
|
840
882
|
|
|
841
|
-
/**
|
|
842
|
-
* Authentication Flow Manager
|
|
843
|
-
* Manages the headless authentication flow with automatic UI
|
|
844
|
-
*
|
|
845
|
-
* @deprecated This class is deprecated. Use DeviceAuthFlowManager instead.
|
|
846
|
-
* Will be removed in v2.0
|
|
847
|
-
*/
|
|
848
|
-
// i18n translations
|
|
849
|
-
const translations$2 = {
|
|
850
|
-
en: {
|
|
851
|
-
signIn: 'Sign In / Register',
|
|
852
|
-
signInSubtitle: 'This game uses PlayKit for cost management.\nIf you don\'t have an account, we\'ll automatically register you. Sign up and get free AI game credits!',
|
|
853
|
-
email: 'Email',
|
|
854
|
-
phone: 'Phone',
|
|
855
|
-
emailPlaceholder: 'Enter your email address',
|
|
856
|
-
phonePlaceholder: 'Enter your phone number (+86 Only)',
|
|
857
|
-
sendCode: 'Send Code',
|
|
858
|
-
enterCode: 'Enter Code',
|
|
859
|
-
enterCodeSubtitle: "We've sent a 6-digit code to your",
|
|
860
|
-
verify: 'Verify',
|
|
861
|
-
pleaseEnterEmail: 'Please enter your email address',
|
|
862
|
-
pleaseEnterPhone: 'Please enter your phone number',
|
|
863
|
-
enterAllDigits: 'Please enter all 6 digits',
|
|
864
|
-
verificationFailed: 'Verification failed',
|
|
865
|
-
failedToSendCode: 'Failed to send code',
|
|
866
|
-
invalidCode: 'Invalid verification code',
|
|
867
|
-
},
|
|
868
|
-
zh: {
|
|
869
|
-
signIn: '登录/注册',
|
|
870
|
-
signInSubtitle: '本游戏使用PlayKit进行成本管理。\n如果您没有帐户,我们会为您自动注册。注册即送AI游戏积分!',
|
|
871
|
-
email: '邮箱',
|
|
872
|
-
phone: '手机',
|
|
873
|
-
emailPlaceholder: '请输入邮箱地址',
|
|
874
|
-
phonePlaceholder: '请输入手机号(仅限 +86)',
|
|
875
|
-
sendCode: '发送验证码',
|
|
876
|
-
enterCode: '输入验证码',
|
|
877
|
-
enterCodeSubtitle: '我们已向您发送了 6 位验证码:',
|
|
878
|
-
verify: '验证',
|
|
879
|
-
pleaseEnterEmail: '请输入邮箱地址',
|
|
880
|
-
pleaseEnterPhone: '请输入手机号',
|
|
881
|
-
enterAllDigits: '请输入完整的 6 位验证码',
|
|
882
|
-
verificationFailed: '验证失败',
|
|
883
|
-
failedToSendCode: '发送验证码失败',
|
|
884
|
-
invalidCode: '验证码无效',
|
|
885
|
-
},
|
|
886
|
-
'zh-TW': {
|
|
887
|
-
signIn: '登入/註冊',
|
|
888
|
-
signInSubtitle: '本遊戲使用PlayKit進行成本管理。\n如果您沒有帳戶,我們會為您自動註冊。註冊即送AI遊戲積分!',
|
|
889
|
-
email: '電子郵件',
|
|
890
|
-
phone: '手機',
|
|
891
|
-
emailPlaceholder: '請輸入電子郵件地址',
|
|
892
|
-
phonePlaceholder: '請輸入手機號碼(僅限 +86)',
|
|
893
|
-
sendCode: '發送驗證碼',
|
|
894
|
-
enterCode: '輸入驗證碼',
|
|
895
|
-
enterCodeSubtitle: '我們已向您發送了 6 位驗證碼:',
|
|
896
|
-
verify: '驗證',
|
|
897
|
-
pleaseEnterEmail: '請輸入電子郵件地址',
|
|
898
|
-
pleaseEnterPhone: '請輸入手機號碼',
|
|
899
|
-
enterAllDigits: '請輸入完整的 6 位驗證碼',
|
|
900
|
-
verificationFailed: '驗證失敗',
|
|
901
|
-
failedToSendCode: '發送驗證碼失敗',
|
|
902
|
-
invalidCode: '驗證碼無效',
|
|
903
|
-
},
|
|
904
|
-
ja: {
|
|
905
|
-
signIn: 'サインイン/登録',
|
|
906
|
-
signInSubtitle: 'このゲームはPlayKitでコスト管理を行っています。\nアカウントをお持ちでない場合は、自動的に登録します。登録するとAIゲームクレジットがもらえます!',
|
|
907
|
-
email: 'メール',
|
|
908
|
-
phone: '電話',
|
|
909
|
-
emailPlaceholder: 'メールアドレスを入力してください',
|
|
910
|
-
phonePlaceholder: '電話番号を入力してください(+86のみ)',
|
|
911
|
-
sendCode: '認証コードを送信',
|
|
912
|
-
enterCode: '認証コードを入力',
|
|
913
|
-
enterCodeSubtitle: '6桁の認証コードを送信しました:',
|
|
914
|
-
verify: '検証',
|
|
915
|
-
pleaseEnterEmail: 'メールアドレスを入力してください',
|
|
916
|
-
pleaseEnterPhone: '電話番号を入力してください',
|
|
917
|
-
enterAllDigits: '6桁すべて入力してください',
|
|
918
|
-
verificationFailed: '検証に失敗しました',
|
|
919
|
-
failedToSendCode: '認証コードの送信に失敗しました',
|
|
920
|
-
invalidCode: '認証コードが無効です',
|
|
921
|
-
},
|
|
922
|
-
ko: {
|
|
923
|
-
signIn: '로그인/가입',
|
|
924
|
-
signInSubtitle: '이 게임은 PlayKit으로 비용 관리를 합니다.\n계정이 없으시면 자동으로 등록해 드립니다. 가입하면 AI 게임 크레딧을 받으세요!',
|
|
925
|
-
email: '이메일',
|
|
926
|
-
phone: '전화',
|
|
927
|
-
emailPlaceholder: '이메일 주소를 입력하세요',
|
|
928
|
-
phonePlaceholder: '전화번호를 입력하세요(+86만 지원)',
|
|
929
|
-
sendCode: '인증 코드 전송',
|
|
930
|
-
enterCode: '인증 코드 입력',
|
|
931
|
-
enterCodeSubtitle: '6자리 인증 코드를 보냈습니다:',
|
|
932
|
-
verify: '확인',
|
|
933
|
-
pleaseEnterEmail: '이메일 주소를 입력하세요',
|
|
934
|
-
pleaseEnterPhone: '전화번호를 입력하세요',
|
|
935
|
-
enterAllDigits: '6자리를 모두 입력하세요',
|
|
936
|
-
verificationFailed: '인증 실패',
|
|
937
|
-
failedToSendCode: '인증 코드 전송 실패',
|
|
938
|
-
invalidCode: '인증 코드가 잘못되었습니다',
|
|
939
|
-
},
|
|
940
|
-
};
|
|
941
|
-
class AuthFlowManager extends EventEmitter {
|
|
942
|
-
constructor(baseURL) {
|
|
943
|
-
super();
|
|
944
|
-
this.currentSessionId = null;
|
|
945
|
-
this._uiContainer = null;
|
|
946
|
-
this._isSuccess = false;
|
|
947
|
-
this.currentLanguage = 'en';
|
|
948
|
-
// UI Elements
|
|
949
|
-
this.modal = null;
|
|
950
|
-
this.identifierPanel = null;
|
|
951
|
-
this.verificationPanel = null;
|
|
952
|
-
this.loadingOverlay = null;
|
|
953
|
-
this.otpInstance = null;
|
|
954
|
-
// @ts-ignore - replaced at build time
|
|
955
|
-
this.baseURL = baseURL || "https://api.playkit.ai";
|
|
956
|
-
this.currentLanguage = this.detectLanguage();
|
|
957
|
-
}
|
|
958
|
-
/**
|
|
959
|
-
* Detect browser language (safe for Node.js environment)
|
|
960
|
-
*/
|
|
961
|
-
detectLanguage() {
|
|
962
|
-
// Check if running in browser environment
|
|
963
|
-
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
964
|
-
return 'en'; // Default to English in Node.js environment
|
|
965
|
-
}
|
|
966
|
-
try {
|
|
967
|
-
const browserLang = navigator.language.toLowerCase();
|
|
968
|
-
// Match language codes
|
|
969
|
-
if (browserLang.startsWith('zh-tw') || browserLang.startsWith('zh-hk')) {
|
|
970
|
-
return 'zh-TW'; // Traditional Chinese
|
|
971
|
-
}
|
|
972
|
-
else if (browserLang.startsWith('zh')) {
|
|
973
|
-
return 'zh'; // Simplified Chinese
|
|
974
|
-
}
|
|
975
|
-
else if (browserLang.startsWith('ja')) {
|
|
976
|
-
return 'ja'; // Japanese
|
|
977
|
-
}
|
|
978
|
-
else if (browserLang.startsWith('ko')) {
|
|
979
|
-
return 'ko'; // Korean
|
|
980
|
-
}
|
|
981
|
-
else {
|
|
982
|
-
return 'en'; // Default to English
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
catch (error) {
|
|
986
|
-
// Fallback to English if detection fails
|
|
987
|
-
return 'en';
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Get translated text
|
|
992
|
-
*/
|
|
993
|
-
t(key) {
|
|
994
|
-
return translations$2[this.currentLanguage][key];
|
|
995
|
-
}
|
|
996
|
-
/**
|
|
997
|
-
* Start the authentication flow
|
|
998
|
-
* Returns a promise that resolves with the JWT token
|
|
999
|
-
*/
|
|
1000
|
-
async startFlow() {
|
|
1001
|
-
return new Promise((resolve, reject) => {
|
|
1002
|
-
// Create and show UI
|
|
1003
|
-
this.createUI();
|
|
1004
|
-
this.showModal();
|
|
1005
|
-
// Listen for success/failure
|
|
1006
|
-
this.once('success', (token) => {
|
|
1007
|
-
this.hideModal();
|
|
1008
|
-
resolve(token);
|
|
1009
|
-
});
|
|
1010
|
-
this.once('error', (error) => {
|
|
1011
|
-
this.hideModal();
|
|
1012
|
-
reject(error);
|
|
1013
|
-
});
|
|
1014
|
-
// Set default auth type based on region
|
|
1015
|
-
this.setDefaultAuthTypeByRegion().catch((err) => {
|
|
1016
|
-
console.error('[PlayKit Auth] Failed to detect region:', err);
|
|
1017
|
-
});
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
/**
|
|
1021
|
-
* Create the authentication UI
|
|
1022
|
-
*/
|
|
1023
|
-
createUI() {
|
|
1024
|
-
// Create modal container
|
|
1025
|
-
this.modal = document.createElement('div');
|
|
1026
|
-
this.modal.className = 'playkit-auth-modal';
|
|
1027
|
-
this.modal.innerHTML = `
|
|
1028
|
-
<div class="playkit-auth-overlay"></div>
|
|
1029
|
-
<div class="playkit-auth-container">
|
|
1030
|
-
<!-- Identifier Panel -->
|
|
1031
|
-
<div class="playkit-auth-panel" id="playkit-identifier-panel">
|
|
1032
|
-
<div class="playkit-auth-header">
|
|
1033
|
-
<h2>${this.t('signIn')}</h2>
|
|
1034
|
-
<p>${this.t('signInSubtitle')}</p>
|
|
1035
|
-
</div>
|
|
1036
|
-
|
|
1037
|
-
<div class="playkit-auth-toggle">
|
|
1038
|
-
<label class="playkit-toggle-option">
|
|
1039
|
-
<input type="radio" name="auth-type" value="email" checked>
|
|
1040
|
-
<span>${this.t('email')}</span>
|
|
1041
|
-
</label>
|
|
1042
|
-
<label class="playkit-toggle-option">
|
|
1043
|
-
<input type="radio" name="auth-type" value="phone">
|
|
1044
|
-
<span>${this.t('phone')}</span>
|
|
1045
|
-
</label>
|
|
1046
|
-
</div>
|
|
1047
|
-
|
|
1048
|
-
<div class="playkit-auth-input-group">
|
|
1049
|
-
<div class="playkit-input-wrapper">
|
|
1050
|
-
<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">
|
|
1051
|
-
<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>
|
|
1052
|
-
<polyline points="22,6 12,13 2,6"></polyline>
|
|
1053
|
-
</svg>
|
|
1054
|
-
<input
|
|
1055
|
-
type="text"
|
|
1056
|
-
id="playkit-identifier-input"
|
|
1057
|
-
placeholder="${this.t('emailPlaceholder')}"
|
|
1058
|
-
autocomplete="off"
|
|
1059
|
-
>
|
|
1060
|
-
</div>
|
|
1061
|
-
</div>
|
|
1062
|
-
|
|
1063
|
-
<button class="playkit-auth-button" id="playkit-send-code-btn">
|
|
1064
|
-
${this.t('sendCode')}
|
|
1065
|
-
</button>
|
|
1066
|
-
|
|
1067
|
-
<div class="playkit-auth-error" id="playkit-error-text"></div>
|
|
1068
|
-
</div>
|
|
1069
|
-
|
|
1070
|
-
<!-- Verification Panel -->
|
|
1071
|
-
<div class="playkit-auth-panel" id="playkit-verification-panel" style="display: none;">
|
|
1072
|
-
<div class="playkit-auth-header">
|
|
1073
|
-
<button class="playkit-back-button" id="playkit-back-btn">
|
|
1074
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1075
|
-
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
1076
|
-
</svg>
|
|
1077
|
-
</button>
|
|
1078
|
-
<h2>${this.t('enterCode')}</h2>
|
|
1079
|
-
<p>${this.t('enterCodeSubtitle')} <span id="playkit-identifier-display"></span></p>
|
|
1080
|
-
</div>
|
|
1081
|
-
|
|
1082
|
-
<div class="playkit-auth-input-group">
|
|
1083
|
-
<div class="playkit-code-inputs">
|
|
1084
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="0">
|
|
1085
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="1">
|
|
1086
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="2">
|
|
1087
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="3">
|
|
1088
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="4">
|
|
1089
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="5">
|
|
1090
|
-
</div>
|
|
1091
|
-
</div>
|
|
1092
|
-
|
|
1093
|
-
<button class="playkit-auth-button" id="playkit-verify-btn">
|
|
1094
|
-
${this.t('verify')}
|
|
1095
|
-
</button>
|
|
1096
|
-
|
|
1097
|
-
<div class="playkit-auth-error" id="playkit-verify-error-text"></div>
|
|
1098
|
-
</div>
|
|
1099
|
-
|
|
1100
|
-
<!-- Loading Overlay -->
|
|
1101
|
-
<div class="playkit-loading-overlay" id="playkit-loading-overlay" style="display: none;">
|
|
1102
|
-
<div class="playkit-spinner"></div>
|
|
1103
|
-
</div>
|
|
1104
|
-
</div>
|
|
1105
|
-
`;
|
|
1106
|
-
// Add styles and load VanillaOTP
|
|
1107
|
-
this.addStyles();
|
|
1108
|
-
this.loadVanillaOTP();
|
|
1109
|
-
// Append to body
|
|
1110
|
-
document.body.appendChild(this.modal);
|
|
1111
|
-
// Get references
|
|
1112
|
-
this.identifierPanel = document.getElementById('playkit-identifier-panel');
|
|
1113
|
-
this.verificationPanel = document.getElementById('playkit-verification-panel');
|
|
1114
|
-
this.loadingOverlay = document.getElementById('playkit-loading-overlay');
|
|
1115
|
-
// Setup event listeners
|
|
1116
|
-
this.setupEventListeners();
|
|
1117
|
-
}
|
|
1118
|
-
/**
|
|
1119
|
-
* Load VanillaOTP library
|
|
1120
|
-
*/
|
|
1121
|
-
loadVanillaOTP() {
|
|
1122
|
-
// Check if VanillaOTP is already loaded
|
|
1123
|
-
if (window.VanillaOTP)
|
|
1124
|
-
return;
|
|
1125
|
-
// Inject VanillaOTP script
|
|
1126
|
-
const script = document.createElement('script');
|
|
1127
|
-
script.textContent = `"use strict";var VanillaOTP=function(t,e=null){if(this.emptyChar=" ","string"==typeof t)this.container=document.querySelector(t);else{if(!(t instanceof Element))return;this.container=t}e&&("string"==typeof e?this.updateTo=document.querySelector(e)||null:e instanceof Element?this.updateTo=e:this.updateTo=null),this.inputs=Array.from(this.container.querySelectorAll("input[type=text], input[type=number], input[type=password]"));let n=this,u=n.inputs.length;for(let i=0;i<u;i++){let l=n.inputs[i];l.addEventListener("input",function(){if(isNaN(l.value))return l.value=l.dataset.otpInputRestore||"",n._updateValue();if(0==l.value.length)return n._saveInputValue(i);if(1==l.value.length){n._saveInputValue(i),n._updateValue(),i+1<u&&n.inputs[i+1].focus();return}if(i==u-1)return n._setInputValue(i,l.value);let t=l.value.split("");for(let e=0;e<t.length&&!(e+i>=u);e++)n._setInputValue(e+i,t[e]);let a=Math.min(u-1,i+t.length);n.inputs[a].focus()}),l.addEventListener("keydown",function(t){if(8==t.keyCode&&""==l.value&&0!=i){n._setInputValue(i-1,""),n.inputs[i-1].focus();return}if(46==t.keyCode&&i!=u-1){let e=l.selectionStart||0;for(let a=i+e;a<u-1;a++)n._setInputValue(a,n.inputs[a+1].value);n._setInputValue(u-1,""),l.selectionStart&&(l.selectionStart=e),t.preventDefault();return}if(37==t.keyCode&&(null==l.selectionStart||0==l.selectionStart)){i>0&&(t.preventDefault(),n.inputs[i-1].focus(),n.inputs[i-1].select());return}if(39==t.keyCode&&(null==l.selectionStart||l.selectionEnd==l.value.length)){i+1<u&&(t.preventDefault(),n.inputs[i+1].focus(),n.inputs[i+1].select());return}})}};VanillaOTP.prototype.setEmptyChar=function(t){this.emptyChar=t},VanillaOTP.prototype.getValue=function(){let t="",e=this;return this.inputs.forEach(function(n){t+=""==n.value?e.emptyChar:n.value}),t},VanillaOTP.prototype.setValue=function(t){if(isNaN(t)){console.error("Please enter an integer value.");return}let e=(t=""+t).split("");for(let n=0;n<this.inputs.length;n++)this._setInputValue(n,e[n]||"")},VanillaOTP.prototype._setInputValue=function(t,e){return isNaN(e)?console.error("Please enter an integer value."):this.inputs[t]?void(this.inputs[t].value=String(e).substring(0,1),this._saveInputValue(t),this._updateValue()):console.error("Index not found.")},VanillaOTP.prototype._saveInputValue=function(t,e){if(!this.inputs[t])return console.error("Index not found.");this.inputs[t].dataset.otpInputRestore=e||this.inputs[t].value},VanillaOTP.prototype._updateValue=function(){this.updateTo&&(this.updateTo.value=this.getValue())};`;
|
|
1128
|
-
document.head.appendChild(script);
|
|
1129
|
-
}
|
|
1130
|
-
/**
|
|
1131
|
-
* Add CSS styles to the page
|
|
1132
|
-
*/
|
|
1133
|
-
addStyles() {
|
|
1134
|
-
const styleId = 'playkit-auth-styles';
|
|
1135
|
-
if (document.getElementById(styleId))
|
|
1136
|
-
return;
|
|
1137
|
-
const style = document.createElement('style');
|
|
1138
|
-
style.id = styleId;
|
|
1139
|
-
style.textContent = `
|
|
1140
|
-
.playkit-auth-modal {
|
|
1141
|
-
position: fixed;
|
|
1142
|
-
top: 0;
|
|
1143
|
-
left: 0;
|
|
1144
|
-
right: 0;
|
|
1145
|
-
bottom: 0;
|
|
1146
|
-
z-index: 999999;
|
|
1147
|
-
display: flex;
|
|
1148
|
-
justify-content: center;
|
|
1149
|
-
align-items: center;
|
|
1150
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
.playkit-auth-overlay {
|
|
1154
|
-
position: absolute;
|
|
1155
|
-
top: 0;
|
|
1156
|
-
left: 0;
|
|
1157
|
-
right: 0;
|
|
1158
|
-
bottom: 0;
|
|
1159
|
-
background: rgba(0, 0, 0, 0.8);
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
.playkit-auth-container {
|
|
1163
|
-
position: relative;
|
|
1164
|
-
background: #fff;
|
|
1165
|
-
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
1166
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.05);
|
|
1167
|
-
width: 90%;
|
|
1168
|
-
max-width: 320px;
|
|
1169
|
-
overflow: hidden;
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
.playkit-auth-panel {
|
|
1173
|
-
padding: 24px;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
.playkit-auth-header {
|
|
1177
|
-
text-align: center;
|
|
1178
|
-
margin-bottom: 20px;
|
|
1179
|
-
position: relative;
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
.playkit-auth-header h2 {
|
|
1183
|
-
margin: 0 0 8px 0;
|
|
1184
|
-
font-size: 14px;
|
|
1185
|
-
font-weight: 600;
|
|
1186
|
-
color: #171717;
|
|
1187
|
-
}
|
|
1188
|
-
|
|
1189
|
-
.playkit-auth-header p {
|
|
1190
|
-
margin: 0;
|
|
1191
|
-
font-size: 14px;
|
|
1192
|
-
color: #666;
|
|
1193
|
-
line-height: 1.5;
|
|
1194
|
-
}
|
|
1195
|
-
|
|
1196
|
-
.playkit-back-button {
|
|
1197
|
-
position: absolute;
|
|
1198
|
-
left: 0;
|
|
1199
|
-
top: 0;
|
|
1200
|
-
background: transparent;
|
|
1201
|
-
border: none;
|
|
1202
|
-
cursor: pointer;
|
|
1203
|
-
padding: 4px;
|
|
1204
|
-
color: #666;
|
|
1205
|
-
transition: background-color 0.2s ease, color 0.2s ease;
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
.playkit-back-button:hover {
|
|
1209
|
-
background: #f5f5f5;
|
|
1210
|
-
color: #171717;
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
.playkit-auth-toggle {
|
|
1214
|
-
display: flex;
|
|
1215
|
-
background: #f5f5f5;
|
|
1216
|
-
padding: 2px;
|
|
1217
|
-
margin-bottom: 20px;
|
|
1218
|
-
gap: 2px;
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
.playkit-toggle-option {
|
|
1222
|
-
flex: 1;
|
|
1223
|
-
display: flex;
|
|
1224
|
-
justify-content: center;
|
|
1225
|
-
align-items: center;
|
|
1226
|
-
padding: 10px 16px;
|
|
1227
|
-
cursor: pointer;
|
|
1228
|
-
transition: background-color 0.2s ease;
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
.playkit-toggle-option input {
|
|
1232
|
-
display: none;
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
.playkit-toggle-option span {
|
|
1236
|
-
font-size: 14px;
|
|
1237
|
-
font-weight: 500;
|
|
1238
|
-
color: #666;
|
|
1239
|
-
transition: color 0.2s ease;
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
.playkit-toggle-option input:checked + span {
|
|
1243
|
-
color: #fff;
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
.playkit-toggle-option:has(input:checked) {
|
|
1247
|
-
background: #171717;
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
.playkit-auth-input-group {
|
|
1251
|
-
margin-bottom: 20px;
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
.playkit-input-wrapper {
|
|
1255
|
-
position: relative;
|
|
1256
|
-
display: flex;
|
|
1257
|
-
align-items: center;
|
|
1258
|
-
}
|
|
1259
|
-
|
|
1260
|
-
.playkit-input-icon {
|
|
1261
|
-
position: absolute;
|
|
1262
|
-
left: 12px;
|
|
1263
|
-
color: #999;
|
|
1264
|
-
pointer-events: none;
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
.playkit-input-wrapper input {
|
|
1268
|
-
width: 100%;
|
|
1269
|
-
padding: 10px 12px 10px 44px;
|
|
1270
|
-
border: 1px solid #e5e7eb;
|
|
1271
|
-
font-size: 14px;
|
|
1272
|
-
transition: border-color 0.2s ease;
|
|
1273
|
-
box-sizing: border-box;
|
|
1274
|
-
background: #fff;
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
.playkit-input-wrapper input:hover {
|
|
1278
|
-
border-color: #d4d4d4;
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
.playkit-input-wrapper input:focus {
|
|
1282
|
-
outline: none;
|
|
1283
|
-
border-color: #171717;
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
.playkit-code-inputs {
|
|
1287
|
-
display: flex;
|
|
1288
|
-
gap: 8px;
|
|
1289
|
-
justify-content: center;
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
.playkit-code-input {
|
|
1293
|
-
width: 40px !important;
|
|
1294
|
-
height: 48px;
|
|
1295
|
-
text-align: center;
|
|
1296
|
-
font-size: 20px;
|
|
1297
|
-
font-weight: 600;
|
|
1298
|
-
border: 1px solid #e5e7eb !important;
|
|
1299
|
-
padding: 0 !important;
|
|
1300
|
-
transition: border-color 0.2s ease;
|
|
1301
|
-
background: #fff;
|
|
1302
|
-
-moz-appearance: textfield;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
.playkit-code-input::-webkit-outer-spin-button,
|
|
1306
|
-
.playkit-code-input::-webkit-inner-spin-button {
|
|
1307
|
-
-webkit-appearance: none;
|
|
1308
|
-
margin: 0;
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
.playkit-code-input:hover {
|
|
1312
|
-
border-color: #d4d4d4 !important;
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
.playkit-code-input:focus {
|
|
1316
|
-
outline: none;
|
|
1317
|
-
border-color: #171717 !important;
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
.playkit-auth-button {
|
|
1321
|
-
width: 100%;
|
|
1322
|
-
padding: 10px 16px;
|
|
1323
|
-
background: #171717;
|
|
1324
|
-
color: white;
|
|
1325
|
-
border: none;
|
|
1326
|
-
font-size: 14px;
|
|
1327
|
-
font-weight: 500;
|
|
1328
|
-
cursor: pointer;
|
|
1329
|
-
transition: background 0.2s ease;
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
.playkit-auth-button:hover:not(:disabled) {
|
|
1333
|
-
background: #404040;
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
.playkit-auth-button:active:not(:disabled) {
|
|
1337
|
-
background: #0a0a0a;
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
.playkit-auth-button:disabled {
|
|
1341
|
-
background: #e5e7eb;
|
|
1342
|
-
color: #999;
|
|
1343
|
-
cursor: not-allowed;
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
.playkit-auth-error {
|
|
1347
|
-
margin-top: 16px;
|
|
1348
|
-
padding: 12px 16px;
|
|
1349
|
-
background: #fef2f2;
|
|
1350
|
-
border: 1px solid #fecaca;
|
|
1351
|
-
color: #dc2626;
|
|
1352
|
-
font-size: 13px;
|
|
1353
|
-
text-align: left;
|
|
1354
|
-
display: none;
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
.playkit-auth-error.show {
|
|
1358
|
-
display: block;
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
.playkit-loading-overlay {
|
|
1362
|
-
position: absolute;
|
|
1363
|
-
top: 0;
|
|
1364
|
-
left: 0;
|
|
1365
|
-
right: 0;
|
|
1366
|
-
bottom: 0;
|
|
1367
|
-
background: rgba(255, 255, 255, 0.96);
|
|
1368
|
-
display: flex;
|
|
1369
|
-
justify-content: center;
|
|
1370
|
-
align-items: center;
|
|
1371
|
-
}
|
|
1372
|
-
|
|
1373
|
-
.playkit-spinner {
|
|
1374
|
-
width: 24px;
|
|
1375
|
-
height: 24px;
|
|
1376
|
-
border: 2px solid #e5e7eb;
|
|
1377
|
-
border-top: 2px solid #171717;
|
|
1378
|
-
border-radius: 50%;
|
|
1379
|
-
animation: playkit-spin 1s linear infinite;
|
|
1380
|
-
}
|
|
1381
|
-
|
|
1382
|
-
@keyframes playkit-spin {
|
|
1383
|
-
0% { transform: rotate(0deg); }
|
|
1384
|
-
100% { transform: rotate(360deg); }
|
|
1385
|
-
}
|
|
1386
|
-
|
|
1387
|
-
@media (max-width: 480px) {
|
|
1388
|
-
.playkit-auth-container {
|
|
1389
|
-
width: 95%;
|
|
1390
|
-
max-width: none;
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
.playkit-auth-panel {
|
|
1394
|
-
padding: 20px;
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
.playkit-code-input {
|
|
1398
|
-
width: 36px !important;
|
|
1399
|
-
height: 44px;
|
|
1400
|
-
font-size: 18px;
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
.playkit-code-inputs {
|
|
1404
|
-
gap: 6px;
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
`;
|
|
1408
|
-
document.head.appendChild(style);
|
|
1409
|
-
}
|
|
1410
|
-
/**
|
|
1411
|
-
* Setup event listeners
|
|
1412
|
-
*/
|
|
1413
|
-
setupEventListeners() {
|
|
1414
|
-
var _a, _b, _c, _d;
|
|
1415
|
-
// Auth type toggle
|
|
1416
|
-
const emailRadio = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('input[value="email"]');
|
|
1417
|
-
const phoneRadio = (_b = this.modal) === null || _b === void 0 ? void 0 : _b.querySelector('input[value="phone"]');
|
|
1418
|
-
const identifierInput = document.getElementById('playkit-identifier-input');
|
|
1419
|
-
const identifierIcon = document.getElementById('playkit-identifier-icon');
|
|
1420
|
-
const updateIcon = () => {
|
|
1421
|
-
const isEmail = emailRadio === null || emailRadio === void 0 ? void 0 : emailRadio.checked;
|
|
1422
|
-
identifierInput.placeholder = isEmail
|
|
1423
|
-
? this.t('emailPlaceholder')
|
|
1424
|
-
: this.t('phonePlaceholder');
|
|
1425
|
-
// Update icon
|
|
1426
|
-
if (isEmail) {
|
|
1427
|
-
identifierIcon.innerHTML = `
|
|
1428
|
-
<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>
|
|
1429
|
-
<polyline points="22,6 12,13 2,6"></polyline>
|
|
1430
|
-
`;
|
|
1431
|
-
}
|
|
1432
|
-
else {
|
|
1433
|
-
identifierIcon.innerHTML = `
|
|
1434
|
-
<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>
|
|
1435
|
-
`;
|
|
1436
|
-
}
|
|
1437
|
-
};
|
|
1438
|
-
emailRadio === null || emailRadio === void 0 ? void 0 : emailRadio.addEventListener('change', updateIcon);
|
|
1439
|
-
phoneRadio === null || phoneRadio === void 0 ? void 0 : phoneRadio.addEventListener('change', updateIcon);
|
|
1440
|
-
// Send code button
|
|
1441
|
-
const sendCodeBtn = document.getElementById('playkit-send-code-btn');
|
|
1442
|
-
sendCodeBtn === null || sendCodeBtn === void 0 ? void 0 : sendCodeBtn.addEventListener('click', () => this.onSendCodeClicked());
|
|
1443
|
-
// Enter key in identifier input
|
|
1444
|
-
identifierInput === null || identifierInput === void 0 ? void 0 : identifierInput.addEventListener('keypress', (e) => {
|
|
1445
|
-
if (e.key === 'Enter') {
|
|
1446
|
-
this.onSendCodeClicked();
|
|
1447
|
-
}
|
|
1448
|
-
});
|
|
1449
|
-
// Initialize VanillaOTP for code inputs
|
|
1450
|
-
const codeInputsContainer = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector('.playkit-code-inputs');
|
|
1451
|
-
if (codeInputsContainer && window.VanillaOTP) {
|
|
1452
|
-
this.otpInstance = new window.VanillaOTP(codeInputsContainer);
|
|
1453
|
-
// Auto-submit when all 6 digits entered
|
|
1454
|
-
const codeInputs = (_d = this.modal) === null || _d === void 0 ? void 0 : _d.querySelectorAll('.playkit-code-input');
|
|
1455
|
-
codeInputs === null || codeInputs === void 0 ? void 0 : codeInputs.forEach((input, _index) => {
|
|
1456
|
-
input.addEventListener('input', () => {
|
|
1457
|
-
// Check if all inputs are filled
|
|
1458
|
-
const allFilled = Array.from(codeInputs).every(inp => inp.value.length === 1);
|
|
1459
|
-
if (allFilled) {
|
|
1460
|
-
// Small delay to ensure the last input is processed
|
|
1461
|
-
setTimeout(() => this.onVerifyClicked(), 100);
|
|
1462
|
-
}
|
|
1463
|
-
});
|
|
1464
|
-
});
|
|
1465
|
-
}
|
|
1466
|
-
// Verify button
|
|
1467
|
-
const verifyBtn = document.getElementById('playkit-verify-btn');
|
|
1468
|
-
verifyBtn === null || verifyBtn === void 0 ? void 0 : verifyBtn.addEventListener('click', () => this.onVerifyClicked());
|
|
1469
|
-
// Back button
|
|
1470
|
-
const backBtn = document.getElementById('playkit-back-btn');
|
|
1471
|
-
backBtn === null || backBtn === void 0 ? void 0 : backBtn.addEventListener('click', () => {
|
|
1472
|
-
this.showIdentifierPanel();
|
|
1473
|
-
});
|
|
1474
|
-
}
|
|
1475
|
-
/**
|
|
1476
|
-
* Handle send code button click
|
|
1477
|
-
*/
|
|
1478
|
-
async onSendCodeClicked() {
|
|
1479
|
-
var _a;
|
|
1480
|
-
this.clearError();
|
|
1481
|
-
const identifierInput = document.getElementById('playkit-identifier-input');
|
|
1482
|
-
const identifier = identifierInput.value.trim();
|
|
1483
|
-
const emailRadio = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('input[value="email"]');
|
|
1484
|
-
const type = emailRadio.checked ? 'email' : 'phone';
|
|
1485
|
-
if (!identifier) {
|
|
1486
|
-
this.showError(type === 'email' ? this.t('pleaseEnterEmail') : this.t('pleaseEnterPhone'));
|
|
1487
|
-
return;
|
|
1488
|
-
}
|
|
1489
|
-
const sendCodeBtn = document.getElementById('playkit-send-code-btn');
|
|
1490
|
-
sendCodeBtn.disabled = true;
|
|
1491
|
-
this.showLoading();
|
|
1492
|
-
try {
|
|
1493
|
-
const success = await this.sendVerificationCode(identifier, type);
|
|
1494
|
-
if (success) {
|
|
1495
|
-
// Store identifier for display
|
|
1496
|
-
const displaySpan = document.getElementById('playkit-identifier-display');
|
|
1497
|
-
if (displaySpan) {
|
|
1498
|
-
displaySpan.textContent = type === 'email' ? identifier : identifier;
|
|
1499
|
-
}
|
|
1500
|
-
// Switch to verification panel
|
|
1501
|
-
this.showVerificationPanel();
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
catch (error) {
|
|
1505
|
-
this.showError(error instanceof Error ? error.message : this.t('failedToSendCode'));
|
|
1506
|
-
}
|
|
1507
|
-
finally {
|
|
1508
|
-
this.hideLoading();
|
|
1509
|
-
sendCodeBtn.disabled = false;
|
|
1510
|
-
}
|
|
1511
|
-
}
|
|
1512
|
-
/**
|
|
1513
|
-
* Handle verify button click
|
|
1514
|
-
*/
|
|
1515
|
-
async onVerifyClicked() {
|
|
1516
|
-
var _a;
|
|
1517
|
-
this.clearError('verify');
|
|
1518
|
-
// Get code from VanillaOTP instance or fallback to manual collection
|
|
1519
|
-
let code = '';
|
|
1520
|
-
if (this.otpInstance) {
|
|
1521
|
-
code = this.otpInstance.getValue().replace(/\s/g, ''); // Remove spaces
|
|
1522
|
-
}
|
|
1523
|
-
else {
|
|
1524
|
-
const codeInputs = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.playkit-code-input');
|
|
1525
|
-
code = Array.from(codeInputs).map((input) => input.value).join('');
|
|
1526
|
-
}
|
|
1527
|
-
if (code.length !== 6 || !/^\d{6}$/.test(code)) {
|
|
1528
|
-
this.showError(this.t('enterAllDigits'), 'verify');
|
|
1529
|
-
return;
|
|
1530
|
-
}
|
|
1531
|
-
this.showLoading();
|
|
1532
|
-
try {
|
|
1533
|
-
const globalToken = await this.verifyCode(code);
|
|
1534
|
-
this.emit('success', globalToken);
|
|
1535
|
-
}
|
|
1536
|
-
catch (error) {
|
|
1537
|
-
this.showError(error instanceof Error ? error.message : this.t('verificationFailed'), 'verify');
|
|
1538
|
-
this.hideLoading();
|
|
1539
|
-
}
|
|
1540
|
-
}
|
|
1541
|
-
/**
|
|
1542
|
-
* Send verification code to backend
|
|
1543
|
-
*/
|
|
1544
|
-
async sendVerificationCode(identifier, type) {
|
|
1545
|
-
const response = await fetch(`${this.baseURL}/api/auth/send-code`, {
|
|
1546
|
-
method: 'POST',
|
|
1547
|
-
headers: Object.assign({ 'Content-Type': 'application/json' }, getSDKHeaders()),
|
|
1548
|
-
body: JSON.stringify({ identifier, type }),
|
|
1549
|
-
});
|
|
1550
|
-
if (!response.ok) {
|
|
1551
|
-
throw new PlayKitError(this.t('failedToSendCode'), 'SEND_CODE_ERROR', response.status);
|
|
1552
|
-
}
|
|
1553
|
-
const data = await response.json();
|
|
1554
|
-
if (!data.success || !data.sessionId) {
|
|
1555
|
-
throw new PlayKitError(this.t('failedToSendCode'), 'INVALID_RESPONSE');
|
|
1556
|
-
}
|
|
1557
|
-
this.currentSessionId = data.sessionId;
|
|
1558
|
-
return true;
|
|
1559
|
-
}
|
|
1560
|
-
/**
|
|
1561
|
-
* Verify the code and get global token
|
|
1562
|
-
*/
|
|
1563
|
-
async verifyCode(code) {
|
|
1564
|
-
if (!this.currentSessionId) {
|
|
1565
|
-
throw new PlayKitError('No session ID available', 'NO_SESSION');
|
|
1566
|
-
}
|
|
1567
|
-
const response = await fetch(`${this.baseURL}/api/auth/verify-code`, {
|
|
1568
|
-
method: 'POST',
|
|
1569
|
-
headers: Object.assign({ 'Content-Type': 'application/json' }, getSDKHeaders()),
|
|
1570
|
-
body: JSON.stringify({
|
|
1571
|
-
sessionId: this.currentSessionId,
|
|
1572
|
-
code,
|
|
1573
|
-
}),
|
|
1574
|
-
});
|
|
1575
|
-
if (!response.ok) {
|
|
1576
|
-
throw new PlayKitError(this.t('invalidCode'), 'INVALID_CODE', response.status);
|
|
1577
|
-
}
|
|
1578
|
-
const data = await response.json();
|
|
1579
|
-
if (!data.success || !data.globalToken) {
|
|
1580
|
-
throw new PlayKitError(this.t('verificationFailed'), 'VERIFICATION_FAILED');
|
|
1581
|
-
}
|
|
1582
|
-
return data.globalToken;
|
|
1583
|
-
}
|
|
1584
|
-
/**
|
|
1585
|
-
* Set default auth type based on user region
|
|
1586
|
-
*/
|
|
1587
|
-
async setDefaultAuthTypeByRegion() {
|
|
1588
|
-
var _a;
|
|
1589
|
-
try {
|
|
1590
|
-
const response = await fetch(`${this.baseURL}/api/reachability`, {
|
|
1591
|
-
headers: Object.assign({}, getSDKHeaders()),
|
|
1592
|
-
});
|
|
1593
|
-
if (response.ok) {
|
|
1594
|
-
const data = await response.json();
|
|
1595
|
-
if (data.region === 'CN') {
|
|
1596
|
-
const phoneRadio = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('input[value="phone"]');
|
|
1597
|
-
if (phoneRadio) {
|
|
1598
|
-
phoneRadio.checked = true;
|
|
1599
|
-
phoneRadio.dispatchEvent(new Event('change'));
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
}
|
|
1604
|
-
catch (error) {
|
|
1605
|
-
console.error('[PlayKit Auth] Failed to detect region:', error);
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
/**
|
|
1609
|
-
* Show/hide panels
|
|
1610
|
-
*/
|
|
1611
|
-
showIdentifierPanel() {
|
|
1612
|
-
var _a;
|
|
1613
|
-
if (this.identifierPanel)
|
|
1614
|
-
this.identifierPanel.style.display = 'block';
|
|
1615
|
-
if (this.verificationPanel)
|
|
1616
|
-
this.verificationPanel.style.display = 'none';
|
|
1617
|
-
// Clear code inputs
|
|
1618
|
-
if (this.otpInstance) {
|
|
1619
|
-
this.otpInstance.setValue(''); // Clear all inputs using VanillaOTP
|
|
1620
|
-
}
|
|
1621
|
-
else {
|
|
1622
|
-
const codeInputs = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.playkit-code-input');
|
|
1623
|
-
codeInputs === null || codeInputs === void 0 ? void 0 : codeInputs.forEach((input) => (input.value = ''));
|
|
1624
|
-
}
|
|
1625
|
-
}
|
|
1626
|
-
showVerificationPanel() {
|
|
1627
|
-
var _a;
|
|
1628
|
-
if (this.identifierPanel)
|
|
1629
|
-
this.identifierPanel.style.display = 'none';
|
|
1630
|
-
if (this.verificationPanel)
|
|
1631
|
-
this.verificationPanel.style.display = 'block';
|
|
1632
|
-
// Focus first code input
|
|
1633
|
-
const firstInput = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('.playkit-code-input');
|
|
1634
|
-
firstInput === null || firstInput === void 0 ? void 0 : firstInput.focus();
|
|
1635
|
-
}
|
|
1636
|
-
/**
|
|
1637
|
-
* Show/hide loading
|
|
1638
|
-
*/
|
|
1639
|
-
showLoading() {
|
|
1640
|
-
if (this.loadingOverlay)
|
|
1641
|
-
this.loadingOverlay.style.display = 'flex';
|
|
1642
|
-
}
|
|
1643
|
-
hideLoading() {
|
|
1644
|
-
if (this.loadingOverlay)
|
|
1645
|
-
this.loadingOverlay.style.display = 'none';
|
|
1646
|
-
}
|
|
1647
|
-
/**
|
|
1648
|
-
* Show/hide error messages
|
|
1649
|
-
*/
|
|
1650
|
-
showError(message, panel = 'identifier') {
|
|
1651
|
-
const errorEl = panel === 'identifier'
|
|
1652
|
-
? document.getElementById('playkit-error-text')
|
|
1653
|
-
: document.getElementById('playkit-verify-error-text');
|
|
1654
|
-
if (errorEl) {
|
|
1655
|
-
errorEl.textContent = message;
|
|
1656
|
-
errorEl.classList.add('show');
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
clearError(panel = 'both') {
|
|
1660
|
-
if (panel === 'identifier' || panel === 'both') {
|
|
1661
|
-
const errorEl = document.getElementById('playkit-error-text');
|
|
1662
|
-
if (errorEl) {
|
|
1663
|
-
errorEl.textContent = '';
|
|
1664
|
-
errorEl.classList.remove('show');
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
if (panel === 'verify' || panel === 'both') {
|
|
1668
|
-
const errorEl = document.getElementById('playkit-verify-error-text');
|
|
1669
|
-
if (errorEl) {
|
|
1670
|
-
errorEl.textContent = '';
|
|
1671
|
-
errorEl.classList.remove('show');
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
/**
|
|
1676
|
-
* Show/hide modal
|
|
1677
|
-
*/
|
|
1678
|
-
showModal() {
|
|
1679
|
-
if (this.modal)
|
|
1680
|
-
this.modal.style.display = 'flex';
|
|
1681
|
-
}
|
|
1682
|
-
hideModal() {
|
|
1683
|
-
if (this.modal) {
|
|
1684
|
-
this.modal.style.display = 'none';
|
|
1685
|
-
// Remove from DOM after animation
|
|
1686
|
-
setTimeout(() => {
|
|
1687
|
-
var _a;
|
|
1688
|
-
(_a = this.modal) === null || _a === void 0 ? void 0 : _a.remove();
|
|
1689
|
-
}, 300);
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
/**
|
|
1693
|
-
* Clean up
|
|
1694
|
-
*/
|
|
1695
|
-
destroy() {
|
|
1696
|
-
var _a;
|
|
1697
|
-
(_a = this.modal) === null || _a === void 0 ? void 0 : _a.remove();
|
|
1698
|
-
this.removeAllListeners();
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
883
|
/**
|
|
1703
884
|
* Device Authorization Flow Manager
|
|
1704
885
|
* Manages Device Auth polling flow for desktop/CLI/Unity applications
|
|
@@ -2072,14 +1253,12 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2072
1253
|
// Store the flow promise so subsequent calls can await the same result
|
|
2073
1254
|
const flowPromise = this.executeFlow(options);
|
|
2074
1255
|
DeviceAuthFlowManager.currentFlowPromise = flowPromise;
|
|
2075
|
-
DeviceAuthFlowManager.activeInstance = this;
|
|
2076
1256
|
try {
|
|
2077
1257
|
return await flowPromise;
|
|
2078
1258
|
}
|
|
2079
1259
|
finally {
|
|
2080
1260
|
// Clean up static state when flow completes (success or failure)
|
|
2081
1261
|
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2082
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2083
1262
|
}
|
|
2084
1263
|
}
|
|
2085
1264
|
/**
|
|
@@ -2418,8 +1597,6 @@ class DeviceAuthFlowManager extends EventEmitter {
|
|
|
2418
1597
|
}
|
|
2419
1598
|
/** Shared promise for the current flow - allows multiple callers to await the same result */
|
|
2420
1599
|
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2421
|
-
/** Reference to the currently active instance */
|
|
2422
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2423
1600
|
|
|
2424
1601
|
/**
|
|
2425
1602
|
* Authentication manager
|
|
@@ -2427,12 +1604,10 @@ DeviceAuthFlowManager.activeInstance = null;
|
|
|
2427
1604
|
*/
|
|
2428
1605
|
// @ts-ignore - replaced at build time
|
|
2429
1606
|
const DEFAULT_BASE_URL$6 = "https://api.playkit.ai";
|
|
2430
|
-
const JWT_EXCHANGE_ENDPOINT = '/api/external/exchange-jwt';
|
|
2431
1607
|
const TOKEN_REFRESH_ENDPOINT = '/api/auth/refresh';
|
|
2432
1608
|
class AuthManager extends EventEmitter {
|
|
2433
1609
|
constructor(config) {
|
|
2434
1610
|
super();
|
|
2435
|
-
this.authFlowManager = null;
|
|
2436
1611
|
this.deviceAuthFlowManager = null;
|
|
2437
1612
|
this.logger = Logger.getLogger('AuthManager');
|
|
2438
1613
|
/** Shared promise for current device auth flow - allows multiple callers to await the same result */
|
|
@@ -2500,11 +1675,6 @@ class AuthManager extends EventEmitter {
|
|
|
2500
1675
|
}
|
|
2501
1676
|
}
|
|
2502
1677
|
}
|
|
2503
|
-
// Check if player JWT was provided
|
|
2504
|
-
if (this.config.playerJWT) {
|
|
2505
|
-
await this.exchangeJWT(this.config.playerJWT);
|
|
2506
|
-
return;
|
|
2507
|
-
}
|
|
2508
1678
|
// Check for platform-injected token (same-domain scenario)
|
|
2509
1679
|
// This allows seamless auth when SDK runs in a context where the platform
|
|
2510
1680
|
// (e.g., Agentland-Space) has already stored a token in localStorage
|
|
@@ -2525,35 +1695,30 @@ class AuthManager extends EventEmitter {
|
|
|
2525
1695
|
this.emit('unauthenticated');
|
|
2526
1696
|
// In server mode, don't try to show UI - just throw error
|
|
2527
1697
|
if (this.config.mode === 'server') {
|
|
2528
|
-
throw new PlayKitError('No authentication token provided. In server mode, please provide developerToken
|
|
1698
|
+
throw new PlayKitError('No authentication token provided. In server mode, please provide developerToken or playerToken.', 'NOT_AUTHENTICATED');
|
|
2529
1699
|
}
|
|
2530
1700
|
// Auto-start login flow in browser environment
|
|
2531
1701
|
if (typeof window !== 'undefined') {
|
|
2532
|
-
|
|
2533
|
-
const authMethod = this.config.authMethod || 'device';
|
|
2534
|
-
await this.startAuthFlow(authMethod);
|
|
1702
|
+
await this.startAuthFlow();
|
|
2535
1703
|
// If we reach here, authentication was successful
|
|
2536
1704
|
// If it failed, startAuthFlow() will have thrown an error
|
|
2537
1705
|
}
|
|
2538
1706
|
else {
|
|
2539
1707
|
// Node.js environment - cannot show UI, must provide token manually
|
|
2540
|
-
throw new PlayKitError('No authentication token provided. Please provide developerToken
|
|
1708
|
+
throw new PlayKitError('No authentication token provided. Please provide developerToken or playerToken.', 'NOT_AUTHENTICATED');
|
|
2541
1709
|
}
|
|
2542
1710
|
}
|
|
2543
1711
|
/**
|
|
2544
|
-
* Start the authentication flow
|
|
2545
|
-
*
|
|
2546
|
-
* @param authMethod - Authentication method to use ('device' or 'headless')
|
|
2547
|
-
* @deprecated 'headless' authentication is deprecated and will be removed in v2.0. Use 'device' instead.
|
|
1712
|
+
* Start the authentication flow (Device Authorization + PKCE).
|
|
2548
1713
|
*/
|
|
2549
|
-
async startAuthFlow(
|
|
1714
|
+
async startAuthFlow() {
|
|
2550
1715
|
// If a flow is already in progress, return the shared promise so all callers await the same result
|
|
2551
1716
|
if (this.currentAuthFlowPromise) {
|
|
2552
1717
|
this.logger.debug('Auth flow already in progress, waiting for existing flow');
|
|
2553
1718
|
return this.currentAuthFlowPromise;
|
|
2554
1719
|
}
|
|
2555
1720
|
// Store the flow promise so subsequent calls can await the same result
|
|
2556
|
-
const flowPromise = this.executeAuthFlow(
|
|
1721
|
+
const flowPromise = this.executeAuthFlow();
|
|
2557
1722
|
this.currentAuthFlowPromise = flowPromise;
|
|
2558
1723
|
try {
|
|
2559
1724
|
return await flowPromise;
|
|
@@ -2563,96 +1728,38 @@ class AuthManager extends EventEmitter {
|
|
|
2563
1728
|
}
|
|
2564
1729
|
}
|
|
2565
1730
|
/**
|
|
2566
|
-
* Internal method that executes the
|
|
1731
|
+
* Internal method that executes the Device Authorization flow.
|
|
2567
1732
|
* @private
|
|
2568
1733
|
*/
|
|
2569
|
-
async executeAuthFlow(
|
|
2570
|
-
var _a
|
|
2571
|
-
// Deprecation warning for headless auth
|
|
2572
|
-
if (authMethod === 'headless') {
|
|
2573
|
-
this.logger.warn('"headless" authentication is deprecated and will be removed in v2.0. ' +
|
|
2574
|
-
'Please migrate to "device" authentication.');
|
|
2575
|
-
}
|
|
2576
|
-
try {
|
|
2577
|
-
if (authMethod === 'device') {
|
|
2578
|
-
// Use Device Authorization flow (recommended)
|
|
2579
|
-
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
2580
|
-
const result = await this.deviceAuthFlowManager.startFlow({
|
|
2581
|
-
scope: 'player:play',
|
|
2582
|
-
});
|
|
2583
|
-
// Update auth state with the player token and refresh token
|
|
2584
|
-
this.authState = {
|
|
2585
|
-
isAuthenticated: true,
|
|
2586
|
-
token: result.access_token,
|
|
2587
|
-
tokenType: 'player',
|
|
2588
|
-
expiresAt: Date.now() + result.expires_in * 1000,
|
|
2589
|
-
refreshToken: result.refresh_token,
|
|
2590
|
-
refreshExpiresAt: Date.now() + result.refresh_expires_in * 1000,
|
|
2591
|
-
};
|
|
2592
|
-
// Save to storage
|
|
2593
|
-
await this.storage.saveAuthState(this.config.gameId, this.authState);
|
|
2594
|
-
this.emit('authenticated', this.authState);
|
|
2595
|
-
// Clean up
|
|
2596
|
-
this.deviceAuthFlowManager.destroy();
|
|
2597
|
-
this.deviceAuthFlowManager = null;
|
|
2598
|
-
}
|
|
2599
|
-
else {
|
|
2600
|
-
// Use headless verification code flow
|
|
2601
|
-
this.authFlowManager = new AuthFlowManager(this.baseURL);
|
|
2602
|
-
// Get global token from auth flow
|
|
2603
|
-
const globalToken = await this.authFlowManager.startFlow();
|
|
2604
|
-
// Exchange for player token
|
|
2605
|
-
await this.exchangeJWT(globalToken);
|
|
2606
|
-
// Clean up
|
|
2607
|
-
this.authFlowManager.destroy();
|
|
2608
|
-
this.authFlowManager = null;
|
|
2609
|
-
}
|
|
2610
|
-
}
|
|
2611
|
-
catch (error) {
|
|
2612
|
-
// User canceled or error occurred
|
|
2613
|
-
(_a = this.authFlowManager) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
2614
|
-
this.authFlowManager = null;
|
|
2615
|
-
(_b = this.deviceAuthFlowManager) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
2616
|
-
this.deviceAuthFlowManager = null;
|
|
2617
|
-
// Re-emit error
|
|
2618
|
-
this.emit('error', error);
|
|
2619
|
-
throw error;
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
/**
|
|
2623
|
-
* Exchange JWT for player token
|
|
2624
|
-
*/
|
|
2625
|
-
async exchangeJWT(jwt) {
|
|
1734
|
+
async executeAuthFlow() {
|
|
1735
|
+
var _a;
|
|
2626
1736
|
try {
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
1737
|
+
// Device Authorization flow with PKCE — the only login flow.
|
|
1738
|
+
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
1739
|
+
const result = await this.deviceAuthFlowManager.startFlow({
|
|
1740
|
+
scope: 'player:play',
|
|
2631
1741
|
});
|
|
2632
|
-
|
|
2633
|
-
const error = await response.json().catch(() => ({ message: 'JWT exchange failed' }));
|
|
2634
|
-
throw new PlayKitError(error.message || 'JWT exchange failed', error.code, response.status);
|
|
2635
|
-
}
|
|
2636
|
-
const data = await response.json();
|
|
2637
|
-
const playerToken = data.playerToken || data.token;
|
|
2638
|
-
if (!playerToken) {
|
|
2639
|
-
throw new PlayKitError('No player token received from server');
|
|
2640
|
-
}
|
|
2641
|
-
// Calculate expiration (assume 24 hours if not provided)
|
|
2642
|
-
const expiresIn = data.expiresIn || 86400;
|
|
2643
|
-
const expiresAt = Date.now() + expiresIn * 1000;
|
|
1742
|
+
// Update auth state with the player token and refresh token
|
|
2644
1743
|
this.authState = {
|
|
2645
1744
|
isAuthenticated: true,
|
|
2646
|
-
token:
|
|
1745
|
+
token: result.access_token,
|
|
2647
1746
|
tokenType: 'player',
|
|
2648
|
-
expiresAt,
|
|
1747
|
+
expiresAt: Date.now() + result.expires_in * 1000,
|
|
1748
|
+
refreshToken: result.refresh_token,
|
|
1749
|
+
refreshExpiresAt: Date.now() + result.refresh_expires_in * 1000,
|
|
2649
1750
|
};
|
|
2650
1751
|
// Save to storage
|
|
2651
1752
|
await this.storage.saveAuthState(this.config.gameId, this.authState);
|
|
2652
1753
|
this.emit('authenticated', this.authState);
|
|
2653
|
-
|
|
1754
|
+
// Clean up
|
|
1755
|
+
this.deviceAuthFlowManager.destroy();
|
|
1756
|
+
this.deviceAuthFlowManager = null;
|
|
2654
1757
|
}
|
|
2655
1758
|
catch (error) {
|
|
1759
|
+
// User canceled or error occurred
|
|
1760
|
+
(_a = this.deviceAuthFlowManager) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
1761
|
+
this.deviceAuthFlowManager = null;
|
|
1762
|
+
// Re-emit error
|
|
2656
1763
|
this.emit('error', error);
|
|
2657
1764
|
throw error;
|
|
2658
1765
|
}
|
|
@@ -2902,7 +2009,7 @@ class AuthManager extends EventEmitter {
|
|
|
2902
2009
|
* Check if an authentication flow is currently in progress
|
|
2903
2010
|
*/
|
|
2904
2011
|
isAuthFlowInProgress() {
|
|
2905
|
-
return !!
|
|
2012
|
+
return !!this.deviceAuthFlowManager;
|
|
2906
2013
|
}
|
|
2907
2014
|
/**
|
|
2908
2015
|
* Poll for authorization token after initiateDeviceAuth().
|
|
@@ -3823,6 +2930,11 @@ const VALID_PART_TYPES = new Set([
|
|
|
3823
2930
|
'file',
|
|
3824
2931
|
'audio',
|
|
3825
2932
|
'input_audio',
|
|
2933
|
+
'reasoning',
|
|
2934
|
+
'tool-call',
|
|
2935
|
+
'tool-result',
|
|
2936
|
+
'tool-approval-request',
|
|
2937
|
+
'tool-approval-response',
|
|
3826
2938
|
]);
|
|
3827
2939
|
function describePart(part) {
|
|
3828
2940
|
if (part === null)
|
|
@@ -3865,13 +2977,13 @@ function assertValidMessages(messages) {
|
|
|
3865
2977
|
if (!hasType) {
|
|
3866
2978
|
if ('role' in part && 'content' in part) {
|
|
3867
2979
|
throw new PlayKitError(`messages[${i}].content[${j}] is shaped like a Message (has role/content) ` +
|
|
3868
|
-
`but content parts must
|
|
2980
|
+
`but content parts must include a recognized 'type' field. ` +
|
|
3869
2981
|
`Did you mean to pass that array as messages directly? ` +
|
|
3870
2982
|
`e.g. \`messages: theArray\` instead of \`messages: [{role:'user', content: theArray}]\`. ` +
|
|
3871
2983
|
`Got part ${describePart(part)}`, 'INVALID_MESSAGES');
|
|
3872
2984
|
}
|
|
3873
2985
|
throw new PlayKitError(`messages[${i}].content[${j}] is missing a recognized 'type' field ` +
|
|
3874
|
-
`(expected one of
|
|
2986
|
+
`(expected one of ${Array.from(VALID_PART_TYPES).join('|')}). Got part ${describePart(part)}`, 'INVALID_MESSAGES');
|
|
3875
2987
|
}
|
|
3876
2988
|
}
|
|
3877
2989
|
}
|
|
@@ -3906,6 +3018,38 @@ class ChatProvider {
|
|
|
3906
3018
|
setPlayerClient(playerClient) {
|
|
3907
3019
|
this.playerClient = playerClient;
|
|
3908
3020
|
}
|
|
3021
|
+
/**
|
|
3022
|
+
* Resolve the `thinking` payload to send on the wire.
|
|
3023
|
+
*
|
|
3024
|
+
* Resolution order for effort: per-request `thinking.effort` > SDK-level
|
|
3025
|
+
* `defaultThinkingEffort` > omit (the server then defaults to off). This
|
|
3026
|
+
* mirrors how the chat model resolves (`chatConfig.model || defaultChatModel`).
|
|
3027
|
+
*
|
|
3028
|
+
* The deprecated `enabled` flag is preserved as an alias: when no effort can be
|
|
3029
|
+
* resolved, `enabled: false` maps to `{ effort: 'off' }` and `enabled: true`
|
|
3030
|
+
* maps to `{ effort: 'minimal' }`.
|
|
3031
|
+
*
|
|
3032
|
+
* @returns The `{ effort }` (and/or `enabled`) object to assign to
|
|
3033
|
+
* `requestBody.thinking`, or `undefined` to send nothing.
|
|
3034
|
+
*/
|
|
3035
|
+
resolveThinking(chatConfig) {
|
|
3036
|
+
const thinking = chatConfig.thinking;
|
|
3037
|
+
// Precedence: per-request `effort` > per-request `enabled` alias > SDK-level
|
|
3038
|
+
// `defaultThinkingEffort` > omit (server then defaults to off). The `enabled`
|
|
3039
|
+
// alias MUST be checked BEFORE the SDK default, so an explicit per-request
|
|
3040
|
+
// `enabled: false` is never overridden by a configured default effort.
|
|
3041
|
+
if (thinking === null || thinking === void 0 ? void 0 : thinking.effort) {
|
|
3042
|
+
return { effort: thinking.effort };
|
|
3043
|
+
}
|
|
3044
|
+
if ((thinking === null || thinking === void 0 ? void 0 : thinking.enabled) !== undefined) {
|
|
3045
|
+
return { effort: thinking.enabled ? 'minimal' : 'off' };
|
|
3046
|
+
}
|
|
3047
|
+
if (this.config.defaultThinkingEffort) {
|
|
3048
|
+
return { effort: this.config.defaultThinkingEffort };
|
|
3049
|
+
}
|
|
3050
|
+
// Nothing to send — server defaults to off.
|
|
3051
|
+
return undefined;
|
|
3052
|
+
}
|
|
3909
3053
|
/**
|
|
3910
3054
|
* Make a chat completion request (non-streaming)
|
|
3911
3055
|
*/
|
|
@@ -3930,8 +3074,9 @@ class ChatProvider {
|
|
|
3930
3074
|
stop: chatConfig.stop || null,
|
|
3931
3075
|
top_p: chatConfig.topP || null,
|
|
3932
3076
|
};
|
|
3933
|
-
|
|
3934
|
-
|
|
3077
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3078
|
+
if (thinking) {
|
|
3079
|
+
requestBody.thinking = thinking;
|
|
3935
3080
|
}
|
|
3936
3081
|
try {
|
|
3937
3082
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -3990,8 +3135,9 @@ class ChatProvider {
|
|
|
3990
3135
|
stop: chatConfig.stop || null,
|
|
3991
3136
|
top_p: chatConfig.topP || null,
|
|
3992
3137
|
};
|
|
3993
|
-
|
|
3994
|
-
|
|
3138
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3139
|
+
if (thinking) {
|
|
3140
|
+
requestBody.thinking = thinking;
|
|
3995
3141
|
}
|
|
3996
3142
|
try {
|
|
3997
3143
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -4057,8 +3203,9 @@ class ChatProvider {
|
|
|
4057
3203
|
if (chatConfig.tool_choice) {
|
|
4058
3204
|
requestBody.tool_choice = chatConfig.tool_choice;
|
|
4059
3205
|
}
|
|
4060
|
-
|
|
4061
|
-
|
|
3206
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3207
|
+
if (thinking) {
|
|
3208
|
+
requestBody.thinking = thinking;
|
|
4062
3209
|
}
|
|
4063
3210
|
try {
|
|
4064
3211
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -4118,8 +3265,9 @@ class ChatProvider {
|
|
|
4118
3265
|
if (chatConfig.tool_choice) {
|
|
4119
3266
|
requestBody.tool_choice = chatConfig.tool_choice;
|
|
4120
3267
|
}
|
|
4121
|
-
|
|
4122
|
-
|
|
3268
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3269
|
+
if (thinking) {
|
|
3270
|
+
requestBody.thinking = thinking;
|
|
4123
3271
|
}
|
|
4124
3272
|
try {
|
|
4125
3273
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -4504,6 +3652,25 @@ class TTSProvider {
|
|
|
4504
3652
|
}
|
|
4505
3653
|
return response;
|
|
4506
3654
|
}
|
|
3655
|
+
/** GET a TTS endpoint; throws a PlayKitError on a non-ok response. */
|
|
3656
|
+
async get(endpoint) {
|
|
3657
|
+
await this.authManager.ensureValidToken();
|
|
3658
|
+
const token = this.authManager.getToken();
|
|
3659
|
+
if (!token) {
|
|
3660
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
3661
|
+
}
|
|
3662
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
3663
|
+
method: 'GET',
|
|
3664
|
+
headers: Object.assign({ Authorization: `Bearer ${token}` }, getSDKHeaders()),
|
|
3665
|
+
});
|
|
3666
|
+
if (!response.ok) {
|
|
3667
|
+
const error = await response
|
|
3668
|
+
.json()
|
|
3669
|
+
.catch(() => ({ message: 'Request failed' }));
|
|
3670
|
+
throw new PlayKitError(error.message || 'Request failed', error.code, response.status);
|
|
3671
|
+
}
|
|
3672
|
+
return response;
|
|
3673
|
+
}
|
|
4507
3674
|
checkBalanceAfter() {
|
|
4508
3675
|
if (this.playerClient) {
|
|
4509
3676
|
this.playerClient.checkBalanceAfterApiCall().catch(() => {
|
|
@@ -4588,6 +3755,39 @@ class TTSProvider {
|
|
|
4588
3755
|
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'TTS_ERROR');
|
|
4589
3756
|
}
|
|
4590
3757
|
}
|
|
3758
|
+
/**
|
|
3759
|
+
* List the voices available for speech synthesis.
|
|
3760
|
+
*/
|
|
3761
|
+
async listVoices() {
|
|
3762
|
+
var _a;
|
|
3763
|
+
const endpoint = `/ai/${this.config.gameId}/v2/audio/voices`;
|
|
3764
|
+
try {
|
|
3765
|
+
const response = await this.get(endpoint);
|
|
3766
|
+
const json = (await response.json());
|
|
3767
|
+
const voices = ((_a = json.voices) !== null && _a !== void 0 ? _a : []).map((v) => {
|
|
3768
|
+
const voice = {
|
|
3769
|
+
voiceId: v.voice_id,
|
|
3770
|
+
kind: v.kind === 'custom' ? 'custom' : 'system',
|
|
3771
|
+
};
|
|
3772
|
+
if (v.name !== undefined)
|
|
3773
|
+
voice.name = v.name;
|
|
3774
|
+
if (v.description !== undefined)
|
|
3775
|
+
voice.description = v.description;
|
|
3776
|
+
if (v.language !== undefined)
|
|
3777
|
+
voice.language = v.language;
|
|
3778
|
+
return voice;
|
|
3779
|
+
});
|
|
3780
|
+
return {
|
|
3781
|
+
voices,
|
|
3782
|
+
total: Number(json.total) || voices.length,
|
|
3783
|
+
};
|
|
3784
|
+
}
|
|
3785
|
+
catch (error) {
|
|
3786
|
+
if (error instanceof PlayKitError)
|
|
3787
|
+
throw error;
|
|
3788
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'TTS_ERROR');
|
|
3789
|
+
}
|
|
3790
|
+
}
|
|
4591
3791
|
}
|
|
4592
3792
|
|
|
4593
3793
|
/******************************************************************************
|
|
@@ -5145,14 +4345,14 @@ class ImageClient {
|
|
|
5145
4345
|
* Generate a single image
|
|
5146
4346
|
*/
|
|
5147
4347
|
async generateImage(config) {
|
|
5148
|
-
var _a;
|
|
4348
|
+
var _a, _b;
|
|
5149
4349
|
const imageConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model, n: 1 });
|
|
5150
4350
|
const response = await this.provider.generateImages(imageConfig);
|
|
5151
4351
|
const imageData = response.data[0];
|
|
5152
4352
|
if (!imageData || !imageData.b64_json) {
|
|
5153
4353
|
throw new Error('No image data in response');
|
|
5154
4354
|
}
|
|
5155
|
-
return new GeneratedImageImpl(imageData.b64_json, config.prompt, (
|
|
4355
|
+
return new GeneratedImageImpl(imageData.b64_json, (_a = config.prompt) !== null && _a !== void 0 ? _a : '', (_b = imageData.revised_prompt) !== null && _b !== void 0 ? _b : config.prompt, config.size, imageData.b64_json_original, imageData.transparent_success);
|
|
5156
4356
|
}
|
|
5157
4357
|
/**
|
|
5158
4358
|
* Generate multiple images
|
|
@@ -5161,11 +4361,11 @@ class ImageClient {
|
|
|
5161
4361
|
const imageConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model, n: config.n || 1 });
|
|
5162
4362
|
const response = await this.provider.generateImages(imageConfig);
|
|
5163
4363
|
return response.data.map((imageData) => {
|
|
5164
|
-
var _a;
|
|
4364
|
+
var _a, _b;
|
|
5165
4365
|
if (!imageData.b64_json) {
|
|
5166
4366
|
throw new Error('No image data in response');
|
|
5167
4367
|
}
|
|
5168
|
-
return new GeneratedImageImpl(imageData.b64_json, config.prompt, (
|
|
4368
|
+
return new GeneratedImageImpl(imageData.b64_json, (_a = config.prompt) !== null && _a !== void 0 ? _a : '', (_b = imageData.revised_prompt) !== null && _b !== void 0 ? _b : config.prompt, config.size, imageData.b64_json_original, imageData.transparent_success);
|
|
5169
4369
|
});
|
|
5170
4370
|
}
|
|
5171
4371
|
/**
|
|
@@ -5340,6 +4540,13 @@ class TTSClient {
|
|
|
5340
4540
|
async synthesizeWithTimestamps(config) {
|
|
5341
4541
|
return this.provider.synthesizeWithTimestamps(Object.assign(Object.assign({}, config), { model: config.model || this.model }));
|
|
5342
4542
|
}
|
|
4543
|
+
/**
|
|
4544
|
+
* List the voices available for speech synthesis
|
|
4545
|
+
* @returns The available voices and a total count
|
|
4546
|
+
*/
|
|
4547
|
+
async listVoices() {
|
|
4548
|
+
return this.provider.listVoices();
|
|
4549
|
+
}
|
|
5343
4550
|
/**
|
|
5344
4551
|
* Synthesize text into speech and return it as a Blob (browser-friendly)
|
|
5345
4552
|
* @param config - Full TTS configuration
|
|
@@ -6213,12 +5420,8 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
6213
5420
|
}));
|
|
6214
5421
|
response.hasActions = response.actionCalls.length > 0;
|
|
6215
5422
|
}
|
|
6216
|
-
// Add assistant response to history
|
|
6217
|
-
const assistantMessage =
|
|
6218
|
-
role: 'assistant',
|
|
6219
|
-
content: response.text,
|
|
6220
|
-
tool_calls: result.tool_calls,
|
|
6221
|
-
};
|
|
5423
|
+
// Add assistant response to history in canonical PlayKit format.
|
|
5424
|
+
const assistantMessage = this.createAssistantHistoryMessage(response.text, result.tool_calls);
|
|
6222
5425
|
this.history.push(assistantMessage);
|
|
6223
5426
|
this.trimHistory();
|
|
6224
5427
|
this.emit('response', response.text);
|
|
@@ -6276,12 +5479,8 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
6276
5479
|
}));
|
|
6277
5480
|
response.hasActions = response.actionCalls.length > 0;
|
|
6278
5481
|
}
|
|
6279
|
-
// Add assistant response to history
|
|
6280
|
-
const assistantMessage =
|
|
6281
|
-
role: 'assistant',
|
|
6282
|
-
content: response.text,
|
|
6283
|
-
tool_calls: result.tool_calls,
|
|
6284
|
-
};
|
|
5482
|
+
// Add assistant response to history in canonical PlayKit format.
|
|
5483
|
+
const assistantMessage = this.createAssistantHistoryMessage(response.text, result.tool_calls);
|
|
6285
5484
|
this.history.push(assistantMessage);
|
|
6286
5485
|
this.trimHistory();
|
|
6287
5486
|
this.emit('response', response.text);
|
|
@@ -6308,22 +5507,64 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
6308
5507
|
*/
|
|
6309
5508
|
reportActionResults(results) {
|
|
6310
5509
|
for (const [callId, result] of Object.entries(results)) {
|
|
6311
|
-
this.history.push(
|
|
6312
|
-
role: 'tool',
|
|
6313
|
-
tool_call_id: callId,
|
|
6314
|
-
content: result,
|
|
6315
|
-
});
|
|
5510
|
+
this.history.push(this.createToolResultHistoryMessage(callId, result));
|
|
6316
5511
|
}
|
|
6317
5512
|
}
|
|
6318
5513
|
/**
|
|
6319
5514
|
* Report a single action result
|
|
6320
5515
|
*/
|
|
6321
5516
|
reportActionResult(callId, result) {
|
|
6322
|
-
this.history.push(
|
|
5517
|
+
this.history.push(this.createToolResultHistoryMessage(callId, result));
|
|
5518
|
+
}
|
|
5519
|
+
createAssistantHistoryMessage(text, toolCalls) {
|
|
5520
|
+
if (!toolCalls || toolCalls.length === 0) {
|
|
5521
|
+
return { role: 'assistant', content: text };
|
|
5522
|
+
}
|
|
5523
|
+
const content = [];
|
|
5524
|
+
if (text) {
|
|
5525
|
+
content.push({ type: 'text', text });
|
|
5526
|
+
}
|
|
5527
|
+
content.push(...toolCalls.map(createToolCallContentPart));
|
|
5528
|
+
return {
|
|
5529
|
+
role: 'assistant',
|
|
5530
|
+
content,
|
|
5531
|
+
};
|
|
5532
|
+
}
|
|
5533
|
+
createToolResultHistoryMessage(callId, result) {
|
|
5534
|
+
const toolName = this.findToolNameForCall(callId);
|
|
5535
|
+
if (!toolName) {
|
|
5536
|
+
// Saved histories from older SDKs may not include enough context to infer
|
|
5537
|
+
// the tool name. Keep the legacy shape; the server normalizer can still
|
|
5538
|
+
// infer it when the matching assistant call is present.
|
|
5539
|
+
return {
|
|
5540
|
+
role: 'tool',
|
|
5541
|
+
tool_call_id: callId,
|
|
5542
|
+
content: result,
|
|
5543
|
+
};
|
|
5544
|
+
}
|
|
5545
|
+
return {
|
|
6323
5546
|
role: 'tool',
|
|
6324
5547
|
tool_call_id: callId,
|
|
6325
|
-
content: result,
|
|
6326
|
-
}
|
|
5548
|
+
content: [createToolResultContentPart(callId, toolName, result)],
|
|
5549
|
+
};
|
|
5550
|
+
}
|
|
5551
|
+
findToolNameForCall(callId) {
|
|
5552
|
+
var _a;
|
|
5553
|
+
for (let i = this.history.length - 1; i >= 0; i--) {
|
|
5554
|
+
const message = this.history[i];
|
|
5555
|
+
if (Array.isArray(message.content)) {
|
|
5556
|
+
for (const part of message.content) {
|
|
5557
|
+
if (part.type === 'tool-call' && part.toolCallId === callId) {
|
|
5558
|
+
return part.toolName;
|
|
5559
|
+
}
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
5562
|
+
const legacyCall = (_a = message.tool_calls) === null || _a === void 0 ? void 0 : _a.find(tc => tc.id === callId);
|
|
5563
|
+
if (legacyCall) {
|
|
5564
|
+
return legacyCall.function.name;
|
|
5565
|
+
}
|
|
5566
|
+
}
|
|
5567
|
+
return undefined;
|
|
6327
5568
|
}
|
|
6328
5569
|
/**
|
|
6329
5570
|
* Parse tool arguments from JSON string
|
|
@@ -6763,8 +6004,7 @@ class PlayKitSDK extends EventEmitter {
|
|
|
6763
6004
|
// Auto-restart login flow in browser environment
|
|
6764
6005
|
if (typeof window !== 'undefined') {
|
|
6765
6006
|
this.logger.debug('Restarting authentication flow...');
|
|
6766
|
-
|
|
6767
|
-
await this.authManager.startAuthFlow(authMethod);
|
|
6007
|
+
await this.authManager.startAuthFlow();
|
|
6768
6008
|
// Retry getting player info after re-authentication
|
|
6769
6009
|
await this.playerClient.getPlayerInfo();
|
|
6770
6010
|
this.logger.debug('Re-authentication successful, token validated');
|
|
@@ -6807,12 +6047,11 @@ class PlayKitSDK extends EventEmitter {
|
|
|
6807
6047
|
throw new PlayKitError('DeveloperToken validation failed: ' + (error instanceof Error ? error.message : String(error)), 'DEVELOPER_TOKEN_INVALID');
|
|
6808
6048
|
}
|
|
6809
6049
|
// Emit fallback started event
|
|
6810
|
-
|
|
6811
|
-
this.
|
|
6812
|
-
this.logger.debug('Starting fallback to player login', { fallbackMethod });
|
|
6050
|
+
this.emit('developer_token_fallback_started', { fallbackMethod: 'device' });
|
|
6051
|
+
this.logger.debug('Starting fallback to player login');
|
|
6813
6052
|
try {
|
|
6814
6053
|
// Start player login flow
|
|
6815
|
-
await this.authManager.startAuthFlow(
|
|
6054
|
+
await this.authManager.startAuthFlow();
|
|
6816
6055
|
// Verify the new token
|
|
6817
6056
|
await this.playerClient.getPlayerInfo();
|
|
6818
6057
|
// Emit fallback completed event
|
|
@@ -6875,24 +6114,6 @@ class PlayKitSDK extends EventEmitter {
|
|
|
6875
6114
|
isAuthenticated() {
|
|
6876
6115
|
return this.authManager.isAuthenticated();
|
|
6877
6116
|
}
|
|
6878
|
-
/**
|
|
6879
|
-
* Exchange JWT for player token
|
|
6880
|
-
*/
|
|
6881
|
-
async login(jwt) {
|
|
6882
|
-
const token = await this.authManager.exchangeJWT(jwt);
|
|
6883
|
-
// Verify token validity and fetch user info
|
|
6884
|
-
try {
|
|
6885
|
-
await this.playerClient.getPlayerInfo();
|
|
6886
|
-
this.logger.debug('Login successful, token validated and user info fetched');
|
|
6887
|
-
}
|
|
6888
|
-
catch (error) {
|
|
6889
|
-
// If token is invalid, logout and re-throw error
|
|
6890
|
-
this.logger.error('Token validation failed after login:', error);
|
|
6891
|
-
await this.authManager.logout();
|
|
6892
|
-
throw new Error('Token validation failed: ' + (error instanceof Error ? error.message : String(error)));
|
|
6893
|
-
}
|
|
6894
|
-
return token;
|
|
6895
|
-
}
|
|
6896
6117
|
/**
|
|
6897
6118
|
* Logout
|
|
6898
6119
|
*/
|
|
@@ -7341,7 +6562,6 @@ class TokenValidator {
|
|
|
7341
6562
|
const defaultTokenValidator = new TokenValidator();
|
|
7342
6563
|
|
|
7343
6564
|
exports.AIContextManager = AIContextManager;
|
|
7344
|
-
exports.AuthFlowManager = AuthFlowManager;
|
|
7345
6565
|
exports.AuthManager = AuthManager;
|
|
7346
6566
|
exports.BrowserStorage = BrowserStorage;
|
|
7347
6567
|
exports.BufferLogHandler = BufferLogHandler;
|