@ttmg/cli 0.4.6-vibe-beta.16 → 0.4.6-vibe-beta.17
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 +6 -12
- package/dist/index.js +119 -40
- package/dist/index.js.map +1 -1
- package/dist/package.json +2 -2
- package/dist/scripts/vibe-ppe-test-preload.cjs +1 -1
- package/dist/scripts/vibe-upload-smoke.js +20 -7
- package/package.json +2 -2
- package/vibe-upload.md +23 -12
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
### @ttmg/cli
|
|
2
2
|
|
|
3
|
+
`0.4.6-vibe-beta.17` 支持上传后扫码预览:`ttmg upload --vibe` 上传完成后继续查询同一任务,收到 `preview_url` 后在原页面显示预览二维码。等待期间保持进程运行;超时或查询失败仍保留上传成功状态,请勿直接重传。详见 [Vibe 接入说明](vibe-upload.md)。
|
|
4
|
+
|
|
5
|
+
Version `0.4.6-vibe-beta.17`: `ttmg upload --vibe` keeps polling the same task after upload and shows a game preview QR on the original page when `preview_url` arrives. Keep the process running. A preview timeout or lookup failure preserves the upload receipt; do not upload again.
|
|
6
|
+
|
|
3
7
|
Vibe 手机扫码授权与上传:`ttmg upload --vibe --dir ./game --title "My game" --icon ./avatar.png --format ndjson`。用户在手机 TikTok 扫码授权后,原命令自动上传。只收集标题和本地头像,并使用游戏目录或代码包;其他应用资料由 CLI 补齐。页面展示标题、头像、描述、类型和子类型。见 [Vibe 接入说明](vibe-upload.md)。
|
|
4
8
|
|
|
5
|
-
扫码上传使用 `0.4.6-vibe-beta.
|
|
9
|
+
扫码上传使用 `0.4.6-vibe-beta.17`,安装后核对版本与能力声明。Snow Crew 已在 PPE 完成真实上传并取得预览链接,用户确认扫码预览跑通;正式环境未开放。
|
|
6
10
|
|
|
7
11
|
`ttmg` is a command-line tool designed for managing and developing mini-game projects. It supports initialization, development, debugging, and packaging for both H5 and native mini-games.
|
|
8
12
|
`ttmg` 是一款专为小游戏项目管理与开发设计的命令行工具,支持 H5 小游戏和原生小游戏的初始化、开发调试及打包构建。
|
|
@@ -14,7 +18,7 @@ Vibe 版本支持手机扫码授权上传、可选 `--description`、分类查
|
|
|
14
18
|
固定版本安装(发布标签为 `vibe-beta`):
|
|
15
19
|
|
|
16
20
|
```bash
|
|
17
|
-
npm install -g @ttmg/cli@0.4.6-vibe-beta.
|
|
21
|
+
npm install -g @ttmg/cli@0.4.6-vibe-beta.17
|
|
18
22
|
ttmg --version
|
|
19
23
|
ttmg capabilities --format json
|
|
20
24
|
ttmg upload --help
|
|
@@ -89,16 +93,6 @@ ttmg login --implicit --email <email> --password <password>
|
|
|
89
93
|
options when credentials are provided by the execution environment.
|
|
90
94
|
执行环境也可以通过 `TTMG_LOGIN_EMAIL` 和 `TTMG_LOGIN_PASSWORD` 提供凭据。
|
|
91
95
|
|
|
92
|
-
Inspect the reusable local session without exposing its Cookie. The status is
|
|
93
|
-
local-only; it does not make a network request. `--require-auth` is useful for
|
|
94
|
-
Agent preflight because it exits non-zero when login is missing.
|
|
95
|
-
可在不暴露 Cookie 的情况下读取本地会话是否可复用。该状态只检查本地配置,不发起网络请求;Agent 预检可增加 `--require-auth`,未登录时以非零状态退出。
|
|
96
|
-
|
|
97
|
-
```
|
|
98
|
-
ttmg auth status --format json
|
|
99
|
-
ttmg auth status --format json --require-auth
|
|
100
|
-
```
|
|
101
|
-
|
|
102
96
|
Agents can discover the exact command and runtime capability surface before
|
|
103
97
|
acting. Unsupported device and Runtime features are explicitly reported as
|
|
104
98
|
`false`; commands that create a platform version are marked with
|
package/dist/index.js
CHANGED
|
@@ -7263,6 +7263,8 @@ Vibe QR upload (real PPE trial):
|
|
|
7263
7263
|
Keep this process running. At waiting_authorization, scan the QR on pageUrl with TikTok on your phone.
|
|
7264
7264
|
pageUrl is the local QR/progress page on the CLI computer. Reopen it with authorizationOpenCommand.
|
|
7265
7265
|
The CLI polls and uploads avatar, app_info and package automatically after authorization. Do not start a second upload.
|
|
7266
|
+
After upload, waiting_preview keeps polling the same task until previewUrl is available; pageUrl then shows the game preview QR.
|
|
7267
|
+
Preview ready: previewReady=true and qrPurpose=game_preview. A preview timeout preserves uploaded=true; check the task, do not reupload.
|
|
7266
7268
|
Real success: terminal=true, status=uploaded, uploaded=true, simulation=false. On failure, read errorCode and nextAction.
|
|
7267
7269
|
The local QR page opens for every output format; --no-open disables automatic opening.
|
|
7268
7270
|
The page displays the submitted title, icon, description, category and subcategory.
|
|
@@ -7711,6 +7713,8 @@ Vibe 扫码上传(真实 PPE 试用):
|
|
|
7711
7713
|
保持原进程运行。在 waiting_authorization 阶段,使用手机 TikTok 扫描 pageUrl 页面中的二维码。
|
|
7712
7714
|
pageUrl 是 CLI 所在电脑的二维码/进度页;重新打开时,执行返回的 authorizationOpenCommand。
|
|
7713
7715
|
CLI 负责轮询,授权后自动上传 avatar、app_info、package,不再启动第二次上传。
|
|
7716
|
+
上传后进入 waiting_preview,继续查询同一任务;拿到 previewUrl 后,原 pageUrl 页面展示游戏预览二维码。
|
|
7717
|
+
previewReady=true 且 qrPurpose=game_preview 表示可扫码预览;等待超时仍保留 uploaded=true,请核对任务,不要重传。
|
|
7714
7718
|
真实成功:terminal=true、status=uploaded、uploaded=true、simulation=false。失败时读取 errorCode 和 nextAction。
|
|
7715
7719
|
所有输出格式都会打开本地二维码页;--no-open 可关闭自动打开。
|
|
7716
7720
|
页面展示本次提交的标题、头像、描述、类型和子类型。
|
|
@@ -16378,7 +16382,7 @@ async function authStatus(options = {}) {
|
|
|
16378
16382
|
return result;
|
|
16379
16383
|
}
|
|
16380
16384
|
|
|
16381
|
-
var version = "0.4.6-vibe-beta.
|
|
16385
|
+
var version = "0.4.6-vibe-beta.17";
|
|
16382
16386
|
var engines = {
|
|
16383
16387
|
node: ">=20.19.1 <21 || >=22"
|
|
16384
16388
|
};
|
|
@@ -17264,7 +17268,18 @@ function getCapabilities() {
|
|
|
17264
17268
|
provisionalHttpAdapter: 'loopback-only',
|
|
17265
17269
|
httpContract: 'minis-import-task',
|
|
17266
17270
|
authorizationQr: true,
|
|
17267
|
-
previewQr:
|
|
17271
|
+
previewQr: true,
|
|
17272
|
+
preview: {
|
|
17273
|
+
taskEndpoint: 'get_minis_import_task_detail_for_agent',
|
|
17274
|
+
waitingStatus: 'waiting_preview',
|
|
17275
|
+
resultFields: ['previewUrl', 'previewReady', 'clientKey', 'appId', 'codeAssetId', 'minisCenterHistoryId'],
|
|
17276
|
+
readiness: 'nonempty-valid-preview-url',
|
|
17277
|
+
qrPurpose: 'game_preview',
|
|
17278
|
+
sameTask: true,
|
|
17279
|
+
timeout: 'shared-operation-timeout',
|
|
17280
|
+
failurePreservesUploaded: true,
|
|
17281
|
+
deviceRunVerified: false,
|
|
17282
|
+
},
|
|
17268
17283
|
realAuthorizationVerified: true,
|
|
17269
17284
|
realUploadVerified: true,
|
|
17270
17285
|
verificationScope: { backend: 'ppe', authorizationMode: 'qr', assets: 'test-fixtures', date: '2026-09-16', production: false },
|
|
@@ -18618,7 +18633,7 @@ var authOpen = /*#__PURE__*/Object.freeze({
|
|
|
18618
18633
|
const prefix = '/bff/app_info/minis_import/';
|
|
18619
18634
|
const MINIS_IMPORT_PATHS = {
|
|
18620
18635
|
create: `${prefix}create_minis_import_task_for_agent/`,
|
|
18621
|
-
status: `${prefix}
|
|
18636
|
+
status: `${prefix}get_minis_import_task_detail_for_agent/`,
|
|
18622
18637
|
icon: `${prefix}upload_minis_import_app_icon_for_agent/`,
|
|
18623
18638
|
info: `${prefix}submit_minis_import_info_for_agent/`,
|
|
18624
18639
|
package: `${prefix}upload_minis_import_package_for_agent/`,
|
|
@@ -18677,6 +18692,31 @@ function createBackend(mode, transport) {
|
|
|
18677
18692
|
});
|
|
18678
18693
|
return {
|
|
18679
18694
|
mode,
|
|
18695
|
+
async getTaskDetail(task, signal) {
|
|
18696
|
+
const data = await call({ method: 'GET', path: MINIS_IMPORT_PATHS.status,
|
|
18697
|
+
data: credentials(task), signal });
|
|
18698
|
+
const raw = status(data.status);
|
|
18699
|
+
if (raw === 8)
|
|
18700
|
+
throw new VibeError('VIBE_AUTH_EXPIRED');
|
|
18701
|
+
if (raw === 7)
|
|
18702
|
+
throw new VibeError('VIBE_TASK_FAILED');
|
|
18703
|
+
if (data.ready_for_input !== undefined && typeof data.ready_for_input !== 'boolean')
|
|
18704
|
+
throw new VibeError('VIBE_INVALID_RESPONSE');
|
|
18705
|
+
const detail = { statusRaw: raw, readyForInput: data.ready_for_input === true };
|
|
18706
|
+
for (const [wire, field] of [['app_id', 'appId'], ['code_asset_id', 'codeAssetId'],
|
|
18707
|
+
['minis_center_history_id', 'minisCenterHistoryId']]) {
|
|
18708
|
+
if (data[wire] !== undefined && data[wire] !== '')
|
|
18709
|
+
detail[field] = taskId(data[wire]);
|
|
18710
|
+
}
|
|
18711
|
+
if (data.client_key !== undefined && data.client_key !== '') {
|
|
18712
|
+
if (!nonempty(data.client_key))
|
|
18713
|
+
throw new VibeError('VIBE_INVALID_RESPONSE');
|
|
18714
|
+
detail.clientKey = data.client_key;
|
|
18715
|
+
}
|
|
18716
|
+
if (data.preview_url !== undefined && data.preview_url !== '')
|
|
18717
|
+
detail.previewUrl = safeWebUrl(data.preview_url);
|
|
18718
|
+
return detail;
|
|
18719
|
+
},
|
|
18680
18720
|
async createTask(input, signal) {
|
|
18681
18721
|
const data = await call({
|
|
18682
18722
|
method: 'POST',
|
|
@@ -18807,6 +18847,7 @@ function createPpeMockBackend(lane, adapter, scenario = 'success') {
|
|
|
18807
18847
|
};
|
|
18808
18848
|
return {
|
|
18809
18849
|
mode: 'ppe-mock',
|
|
18850
|
+
getTaskDetail: (task, signal) => real.getTaskDetail(task, signal),
|
|
18810
18851
|
uploadAvailable: true,
|
|
18811
18852
|
dispose: () => real.dispose?.(),
|
|
18812
18853
|
async createTask(input, signal) {
|
|
@@ -19283,9 +19324,9 @@ const vibePageStyles = `
|
|
|
19283
19324
|
|
|
19284
19325
|
:root{font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;color:#24282f;background:#fff;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased}
|
|
19285
19326
|
*{box-sizing:border-box}
|
|
19286
|
-
body{margin:0;min-height:100vh;min-height:100svh;display:flex;align-items:center;justify-content:center;padding:
|
|
19287
|
-
.shell{width:100%;max-width:400px}
|
|
19288
|
-
.steps{display:flex;align-items:center;justify-content:center;gap:10px;margin:0 0
|
|
19327
|
+
body{margin:0;min-height:100vh;min-height:100svh;display:flex;align-items:center;justify-content:center;padding:64px 24px;font-size:14px;line-height:1.5}
|
|
19328
|
+
.shell{position:relative;width:100%;max-width:400px}
|
|
19329
|
+
.steps{display:flex;align-items:center;justify-content:center;gap:10px;margin:0 0 24px;padding:0;list-style:none}
|
|
19289
19330
|
.step{display:flex;align-items:center;gap:6px;font-size:11px;color:#9298a2;white-space:nowrap}
|
|
19290
19331
|
.step:after{content:"";height:1px;width:25px;margin-left:4px;background:#e9ebef}.step:last-child:after{display:none}
|
|
19291
19332
|
.step-number{height:18px;min-width:18px;border-radius:50%;border:1px solid #e2e5e9;display:grid;place-items:center;font-size:10px}
|
|
@@ -19293,17 +19334,16 @@ body{margin:0;min-height:100vh;min-height:100svh;display:flex;align-items:center
|
|
|
19293
19334
|
.step.done{color:#537565}.step.done .step-number{background:#edf6f0;color:#287c54;border-color:#edf6f0}
|
|
19294
19335
|
.heading{text-align:center}h1{font-size:26px;font-weight:650;line-height:1.35;letter-spacing:-.6px;margin:0 0 10px}
|
|
19295
19336
|
.subtitle{color:#7a818c;font-size:12px;line-height:1.7;margin:0;overflow-wrap:anywhere}
|
|
19296
|
-
.game{margin:
|
|
19297
|
-
.game-summary{display:flex;align-items:center;gap:12px}.game-title{margin:0;font-size:15px;font-weight:600;overflow-wrap:anywhere;min-width:0}
|
|
19337
|
+
.game{margin:24px 0 0;padding-top:20px;border-top:1px solid #eceef1;text-align:center}
|
|
19338
|
+
.game-summary{display:flex;align-items:center;justify-content:center;gap:12px}.game-title{max-width:100%;margin:0;font-size:15px;font-weight:600;overflow-wrap:anywhere;min-width:0}
|
|
19298
19339
|
.game-icon,.game-avatar{width:44px;height:44px;border-radius:10px;flex-shrink:0;background:#f0f2f5}.game-avatar{object-fit:cover}.game-icon{display:grid;place-items:center;color:#707b8b}
|
|
19299
|
-
.game-details{margin:
|
|
19300
|
-
.game-description{white-space:pre-wrap;line-height:1.65}.game-categories{display:grid;grid-template-columns:1fr
|
|
19340
|
+
.game-details{margin:16px 0 0;font-size:13px}.game-details>div:first-child,.game-categories>div{display:flex;align-items:baseline;justify-content:center;gap:8px}.game-details dt{flex-shrink:0;font-size:11px;color:#9298a2;margin:0}.game-details dd{min-width:0;margin:0;text-align:left;overflow-wrap:anywhere}
|
|
19341
|
+
.game-description{white-space:pre-wrap;line-height:1.65}.game-categories{display:grid;grid-template-columns:1fr;gap:16px;margin-top:16px}
|
|
19301
19342
|
.scan-action{text-align:center;font-size:13px;font-weight:500;margin:26px 0 10px}.qr-area{display:flex;justify-content:center}.qr-frame{padding:8px;width:208px;height:208px}.qr-frame img{display:block;width:192px;height:192px;max-width:100%}
|
|
19302
19343
|
.upload-area{display:flex;align-items:center;flex-direction:column;gap:16px;padding-top:26px}.percentage{font-size:34px;line-height:1;font-variant-numeric:tabular-nums;font-weight:550}.percentage span{font-size:16px;color:#858e9d;padding-left:3px}
|
|
19303
19344
|
.progress-wrap{width:100%}progress{display:block;width:100%;height:4px;border:none;border-radius:20px;overflow:hidden;background:#edf0f4;accent-color:#4c6378}progress::-webkit-progress-bar{background:#edf0f4;border-radius:20px}progress::-webkit-progress-value{background:#4c6378;border-radius:20px}progress::-moz-progress-bar{background:#4c6378;border-radius:20px}.transfer-label{text-align:center;font-size:11px;color:#8b939f;margin:8px 0 0}
|
|
19304
|
-
.footer{text-align:center;font-size:10px;line-height:1.7;color:#a0a5ae;margin:
|
|
19305
|
-
@media(max-width:380px){body{padding:
|
|
19306
|
-
@media(max-height:640px){body{align-items:flex-start;padding-top:28px;padding-bottom:28px}}
|
|
19345
|
+
.footer{text-align:center;font-size:10px;line-height:1.7;color:#a0a5ae;margin:24px 0 0}.footer .dot{display:inline-block;height:5px;width:5px;border-radius:50%;background:#c1995e;vertical-align:middle;margin-right:5px}.mock-badge{width:fit-content;margin:0 0 10px auto;font-size:10px;padding:2px 7px;border:1px solid #dfe2e7;border-radius:5px;color:#707783}
|
|
19346
|
+
@media(max-width:380px){body{padding-left:20px;padding-right:20px}.steps{gap:7px}.step:after{width:16px;margin-left:1px}h1{font-size:24px}}
|
|
19307
19347
|
`;
|
|
19308
19348
|
|
|
19309
19349
|
const VIBE_PAGE_WORKER = '__vibe-page-server';
|
|
@@ -19311,7 +19351,7 @@ const VIBE_PAGE_WORKER = '__vibe-page-server';
|
|
|
19311
19351
|
const VIBE_PAGE_HTML_LIMIT = 16 * 1024 * 1024;
|
|
19312
19352
|
const pageUpdates = `(() => {
|
|
19313
19353
|
let etag;
|
|
19314
|
-
const terminal = () => ['complete', 'failed'].includes(document.querySelector('main')?.dataset.phase);
|
|
19354
|
+
const terminal = () => ['complete', 'preview', 'failed'].includes(document.querySelector('main')?.dataset.phase);
|
|
19315
19355
|
async function refresh() {
|
|
19316
19356
|
if (terminal()) return;
|
|
19317
19357
|
try {
|
|
@@ -19405,28 +19445,34 @@ async function renderVibePage(input) {
|
|
|
19405
19445
|
: '<span class="game-icon" aria-hidden="true"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M7 7h10c2 0 3 2 3 4l1 5c.4 2-1 3-2.5 2l-3-2h-7l-3 2C4 19 2.6 18 3 16l1-5c0-2 1-4 3-4Z" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round"/><path d="M8 10v4m-2-2h4m6-1h.01M18 13h.01" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></span>';
|
|
19406
19446
|
const game = `<div class="game"><div class="game-summary">${icon}<p class="game-title">${escape(input.title)}</p></div><dl class="game-details"><div><dt>${zh ? '描述' : 'Description'}</dt><dd class="game-description">${escape(input.description ?? VIBE_PPE_DEFAULT_APP_INFO.description)}</dd></div><div class="game-categories"><div><dt>${zh ? '类型' : 'Category'}</dt><dd>${escape(input.category ?? VIBE_PPE_DEFAULT_APP_INFO.category)}</dd></div><div><dt>${zh ? '子类型' : 'Subcategory'}</dt><dd>${escape(input.subcategory ?? VIBE_PPE_DEFAULT_APP_INFO.subcategory)}</dd></div></div></dl></div>`;
|
|
19407
19447
|
const checkIcon = '<svg width="12" height="12" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="m3 8 3 3 7-7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
19408
|
-
const title = phase === '
|
|
19409
|
-
?
|
|
19410
|
-
|
|
19411
|
-
|
|
19412
|
-
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
|
|
19416
|
-
|
|
19417
|
-
|
|
19418
|
-
|
|
19419
|
-
: phase === '
|
|
19420
|
-
|
|
19421
|
-
|
|
19422
|
-
|
|
19448
|
+
const title = phase === 'waiting_preview' ? (zh ? '正在准备预览' : 'Preparing preview')
|
|
19449
|
+
: phase === 'preview' ? (zh ? '扫码预览游戏' : 'Scan to preview')
|
|
19450
|
+
: phase === 'binding'
|
|
19451
|
+
? copy.bindingTitle
|
|
19452
|
+
: phase === 'uploading'
|
|
19453
|
+
? copy.uploadingTitle
|
|
19454
|
+
: phase === 'failed'
|
|
19455
|
+
? copy.failedTitle
|
|
19456
|
+
: copy.completeTitle;
|
|
19457
|
+
const subtitle = phase === 'waiting_preview' ? (zh ? '游戏内容已上传,预览就绪后会自动显示二维码。' : 'Game content uploaded. The preview QR will appear when ready.')
|
|
19458
|
+
: phase === 'preview' ? (zh ? '上传完成,使用手机 TikTok 扫描下方二维码。' : 'Upload complete. Scan the QR below with TikTok on your phone.')
|
|
19459
|
+
: phase === 'complete' && !input.simulation ? escape(input.message)
|
|
19460
|
+
: phase === 'binding'
|
|
19461
|
+
? copy.bindingSubtitle
|
|
19462
|
+
: phase === 'uploading'
|
|
19463
|
+
? copy.uploadingSubtitle
|
|
19464
|
+
: phase === 'failed'
|
|
19465
|
+
? escape(input.message)
|
|
19466
|
+
: copy.completeSubtitle;
|
|
19467
|
+
const qr = (phase === 'binding' || phase === 'preview') && !input.web && input.qrUrl
|
|
19423
19468
|
? await QRCode.toDataURL(input.qrUrl, {
|
|
19424
19469
|
width: 384,
|
|
19425
19470
|
margin: 4,
|
|
19426
19471
|
errorCorrectionLevel: 'M',
|
|
19427
19472
|
})
|
|
19428
19473
|
: '';
|
|
19429
|
-
const purpose = copy.bindingCode;
|
|
19474
|
+
const purpose = phase === 'preview' ? (zh ? '游戏预览二维码' : 'Game preview QR') : copy.bindingCode;
|
|
19475
|
+
const done = phase === 'complete' || phase === 'preview';
|
|
19430
19476
|
const progress = typeof input.progressPercent === 'number' &&
|
|
19431
19477
|
Number.isFinite(input.progressPercent)
|
|
19432
19478
|
? Math.max(0, Math.min(100, Math.round(input.progressPercent)))
|
|
@@ -19438,7 +19484,7 @@ async function renderVibePage(input) {
|
|
|
19438
19484
|
: '';
|
|
19439
19485
|
return `<!doctype html><html lang="${zh ? 'zh-CN' : 'en'}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escape(title)} · ${escape(input.title)}</title><style>${vibePageStyles}</style><script src="?updates" defer></script></head>
|
|
19440
19486
|
<body><main class="shell" data-phase="${phase}">${input.simulation ? `<p class="mock-badge">${copy.mock}</p>` : ''}
|
|
19441
|
-
<section class="card" aria-labelledby="page-title">${phase === 'failed' ? '' : `<ol class="steps" aria-label="${zh ? '上传步骤' : 'Upload steps'}">${copy.steps.map((label, i) => `<li class="step ${
|
|
19487
|
+
<section class="card" aria-labelledby="page-title">${phase === 'failed' ? '' : `<ol class="steps" aria-label="${zh ? '上传步骤' : 'Upload steps'}">${copy.steps.map((label, i) => `<li class="step ${done || i < step ? 'done' : i === step ? 'active' : ''}"${!done && i === step ? ' aria-current="step"' : ''}><span class="step-number">${done || i < step ? checkIcon : i + 1}</span>${label}</li>`).join('')}</ol>`}
|
|
19442
19488
|
<div class="heading"><h1 id="page-title">${title}</h1><p class="subtitle" role="status">${subtitle}</p></div>${game}${phase === 'binding' ? `<p class="scan-action">${copy.bindingAction}</p>` : ''}${content}
|
|
19443
19489
|
</section>
|
|
19444
19490
|
<p class="footer">${input.simulation ? `<span class="dot" aria-hidden="true"></span>${copy.mockNote}` : copy.footer}</p></main></body></html>`;
|
|
@@ -19634,6 +19680,7 @@ const stageText = {
|
|
|
19634
19680
|
],
|
|
19635
19681
|
uploading: ['授权完成,正在自动上传', 'Authorized; uploading automatically'],
|
|
19636
19682
|
uploaded: ['上传完成', 'Upload complete'],
|
|
19683
|
+
waiting_preview: ['上传完成,正在准备预览', 'Upload complete; preparing preview'],
|
|
19637
19684
|
failed: [
|
|
19638
19685
|
'本次操作失败,请根据错误码处理',
|
|
19639
19686
|
'Operation failed; check the error code',
|
|
@@ -19701,6 +19748,7 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
19701
19748
|
let timedOut = false;
|
|
19702
19749
|
let page;
|
|
19703
19750
|
let backend = deps.backend;
|
|
19751
|
+
let task;
|
|
19704
19752
|
let detached = false;
|
|
19705
19753
|
let progressUpdates = Promise.resolve();
|
|
19706
19754
|
let ppeLane;
|
|
@@ -19844,7 +19892,7 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
19844
19892
|
};
|
|
19845
19893
|
const sourceProjectId = deps.projectId(options);
|
|
19846
19894
|
emit('creating_task', { platformWrite: backend.mode === 'ppe' || backend.mode === 'ppe-mock' });
|
|
19847
|
-
|
|
19895
|
+
task = await backend.createTask({
|
|
19848
19896
|
source_type: 1,
|
|
19849
19897
|
source_project_id: sourceProjectId,
|
|
19850
19898
|
task_idempotency_id: result.operationId,
|
|
@@ -19979,7 +20027,6 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
19979
20027
|
}
|
|
19980
20028
|
}
|
|
19981
20029
|
});
|
|
19982
|
-
task.importToken = '';
|
|
19983
20030
|
task.landingUrl = '';
|
|
19984
20031
|
// A validated upload receipt is authoritative even if result-page rendering fails.
|
|
19985
20032
|
result = { ...result, uploaded: true, ...(backend.mode === 'ppe-mock'
|
|
@@ -19988,20 +20035,48 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
19988
20035
|
await progressUpdates;
|
|
19989
20036
|
if (progressPageError)
|
|
19990
20037
|
throw progressPageError;
|
|
20038
|
+
if (!result.simulation) {
|
|
20039
|
+
emit('waiting_preview', { previewReady: false, terminal: false, nextAction: 'wait',
|
|
20040
|
+
qrPurpose: undefined, authorizationOpenCommand: undefined });
|
|
20041
|
+
await page.update({ ...pageGame, language: getCurrentLanguage(), phase: 'waiting_preview',
|
|
20042
|
+
simulation: false, message: text('waiting_preview') });
|
|
20043
|
+
while (true) {
|
|
20044
|
+
ensureActive();
|
|
20045
|
+
const detail = await backend.getTaskDetail(task, controller.signal);
|
|
20046
|
+
ensureActive();
|
|
20047
|
+
const fields = { taskStatusRaw: detail.statusRaw,
|
|
20048
|
+
...(detail.clientKey ? { clientKey: detail.clientKey } : {}),
|
|
20049
|
+
...(detail.appId ? { appId: detail.appId } : {}),
|
|
20050
|
+
...(detail.codeAssetId ? { codeAssetId: detail.codeAssetId } : {}),
|
|
20051
|
+
...(detail.minisCenterHistoryId ? { minisCenterHistoryId: detail.minisCenterHistoryId } : {}) };
|
|
20052
|
+
if (detail.previewUrl) {
|
|
20053
|
+
result = { ...result, ...fields, previewUrl: detail.previewUrl, previewReady: true };
|
|
20054
|
+
break;
|
|
20055
|
+
}
|
|
20056
|
+
if (Object.entries(fields).some(([key, value]) => result[key] !== value))
|
|
20057
|
+
emit('waiting_preview', fields);
|
|
20058
|
+
await deps.sleep(pollMs, controller.signal);
|
|
20059
|
+
}
|
|
20060
|
+
}
|
|
19991
20061
|
await page.update({
|
|
19992
20062
|
...pageGame,
|
|
19993
20063
|
language: getCurrentLanguage(),
|
|
19994
|
-
phase: 'complete',
|
|
20064
|
+
phase: result.previewReady ? 'preview' : 'complete',
|
|
20065
|
+
qrUrl: result.previewUrl,
|
|
20066
|
+
purpose: result.previewReady ? 'game_preview' : undefined,
|
|
19995
20067
|
simulation: result.simulation,
|
|
19996
20068
|
message: text('uploaded', result.simulation),
|
|
19997
20069
|
});
|
|
19998
20070
|
page.detach();
|
|
19999
20071
|
detached = true;
|
|
20000
|
-
return emit('uploaded', { terminal: true, nextAction: 'none'
|
|
20072
|
+
return emit('uploaded', { terminal: true, nextAction: result.previewReady ? 'scan_qr' : 'none',
|
|
20073
|
+
qrPurpose: result.previewReady ? 'game_preview' : undefined,
|
|
20074
|
+
...(result.previewReady ? { message: getCurrentLanguage() === 'zh-CN'
|
|
20075
|
+
? '上传完成,请使用 TikTok 扫码预览游戏。' : 'Upload complete. Scan with TikTok to preview your game.' } : {}) });
|
|
20001
20076
|
}
|
|
20002
20077
|
catch (error) {
|
|
20003
20078
|
const code = timedOut
|
|
20004
|
-
? 'VIBE_TIMEOUT'
|
|
20079
|
+
? result.uploaded ? 'VIBE_PREVIEW_TIMEOUT' : 'VIBE_TIMEOUT'
|
|
20005
20080
|
: controller.signal.aborted
|
|
20006
20081
|
? 'VIBE_CANCELLED'
|
|
20007
20082
|
: error instanceof VibeError
|
|
@@ -20090,14 +20165,14 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
20090
20165
|
};
|
|
20091
20166
|
const message = result.uploaded
|
|
20092
20167
|
? getCurrentLanguage() === 'zh-CN'
|
|
20093
|
-
? '
|
|
20094
|
-
:
|
|
20168
|
+
? `游戏内容已上传,但${code === 'VIBE_PREVIEW_TIMEOUT' ? '等待预览超时' : code === 'VIBE_CANCELLED' ? '已停止等待预览' : '预览查询或页面显示未完成'}。请核对任务,请勿重复上传。`
|
|
20169
|
+
: `Game content was uploaded, but ${code === 'VIBE_PREVIEW_TIMEOUT' ? 'preview polling timed out' : code === 'VIBE_CANCELLED' ? 'preview polling was cancelled' : 'preview lookup or display did not complete'}. Check the task; do not upload again.`
|
|
20095
20170
|
: messages[code]?.[getCurrentLanguage() === 'zh-CN' ? 0 : 1] ||
|
|
20096
20171
|
text(status);
|
|
20097
20172
|
controller.abort();
|
|
20098
20173
|
await progressUpdates;
|
|
20099
20174
|
// Remove the binding QR on failure too. Keep a readable terminal result page.
|
|
20100
|
-
if (page && code !== 'VIBE_CANCELLED') {
|
|
20175
|
+
if (page && (code !== 'VIBE_CANCELLED' || result.uploaded)) {
|
|
20101
20176
|
try {
|
|
20102
20177
|
await page.update({
|
|
20103
20178
|
...pageMetadata,
|
|
@@ -20117,7 +20192,7 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
20117
20192
|
}
|
|
20118
20193
|
return emit(status, {
|
|
20119
20194
|
terminal: true,
|
|
20120
|
-
nextAction: result.uploaded
|
|
20195
|
+
nextAction: result.uploaded ? 'check_task' : code === 'VIBE_CANCELLED'
|
|
20121
20196
|
? 'none'
|
|
20122
20197
|
: result.uploadAttempted ||
|
|
20123
20198
|
(result.taskId &&
|
|
@@ -20141,6 +20216,10 @@ async function executeVibeUpload(options, onEvent = () => { }, dependencies = {}
|
|
|
20141
20216
|
});
|
|
20142
20217
|
}
|
|
20143
20218
|
finally {
|
|
20219
|
+
if (task) {
|
|
20220
|
+
task.importToken = '';
|
|
20221
|
+
task.landingUrl = '';
|
|
20222
|
+
}
|
|
20144
20223
|
clearTimeout(timeout);
|
|
20145
20224
|
externalSignal?.removeEventListener('abort', cancel);
|
|
20146
20225
|
backend?.dispose?.();
|