@heybox/hb-sdk 0.6.6-alpha.2 → 0.6.6-alpha.4

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 +44 -7
  2. package/dist/cli-chunks/build-C54stoRf.cjs +142 -0
  3. package/dist/cli-chunks/context-DvTynj3F.cjs +410 -0
  4. package/dist/cli-chunks/{create-CxjB3oSo.cjs → create-uQS30kS_.cjs} +1 -1
  5. package/dist/cli-chunks/{dev-Km0or0yY.cjs → dev-1wE8dNiL.cjs} +29 -149
  6. package/dist/cli-chunks/{doctor-baVOqNSh.cjs → doctor-B2aCUOQ7.cjs} +1 -1
  7. package/dist/cli-chunks/{index-ByDy5HXi.cjs → index-19i3Dr5H.cjs} +32 -16
  8. package/dist/cli-chunks/{index-DCsEAuca.cjs → index-DypVMqsr.cjs} +3 -3
  9. package/dist/cli-chunks/{login-fNe0eDs_.cjs → login-BIIUGwoq.cjs} +2 -2
  10. package/dist/cli-chunks/project-vite-Dl3OoQjL.cjs +45 -0
  11. package/dist/cli-chunks/remote-47MjCKhu.cjs +1522 -0
  12. package/dist/cli-chunks/{remote-BRIlRrCG.cjs → runtime-gate--rPXjiG6.cjs} +7 -1501
  13. package/dist/cli-chunks/{context-CM46YbPT.cjs → runtime-permission-env-BSs4uCNa.cjs} +75 -293
  14. package/dist/cli-chunks/{session-CTcelATz.cjs → session-DJEuhrgq.cjs} +1 -1
  15. package/dist/cli.cjs +1 -1
  16. package/dist/devtools/mock-host/main.js +149 -3
  17. package/dist/index.cjs.js +1 -1
  18. package/dist/index.esm.js +1 -1
  19. package/dist/templates/vue3-vite-ts/README.md.ejs +2 -2
  20. package/dist/templates/vue3-vite-ts/package.json.ejs +1 -1
  21. package/dist/vite.cjs.js +68 -4
  22. package/dist/vite.esm.js +68 -4
  23. package/package.json +2 -2
  24. package/skill/SKILL.md +19 -14
  25. package/skill/references/api-protocol.md +3 -2
  26. package/skill/references/api-root.md +57 -11
  27. package/skill/references/cli.md +33 -1
  28. package/skill/references/recipes.md +53 -0
  29. package/skill/references/safety-boundaries.md +1 -1
  30. package/skill/scripts/sync-references.mjs +23 -1
  31. package/skill/skill.json +4 -4
  32. package/types/index.d.ts +1 -1
  33. package/types/modules/share/types.d.ts +11 -0
  34. package/types/protocol.d.ts +1 -1
  35. package/types/vite/html-policy.d.ts +5 -1
  36. package/types/vite/index.d.ts +10 -1
  37. package/types/vite/runtime-permission-env.d.ts +9 -0
package/README.md CHANGED
@@ -132,6 +132,10 @@ await share.showShareMenu({
132
132
  title: '我的小程序页面',
133
133
  desc: '来自黑盒小程序的分享',
134
134
  imageUrl: 'https://imgheybox.max-c.com/demo.png',
135
+ post: {
136
+ topicIds: [235709],
137
+ topics: ['无畏契约战绩'],
138
+ },
135
139
  });
136
140
  ```
137
141
 
@@ -139,15 +143,23 @@ await share.showShareMenu({
139
143
  `/tools/common_share?user_miniprogram_id=...` 分享落地页。只有确实要分享外部
140
144
  HTTP(S) 页面时才显式传 `url`。
141
145
 
146
+ `post` 用于给“转发到社区”预置可编辑的分区与话题。`topicIds` 接受正整数或非空字符串并按首次出现顺序去重;`topics` 只传话题内容,不要包含首尾 `#`。`showShareMenu()` 只支持一个默认分区,并且不能与 `channel` 同时使用;本地 Mock、App Dev Shell 和开发 Runtime 会直接拒绝这类错误,生产 Runtime 会过滤非法项、只取第一个分区并继续普通分享。`post: null` 等同于不配置。
147
+
142
148
  截图分享:
143
149
 
144
150
  ```ts
145
151
  await share.screenshot({
146
152
  delay: 100,
147
153
  saveToAlbum: true,
154
+ post: {
155
+ topicIds: [235709, 66739],
156
+ topics: ['无畏契约战绩'],
157
+ },
148
158
  });
149
159
  ```
150
160
 
161
+ 截图分享支持多个预置分区;分区与话题仍由用户在客户端发帖页中确认和修改,SDK 不会直接发布内容。
162
+
151
163
  ### 基础 UI
152
164
 
