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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * playkit-sdk v1.4.0
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.4.0"';
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, playerToken, or playerJWT.', 'NOT_AUTHENTICATED');
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
- // Default to device auth if not specified
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, playerToken, playerJWT, or call login() manually.', 'NOT_AUTHENTICATED');
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 UI
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(authMethod = 'device') {
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(authMethod);
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 actual auth flow
1731
+ * Internal method that executes the Device Authorization flow.
2567
1732
  * @private
2568
1733
  */
2569
- async executeAuthFlow(authMethod = 'device') {
2570
- var _a, _b;
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
- const response = await fetch(`${this.baseURL}${JWT_EXCHANGE_ENDPOINT}`, {
2628
- method: 'POST',
2629
- headers: Object.assign({ Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' }, getSDKHeaders()),
2630
- body: JSON.stringify({ gameId: this.config.gameId }),
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
- if (!response.ok) {
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: playerToken,
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
- return playerToken;
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 !!(this.authFlowManager || this.deviceAuthFlowManager);
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 be {type:'text'|'image'|'image_url'|'file'|'audio'|'input_audio',...}. ` +
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 text|image|image_url|file|audio|input_audio). Got part ${describePart(part)}`, 'INVALID_MESSAGES');
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
- if (chatConfig.thinking) {
3934
- requestBody.thinking = chatConfig.thinking;
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
- if (chatConfig.thinking) {
3994
- requestBody.thinking = chatConfig.thinking;
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
- if (chatConfig.thinking) {
4061
- requestBody.thinking = chatConfig.thinking;
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
- if (chatConfig.thinking) {
4122
- requestBody.thinking = chatConfig.thinking;
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, (_a = imageData.revised_prompt) !== null && _a !== void 0 ? _a : config.prompt, config.size, imageData.b64_json_original, imageData.transparent_success);
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, (_a = imageData.revised_prompt) !== null && _a !== void 0 ? _a : config.prompt, config.size, imageData.b64_json_original, imageData.transparent_success);
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
- const authMethod = this.config.authMethod || 'device';
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
- const fallbackMethod = this.config.authMethod || 'device';
6811
- this.emit('developer_token_fallback_started', { fallbackMethod });
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(fallbackMethod);
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;