playkit-sdk 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/playkit-sdk.cjs.js +242 -1022
- package/dist/playkit-sdk.cjs.js.map +1 -1
- package/dist/playkit-sdk.d.ts +304 -309
- package/dist/playkit-sdk.esm.js +243 -1022
- package/dist/playkit-sdk.esm.js.map +1 -1
- package/dist/playkit-sdk.umd.js +242 -1022
- package/dist/playkit-sdk.umd.js.map +1 -1
- package/package.json +4 -4
package/dist/playkit-sdk.umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* playkit-sdk v1.
|
|
2
|
+
* playkit-sdk v1.6.0
|
|
3
3
|
* PlayKit SDK for JavaScript
|
|
4
4
|
* @license SEE LICENSE IN LICENSE
|
|
5
5
|
*/
|
|
@@ -394,6 +394,48 @@
|
|
|
394
394
|
}
|
|
395
395
|
return { role, content };
|
|
396
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* Convert an OpenAI-compatible tool call returned by the API into the canonical
|
|
399
|
+
* PlayKit message content part used for future requests.
|
|
400
|
+
*/
|
|
401
|
+
function createToolCallContentPart(toolCall) {
|
|
402
|
+
var _a;
|
|
403
|
+
let input = {};
|
|
404
|
+
const args = (_a = toolCall.function) === null || _a === void 0 ? void 0 : _a.arguments;
|
|
405
|
+
if (typeof args === 'string' && args.trim()) {
|
|
406
|
+
try {
|
|
407
|
+
input = JSON.parse(args);
|
|
408
|
+
}
|
|
409
|
+
catch (_b) {
|
|
410
|
+
input = args;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
type: 'tool-call',
|
|
415
|
+
toolCallId: toolCall.id,
|
|
416
|
+
toolName: toolCall.function.name,
|
|
417
|
+
input,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Create a canonical PlayKit tool-result content part.
|
|
422
|
+
*/
|
|
423
|
+
function createToolResultContentPart(toolCallId, toolName, result) {
|
|
424
|
+
if (typeof result === 'string') {
|
|
425
|
+
return {
|
|
426
|
+
type: 'tool-result',
|
|
427
|
+
toolCallId,
|
|
428
|
+
toolName,
|
|
429
|
+
output: { type: 'text', value: result },
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
type: 'tool-result',
|
|
434
|
+
toolCallId,
|
|
435
|
+
toolName,
|
|
436
|
+
output: { type: 'json', value: result },
|
|
437
|
+
};
|
|
438
|
+
}
|
|
397
439
|
/**
|
|
398
440
|
* Error types that can be thrown by the SDK
|
|
399
441
|
*/
|
|
@@ -1177,7 +1219,7 @@
|
|
|
1177
1219
|
}
|
|
1178
1220
|
|
|
1179
1221
|
const SDK_TYPE = 'Javascript';
|
|
1180
|
-
const SDK_VERSION = '"1.
|
|
1222
|
+
const SDK_VERSION = '"1.6.0"';
|
|
1181
1223
|
function getSDKHeaders() {
|
|
1182
1224
|
return {
|
|
1183
1225
|
'X-SDK-Type': SDK_TYPE,
|
|
@@ -1185,867 +1227,6 @@
|
|
|
1185
1227
|
};
|
|
1186
1228
|
}
|
|
1187
1229
|
|
|
1188
|
-
/**
|
|
1189
|
-
* Authentication Flow Manager
|
|
1190
|
-
* Manages the headless authentication flow with automatic UI
|
|
1191
|
-
*
|
|
1192
|
-
* @deprecated This class is deprecated. Use DeviceAuthFlowManager instead.
|
|
1193
|
-
* Will be removed in v2.0
|
|
1194
|
-
*/
|
|
1195
|
-
// i18n translations
|
|
1196
|
-
const translations$2 = {
|
|
1197
|
-
en: {
|
|
1198
|
-
signIn: 'Sign In / Register',
|
|
1199
|
-
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!',
|
|
1200
|
-
email: 'Email',
|
|
1201
|
-
phone: 'Phone',
|
|
1202
|
-
emailPlaceholder: 'Enter your email address',
|
|
1203
|
-
phonePlaceholder: 'Enter your phone number (+86 Only)',
|
|
1204
|
-
sendCode: 'Send Code',
|
|
1205
|
-
enterCode: 'Enter Code',
|
|
1206
|
-
enterCodeSubtitle: "We've sent a 6-digit code to your",
|
|
1207
|
-
verify: 'Verify',
|
|
1208
|
-
pleaseEnterEmail: 'Please enter your email address',
|
|
1209
|
-
pleaseEnterPhone: 'Please enter your phone number',
|
|
1210
|
-
enterAllDigits: 'Please enter all 6 digits',
|
|
1211
|
-
verificationFailed: 'Verification failed',
|
|
1212
|
-
failedToSendCode: 'Failed to send code',
|
|
1213
|
-
invalidCode: 'Invalid verification code',
|
|
1214
|
-
},
|
|
1215
|
-
zh: {
|
|
1216
|
-
signIn: '登录/注册',
|
|
1217
|
-
signInSubtitle: '本游戏使用PlayKit进行成本管理。\n如果您没有帐户,我们会为您自动注册。注册即送AI游戏积分!',
|
|
1218
|
-
email: '邮箱',
|
|
1219
|
-
phone: '手机',
|
|
1220
|
-
emailPlaceholder: '请输入邮箱地址',
|
|
1221
|
-
phonePlaceholder: '请输入手机号(仅限 +86)',
|
|
1222
|
-
sendCode: '发送验证码',
|
|
1223
|
-
enterCode: '输入验证码',
|
|
1224
|
-
enterCodeSubtitle: '我们已向您发送了 6 位验证码:',
|
|
1225
|
-
verify: '验证',
|
|
1226
|
-
pleaseEnterEmail: '请输入邮箱地址',
|
|
1227
|
-
pleaseEnterPhone: '请输入手机号',
|
|
1228
|
-
enterAllDigits: '请输入完整的 6 位验证码',
|
|
1229
|
-
verificationFailed: '验证失败',
|
|
1230
|
-
failedToSendCode: '发送验证码失败',
|
|
1231
|
-
invalidCode: '验证码无效',
|
|
1232
|
-
},
|
|
1233
|
-
'zh-TW': {
|
|
1234
|
-
signIn: '登入/註冊',
|
|
1235
|
-
signInSubtitle: '本遊戲使用PlayKit進行成本管理。\n如果您沒有帳戶,我們會為您自動註冊。註冊即送AI遊戲積分!',
|
|
1236
|
-
email: '電子郵件',
|
|
1237
|
-
phone: '手機',
|
|
1238
|
-
emailPlaceholder: '請輸入電子郵件地址',
|
|
1239
|
-
phonePlaceholder: '請輸入手機號碼(僅限 +86)',
|
|
1240
|
-
sendCode: '發送驗證碼',
|
|
1241
|
-
enterCode: '輸入驗證碼',
|
|
1242
|
-
enterCodeSubtitle: '我們已向您發送了 6 位驗證碼:',
|
|
1243
|
-
verify: '驗證',
|
|
1244
|
-
pleaseEnterEmail: '請輸入電子郵件地址',
|
|
1245
|
-
pleaseEnterPhone: '請輸入手機號碼',
|
|
1246
|
-
enterAllDigits: '請輸入完整的 6 位驗證碼',
|
|
1247
|
-
verificationFailed: '驗證失敗',
|
|
1248
|
-
failedToSendCode: '發送驗證碼失敗',
|
|
1249
|
-
invalidCode: '驗證碼無效',
|
|
1250
|
-
},
|
|
1251
|
-
ja: {
|
|
1252
|
-
signIn: 'サインイン/登録',
|
|
1253
|
-
signInSubtitle: 'このゲームはPlayKitでコスト管理を行っています。\nアカウントをお持ちでない場合は、自動的に登録します。登録するとAIゲームクレジットがもらえます!',
|
|
1254
|
-
email: 'メール',
|
|
1255
|
-
phone: '電話',
|
|
1256
|
-
emailPlaceholder: 'メールアドレスを入力してください',
|
|
1257
|
-
phonePlaceholder: '電話番号を入力してください(+86のみ)',
|
|
1258
|
-
sendCode: '認証コードを送信',
|
|
1259
|
-
enterCode: '認証コードを入力',
|
|
1260
|
-
enterCodeSubtitle: '6桁の認証コードを送信しました:',
|
|
1261
|
-
verify: '検証',
|
|
1262
|
-
pleaseEnterEmail: 'メールアドレスを入力してください',
|
|
1263
|
-
pleaseEnterPhone: '電話番号を入力してください',
|
|
1264
|
-
enterAllDigits: '6桁すべて入力してください',
|
|
1265
|
-
verificationFailed: '検証に失敗しました',
|
|
1266
|
-
failedToSendCode: '認証コードの送信に失敗しました',
|
|
1267
|
-
invalidCode: '認証コードが無効です',
|
|
1268
|
-
},
|
|
1269
|
-
ko: {
|
|
1270
|
-
signIn: '로그인/가입',
|
|
1271
|
-
signInSubtitle: '이 게임은 PlayKit으로 비용 관리를 합니다.\n계정이 없으시면 자동으로 등록해 드립니다. 가입하면 AI 게임 크레딧을 받으세요!',
|
|
1272
|
-
email: '이메일',
|
|
1273
|
-
phone: '전화',
|
|
1274
|
-
emailPlaceholder: '이메일 주소를 입력하세요',
|
|
1275
|
-
phonePlaceholder: '전화번호를 입력하세요(+86만 지원)',
|
|
1276
|
-
sendCode: '인증 코드 전송',
|
|
1277
|
-
enterCode: '인증 코드 입력',
|
|
1278
|
-
enterCodeSubtitle: '6자리 인증 코드를 보냈습니다:',
|
|
1279
|
-
verify: '확인',
|
|
1280
|
-
pleaseEnterEmail: '이메일 주소를 입력하세요',
|
|
1281
|
-
pleaseEnterPhone: '전화번호를 입력하세요',
|
|
1282
|
-
enterAllDigits: '6자리를 모두 입력하세요',
|
|
1283
|
-
verificationFailed: '인증 실패',
|
|
1284
|
-
failedToSendCode: '인증 코드 전송 실패',
|
|
1285
|
-
invalidCode: '인증 코드가 잘못되었습니다',
|
|
1286
|
-
},
|
|
1287
|
-
};
|
|
1288
|
-
class AuthFlowManager extends EventEmitter {
|
|
1289
|
-
constructor(baseURL) {
|
|
1290
|
-
super();
|
|
1291
|
-
this.currentSessionId = null;
|
|
1292
|
-
this._uiContainer = null;
|
|
1293
|
-
this._isSuccess = false;
|
|
1294
|
-
this.currentLanguage = 'en';
|
|
1295
|
-
// UI Elements
|
|
1296
|
-
this.modal = null;
|
|
1297
|
-
this.identifierPanel = null;
|
|
1298
|
-
this.verificationPanel = null;
|
|
1299
|
-
this.loadingOverlay = null;
|
|
1300
|
-
this.otpInstance = null;
|
|
1301
|
-
// @ts-ignore - replaced at build time
|
|
1302
|
-
this.baseURL = baseURL || "https://api.playkit.ai";
|
|
1303
|
-
this.currentLanguage = this.detectLanguage();
|
|
1304
|
-
}
|
|
1305
|
-
/**
|
|
1306
|
-
* Detect browser language (safe for Node.js environment)
|
|
1307
|
-
*/
|
|
1308
|
-
detectLanguage() {
|
|
1309
|
-
// Check if running in browser environment
|
|
1310
|
-
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
|
1311
|
-
return 'en'; // Default to English in Node.js environment
|
|
1312
|
-
}
|
|
1313
|
-
try {
|
|
1314
|
-
const browserLang = navigator.language.toLowerCase();
|
|
1315
|
-
// Match language codes
|
|
1316
|
-
if (browserLang.startsWith('zh-tw') || browserLang.startsWith('zh-hk')) {
|
|
1317
|
-
return 'zh-TW'; // Traditional Chinese
|
|
1318
|
-
}
|
|
1319
|
-
else if (browserLang.startsWith('zh')) {
|
|
1320
|
-
return 'zh'; // Simplified Chinese
|
|
1321
|
-
}
|
|
1322
|
-
else if (browserLang.startsWith('ja')) {
|
|
1323
|
-
return 'ja'; // Japanese
|
|
1324
|
-
}
|
|
1325
|
-
else if (browserLang.startsWith('ko')) {
|
|
1326
|
-
return 'ko'; // Korean
|
|
1327
|
-
}
|
|
1328
|
-
else {
|
|
1329
|
-
return 'en'; // Default to English
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
catch (error) {
|
|
1333
|
-
// Fallback to English if detection fails
|
|
1334
|
-
return 'en';
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
/**
|
|
1338
|
-
* Get translated text
|
|
1339
|
-
*/
|
|
1340
|
-
t(key) {
|
|
1341
|
-
return translations$2[this.currentLanguage][key];
|
|
1342
|
-
}
|
|
1343
|
-
/**
|
|
1344
|
-
* Start the authentication flow
|
|
1345
|
-
* Returns a promise that resolves with the JWT token
|
|
1346
|
-
*/
|
|
1347
|
-
async startFlow() {
|
|
1348
|
-
return new Promise((resolve, reject) => {
|
|
1349
|
-
// Create and show UI
|
|
1350
|
-
this.createUI();
|
|
1351
|
-
this.showModal();
|
|
1352
|
-
// Listen for success/failure
|
|
1353
|
-
this.once('success', (token) => {
|
|
1354
|
-
this.hideModal();
|
|
1355
|
-
resolve(token);
|
|
1356
|
-
});
|
|
1357
|
-
this.once('error', (error) => {
|
|
1358
|
-
this.hideModal();
|
|
1359
|
-
reject(error);
|
|
1360
|
-
});
|
|
1361
|
-
// Set default auth type based on region
|
|
1362
|
-
this.setDefaultAuthTypeByRegion().catch((err) => {
|
|
1363
|
-
console.error('[PlayKit Auth] Failed to detect region:', err);
|
|
1364
|
-
});
|
|
1365
|
-
});
|
|
1366
|
-
}
|
|
1367
|
-
/**
|
|
1368
|
-
* Create the authentication UI
|
|
1369
|
-
*/
|
|
1370
|
-
createUI() {
|
|
1371
|
-
// Create modal container
|
|
1372
|
-
this.modal = document.createElement('div');
|
|
1373
|
-
this.modal.className = 'playkit-auth-modal';
|
|
1374
|
-
this.modal.innerHTML = `
|
|
1375
|
-
<div class="playkit-auth-overlay"></div>
|
|
1376
|
-
<div class="playkit-auth-container">
|
|
1377
|
-
<!-- Identifier Panel -->
|
|
1378
|
-
<div class="playkit-auth-panel" id="playkit-identifier-panel">
|
|
1379
|
-
<div class="playkit-auth-header">
|
|
1380
|
-
<h2>${this.t('signIn')}</h2>
|
|
1381
|
-
<p>${this.t('signInSubtitle')}</p>
|
|
1382
|
-
</div>
|
|
1383
|
-
|
|
1384
|
-
<div class="playkit-auth-toggle">
|
|
1385
|
-
<label class="playkit-toggle-option">
|
|
1386
|
-
<input type="radio" name="auth-type" value="email" checked>
|
|
1387
|
-
<span>${this.t('email')}</span>
|
|
1388
|
-
</label>
|
|
1389
|
-
<label class="playkit-toggle-option">
|
|
1390
|
-
<input type="radio" name="auth-type" value="phone">
|
|
1391
|
-
<span>${this.t('phone')}</span>
|
|
1392
|
-
</label>
|
|
1393
|
-
</div>
|
|
1394
|
-
|
|
1395
|
-
<div class="playkit-auth-input-group">
|
|
1396
|
-
<div class="playkit-input-wrapper">
|
|
1397
|
-
<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">
|
|
1398
|
-
<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>
|
|
1399
|
-
<polyline points="22,6 12,13 2,6"></polyline>
|
|
1400
|
-
</svg>
|
|
1401
|
-
<input
|
|
1402
|
-
type="text"
|
|
1403
|
-
id="playkit-identifier-input"
|
|
1404
|
-
placeholder="${this.t('emailPlaceholder')}"
|
|
1405
|
-
autocomplete="off"
|
|
1406
|
-
>
|
|
1407
|
-
</div>
|
|
1408
|
-
</div>
|
|
1409
|
-
|
|
1410
|
-
<button class="playkit-auth-button" id="playkit-send-code-btn">
|
|
1411
|
-
${this.t('sendCode')}
|
|
1412
|
-
</button>
|
|
1413
|
-
|
|
1414
|
-
<div class="playkit-auth-error" id="playkit-error-text"></div>
|
|
1415
|
-
</div>
|
|
1416
|
-
|
|
1417
|
-
<!-- Verification Panel -->
|
|
1418
|
-
<div class="playkit-auth-panel" id="playkit-verification-panel" style="display: none;">
|
|
1419
|
-
<div class="playkit-auth-header">
|
|
1420
|
-
<button class="playkit-back-button" id="playkit-back-btn">
|
|
1421
|
-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1422
|
-
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
|
1423
|
-
</svg>
|
|
1424
|
-
</button>
|
|
1425
|
-
<h2>${this.t('enterCode')}</h2>
|
|
1426
|
-
<p>${this.t('enterCodeSubtitle')} <span id="playkit-identifier-display"></span></p>
|
|
1427
|
-
</div>
|
|
1428
|
-
|
|
1429
|
-
<div class="playkit-auth-input-group">
|
|
1430
|
-
<div class="playkit-code-inputs">
|
|
1431
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="0">
|
|
1432
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="1">
|
|
1433
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="2">
|
|
1434
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="3">
|
|
1435
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="4">
|
|
1436
|
-
<input type="number" maxlength="1" class="playkit-code-input" data-index="5">
|
|
1437
|
-
</div>
|
|
1438
|
-
</div>
|
|
1439
|
-
|
|
1440
|
-
<button class="playkit-auth-button" id="playkit-verify-btn">
|
|
1441
|
-
${this.t('verify')}
|
|
1442
|
-
</button>
|
|
1443
|
-
|
|
1444
|
-
<div class="playkit-auth-error" id="playkit-verify-error-text"></div>
|
|
1445
|
-
</div>
|
|
1446
|
-
|
|
1447
|
-
<!-- Loading Overlay -->
|
|
1448
|
-
<div class="playkit-loading-overlay" id="playkit-loading-overlay" style="display: none;">
|
|
1449
|
-
<div class="playkit-spinner"></div>
|
|
1450
|
-
</div>
|
|
1451
|
-
</div>
|
|
1452
|
-
`;
|
|
1453
|
-
// Add styles and load VanillaOTP
|
|
1454
|
-
this.addStyles();
|
|
1455
|
-
this.loadVanillaOTP();
|
|
1456
|
-
// Append to body
|
|
1457
|
-
document.body.appendChild(this.modal);
|
|
1458
|
-
// Get references
|
|
1459
|
-
this.identifierPanel = document.getElementById('playkit-identifier-panel');
|
|
1460
|
-
this.verificationPanel = document.getElementById('playkit-verification-panel');
|
|
1461
|
-
this.loadingOverlay = document.getElementById('playkit-loading-overlay');
|
|
1462
|
-
// Setup event listeners
|
|
1463
|
-
this.setupEventListeners();
|
|
1464
|
-
}
|
|
1465
|
-
/**
|
|
1466
|
-
* Load VanillaOTP library
|
|
1467
|
-
*/
|
|
1468
|
-
loadVanillaOTP() {
|
|
1469
|
-
// Check if VanillaOTP is already loaded
|
|
1470
|
-
if (window.VanillaOTP)
|
|
1471
|
-
return;
|
|
1472
|
-
// Inject VanillaOTP script
|
|
1473
|
-
const script = document.createElement('script');
|
|
1474
|
-
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())};`;
|
|
1475
|
-
document.head.appendChild(script);
|
|
1476
|
-
}
|
|
1477
|
-
/**
|
|
1478
|
-
* Add CSS styles to the page
|
|
1479
|
-
*/
|
|
1480
|
-
addStyles() {
|
|
1481
|
-
const styleId = 'playkit-auth-styles';
|
|
1482
|
-
if (document.getElementById(styleId))
|
|
1483
|
-
return;
|
|
1484
|
-
const style = document.createElement('style');
|
|
1485
|
-
style.id = styleId;
|
|
1486
|
-
style.textContent = `
|
|
1487
|
-
.playkit-auth-modal {
|
|
1488
|
-
position: fixed;
|
|
1489
|
-
top: 0;
|
|
1490
|
-
left: 0;
|
|
1491
|
-
right: 0;
|
|
1492
|
-
bottom: 0;
|
|
1493
|
-
z-index: 999999;
|
|
1494
|
-
display: flex;
|
|
1495
|
-
justify-content: center;
|
|
1496
|
-
align-items: center;
|
|
1497
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
|
-
.playkit-auth-overlay {
|
|
1501
|
-
position: absolute;
|
|
1502
|
-
top: 0;
|
|
1503
|
-
left: 0;
|
|
1504
|
-
right: 0;
|
|
1505
|
-
bottom: 0;
|
|
1506
|
-
background: rgba(0, 0, 0, 0.8);
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
.playkit-auth-container {
|
|
1510
|
-
position: relative;
|
|
1511
|
-
background: #fff;
|
|
1512
|
-
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
1513
|
-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.05);
|
|
1514
|
-
width: 90%;
|
|
1515
|
-
max-width: 320px;
|
|
1516
|
-
overflow: hidden;
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
.playkit-auth-panel {
|
|
1520
|
-
padding: 24px;
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
.playkit-auth-header {
|
|
1524
|
-
text-align: center;
|
|
1525
|
-
margin-bottom: 20px;
|
|
1526
|
-
position: relative;
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
.playkit-auth-header h2 {
|
|
1530
|
-
margin: 0 0 8px 0;
|
|
1531
|
-
font-size: 14px;
|
|
1532
|
-
font-weight: 600;
|
|
1533
|
-
color: #171717;
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
.playkit-auth-header p {
|
|
1537
|
-
margin: 0;
|
|
1538
|
-
font-size: 14px;
|
|
1539
|
-
color: #666;
|
|
1540
|
-
line-height: 1.5;
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
.playkit-back-button {
|
|
1544
|
-
position: absolute;
|
|
1545
|
-
left: 0;
|
|
1546
|
-
top: 0;
|
|
1547
|
-
background: transparent;
|
|
1548
|
-
border: none;
|
|
1549
|
-
cursor: pointer;
|
|
1550
|
-
padding: 4px;
|
|
1551
|
-
color: #666;
|
|
1552
|
-
transition: background-color 0.2s ease, color 0.2s ease;
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1555
|
-
.playkit-back-button:hover {
|
|
1556
|
-
background: #f5f5f5;
|
|
1557
|
-
color: #171717;
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
.playkit-auth-toggle {
|
|
1561
|
-
display: flex;
|
|
1562
|
-
background: #f5f5f5;
|
|
1563
|
-
padding: 2px;
|
|
1564
|
-
margin-bottom: 20px;
|
|
1565
|
-
gap: 2px;
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
.playkit-toggle-option {
|
|
1569
|
-
flex: 1;
|
|
1570
|
-
display: flex;
|
|
1571
|
-
justify-content: center;
|
|
1572
|
-
align-items: center;
|
|
1573
|
-
padding: 10px 16px;
|
|
1574
|
-
cursor: pointer;
|
|
1575
|
-
transition: background-color 0.2s ease;
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
.playkit-toggle-option input {
|
|
1579
|
-
display: none;
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
.playkit-toggle-option span {
|
|
1583
|
-
font-size: 14px;
|
|
1584
|
-
font-weight: 500;
|
|
1585
|
-
color: #666;
|
|
1586
|
-
transition: color 0.2s ease;
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
.playkit-toggle-option input:checked + span {
|
|
1590
|
-
color: #fff;
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
.playkit-toggle-option:has(input:checked) {
|
|
1594
|
-
background: #171717;
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
.playkit-auth-input-group {
|
|
1598
|
-
margin-bottom: 20px;
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
.playkit-input-wrapper {
|
|
1602
|
-
position: relative;
|
|
1603
|
-
display: flex;
|
|
1604
|
-
align-items: center;
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
.playkit-input-icon {
|
|
1608
|
-
position: absolute;
|
|
1609
|
-
left: 12px;
|
|
1610
|
-
color: #999;
|
|
1611
|
-
pointer-events: none;
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
.playkit-input-wrapper input {
|
|
1615
|
-
width: 100%;
|
|
1616
|
-
padding: 10px 12px 10px 44px;
|
|
1617
|
-
border: 1px solid #e5e7eb;
|
|
1618
|
-
font-size: 14px;
|
|
1619
|
-
transition: border-color 0.2s ease;
|
|
1620
|
-
box-sizing: border-box;
|
|
1621
|
-
background: #fff;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
.playkit-input-wrapper input:hover {
|
|
1625
|
-
border-color: #d4d4d4;
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
.playkit-input-wrapper input:focus {
|
|
1629
|
-
outline: none;
|
|
1630
|
-
border-color: #171717;
|
|
1631
|
-
}
|
|
1632
|
-
|
|
1633
|
-
.playkit-code-inputs {
|
|
1634
|
-
display: flex;
|
|
1635
|
-
gap: 8px;
|
|
1636
|
-
justify-content: center;
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
.playkit-code-input {
|
|
1640
|
-
width: 40px !important;
|
|
1641
|
-
height: 48px;
|
|
1642
|
-
text-align: center;
|
|
1643
|
-
font-size: 20px;
|
|
1644
|
-
font-weight: 600;
|
|
1645
|
-
border: 1px solid #e5e7eb !important;
|
|
1646
|
-
padding: 0 !important;
|
|
1647
|
-
transition: border-color 0.2s ease;
|
|
1648
|
-
background: #fff;
|
|
1649
|
-
-moz-appearance: textfield;
|
|
1650
|
-
}
|
|
1651
|
-
|
|
1652
|
-
.playkit-code-input::-webkit-outer-spin-button,
|
|
1653
|
-
.playkit-code-input::-webkit-inner-spin-button {
|
|
1654
|
-
-webkit-appearance: none;
|
|
1655
|
-
margin: 0;
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
.playkit-code-input:hover {
|
|
1659
|
-
border-color: #d4d4d4 !important;
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
.playkit-code-input:focus {
|
|
1663
|
-
outline: none;
|
|
1664
|
-
border-color: #171717 !important;
|
|
1665
|
-
}
|
|
1666
|
-
|
|
1667
|
-
.playkit-auth-button {
|
|
1668
|
-
width: 100%;
|
|
1669
|
-
padding: 10px 16px;
|
|
1670
|
-
background: #171717;
|
|
1671
|
-
color: white;
|
|
1672
|
-
border: none;
|
|
1673
|
-
font-size: 14px;
|
|
1674
|
-
font-weight: 500;
|
|
1675
|
-
cursor: pointer;
|
|
1676
|
-
transition: background 0.2s ease;
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
.playkit-auth-button:hover:not(:disabled) {
|
|
1680
|
-
background: #404040;
|
|
1681
|
-
}
|
|
1682
|
-
|
|
1683
|
-
.playkit-auth-button:active:not(:disabled) {
|
|
1684
|
-
background: #0a0a0a;
|
|
1685
|
-
}
|
|
1686
|
-
|
|
1687
|
-
.playkit-auth-button:disabled {
|
|
1688
|
-
background: #e5e7eb;
|
|
1689
|
-
color: #999;
|
|
1690
|
-
cursor: not-allowed;
|
|
1691
|
-
}
|
|
1692
|
-
|
|
1693
|
-
.playkit-auth-error {
|
|
1694
|
-
margin-top: 16px;
|
|
1695
|
-
padding: 12px 16px;
|
|
1696
|
-
background: #fef2f2;
|
|
1697
|
-
border: 1px solid #fecaca;
|
|
1698
|
-
color: #dc2626;
|
|
1699
|
-
font-size: 13px;
|
|
1700
|
-
text-align: left;
|
|
1701
|
-
display: none;
|
|
1702
|
-
}
|
|
1703
|
-
|
|
1704
|
-
.playkit-auth-error.show {
|
|
1705
|
-
display: block;
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
.playkit-loading-overlay {
|
|
1709
|
-
position: absolute;
|
|
1710
|
-
top: 0;
|
|
1711
|
-
left: 0;
|
|
1712
|
-
right: 0;
|
|
1713
|
-
bottom: 0;
|
|
1714
|
-
background: rgba(255, 255, 255, 0.96);
|
|
1715
|
-
display: flex;
|
|
1716
|
-
justify-content: center;
|
|
1717
|
-
align-items: center;
|
|
1718
|
-
}
|
|
1719
|
-
|
|
1720
|
-
.playkit-spinner {
|
|
1721
|
-
width: 24px;
|
|
1722
|
-
height: 24px;
|
|
1723
|
-
border: 2px solid #e5e7eb;
|
|
1724
|
-
border-top: 2px solid #171717;
|
|
1725
|
-
border-radius: 50%;
|
|
1726
|
-
animation: playkit-spin 1s linear infinite;
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
@keyframes playkit-spin {
|
|
1730
|
-
0% { transform: rotate(0deg); }
|
|
1731
|
-
100% { transform: rotate(360deg); }
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
@media (max-width: 480px) {
|
|
1735
|
-
.playkit-auth-container {
|
|
1736
|
-
width: 95%;
|
|
1737
|
-
max-width: none;
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
.playkit-auth-panel {
|
|
1741
|
-
padding: 20px;
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
.playkit-code-input {
|
|
1745
|
-
width: 36px !important;
|
|
1746
|
-
height: 44px;
|
|
1747
|
-
font-size: 18px;
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
.playkit-code-inputs {
|
|
1751
|
-
gap: 6px;
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
`;
|
|
1755
|
-
document.head.appendChild(style);
|
|
1756
|
-
}
|
|
1757
|
-
/**
|
|
1758
|
-
* Setup event listeners
|
|
1759
|
-
*/
|
|
1760
|
-
setupEventListeners() {
|
|
1761
|
-
var _a, _b, _c, _d;
|
|
1762
|
-
// Auth type toggle
|
|
1763
|
-
const emailRadio = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('input[value="email"]');
|
|
1764
|
-
const phoneRadio = (_b = this.modal) === null || _b === void 0 ? void 0 : _b.querySelector('input[value="phone"]');
|
|
1765
|
-
const identifierInput = document.getElementById('playkit-identifier-input');
|
|
1766
|
-
const identifierIcon = document.getElementById('playkit-identifier-icon');
|
|
1767
|
-
const updateIcon = () => {
|
|
1768
|
-
const isEmail = emailRadio === null || emailRadio === void 0 ? void 0 : emailRadio.checked;
|
|
1769
|
-
identifierInput.placeholder = isEmail
|
|
1770
|
-
? this.t('emailPlaceholder')
|
|
1771
|
-
: this.t('phonePlaceholder');
|
|
1772
|
-
// Update icon
|
|
1773
|
-
if (isEmail) {
|
|
1774
|
-
identifierIcon.innerHTML = `
|
|
1775
|
-
<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>
|
|
1776
|
-
<polyline points="22,6 12,13 2,6"></polyline>
|
|
1777
|
-
`;
|
|
1778
|
-
}
|
|
1779
|
-
else {
|
|
1780
|
-
identifierIcon.innerHTML = `
|
|
1781
|
-
<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>
|
|
1782
|
-
`;
|
|
1783
|
-
}
|
|
1784
|
-
};
|
|
1785
|
-
emailRadio === null || emailRadio === void 0 ? void 0 : emailRadio.addEventListener('change', updateIcon);
|
|
1786
|
-
phoneRadio === null || phoneRadio === void 0 ? void 0 : phoneRadio.addEventListener('change', updateIcon);
|
|
1787
|
-
// Send code button
|
|
1788
|
-
const sendCodeBtn = document.getElementById('playkit-send-code-btn');
|
|
1789
|
-
sendCodeBtn === null || sendCodeBtn === void 0 ? void 0 : sendCodeBtn.addEventListener('click', () => this.onSendCodeClicked());
|
|
1790
|
-
// Enter key in identifier input
|
|
1791
|
-
identifierInput === null || identifierInput === void 0 ? void 0 : identifierInput.addEventListener('keypress', (e) => {
|
|
1792
|
-
if (e.key === 'Enter') {
|
|
1793
|
-
this.onSendCodeClicked();
|
|
1794
|
-
}
|
|
1795
|
-
});
|
|
1796
|
-
// Initialize VanillaOTP for code inputs
|
|
1797
|
-
const codeInputsContainer = (_c = this.modal) === null || _c === void 0 ? void 0 : _c.querySelector('.playkit-code-inputs');
|
|
1798
|
-
if (codeInputsContainer && window.VanillaOTP) {
|
|
1799
|
-
this.otpInstance = new window.VanillaOTP(codeInputsContainer);
|
|
1800
|
-
// Auto-submit when all 6 digits entered
|
|
1801
|
-
const codeInputs = (_d = this.modal) === null || _d === void 0 ? void 0 : _d.querySelectorAll('.playkit-code-input');
|
|
1802
|
-
codeInputs === null || codeInputs === void 0 ? void 0 : codeInputs.forEach((input, _index) => {
|
|
1803
|
-
input.addEventListener('input', () => {
|
|
1804
|
-
// Check if all inputs are filled
|
|
1805
|
-
const allFilled = Array.from(codeInputs).every(inp => inp.value.length === 1);
|
|
1806
|
-
if (allFilled) {
|
|
1807
|
-
// Small delay to ensure the last input is processed
|
|
1808
|
-
setTimeout(() => this.onVerifyClicked(), 100);
|
|
1809
|
-
}
|
|
1810
|
-
});
|
|
1811
|
-
});
|
|
1812
|
-
}
|
|
1813
|
-
// Verify button
|
|
1814
|
-
const verifyBtn = document.getElementById('playkit-verify-btn');
|
|
1815
|
-
verifyBtn === null || verifyBtn === void 0 ? void 0 : verifyBtn.addEventListener('click', () => this.onVerifyClicked());
|
|
1816
|
-
// Back button
|
|
1817
|
-
const backBtn = document.getElementById('playkit-back-btn');
|
|
1818
|
-
backBtn === null || backBtn === void 0 ? void 0 : backBtn.addEventListener('click', () => {
|
|
1819
|
-
this.showIdentifierPanel();
|
|
1820
|
-
});
|
|
1821
|
-
}
|
|
1822
|
-
/**
|
|
1823
|
-
* Handle send code button click
|
|
1824
|
-
*/
|
|
1825
|
-
async onSendCodeClicked() {
|
|
1826
|
-
var _a;
|
|
1827
|
-
this.clearError();
|
|
1828
|
-
const identifierInput = document.getElementById('playkit-identifier-input');
|
|
1829
|
-
const identifier = identifierInput.value.trim();
|
|
1830
|
-
const emailRadio = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('input[value="email"]');
|
|
1831
|
-
const type = emailRadio.checked ? 'email' : 'phone';
|
|
1832
|
-
if (!identifier) {
|
|
1833
|
-
this.showError(type === 'email' ? this.t('pleaseEnterEmail') : this.t('pleaseEnterPhone'));
|
|
1834
|
-
return;
|
|
1835
|
-
}
|
|
1836
|
-
const sendCodeBtn = document.getElementById('playkit-send-code-btn');
|
|
1837
|
-
sendCodeBtn.disabled = true;
|
|
1838
|
-
this.showLoading();
|
|
1839
|
-
try {
|
|
1840
|
-
const success = await this.sendVerificationCode(identifier, type);
|
|
1841
|
-
if (success) {
|
|
1842
|
-
// Store identifier for display
|
|
1843
|
-
const displaySpan = document.getElementById('playkit-identifier-display');
|
|
1844
|
-
if (displaySpan) {
|
|
1845
|
-
displaySpan.textContent = type === 'email' ? identifier : identifier;
|
|
1846
|
-
}
|
|
1847
|
-
// Switch to verification panel
|
|
1848
|
-
this.showVerificationPanel();
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
catch (error) {
|
|
1852
|
-
this.showError(error instanceof Error ? error.message : this.t('failedToSendCode'));
|
|
1853
|
-
}
|
|
1854
|
-
finally {
|
|
1855
|
-
this.hideLoading();
|
|
1856
|
-
sendCodeBtn.disabled = false;
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
/**
|
|
1860
|
-
* Handle verify button click
|
|
1861
|
-
*/
|
|
1862
|
-
async onVerifyClicked() {
|
|
1863
|
-
var _a;
|
|
1864
|
-
this.clearError('verify');
|
|
1865
|
-
// Get code from VanillaOTP instance or fallback to manual collection
|
|
1866
|
-
let code = '';
|
|
1867
|
-
if (this.otpInstance) {
|
|
1868
|
-
code = this.otpInstance.getValue().replace(/\s/g, ''); // Remove spaces
|
|
1869
|
-
}
|
|
1870
|
-
else {
|
|
1871
|
-
const codeInputs = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.playkit-code-input');
|
|
1872
|
-
code = Array.from(codeInputs).map((input) => input.value).join('');
|
|
1873
|
-
}
|
|
1874
|
-
if (code.length !== 6 || !/^\d{6}$/.test(code)) {
|
|
1875
|
-
this.showError(this.t('enterAllDigits'), 'verify');
|
|
1876
|
-
return;
|
|
1877
|
-
}
|
|
1878
|
-
this.showLoading();
|
|
1879
|
-
try {
|
|
1880
|
-
const globalToken = await this.verifyCode(code);
|
|
1881
|
-
this.emit('success', globalToken);
|
|
1882
|
-
}
|
|
1883
|
-
catch (error) {
|
|
1884
|
-
this.showError(error instanceof Error ? error.message : this.t('verificationFailed'), 'verify');
|
|
1885
|
-
this.hideLoading();
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
/**
|
|
1889
|
-
* Send verification code to backend
|
|
1890
|
-
*/
|
|
1891
|
-
async sendVerificationCode(identifier, type) {
|
|
1892
|
-
const response = await fetch(`${this.baseURL}/api/auth/send-code`, {
|
|
1893
|
-
method: 'POST',
|
|
1894
|
-
headers: Object.assign({ 'Content-Type': 'application/json' }, getSDKHeaders()),
|
|
1895
|
-
body: JSON.stringify({ identifier, type }),
|
|
1896
|
-
});
|
|
1897
|
-
if (!response.ok) {
|
|
1898
|
-
throw new PlayKitError(this.t('failedToSendCode'), 'SEND_CODE_ERROR', response.status);
|
|
1899
|
-
}
|
|
1900
|
-
const data = await response.json();
|
|
1901
|
-
if (!data.success || !data.sessionId) {
|
|
1902
|
-
throw new PlayKitError(this.t('failedToSendCode'), 'INVALID_RESPONSE');
|
|
1903
|
-
}
|
|
1904
|
-
this.currentSessionId = data.sessionId;
|
|
1905
|
-
return true;
|
|
1906
|
-
}
|
|
1907
|
-
/**
|
|
1908
|
-
* Verify the code and get global token
|
|
1909
|
-
*/
|
|
1910
|
-
async verifyCode(code) {
|
|
1911
|
-
if (!this.currentSessionId) {
|
|
1912
|
-
throw new PlayKitError('No session ID available', 'NO_SESSION');
|
|
1913
|
-
}
|
|
1914
|
-
const response = await fetch(`${this.baseURL}/api/auth/verify-code`, {
|
|
1915
|
-
method: 'POST',
|
|
1916
|
-
headers: Object.assign({ 'Content-Type': 'application/json' }, getSDKHeaders()),
|
|
1917
|
-
body: JSON.stringify({
|
|
1918
|
-
sessionId: this.currentSessionId,
|
|
1919
|
-
code,
|
|
1920
|
-
}),
|
|
1921
|
-
});
|
|
1922
|
-
if (!response.ok) {
|
|
1923
|
-
throw new PlayKitError(this.t('invalidCode'), 'INVALID_CODE', response.status);
|
|
1924
|
-
}
|
|
1925
|
-
const data = await response.json();
|
|
1926
|
-
if (!data.success || !data.globalToken) {
|
|
1927
|
-
throw new PlayKitError(this.t('verificationFailed'), 'VERIFICATION_FAILED');
|
|
1928
|
-
}
|
|
1929
|
-
return data.globalToken;
|
|
1930
|
-
}
|
|
1931
|
-
/**
|
|
1932
|
-
* Set default auth type based on user region
|
|
1933
|
-
*/
|
|
1934
|
-
async setDefaultAuthTypeByRegion() {
|
|
1935
|
-
var _a;
|
|
1936
|
-
try {
|
|
1937
|
-
const response = await fetch(`${this.baseURL}/api/reachability`, {
|
|
1938
|
-
headers: Object.assign({}, getSDKHeaders()),
|
|
1939
|
-
});
|
|
1940
|
-
if (response.ok) {
|
|
1941
|
-
const data = await response.json();
|
|
1942
|
-
if (data.region === 'CN') {
|
|
1943
|
-
const phoneRadio = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('input[value="phone"]');
|
|
1944
|
-
if (phoneRadio) {
|
|
1945
|
-
phoneRadio.checked = true;
|
|
1946
|
-
phoneRadio.dispatchEvent(new Event('change'));
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
catch (error) {
|
|
1952
|
-
console.error('[PlayKit Auth] Failed to detect region:', error);
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
/**
|
|
1956
|
-
* Show/hide panels
|
|
1957
|
-
*/
|
|
1958
|
-
showIdentifierPanel() {
|
|
1959
|
-
var _a;
|
|
1960
|
-
if (this.identifierPanel)
|
|
1961
|
-
this.identifierPanel.style.display = 'block';
|
|
1962
|
-
if (this.verificationPanel)
|
|
1963
|
-
this.verificationPanel.style.display = 'none';
|
|
1964
|
-
// Clear code inputs
|
|
1965
|
-
if (this.otpInstance) {
|
|
1966
|
-
this.otpInstance.setValue(''); // Clear all inputs using VanillaOTP
|
|
1967
|
-
}
|
|
1968
|
-
else {
|
|
1969
|
-
const codeInputs = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.playkit-code-input');
|
|
1970
|
-
codeInputs === null || codeInputs === void 0 ? void 0 : codeInputs.forEach((input) => (input.value = ''));
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
showVerificationPanel() {
|
|
1974
|
-
var _a;
|
|
1975
|
-
if (this.identifierPanel)
|
|
1976
|
-
this.identifierPanel.style.display = 'none';
|
|
1977
|
-
if (this.verificationPanel)
|
|
1978
|
-
this.verificationPanel.style.display = 'block';
|
|
1979
|
-
// Focus first code input
|
|
1980
|
-
const firstInput = (_a = this.modal) === null || _a === void 0 ? void 0 : _a.querySelector('.playkit-code-input');
|
|
1981
|
-
firstInput === null || firstInput === void 0 ? void 0 : firstInput.focus();
|
|
1982
|
-
}
|
|
1983
|
-
/**
|
|
1984
|
-
* Show/hide loading
|
|
1985
|
-
*/
|
|
1986
|
-
showLoading() {
|
|
1987
|
-
if (this.loadingOverlay)
|
|
1988
|
-
this.loadingOverlay.style.display = 'flex';
|
|
1989
|
-
}
|
|
1990
|
-
hideLoading() {
|
|
1991
|
-
if (this.loadingOverlay)
|
|
1992
|
-
this.loadingOverlay.style.display = 'none';
|
|
1993
|
-
}
|
|
1994
|
-
/**
|
|
1995
|
-
* Show/hide error messages
|
|
1996
|
-
*/
|
|
1997
|
-
showError(message, panel = 'identifier') {
|
|
1998
|
-
const errorEl = panel === 'identifier'
|
|
1999
|
-
? document.getElementById('playkit-error-text')
|
|
2000
|
-
: document.getElementById('playkit-verify-error-text');
|
|
2001
|
-
if (errorEl) {
|
|
2002
|
-
errorEl.textContent = message;
|
|
2003
|
-
errorEl.classList.add('show');
|
|
2004
|
-
}
|
|
2005
|
-
}
|
|
2006
|
-
clearError(panel = 'both') {
|
|
2007
|
-
if (panel === 'identifier' || panel === 'both') {
|
|
2008
|
-
const errorEl = document.getElementById('playkit-error-text');
|
|
2009
|
-
if (errorEl) {
|
|
2010
|
-
errorEl.textContent = '';
|
|
2011
|
-
errorEl.classList.remove('show');
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
if (panel === 'verify' || panel === 'both') {
|
|
2015
|
-
const errorEl = document.getElementById('playkit-verify-error-text');
|
|
2016
|
-
if (errorEl) {
|
|
2017
|
-
errorEl.textContent = '';
|
|
2018
|
-
errorEl.classList.remove('show');
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
/**
|
|
2023
|
-
* Show/hide modal
|
|
2024
|
-
*/
|
|
2025
|
-
showModal() {
|
|
2026
|
-
if (this.modal)
|
|
2027
|
-
this.modal.style.display = 'flex';
|
|
2028
|
-
}
|
|
2029
|
-
hideModal() {
|
|
2030
|
-
if (this.modal) {
|
|
2031
|
-
this.modal.style.display = 'none';
|
|
2032
|
-
// Remove from DOM after animation
|
|
2033
|
-
setTimeout(() => {
|
|
2034
|
-
var _a;
|
|
2035
|
-
(_a = this.modal) === null || _a === void 0 ? void 0 : _a.remove();
|
|
2036
|
-
}, 300);
|
|
2037
|
-
}
|
|
2038
|
-
}
|
|
2039
|
-
/**
|
|
2040
|
-
* Clean up
|
|
2041
|
-
*/
|
|
2042
|
-
destroy() {
|
|
2043
|
-
var _a;
|
|
2044
|
-
(_a = this.modal) === null || _a === void 0 ? void 0 : _a.remove();
|
|
2045
|
-
this.removeAllListeners();
|
|
2046
|
-
}
|
|
2047
|
-
}
|
|
2048
|
-
|
|
2049
1230
|
/**
|
|
2050
1231
|
* Device Authorization Flow Manager
|
|
2051
1232
|
* Manages Device Auth polling flow for desktop/CLI/Unity applications
|
|
@@ -2419,14 +1600,12 @@
|
|
|
2419
1600
|
// Store the flow promise so subsequent calls can await the same result
|
|
2420
1601
|
const flowPromise = this.executeFlow(options);
|
|
2421
1602
|
DeviceAuthFlowManager.currentFlowPromise = flowPromise;
|
|
2422
|
-
DeviceAuthFlowManager.activeInstance = this;
|
|
2423
1603
|
try {
|
|
2424
1604
|
return await flowPromise;
|
|
2425
1605
|
}
|
|
2426
1606
|
finally {
|
|
2427
1607
|
// Clean up static state when flow completes (success or failure)
|
|
2428
1608
|
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2429
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2430
1609
|
}
|
|
2431
1610
|
}
|
|
2432
1611
|
/**
|
|
@@ -2765,8 +1944,6 @@
|
|
|
2765
1944
|
}
|
|
2766
1945
|
/** Shared promise for the current flow - allows multiple callers to await the same result */
|
|
2767
1946
|
DeviceAuthFlowManager.currentFlowPromise = null;
|
|
2768
|
-
/** Reference to the currently active instance */
|
|
2769
|
-
DeviceAuthFlowManager.activeInstance = null;
|
|
2770
1947
|
|
|
2771
1948
|
/**
|
|
2772
1949
|
* Authentication manager
|
|
@@ -2774,12 +1951,10 @@
|
|
|
2774
1951
|
*/
|
|
2775
1952
|
// @ts-ignore - replaced at build time
|
|
2776
1953
|
const DEFAULT_BASE_URL$6 = "https://api.playkit.ai";
|
|
2777
|
-
const JWT_EXCHANGE_ENDPOINT = '/api/external/exchange-jwt';
|
|
2778
1954
|
const TOKEN_REFRESH_ENDPOINT = '/api/auth/refresh';
|
|
2779
1955
|
class AuthManager extends EventEmitter {
|
|
2780
1956
|
constructor(config) {
|
|
2781
1957
|
super();
|
|
2782
|
-
this.authFlowManager = null;
|
|
2783
1958
|
this.deviceAuthFlowManager = null;
|
|
2784
1959
|
this.logger = Logger.getLogger('AuthManager');
|
|
2785
1960
|
/** Shared promise for current device auth flow - allows multiple callers to await the same result */
|
|
@@ -2847,11 +2022,6 @@
|
|
|
2847
2022
|
}
|
|
2848
2023
|
}
|
|
2849
2024
|
}
|
|
2850
|
-
// Check if player JWT was provided
|
|
2851
|
-
if (this.config.playerJWT) {
|
|
2852
|
-
await this.exchangeJWT(this.config.playerJWT);
|
|
2853
|
-
return;
|
|
2854
|
-
}
|
|
2855
2025
|
// Check for platform-injected token (same-domain scenario)
|
|
2856
2026
|
// This allows seamless auth when SDK runs in a context where the platform
|
|
2857
2027
|
// (e.g., Agentland-Space) has already stored a token in localStorage
|
|
@@ -2872,35 +2042,30 @@
|
|
|
2872
2042
|
this.emit('unauthenticated');
|
|
2873
2043
|
// In server mode, don't try to show UI - just throw error
|
|
2874
2044
|
if (this.config.mode === 'server') {
|
|
2875
|
-
throw new PlayKitError('No authentication token provided. In server mode, please provide developerToken
|
|
2045
|
+
throw new PlayKitError('No authentication token provided. In server mode, please provide developerToken or playerToken.', 'NOT_AUTHENTICATED');
|
|
2876
2046
|
}
|
|
2877
2047
|
// Auto-start login flow in browser environment
|
|
2878
2048
|
if (typeof window !== 'undefined') {
|
|
2879
|
-
|
|
2880
|
-
const authMethod = this.config.authMethod || 'device';
|
|
2881
|
-
await this.startAuthFlow(authMethod);
|
|
2049
|
+
await this.startAuthFlow();
|
|
2882
2050
|
// If we reach here, authentication was successful
|
|
2883
2051
|
// If it failed, startAuthFlow() will have thrown an error
|
|
2884
2052
|
}
|
|
2885
2053
|
else {
|
|
2886
2054
|
// Node.js environment - cannot show UI, must provide token manually
|
|
2887
|
-
throw new PlayKitError('No authentication token provided. Please provide developerToken
|
|
2055
|
+
throw new PlayKitError('No authentication token provided. Please provide developerToken or playerToken.', 'NOT_AUTHENTICATED');
|
|
2888
2056
|
}
|
|
2889
2057
|
}
|
|
2890
2058
|
/**
|
|
2891
|
-
* Start the authentication flow
|
|
2892
|
-
*
|
|
2893
|
-
* @param authMethod - Authentication method to use ('device' or 'headless')
|
|
2894
|
-
* @deprecated 'headless' authentication is deprecated and will be removed in v2.0. Use 'device' instead.
|
|
2059
|
+
* Start the authentication flow (Device Authorization + PKCE).
|
|
2895
2060
|
*/
|
|
2896
|
-
async startAuthFlow(
|
|
2061
|
+
async startAuthFlow() {
|
|
2897
2062
|
// If a flow is already in progress, return the shared promise so all callers await the same result
|
|
2898
2063
|
if (this.currentAuthFlowPromise) {
|
|
2899
2064
|
this.logger.debug('Auth flow already in progress, waiting for existing flow');
|
|
2900
2065
|
return this.currentAuthFlowPromise;
|
|
2901
2066
|
}
|
|
2902
2067
|
// Store the flow promise so subsequent calls can await the same result
|
|
2903
|
-
const flowPromise = this.executeAuthFlow(
|
|
2068
|
+
const flowPromise = this.executeAuthFlow();
|
|
2904
2069
|
this.currentAuthFlowPromise = flowPromise;
|
|
2905
2070
|
try {
|
|
2906
2071
|
return await flowPromise;
|
|
@@ -2910,96 +2075,38 @@
|
|
|
2910
2075
|
}
|
|
2911
2076
|
}
|
|
2912
2077
|
/**
|
|
2913
|
-
* Internal method that executes the
|
|
2078
|
+
* Internal method that executes the Device Authorization flow.
|
|
2914
2079
|
* @private
|
|
2915
2080
|
*/
|
|
2916
|
-
async executeAuthFlow(
|
|
2917
|
-
var _a
|
|
2918
|
-
// Deprecation warning for headless auth
|
|
2919
|
-
if (authMethod === 'headless') {
|
|
2920
|
-
this.logger.warn('"headless" authentication is deprecated and will be removed in v2.0. ' +
|
|
2921
|
-
'Please migrate to "device" authentication.');
|
|
2922
|
-
}
|
|
2923
|
-
try {
|
|
2924
|
-
if (authMethod === 'device') {
|
|
2925
|
-
// Use Device Authorization flow (recommended)
|
|
2926
|
-
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
2927
|
-
const result = await this.deviceAuthFlowManager.startFlow({
|
|
2928
|
-
scope: 'player:play',
|
|
2929
|
-
});
|
|
2930
|
-
// Update auth state with the player token and refresh token
|
|
2931
|
-
this.authState = {
|
|
2932
|
-
isAuthenticated: true,
|
|
2933
|
-
token: result.access_token,
|
|
2934
|
-
tokenType: 'player',
|
|
2935
|
-
expiresAt: Date.now() + result.expires_in * 1000,
|
|
2936
|
-
refreshToken: result.refresh_token,
|
|
2937
|
-
refreshExpiresAt: Date.now() + result.refresh_expires_in * 1000,
|
|
2938
|
-
};
|
|
2939
|
-
// Save to storage
|
|
2940
|
-
await this.storage.saveAuthState(this.config.gameId, this.authState);
|
|
2941
|
-
this.emit('authenticated', this.authState);
|
|
2942
|
-
// Clean up
|
|
2943
|
-
this.deviceAuthFlowManager.destroy();
|
|
2944
|
-
this.deviceAuthFlowManager = null;
|
|
2945
|
-
}
|
|
2946
|
-
else {
|
|
2947
|
-
// Use headless verification code flow
|
|
2948
|
-
this.authFlowManager = new AuthFlowManager(this.baseURL);
|
|
2949
|
-
// Get global token from auth flow
|
|
2950
|
-
const globalToken = await this.authFlowManager.startFlow();
|
|
2951
|
-
// Exchange for player token
|
|
2952
|
-
await this.exchangeJWT(globalToken);
|
|
2953
|
-
// Clean up
|
|
2954
|
-
this.authFlowManager.destroy();
|
|
2955
|
-
this.authFlowManager = null;
|
|
2956
|
-
}
|
|
2957
|
-
}
|
|
2958
|
-
catch (error) {
|
|
2959
|
-
// User canceled or error occurred
|
|
2960
|
-
(_a = this.authFlowManager) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
2961
|
-
this.authFlowManager = null;
|
|
2962
|
-
(_b = this.deviceAuthFlowManager) === null || _b === void 0 ? void 0 : _b.destroy();
|
|
2963
|
-
this.deviceAuthFlowManager = null;
|
|
2964
|
-
// Re-emit error
|
|
2965
|
-
this.emit('error', error);
|
|
2966
|
-
throw error;
|
|
2967
|
-
}
|
|
2968
|
-
}
|
|
2969
|
-
/**
|
|
2970
|
-
* Exchange JWT for player token
|
|
2971
|
-
*/
|
|
2972
|
-
async exchangeJWT(jwt) {
|
|
2081
|
+
async executeAuthFlow() {
|
|
2082
|
+
var _a;
|
|
2973
2083
|
try {
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2084
|
+
// Device Authorization flow with PKCE — the only login flow.
|
|
2085
|
+
this.deviceAuthFlowManager = new DeviceAuthFlowManager(this.baseURL, this.config.gameId);
|
|
2086
|
+
const result = await this.deviceAuthFlowManager.startFlow({
|
|
2087
|
+
scope: 'player:play',
|
|
2978
2088
|
});
|
|
2979
|
-
|
|
2980
|
-
const error = await response.json().catch(() => ({ message: 'JWT exchange failed' }));
|
|
2981
|
-
throw new PlayKitError(error.message || 'JWT exchange failed', error.code, response.status);
|
|
2982
|
-
}
|
|
2983
|
-
const data = await response.json();
|
|
2984
|
-
const playerToken = data.playerToken || data.token;
|
|
2985
|
-
if (!playerToken) {
|
|
2986
|
-
throw new PlayKitError('No player token received from server');
|
|
2987
|
-
}
|
|
2988
|
-
// Calculate expiration (assume 24 hours if not provided)
|
|
2989
|
-
const expiresIn = data.expiresIn || 86400;
|
|
2990
|
-
const expiresAt = Date.now() + expiresIn * 1000;
|
|
2089
|
+
// Update auth state with the player token and refresh token
|
|
2991
2090
|
this.authState = {
|
|
2992
2091
|
isAuthenticated: true,
|
|
2993
|
-
token:
|
|
2092
|
+
token: result.access_token,
|
|
2994
2093
|
tokenType: 'player',
|
|
2995
|
-
expiresAt,
|
|
2094
|
+
expiresAt: Date.now() + result.expires_in * 1000,
|
|
2095
|
+
refreshToken: result.refresh_token,
|
|
2096
|
+
refreshExpiresAt: Date.now() + result.refresh_expires_in * 1000,
|
|
2996
2097
|
};
|
|
2997
2098
|
// Save to storage
|
|
2998
2099
|
await this.storage.saveAuthState(this.config.gameId, this.authState);
|
|
2999
2100
|
this.emit('authenticated', this.authState);
|
|
3000
|
-
|
|
2101
|
+
// Clean up
|
|
2102
|
+
this.deviceAuthFlowManager.destroy();
|
|
2103
|
+
this.deviceAuthFlowManager = null;
|
|
3001
2104
|
}
|
|
3002
2105
|
catch (error) {
|
|
2106
|
+
// User canceled or error occurred
|
|
2107
|
+
(_a = this.deviceAuthFlowManager) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
2108
|
+
this.deviceAuthFlowManager = null;
|
|
2109
|
+
// Re-emit error
|
|
3003
2110
|
this.emit('error', error);
|
|
3004
2111
|
throw error;
|
|
3005
2112
|
}
|
|
@@ -3249,7 +2356,7 @@
|
|
|
3249
2356
|
* Check if an authentication flow is currently in progress
|
|
3250
2357
|
*/
|
|
3251
2358
|
isAuthFlowInProgress() {
|
|
3252
|
-
return !!
|
|
2359
|
+
return !!this.deviceAuthFlowManager;
|
|
3253
2360
|
}
|
|
3254
2361
|
/**
|
|
3255
2362
|
* Poll for authorization token after initiateDeviceAuth().
|
|
@@ -4170,6 +3277,11 @@
|
|
|
4170
3277
|
'file',
|
|
4171
3278
|
'audio',
|
|
4172
3279
|
'input_audio',
|
|
3280
|
+
'reasoning',
|
|
3281
|
+
'tool-call',
|
|
3282
|
+
'tool-result',
|
|
3283
|
+
'tool-approval-request',
|
|
3284
|
+
'tool-approval-response',
|
|
4173
3285
|
]);
|
|
4174
3286
|
function describePart(part) {
|
|
4175
3287
|
if (part === null)
|
|
@@ -4212,13 +3324,13 @@
|
|
|
4212
3324
|
if (!hasType) {
|
|
4213
3325
|
if ('role' in part && 'content' in part) {
|
|
4214
3326
|
throw new PlayKitError(`messages[${i}].content[${j}] is shaped like a Message (has role/content) ` +
|
|
4215
|
-
`but content parts must
|
|
3327
|
+
`but content parts must include a recognized 'type' field. ` +
|
|
4216
3328
|
`Did you mean to pass that array as messages directly? ` +
|
|
4217
3329
|
`e.g. \`messages: theArray\` instead of \`messages: [{role:'user', content: theArray}]\`. ` +
|
|
4218
3330
|
`Got part ${describePart(part)}`, 'INVALID_MESSAGES');
|
|
4219
3331
|
}
|
|
4220
3332
|
throw new PlayKitError(`messages[${i}].content[${j}] is missing a recognized 'type' field ` +
|
|
4221
|
-
`(expected one of
|
|
3333
|
+
`(expected one of ${Array.from(VALID_PART_TYPES).join('|')}). Got part ${describePart(part)}`, 'INVALID_MESSAGES');
|
|
4222
3334
|
}
|
|
4223
3335
|
}
|
|
4224
3336
|
}
|
|
@@ -4253,6 +3365,38 @@
|
|
|
4253
3365
|
setPlayerClient(playerClient) {
|
|
4254
3366
|
this.playerClient = playerClient;
|
|
4255
3367
|
}
|
|
3368
|
+
/**
|
|
3369
|
+
* Resolve the `thinking` payload to send on the wire.
|
|
3370
|
+
*
|
|
3371
|
+
* Resolution order for effort: per-request `thinking.effort` > SDK-level
|
|
3372
|
+
* `defaultThinkingEffort` > omit (the server then defaults to off). This
|
|
3373
|
+
* mirrors how the chat model resolves (`chatConfig.model || defaultChatModel`).
|
|
3374
|
+
*
|
|
3375
|
+
* The deprecated `enabled` flag is preserved as an alias: when no effort can be
|
|
3376
|
+
* resolved, `enabled: false` maps to `{ effort: 'off' }` and `enabled: true`
|
|
3377
|
+
* maps to `{ effort: 'minimal' }`.
|
|
3378
|
+
*
|
|
3379
|
+
* @returns The `{ effort }` (and/or `enabled`) object to assign to
|
|
3380
|
+
* `requestBody.thinking`, or `undefined` to send nothing.
|
|
3381
|
+
*/
|
|
3382
|
+
resolveThinking(chatConfig) {
|
|
3383
|
+
const thinking = chatConfig.thinking;
|
|
3384
|
+
// Precedence: per-request `effort` > per-request `enabled` alias > SDK-level
|
|
3385
|
+
// `defaultThinkingEffort` > omit (server then defaults to off). The `enabled`
|
|
3386
|
+
// alias MUST be checked BEFORE the SDK default, so an explicit per-request
|
|
3387
|
+
// `enabled: false` is never overridden by a configured default effort.
|
|
3388
|
+
if (thinking === null || thinking === void 0 ? void 0 : thinking.effort) {
|
|
3389
|
+
return { effort: thinking.effort };
|
|
3390
|
+
}
|
|
3391
|
+
if ((thinking === null || thinking === void 0 ? void 0 : thinking.enabled) !== undefined) {
|
|
3392
|
+
return { effort: thinking.enabled ? 'minimal' : 'off' };
|
|
3393
|
+
}
|
|
3394
|
+
if (this.config.defaultThinkingEffort) {
|
|
3395
|
+
return { effort: this.config.defaultThinkingEffort };
|
|
3396
|
+
}
|
|
3397
|
+
// Nothing to send — server defaults to off.
|
|
3398
|
+
return undefined;
|
|
3399
|
+
}
|
|
4256
3400
|
/**
|
|
4257
3401
|
* Make a chat completion request (non-streaming)
|
|
4258
3402
|
*/
|
|
@@ -4277,8 +3421,9 @@
|
|
|
4277
3421
|
stop: chatConfig.stop || null,
|
|
4278
3422
|
top_p: chatConfig.topP || null,
|
|
4279
3423
|
};
|
|
4280
|
-
|
|
4281
|
-
|
|
3424
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3425
|
+
if (thinking) {
|
|
3426
|
+
requestBody.thinking = thinking;
|
|
4282
3427
|
}
|
|
4283
3428
|
try {
|
|
4284
3429
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -4337,8 +3482,9 @@
|
|
|
4337
3482
|
stop: chatConfig.stop || null,
|
|
4338
3483
|
top_p: chatConfig.topP || null,
|
|
4339
3484
|
};
|
|
4340
|
-
|
|
4341
|
-
|
|
3485
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3486
|
+
if (thinking) {
|
|
3487
|
+
requestBody.thinking = thinking;
|
|
4342
3488
|
}
|
|
4343
3489
|
try {
|
|
4344
3490
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -4404,8 +3550,9 @@
|
|
|
4404
3550
|
if (chatConfig.tool_choice) {
|
|
4405
3551
|
requestBody.tool_choice = chatConfig.tool_choice;
|
|
4406
3552
|
}
|
|
4407
|
-
|
|
4408
|
-
|
|
3553
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3554
|
+
if (thinking) {
|
|
3555
|
+
requestBody.thinking = thinking;
|
|
4409
3556
|
}
|
|
4410
3557
|
try {
|
|
4411
3558
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -4465,8 +3612,9 @@
|
|
|
4465
3612
|
if (chatConfig.tool_choice) {
|
|
4466
3613
|
requestBody.tool_choice = chatConfig.tool_choice;
|
|
4467
3614
|
}
|
|
4468
|
-
|
|
4469
|
-
|
|
3615
|
+
const thinking = this.resolveThinking(chatConfig);
|
|
3616
|
+
if (thinking) {
|
|
3617
|
+
requestBody.thinking = thinking;
|
|
4470
3618
|
}
|
|
4471
3619
|
try {
|
|
4472
3620
|
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
@@ -4851,6 +3999,25 @@
|
|
|
4851
3999
|
}
|
|
4852
4000
|
return response;
|
|
4853
4001
|
}
|
|
4002
|
+
/** GET a TTS endpoint; throws a PlayKitError on a non-ok response. */
|
|
4003
|
+
async get(endpoint) {
|
|
4004
|
+
await this.authManager.ensureValidToken();
|
|
4005
|
+
const token = this.authManager.getToken();
|
|
4006
|
+
if (!token) {
|
|
4007
|
+
throw new PlayKitError('Not authenticated', 'NOT_AUTHENTICATED');
|
|
4008
|
+
}
|
|
4009
|
+
const response = await fetch(`${this.baseURL}${endpoint}`, {
|
|
4010
|
+
method: 'GET',
|
|
4011
|
+
headers: Object.assign({ Authorization: `Bearer ${token}` }, getSDKHeaders()),
|
|
4012
|
+
});
|
|
4013
|
+
if (!response.ok) {
|
|
4014
|
+
const error = await response
|
|
4015
|
+
.json()
|
|
4016
|
+
.catch(() => ({ message: 'Request failed' }));
|
|
4017
|
+
throw new PlayKitError(error.message || 'Request failed', error.code, response.status);
|
|
4018
|
+
}
|
|
4019
|
+
return response;
|
|
4020
|
+
}
|
|
4854
4021
|
checkBalanceAfter() {
|
|
4855
4022
|
if (this.playerClient) {
|
|
4856
4023
|
this.playerClient.checkBalanceAfterApiCall().catch(() => {
|
|
@@ -4935,6 +4102,39 @@
|
|
|
4935
4102
|
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'TTS_ERROR');
|
|
4936
4103
|
}
|
|
4937
4104
|
}
|
|
4105
|
+
/**
|
|
4106
|
+
* List the voices available for speech synthesis.
|
|
4107
|
+
*/
|
|
4108
|
+
async listVoices() {
|
|
4109
|
+
var _a;
|
|
4110
|
+
const endpoint = `/ai/${this.config.gameId}/v2/audio/voices`;
|
|
4111
|
+
try {
|
|
4112
|
+
const response = await this.get(endpoint);
|
|
4113
|
+
const json = (await response.json());
|
|
4114
|
+
const voices = ((_a = json.voices) !== null && _a !== void 0 ? _a : []).map((v) => {
|
|
4115
|
+
const voice = {
|
|
4116
|
+
voiceId: v.voice_id,
|
|
4117
|
+
kind: v.kind === 'custom' ? 'custom' : 'system',
|
|
4118
|
+
};
|
|
4119
|
+
if (v.name !== undefined)
|
|
4120
|
+
voice.name = v.name;
|
|
4121
|
+
if (v.description !== undefined)
|
|
4122
|
+
voice.description = v.description;
|
|
4123
|
+
if (v.language !== undefined)
|
|
4124
|
+
voice.language = v.language;
|
|
4125
|
+
return voice;
|
|
4126
|
+
});
|
|
4127
|
+
return {
|
|
4128
|
+
voices,
|
|
4129
|
+
total: Number(json.total) || voices.length,
|
|
4130
|
+
};
|
|
4131
|
+
}
|
|
4132
|
+
catch (error) {
|
|
4133
|
+
if (error instanceof PlayKitError)
|
|
4134
|
+
throw error;
|
|
4135
|
+
throw new PlayKitError(error instanceof Error ? error.message : 'Unknown error', 'TTS_ERROR');
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4938
4138
|
}
|
|
4939
4139
|
|
|
4940
4140
|
/******************************************************************************
|
|
@@ -5492,14 +4692,14 @@
|
|
|
5492
4692
|
* Generate a single image
|
|
5493
4693
|
*/
|
|
5494
4694
|
async generateImage(config) {
|
|
5495
|
-
var _a;
|
|
4695
|
+
var _a, _b;
|
|
5496
4696
|
const imageConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model, n: 1 });
|
|
5497
4697
|
const response = await this.provider.generateImages(imageConfig);
|
|
5498
4698
|
const imageData = response.data[0];
|
|
5499
4699
|
if (!imageData || !imageData.b64_json) {
|
|
5500
4700
|
throw new Error('No image data in response');
|
|
5501
4701
|
}
|
|
5502
|
-
return new GeneratedImageImpl(imageData.b64_json, config.prompt, (
|
|
4702
|
+
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);
|
|
5503
4703
|
}
|
|
5504
4704
|
/**
|
|
5505
4705
|
* Generate multiple images
|
|
@@ -5508,11 +4708,11 @@
|
|
|
5508
4708
|
const imageConfig = Object.assign(Object.assign({}, config), { model: config.model || this.model, n: config.n || 1 });
|
|
5509
4709
|
const response = await this.provider.generateImages(imageConfig);
|
|
5510
4710
|
return response.data.map((imageData) => {
|
|
5511
|
-
var _a;
|
|
4711
|
+
var _a, _b;
|
|
5512
4712
|
if (!imageData.b64_json) {
|
|
5513
4713
|
throw new Error('No image data in response');
|
|
5514
4714
|
}
|
|
5515
|
-
return new GeneratedImageImpl(imageData.b64_json, config.prompt, (
|
|
4715
|
+
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);
|
|
5516
4716
|
});
|
|
5517
4717
|
}
|
|
5518
4718
|
/**
|
|
@@ -5687,6 +4887,13 @@
|
|
|
5687
4887
|
async synthesizeWithTimestamps(config) {
|
|
5688
4888
|
return this.provider.synthesizeWithTimestamps(Object.assign(Object.assign({}, config), { model: config.model || this.model }));
|
|
5689
4889
|
}
|
|
4890
|
+
/**
|
|
4891
|
+
* List the voices available for speech synthesis
|
|
4892
|
+
* @returns The available voices and a total count
|
|
4893
|
+
*/
|
|
4894
|
+
async listVoices() {
|
|
4895
|
+
return this.provider.listVoices();
|
|
4896
|
+
}
|
|
5690
4897
|
/**
|
|
5691
4898
|
* Synthesize text into speech and return it as a Blob (browser-friendly)
|
|
5692
4899
|
* @param config - Full TTS configuration
|
|
@@ -6560,12 +5767,8 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
6560
5767
|
}));
|
|
6561
5768
|
response.hasActions = response.actionCalls.length > 0;
|
|
6562
5769
|
}
|
|
6563
|
-
// Add assistant response to history
|
|
6564
|
-
const assistantMessage =
|
|
6565
|
-
role: 'assistant',
|
|
6566
|
-
content: response.text,
|
|
6567
|
-
tool_calls: result.tool_calls,
|
|
6568
|
-
};
|
|
5770
|
+
// Add assistant response to history in canonical PlayKit format.
|
|
5771
|
+
const assistantMessage = this.createAssistantHistoryMessage(response.text, result.tool_calls);
|
|
6569
5772
|
this.history.push(assistantMessage);
|
|
6570
5773
|
this.trimHistory();
|
|
6571
5774
|
this.emit('response', response.text);
|
|
@@ -6623,12 +5826,8 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
6623
5826
|
}));
|
|
6624
5827
|
response.hasActions = response.actionCalls.length > 0;
|
|
6625
5828
|
}
|
|
6626
|
-
// Add assistant response to history
|
|
6627
|
-
const assistantMessage =
|
|
6628
|
-
role: 'assistant',
|
|
6629
|
-
content: response.text,
|
|
6630
|
-
tool_calls: result.tool_calls,
|
|
6631
|
-
};
|
|
5829
|
+
// Add assistant response to history in canonical PlayKit format.
|
|
5830
|
+
const assistantMessage = this.createAssistantHistoryMessage(response.text, result.tool_calls);
|
|
6632
5831
|
this.history.push(assistantMessage);
|
|
6633
5832
|
this.trimHistory();
|
|
6634
5833
|
this.emit('response', response.text);
|
|
@@ -6655,22 +5854,64 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
6655
5854
|
*/
|
|
6656
5855
|
reportActionResults(results) {
|
|
6657
5856
|
for (const [callId, result] of Object.entries(results)) {
|
|
6658
|
-
this.history.push(
|
|
6659
|
-
role: 'tool',
|
|
6660
|
-
tool_call_id: callId,
|
|
6661
|
-
content: result,
|
|
6662
|
-
});
|
|
5857
|
+
this.history.push(this.createToolResultHistoryMessage(callId, result));
|
|
6663
5858
|
}
|
|
6664
5859
|
}
|
|
6665
5860
|
/**
|
|
6666
5861
|
* Report a single action result
|
|
6667
5862
|
*/
|
|
6668
5863
|
reportActionResult(callId, result) {
|
|
6669
|
-
this.history.push(
|
|
5864
|
+
this.history.push(this.createToolResultHistoryMessage(callId, result));
|
|
5865
|
+
}
|
|
5866
|
+
createAssistantHistoryMessage(text, toolCalls) {
|
|
5867
|
+
if (!toolCalls || toolCalls.length === 0) {
|
|
5868
|
+
return { role: 'assistant', content: text };
|
|
5869
|
+
}
|
|
5870
|
+
const content = [];
|
|
5871
|
+
if (text) {
|
|
5872
|
+
content.push({ type: 'text', text });
|
|
5873
|
+
}
|
|
5874
|
+
content.push(...toolCalls.map(createToolCallContentPart));
|
|
5875
|
+
return {
|
|
5876
|
+
role: 'assistant',
|
|
5877
|
+
content,
|
|
5878
|
+
};
|
|
5879
|
+
}
|
|
5880
|
+
createToolResultHistoryMessage(callId, result) {
|
|
5881
|
+
const toolName = this.findToolNameForCall(callId);
|
|
5882
|
+
if (!toolName) {
|
|
5883
|
+
// Saved histories from older SDKs may not include enough context to infer
|
|
5884
|
+
// the tool name. Keep the legacy shape; the server normalizer can still
|
|
5885
|
+
// infer it when the matching assistant call is present.
|
|
5886
|
+
return {
|
|
5887
|
+
role: 'tool',
|
|
5888
|
+
tool_call_id: callId,
|
|
5889
|
+
content: result,
|
|
5890
|
+
};
|
|
5891
|
+
}
|
|
5892
|
+
return {
|
|
6670
5893
|
role: 'tool',
|
|
6671
5894
|
tool_call_id: callId,
|
|
6672
|
-
content: result,
|
|
6673
|
-
}
|
|
5895
|
+
content: [createToolResultContentPart(callId, toolName, result)],
|
|
5896
|
+
};
|
|
5897
|
+
}
|
|
5898
|
+
findToolNameForCall(callId) {
|
|
5899
|
+
var _a;
|
|
5900
|
+
for (let i = this.history.length - 1; i >= 0; i--) {
|
|
5901
|
+
const message = this.history[i];
|
|
5902
|
+
if (Array.isArray(message.content)) {
|
|
5903
|
+
for (const part of message.content) {
|
|
5904
|
+
if (part.type === 'tool-call' && part.toolCallId === callId) {
|
|
5905
|
+
return part.toolName;
|
|
5906
|
+
}
|
|
5907
|
+
}
|
|
5908
|
+
}
|
|
5909
|
+
const legacyCall = (_a = message.tool_calls) === null || _a === void 0 ? void 0 : _a.find(tc => tc.id === callId);
|
|
5910
|
+
if (legacyCall) {
|
|
5911
|
+
return legacyCall.function.name;
|
|
5912
|
+
}
|
|
5913
|
+
}
|
|
5914
|
+
return undefined;
|
|
6674
5915
|
}
|
|
6675
5916
|
/**
|
|
6676
5917
|
* Parse tool arguments from JSON string
|
|
@@ -7110,8 +6351,7 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
7110
6351
|
// Auto-restart login flow in browser environment
|
|
7111
6352
|
if (typeof window !== 'undefined') {
|
|
7112
6353
|
this.logger.debug('Restarting authentication flow...');
|
|
7113
|
-
|
|
7114
|
-
await this.authManager.startAuthFlow(authMethod);
|
|
6354
|
+
await this.authManager.startAuthFlow();
|
|
7115
6355
|
// Retry getting player info after re-authentication
|
|
7116
6356
|
await this.playerClient.getPlayerInfo();
|
|
7117
6357
|
this.logger.debug('Re-authentication successful, token validated');
|
|
@@ -7154,12 +6394,11 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
7154
6394
|
throw new PlayKitError('DeveloperToken validation failed: ' + (error instanceof Error ? error.message : String(error)), 'DEVELOPER_TOKEN_INVALID');
|
|
7155
6395
|
}
|
|
7156
6396
|
// Emit fallback started event
|
|
7157
|
-
|
|
7158
|
-
this.
|
|
7159
|
-
this.logger.debug('Starting fallback to player login', { fallbackMethod });
|
|
6397
|
+
this.emit('developer_token_fallback_started', { fallbackMethod: 'device' });
|
|
6398
|
+
this.logger.debug('Starting fallback to player login');
|
|
7160
6399
|
try {
|
|
7161
6400
|
// Start player login flow
|
|
7162
|
-
await this.authManager.startAuthFlow(
|
|
6401
|
+
await this.authManager.startAuthFlow();
|
|
7163
6402
|
// Verify the new token
|
|
7164
6403
|
await this.playerClient.getPlayerInfo();
|
|
7165
6404
|
// Emit fallback completed event
|
|
@@ -7222,24 +6461,6 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
7222
6461
|
isAuthenticated() {
|
|
7223
6462
|
return this.authManager.isAuthenticated();
|
|
7224
6463
|
}
|
|
7225
|
-
/**
|
|
7226
|
-
* Exchange JWT for player token
|
|
7227
|
-
*/
|
|
7228
|
-
async login(jwt) {
|
|
7229
|
-
const token = await this.authManager.exchangeJWT(jwt);
|
|
7230
|
-
// Verify token validity and fetch user info
|
|
7231
|
-
try {
|
|
7232
|
-
await this.playerClient.getPlayerInfo();
|
|
7233
|
-
this.logger.debug('Login successful, token validated and user info fetched');
|
|
7234
|
-
}
|
|
7235
|
-
catch (error) {
|
|
7236
|
-
// If token is invalid, logout and re-throw error
|
|
7237
|
-
this.logger.error('Token validation failed after login:', error);
|
|
7238
|
-
await this.authManager.logout();
|
|
7239
|
-
throw new Error('Token validation failed: ' + (error instanceof Error ? error.message : String(error)));
|
|
7240
|
-
}
|
|
7241
|
-
return token;
|
|
7242
|
-
}
|
|
7243
6464
|
/**
|
|
7244
6465
|
* Logout
|
|
7245
6466
|
*/
|
|
@@ -7696,7 +6917,6 @@ Output ONLY a JSON array of ${predictionNum} strings, nothing else:
|
|
|
7696
6917
|
var namespace = /*#__PURE__*/Object.freeze({
|
|
7697
6918
|
__proto__: null,
|
|
7698
6919
|
AIContextManager: AIContextManager,
|
|
7699
|
-
AuthFlowManager: AuthFlowManager,
|
|
7700
6920
|
AuthManager: AuthManager,
|
|
7701
6921
|
BrowserStorage: BrowserStorage,
|
|
7702
6922
|
BufferLogHandler: BufferLogHandler,
|