153
165
  ```ts
@@ -385,6 +397,7 @@ try {
385
397
  | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
386
398
  | `hb-sdk create <project-name>` | 创建外部小程序模板。 |
387
399
  | `hb-sdk dev [--runtime-url <url>]` | 启动 Vite 和浏览器 mock 宿主;远端权限可用时使用真实快照,否则以缺失快照启动并默认拒绝受管能力。 |
400
+ | `hb-sdk build [--env <name>]` | 直接使用项目 Vite 构建固定的 `dist/` 生产产物;不执行类型检查,也不要求登录或绑定小程序。 |
388
401
  | `hb-sdk login [--login-base-url <url>] [--no-select-entity]` | 登录 Heybox,并把 CLI 自己需要的登录态和登录入口环境保存在本地缓存中;默认会引导多主体用户选择服务端 current entity。 |
389
402
  | `hb-sdk login status` | 查看脱敏后的 CLI 登录态。 |
390
403
  | `hb-sdk login clear` | 清理 CLI 登录态。 |
@@ -414,6 +427,28 @@ try {
414
427
 
415
428
  所有命令都支持 `--verbose` / `-v`。默认输出只展示关键阶段状态、可访问 URL、下一步命令和可直接处理的错误提示;需要排查后端 envelope、HTTP 状态、trace id、原始响应体、cache 路径、API origin、逐文件上传进度或提交审核原始失败原因时,再追加 `--verbose` 查看详细调试信息。交互式终端会用颜色、符号和 loading 动画区分成功、警告、错误与耗时步骤;CI、非 TTY 和管道输出会退化为 `[hb-sdk] LEVEL ...` 这种稳定文本行。
416
429
 
430
+ ## hb-sdk build
431
+
432
+ 生产构建推荐使用:
433
+
434
+ ```bash
435
+ hb-sdk build [--env <name>] [--verbose]
436
+ ```
437
+
438
+ `hb-sdk build` 直接调用当前项目安装的 Vite,固定清理并重新生成 `dist/`,然后校验 `index.html`、`manifest.json` 和可上传产物。命令只负责生产构建,不执行 `scripts.build` 或 TypeScript 类型检查,也不需要 CLI 登录、项目绑定或远端网络。`--env <name>` 用于选择同名构建环境;除 `--env` 和 `--verbose` 外不提供其他构建参数。
439
+
440
+ 项目必须在 `vite.config.ts` 中显式注册 `miniappManifest()`。推荐让项目脚本保留类型检查:
441
+
442
+ ```json
443
+ {
444
+ "scripts": {
445
+ "build": "vue-tsc --noEmit && hb-sdk build"
446
+ }
447
+ }
448
+ ```
449
+
450
+ 现有项目继续使用 `vite build` 仍然兼容,不会被自动迁移;新模板和新文档以 `hb-sdk build` 作为生产构建入口。`hb-sdk remote deploy` 仍执行项目自己的 `scripts.build`,因此会保留项目定义的类型检查和其他发布前步骤。
451
+
417
452
  ## hb-sdk remote deploy
418
453
 
419
454
  `hb-sdk remote deploy` 把版本预检、build、CDN 上传、提交审核 API 串成单条命令。顶层 `hb-sdk deploy` 已删除;旧脚本必须改成 `hb-sdk remote deploy`。命令前置要求:
@@ -538,7 +573,7 @@ CLI 登录态只供 CLI 命令访问黑盒接口时复用,不会注入 iframe
538
573
 
539
574
  ## Manifest
540
575
 
541
- `@heybox/hb-sdk/vite` 提供构建时插件 `miniappManifest()`。Vite 项目完成 `vite build` 后,会在输出目录写入 `manifest.json`:
576
+ `@heybox/hb-sdk/vite` 提供构建时插件 `miniappManifest()`。项目通过 `hb-sdk build` 完成生产构建后,会在固定的 `dist/` 中写入 `manifest.json`:
542
577
 
543
578
  ```json
544
579
  {
@@ -547,7 +582,7 @@ CLI 登录态只供 CLI 命令访问黑盒接口时复用,不会注入 iframe
547
582
  }
548
583
  ```
549
584
 
550
- `version` 来自小程序项目自身的 `package.json.version`,`sdkVersion` 来自当前安装 SDK 的构建版本且不能由业务覆盖。`hb-sdk create` 生成的模板默认已注册插件;现有 Vite 项目可以在 `vite.config.ts` 中手动接入:
585
+ `version` 来自小程序项目自身的 `package.json.version`,`sdkVersion` 来自当前安装 SDK 的构建版本且不能由业务覆盖。`hb-sdk build` 要求项目显式注册这个插件;`hb-sdk create` 生成的模板默认已注册,现有 Vite 项目可以在 `vite.config.ts` 中手动接入:
551
586
 
552
587
  ```ts
553
588
  import { miniappManifest } from '@heybox/hb-sdk/vite';
