@heybox/hb-sdk 0.4.3 → 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.
Files changed (37) hide show
  1. package/README.md +106 -18
  2. package/dist/cli-chunks/{create-BV4h2BTs.cjs → create-DpyZCNdo.cjs} +1 -1
  3. package/dist/cli-chunks/{dev-DgX88vaK.cjs → dev-DWIpgJnn.cjs} +1 -1
  4. package/dist/cli-chunks/{doctor-BIZoQ6go.cjs → doctor-DBotVUQI.cjs} +1 -1
  5. package/dist/cli-chunks/{index-ovy_xoLn.cjs → index-BYMTp2I6.cjs} +171 -43
  6. package/dist/cli-chunks/{index-DQAFCtK1.cjs → index-DRsyeAcg.cjs} +3 -3
  7. package/dist/cli-chunks/{login-CoZhlwxt.cjs → login-DIgcT1gv.cjs} +2 -2
  8. package/dist/cli-chunks/{deploy-Bz0-WpHy.cjs → remote-DjaOc1VS.cjs} +797 -21
  9. package/dist/cli-chunks/{session-BQs0wf65.cjs → session-BAgaqpNL.cjs} +1 -1
  10. package/dist/cli.cjs +1 -1
  11. package/dist/devtools/mock-host/main.js +842 -428
  12. package/dist/index.cjs.js +98 -0
  13. package/dist/index.esm.js +96 -1
  14. package/dist/miniapp-publish.cjs.js +26 -0
  15. package/dist/miniapp-publish.esm.js +14 -1
  16. package/dist/protocol.cjs.js +70 -0
  17. package/dist/protocol.esm.js +64 -1
  18. package/dist/templates/vue3-vite-ts/README.md.ejs +1 -1
  19. package/dist/templates/vue3-vite-ts/package.json.ejs +1 -1
  20. package/package.json +1 -1
  21. package/skill/SKILL.md +23 -18
  22. package/skill/references/api-protocol.md +34 -2
  23. package/skill/references/api-root.md +79 -4
  24. package/skill/references/cli.md +86 -349
  25. package/skill/references/llms-index.md +2 -2
  26. package/skill/references/safety-boundaries.md +1 -1
  27. package/skill/scripts/sync-references.mjs +48 -4
  28. package/skill/skill.json +4 -4
  29. package/types/core/sdk.d.ts +9 -0
  30. package/types/core/singleton.d.ts +9 -0
  31. package/types/index.d.ts +7 -1
  32. package/types/miniapp-publish/index.d.ts +13 -0
  33. package/types/modules/device/index.d.ts +34 -0
  34. package/types/modules/navigation/index.d.ts +24 -0
  35. package/types/modules/ui/index.d.ts +42 -0
  36. package/types/protocol/capabilities.d.ts +81 -2
  37. package/types/protocol.d.ts +5 -2
@@ -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 promises = require('node:readline/promises');
8
- var session = require('./session-BQs0wf65.cjs');
9
- var index = require('./index-ovy_xoLn.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-DQAFCtK1.cjs'); }).then(function (n) { return n.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
- logger.success(`提交审核成功:${miniProgramId} ${version}`);
3511
- logger.info(`发布策略:${autoPublish ? '审核通过后自动发布' : '审核通过后需在开放平台手动发布'}`);
3512
- if (submitAuditResult.preview_url) {
3513
- logger.info(`Preview URL: ${submitAuditResult.preview_url}`);
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
- var deploy = /*#__PURE__*/Object.freeze({
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
- resolveDeployReleaseNote: resolveDeployReleaseNote,
3725
- runDeployCommand: runDeployCommand,
3726
- validateDeployReleaseNote: validateDeployReleaseNote
4502
+ runRemoteCommand: runRemoteCommand
3727
4503
  });
3728
4504
 
3729
- exports.deploy = deploy;
4505
+ exports.remote = remote;
3730
4506
  exports.requireSemver = requireSemver;