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