@@ -563,15 +598,17 @@ export default defineConfig({
563
598
 
564
599
  工坊小程序构建产物只能在兼容的小黑盒 Runtime 中启动。普通浏览器直接打开时不会执行标准业务脚本,并会提示在小黑盒 APP 内打开。项目应使用标准 Vite module 入口。
565
600
 
566
- 插件只接受单页应用:输出目录只能存在入口 `index.html`。builddev 都不会注入平台 CSP;项目已有的 CSP 会原样保留。浏览器原生 `fetch`、XHR、WebSocket、EventSource、Beacon、Worker、iframe 和表单等能力不再由 SDK 构建产物统一限制,是否可用由宿主环境、项目自身策略和审核规则共同决定;需要宿主授权的业务网络请求仍应使用 `network.request()`。
601
+ 插件只接受单页应用:输出目录只能存在入口 `index.html`。`hb-sdk dev` `hb-sdk remote deploy` 会读取绑定小程序的远端 Runtime 权限;仅当 `network.request` 已启用且 `useOfficialDomain=true` 时跳过平台 CSP,否则 build 会把平台 CSP 插入 `<head>` 首位。直接运行 `vite build`、匿名 dev、非法快照或远端权限读取失败时均继续注入。已有 CSP 始终原样保留;注入平台 CSP 时,两份策略按浏览器交集生效。
602
+
603
+ 平台 CSP 会禁止 `fetch`、XHR、WebSocket、EventSource、Beacon、Worker、iframe、表单和对象加载等浏览器原生出口;dev 只额外放行当前 Vite 的精确 HMR WebSocket 地址。跳过平台 CSP 时,这些能力不再由 SDK 构建产物统一限制,但需要宿主授权的业务网络请求仍应使用 `network.request()`。本地 Mock 权限覆盖不会改变构建 CSP,构建判定始终以远端权限快照为准。
567
604
 
568
- meta refresh、外部 anchor、`dns-prefetch`、`preconnect`、`prerender`、外部资源 URL 和额外 HTML 仍会使 build 失败。`dev` 和手动 Vite build 不再请求远端最低 SDK 版本;构建仍会把当前 `sdkVersion` 写入 Manifest,`hb-sdk remote deploy` 仍校验 Manifest 结构并经过服务端 precheck / submit-audit 策略。
605
+ meta refresh、外部 anchor、`dns-prefetch`、`preconnect`、`prerender`、外部资源 URL 和额外 HTML 会使 build 失败。内联 script/style 允许,但 `unsafe-eval` 不允许。`dev`、`hb-sdk build` 和手动 Vite build 都不请求远端最低 SDK 版本;构建仍会把当前 `sdkVersion` 写入 Manifest,`hb-sdk remote deploy` 仍校验 Manifest 结构并经过服务端 precheck / submit-audit 策略。
569
606
 
570
607
  失败与警告语义:
571
608
 
572
- - 读取 `package.json` 失败或 JSON 解析失败:`vite build` 直接失败,并输出具体原因。
573
- - `package.json.version` 不是非空字符串:`vite build` 直接失败。
574
- - `package.json.version` 仍是模板默认值 `0.0.0`:`vite build` 直接失败,必须改成实际 SemVer。
609
+ - 读取 `package.json` 失败或 JSON 解析失败:build 直接失败,并输出具体原因。
610
+ - `package.json.version` 不是非空字符串:build 直接失败。
611
+ - `package.json.version` 仍是模板默认值 `0.0.0`:build 直接失败,必须改成实际 SemVer。
575
612
  - 版本号不是严格 SemVer、包含 build metadata 或缺少 `sdkVersion`:build/deploy 直接失败。
576
613
 
577
614
  `manifest.json` 不部署到 CDN,只交给发布流水线读取后上送后台;Host 通过后台 API 间接读取版本信息。第一阶段只支持 Vite 项目,非 Vite 打包器未来通过其他子入口扩展。
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ var fs$1 = require('node:fs');
4
+ var fs = require('node:fs/promises');
5
+ var path = require('node:path');
6
+ var runtimePermissionEnv = require('./runtime-permission-env-BSs4uCNa.cjs');
7
+ var runtimeGate = require('./runtime-gate--rPXjiG6.cjs');
8
+ var index = require('./index-19i3Dr5H.cjs');
9
+ var projectVite = require('./project-vite-Dl3OoQjL.cjs');
10
+ require('node:async_hooks');
11
+ require('node:module');
12
+ require('path');
13
+ require('os');
14
+ require('readline');
15
+ require('tty');
16
+ require('assert');
17
+ require('events');
18
+ require('stream');
19
+ require('buffer');
20
+ require('util');
21
+ require('node:url');
22
+
23
+ async function runBuildCommand(_options = {}, runtime = {}) {
24
+ const logger = runtime.logger ?? index.createCliLogger();
25
+ const projectRoot = projectVite.findProjectRoot(runtime.cwd ?? process.cwd());
26
+ const distDir = path.join(projectRoot, 'dist');
27
+ const env = runtime.env ?? process.env;
28
+ const mode = env.HB_SDK_ENV?.trim() || undefined;
29
+ const skipPlatformCsp = runtimePermissionEnv.shouldSkipMiniappPlatformCspFromEnv(env);
30
+ await fs.rm(distDir, { force: true, recursive: true });
31
+ try {
32
+ return await runtimePermissionEnv.withMiniappPlatformCspEnv(skipPlatformCsp, async () => {
33
+ const vite = await logger.task('正在加载项目 Vite', () => projectVite.loadProjectVite(projectRoot), {
34
+ successText: '已加载项目 Vite',
35
+ });
36
+ await logger.task('正在构建小程序', () => vite.build({
37
+ root: projectRoot,
38
+ ...(mode ? { mode } : {}),
39
+ plugins: [createFixedBuildOutputPlugin(projectRoot)],
40
+ build: {
41
+ outDir: 'dist',
42
+ emptyOutDir: true,
43
+ watch: null,
44
+ write: true,
45
+ },
46
+ }), { successText: 'Vite 构建完成' });
47
+ const result = await validateBuildOutput(projectRoot, logger);
48
+ logger.success(`构建完成: dist/ | manifest version ${result.version} | sdkVersion ${result.sdkVersion} | 待上传文件 ${result.fileCount} 个 | ${formatSize(result.totalBytes)}`);
49
+ return result;
50
+ }, env);
51
+ }
52
+ catch (error) {
53
+ await fs.rm(distDir, { force: true, recursive: true });
54
+ throw error;
55
+ }
56
+ }
57
+ function createFixedBuildOutputPlugin(projectRoot) {
58
+ const distDir = path.join(projectRoot, 'dist');
59
+ return {
60
+ name: 'heybox:fixed-miniapp-build-output',
61
+ configResolved(config) {
62
+ if (path.resolve(config.root, config.build.outDir) !== distDir || config.build.watch || config.build.write === false) {
63
+ throw new Error('hb-sdk build 必须执行一次性落盘构建,并输出到项目 dist 目录');
64
+ }
65
+ const outputs = Array.isArray(config.build.rollupOptions.output) ? config.build.rollupOptions.output : [config.build.rollupOptions.output];
66
+ for (const output of outputs) {
67
+ if (!output)
68
+ continue;
69
+ if (output.file || output.dir) {
70
+ throw new Error('hb-sdk build 不允许通过 Rollup output.dir/file 覆盖固定的 dist 输出目录');
71
+ }
72
+ }
73
+ },
74
+ };
75
+ }
76
+ async function validateBuildOutput(projectRoot, logger) {
77
+ const distDir = path.join(projectRoot, 'dist');
78
+ const entryHtmlPath = path.join(distDir, 'index.html');
79
+ const manifestPath = path.join(distDir, 'manifest.json');
80
+ if (!fs$1.existsSync(entryHtmlPath)) {
81
+ throw new Error('未找到 dist/index.html,Vite 构建产物不完整');
82
+ }
83
+ if (!fs$1.existsSync(manifestPath)) {
84
+ throw new Error('未找到 dist/manifest.json,请在 Vite 配置中显式启用 miniappManifest()');
85
+ }
86
+ const entryHtml = await fs.readFile(entryHtmlPath, 'utf8');
87
+ if (!runtimeGate.hasMiniappRuntimeGate(entryHtml)) {
88
+ throw new Error('dist/index.html 缺少平台 Runtime 启动门禁,请在 Vite 配置中显式启用 miniappManifest()');
89
+ }
90
+ const { manifest, hadBom } = runtimeGate.parseMiniappManifestJson(await fs.readFile(manifestPath, 'utf8'), 'dist/manifest.json');
91
+ if (hadBom) {
92
+ logger.warn('dist/manifest.json 包含 BOM,已自动剥离');
93
+ }
94
+ const { sdkVersion, version } = runtimeGate.validateMiniappManifestForDeploy(manifest);
95
+ const allFiles = await walkDistFiles(distDir);
96
+ const uploadFiles = allFiles.filter((file) => runtimePermissionEnv.shouldUploadDistFile(file.relativePath));
97
+ const sizeError = runtimePermissionEnv.validateUploadTotalSize(uploadFiles);
98
+ if (sizeError) {
99
+ throw new Error(sizeError.replace('重新 deploy', '重新 build'));
100
+ }
101
+ return {
102
+ distDir,
103
+ fileCount: uploadFiles.length,
104
+ sdkVersion,
105
+ totalBytes: uploadFiles.reduce((total, file) => total + file.size, 0),
106
+ version,
107
+ };
108
+ }
109
+ async function walkDistFiles(distDir) {
110
+ const results = [];
111
+ await walk(distDir, '');
112
+ return results;
113
+ async function walk(absDir, relDir) {
114
+ const entries = await fs.readdir(absDir, { withFileTypes: true });
115
+ for (const entry of entries) {
116
+ const absPath = path.join(absDir, entry.name);
117
+ const relPath = runtimePermissionEnv.normalizeRelativePath(relDir ? `${relDir}/${entry.name}` : entry.name);
118
+ const link = await fs.lstat(absPath);
119
+ if (link.isSymbolicLink()) {
120
+ throw new Error(`dist 目录包含 symlink,拒绝处理:${relPath}`);
121
+ }
122
+ if (runtimePermissionEnv.relativePathContainsNodeModulesSegment(relPath)) {
123
+ throw new Error(`dist 目录含 node_modules:${relPath}`);
124
+ }
125
+ if (entry.isDirectory()) {
126
+ await walk(absPath, relPath);
127
+ }
128
+ else if (entry.isFile()) {
129
+ results.push({ relativePath: relPath, size: (await fs.stat(absPath)).size });
130
+ }
131
+ }
132
+ }
133
+ }
134
+ function formatSize(bytes) {
135
+ if (bytes < 1024)
136
+ return `${bytes} B`;
137
+ if (bytes < 1024 * 1024)
138
+ return `${(bytes / 1024).toFixed(1)} KiB`;
139
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
140
+ }
141
+
142
+ exports.runBuildCommand = runBuildCommand;
@@ -0,0 +1,410 @@
1
+ 'use strict';
2
+
3
+ var session = require('./session-DJEuhrgq.cjs');
4
+ var runtimePermissionEnv = require('./runtime-permission-env-BSs4uCNa.cjs');
5
+ var fs$1 = require('node:fs');
6
+ var fs = require('node:fs/promises');
7
+ var path = require('node:path');
8
+
9
+ const MANAGED_RUNTIME_PERMISSION_KEYS = new Set(['network.request']);
10
+ /**
11
+ * 判断 permission key 是否由 Runtime 权限快照管理。
12
+ *
13
+ * @param key 待判断的 permission key。
14
+ * @returns 该 key 需要读取 Runtime 权限快照时返回 `true`。
15
+ */
16
+ function isManagedMiniProgramRuntimePermissionKey(key) {
17
+ return MANAGED_RUNTIME_PERMISSION_KEYS.has(key);
18
+ }
19
+ /**
20
+ * 解析服务端权限快照;格式不完整时整份快照失效并 fail closed。
21
+ *
22
+ * @param snapshot 待校验的服务端权限快照。
23
+ * @returns 解析状态和通过校验的受管权限。
24
+ */
25
+ function parseMiniProgramRuntimePermissions(snapshot) {
26
+ if (!isRecord(snapshot) || snapshot.schema_version !== 1 || !Array.isArray(snapshot.entries)) {
27
+ return { valid: false, permissions: {} };
28
+ }
29
+ if (snapshot.revision !== undefined && (typeof snapshot.revision !== 'number' || !Number.isInteger(snapshot.revision) || snapshot.revision < 0)) {
30
+ return { valid: false, permissions: {} };
31
+ }
32
+ const seenKeys = new Set();
33
+ const permissions = {};
34
+ for (const rawEntry of snapshot.entries) {
35
+ if (!isRecord(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
36
+ return { valid: false, permissions: {} };
37
+ }
38
+ const key = rawEntry.key.trim();
39
+ if (seenKeys.has(key) || (rawEntry.status !== 'enabled' && rawEntry.status !== 'disabled') || !isRecord(rawEntry.config)) {
40
+ return { valid: false, permissions: {} };
41
+ }
42
+ seenKeys.add(key);
43
+ if (!isManagedMiniProgramRuntimePermissionKey(key)) {
44
+ continue;
45
+ }
46
+ if (key === 'network.request' && typeof rawEntry.config.useOfficialDomain !== 'boolean') {
47
+ return { valid: false, permissions: {} };
48
+ }
49
+ permissions[key] = {
50
+ key,
51
+ status: rawEntry.status,
52
+ config: { useOfficialDomain: rawEntry.config.useOfficialDomain },
53
+ };
54
+ }
55
+ return { valid: true, permissions };
56
+ }
57
+ function isRecord(value) {
58
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
59
+ }
60
+
61
+ const DEFAULT_PERMISSION_STATE = {
62
+ networkRequest: {
63
+ status: 'disabled',
64
+ useOfficialDomain: false,
65
+ },
66
+ };
67
+ function createMiniProgramMockPermissionState(context) {
68
+ const parsed = parseMiniProgramRuntimePermissions(context.runtimePermissions);
69
+ const networkRequest = parsed.permissions['network.request'];
70
+ return parsed.valid && networkRequest
71
+ ? {
72
+ networkRequest: {
73
+ status: networkRequest.status,
74
+ useOfficialDomain: networkRequest.config.useOfficialDomain === true,
75
+ },
76
+ }
77
+ : cloneDefaultPermissionState();
78
+ }
79
+ function shouldSkipMiniappPlatformCsp(runtimePermissions) {
80
+ const parsed = parseMiniProgramRuntimePermissions(runtimePermissions);
81
+ const networkRequest = parsed.permissions['network.request'];
82
+ return parsed.valid && networkRequest?.status === 'enabled' && networkRequest.config.useOfficialDomain === true;
83
+ }
84
+ function createMiniProgramMockRuntimePermissions(state) {
85
+ return {
86
+ schema_version: 1,
87
+ entries: [
88
+ {
89
+ key: 'network.request',
90
+ status: state.networkRequest.status,
91
+ config: {
92
+ useOfficialDomain: state.networkRequest.useOfficialDomain,
93
+ },
94
+ },
95
+ ],
96
+ };
97
+ }
98
+ function cloneDefaultPermissionState() {
99
+ return {
100
+ networkRequest: { ...DEFAULT_PERMISSION_STATE.networkRequest },
101
+ };
102
+ }
103
+
104
+ function createRemoteApiClient(options) {
105
+ return {
106
+ listDeveloperEntities: () => listDeveloperEntities(options),
107
+ switchDeveloperEntity: (requestOptions) => switchDeveloperEntity(requestOptions, options),
108
+ getDeveloperAccessStatus: () => getDeveloperAccessStatus(options),
109
+ listUserMiniprograms: (requestOptions = {}) => listUserMiniprograms(requestOptions, options),
110
+ createUserMiniprogram: () => createUserMiniprogram(options),
111
+ getUserMiniprogramDetail: (requestOptions) => getUserMiniprogramDetail(requestOptions, options),
112
+ getPreviewAllowlist: (requestOptions) => getPreviewAllowlist(requestOptions, options),
113
+ updatePreviewAllowlist: (requestOptions) => updatePreviewAllowlist(requestOptions, options),
114
+ createUserMiniprogramLeaderboard: (requestOptions) => createUserMiniprogramLeaderboard(requestOptions, options),
115
+ getUserMiniprogramLeaderboard: (requestOptions) => getUserMiniprogramLeaderboard(requestOptions, options),
116
+ listUserMiniprogramLeaderboards: (requestOptions) => listUserMiniprogramLeaderboards(requestOptions, options),
117
+ deleteUserMiniprogramLeaderboard: (requestOptions) => deleteUserMiniprogramLeaderboard(requestOptions, options),
118
+ precheckUserMiniprogramVersion: (requestOptions) => precheckUserMiniprogramVersion(requestOptions, options),
119
+ submitUserMiniprogramAudit: (requestOptions) => submitUserMiniprogramAudit(requestOptions, options),
120
+ getVersionPreviewInfo: (requestOptions) => getVersionPreviewInfo(requestOptions, options),
121
+ withdrawUserMiniprogramVersion: (requestOptions) => withdrawUserMiniprogramVersion(requestOptions, options),
122
+ releaseUserMiniprogramVersion: (requestOptions) => releaseUserMiniprogramVersion(requestOptions, options),
123
+ takeDownUserMiniprogram: (requestOptions) => takeDownUserMiniprogram(requestOptions, options),
124
+ reopenUserMiniprogram: (requestOptions) => reopenUserMiniprogram(requestOptions, options),
125
+ updateSquareDisplay: (requestOptions) => updateSquareDisplay(requestOptions, options),
126
+ listUserMiniprogramVersions: (requestOptions) => listUserMiniprogramVersions(requestOptions, options),
127
+ };
128
+ }
129
+ async function listDeveloperEntities(runtime) {
130
+ return remoteGet(runtimePermissionEnv.DEVELOPER_ENTITY_LIST_API_PATH, {}, runtime);
131
+ }
132
+ async function switchDeveloperEntity(options, runtime) {
133
+ return (await remotePostForm(runtimePermissionEnv.DEVELOPER_ENTITY_SWITCH_API_PATH, options, runtime, { requireResult: false })) ?? {};
134
+ }
135
+ async function getDeveloperAccessStatus(runtime) {
136
+ return remoteGet(runtimePermissionEnv.USER_MINIPROGRAM_ACCESS_STATUS_API_PATH, {}, runtime);
137
+ }
138
+ async function listUserMiniprograms(options, runtime) {
139
+ return remoteGet(runtimePermissionEnv.LIST_USER_MINIPROGRAM_API_PATH, options, runtime);
140
+ }
141
+ async function createUserMiniprogram(runtime) {
142
+ return remotePostForm(runtimePermissionEnv.CREATE_USER_MINIPROGRAM_API_PATH, {}, runtime);
143
+ }
144
+ async function getUserMiniprogramDetail(options, runtime) {
145
+ return remoteGet(runtimePermissionEnv.DETAIL_USER_MINIPROGRAM_API_PATH, options, runtime);
146
+ }
147
+ async function getPreviewAllowlist(options, runtime) {
148
+ return remoteGet(runtimePermissionEnv.USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH, options, runtime);
149
+ }
150
+ async function updatePreviewAllowlist(options, runtime) {
151
+ return remotePostForm(runtimePermissionEnv.UPDATE_USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH, options, runtime);
152
+ }
153
+ async function createUserMiniprogramLeaderboard(options, runtime) {
154
+ return remotePostForm(runtimePermissionEnv.CREATE_USER_MINIPROGRAM_LEADERBOARD_API_PATH, options, runtime);
155
+ }
156
+ async function getUserMiniprogramLeaderboard(options, runtime) {
157
+ return remoteGet(runtimePermissionEnv.DETAIL_USER_MINIPROGRAM_LEADERBOARD_API_PATH, options, runtime);
158
+ }
159
+ async function listUserMiniprogramLeaderboards(options, runtime) {
160
+ return remoteGet(runtimePermissionEnv.LIST_USER_MINIPROGRAM_LEADERBOARD_API_PATH, options, runtime);
161
+ }
162
+ async function deleteUserMiniprogramLeaderboard(options, runtime) {
163
+ return (await remotePostForm(runtimePermissionEnv.DELETE_USER_MINIPROGRAM_LEADERBOARD_API_PATH, options, runtime, { requireResult: false })) ?? {};
164
+ }
165
+ async function precheckUserMiniprogramVersion(options, runtime) {
166
+ return remotePostForm(runtimePermissionEnv.PRECHECK_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
167
+ }
168
+ async function submitUserMiniprogramAudit(options, runtime) {
169
+ const form = { ...options };
170
+ if (form.manifest && typeof form.manifest !== 'string') {
171
+ form.manifest = JSON.stringify(form.manifest);
172
+ }
173
+ return remotePostForm(runtimePermissionEnv.SUBMIT_USER_MINIPROGRAM_AUDIT_API_PATH, form, runtime);
174
+ }
175
+ async function getVersionPreviewInfo(options, runtime) {
176
+ return remoteGet(runtimePermissionEnv.USER_MINIPROGRAM_VERSION_PREVIEW_INFO_API_PATH, {
177
+ mini_program_id: options.mini_program_id,
178
+ preview_version: options.version,
179
+ }, runtime);
180
+ }
181
+ async function withdrawUserMiniprogramVersion(options, runtime) {
182
+ return remotePostForm(runtimePermissionEnv.WITHDRAW_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
183
+ }
184
+ async function releaseUserMiniprogramVersion(options, runtime) {
185
+ return remotePostForm(runtimePermissionEnv.RELEASE_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
186
+ }
187
+ async function takeDownUserMiniprogram(options, runtime) {
188
+ return remotePostForm(runtimePermissionEnv.TAKE_DOWN_USER_MINIPROGRAM_API_PATH, options, runtime);
189
+ }
190
+ async function reopenUserMiniprogram(options, runtime) {
191
+ return remotePostForm(runtimePermissionEnv.REOPEN_USER_MINIPROGRAM_API_PATH, options, runtime);
192
+ }
193
+ async function updateSquareDisplay(options, runtime) {
194
+ return remotePostForm(runtimePermissionEnv.UPDATE_SQUARE_DISPLAY_API_PATH, options, runtime);
195
+ }
196
+ async function listUserMiniprogramVersions(options, runtime) {
197
+ return remoteGet(runtimePermissionEnv.LIST_USER_MINIPROGRAM_VERSION_API_PATH, options, runtime);
198
+ }
199
+ async function remoteGet(path, query, runtime) {
200
+ const pathWithQuery = createPathWithQuery(path, query);
201
+ const context = session.createHeyboxOpenPlatformRequestContext(runtime.session, pathWithQuery);
202
+ const fetchImpl = runtime.fetchImpl ?? fetch;
203
+ const response = await fetchImpl(session.createHeyboxApiUrl(runtime.baseUrl ?? context.baseUrl, pathWithQuery, context.platformParams), {
204
+ method: 'GET',
205
+ headers: context.headers,
206
+ });
207
+ return readRequiredResult(response, pathWithQuery);
208
+ }
209
+ async function remotePostForm(path, fields, runtime, options = {}) {
210
+ const context = session.createHeyboxOpenPlatformRequestContext(runtime.session, path, {
211
+ contentType: 'application/x-www-form-urlencoded',
212
+ });
213
+ const fetchImpl = runtime.fetchImpl ?? fetch;
214
+ const response = await fetchImpl(session.createHeyboxApiUrl(runtime.baseUrl ?? context.baseUrl, path, context.platformParams), {
215
+ method: 'POST',
216
+ headers: context.headers,
217
+ body: createFormBody(fields),
218
+ });
219
+ if (options.requireResult === false) {
220
+ return readOptionalResult(response, path);
221
+ }
222
+ return readRequiredResult(response, path);
223
+ }
224
+ async function readRequiredResult(response, pathWithQuery) {
225
+ const result = await session.readHeyboxApiEnvelope(response, { pathWithQuery, requireResult: true });
226
+ return result;
227
+ }
228
+ async function readOptionalResult(response, pathWithQuery) {
229
+ return session.readHeyboxApiEnvelope(response, { pathWithQuery, requireResult: false });
230
+ }
231
+ function createPathWithQuery(path, query) {
232
+ const params = new URLSearchParams();
233
+ for (const [key, value] of Object.entries(query)) {
234
+ if (value !== undefined && value !== null && value !== '') {
235
+ params.set(key, String(value));
236
+ }
237
+ }
238
+ const queryString = params.toString();
239
+ return queryString ? `${path}?${queryString}` : path;
240
+ }
241
+ function createFormBody(fields) {
242
+ const body = new URLSearchParams();
243
+ for (const [key, value] of Object.entries(fields)) {
244
+ if (value === undefined || value === null) {
245
+ continue;
246
+ }
247
+ if (Array.isArray(value)) {
248
+ body.set(key, value.join(','));
249
+ continue;
250
+ }
251
+ if (typeof value === 'object') {
252
+ body.set(key, JSON.stringify(value));
253
+ continue;
254
+ }
255
+ body.set(key, String(value));
256
+ }
257
+ return body.toString();
258
+ }
259
+
260
+ class MiniProgramProjectBindingError extends Error {
261
+ code;
262
+ constructor(message, code) {
263
+ super(message);
264
+ this.code = code;
265
+ this.name = 'MiniProgramProjectBindingError';
266
+ }
267
+ }
268
+ function findMiniProgramProjectRoot(startDir) {
269
+ let current = path.resolve(startDir);
270
+ while (true) {
271
+ if (fs$1.existsSync(path.join(current, 'package.json'))) {
272
+ return current;
273
+ }
274
+ const parent = path.dirname(current);
275
+ if (parent === current) {
276
+ throw new MiniProgramProjectBindingError('当前目录或父目录未找到 package.json', 'PACKAGE_JSON_NOT_FOUND');
277
+ }
278
+ current = parent;
279
+ }
280
+ }
281
+ async function readMiniProgramProjectPackage(startDir) {
282
+ const projectRoot = findMiniProgramProjectRoot(startDir);
283
+ const packageJsonPath = path.join(projectRoot, 'package.json');
284
+ const raw = await fs.readFile(packageJsonPath, 'utf8');
285
+ let packageJson;
286
+ try {
287
+ packageJson = JSON.parse(raw);
288
+ }
289
+ catch (error) {
290
+ const message = error instanceof Error ? error.message : String(error);
291
+ throw new MiniProgramProjectBindingError(`package.json 不是合法 JSON:${packageJsonPath}\n${message}`, 'PACKAGE_JSON_INVALID');
292
+ }
293
+ return {
294
+ projectRoot,
295
+ packageJsonPath,
296
+ packageJson,
297
+ raw,
298
+ indent: detectJsonIndent(raw),
299
+ trailingNewline: raw.endsWith('\r\n') ? '\r\n' : raw.endsWith('\n') ? '\n' : '',
300
+ };
301
+ }
302
+ function readBoundMiniProgramIdFromPackageJson(packageJson) {
303
+ const value = packageJson.heybox?.miniProgramId;
304
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
305
+ }
306
+ async function readBoundMiniProgramId(startDir) {
307
+ return readBoundMiniProgramIdFromPackageJson((await readMiniProgramProjectPackage(startDir)).packageJson);
308
+ }
309
+ async function requireBoundMiniProgramId(startDir) {
310
+ const context = await readMiniProgramProjectPackage(startDir);
311
+ const miniProgramId = readBoundMiniProgramIdFromPackageJson(context.packageJson);
312
+ if (!miniProgramId) {
313
+ throw new MiniProgramProjectBindingError(`当前项目未绑定小程序。请先运行 hb-sdk remote create 或 hb-sdk remote bind <mini-program-id>。\n配置位置:${context.packageJsonPath}#heybox.miniProgramId`, 'MINI_PROGRAM_UNBOUND');
314
+ }
315
+ return { ...context, miniProgramId };
316
+ }
317
+ async function writeBoundMiniProgramId(startDir, miniProgramId, options = {}) {
318
+ const context = await readMiniProgramProjectPackage(startDir);
319
+ const normalizedMiniProgramId = String(miniProgramId).trim();
320
+ if (!normalizedMiniProgramId) {
321
+ throw new MiniProgramProjectBindingError('miniProgramId 不能为空', 'PACKAGE_JSON_INVALID');
322
+ }
323
+ const currentMiniProgramId = readBoundMiniProgramIdFromPackageJson(context.packageJson);
324
+ if (currentMiniProgramId && currentMiniProgramId !== normalizedMiniProgramId && !options.force) {
325
+ throw new MiniProgramProjectBindingError(`当前项目已绑定小程序 ${currentMiniProgramId}。如需覆盖本地绑定,请使用 --force。`, 'MINI_PROGRAM_BINDING_EXISTS');
326
+ }
327
+ if (currentMiniProgramId === normalizedMiniProgramId) {
328
+ return {
329
+ ...context,
330
+ changed: false,
331
+ miniProgramId: normalizedMiniProgramId,
332
+ };
333
+ }
334
+ if (context.packageJson.heybox !== undefined && !isPlainObject(context.packageJson.heybox)) {
335
+ throw new MiniProgramProjectBindingError('package.json heybox 字段必须是对象,不能写入 miniProgramId', 'PACKAGE_JSON_HEYBOX_INVALID');
336
+ }
337
+ context.packageJson.heybox = {
338
+ ...(context.packageJson.heybox ?? {}),
339
+ miniProgramId: normalizedMiniProgramId,
340
+ };
341
+ await fs.writeFile(context.packageJsonPath, `${JSON.stringify(context.packageJson, null, context.indent)}${context.trailingNewline || '\n'}`, 'utf8');
342
+ return {
343
+ ...context,
344
+ changed: true,
345
+ miniProgramId: normalizedMiniProgramId,
346
+ };
347
+ }
348
+ function detectJsonIndent(raw) {
349
+ const match = raw.match(/\n(\s+)"[^"]+":/);
350
+ return match?.[1] ?? 2;
351
+ }
352
+ function isPlainObject(value) {
353
+ return Object.prototype.toString.call(value) === '[object Object]';
354
+ }
355
+
356
+ async function resolveRemoteEnvironment(options = {}, runtime = {}) {
357
+ const env = options.env ?? process.env;
358
+ const apiBaseUrl = session.resolveHeyboxApiBaseUrl({ ...options, env });
359
+ const loginBaseUrl = session.resolveHeyboxLoginBaseUrl({ ...options, env });
360
+ const session$1 = options.session ?? (await (runtime.requireAuthSession ?? session.requireHeyboxAuthSession)({ loginBaseUrl }));
361
+ return {
362
+ apiBaseUrl,
363
+ loginBaseUrl,
364
+ allowUnsafeApiBaseUrl: options.allowUnsafeApiBaseUrl === true || isTruthyEnvFlag(env.HB_SDK_ALLOW_UNSAFE_API_BASE_URL),
365
+ env,
366
+ fetchImpl: runtime.fetchImpl ?? options.fetchImpl ?? fetch,
367
+ session: session$1,
368
+ };
369
+ }
370
+ function createRemoteApiClientForEnvironment(environment) {
371
+ return createRemoteApiClient({
372
+ baseUrl: environment.apiBaseUrl,
373
+ fetchImpl: environment.fetchImpl,
374
+ session: environment.session,
375
+ });
376
+ }
377
+ async function getBoundMiniProgram(options = {}, runtime = {}) {
378
+ const cwd = options.cwd ?? process.cwd();
379
+ const binding = await requireBoundMiniProgramId(cwd);
380
+ const api = await resolveRemoteApiClient(options, runtime);
381
+ const detail = await api.getUserMiniprogramDetail({ mini_program_id: binding.miniProgramId });
382
+ return {
383
+ ...binding,
384
+ detail,
385
+ };
386
+ }
387
+ async function resolveRemoteApiClient(options, runtime) {
388
+ if (runtime.apiClient) {
389
+ return runtime.apiClient;
390
+ }
391
+ return createRemoteApiClientForEnvironment(await resolveRemoteEnvironment(options, runtime));
392
+ }
393
+ function isTruthyEnvFlag(value) {
394
+ return ['1', 'true', 'yes', 'on'].includes(String(value ?? '')
395
+ .trim()
396
+ .toLowerCase());
397
+ }
398
+
399
+ exports.MiniProgramProjectBindingError = MiniProgramProjectBindingError;
400
+ exports.createMiniProgramMockPermissionState = createMiniProgramMockPermissionState;
401
+ exports.createMiniProgramMockRuntimePermissions = createMiniProgramMockRuntimePermissions;
402
+ exports.createRemoteApiClientForEnvironment = createRemoteApiClientForEnvironment;
403
+ exports.getBoundMiniProgram = getBoundMiniProgram;
404
+ exports.parseMiniProgramRuntimePermissions = parseMiniProgramRuntimePermissions;
405
+ exports.readBoundMiniProgramId = readBoundMiniProgramId;
406
+ exports.readBoundMiniProgramIdFromPackageJson = readBoundMiniProgramIdFromPackageJson;
407
+ exports.readMiniProgramProjectPackage = readMiniProgramProjectPackage;
408
+ exports.resolveRemoteEnvironment = resolveRemoteEnvironment;
409
+ exports.shouldSkipMiniappPlatformCsp = shouldSkipMiniappPlatformCsp;
410
+ exports.writeBoundMiniProgramId = writeBoundMiniProgramId;
@@ -5,7 +5,7 @@ var fs = require('node:fs/promises');
5
5
  var path = require('node:path');
6
6
  var require$$0 = require('fs');
7
7
  var require$$1 = require('path');
8
- var index = require('./index-ByDy5HXi.cjs');
8
+ var index = require('./index-19i3Dr5H.cjs');
9
9
  require('node:module');
10
10
  require('os');
11
11
  require('readline');