@heybox/hb-sdk 0.4.4 → 0.4.6

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.
@@ -1,10 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ var promises = require('node:readline/promises');
3
4
  var node_crypto = require('node:crypto');
4
5
  var node_http = require('node:http');
5
- var session = require('./session-DiyDXvXu.cjs');
6
+ var session = require('./session-D7lF9mpd.cjs');
6
7
  var browser = require('./browser-RAy8e8cV.cjs');
7
- var index = require('./index-Bboot1us.cjs');
8
+ var index = require('./index-DuwxUSkq.cjs');
8
9
  require('node:path');
9
10
  require('fs');
10
11
  require('constants');
@@ -134,6 +135,8 @@ function closeServer(server) {
134
135
  });
135
136
  }
136
137
 
138
+ const DEVELOPER_ENTITY_LIST_API_PATH = '/mall/developer/entity/list';
139
+ const DEVELOPER_ENTITY_SWITCH_API_PATH = '/mall/developer/entity/switch';
137
140
  async function loginToHeybox(options = {}) {
138
141
  const logger = options.logger ?? index.createCliLogger();
139
142
  const waitForBrowserCallback = options.waitForBrowserCallback ?? waitForHeyboxBrowserCallback;
@@ -162,6 +165,7 @@ async function loginToHeybox(options = {}) {
162
165
  const session$1 = session.createHeyboxAuthSession(payload, { ...options, loginBaseUrl });
163
166
  await session.writeHeyboxAuthSession(session$1, options);
164
167
  logger.success(`Heybox 登录成功:${session$1.heyboxId}`);
168
+ await selectDeveloperEntityAfterLogin(session$1, options, logger);
165
169
  logger.debug(`cache: ${session.getAuthCacheFilePath(options)}`);
166
170
  logger.info('验证命令: hb-sdk login status');
167
171
  }
@@ -179,6 +183,9 @@ async function printLoginStatus(options = {}) {
179
183
  logger.info(`heyboxId: ${status.heyboxId}`);
180
184
  logger.info(`loginBaseUrl: ${status.loginBaseUrl}`);
181
185
  logger.info(`loggedInAt: ${status.loggedInAt}`);
186
+ if (status.selectedEntity) {
187
+ logger.info(`selectedEntity: ${formatDeveloperEntity(status.selectedEntity)}`);
188
+ }
182
189
  logger.debug(`cache: ${status.cacheFile}`);
183
190
  }
184
191
  async function clearLoginStatus(options = {}) {
@@ -187,6 +194,150 @@ async function clearLoginStatus(options = {}) {
187
194
  logger.success('已清理 Heybox 登录态');
188
195
  logger.debug(`cache: ${session.getAuthCacheFilePath(options)}`);
189
196
  }
197
+ async function selectDeveloperEntityAfterLogin(session$1, options, logger) {
198
+ if (options.noSelectEntity) {
199
+ logger.info('已跳过开发者主体选择。后续可运行: hb-sdk remote entity switch <entity-id>');
200
+ return;
201
+ }
202
+ const entities = await logger.task('读取开发者主体列表', () => listDeveloperEntities(session$1, options), {
203
+ successText: '已读取开发者主体列表',
204
+ });
205
+ if (entities.length === 0) {
206
+ logger.warn('当前账号未绑定开发者平台主体。');
207
+ logger.info('请先在开发者平台完成主体绑定,再运行 remote 命令。');
208
+ return;
209
+ }
210
+ if (entities.length === 1) {
211
+ const [entity] = entities;
212
+ if (!entity.isCurrent) {
213
+ await switchDeveloperEntity(session$1, entity, options);
214
+ await session.setSelectedDeveloperEntitySnapshot(entity, options);
215
+ logger.success(`已切换开发者主体:${formatDeveloperEntity(entity)}`);
216
+ return;
217
+ }
218
+ await session.setSelectedDeveloperEntitySnapshot(entity, options);
219
+ logger.info(`当前开发者主体:${formatDeveloperEntity(entity)}`);
220
+ return;
221
+ }
222
+ printDeveloperEntityChoices(logger, entities);
223
+ const isTTY = options.isTTY ?? logger.isInteractive;
224
+ if (!isTTY) {
225
+ logger.warn('检测到多个开发者主体,非交互环境不会自动切换。');
226
+ logger.info('请运行: hb-sdk remote entity switch <entity-id>');
227
+ return;
228
+ }
229
+ const selected = options.promptSelectEntity
230
+ ? await options.promptSelectEntity(entities)
231
+ : await promptSelectDeveloperEntity(entities, options);
232
+ if (!selected) {
233
+ throw new Error('必须选择一个开发者主体;如需跳过,请显式传 --no-select-entity');
234
+ }
235
+ await switchDeveloperEntity(session$1, selected, options);
236
+ await session.setSelectedDeveloperEntitySnapshot(selected, options);
237
+ logger.success(`已切换开发者主体:${formatDeveloperEntity(selected)}`);
238
+ }
239
+ async function listDeveloperEntities(session, options) {
240
+ const result = await requestDeveloperEntityApi(DEVELOPER_ENTITY_LIST_API_PATH, 'GET', session, options);
241
+ const rawItems = readDeveloperEntityItems(result);
242
+ return rawItems.map(normalizeDeveloperEntity).filter((item) => Boolean(item));
243
+ }
244
+ async function switchDeveloperEntity(session, entity, options) {
245
+ await requestDeveloperEntityApi(DEVELOPER_ENTITY_SWITCH_API_PATH, 'POST', session, options, {
246
+ entity_id: entity.entityId,
247
+ });
248
+ }
249
+ async function requestDeveloperEntityApi(path, method, session$1, options, fields = {}) {
250
+ const apiBaseUrl = session.resolveHeyboxApiBaseUrl(options);
251
+ const context = session.createHeyboxOpenPlatformRequestContext(session$1, path, {
252
+ ...(method === 'POST' ? { contentType: 'application/x-www-form-urlencoded' } : {}),
253
+ });
254
+ const fetchImpl = options.fetchImpl ?? fetch;
255
+ const response = await fetchImpl(session.createHeyboxApiUrl(apiBaseUrl, path, context.platformParams), {
256
+ method,
257
+ headers: context.headers,
258
+ ...(method === 'POST' ? { body: new URLSearchParams(stringifyFormFields(fields)).toString() } : {}),
259
+ });
260
+ return session.readHeyboxApiEnvelope(response, { pathWithQuery: path, requireResult: method === 'GET' });
261
+ }
262
+ function stringifyFormFields(fields) {
263
+ return Object.fromEntries(Object.entries(fields).map(([key, value]) => [key, String(value)]));
264
+ }
265
+ function readDeveloperEntityItems(result) {
266
+ if (Array.isArray(result)) {
267
+ return result;
268
+ }
269
+ if (!isRecord(result)) {
270
+ return [];
271
+ }
272
+ if (Array.isArray(result.items)) {
273
+ return result.items;
274
+ }
275
+ if (Array.isArray(result.list)) {
276
+ return result.list;
277
+ }
278
+ return [];
279
+ }
280
+ function normalizeDeveloperEntity(value) {
281
+ if (!isRecord(value)) {
282
+ return undefined;
283
+ }
284
+ const entityId = readPositiveInteger(value.entity_id ?? value.entityId);
285
+ if (entityId === undefined) {
286
+ return undefined;
287
+ }
288
+ const ownerHeyboxId = readPositiveInteger(value.owner_heybox_id ?? value.ownerHeyboxId);
289
+ return {
290
+ entityId,
291
+ entityName: readNonEmptyString(value.entity_name ?? value.entityName) ?? `主体 ${entityId}`,
292
+ ...(ownerHeyboxId === undefined ? {} : { ownerHeyboxId }),
293
+ isCurrent: value.is_current === true || value.isCurrent === true,
294
+ };
295
+ }
296
+ function readPositiveInteger(value) {
297
+ const parsed = typeof value === 'number' ? value : typeof value === 'string' && /^\d+$/.test(value.trim()) ? Number(value.trim()) : NaN;
298
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
299
+ }
300
+ function readNonEmptyString(value) {
301
+ const normalized = typeof value === 'string' ? value.trim() : '';
302
+ return normalized || undefined;
303
+ }
304
+ function printDeveloperEntityChoices(logger, entities) {
305
+ logger.info('可用开发者主体:');
306
+ entities.forEach((entity, index) => {
307
+ logger.info(`${index + 1}. ${formatDeveloperEntity(entity)}${entity.isCurrent ? ' (current)' : ''}`);
308
+ });
309
+ }
310
+ async function promptSelectDeveloperEntity(entities, options) {
311
+ const input = options.stdin ?? process.stdin;
312
+ const output = options.stderr ?? process.stderr;
313
+ const rl = promises.createInterface({ input, output: output });
314
+ try {
315
+ for (;;) {
316
+ const answer = (await rl.question('请选择开发者主体序号或 entity_id: ')).trim();
317
+ const selected = findDeveloperEntityChoice(entities, answer);
318
+ if (selected) {
319
+ return selected;
320
+ }
321
+ output.write('输入无效,请重新选择。\n');
322
+ }
323
+ }
324
+ finally {
325
+ rl.close();
326
+ }
327
+ }
328
+ function findDeveloperEntityChoice(entities, answer) {
329
+ const index = readPositiveInteger(answer);
330
+ if (index !== undefined && index <= entities.length) {
331
+ return entities[index - 1];
332
+ }
333
+ return entities.find((entity) => String(entity.entityId) === answer);
334
+ }
335
+ function formatDeveloperEntity(entity) {
336
+ return `${entity.entityName} (ID: ${entity.entityId}${entity.ownerHeyboxId === undefined ? '' : `, owner: ${entity.ownerHeyboxId}`})`;
337
+ }
338
+ function isRecord(value) {
339
+ return Object.prototype.toString.call(value) === '[object Object]';
340
+ }
190
341
 
191
342
  exports.clearLoginStatus = clearLoginStatus;
192
343
  exports.loginToHeybox = loginToHeybox;