@heybox/hb-sdk 0.8.3-alpha.2 → 0.8.3-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 (40) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +45 -7
  3. package/dist/cli-chunks/{build-lnIkF-rf.cjs → build-CkPA6jAR.cjs} +5 -5
  4. package/dist/cli-chunks/{context-DAdousk7.cjs → context-DoVGwJek.cjs} +35 -8
  5. package/dist/cli-chunks/{create-BrH3TKd9.cjs → create-vFF2Au_f.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-Dazm6mjQ.cjs → dev-5lkHU1uv.cjs} +194 -73
  7. package/dist/cli-chunks/{doctor-Dqju9vZQ.cjs → doctor-DFt0LWou.cjs} +1 -1
  8. package/dist/cli-chunks/{index-ZxzVU017.cjs → index-CguXMrgP.cjs} +2 -2
  9. package/dist/cli-chunks/{index-Cscd6hCr.cjs → index-Ol4wxcob.cjs} +15 -15
  10. package/dist/cli-chunks/{index.esm-BPF3ML9J.cjs → index.esm-DUvvFi-Z.cjs} +7 -7
  11. package/dist/cli-chunks/{login-CR8vCqdL.cjs → login-CA5BhdXd.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-C0fvgvWp.cjs → project-vite-P09pYZoU.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-CZBw05sT.cjs → remote-DU0f2mlK.cjs} +36 -9
  14. package/dist/cli-chunks/{runtime-gate-CCyvzllG.cjs → runtime-gate-Ay8_t7m0.cjs} +1 -1
  15. package/dist/cli-chunks/{runtime-permission-env-v9THnMre.cjs → runtime-permission-env-C0clU7_f.cjs} +119 -6
  16. package/dist/cli-chunks/{session-UhAizNH0.cjs → session-2vOGqgeA.cjs} +1 -1
  17. package/dist/cli-chunks/{skill-BxL6KOYN.cjs → skill-D5Pf0dxT.cjs} +2 -2
  18. package/dist/cli-chunks/{version-B-iUWMkU.cjs → version-CF6ilsAH.cjs} +1 -1
  19. package/dist/cli.cjs +1 -1
  20. package/dist/devtools/browser-dev-host/assets/browser-dev-host-D6g0uewc.js +101 -0
  21. package/dist/devtools/browser-dev-host/assets/{desktop-app-launch-B1QBmFTk.js → desktop-app-launch-Cku9Fxud.js} +3 -3
  22. package/dist/devtools/browser-dev-host/assets/index-BrXEMo2-.css +1 -0
  23. package/dist/devtools/browser-dev-host/assets/{index-DWFHHorU.js → index-CVARuXxw.js} +4 -4
  24. package/dist/devtools/browser-dev-host/index.html +3 -3
  25. package/dist/index.cjs.js +32 -16
  26. package/dist/index.esm.js +32 -16
  27. package/dist/protocol.cjs.js +29 -20
  28. package/dist/protocol.esm.js +29 -21
  29. package/dist/vite.cjs.js +3 -3
  30. package/dist/vite.esm.js +3 -3
  31. package/docs/runtime-host-migration.md +5 -3
  32. package/package.json +6 -6
  33. package/skill/skill.json +4 -4
  34. package/types/index.d.ts +2 -2
  35. package/types/modules/viewport/index.d.ts +33 -2
  36. package/types/protocol/capabilities.d.ts +1 -1
  37. package/types/protocol/dev-session.d.ts +13 -2
  38. package/types/protocol.d.ts +2 -2
  39. package/dist/devtools/browser-dev-host/assets/browser-dev-host-BKVURp-m.js +0 -101
  40. package/dist/devtools/browser-dev-host/assets/index-D-cRoNV5.css +0 -1
@@ -1,24 +1,24 @@
1
1
  'use strict';
2
2
 
3
- var context = require('./context-DAdousk7.cjs');
3
+ var context = require('./context-DoVGwJek.cjs');
4
4
  var node_crypto = require('node:crypto');
5
5
  var fs = require('node:fs');
6
+ var runtimePermissionEnv = require('./runtime-permission-env-C0clU7_f.cjs');
6
7
  var os = require('node:os');
7
8
  var path = require('node:path');
8
9
  var net = require('node:net');
9
10
  var promises = require('node:dns/promises');
10
11
  var node_http = require('node:http');
11
12
  var node_module = require('node:module');
12
- var runtimePermissionEnv = require('./runtime-permission-env-v9THnMre.cjs');
13
13
  var undici = require('undici');
14
14
  var fs$1 = require('node:fs/promises');
15
- var index = require('./index-Cscd6hCr.cjs');
15
+ var index = require('./index-Ol4wxcob.cjs');
16
16
  var require$$0$1 = require('crypto');
17
17
  var require$$0 = require('buffer');
18
- var session = require('./session-UhAizNH0.cjs');
18
+ var session = require('./session-2vOGqgeA.cjs');
19
19
  var browser = require('./browser-RAy8e8cV.cjs');
20
- var projectVite = require('./project-vite-C0fvgvWp.cjs');
21
- var version = require('./version-B-iUWMkU.cjs');
20
+ var projectVite = require('./project-vite-P09pYZoU.cjs');
21
+ var version = require('./version-CF6ilsAH.cjs');
22
22
  require('node:zlib');
23
23
 
24
24
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -1160,14 +1160,15 @@ function createDevSessionRoutes(options) {
1160
1160
  }
