@heybox/hb-sdk 0.4.4 → 0.4.5
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 +55 -14
- package/dist/cli-chunks/{create-DAW1oAnH.cjs → create-DpyZCNdo.cjs} +1 -1
- package/dist/cli-chunks/{dev-BA_4fnzO.cjs → dev-DWIpgJnn.cjs} +1 -1
- package/dist/cli-chunks/{doctor-Bbv8Lzu_.cjs → doctor-DBotVUQI.cjs} +1 -1
- package/dist/cli-chunks/{index-Bboot1us.cjs → index-BYMTp2I6.cjs} +171 -43
- package/dist/cli-chunks/{index-D7-awGYB.cjs → index-DRsyeAcg.cjs} +3 -3
- package/dist/cli-chunks/{login-BQo2pIkq.cjs → login-DIgcT1gv.cjs} +2 -2
- package/dist/cli-chunks/{deploy-BaLyuR1X.cjs → remote-DjaOc1VS.cjs} +797 -21
- package/dist/cli-chunks/{session-DiyDXvXu.cjs → session-BAgaqpNL.cjs} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/devtools/mock-host/main.js +430 -391
- package/dist/miniapp-publish.cjs.js +26 -0
- package/dist/miniapp-publish.esm.js +14 -1
- package/dist/templates/vue3-vite-ts/README.md.ejs +1 -1
- package/dist/templates/vue3-vite-ts/package.json.ejs +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +23 -18
- package/skill/references/api-root.md +2 -2
- package/skill/references/cli.md +86 -349
- package/skill/scripts/sync-references.mjs +48 -4
- package/skill/skill.json +4 -4
- package/types/miniapp-publish/index.d.ts +13 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var promises = require('node:readline/promises');
|
|
3
4
|
var childProcess = require('node:child_process');
|
|
4
5
|
var fs = require('node:fs');
|
|
5
6
|
var fs$1 = require('node:fs/promises');
|
|
6
7
|
var path = require('node:path');
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var index = require('./index-Bboot1us.cjs');
|
|
8
|
+
var session = require('./session-BAgaqpNL.cjs');
|
|
9
|
+
var index = require('./index-BYMTp2I6.cjs');
|
|
10
10
|
var node_crypto = require('node:crypto');
|
|
11
11
|
|
|
12
12
|
var re = {exports: {}};
|
|
@@ -2859,8 +2859,21 @@ function formatReason(error) {
|
|
|
2859
2859
|
|
|
2860
2860
|
const MINIAPP_UPLOAD_SCOPE = 'activity';
|
|
2861
2861
|
const ACTIVITY_UPLOAD_KEY_MAX_LENGTH = 64;
|
|
2862
|
+
const USER_MINIPROGRAM_ACCESS_STATUS_API_PATH = '/mall/developer/user_miniprogram/access_status';
|
|
2863
|
+
const LIST_USER_MINIPROGRAM_API_PATH = '/mall/developer/user_miniprogram/list';
|
|
2864
|
+
const CREATE_USER_MINIPROGRAM_API_PATH = '/mall/developer/user_miniprogram/create';
|
|
2865
|
+
const UPDATE_USER_MINIPROGRAM_API_PATH = '/mall/developer/user_miniprogram/update';
|
|
2866
|
+
const DETAIL_USER_MINIPROGRAM_API_PATH = '/mall/developer/user_miniprogram/detail';
|
|
2867
|
+
const USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH = '/mall/developer/user_miniprogram/preview_allowlist';
|
|
2868
|
+
const UPDATE_USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH = '/mall/developer/user_miniprogram/preview_allowlist/update';
|
|
2862
2869
|
const PRECHECK_USER_MINIPROGRAM_VERSION_API_PATH = '/mall/developer/user_miniprogram/version/precheck';
|
|
2863
2870
|
const SUBMIT_USER_MINIPROGRAM_AUDIT_API_PATH = '/mall/developer/user_miniprogram/version/submit_audit';
|
|
2871
|
+
const USER_MINIPROGRAM_VERSION_PREVIEW_INFO_API_PATH = '/mall/developer/user_miniprogram/version/preview_info';
|
|
2872
|
+
const WITHDRAW_USER_MINIPROGRAM_VERSION_API_PATH = '/mall/developer/user_miniprogram/version/withdraw';
|
|
2873
|
+
const RELEASE_USER_MINIPROGRAM_VERSION_API_PATH = '/mall/developer/user_miniprogram/version/release';
|
|
2874
|
+
const TAKE_DOWN_USER_MINIPROGRAM_API_PATH = '/mall/developer/user_miniprogram/take_down';
|
|
2875
|
+
const REOPEN_USER_MINIPROGRAM_API_PATH = '/mall/developer/user_miniprogram/reopen';
|
|
2876
|
+
const LIST_USER_MINIPROGRAM_VERSION_API_PATH = '/mall/developer/user_miniprogram/version/list';
|
|
2864
2877
|
const FNV_OFFSET = 0x811c9dc5;
|
|
2865
2878
|
const FNV_PRIME = 0x01000193;
|
|
2866
2879
|
function normalizeRelativePath(relativePath) {
|
|
@@ -3328,7 +3341,7 @@ async function createDefaultCosClient(uploadToken) {
|
|
|
3328
3341
|
};
|
|
3329
3342
|
}
|
|
3330
3343
|
async function loadCosConstructor() {
|
|
3331
|
-
const cosModule = await Promise.resolve().then(function () { return require('./index-
|
|
3344
|
+
const cosModule = await Promise.resolve().then(function () { return require('./index-DRsyeAcg.cjs'); }).then(function (n) { return n.index; });
|
|
3332
3345
|
return cosModule.default;
|
|
3333
3346
|
}
|
|
3334
3347
|
function formatSize(bytes) {
|
|
@@ -3371,14 +3384,14 @@ function isRecord(value) {
|
|
|
3371
3384
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
3372
3385
|
}
|
|
3373
3386
|
|
|
3374
|
-
async function precheckUserMiniprogramVersion(options, runtime = {}) {
|
|
3387
|
+
async function precheckUserMiniprogramVersion$1(options, runtime = {}) {
|
|
3375
3388
|
return postUserMiniprogramVersionForm(PRECHECK_USER_MINIPROGRAM_VERSION_API_PATH, options, {
|
|
3376
3389
|
version: options.version,
|
|
3377
3390
|
release_note: options.releaseNote,
|
|
3378
3391
|
auto_publish: String(options.autoPublish),
|
|
3379
3392
|
}, runtime);
|
|
3380
3393
|
}
|
|
3381
|
-
async function submitUserMiniprogramAudit(options, runtime = {}) {
|
|
3394
|
+
async function submitUserMiniprogramAudit$1(options, runtime = {}) {
|
|
3382
3395
|
return postUserMiniprogramVersionForm(SUBMIT_USER_MINIPROGRAM_AUDIT_API_PATH, options, {
|
|
3383
3396
|
manifest: JSON.stringify(options.manifest),
|
|
3384
3397
|
release_note: options.releaseNote,
|
|
@@ -3460,7 +3473,10 @@ async function runDeployCommand(options, runtime = {}) {
|
|
|
3460
3473
|
}, runtime, apiBaseUrl, projectRoot, logger);
|
|
3461
3474
|
const pm = detectPackageManager(projectRoot);
|
|
3462
3475
|
logger.info(`开始构建: ${pm} run build`);
|
|
3463
|
-
await runBuildScript(pm, projectRoot, runtime.spawn ?? childProcess.spawn
|
|
3476
|
+
await runBuildScript(pm, projectRoot, runtime.spawn ?? childProcess.spawn, {
|
|
3477
|
+
outputMode: options.buildOutputMode ?? 'inherit',
|
|
3478
|
+
stderr: runtime.stderr,
|
|
3479
|
+
});
|
|
3464
3480
|
logger.success('构建完成');
|
|
3465
3481
|
}
|
|
3466
3482
|
else {
|
|
@@ -3502,15 +3518,36 @@ async function runDeployCommand(options, runtime = {}) {
|
|
|
3502
3518
|
throw translateHeyboxDeployError(error, { projectRoot, stage: 'upload', version });
|
|
3503
3519
|
}
|
|
3504
3520
|
try {
|
|
3505
|
-
submitAuditResult = await logger.task('正在提交审核', () => (runtime.submitUserMiniprogramAudit ?? submitUserMiniprogramAudit)({ session: session$1, miniProgramId, manifest, releaseNote, autoPublish }, { baseUrl: apiBaseUrl, fetchImpl: runtime.fetchImpl }), { successText: '审核提交完成' });
|
|
3521
|
+
submitAuditResult = await logger.task('正在提交审核', () => (runtime.submitUserMiniprogramAudit ?? submitUserMiniprogramAudit$1)({ session: session$1, miniProgramId, manifest, releaseNote, autoPublish }, { baseUrl: apiBaseUrl, fetchImpl: runtime.fetchImpl }), { successText: '审核提交完成' });
|
|
3506
3522
|
}
|
|
3507
3523
|
catch (error) {
|
|
3508
3524
|
throw translateHeyboxDeployError(error, { projectRoot, stage: 'submitAudit', version });
|
|
3509
3525
|
}
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3526
|
+
printDeploySuccess({ autoPublish, logger, miniProgramId, mode: options.successOutputMode ?? 'legacy', previewUrl: submitAuditResult.preview_url, version });
|
|
3527
|
+
return {
|
|
3528
|
+
autoPublish,
|
|
3529
|
+
changed: true,
|
|
3530
|
+
miniProgramId,
|
|
3531
|
+
...(submitAuditResult.preview_url ? { previewUrl: submitAuditResult.preview_url } : {}),
|
|
3532
|
+
version,
|
|
3533
|
+
};
|
|
3534
|
+
}
|
|
3535
|
+
function printDeploySuccess(options) {
|
|
3536
|
+
options.logger.success(`提交审核成功:${options.miniProgramId} ${options.version}`);
|
|
3537
|
+
if (options.mode === 'remote') {
|
|
3538
|
+
options.logger.info(`发布策略:${options.autoPublish ? '审核通过后自动发布' : '审核通过后需手动发布'}`);
|
|
3539
|
+
if (options.previewUrl) {
|
|
3540
|
+
options.logger.info(`Preview URL: ${options.previewUrl}`);
|
|
3541
|
+
options.logger.info('允许他人预览:hb-sdk remote allowlist add <heybox_id>');
|
|
3542
|
+
}
|
|
3543
|
+
options.logger.info(options.autoPublish
|
|
3544
|
+
? '下一步:hb-sdk remote versions'
|
|
3545
|
+
: `下一步:hb-sdk remote versions;审核通过后运行 hb-sdk remote release ${options.version}`);
|
|
3546
|
+
return;
|
|
3547
|
+
}
|
|
3548
|
+
options.logger.info(`发布策略:${options.autoPublish ? '审核通过后自动发布' : '审核通过后需在开放平台手动发布'}`);
|
|
3549
|
+
if (options.previewUrl) {
|
|
3550
|
+
options.logger.info(`Preview URL: ${options.previewUrl}`);
|
|
3514
3551
|
}
|
|
3515
3552
|
}
|
|
3516
3553
|
function findProjectRoot(startDir) {
|
|
@@ -3574,7 +3611,7 @@ async function maybePromptReleaseNote(runtime) {
|
|
|
3574
3611
|
}
|
|
3575
3612
|
const isTTY = runtime.isTTY ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
3576
3613
|
if (!isTTY) {
|
|
3577
|
-
throw new Error('非交互环境执行 hb-sdk deploy 必须传 --release-note <text>');
|
|
3614
|
+
throw new Error('非交互环境执行 hb-sdk remote deploy 必须传 --release-note <text>');
|
|
3578
3615
|
}
|
|
3579
3616
|
const input = runtime.stdin ?? process.stdin;
|
|
3580
3617
|
const output = runtime.stdout ?? process.stdout;
|
|
@@ -3588,7 +3625,7 @@ async function maybePromptReleaseNote(runtime) {
|
|
|
3588
3625
|
}
|
|
3589
3626
|
async function runVersionPrecheck(options, runtime, apiBaseUrl, projectRoot, logger) {
|
|
3590
3627
|
try {
|
|
3591
|
-
await logger.task(`正在预检版本 ${options.version}`, () => (runtime.precheckUserMiniprogramVersion ?? precheckUserMiniprogramVersion)(options, {
|
|
3628
|
+
await logger.task(`正在预检版本 ${options.version}`, () => (runtime.precheckUserMiniprogramVersion ?? precheckUserMiniprogramVersion$1)(options, {
|
|
3592
3629
|
baseUrl: apiBaseUrl,
|
|
3593
3630
|
fetchImpl: runtime.fetchImpl,
|
|
3594
3631
|
}), { successText: `版本 ${options.version} 预检通过` });
|
|
@@ -3605,12 +3642,18 @@ function detectPackageManager(projectRoot) {
|
|
|
3605
3642
|
}
|
|
3606
3643
|
return 'npm';
|
|
3607
3644
|
}
|
|
3608
|
-
async function runBuildScript(pm, cwd, spawnImpl) {
|
|
3645
|
+
async function runBuildScript(pm, cwd, spawnImpl, options) {
|
|
3609
3646
|
await new Promise((resolve, reject) => {
|
|
3647
|
+
const pipeStdoutToStderr = options.outputMode === 'stderr';
|
|
3610
3648
|
const child = spawnImpl(pm, ['run', 'build'], {
|
|
3611
3649
|
cwd,
|
|
3612
|
-
stdio: 'inherit',
|
|
3650
|
+
stdio: pipeStdoutToStderr ? ['inherit', 'pipe', 'inherit'] : 'inherit',
|
|
3613
3651
|
});
|
|
3652
|
+
if (pipeStdoutToStderr) {
|
|
3653
|
+
child.stdout?.on('data', (chunk) => {
|
|
3654
|
+
(options.stderr ?? process.stderr).write(chunk);
|
|
3655
|
+
});
|
|
3656
|
+
}
|
|
3614
3657
|
child.on('error', reject);
|
|
3615
3658
|
child.on('exit', (code) => {
|
|
3616
3659
|
if (code === 0) {
|
|
@@ -3719,12 +3762,745 @@ function suggestNextPatchVersion(version) {
|
|
|
3719
3762
|
return `${matched[1]}.${matched[2]}.${Number(matched[3]) + 1}`;
|
|
3720
3763
|
}
|
|
3721
3764
|
|
|
3722
|
-
|
|
3765
|
+
function createRemoteApiClient(options) {
|
|
3766
|
+
return {
|
|
3767
|
+
getDeveloperAccessStatus: () => getDeveloperAccessStatus(options),
|
|
3768
|
+
listUserMiniprograms: (requestOptions = {}) => listUserMiniprograms(requestOptions, options),
|
|
3769
|
+
createUserMiniprogram: (requestOptions) => createUserMiniprogram(requestOptions, options),
|
|
3770
|
+
updateUserMiniprogram: (requestOptions) => updateUserMiniprogram(requestOptions, options),
|
|
3771
|
+
getUserMiniprogramDetail: (requestOptions) => getUserMiniprogramDetail(requestOptions, options),
|
|
3772
|
+
getPreviewAllowlist: (requestOptions) => getPreviewAllowlist(requestOptions, options),
|
|
3773
|
+
updatePreviewAllowlist: (requestOptions) => updatePreviewAllowlist(requestOptions, options),
|
|
3774
|
+
precheckUserMiniprogramVersion: (requestOptions) => precheckUserMiniprogramVersion(requestOptions, options),
|
|
3775
|
+
submitUserMiniprogramAudit: (requestOptions) => submitUserMiniprogramAudit(requestOptions, options),
|
|
3776
|
+
getVersionPreviewInfo: (requestOptions) => getVersionPreviewInfo(requestOptions, options),
|
|
3777
|
+
withdrawUserMiniprogramVersion: (requestOptions) => withdrawUserMiniprogramVersion(requestOptions, options),
|
|
3778
|
+
releaseUserMiniprogramVersion: (requestOptions) => releaseUserMiniprogramVersion(requestOptions, options),
|
|
3779
|
+
takeDownUserMiniprogram: (requestOptions) => takeDownUserMiniprogram(requestOptions, options),
|
|
3780
|
+
reopenUserMiniprogram: (requestOptions) => reopenUserMiniprogram(requestOptions, options),
|
|
3781
|
+
listUserMiniprogramVersions: (requestOptions) => listUserMiniprogramVersions(requestOptions, options),
|
|
3782
|
+
};
|
|
3783
|
+
}
|
|
3784
|
+
async function getDeveloperAccessStatus(runtime) {
|
|
3785
|
+
return remoteGet(USER_MINIPROGRAM_ACCESS_STATUS_API_PATH, {}, runtime);
|
|
3786
|
+
}
|
|
3787
|
+
async function listUserMiniprograms(options, runtime) {
|
|
3788
|
+
return remoteGet(LIST_USER_MINIPROGRAM_API_PATH, options, runtime);
|
|
3789
|
+
}
|
|
3790
|
+
async function createUserMiniprogram(options, runtime) {
|
|
3791
|
+
return remotePostForm(CREATE_USER_MINIPROGRAM_API_PATH, options, runtime);
|
|
3792
|
+
}
|
|
3793
|
+
async function updateUserMiniprogram(options, runtime) {
|
|
3794
|
+
return remotePostForm(UPDATE_USER_MINIPROGRAM_API_PATH, options, runtime);
|
|
3795
|
+
}
|
|
3796
|
+
async function getUserMiniprogramDetail(options, runtime) {
|
|
3797
|
+
return remoteGet(DETAIL_USER_MINIPROGRAM_API_PATH, options, runtime);
|
|
3798
|
+
}
|
|
3799
|
+
async function getPreviewAllowlist(options, runtime) {
|
|
3800
|
+
return remoteGet(USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH, options, runtime);
|
|
3801
|
+
}
|
|
3802
|
+
async function updatePreviewAllowlist(options, runtime) {
|
|
3803
|
+
return remotePostForm(UPDATE_USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH, options, runtime);
|
|
3804
|
+
}
|
|
3805
|
+
async function precheckUserMiniprogramVersion(options, runtime) {
|
|
3806
|
+
return remotePostForm(PRECHECK_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
|
|
3807
|
+
}
|
|
3808
|
+
async function submitUserMiniprogramAudit(options, runtime) {
|
|
3809
|
+
return remotePostForm(SUBMIT_USER_MINIPROGRAM_AUDIT_API_PATH, {
|
|
3810
|
+
...options,
|
|
3811
|
+
manifest: typeof options.manifest === 'string' ? options.manifest : JSON.stringify(options.manifest),
|
|
3812
|
+
}, runtime);
|
|
3813
|
+
}
|
|
3814
|
+
async function getVersionPreviewInfo(options, runtime) {
|
|
3815
|
+
return remoteGet(USER_MINIPROGRAM_VERSION_PREVIEW_INFO_API_PATH, options, runtime);
|
|
3816
|
+
}
|
|
3817
|
+
async function withdrawUserMiniprogramVersion(options, runtime) {
|
|
3818
|
+
return remotePostForm(WITHDRAW_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
|
|
3819
|
+
}
|
|
3820
|
+
async function releaseUserMiniprogramVersion(options, runtime) {
|
|
3821
|
+
return remotePostForm(RELEASE_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
|
|
3822
|
+
}
|
|
3823
|
+
async function takeDownUserMiniprogram(options, runtime) {
|
|
3824
|
+
return remotePostForm(TAKE_DOWN_USER_MINIPROGRAM_API_PATH, options, runtime);
|
|
3825
|
+
}
|
|
3826
|
+
async function reopenUserMiniprogram(options, runtime) {
|
|
3827
|
+
return remotePostForm(REOPEN_USER_MINIPROGRAM_API_PATH, options, runtime);
|
|
3828
|
+
}
|
|
3829
|
+
async function listUserMiniprogramVersions(options, runtime) {
|
|
3830
|
+
return remoteGet(LIST_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
|
|
3831
|
+
}
|
|
3832
|
+
async function remoteGet(path, query, runtime) {
|
|
3833
|
+
const pathWithQuery = createPathWithQuery(path, query);
|
|
3834
|
+
const context = createHeyboxOpenPlatformRequestContext(runtime.session, pathWithQuery);
|
|
3835
|
+
const fetchImpl = runtime.fetchImpl ?? fetch;
|
|
3836
|
+
const response = await fetchImpl(createHeyboxApiUrl(runtime.baseUrl ?? context.baseUrl, pathWithQuery, context.platformParams), {
|
|
3837
|
+
method: 'GET',
|
|
3838
|
+
headers: context.headers,
|
|
3839
|
+
});
|
|
3840
|
+
return readRequiredResult(response, pathWithQuery);
|
|
3841
|
+
}
|
|
3842
|
+
async function remotePostForm(path, fields, runtime) {
|
|
3843
|
+
const context = createHeyboxOpenPlatformRequestContext(runtime.session, path, {
|
|
3844
|
+
contentType: 'application/x-www-form-urlencoded',
|
|
3845
|
+
});
|
|
3846
|
+
const fetchImpl = runtime.fetchImpl ?? fetch;
|
|
3847
|
+
const response = await fetchImpl(createHeyboxApiUrl(runtime.baseUrl ?? context.baseUrl, path, context.platformParams), {
|
|
3848
|
+
method: 'POST',
|
|
3849
|
+
headers: context.headers,
|
|
3850
|
+
body: createFormBody(fields),
|
|
3851
|
+
});
|
|
3852
|
+
return readRequiredResult(response, path);
|
|
3853
|
+
}
|
|
3854
|
+
async function readRequiredResult(response, pathWithQuery) {
|
|
3855
|
+
const result = await readHeyboxApiEnvelope(response, { pathWithQuery, requireResult: true });
|
|
3856
|
+
return result;
|
|
3857
|
+
}
|
|
3858
|
+
function createPathWithQuery(path, query) {
|
|
3859
|
+
const params = new URLSearchParams();
|
|
3860
|
+
for (const [key, value] of Object.entries(query)) {
|
|
3861
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
3862
|
+
params.set(key, String(value));
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
const queryString = params.toString();
|
|
3866
|
+
return queryString ? `${path}?${queryString}` : path;
|
|
3867
|
+
}
|
|
3868
|
+
function createFormBody(fields) {
|
|
3869
|
+
const body = new URLSearchParams();
|
|
3870
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
3871
|
+
if (value === undefined || value === null) {
|
|
3872
|
+
continue;
|
|
3873
|
+
}
|
|
3874
|
+
if (Array.isArray(value)) {
|
|
3875
|
+
body.set(key, value.join(','));
|
|
3876
|
+
continue;
|
|
3877
|
+
}
|
|
3878
|
+
if (typeof value === 'object') {
|
|
3879
|
+
body.set(key, JSON.stringify(value));
|
|
3880
|
+
continue;
|
|
3881
|
+
}
|
|
3882
|
+
body.set(key, String(value));
|
|
3883
|
+
}
|
|
3884
|
+
return body.toString();
|
|
3885
|
+
}
|
|
3886
|
+
|
|
3887
|
+
class MiniProgramProjectBindingError extends Error {
|
|
3888
|
+
code;
|
|
3889
|
+
constructor(message, code) {
|
|
3890
|
+
super(message);
|
|
3891
|
+
this.code = code;
|
|
3892
|
+
this.name = 'MiniProgramProjectBindingError';
|
|
3893
|
+
}
|
|
3894
|
+
}
|
|
3895
|
+
function findMiniProgramProjectRoot(startDir) {
|
|
3896
|
+
let current = path.resolve(startDir);
|
|
3897
|
+
while (true) {
|
|
3898
|
+
if (fs.existsSync(path.join(current, 'package.json'))) {
|
|
3899
|
+
return current;
|
|
3900
|
+
}
|
|
3901
|
+
const parent = path.dirname(current);
|
|
3902
|
+
if (parent === current) {
|
|
3903
|
+
throw new MiniProgramProjectBindingError('当前目录或父目录未找到 package.json', 'PACKAGE_JSON_NOT_FOUND');
|
|
3904
|
+
}
|
|
3905
|
+
current = parent;
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
async function readMiniProgramProjectPackage(startDir) {
|
|
3909
|
+
const projectRoot = findMiniProgramProjectRoot(startDir);
|
|
3910
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
3911
|
+
const raw = await fs$1.readFile(packageJsonPath, 'utf8');
|
|
3912
|
+
let packageJson;
|
|
3913
|
+
try {
|
|
3914
|
+
packageJson = JSON.parse(raw);
|
|
3915
|
+
}
|
|
3916
|
+
catch (error) {
|
|
3917
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3918
|
+
throw new MiniProgramProjectBindingError(`package.json 不是合法 JSON:${packageJsonPath}\n${message}`, 'PACKAGE_JSON_INVALID');
|
|
3919
|
+
}
|
|
3920
|
+
return {
|
|
3921
|
+
projectRoot,
|
|
3922
|
+
packageJsonPath,
|
|
3923
|
+
packageJson,
|
|
3924
|
+
raw,
|
|
3925
|
+
indent: detectJsonIndent(raw),
|
|
3926
|
+
trailingNewline: raw.endsWith('\r\n') ? '\r\n' : raw.endsWith('\n') ? '\n' : '',
|
|
3927
|
+
};
|
|
3928
|
+
}
|
|
3929
|
+
function readBoundMiniProgramIdFromPackageJson(packageJson) {
|
|
3930
|
+
const value = packageJson.heybox?.miniProgramId;
|
|
3931
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
3932
|
+
}
|
|
3933
|
+
async function writeBoundMiniProgramId(startDir, miniProgramId, options = {}) {
|
|
3934
|
+
const context = await readMiniProgramProjectPackage(startDir);
|
|
3935
|
+
const normalizedMiniProgramId = String(miniProgramId).trim();
|
|
3936
|
+
if (!normalizedMiniProgramId) {
|
|
3937
|
+
throw new MiniProgramProjectBindingError('miniProgramId 不能为空', 'PACKAGE_JSON_INVALID');
|
|
3938
|
+
}
|
|
3939
|
+
const currentMiniProgramId = readBoundMiniProgramIdFromPackageJson(context.packageJson);
|
|
3940
|
+
if (currentMiniProgramId && currentMiniProgramId !== normalizedMiniProgramId && !options.force) {
|
|
3941
|
+
throw new MiniProgramProjectBindingError(`当前项目已绑定小程序 ${currentMiniProgramId}。如需覆盖本地绑定,请使用 --force。`, 'MINI_PROGRAM_BINDING_EXISTS');
|
|
3942
|
+
}
|
|
3943
|
+
if (currentMiniProgramId === normalizedMiniProgramId) {
|
|
3944
|
+
return {
|
|
3945
|
+
...context,
|
|
3946
|
+
changed: false,
|
|
3947
|
+
miniProgramId: normalizedMiniProgramId,
|
|
3948
|
+
};
|
|
3949
|
+
}
|
|
3950
|
+
if (context.packageJson.heybox !== undefined && !isPlainObject(context.packageJson.heybox)) {
|
|
3951
|
+
throw new MiniProgramProjectBindingError('package.json heybox 字段必须是对象,不能写入 miniProgramId', 'PACKAGE_JSON_HEYBOX_INVALID');
|
|
3952
|
+
}
|
|
3953
|
+
context.packageJson.heybox = {
|
|
3954
|
+
...(context.packageJson.heybox ?? {}),
|
|
3955
|
+
miniProgramId: normalizedMiniProgramId,
|
|
3956
|
+
};
|
|
3957
|
+
await fs$1.writeFile(context.packageJsonPath, `${JSON.stringify(context.packageJson, null, context.indent)}${context.trailingNewline || '\n'}`, 'utf8');
|
|
3958
|
+
return {
|
|
3959
|
+
...context,
|
|
3960
|
+
changed: true,
|
|
3961
|
+
miniProgramId: normalizedMiniProgramId,
|
|
3962
|
+
};
|
|
3963
|
+
}
|
|
3964
|
+
function detectJsonIndent(raw) {
|
|
3965
|
+
const match = raw.match(/\n(\s+)"[^"]+":/);
|
|
3966
|
+
return match?.[1] ?? 2;
|
|
3967
|
+
}
|
|
3968
|
+
function isPlainObject(value) {
|
|
3969
|
+
return Object.prototype.toString.call(value) === '[object Object]';
|
|
3970
|
+
}
|
|
3971
|
+
|
|
3972
|
+
async function resolveRemoteEnvironment(options = {}, runtime = {}) {
|
|
3973
|
+
const env = options.env ?? process.env;
|
|
3974
|
+
const apiBaseUrl = session.resolveHeyboxApiBaseUrl({ ...options, env });
|
|
3975
|
+
const loginBaseUrl = session.resolveHeyboxLoginBaseUrl({ ...options, env });
|
|
3976
|
+
const session$1 = options.session ?? (await (runtime.requireAuthSession ?? session.requireHeyboxAuthSession)({ loginBaseUrl }));
|
|
3977
|
+
return {
|
|
3978
|
+
apiBaseUrl,
|
|
3979
|
+
loginBaseUrl,
|
|
3980
|
+
allowUnsafeApiBaseUrl: options.allowUnsafeApiBaseUrl === true || isTruthyEnvFlag(env.HB_SDK_ALLOW_UNSAFE_API_BASE_URL),
|
|
3981
|
+
env,
|
|
3982
|
+
fetchImpl: runtime.fetchImpl ?? options.fetchImpl ?? fetch,
|
|
3983
|
+
session: session$1,
|
|
3984
|
+
};
|
|
3985
|
+
}
|
|
3986
|
+
function createRemoteApiClientForEnvironment(environment) {
|
|
3987
|
+
return createRemoteApiClient({
|
|
3988
|
+
baseUrl: environment.apiBaseUrl,
|
|
3989
|
+
fetchImpl: environment.fetchImpl,
|
|
3990
|
+
session: environment.session,
|
|
3991
|
+
});
|
|
3992
|
+
}
|
|
3993
|
+
function isTruthyEnvFlag(value) {
|
|
3994
|
+
return ['1', 'true', 'yes', 'on'].includes(String(value ?? '')
|
|
3995
|
+
.trim()
|
|
3996
|
+
.toLowerCase());
|
|
3997
|
+
}
|
|
3998
|
+
|
|
3999
|
+
async function runRemoteCommand(options, runtime = {}) {
|
|
4000
|
+
if (options.command === 'deploy') {
|
|
4001
|
+
return runRemoteDeployCommand(options, runtime);
|
|
4002
|
+
}
|
|
4003
|
+
const context = await createRemoteCommandContext(options, runtime);
|
|
4004
|
+
switch (options.command) {
|
|
4005
|
+
case 'access':
|
|
4006
|
+
return remoteAccess(options, context, runtime);
|
|
4007
|
+
case 'list':
|
|
4008
|
+
return remoteList(options, context, runtime);
|
|
4009
|
+
case 'create':
|
|
4010
|
+
return remoteCreate(options, context, runtime);
|
|
4011
|
+
case 'bind':
|
|
4012
|
+
return remoteBind(options, context, runtime);
|
|
4013
|
+
case 'info':
|
|
4014
|
+
return remoteInfo(options, context, runtime);
|
|
4015
|
+
case 'update':
|
|
4016
|
+
return remoteUpdate(options, context, runtime);
|
|
4017
|
+
case 'allowlist:list':
|
|
4018
|
+
return remoteAllowlistList(options, context, runtime);
|
|
4019
|
+
case 'allowlist:add':
|
|
4020
|
+
case 'allowlist:remove':
|
|
4021
|
+
case 'allowlist:set':
|
|
4022
|
+
return remoteAllowlistWrite(options, context, runtime);
|
|
4023
|
+
case 'versions':
|
|
4024
|
+
return remoteVersions(options, context, runtime);
|
|
4025
|
+
case 'preview':
|
|
4026
|
+
return remotePreview(options, context, runtime);
|
|
4027
|
+
case 'release':
|
|
4028
|
+
case 'withdraw':
|
|
4029
|
+
case 'take-down':
|
|
4030
|
+
case 'reopen':
|
|
4031
|
+
return remoteDangerousWrite(options, context, runtime);
|
|
4032
|
+
default:
|
|
4033
|
+
throw new Error(`不支持的 remote 命令:${String(options.command)}`);
|
|
4034
|
+
}
|
|
4035
|
+
}
|
|
4036
|
+
async function runRemoteDeployCommand(options, runtime) {
|
|
4037
|
+
const logger = resolveRemoteLogger(options, runtime);
|
|
4038
|
+
const deployRuntime = {
|
|
4039
|
+
cwd: runtime.cwd,
|
|
4040
|
+
fetchImpl: runtime.fetchImpl,
|
|
4041
|
+
isTTY: runtime.isTTY,
|
|
4042
|
+
logger: options.json ? createJsonSafeLogger(runtime) : logger,
|
|
4043
|
+
requireAuthSession: runtime.requireAuthSession,
|
|
4044
|
+
stdin: runtime.stdin,
|
|
4045
|
+
stdout: runtime.stdout,
|
|
4046
|
+
};
|
|
4047
|
+
const deployOptions = {
|
|
4048
|
+
allowUnsafeApiBaseUrl: options.allowUnsafeApiBaseUrl,
|
|
4049
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
4050
|
+
autoPublish: options.autoPublish,
|
|
4051
|
+
env: options.env,
|
|
4052
|
+
loginBaseUrl: options.loginBaseUrl,
|
|
4053
|
+
releaseNote: options.releaseNote,
|
|
4054
|
+
skipBuild: options.skipBuild,
|
|
4055
|
+
buildOutputMode: options.json ? 'stderr' : 'inherit',
|
|
4056
|
+
successOutputMode: 'remote',
|
|
4057
|
+
};
|
|
4058
|
+
const result = await (runtime.runDeployCommand ?? runDeployCommand)(deployOptions, deployRuntime);
|
|
4059
|
+
const output = result ?? { changed: true };
|
|
4060
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4061
|
+
}
|
|
4062
|
+
async function createRemoteCommandContext(options, runtime) {
|
|
4063
|
+
const logger = resolveRemoteLogger(options, runtime);
|
|
4064
|
+
const environment = await resolveRemoteEnvironment({
|
|
4065
|
+
allowUnsafeApiBaseUrl: options.allowUnsafeApiBaseUrl,
|
|
4066
|
+
apiBaseUrl: options.apiBaseUrl,
|
|
4067
|
+
env: options.env,
|
|
4068
|
+
fetchImpl: runtime.fetchImpl,
|
|
4069
|
+
loginBaseUrl: options.loginBaseUrl,
|
|
4070
|
+
}, {
|
|
4071
|
+
fetchImpl: runtime.fetchImpl,
|
|
4072
|
+
requireAuthSession: runtime.requireAuthSession,
|
|
4073
|
+
});
|
|
4074
|
+
const packageJson = await readMiniProgramProjectPackage(runtime.cwd ?? process.cwd());
|
|
4075
|
+
const binding = readBoundMiniProgramIdFromPackageJson(packageJson.packageJson);
|
|
4076
|
+
const api = {
|
|
4077
|
+
...adaptRemoteApiClient(createRemoteApiClientForEnvironment(environment)),
|
|
4078
|
+
...runtime.api,
|
|
4079
|
+
};
|
|
4080
|
+
logger.debug(`Heybox API: ${environment.apiBaseUrl}`);
|
|
4081
|
+
return {
|
|
4082
|
+
api,
|
|
4083
|
+
apiBaseUrl: environment.apiBaseUrl,
|
|
4084
|
+
binding,
|
|
4085
|
+
logger,
|
|
4086
|
+
loginBaseUrl: environment.loginBaseUrl,
|
|
4087
|
+
packageJson,
|
|
4088
|
+
session: environment.session,
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4091
|
+
function adaptRemoteApiClient(api) {
|
|
4092
|
+
return {
|
|
4093
|
+
accessStatus: () => api.getDeveloperAccessStatus(),
|
|
4094
|
+
listMiniPrograms: ({ keyword, status }) => api.listUserMiniprograms({ keyword, status, offset: 0, limit: 200 }),
|
|
4095
|
+
createMiniProgram: ({ name, previewImageUrl }) => api.createUserMiniprogram({ name, ...(previewImageUrl ? { preview_image_url: previewImageUrl } : {}) }),
|
|
4096
|
+
updateMiniProgram: ({ miniProgramId, name, previewImageUrl }) => api.updateUserMiniprogram({ mini_program_id: miniProgramId, name, preview_image_url: previewImageUrl }),
|
|
4097
|
+
getMiniProgramDetail: (miniProgramId) => api.getUserMiniprogramDetail({ mini_program_id: miniProgramId }),
|
|
4098
|
+
getAllowlist: (miniProgramId) => api.getPreviewAllowlist({ mini_program_id: miniProgramId }),
|
|
4099
|
+
updateAllowlist: ({ miniProgramId, heyboxIds }) => api.updatePreviewAllowlist({ mini_program_id: miniProgramId, heybox_ids: heyboxIds }),
|
|
4100
|
+
listVersions: (miniProgramId) => api.listUserMiniprogramVersions({ mini_program_id: miniProgramId, offset: 0, limit: 50 }),
|
|
4101
|
+
getPreviewInfo: ({ miniProgramId, version }) => api.getVersionPreviewInfo({ mini_program_id: miniProgramId, preview_version: version }),
|
|
4102
|
+
releaseVersion: ({ miniProgramId, version }) => api.releaseUserMiniprogramVersion({ mini_program_id: miniProgramId, version }),
|
|
4103
|
+
withdrawVersion: ({ miniProgramId, reason, version }) => api.withdrawUserMiniprogramVersion({ mini_program_id: miniProgramId, version, reason }),
|
|
4104
|
+
takeDown: (miniProgramId) => api.takeDownUserMiniprogram({ mini_program_id: miniProgramId }),
|
|
4105
|
+
reopen: (miniProgramId) => api.reopenUserMiniprogram({ mini_program_id: miniProgramId }),
|
|
4106
|
+
};
|
|
4107
|
+
}
|
|
4108
|
+
async function remoteAccess(options, context, runtime) {
|
|
4109
|
+
const result = await context.api.accessStatus();
|
|
4110
|
+
const output = { changed: false, access: toCamelCaseDeep(result) };
|
|
4111
|
+
if (!options.json) {
|
|
4112
|
+
context.logger.info(`Access status: ${String(result.status ?? 'unknown')}`);
|
|
4113
|
+
if (result.developer_name) {
|
|
4114
|
+
context.logger.info(`Developer: ${String(result.developer_name)}`);
|
|
4115
|
+
}
|
|
4116
|
+
if (result.disabled_reason) {
|
|
4117
|
+
context.logger.warn(`Disabled reason: ${String(result.disabled_reason)}`);
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4121
|
+
}
|
|
4122
|
+
async function remoteList(options, context, runtime) {
|
|
4123
|
+
const result = await context.api.listMiniPrograms({ keyword: options.keyword, status: options.status });
|
|
4124
|
+
const items = Array.isArray(result.items) ? result.items : [];
|
|
4125
|
+
const outputItems = items.map((item) => ({ ...toCamelCaseDeep(item), bound: item.mini_program_id === context.binding }));
|
|
4126
|
+
const output = { changed: false, items: outputItems, total: readNumber(result.total, items.length) };
|
|
4127
|
+
if (!options.json) {
|
|
4128
|
+
if (items.length === 0) {
|
|
4129
|
+
context.logger.info('未找到远端小程序');
|
|
4130
|
+
}
|
|
4131
|
+
else {
|
|
4132
|
+
for (const item of items) {
|
|
4133
|
+
const marker = item.mini_program_id === context.binding ? '* ' : ' ';
|
|
4134
|
+
context.logger.info(`${marker}${item.mini_program_id ?? '--'} ${item.name ?? '--'} status=${item.status ?? '--'} version=${item.version || item.latest_version_status || '--'}`);
|
|
4135
|
+
}
|
|
4136
|
+
}
|
|
4137
|
+
if (!context.binding) {
|
|
4138
|
+
context.logger.info('当前项目尚未绑定远端小程序。绑定已有小程序:hb-sdk remote bind <mini-program-id>');
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4142
|
+
}
|
|
4143
|
+
async function remoteCreate(options, context, runtime) {
|
|
4144
|
+
if (context.binding && !options.forceBind) {
|
|
4145
|
+
throw new Error(`当前项目已绑定 ${context.binding};如需覆盖,请使用 --force-bind`);
|
|
4146
|
+
}
|
|
4147
|
+
const name = requireNonEmpty(options.name, 'remote create 必须传 --name <name>');
|
|
4148
|
+
const previewImageUrl = validateOptionalHttpsUrl(options.previewImageUrl, '--preview-image-url');
|
|
4149
|
+
const access = await context.api.accessStatus();
|
|
4150
|
+
if (access.status !== 'approved') {
|
|
4151
|
+
throw new Error(`当前 CLI 用户没有创建开发者用户小程序权限:${String(access.status ?? 'unknown')}`);
|
|
4152
|
+
}
|
|
4153
|
+
const result = await context.api.createMiniProgram({ name, previewImageUrl });
|
|
4154
|
+
const miniProgramId = requireMiniProgramId(result);
|
|
4155
|
+
await writeBoundMiniProgramId(context.packageJson.projectRoot, miniProgramId, { force: options.forceBind });
|
|
4156
|
+
const output = { changed: true, miniProgramId, remote: toCamelCaseDeep(result) };
|
|
4157
|
+
if (!options.json) {
|
|
4158
|
+
context.logger.success(`创建并绑定成功:${miniProgramId}`);
|
|
4159
|
+
}
|
|
4160
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4161
|
+
}
|
|
4162
|
+
async function remoteBind(options, context, runtime) {
|
|
4163
|
+
const miniProgramId = requireNonEmpty(options.miniProgramId, 'remote bind 必须传 <mini-program-id>');
|
|
4164
|
+
if (context.binding && context.binding !== miniProgramId && !options.force) {
|
|
4165
|
+
throw new Error(`当前项目已绑定 ${context.binding};如需覆盖本地绑定,请使用 --force`);
|
|
4166
|
+
}
|
|
4167
|
+
const detail = await context.api.getMiniProgramDetail(miniProgramId);
|
|
4168
|
+
const verifiedId = requireMiniProgramId(detail);
|
|
4169
|
+
const changed = context.binding !== verifiedId;
|
|
4170
|
+
if (changed) {
|
|
4171
|
+
await writeBoundMiniProgramId(context.packageJson.projectRoot, verifiedId, { force: options.force });
|
|
4172
|
+
}
|
|
4173
|
+
const output = { changed, miniProgramId: verifiedId, remote: toCamelCaseDeep(detail) };
|
|
4174
|
+
if (!options.json) {
|
|
4175
|
+
context.logger.success(changed ? `绑定成功:${verifiedId}` : `已绑定:${verifiedId}`);
|
|
4176
|
+
}
|
|
4177
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4178
|
+
}
|
|
4179
|
+
async function remoteInfo(options, context, runtime) {
|
|
4180
|
+
const miniProgramId = requireBinding(context);
|
|
4181
|
+
const detail = await context.api.getMiniProgramDetail(miniProgramId);
|
|
4182
|
+
const output = { changed: false, miniProgramId, detail: toCamelCaseDeep(detail) };
|
|
4183
|
+
if (!options.json) {
|
|
4184
|
+
printMiniProgramDetail(context.logger, detail);
|
|
4185
|
+
}
|
|
4186
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4187
|
+
}
|
|
4188
|
+
async function remoteUpdate(options, context, runtime) {
|
|
4189
|
+
const miniProgramId = requireBinding(context);
|
|
4190
|
+
const hasName = options.name !== undefined;
|
|
4191
|
+
const hasPreviewImageUrl = options.previewImageUrl !== undefined;
|
|
4192
|
+
if (!hasName && !hasPreviewImageUrl) {
|
|
4193
|
+
throw new Error('remote update 至少需要传 --name 或 --preview-image-url');
|
|
4194
|
+
}
|
|
4195
|
+
const detail = await context.api.getMiniProgramDetail(miniProgramId);
|
|
4196
|
+
const nextName = hasName ? requireNonEmpty(options.name, '--name 不能为空') : requireNonEmpty(detail.name, '远端详情缺少 name,无法补全 update 请求');
|
|
4197
|
+
const nextPreviewImageUrl = hasPreviewImageUrl
|
|
4198
|
+
? validateOptionalHttpsUrl(options.previewImageUrl, '--preview-image-url') ?? ''
|
|
4199
|
+
: String(detail.preview_image_url ?? '');
|
|
4200
|
+
const result = await context.api.updateMiniProgram({ miniProgramId, name: nextName, previewImageUrl: nextPreviewImageUrl });
|
|
4201
|
+
const output = { changed: true, miniProgramId, remote: toCamelCaseDeep(result) };
|
|
4202
|
+
if (!options.json) {
|
|
4203
|
+
context.logger.success(`更新成功:${miniProgramId}`);
|
|
4204
|
+
}
|
|
4205
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4206
|
+
}
|
|
4207
|
+
async function remoteAllowlistList(options, context, runtime) {
|
|
4208
|
+
const miniProgramId = requireBinding(context);
|
|
4209
|
+
const result = await context.api.getAllowlist(miniProgramId);
|
|
4210
|
+
const output = {
|
|
4211
|
+
changed: false,
|
|
4212
|
+
items: toCamelCaseDeep(Array.isArray(result.items) ? result.items : []),
|
|
4213
|
+
limit: readNumber(result.limit, 0),
|
|
4214
|
+
miniProgramId,
|
|
4215
|
+
};
|
|
4216
|
+
if (!options.json) {
|
|
4217
|
+
printAllowlist(context.logger, result);
|
|
4218
|
+
}
|
|
4219
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4220
|
+
}
|
|
4221
|
+
async function remoteAllowlistWrite(options, context, runtime) {
|
|
4222
|
+
const miniProgramId = requireBinding(context);
|
|
4223
|
+
const inputIds = parseHeyboxIds(options.heyboxIds ?? []);
|
|
4224
|
+
const current = await context.api.getAllowlist(miniProgramId);
|
|
4225
|
+
const nextIds = mergeAllowlistIds(options.command, current, inputIds);
|
|
4226
|
+
assertAllowlistLimit(nextIds, current.limit);
|
|
4227
|
+
const result = await context.api.updateAllowlist({ miniProgramId, heyboxIds: nextIds });
|
|
4228
|
+
const output = {
|
|
4229
|
+
changed: true,
|
|
4230
|
+
items: toCamelCaseDeep(Array.isArray(result.items) ? result.items : []),
|
|
4231
|
+
limit: readNumber(result.limit, readNumber(current.limit, 0)),
|
|
4232
|
+
miniProgramId,
|
|
4233
|
+
};
|
|
4234
|
+
if (!options.json) {
|
|
4235
|
+
context.logger.success(`白名单已更新:${nextIds.join(',') || '(empty)'}`);
|
|
4236
|
+
}
|
|
4237
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4238
|
+
}
|
|
4239
|
+
async function remoteVersions(options, context, runtime) {
|
|
4240
|
+
const miniProgramId = requireBinding(context);
|
|
4241
|
+
const result = await context.api.listVersions(miniProgramId);
|
|
4242
|
+
const items = Array.isArray(result.items) ? result.items : [];
|
|
4243
|
+
const output = { changed: false, items: toCamelCaseDeep(items), miniProgramId, total: readNumber(result.total, items.length) };
|
|
4244
|
+
if (!options.json) {
|
|
4245
|
+
for (const item of items) {
|
|
4246
|
+
context.logger.info(`${item.version ?? '--'} status=${item.status ?? '--'} preview=${item.preview_url ?? '--'} publish=${item.publish_url ?? '--'}`);
|
|
4247
|
+
}
|
|
4248
|
+
if (items.length === 0) {
|
|
4249
|
+
context.logger.info('暂无远端版本');
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4253
|
+
}
|
|
4254
|
+
async function remotePreview(options, context, runtime) {
|
|
4255
|
+
const miniProgramId = requireBinding(context);
|
|
4256
|
+
const version = requireNonEmpty(options.version, 'remote preview 必须传 <version>');
|
|
4257
|
+
const result = await context.api.getPreviewInfo({ miniProgramId, version });
|
|
4258
|
+
const previewUrl = String(result.preview_url || result.publish_url || result.page_url || '');
|
|
4259
|
+
const output = { changed: false, miniProgramId, previewUrl, version, preview: toCamelCaseDeep(result) };
|
|
4260
|
+
if (!options.json) {
|
|
4261
|
+
context.logger.info(previewUrl ? `Preview URL: ${previewUrl}` : `版本 ${version} 暂无 preview URL`);
|
|
4262
|
+
}
|
|
4263
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4264
|
+
}
|
|
4265
|
+
async function remoteDangerousWrite(options, context, runtime) {
|
|
4266
|
+
const miniProgramId = requireBinding(context);
|
|
4267
|
+
const version = options.command === 'release' || options.command === 'withdraw' ? requireNonEmpty(options.version, `remote ${options.command} 必须传 <version>`) : undefined;
|
|
4268
|
+
const detail = await context.api.getMiniProgramDetail(miniProgramId);
|
|
4269
|
+
await confirmDangerousRemoteChange(options, runtime, context.logger, {
|
|
4270
|
+
miniProgramId,
|
|
4271
|
+
name: detail.name,
|
|
4272
|
+
operation: options.command,
|
|
4273
|
+
status: detail.status,
|
|
4274
|
+
version,
|
|
4275
|
+
});
|
|
4276
|
+
if (options.command === 'release') {
|
|
4277
|
+
const result = await context.api.releaseVersion({ miniProgramId, version: version });
|
|
4278
|
+
return finishDangerousWrite(options, runtime, context.logger, miniProgramId, result, { status: result.status, version });
|
|
4279
|
+
}
|
|
4280
|
+
if (options.command === 'withdraw') {
|
|
4281
|
+
const result = await context.api.withdrawVersion({ miniProgramId, reason: options.reason, version: version });
|
|
4282
|
+
return finishDangerousWrite(options, runtime, context.logger, miniProgramId, result, { status: result.status, version });
|
|
4283
|
+
}
|
|
4284
|
+
if (options.command === 'take-down') {
|
|
4285
|
+
const result = await context.api.takeDown(miniProgramId);
|
|
4286
|
+
return finishDangerousWrite(options, runtime, context.logger, miniProgramId, result, { status: result.status });
|
|
4287
|
+
}
|
|
4288
|
+
const result = await context.api.reopen(miniProgramId);
|
|
4289
|
+
return finishDangerousWrite(options, runtime, context.logger, miniProgramId, result, { status: result.status });
|
|
4290
|
+
}
|
|
4291
|
+
function finishDangerousWrite(options, runtime, logger, miniProgramId, result, extras) {
|
|
4292
|
+
const output = { changed: true, miniProgramId, ...extras, remote: toCamelCaseDeep(result) };
|
|
4293
|
+
if (!options.json) {
|
|
4294
|
+
logger.success(`操作成功:${options.command} ${miniProgramId}`);
|
|
4295
|
+
}
|
|
4296
|
+
return finishRemoteCommand(options, runtime, output);
|
|
4297
|
+
}
|
|
4298
|
+
function finishRemoteCommand(options, runtime, output) {
|
|
4299
|
+
const normalized = toCamelCaseDeep(output);
|
|
4300
|
+
if (options.json) {
|
|
4301
|
+
writeStdout(runtime, `${JSON.stringify(normalized)}\n`);
|
|
4302
|
+
}
|
|
4303
|
+
return normalized;
|
|
4304
|
+
}
|
|
4305
|
+
function resolveRemoteLogger(options, runtime) {
|
|
4306
|
+
if (options.json) {
|
|
4307
|
+
return createJsonSafeLogger(runtime);
|
|
4308
|
+
}
|
|
4309
|
+
if (runtime.logger) {
|
|
4310
|
+
return runtime.logger;
|
|
4311
|
+
}
|
|
4312
|
+
return index.createCliLogger({
|
|
4313
|
+
isTTY: runtime.isTTY,
|
|
4314
|
+
stderr: runtime.stderr,
|
|
4315
|
+
stdout: runtime.stdout,
|
|
4316
|
+
});
|
|
4317
|
+
}
|
|
4318
|
+
function createJsonSafeLogger(runtime) {
|
|
4319
|
+
const stderr = runtime.stderr ?? process.stderr;
|
|
4320
|
+
return index.createCliLogger({
|
|
4321
|
+
isTTY: runtime.isTTY,
|
|
4322
|
+
stderr,
|
|
4323
|
+
stdout: stderr,
|
|
4324
|
+
});
|
|
4325
|
+
}
|
|
4326
|
+
function writeStdout(runtime, message) {
|
|
4327
|
+
(runtime.stdout ?? process.stdout).write(message);
|
|
4328
|
+
}
|
|
4329
|
+
function requireBinding(context) {
|
|
4330
|
+
if (!context.binding) {
|
|
4331
|
+
throw new Error('当前项目尚未绑定远端小程序,请先运行 hb-sdk remote create 或 hb-sdk remote bind <mini-program-id>');
|
|
4332
|
+
}
|
|
4333
|
+
return context.binding;
|
|
4334
|
+
}
|
|
4335
|
+
function requireMiniProgramId(result) {
|
|
4336
|
+
const miniProgramId = result.mini_program_id;
|
|
4337
|
+
if (typeof miniProgramId !== 'string' || !miniProgramId.trim()) {
|
|
4338
|
+
throw new Error('远端响应缺少 mini_program_id');
|
|
4339
|
+
}
|
|
4340
|
+
return miniProgramId.trim();
|
|
4341
|
+
}
|
|
4342
|
+
function requireNonEmpty(value, message) {
|
|
4343
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
4344
|
+
if (!normalized) {
|
|
4345
|
+
throw new Error(message);
|
|
4346
|
+
}
|
|
4347
|
+
return normalized;
|
|
4348
|
+
}
|
|
4349
|
+
function validateOptionalHttpsUrl(value, label) {
|
|
4350
|
+
if (value === undefined) {
|
|
4351
|
+
return undefined;
|
|
4352
|
+
}
|
|
4353
|
+
const raw = requireNonEmpty(value, `${label} 不能为空`);
|
|
4354
|
+
let url;
|
|
4355
|
+
try {
|
|
4356
|
+
url = new URL(raw);
|
|
4357
|
+
}
|
|
4358
|
+
catch {
|
|
4359
|
+
throw new Error(`${label} 必须是合法 HTTPS URL`);
|
|
4360
|
+
}
|
|
4361
|
+
if (url.protocol !== 'https:') {
|
|
4362
|
+
throw new Error(`${label} 只接受 HTTPS URL`);
|
|
4363
|
+
}
|
|
4364
|
+
return raw;
|
|
4365
|
+
}
|
|
4366
|
+
function parseHeyboxIds(values) {
|
|
4367
|
+
if (values.length === 0) {
|
|
4368
|
+
throw new Error('请传入至少一个十进制 heybox_id');
|
|
4369
|
+
}
|
|
4370
|
+
const ids = [];
|
|
4371
|
+
for (const value of values) {
|
|
4372
|
+
const raw = String(value).trim();
|
|
4373
|
+
if (!/^(0|[1-9]\d*)$/.test(raw)) {
|
|
4374
|
+
throw new Error(`heybox_id 只接受十进制数字:${value}`);
|
|
4375
|
+
}
|
|
4376
|
+
const id = Number(raw);
|
|
4377
|
+
if (!Number.isSafeInteger(id) || id <= 0) {
|
|
4378
|
+
throw new Error(`heybox_id 超出有效范围:${value}`);
|
|
4379
|
+
}
|
|
4380
|
+
if (!ids.includes(id)) {
|
|
4381
|
+
ids.push(id);
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
return ids;
|
|
4385
|
+
}
|
|
4386
|
+
function mergeAllowlistIds(command, current, inputIds) {
|
|
4387
|
+
const items = Array.isArray(current.items) ? current.items : [];
|
|
4388
|
+
const ownerIds = items.filter((item) => item.is_owner === true && isValidHeyboxIdNumber(item.heybox_id)).map((item) => item.heybox_id);
|
|
4389
|
+
const currentIds = items.filter((item) => isValidHeyboxIdNumber(item.heybox_id)).map((item) => item.heybox_id);
|
|
4390
|
+
if (command === 'allowlist:add') {
|
|
4391
|
+
return uniqueNumbers([...currentIds, ...inputIds]);
|
|
4392
|
+
}
|
|
4393
|
+
if (command === 'allowlist:remove') {
|
|
4394
|
+
return uniqueNumbers(currentIds.filter((id) => ownerIds.includes(id) || !inputIds.includes(id)));
|
|
4395
|
+
}
|
|
4396
|
+
return uniqueNumbers([...ownerIds, ...inputIds.filter((id) => !ownerIds.includes(id))]);
|
|
4397
|
+
}
|
|
4398
|
+
function assertAllowlistLimit(ids, limit) {
|
|
4399
|
+
const parsedLimit = typeof limit === 'number' && Number.isFinite(limit) ? limit : undefined;
|
|
4400
|
+
if (parsedLimit !== undefined && ids.length > parsedLimit) {
|
|
4401
|
+
throw new Error(`内测白名单最多 ${parsedLimit} 人,当前操作会变为 ${ids.length} 人`);
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
function uniqueNumbers(values) {
|
|
4405
|
+
const result = [];
|
|
4406
|
+
for (const value of values) {
|
|
4407
|
+
if (!result.includes(value)) {
|
|
4408
|
+
result.push(value);
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
return result;
|
|
4412
|
+
}
|
|
4413
|
+
function isValidHeyboxIdNumber(value) {
|
|
4414
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value > 0;
|
|
4415
|
+
}
|
|
4416
|
+
async function confirmDangerousRemoteChange(options, runtime, logger, context) {
|
|
4417
|
+
const lines = [
|
|
4418
|
+
`操作:${context.operation}`,
|
|
4419
|
+
`Mini-program: ${context.miniProgramId}`,
|
|
4420
|
+
`名称:${context.name || '--'}`,
|
|
4421
|
+
`当前状态:${context.status || '--'}`,
|
|
4422
|
+
...(context.version ? [`目标版本:${context.version}`] : []),
|
|
4423
|
+
];
|
|
4424
|
+
if (!options.json) {
|
|
4425
|
+
for (const line of lines) {
|
|
4426
|
+
logger.info(line);
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4429
|
+
else if (!options.yes) {
|
|
4430
|
+
for (const line of lines) {
|
|
4431
|
+
logger.info(line, { stream: 'stderr' });
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
if (options.yes) {
|
|
4435
|
+
return;
|
|
4436
|
+
}
|
|
4437
|
+
const isTTY = runtime.isTTY ?? Boolean(process.stdin.isTTY && process.stderr.isTTY);
|
|
4438
|
+
if (!isTTY) {
|
|
4439
|
+
throw new Error(`非交互环境执行 hb-sdk remote ${context.operation} 必须传 --yes`);
|
|
4440
|
+
}
|
|
4441
|
+
const accepted = runtime.promptConfirm
|
|
4442
|
+
? await runtime.promptConfirm(`确认执行 ${context.operation}?`)
|
|
4443
|
+
: await promptConfirm(`确认执行 ${context.operation}?输入 yes 继续: `, runtime);
|
|
4444
|
+
if (!accepted) {
|
|
4445
|
+
throw new Error('已取消操作');
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
async function promptConfirm(message, runtime) {
|
|
4449
|
+
const input = runtime.stdin ?? process.stdin;
|
|
4450
|
+
const output = runtime.stderr ?? process.stderr;
|
|
4451
|
+
const rl = promises.createInterface({ input, output: output });
|
|
4452
|
+
try {
|
|
4453
|
+
const answer = await rl.question(message);
|
|
4454
|
+
return answer.trim().toLowerCase() === 'yes';
|
|
4455
|
+
}
|
|
4456
|
+
finally {
|
|
4457
|
+
rl.close();
|
|
4458
|
+
}
|
|
4459
|
+
}
|
|
4460
|
+
function printMiniProgramDetail(logger, detail) {
|
|
4461
|
+
logger.info(`Mini-program: ${detail.mini_program_id ?? '--'}`);
|
|
4462
|
+
logger.info(`Name: ${detail.name ?? '--'}`);
|
|
4463
|
+
logger.info(`Status: ${detail.status ?? '--'}`);
|
|
4464
|
+
logger.info(`Version: ${detail.version || detail.latest_version_status || '--'}`);
|
|
4465
|
+
if (detail.publish_url) {
|
|
4466
|
+
logger.info(`Publish URL: ${detail.publish_url}`);
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4469
|
+
function printAllowlist(logger, result) {
|
|
4470
|
+
const items = Array.isArray(result.items) ? result.items : [];
|
|
4471
|
+
logger.info(`Limit: ${readNumber(result.limit, 0)}`);
|
|
4472
|
+
if (items.length === 0) {
|
|
4473
|
+
logger.info('内测白名单为空');
|
|
4474
|
+
return;
|
|
4475
|
+
}
|
|
4476
|
+
for (const item of items) {
|
|
4477
|
+
logger.info(`${item.heybox_id ?? '--'}${item.is_owner ? ' (owner)' : ''}${item.nickname ? ` ${item.nickname}` : ''}`);
|
|
4478
|
+
}
|
|
4479
|
+
}
|
|
4480
|
+
function readNumber(value, fallback) {
|
|
4481
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
4482
|
+
}
|
|
4483
|
+
function toCamelCaseDeep(value) {
|
|
4484
|
+
if (Array.isArray(value)) {
|
|
4485
|
+
return value.map((item) => toCamelCaseDeep(item));
|
|
4486
|
+
}
|
|
4487
|
+
if (!value || Object.prototype.toString.call(value) !== '[object Object]') {
|
|
4488
|
+
return value;
|
|
4489
|
+
}
|
|
4490
|
+
const result = {};
|
|
4491
|
+
for (const [key, item] of Object.entries(value)) {
|
|
4492
|
+
result[toCamelKey(key)] = toCamelCaseDeep(item);
|
|
4493
|
+
}
|
|
4494
|
+
return result;
|
|
4495
|
+
}
|
|
4496
|
+
function toCamelKey(key) {
|
|
4497
|
+
return key.replace(/_([a-z0-9])/g, (_, char) => char.toUpperCase());
|
|
4498
|
+
}
|
|
4499
|
+
|
|
4500
|
+
var remote = /*#__PURE__*/Object.freeze({
|
|
3723
4501
|
__proto__: null,
|
|
3724
|
-
|
|
3725
|
-
runDeployCommand: runDeployCommand,
|
|
3726
|
-
validateDeployReleaseNote: validateDeployReleaseNote
|
|
4502
|
+
runRemoteCommand: runRemoteCommand
|
|
3727
4503
|
});
|
|
3728
4504
|
|
|
3729
|
-
exports.
|
|
4505
|
+
exports.remote = remote;
|
|
3730
4506
|
exports.requireSemver = requireSemver;
|