1161
1161
  try {
1162
1162
  const payload = await readJsonRequestBody(request);
1163
- const runtimePermissions = context.createMobileDevSessionRuntimePermissions(await options.readDevContext());
1163
+ const context$1 = await options.readDevContext();
1164
+ const runtimePermissions = context.createMobileDevSessionRuntimePermissions(context$1);
1164
1165
  const validated = validateDevSessionCreatePayload(payload, options.allowedMiniUrlOrigins, runtimePermissions);
1165
1166
  reapExpiredDevSessions(devSessions, expiredDevSessions, options.now());
1166
1167
  const replacedTokens = findDevSessionTokensForOrigin(devSessions, validated.miniUrlOrigin);
1167
1168
  if (devSessions.size - replacedTokens.length >= MAX_ACTIVE_DEV_SESSIONS) {
1168
1169
  throw createBrowserDevHostError(429, 'DEV_SESSION_LIMIT_REACHED', 'active Dev Session limit reached');
1169
1170
  }
1170
- const expiresAt = options.now() + DEV_SESSION_TTL_MS;
1171
+ const expiresAt = Math.min(options.now() + DEV_SESSION_TTL_MS, context$1.expiresAt ?? Infinity);
1171
1172
  const token = createDevSessionToken(devSessions);
1172
1173
  const snapshot = {
1173
1174
  schema_version: MINI_PROGRAM_DEV_SESSION_SCHEMA_VERSION,
@@ -1175,6 +1176,7 @@ function createDevSessionRoutes(options) {
1175
1176
  expires_at: expiresAt,
1176
1177
  mini_url_origin: validated.miniUrlOrigin,
1177
1178
  runtime_permissions: validated.runtimePermissions,
1179
+ ...createContextFields(context$1),
1178
1180
  };
1179
1181
  devSessions.set(token, {
1180
1182
  expiresAt,
@@ -1225,10 +1227,28 @@ function createDevSessionRoutes(options) {
1225
1227
  writeDevSessionCorsResponse(response, resolved.status);
1226
1228
  return;
1227
1229
  }
1228
- writeDevSessionCorsResponse(response, request.method === 'OPTIONS' ? 204 : 200, request.method === 'GET' ? resolved.session.serialized : undefined);
1230
+ // 同一个不可猜测引用读取当前 CLI 快照,让 Host 可检测撤权与 revision 变化。
1231
+ const context$1 = request.method === 'GET' ? options.readCurrentDevContext?.() : undefined;
1232
+ const serialized = context$1 ? JSON.stringify({ ...JSON.parse(resolved.session.serialized),
1233
+ ...createContextFields(context$1),
1234
+ expires_at: Math.min(resolved.session.expiresAt, context$1.expiresAt ?? Infinity),
1235
+ runtime_permissions: context.createMobileDevSessionRuntimePermissions(context$1) }) : undefined;
1236
+ writeDevSessionCorsResponse(response, request.method === 'OPTIONS' ? 204 : 200, request.method === 'GET' ? serialized ?? resolved.session.serialized : undefined);
1229
1237
  },
1230
1238
  };
1231
1239
  }
1240
+ function createContextFields(context) {
1241
+ return {
1242
+ local_dev_grant: context.localDevGrant,
1243
+ context_revision: context.contextRevision,
1244
+ declared_permissions: context.declaredPermissions,
1245
+ platforms: context.platforms,
1246
+ dev_session_id: context.devSessionId,
1247
+ local_dev_launch_token: context.localDevLaunchToken,
1248
+ mini_program_id: context.miniProgramId,
1249
+ companion_manifest_sha256: context.companionManifestSha256,
1250
+ };
1251
+ }
1232
1252
  function validateDevSessionCreatePayload(payload, allowedMiniUrlOrigins, runtimePermissions) {
1233
1253
  if (!isRecord$2(payload) || Object.keys(payload).some((key) => !['mini_url_origin', 'runtime_permissions'].includes(key))) {
1234
1254
  throw new TypeError('Dev Session body is invalid');
@@ -1950,8 +1970,8 @@ const DEFAULT_CHANNEL_TRANSPORT = {
1950
1970
  };
1951
1971
  const IPV4_LOOPBACK_ADDRESSES = new net.BlockList();
1952
1972
  IPV4_LOOPBACK_ADDRESSES.addSubnet('127.0.0.0', 8, 'ipv4');
1953
- const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-Dazm6mjQ.cjs', document.baseURI).href)))('ws');
1954
- const { parse: parseHtml } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-Dazm6mjQ.cjs', document.baseURI).href)))('parse5');
1973
+ const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-5lkHU1uv.cjs', document.baseURI).href)))('ws');
1974
+ const { parse: parseHtml } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-5lkHU1uv.cjs', document.baseURI).href)))('parse5');
1955
1975
  const BROWSER_DEV_HOST_ROOT_CANDIDATES = [
1956
1976
  path.resolve(__dirname, 'devtools/browser-dev-host'),
1957
1977
  path.resolve(__dirname, '../devtools/browser-dev-host'),
@@ -2182,6 +2202,7 @@ function createBrowserDevHostServer(root, runtime) {
2182
2202
  lookupHostname: runtime.lookupHostname,
2183
2203
  now: runtime.now,
2184
2204
  readDevContext: runtime.readMobileDevSessionContext,
2205
+ readCurrentDevContext: runtime.readDevContext,
2185
2206
  onCreated: ({ expiresAt, miniUrlOrigin, token }, request) => {
2186
2207
  const origin = new URL(readRequestOrigin(request));
2187
2208
  const hostname = origin.hostname.startsWith('[') && origin.hostname.endsWith(']') ? origin.hostname.slice(1, -1) : origin.hostname;
@@ -2790,7 +2811,7 @@ function createBrowserDevHostChannelServer(server, options) {
2790
2811
  }
2791
2812
  async function readBrowserDevHostChannelSnapshot(runtime, cookieHeader) {
2792
2813
  const status = await readAccountStatus(runtime, cookieHeader);
2793
- const permissions = context.createBrowserDevPermissionState(runtime.readDevContext());
2814
+ const permissions = context.createBrowserDevPermissionState(context.resolveBrowserFakeContext(runtime.readDevContext()));
2794
2815
  return {
2795
2816
  account: {
2796
2817
  revision: status.revision,
@@ -11049,7 +11070,7 @@ function assertNodeRuntimeCapabilities(ctx, settings) {
11049
11070
  function createNodeRealtimeDriverRegistry() {
11050
11071
  const registry = createRuntimeRealtimeDriverRegistry();
11051
11072
  registry.registerLazy('node-websocket', async () => {
11052
- const mod = await Promise.resolve().then(function () { return require('./index.esm-BPF3ML9J.cjs'); });
11073
+ const mod = await Promise.resolve().then(function () { return require('./index.esm-DUvvFi-Z.cjs'); });
11053
11074
  return mod.createNodeWebSocketRuntimeDriver();
11054
11075
  });
11055
11076
  return registry;
@@ -15031,7 +15052,9 @@ function tryHandleMiniProgramDevLaunchRequest(request, response, readSource) {
15031
15052
  catch {
15032
15053
  return false;
15033
15054
  }
15034
- if (requestUrl.pathname !== MINI_PROGRAM_DEV_LAUNCH_PATH || requestUrl.search !== '') {
15055
+ const contextSource = /^\/__hb_sdk__\/dev-context\/[a-f0-9]{64}$/.test(requestUrl.pathname) ? readSource() : undefined;
15056
+ const isContext = contextSource?.devContextPath !== undefined && requestUrl.pathname === contextSource.devContextPath;
15057
+ if ((!isContext && requestUrl.pathname !== MINI_PROGRAM_DEV_LAUNCH_PATH) || requestUrl.search !== '') {
15035
15058
  return false;
15036
15059
  }
15037
15060
  if (!isAllowedLaunchOrigin(request.headers.origin)) {
@@ -15056,7 +15079,11 @@ function tryHandleMiniProgramDevLaunchRequest(request, response, readSource) {
15056
15079
  writeLaunchResponse(response, 204);
15057
15080
  return true;
15058
15081
  }
15059
- writeLaunchResponse(response, 200, JSON.stringify(createLaunchSnapshot(readSource(), origin)));
15082
+ const source = contextSource ?? readSource();
15083
+ const snapshot = createLaunchSnapshot(source, origin);
15084
+ writeLaunchResponse(response, 200, JSON.stringify(isContext
15085
+ ? { ...snapshot, revision: source.devContext?.contextRevision ?? 0, mini_url_origin: origin.origin }
15086
+ : snapshot));
15060
15087
  return true;
15061
15088
  }
15062
15089
  function createLaunchSnapshot(source, requestOrigin) {
@@ -15076,6 +15103,13 @@ function createLaunchSnapshot(source, requestOrigin) {
15076
15103
  snapshot.dev_session_id = source.devSessionId;
15077
15104
  if (source.expiresAt)
15078
15105
  snapshot.expires_at = source.expiresAt;
15106
+ const context = source.devContext;
15107
+ if (context) {
15108
+ snapshot.context_revision = context.contextRevision;
15109
+ snapshot.local_dev_grant = context.localDevGrant;
15110
+ snapshot.declared_permissions = context.declaredPermissions;
15111
+ snapshot.platforms = context.platforms;
15112
+ }
15079
15113
  const companionManifestSha256 = source.companionManifestSha256?.trim();
15080
15114
  if (companionManifestSha256)
15081
15115
  snapshot.companion_manifest_sha256 = companionManifestSha256;
@@ -15086,6 +15120,8 @@ function createLaunchSnapshot(source, requestOrigin) {
15086
15120
  if (storedContextUrl) {
15087
15121
  snapshot.dev_context_url = projectStoredDevContextUrl(storedContextUrl, requestOrigin.hostname);
15088
15122
  }
15123
+ if (source.devContextPath)
15124
+ snapshot.dev_context_url = new URL(source.devContextPath, requestOrigin).toString();
15089
15125
  if (runtimePermissionEnv.parseMiniProgramRuntimePermissions(source.runtimePermissions).valid && source.runtimePermissions) {
15090
15126
  snapshot.runtime_permissions = JSON.parse(JSON.stringify(source.runtimePermissions));
15091
15127
  }
@@ -15154,9 +15190,6 @@ async function runDevCommand(options, runtime = {}) {
15154
15190
  const logger = runtime.logger ?? index.createCliLogger();
15155
15191
  const fetchImpl = runtime.fetchImpl ?? fetch;
15156
15192
  const openUrl = runtime.openExternalUrl ?? browser.openExternalUrl;
15157
- if (!(await session.readHeyboxAuthSession({ env: runtime.env }))) {
15158
- throw new Error('hb-sdk dev 需要 CLI 登录态。请先运行 hb-sdk login。');
15159
- }
15160
15193
  const networkInterfaceSnapshot = (runtime.networkInterfaces ?? os.networkInterfaces)();
15161
15194
  const getPortImpl = runtime.getPort ?? getPorts;
15162
15195
  const appPort = await selectAvailablePort({
@@ -15174,6 +15207,7 @@ async function runDevCommand(options, runtime = {}) {
15174
15207
  const companionArtifactAccessToken = (runtime.randomBytes ?? node_crypto.randomBytes)(32).toString('base64url');
15175
15208
  const miniProgramManifestAccessToken = (runtime.randomBytes ?? node_crypto.randomBytes)(32).toString('base64url');
15176
15209
  const devSessionId = node_crypto.randomBytes(16).toString('hex');
15210
+ const devContextPath = `/__hb_sdk__/dev-context/${node_crypto.randomBytes(32).toString('hex')}`;
15177
15211
  const miniProgramPlatforms = runtimePermissionEnv.readMiniappPlatformsFromPackageJson(projectRoot);
15178
15212
  const { context: devLaunchContext, miniProgram } = await loadDevLaunchContext({
15179
15213
  env: runtime.env,
@@ -15183,19 +15217,42 @@ async function runDevCommand(options, runtime = {}) {
15183
15217
  timeoutMs: runtime.devContextTimeoutMs ?? DEFAULT_DEV_CONTEXT_TIMEOUT_MS,
15184
15218
  });
15185
15219
  let currentDevContext = devLaunchContext;
15186
- let launchRuntimePermissions = context.createBrowserDevRuntimePermissions(devLaunchContext.runtimePermissions, context.createBrowserDevPermissionState(devLaunchContext));
15220
+ let contextRevision = 1;
15221
+ let launchRuntimePermissions = context.createMobileDevSessionRuntimePermissions(devLaunchContext);
15187
15222
  const mobileDevContextUrlsByOrigin = new Map();
15188
15223
  let currentCompanionManifestSha256;
15189
15224
  let currentLocalDevLaunchToken = devLaunchContext.localDevLaunchToken;
15190
15225
  let currentExpiresAt;
15226
+ let refreshDevCsp;
15227
+ let lastTemporaryWarning = '';
15191
15228
  let tokenSession;
15229
+ const updateLocalContext = (allowedTemporaryKeys) => {
15230
+ const grant = runtimePermissionEnv.createMiniProgramLocalDevGrant({ declaredPermissions: currentDevContext.declaredPermissions ?? {},
15231
+ runtimePermissions: currentDevContext.runtimePermissions, revision: contextRevision,
15232
+ eligiblePermissionKeys: currentCompanionManifestSha256 && runtimePermissionEnv.hasMiniappDesktopPlatform(currentDevContext.platforms)
15233
+ ? ['network', 'companion'] : ['network'] });
15234
+ if (allowedTemporaryKeys)
15235
+ grant.entries = grant.entries.filter(entry => allowedTemporaryKeys.has(entry.key));
15236
+ const temporaryWarning = grant.entries.map(entry => entry.key).join('、');
15237
+ if (temporaryWarning && temporaryWarning !== lastTemporaryWarning)
15238
+ logger.warn(`本地临时权限:${temporaryWarning};线上未批准,发布后不可用。`);
15239
+ lastTemporaryWarning = temporaryWarning;
15240
+ currentDevContext = { ...currentDevContext, localDevGrant: grant, contextRevision, devSessionId,
15241
+ companionManifestSha256: currentCompanionManifestSha256,
15242
+ expiresAt: currentExpiresAt ?? Date.now() + 24 * 60 * 60 * 1000 };
15243
+ launchRuntimePermissions = context.createMobileDevSessionRuntimePermissions(currentDevContext);
15244
+ refreshDevCsp?.();
15245
+ };
15246
+ updateLocalContext();
15192
15247
  const readLaunchSource = () => ({
15248
+ devContext: currentDevContext,
15249
+ devContextPath,
15193
15250
  companionArtifactAccessToken,
15194
15251
  companionManifestSha256: currentCompanionManifestSha256,
15195
15252
  devContextUrlsByMiniUrlOrigin: mobileDevContextUrlsByOrigin,
15196
15253
  localDevLaunchToken: currentLocalDevLaunchToken,
15197
15254
  devSessionId,
15198
- expiresAt: currentExpiresAt,
15255
+ expiresAt: currentDevContext.expiresAt,
15199
15256
  miniProgramId: devLaunchContext.miniProgramId,
15200
15257
  runtimePermissions: launchRuntimePermissions,
15201
15258
  sdkVersion: version.HB_SDK_VERSION,
@@ -15234,11 +15291,21 @@ async function runDevCommand(options, runtime = {}) {
15234
15291
  return true;
15235
15292
  });
15236
15293
  const vite = await runDevStartupTask(logger, '正在加载项目 Vite', () => projectVite.loadProjectVite(projectRoot), '已加载项目 Vite');
15237
- const appServer = await runDevStartupTask(logger, '正在创建 Vite 开发服务器', () => runtimePermissionEnv.withMiniappPlatformCspEnv(context.shouldSkipMiniappPlatformCsp(devLaunchContext.runtimePermissions), () => withCompanionArtifactAccessTokenEnv(companionArtifactAccessToken, () => withMiniProgramManifestAccessTokenEnv(miniProgramManifestAccessToken, () => withManagedDevOutputEnv(() => vite.createServer(createViteServerOptions(projectRoot, resolvedOptions, launchPlugin)), runtime.env), runtime.env), runtime.env), runtime.env), '已创建 Vite 开发服务器');
15294
+ const appServer = await runDevStartupTask(logger, '正在创建 Vite 开发服务器', () => runtimePermissionEnv.withMiniappPlatformCspEnv(context.shouldSkipMiniappPlatformCsp(devLaunchContext.runtimePermissions) || currentDevContext.localDevGrant?.entries.some(entry => entry.key === 'network') === true, () => withCompanionArtifactAccessTokenEnv(companionArtifactAccessToken, () => withMiniProgramManifestAccessTokenEnv(miniProgramManifestAccessToken, () => withManagedDevOutputEnv(() => vite.createServer(createViteServerOptions(projectRoot, resolvedOptions, launchPlugin)), runtime.env), runtime.env), runtime.env), runtime.env), '已创建 Vite 开发服务器');
15238
15295
  await runDevStartupTask(logger, '正在启动 Vite 开发服务器', () => appServer.listen(appPort), 'Vite 开发服务器已启动');
15296
+ let skipDevCsp = context.shouldSkipMiniappPlatformCsp(currentDevContext.runtimePermissions) || currentDevContext.localDevGrant?.entries.some(entry => entry.key === 'network') === true;
15297
+ refreshDevCsp = () => {
15298
+ const next = context.shouldSkipMiniappPlatformCsp(currentDevContext.runtimePermissions) || currentDevContext.localDevGrant?.entries.some(entry => entry.key === 'network') === true;
15299
+ if (next === skipDevCsp || !appServer.restart)
15300
+ return;
15301
+ skipDevCsp = next;
15302
+ void runtimePermissionEnv.withMiniappPlatformCspEnv(next, () => withCompanionArtifactAccessTokenEnv(companionArtifactAccessToken, () => withMiniProgramManifestAccessTokenEnv(miniProgramManifestAccessToken, () => appServer.restart(), runtime.env), runtime.env), runtime.env)
15303
+ .catch(() => logger.warn('开发服务器权限配置刷新失败,请重新运行 hb-sdk dev'));
15304
+ };
15239
15305
  const appUrl = await runDevStartupTask(logger, '正在探测小程序入口', () => resolveViteAppUrl(appServer, resolvedOptions, fetchImpl), '已确定小程序入口');
15240
15306
  const buildLanAddresses = () => createLanAddressCandidates({
15241
15307
  appUrl,
15308
+ devContextPath,
15242
15309
  devContextUrlsByMiniUrlOrigin: mobileDevContextUrlsByOrigin,
15243
15310
  hmrHost: resolvedOptions.hmrHost,
15244
15311
  interfaces: networkInterfaceSnapshot,
@@ -15272,28 +15339,18 @@ async function runDevCommand(options, runtime = {}) {
15272
15339
  });
15273
15340
  },
15274
15341
  readMobileDevSessionContext: async () => {
15275
- try {
15276
- const refreshed = await loadDevLaunchContext({
15277
- env: runtime.env,
15278
- fetchImpl,
15279
- logger,
15280
- projectRoot,
15281
- timeoutMs: runtime.devContextTimeoutMs ?? DEFAULT_DEV_CONTEXT_TIMEOUT_MS,
15282
- });
15283
- currentDevContext = withCurrentLocalDevLaunchToken(refreshed.context, currentLocalDevLaunchToken);
15284
- launchRuntimePermissions = context.createMobileDevSessionRuntimePermissions(currentDevContext);
15285
- browserDevHost.updateBootstrap({
15286
- devContext: currentDevContext,
15287
- miniProgram: refreshed.miniProgram,
15288
- });
15289
- return currentDevContext;
15290
- }
15291
- catch (error) {
15292
- currentDevContext = { source: 'anonymous' };
15293
- launchRuntimePermissions = { schema_version: 1, entries: [] };
15294
- browserDevHost.updateBootstrap({ devContext: currentDevContext });
15295
- throw error;
15342
+ if (currentDevContext.source === 'remote') {
15343
+ const refreshed = await loadDevLaunchContext({ env: runtime.env, fetchImpl, logger, projectRoot,
15344
+ timeoutMs: runtime.devContextTimeoutMs ?? DEFAULT_DEV_CONTEXT_TIMEOUT_MS });
15345
+ if (refreshed.context.source === 'remote' && refreshed.context.miniProgramId === currentDevContext.miniProgramId) {
15346
+ if (JSON.stringify(currentDevContext.runtimePermissions) !== JSON.stringify(refreshed.context.runtimePermissions))
15347
+ contextRevision++;
15348
+ currentDevContext = withCurrentLocalDevLaunchToken(refreshed.context, currentLocalDevLaunchToken);
15349
+ updateLocalContext();
15350
+ browserDevHost.updateBootstrap({ devContext: currentDevContext });
15351
+ }
15296
15352
  }
15353
+ return currentDevContext;
15297
15354
  },
15298
15355
  port: options.browserDevHostPort ?? DEFAULT_BROWSER_DEV_HOST_PORT,
15299
15356
  root: runtime.browserDevHostRoot,
@@ -15313,24 +15370,30 @@ async function runDevCommand(options, runtime = {}) {
15313
15370
  logger,
15314
15371
  manifestUrl: new URL(COMPANION_DEV_MANIFEST_PATH, appUrl).toString(),
15315
15372
  companionArtifactAccessToken,
15316
- companionApproved: hasCompanionApproval(devLaunchContext.runtimePermissions),
15373
+ companionDeclared: currentDevContext.declaredPermissions?.companion?.enabled === true && runtimePermissionEnv.hasMiniappDesktopPlatform(currentDevContext.platforms),
15317
15374
  miniProgramId: devLaunchContext.miniProgramId,
15318
15375
  refreshPermissions: async () => {
15319
15376
  const refreshed = await loadDevLaunchContext({ env: runtime.env, fetchImpl, logger, projectRoot,
15320
15377
  timeoutMs: runtime.devContextTimeoutMs ?? DEFAULT_DEV_CONTEXT_TIMEOUT_MS });
15321
15378
  if (refreshed.context.miniProgramId !== devLaunchContext.miniProgramId)
15322
15379
  throw new Error('项目绑定已变更,请重新启动调试');
15323
- devLaunchContext.runtimePermissions = refreshed.context.runtimePermissions;
15324
- currentDevContext = withCurrentLocalDevLaunchToken(devLaunchContext, currentLocalDevLaunchToken);
15325
- launchRuntimePermissions = context.createBrowserDevRuntimePermissions(devLaunchContext.runtimePermissions, context.createBrowserDevPermissionState(devLaunchContext));
15380
+ if (refreshed.context.source !== 'remote')
15381
+ throw new Error('远端权限刷新暂不可用');
15382
+ if (JSON.stringify(currentDevContext.runtimePermissions) !== JSON.stringify(refreshed.context.runtimePermissions))
15383
+ contextRevision++;
15384
+ currentDevContext = withCurrentLocalDevLaunchToken(refreshed.context, currentLocalDevLaunchToken);
15385
+ updateLocalContext();
15326
15386
  browserDevHost.updateBootstrap({ devContext: currentDevContext });
15327
- return hasCompanionApproval(devLaunchContext.runtimePermissions);
15387
+ return currentDevContext.declaredPermissions?.companion?.enabled === true && runtimePermissionEnv.hasMiniappDesktopPlatform(currentDevContext.platforms);
15328
15388
  },
15329
15389
  onToken: (localDevLaunchToken, companionManifestSha256, expiresAt) => {
15330
- currentExpiresAt = expiresAt;
15390
+ if (currentCompanionManifestSha256 !== companionManifestSha256 || Boolean(currentLocalDevLaunchToken) !== Boolean(localDevLaunchToken))
15391
+ contextRevision++;
15392
+ currentExpiresAt = expiresAt ?? (currentLocalDevLaunchToken ? Date.now() : undefined);
15331
15393
  currentCompanionManifestSha256 = companionManifestSha256;
15332
15394
  currentLocalDevLaunchToken = localDevLaunchToken;
15333
15395
  currentDevContext = withCurrentLocalDevLaunchToken(currentDevContext, localDevLaunchToken);
15396
+ updateLocalContext();
15334
15397
  browserDevHost.updateBootstrap({
15335
15398
  devContext: currentDevContext,
15336
15399
  lanAddresses: buildLanAddresses(),
@@ -15352,6 +15415,44 @@ async function runDevCommand(options, runtime = {}) {
15352
15415
  },
15353
15416
  });
15354
15417
  }
15418
+ const packagePath = path.join(projectRoot, 'package.json');
15419
+ const onDeclarationChange = () => {
15420
+ try {
15421
+ const previouslyTemporary = new Set(currentDevContext.localDevGrant?.entries.map(entry => entry.key));
15422
+ const local = runtimePermissionEnv.readMiniappPermissionsFromPackageJson(projectRoot, runtimePermissionEnv.resolveMiniappSdkVersion());
15423
+ const platforms = runtimePermissionEnv.readMiniappPlatformsFromPackageJson(projectRoot);
15424
+ contextRevision++;
15425
+ currentDevContext = { ...currentDevContext, declaredPermissions: local.permissions ?? {}, platforms,
15426
+ runtimePermissions: runtimePermissionEnv.composeMiniappRuntimePermissions(local, currentDevContext.runtimePermissions).runtimePermissions };
15427
+ // 新声明必须重新取得远端基线;已有票据期间只允许删除,不因刷新失败扩权。
15428
+ currentCompanionManifestSha256 = undefined;
15429
+ updateLocalContext(currentDevContext.source === 'remote' ? previouslyTemporary : undefined);
15430
+ tokenSession?.refresh();
15431
+ browserDevHost.updateBootstrap({ devContext: currentDevContext, miniProgramSupportsDesktop: runtimePermissionEnv.hasMiniappDesktopPlatform(platforms) });
15432
+ }
15433
+ catch {
15434
+ contextRevision++;
15435
+ currentDevContext = { ...currentDevContext, declaredPermissions: {}, localDevGrant: undefined,
15436
+ contextRevision, platforms: [], localDevLaunchToken: undefined, expiresAt: undefined,
15437
+ runtimePermissions: { schema_version: 1, entries: [] }, warning: '本地权限声明无效,调试权限已撤销' };
15438
+ launchRuntimePermissions = { schema_version: 1, entries: [] };
15439
+ currentCompanionManifestSha256 = undefined;
15440
+ currentLocalDevLaunchToken = undefined;
15441
+ currentExpiresAt = undefined;
15442
+ refreshDevCsp?.();
15443
+ tokenSession?.refresh();
15444
+ browserDevHost.updateBootstrap({
15445
+ devContext: currentDevContext,
15446
+ devReadiness: {
15447
+ browser: { state: 'ready' },
15448
+ mobile: { state: 'blocked', reason: '本地权限声明无效,已撤销真实客户端调试' },
15449
+ companion: { state: 'blocked', reason: '本地权限声明无效,已撤销真实客户端调试' },
15450
+ },
15451
+ });
15452
+ }
15453
+ };
15454
+ fs.watchFile(packagePath, { interval: 500, persistent: false }, onDeclarationChange);
15455
+ closers.push(() => fs.unwatchFile(packagePath, onDeclarationChange));
15355
15456
  logger.success('Web / Browser Fake 调试已就绪');
15356
15457
  logger.info(`调试页:${browserDevHost.url}`);
15357
15458
  logger.info(`小程序地址:${appUrl}`);
@@ -15364,9 +15465,9 @@ async function runDevCommand(options, runtime = {}) {
15364
15465
  }
15365
15466
  function withCurrentLocalDevLaunchToken(context, localDevLaunchToken) {
15366
15467
  return {
15367
- source: context.source,
15468
+ ...context,
15368
15469
  ...(context.miniProgramId ? { miniProgramId: context.miniProgramId } : {}),
15369
- ...(localDevLaunchToken ? { localDevLaunchToken } : {}),
15470
+ localDevLaunchToken,
15370
15471
  ...(context.runtimePermissions !== undefined ? { runtimePermissions: context.runtimePermissions } : {}),
15371
15472
  ...(context.warning ? { warning: context.warning } : {}),
15372
15473
  };
@@ -15378,10 +15479,19 @@ function runDevStartupTask(logger, text, action, successText) {
15378
15479
  return logger.task(text, () => action(), { successText });
15379
15480
  }
15380
15481
  async function loadDevLaunchContext(options) {
15482
+ // 声明错误始终阻断;远端不可用只影响真实 Host。
15483
+ const localPermissions = runtimePermissionEnv.readMiniappPermissionsFromPackageJson(options.projectRoot, runtimePermissionEnv.resolveMiniappSdkVersion());
15484
+ const platforms = runtimePermissionEnv.readMiniappPlatformsFromPackageJson(options.projectRoot);
15485
+ if (!localPermissions.declared)
15486
+ options.logger.warn(runtimePermissionEnv.getMissingPermissionsWarning());
15487
+ const anonymous = (warning) => ({ context: { source: 'anonymous', warning,
15488
+ declaredPermissions: localPermissions.permissions ?? {}, platforms,
15489
+ runtimePermissions: runtimePermissionEnv.composeMiniappRuntimePermissions(localPermissions, undefined).runtimePermissions }, miniProgram: null });
15490
+ if (!(await session.readHeyboxAuthSession({ env: options.env })))
15491
+ return anonymous('尚未登录 CLI,真实手机和 PC 调试不可用');
15381
15492
  const miniProgramId = await context.readBoundMiniProgramId(options.projectRoot);
15382
- if (!miniProgramId) {
15383
- throw new Error('hb-sdk dev 需要绑定小程序。请先运行 hb-sdk remote create 或 hb-sdk remote bind <mini-program-id>。');
15384
- }
15493
+ if (!miniProgramId)
15494
+ return anonymous('尚未绑定小程序,真实手机和 PC 调试不可用');
15385
15495
  let migratingProfile = false;
15386
15496
  try {
15387
15497
  const { detail, miniProgramId: verifiedMiniProgramId } = await runDevStartupTask(options.logger, '正在读取远端小程序权限', () => loadRemoteDevContextWithTimeout({
@@ -15398,15 +15508,16 @@ async function loadDevLaunchContext(options) {
15398
15508
  migratingProfile = false;
15399
15509
  if (migration.changed)
15400
15510
  options.logger.info('已迁移当前正式发布名称与图片,继续启动开发环境');
15401
- const localPermissions = runtimePermissionEnv.readMiniappPermissionsFromPackageJson(options.projectRoot, runtimePermissionEnv.resolveMiniappSdkVersion());
15402
- if (!localPermissions.declared)
15403
- options.logger.warn(runtimePermissionEnv.getMissingPermissionsWarning());
15511
+ if (!runtimePermissionEnv.parseMiniProgramRuntimePermissions(detail.runtime_permissions).valid)
15512
+ return anonymous('线上权限快照无效,真实手机和 PC 调试不可用');
15404
15513
  const effectivePermissions = runtimePermissionEnv.composeMiniappRuntimePermissions(localPermissions, detail.runtime_permissions).runtimePermissions;
15405
15514
  return {
15406
15515
  context: {
15407
15516
  source: 'remote',
15408
15517
  miniProgramId: verifiedMiniProgramId,
15409
15518
  runtimePermissions: effectivePermissions,
15519
+ declaredPermissions: localPermissions.permissions ?? {},
15520
+ platforms,
15410
15521
  },
15411
15522
  miniProgram: createMiniProgramSummary(verifiedMiniProgramId, detail),
15412
15523
  };
@@ -15414,10 +15525,9 @@ async function loadDevLaunchContext(options) {
15414
15525
  catch (error) {
15415
15526
  if (migratingProfile)
15416
15527
  throw new Error(`版本资料配置失败:${index.readRedactedErrorMessage(error)}。请配置 heybox.name/icon/coverImages 后重试。`, { cause: error });
15417
- if (error instanceof context.MiniProgramProjectBindingError && error.code !== 'MINI_PROGRAM_UNBOUND') {
15528
+ if (error instanceof context.MiniProgramProjectBindingError && error.code.startsWith('PACKAGE_JSON_'))
15418
15529
  throw error;
15419
- }
15420
- throw new Error('无法读取远端 Dev Context,请检查 CLI 登录态、项目绑定和网络后重试。', { cause: error });
15530
+ return anonymous('未连接线上上下文,请检查 CLI 登录态、项目绑定和网络');
15421
15531
  }
15422
15532
  }
15423
15533
  function createMiniProgramSummary(miniProgramId, detail) {
@@ -15649,12 +15759,13 @@ function startLocalDevLaunchTokenSession(options) {
15649
15759
  let expirationTimer;
15650
15760
  let hasReportedTokenFailure = false;
15651
15761
  let refreshTimer;
15652
- let companionApproved = options.companionApproved;
15762
+ let companionDeclared = options.companionDeclared;
15653
15763
  let permissionsRefreshAt = Date.now() + 30_000;
15654
15764
  let publishedToken;
15655
15765
  let publishedDigest;
15656
15766
  let ticket;
15657
15767
  let pending;
15768
+ let refreshing = false;
15658
15769
  const getTicket = async (companionManifestSha256) => {
15659
15770
  if (closed)
15660
15771
  return undefined;
@@ -15678,24 +15789,27 @@ function startLocalDevLaunchTokenSession(options) {
15678
15789
  return promise;
15679
15790
  };
15680
15791
  const refresh = async () => {
15792
+ if (refreshing || closed)
15793
+ return;
15794
+ refreshing = true;
15681
15795
  try {
15682
15796
  if (options.refreshPermissions && Date.now() >= permissionsRefreshAt) {
15683
- companionApproved = await options.refreshPermissions();
15797
+ companionDeclared = await options.refreshPermissions();
15684
15798
  permissionsRefreshAt = Date.now() + 30_000;
15685
15799
  }
15686
15800
  let manifest;
15687
15801
  let snapshotError;
15688
15802
  try {
15689
- manifest = await loadRemoteDevContextWithTimeout({
15803
+ manifest = companionDeclared ? await loadRemoteDevContextWithTimeout({
15690
15804
  fetchImpl: options.fetchImpl,
15691
15805
  timeoutMs: options.timeoutMs,
15692
15806
  load: fetchImpl => readCompanionManifest(options.manifestUrl, options.companionArtifactAccessToken, fetchImpl),
15693
- });
15807
+ }) : undefined;
15694
15808
  }
15695
15809
  catch (error) {
15696
15810
  snapshotError = error;
15697
15811
  }
15698
- const digest = manifest?.digest;
15812
+ const digest = manifest?.artifacts.length ? manifest.digest : undefined;
15699
15813
  const issued = await getTicket(digest);
15700
15814
  if (!issued)
15701
15815
  return;
@@ -15712,9 +15826,9 @@ function startLocalDevLaunchTokenSession(options) {
15712
15826
  companion: snapshotError
15713
15827
  ? { state: snapshotError instanceof Error && snapshotError.message.includes('artifact-updating') ? 'pending' : 'blocked', reason: safeCompanionFailureReason(snapshotError) }
15714
15828
  : manifest?.artifacts.length
15715
- ? companionApproved
15829
+ ? companionDeclared
15716
15830
  ? { state: 'ready', digest, artifacts: manifest.artifacts, reason: '本地产物和启动票已就绪,PC 授权将在打开后验证' }
15717
- : { state: 'blocked', reason: 'Companion 未获 COA 批准或本地权限声明未开启' }
15831
+ : { state: 'blocked', reason: 'Companion 本地权限或桌面平台声明未开启' }
15718
15832
  : { state: 'not-configured', reason: '未配置本地 Companion 产物' },
15719
15833
  });
15720
15834
  if (snapshotError)
@@ -15739,6 +15853,9 @@ function startLocalDevLaunchTokenSession(options) {
15739
15853
  options.logger.debug(`本地调试凭证获取失败,详细原因:${index.readRedactedErrorMessage(error, { verbose: true })}`);
15740
15854
  schedule(options.timeoutMs);
15741
15855
  }
15856
+ finally {
15857
+ refreshing = false;
15858
+ }
15742
15859
  };
15743
15860
  const schedule = (delayMs) => {
15744
15861
  refreshTimer = setTimeout(() => {
@@ -15763,6 +15880,13 @@ function startLocalDevLaunchTokenSession(options) {
15763
15880
  const ready = refresh();
15764
15881
  return {
15765
15882
  getTicket,
15883
+ refresh: () => {
15884
+ permissionsRefreshAt = 0;
15885
+ publishedDigest = undefined;
15886
+ if (refreshTimer)
15887
+ clearTimeout(refreshTimer);
15888
+ void refresh();
15889
+ },
15766
15890
  ready,
15767
15891
  close: () => {
15768
15892
  closed = true;
@@ -15816,18 +15940,13 @@ function safeCompanionFailureReason(error) {
15816
15940
  if (/404|not found/i.test(message))
15817
15941
  return '调试接口尚未部署或当前登录环境不匹配';
15818
15942
  if (/403|forbidden|permission|授权|权限/i.test(message))
15819
- return 'Companion 授权未通过,请检查 COA 批准与开发者身份';
15943
+ return 'Companion 本地授权未通过,请检查开发者身份与调试凭证';
15820
15944
  if (/401|登录/i.test(message))
15821
15945
  return 'CLI 登录态已失效,请重新登录';
15822
15946
  if (/manifest|快照|ZIP|ENOENT/i.test(message))
15823
15947
  return '本地 Companion ZIP 或 Manifest 校验失败,请检查产物与配置';
15824
15948
  return 'PC Companion 暂不可用,请检查网络、登录环境和调试接口';
15825
15949
  }
15826
- function hasCompanionApproval(value) {
15827
- if (!value || typeof value !== 'object' || !('entries' in value) || !Array.isArray(value.entries))
15828
- return false;
15829
- return value.entries.some(entry => entry?.key === 'companion' && entry?.status === 'enabled');
15830
- }
15831
15950
  async function readCompanionManifest(manifestUrl, companionArtifactAccessToken, fetchImpl) {
15832
15951
  try {
15833
15952
  const response = await fetchImpl(manifestUrl, {
@@ -15919,7 +16038,9 @@ function createLanAddressCandidates(options) {
15919
16038
  id,
15920
16039
  name,
15921
16040
  };
15922
- const lanDevContextUrl = readLanDevContextUrl(options.devContextUrlsByMiniUrlOrigin?.get(new URL(appUrl).origin), address);
16041
+ const lanDevContextUrl = options.devContextPath
16042
+ ? new URL(options.devContextPath, appUrl).toString()
16043
+ : readLanDevContextUrl(options.devContextUrlsByMiniUrlOrigin?.get(new URL(appUrl).origin), address);
15923
16044
  // 真机 WebView 基址是 127.0.0.1 详情页,HTML 来自线上缓存;完整启动参数写进 sandbox query,
15924
16045
  // 作为 /l/<token> HTML 跳转页的目标;调试页二维码只编码这条短链。
15925
16046
  candidate.mobileAppQrPayload = createMobileAppQrPayload(appUrl, {
@@ -3,7 +3,7 @@
3
3
  var fs = require('node:fs/promises');
4
4
  var os = require('node:os');
5
5
  var path = require('node:path');
6
- var index = require('./index-Cscd6hCr.cjs');
6
+ var index = require('./index-Ol4wxcob.cjs');
7
7
  require('node:module');
8
8
  require('node:fs');
9
9
  require('path');
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-Cscd6hCr.cjs');
3
+ var index$2 = require('./index-Ol4wxcob.cjs');
4
4
  var require$$0$3 = require('fs');
5
5
  var require$$0$2 = require('crypto');
6
6
  var require$$1$2 = require('path');
7
7
  var require$$0$5 = require('assert');
8
8
  var require$$0$4 = require('events');
9
9
  var require$$1$1 = require('util');
10
- var runtimePermissionEnv = require('./runtime-permission-env-v9THnMre.cjs');
10
+ var runtimePermissionEnv = require('./runtime-permission-env-C0clU7_f.cjs');
11
11
  var require$$0$7 = require('net');
12
12
  var require$$0$6 = require('url');
13
13
  var require$$2$1 = require('http');