@heybox/hb-sdk 0.6.9 → 0.7.0-alpha.2

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 (62) hide show
  1. package/CHANGELOG.md +51 -7
  2. package/README.md +83 -20
  3. package/dist/cli-chunks/{build-BtGxhrcV.cjs → build-DLIhlBQA.cjs} +4 -4
  4. package/dist/cli-chunks/{context-DX1KG-8A.cjs → context-Bl_Q4RKq.cjs} +15 -2
  5. package/dist/cli-chunks/{create-DAD0OF1r.cjs → create-C--pwY0l.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-Dh4HY0I8.cjs → dev-B1tyT5ql.cjs} +197 -13
  7. package/dist/cli-chunks/{doctor-BfKdiD3H.cjs → doctor-D9M2scaJ.cjs} +1 -1
  8. package/dist/cli-chunks/{index-tCURDEx8.cjs → index-BnBeTd0B.cjs} +15 -14
  9. package/dist/cli-chunks/{index-DB6Q8HaC.cjs → index-HNB8i51C.cjs} +2 -2
  10. package/dist/cli-chunks/{login-D60EJLgs.cjs → login-DnX81kof.cjs} +2 -2
  11. package/dist/cli-chunks/{project-vite-DAUaP0_3.cjs → project-vite-CgnCpNDZ.cjs} +1 -1
  12. package/dist/cli-chunks/{remote-nQDniAUY.cjs → remote-CETqg77E.cjs} +6 -6
  13. package/dist/cli-chunks/{runtime-gate-BWlU-R4h.cjs → runtime-gate-CtV7rWyX.cjs} +1 -1
  14. package/dist/cli-chunks/{runtime-permission-env-DKrhgVM3.cjs → runtime-permission-env-D-8_jPG3.cjs} +2 -0
  15. package/dist/cli-chunks/{session-D6jOKXeu.cjs → session-Davw2CMd.cjs} +1 -1
  16. package/dist/cli.cjs +1 -1
  17. package/dist/devtools/mock-host/index.html +9 -2
  18. package/dist/devtools/mock-host/main.js +426 -802
  19. package/dist/index.cjs.js +46 -90
  20. package/dist/index.esm.js +46 -90
  21. package/dist/miniapp-publish.cjs.js +2 -0
  22. package/dist/miniapp-publish.esm.js +2 -1
  23. package/dist/protocol.cjs.js +98 -42
  24. package/dist/protocol.esm.js +93 -39
  25. package/dist/templates/vue3-vite-ts/README.md.ejs +1 -1
  26. package/dist/templates/vue3-vite-ts/src/App.vue +22 -17
  27. package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +37 -29
  28. package/dist/templates/vue3-vite-ts/src/auth-handoff.ts +46 -0
  29. package/dist/vite.cjs.js +2 -2
  30. package/dist/vite.esm.js +2 -2
  31. package/package.json +2 -2
  32. package/skill/SKILL.md +16 -12
  33. package/skill/references/api-protocol.md +22 -28
  34. package/skill/references/api-root.md +127 -112
  35. package/skill/references/cli.md +15 -20
  36. package/skill/references/examples.md +29 -17
  37. package/skill/references/recipes.md +180 -134
  38. package/skill/references/safety-boundaries.md +9 -3
  39. package/skill/scripts/sync-references.mjs +235 -139
  40. package/skill/scripts/validate-skill.mjs +18 -14
  41. package/skill/skill.json +4 -4
  42. package/types/index.d.ts +4 -4
  43. package/types/miniapp-publish/index.d.ts +1 -0
  44. package/types/modules/auth/index.d.ts +16 -28
  45. package/types/modules/cloud/index.d.ts +2 -2
  46. package/types/modules/network/index.d.ts +1 -2
  47. package/types/modules/user/get-info.d.ts +4 -4
  48. package/types/modules/user/get-local-identity.d.ts +9 -0
  49. package/types/modules/user/index.d.ts +13 -41
  50. package/types/modules/user/revoke-authorization.d.ts +7 -0
  51. package/types/modules/user/steam-game-list.d.ts +72 -0
  52. package/types/modules/user/types.d.ts +37 -302
  53. package/types/protocol/capabilities.d.ts +24 -49
  54. package/types/protocol/constants.d.ts +1 -1
  55. package/types/protocol/network-policy.d.ts +10 -0
  56. package/types/protocol/types.d.ts +10 -6
  57. package/types/protocol.d.ts +4 -3
  58. package/types/modules/user/get-current-user-detail.d.ts +0 -9
  59. package/types/modules/user/get-current-user-profile.d.ts +0 -9
  60. package/types/modules/user/get-platform-account-info.d.ts +0 -12
  61. package/types/modules/user/get-platform-account-overview.d.ts +0 -9
  62. package/types/modules/user/get-steam-game-list.d.ts +0 -12
@@ -3,6 +3,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import process from 'node:process';
6
+ import ts from 'typescript';
6
7
  import { createSkillContentHash, createSkillManifest, normalizeSkillManifest } from './skill-metadata.mjs';
7
8
 
8
9
  const scriptDir = path.dirname(fileURLToPath(import.meta.url));
@@ -13,7 +14,9 @@ const checkMode = process.argv.includes('--check');
13
14
  const TEXT_FILE_RE = /\.(?:md|mjs|js|cjs|ts|tsx|json|txt|sh|yaml|yml)$/i;
14
15
 
15
16
  if (!repoRoot) {
16
- console.error('Cannot sync hb-sdk references outside the heybox-webapp repository. Run this script from a checkout that contains packages/hb-sdk/package.json.');
17
+ console.error(
18
+ 'Cannot sync hb-sdk references outside the heybox-webapp repository. Run this script from a checkout that contains packages/hb-sdk/package.json.',
19
+ );
17
20
  process.exit(1);
18
21
  }
19
22
 
@@ -35,7 +38,7 @@ function read(relativePath) {
35
38
 
36
39
  function extractSection(markdown, heading) {
37
40
  const lines = markdown.split('\n');
38
- const start = lines.findIndex(line => line.trim() === heading);
41
+ const start = lines.findIndex((line) => line.trim() === heading);
39
42
  if (start === -1) return '';
40
43
  const level = heading.match(/^#+/)?.[0].length ?? 2;
41
44
  const out = [lines[start]];
@@ -67,7 +70,7 @@ function extractSection(markdown, heading) {
67
70
 
68
71
  function fenced(language, value) {
69
72
  const content = value.trimEnd();
70
- const longestFence = Math.max(2, ...Array.from(content.matchAll(/`{3,}/g), match => match[0].length));
73
+ const longestFence = Math.max(2, ...Array.from(content.matchAll(/`{3,}/g), (match) => match[0].length));
71
74
  const fence = '`'.repeat(longestFence + 1);
72
75
  return `${fence}${language}\n${content}\n${fence}`;
73
76
  }
@@ -80,7 +83,7 @@ function header(title, sources) {
80
83
  '',
81
84
  '## Sources',
82
85
  '',
83
- ...sources.map(source => `- ${source}`),
86
+ ...sources.map((source) => `- ${source}`),
84
87
  '',
85
88
  ].join('\n');
86
89
  }
@@ -99,10 +102,7 @@ function rewriteBundledRecipeLinks(markdown) {
99
102
  }
100
103
 
101
104
  function rewriteBundledCliLinks(markdown) {
102
- return markdown.replaceAll(
103
- '(./mini-program-publishing-rules)',
104
- '(https://docs.xiaoheihe.cn/hb_sdk/guide/mini-program-publishing-rules)',
105
- );
105
+ return markdown.replaceAll('(./mini-program-publishing-rules)', '(https://docs.xiaoheihe.cn/hb_sdk/guide/mini-program-publishing-rules)');
106
106
  }
107
107
 
108
108
  function rewriteBundledProtocolIndexLinks(markdown) {
@@ -114,14 +114,50 @@ function rewriteBundledProtocolIndexLinks(markdown) {
114
114
  .replaceAll('(../guide/)', '(recipes.md)');
115
115
  }
116
116
 
117
+ const INTERNAL_PROTOCOL_DIAGNOSTIC_EXPORTS = new Set([
118
+ 'RUNTIME_LOCATION_PROBE_METHOD',
119
+ 'RuntimeLocationProbePayload',
120
+ 'SDK_CSP_VIOLATION_METHOD',
121
+ 'SDK_LOCATION_REPORT_METHOD',
122
+ 'SDKCSPBlockedResourceType',
123
+ 'SDKCSPViolationPayload',
124
+ 'SDKLocationReportPayload',
125
+ 'SDKLocationReportTrigger',
126
+ ]);
127
+
128
+ function omitNamedExports(source, omittedNames) {
129
+ const sourceFile = ts.createSourceFile('protocol.ts', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
130
+ const lineStarts = sourceFile.getLineStarts();
131
+ const removals = [];
132
+
133
+ for (const statement of sourceFile.statements) {
134
+ if (!ts.isExportDeclaration(statement) || !statement.exportClause || !ts.isNamedExports(statement.exportClause)) {
135
+ continue;
136
+ }
137
+
138
+ for (const element of statement.exportClause.elements) {
139
+ if (!omittedNames.has(element.name.text)) continue;
140
+
141
+ const { line } = sourceFile.getLineAndCharacterOfPosition(element.getStart(sourceFile));
142
+ const start = lineStarts[line];
143
+ const end = lineStarts[line + 1] ?? source.length;
144
+ const lineText = source.slice(start, end).trim();
145
+ const elementText = element.getText(sourceFile);
146
+
147
+ if (lineText !== `${elementText},` && lineText !== elementText) {
148
+ throw new Error(`Internal protocol export must occupy its own line: ${element.name.text}`);
149
+ }
150
+ removals.push({ start, end });
151
+ }
152
+ }
153
+
154
+ return removals
155
+ .sort((left, right) => right.start - left.start)
156
+ .reduce((result, { start, end }) => `${result.slice(0, start)}${result.slice(end)}`, source);
157
+ }
158
+
117
159
  function contents(items) {
118
- return [
119
- '',
120
- '## Contents',
121
- '',
122
- ...items.map(([title, anchor]) => `- [${title}](#${anchor})`),
123
- '',
124
- ].join('\n');
160
+ return ['', '## Contents', '', ...items.map(([title, anchor]) => `- [${title}](#${anchor})`), ''].join('\n');
125
161
  }
126
162
 
127
163
  function toPosix(value) {
@@ -183,7 +219,7 @@ function createCurrentSkillManifest(generatedReferences) {
183
219
  ];
184
220
  const fileEntries = Array.from(new Set(distributableFiles))
185
221
  .sort((left, right) => left.localeCompare(right))
186
- .map(relativePath => ({
222
+ .map((relativePath) => ({
187
223
  path: relativePath,
188
224
  content: readGeneratedOrDiskSkillFile(relativePath, generatedReferences),
189
225
  }));
@@ -194,7 +230,6 @@ function createCurrentSkillManifest(generatedReferences) {
194
230
  });
195
231
  }
196
232
 
197
-
198
233
  const packageJson = JSON.parse(read('packages/hb-sdk/package.json'));
199
234
  const rootEntry = read('packages/hb-sdk/src/index.ts');
200
235
  const protocolEntry = read('packages/hb-sdk/src/protocol.ts');
@@ -212,6 +247,8 @@ const customInstance = frontmatterless(read('apps/docs/hb-sdk/recipes/custom-ins
212
247
  const referenceHome = frontmatterless(read('apps/docs/hb-sdk/reference/index.md'));
213
248
  const publicCapabilities = extractSection(readme, '## 能力概览');
214
249
  const capabilityBoundaries = extractSection(readme, '## 关键约束');
250
+ const leaderboardSection = extractSection(readme, '## 云端排行榜');
251
+ const publicProtocolEntry = omitNamedExports(protocolEntry, INTERNAL_PROTOCOL_DIAGNOSTIC_EXPORTS);
215
252
  const manifestSection = extractSection(cliGuide, '## 生产构建');
216
253
  const cliCreateSection = extractSection(cliGuide, '## 创建工坊小程序');
217
254
  const cliDevSection = extractSection(cliGuide, '## 推荐调试流程');
@@ -254,9 +291,12 @@ Removed: hb-sdk deploy`;
254
291
 
255
292
  const cliRemoteEntitySection = `Developer account selection lives under \`hb-sdk remote entity\`:
256
293
 
257
- ${fenced('bash', `hb-sdk remote entity list
294
+ ${fenced(
295
+ 'bash',
296
+ `hb-sdk remote entity list
258
297
  hb-sdk remote entity current
259
- hb-sdk remote entity switch <entity-id>`)}
298
+ hb-sdk remote entity switch <entity-id>`,
299
+ )}
260
300
 
261
301
  Remote management commands use the current developer account. Use \`current\` to confirm it and \`switch\` to change it before creating, binding, or publishing a mini-program.`;
262
302
 
@@ -264,22 +304,25 @@ const cliRemoteEntityDeploySection = `Before publishing, \`hb-sdk remote deploy\
264
304
 
265
305
  const files = new Map();
266
306
 
267
- files.set('api-root.md', `${header('Root API reference', [
268
- 'packages/hb-sdk/package.json',
269
- 'packages/hb-sdk/src/index.ts',
270
- 'packages/hb-sdk/src/vite/index.ts',
271
- 'packages/hb-sdk/README.md',
272
- 'apps/docs/hb-sdk/guide/quick-start.md',
273
- 'apps/docs/hb-sdk/guide/error-handling.md',
274
- 'apps/docs/hb-sdk/guide/lifecycle.md',
275
- 'apps/docs/hb-sdk/guide/cli.md',
276
- ])}${contents([
277
- ['Package metadata', 'package-metadata'],
278
- ['Public root entrypoint', 'public-root-entrypoint'],
279
- ['Vite plugin export', 'vite-plugin-export'],
280
- ['App-facing concepts', 'app-facing-concepts'],
281
- ['Public modules', 'public-modules'],
282
- ])}## Package metadata
307
+ files.set(
308
+ 'api-root.md',
309
+ `${header('Root API reference', [
310
+ 'packages/hb-sdk/package.json',
311
+ 'packages/hb-sdk/src/index.ts',
312
+ 'packages/hb-sdk/src/vite/index.ts',
313
+ 'packages/hb-sdk/README.md',
314
+ 'apps/docs/hb-sdk/guide/quick-start.md',
315
+ 'apps/docs/hb-sdk/guide/error-handling.md',
316
+ 'apps/docs/hb-sdk/guide/lifecycle.md',
317
+ 'apps/docs/hb-sdk/guide/cli.md',
318
+ ])}${contents([
319
+ ['Package metadata', 'package-metadata'],
320
+ ['Public root entrypoint', 'public-root-entrypoint'],
321
+ ['Vite plugin export', 'vite-plugin-export'],
322
+ ['App-facing concepts', 'app-facing-concepts'],
323
+ ['Public modules', 'public-modules'],
324
+ ['Cloud leaderboard', 'cloud-leaderboard'],
325
+ ])}## Package metadata
283
326
 
284
327
  - Package: \`${packageJson.name}\`
285
328
  - Version at generation time: \`${packageJson.version}\`
@@ -310,53 +353,58 @@ ${rewriteBundledRecipeLinks(errorGuide)}
310
353
  ${publicCapabilities}
311
354
 
312
355
  ${rewriteBundledRecipeLinks(lifecycleGuide)}
313
- `);
314
356
 
315
- files.set('api-protocol.md', `${header('Protocol API reference', [
316
- 'packages/hb-sdk/src/protocol.ts',
317
- 'apps/docs/hb-sdk/reference/index.md',
318
- ])}${contents([
319
- ['Host/runtime-only warning', 'hostruntime-only-warning'],
320
- ['Public protocol entrypoint', 'public-protocol-entrypoint'],
321
- ['Generated reference index', 'generated-reference-index'],
322
- ])}## Host/runtime-only warning
357
+ ${leaderboardSection}
358
+ `,
359
+ );
360
+
361
+ files.set(
362
+ 'api-protocol.md',
363
+ `${header('Protocol API reference', ['packages/hb-sdk/src/protocol.ts', 'apps/docs/hb-sdk/reference/index.md'])}${contents([
364
+ ['Host/runtime-only warning', 'hostruntime-only-warning'],
365
+ ['Public protocol entrypoint', 'public-protocol-entrypoint'],
366
+ ['Generated reference index', 'generated-reference-index'],
367
+ ])}## Host/runtime-only warning
323
368
 
324
369
  Use \`@heybox/hb-sdk/protocol\` only for parent-container runtime, bridge-server, protocol-contract, or \`@heybox/hb-sdk-runtime\` integration tasks. Iframe mini-program business code must use root SDK APIs and must not construct bridge envelopes, nonce handling, or raw \`postMessage\` flows.
325
370
 
326
371
  ## Public protocol entrypoint
327
372
 
328
- ${fenced('ts', protocolEntry)}
373
+ ${fenced('ts', publicProtocolEntry)}
329
374
 
330
375
  ## Generated reference index
331
376
 
332
377
  ${rewriteBundledProtocolIndexLinks(referenceHome)}
333
- `);
334
-
335
- files.set('cli.md', `${header('CLI reference', [
336
- 'packages/hb-sdk/package.json',
337
- 'packages/hb-sdk/src/cli/index.ts',
338
- 'packages/hb-sdk/src/cli/commands/create.ts',
339
- 'packages/hb-sdk/src/cli/commands/dev.ts',
340
- 'packages/hb-sdk/src/cli/commands/build.ts',
341
- 'packages/hb-sdk/src/cli/commands/login.ts',
342
- 'apps/docs/hb-sdk/guide/cli.md',
343
- ])}${contents([
344
- ['When to use the CLI', 'when-to-use-the-cli'],
345
- ['Command surface', 'command-surface'],
346
- ['Create a mini-program template', 'create-a-mini-program-template'],
347
- ['Local debugging', 'local-debugging'],
348
- ['Production build', 'production-build'],
349
- ['Deploy and publish', 'deploy-and-publish'],
350
- ['Developer account scope', 'developer-account-scope'],
351
- ['Remote management commands', 'remote-management-commands'],
352
- ['CLI login', 'cli-login'],
353
- ['Agent Skill doctor', 'agent-skill-doctor'],
354
- ['Update reminders', 'update-reminders'],
355
- ])}## When to use the CLI
378
+ `,
379
+ );
380
+
381
+ files.set(
382
+ 'cli.md',
383
+ `${header('CLI reference', [
384
+ 'packages/hb-sdk/package.json',
385
+ 'packages/hb-sdk/src/cli/index.ts',
386
+ 'packages/hb-sdk/src/cli/commands/create.ts',
387
+ 'packages/hb-sdk/src/cli/commands/dev.ts',
388
+ 'packages/hb-sdk/src/cli/commands/build.ts',
389
+ 'packages/hb-sdk/src/cli/commands/login.ts',
390
+ 'apps/docs/hb-sdk/guide/cli.md',
391
+ ])}${contents([
392
+ ['When to use the CLI', 'when-to-use-the-cli'],
393
+ ['Command surface', 'command-surface'],
394
+ ['Create a mini-program template', 'create-a-mini-program-template'],
395
+ ['Local debugging', 'local-debugging'],
396
+ ['Production build', 'production-build'],
397
+ ['Deploy and publish', 'deploy-and-publish'],
398
+ ['Developer account scope', 'developer-account-scope'],
399
+ ['Remote management commands', 'remote-management-commands'],
400
+ ['CLI login', 'cli-login'],
401
+ ['Agent Skill doctor', 'agent-skill-doctor'],
402
+ ['Update reminders', 'update-reminders'],
403
+ ])}## When to use the CLI
356
404
 
357
405
  Use the bundled \`hb-sdk\` CLI to create a workshop mini-program, open the local debugging page, test in the Heybox Mac or mobile App, or manage and publish a remote mini-program.
358
406
 
359
- \`hb-sdk login\` is for development and publishing commands only. It does not change \`auth.login()\`, \`user.getInfo()\`, or \`network.request()\` inside a mini-program.
407
+ \`hb-sdk login\` is for development and publishing commands only. It does not authorize mini-program users and does not change \`auth.login()\`, \`user.getLocalIdentity()\`, or \`network.request()\` inside a mini-program.
360
408
 
361
409
  ## Command surface
362
410
 
@@ -460,25 +508,28 @@ Agent rules:
460
508
 
461
509
  ${cliUpdateSection}
462
510
 
463
- `);
464
-
465
- files.set('recipes.md', `${header('Recipes', [
466
- 'apps/docs/hb-sdk/guide/quick-start.md',
467
- 'apps/docs/hb-sdk/guide/auth.md',
468
- 'apps/docs/hb-sdk/guide/lifecycle.md',
469
- 'apps/docs/hb-sdk/guide/error-handling.md',
470
- 'apps/docs/hb-sdk/recipes/login-gate.md',
471
- 'apps/docs/hb-sdk/recipes/community-share.md',
472
- 'apps/docs/hb-sdk/recipes/custom-instance.md',
473
- ])}${contents([
474
- ['Quick start', 'quick-start'],
475
- ['User and login', 'user-and-login'],
476
- ['Lifecycle events', 'lifecycle-events'],
477
- ['Error handling', 'error-handling'],
478
- ['Login gate recipe', 'login-gate-recipe'],
479
- ['Community share recipe', 'community-share-recipe'],
480
- ['Custom instance recipe', 'custom-instance-recipe'],
481
- ])}## Quick start
511
+ `,
512
+ );
513
+
514
+ files.set(
515
+ 'recipes.md',
516
+ `${header('Recipes', [
517
+ 'apps/docs/hb-sdk/guide/quick-start.md',
518
+ 'apps/docs/hb-sdk/guide/auth.md',
519
+ 'apps/docs/hb-sdk/guide/lifecycle.md',
520
+ 'apps/docs/hb-sdk/guide/error-handling.md',
521
+ 'apps/docs/hb-sdk/recipes/login-gate.md',
522
+ 'apps/docs/hb-sdk/recipes/community-share.md',
523
+ 'apps/docs/hb-sdk/recipes/custom-instance.md',
524
+ ])}${contents([
525
+ ['Quick start', 'quick-start'],
526
+ ['User and login', 'user-and-login'],
527
+ ['Lifecycle events', 'lifecycle-events'],
528
+ ['Error handling', 'error-handling'],
529
+ ['Login gate recipe', 'login-gate-recipe'],
530
+ ['Community share recipe', 'community-share-recipe'],
531
+ ['Custom instance recipe', 'custom-instance-recipe'],
532
+ ])}## Quick start
482
533
 
483
534
  ${rewriteBundledRecipeLinks(quickStart)}
484
535
 
@@ -505,12 +556,12 @@ ${rewriteBundledRecipeLinks(communityShare)}
505
556
  ## Custom instance recipe
506
557
 
507
558
  ${rewriteBundledRecipeLinks(customInstance)}
508
- `);
559
+ `,
560
+ );
509
561
 
510
- files.set('safety-boundaries.md', `${header('Safety boundaries', [
511
- 'packages/hb-sdk/README.md',
512
- 'apps/docs/hb-sdk/guide/auth.md',
513
- ])}## Required boundaries
562
+ files.set(
563
+ 'safety-boundaries.md',
564
+ `${header('Safety boundaries', ['packages/hb-sdk/README.md', 'apps/docs/hb-sdk/guide/auth.md'])}## Required boundaries
514
565
 
515
566
  ${capabilityBoundaries}
516
567
 
@@ -519,19 +570,22 @@ ${capabilityBoundaries}
519
570
  - Do not instruct mini-program code to read, extract, forward, store, or depend on token, cookie, phone number, or private credentials.
520
571
  - Negative safety statements that explain the SDK does not expose token/cookie/private credentials are correct and should be preserved.
521
572
  - Do not use raw share protocol fields, JS callbacks, activity reporting, direct post publishing, custom buttons, or upload-only flows. Public \`share.*({ post })\` options only preset an editable client post flow.
522
- - Do not use storage delete, clear, info listing, V2, or global Heybox client storage access.
573
+ - Do not use storage delete, clear, info listing, or global Heybox client storage access.
523
574
  - Do not pass host-only protocol fields through \`network.request\`.
524
575
  - Do not build raw \`postMessage\` bridge flows in iframe business code.
525
576
  - Do not fetch deployed \`dist/manifest.json\` from business code; it is a build artifact for the release pipeline, not a CDN runtime asset.
526
577
  - Do not import from internal hb-sdk implementation paths; only use documented package entrypoints.
527
- `);
528
-
529
- files.set('llms-index.md', `${header('LLM documentation index', [
530
- 'apps/docs/hb-sdk/guide/**',
531
- 'apps/docs/hb-sdk/recipes/**',
532
- 'apps/docs/hb-sdk/reference/**',
533
- 'packages/hb-sdk/src/**',
534
- ])}## Offline references
578
+ `,
579
+ );
580
+
581
+ files.set(
582
+ 'llms-index.md',
583
+ `${header('LLM documentation index', [
584
+ 'apps/docs/hb-sdk/guide/**',
585
+ 'apps/docs/hb-sdk/recipes/**',
586
+ 'apps/docs/hb-sdk/reference/**',
587
+ 'packages/hb-sdk/src/**',
588
+ ])}## Offline references
535
589
 
536
590
  The bundled references are generated directly from hand-maintained docs, generated API owner sources, and SDK/CLI sources. They do not depend on the docs site's \`.vitepress/public/llms\` mirrors.
537
591
 
@@ -545,49 +599,72 @@ The bundled references are generated directly from hand-maintained docs, generat
545
599
  ## Online supplement
546
600
 
547
601
  Online \`llms.txt\` and markdown mirrors are optional supplements, not prerequisites for offline Skill use. Their canonical public URL is not frozen: on 2026-07-10 \`https://docs.xiaoheihe.cn/hb_sdk/llms.txt\` returned 404 and the legacy URL fetch timed out. Do not claim either endpoint is available without a fresh successful response.
548
- `);
602
+ `,
603
+ );
549
604
 
550
- files.set('examples.md', `${header('Smoke examples and anti-examples', [
551
- 'packages/hb-sdk/README.md',
552
- 'apps/docs/hb-sdk/guide/**',
553
- 'apps/docs/hb-sdk/recipes/**',
554
- ])}## Positive examples
605
+ files.set(
606
+ 'examples.md',
607
+ `${header('Smoke examples and anti-examples', [
608
+ 'packages/hb-sdk/README.md',
609
+ 'apps/docs/hb-sdk/guide/**',
610
+ 'apps/docs/hb-sdk/recipes/**',
611
+ ])}## Positive examples
555
612
 
556
- ### Minimal user info
613
+ ### Local identity for a network-disabled mini-program
557
614
 
558
- ${fenced('ts', `import { ready, user } from '@heybox/hb-sdk';
615
+ ${fenced(
616
+ 'ts',
617
+ `import { ready, user, HbMiniProgramSDKError } from '@heybox/hb-sdk';
559
618
 
560
- await ready();
619
+ export async function getLocalIdentityFromUserAction() {
620
+ await ready();
561
621
 
562
- const result = await user.getInfo();
563
- if (result.isLogin && result.userInfo) {
564
- console.log(result.userInfo.nickname);
565
- }`)}
622
+ try {
623
+ return await user.getLocalIdentity();
624
+ } catch (error) {
625
+ if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
626
+ return undefined;
627
+ }
628
+ throw error;
629
+ }
630
+ }`,
631
+ )}
566
632
 
567
- ### Login gate
633
+ ### Developer server session for a network-enabled mini-program
568
634
 
569
- ${fenced('ts', `import { auth, ready, user, HbMiniProgramSDKError } from '@heybox/hb-sdk';
635
+ ${fenced(
636
+ 'ts',
637
+ `import { auth, network, ready, HbMiniProgramSDKError } from '@heybox/hb-sdk';
570
638
 
571
- export async function ensureLogin() {
639
+ export async function createServerSessionFromUserAction() {
572
640
  await ready();
573
641
 
574
- const current = await user.getInfo();
575
- if (current.isLogin && current.userInfo) return current.userInfo;
576
-
577
642
  try {
578
- const loginResult = await auth.login();
579
- return loginResult.userInfo;
643
+ const result = await auth.login({ scopes: ['profile'] });
644
+ await exchangeCodeWithDeveloperServer(result.code);
645
+ return { status: 'ready' as const };
580
646
  } catch (error) {
581
- if (error instanceof HbMiniProgramSDKError) {
582
- console.warn(error.code, error.message);
647
+ if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
648
+ return { status: 'cancelled' as const };
583
649
  }
584
- return null;
650
+ throw error;
585
651
  }
586
- }`)}
652
+ }
653
+
654
+ async function exchangeCodeWithDeveloperServer(code: string) {
655
+ await network.request({
656
+ url: 'https://api.example.com/session/heybox',
657
+ method: 'POST',
658
+ data: { code },
659
+ });
660
+ }`,
661
+ )}
587
662
 
588
663
  ### Network request
589
664
 
590
- ${fenced('ts', `import { ready, network, HbMiniProgramNetworkError, HbMiniProgramSDKError } from '@heybox/hb-sdk';
665
+ ${fenced(
666
+ 'ts',
667
+ `import { ready, network, HbMiniProgramNetworkError, HbMiniProgramSDKError } from '@heybox/hb-sdk';
591
668
 
592
669
  try {
593
670
  await ready();
@@ -616,42 +693,55 @@ try {
616
693
  // e.g. INVALID_PARAMS for unsupported multipart shape
617
694
  console.warn(error.code, error.message);
618
695
  }
619
- }`)}
696
+ }`,
697
+ )}
620
698
 
621
699
  ### Host/runtime protocol import
622
700
 
623
- ${fenced('ts', `import { NETWORK_REQUEST_METHOD, type NetworkRequestPayload } from '@heybox/hb-sdk/protocol';
701
+ ${fenced(
702
+ 'ts',
703
+ `import { NETWORK_REQUEST_METHOD, type NetworkRequestPayload } from '@heybox/hb-sdk/protocol';
624
704
 
625
705
  // Host/runtime integration only. Do not use this in iframe business code.
626
706
  export function canHandleNetwork(method: string): method is typeof NETWORK_REQUEST_METHOD {
627
707
  return method === NETWORK_REQUEST_METHOD;
628
- }`)}
708
+ }`,
709
+ )}
629
710
 
630
711
  ### CLI local mock development
631
712
 
632
- ${fenced('bash', `hb-sdk create my-miniapp
713
+ ${fenced(
714
+ 'bash',
715
+ `hb-sdk create my-miniapp
633
716
  cd my-miniapp
634
717
  npm install
635
718
  npm run dev
636
719
 
637
720
  # In an existing project:
638
- hb-sdk dev`)}
721
+ hb-sdk dev`,
722
+ )}
639
723
 
640
724
  ### CLI login cache
641
725
 
642
- ${fenced('bash', `hb-sdk login
726
+ ${fenced(
727
+ 'bash',
728
+ `hb-sdk login
643
729
  hb-sdk login status
644
- hb-sdk login clear`)}
730
+ hb-sdk login clear`,
731
+ )}
645
732
 
646
733
  ### Vite manifest plugin
647
734
 
648
- ${fenced('ts', `import { miniappManifest } from '@heybox/hb-sdk/vite';
735
+ ${fenced(
736
+ 'ts',
737
+ `import { miniappManifest } from '@heybox/hb-sdk/vite';
649
738
  import { defineConfig } from 'vite';
650
739
 
651
740
  export default defineConfig({
652
741
  base: './',
653
742
  plugins: [miniappManifest()],
654
- });`)}
743
+ });`,
744
+ )}
655
745
 
656
746
  ## Negative examples
657
747
 
@@ -664,7 +754,8 @@ export default defineConfig({
664
754
  - Do not treat \`hb-sdk login\` as iframe SDK authentication state.
665
755
  - Do not create a second mock runtime package when \`hb-sdk dev\` is the supported local mock workflow.
666
756
  - Do not import \`@heybox/hb-sdk/vite\` from iframe business code or fetch a deployed \`manifest.json\` directly.
667
- `);
757
+ `,
758
+ );
668
759
 
669
760
  const skillManifest = normalizeSkillManifest(createCurrentSkillManifest(files));
670
761
 
@@ -691,7 +782,12 @@ if (currentSkillManifest !== skillManifest) {
691
782
  }
692
783
 
693
784
  if (checkMode && changed) {
694
- console.error(`hb-sdk skill references are out of date. Run \`node ${path.relative(repoRoot, fileURLToPath(import.meta.url)).split(path.sep).join('/')}\`.`);
785
+ console.error(
786
+ `hb-sdk skill references are out of date. Run \`node ${path
787
+ .relative(repoRoot, fileURLToPath(import.meta.url))
788
+ .split(path.sep)
789
+ .join('/')}\`.`,
790
+ );
695
791
  process.exit(1);
696
792
  }
697
793
 
@@ -3,11 +3,7 @@ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import process from 'node:process';
6
- import {
7
- HB_SDK_PACKAGE_NAME,
8
- HB_SDK_SKILL_NAME,
9
- validateSkillManifest,
10
- } from './skill-metadata.mjs';
6
+ import { HB_SDK_PACKAGE_NAME, HB_SDK_SKILL_NAME, validateSkillManifest } from './skill-metadata.mjs';
11
7
 
12
8
  const scriptDir = path.dirname(fileURLToPath(import.meta.url));
13
9
  const skillRoot = path.resolve(scriptDir, '..');
@@ -156,17 +152,18 @@ if (existsSync(skillMdPath)) {
156
152
  }
157
153
 
158
154
  const nestedReferenceFiles = existsSync(path.join(skillRoot, 'references'))
159
- ? walk(path.join(skillRoot, 'references')).filter(file => path.dirname(path.relative(path.join(skillRoot, 'references'), file)).includes(path.sep))
155
+ ? walk(path.join(skillRoot, 'references')).filter((file) =>
156
+ path.dirname(path.relative(path.join(skillRoot, 'references'), file)).includes(path.sep),
157
+ )
160
158
  : [];
161
159
  for (const file of nestedReferenceFiles) fail(`References must be one level deep: ${skillRel(file)}`);
162
160
 
163
- if (existsSync(path.join(skillRoot, 'README.md'))) fail('Do not create README.md inside hb-sdk skill; keep human distribution docs outside the skill folder.');
161
+ if (existsSync(path.join(skillRoot, 'README.md')))
162
+ fail('Do not create README.md inside hb-sdk skill; keep human distribution docs outside the skill folder.');
164
163
  if (existsSync(path.join(skillRoot, 'CHANGELOG.md'))) fail('Do not create CHANGELOG.md inside hb-sdk skill.');
165
164
  if (existsSync(path.join(skillRoot, 'INSTALLATION_GUIDE.md'))) fail('Do not create INSTALLATION_GUIDE.md inside hb-sdk skill.');
166
165
 
167
- const textFiles = existsSync(skillRoot)
168
- ? walk(skillRoot).filter(file => /\.(md|yaml|yml|json|txt)$/.test(file))
169
- : [];
166
+ const textFiles = existsSync(skillRoot) ? walk(skillRoot).filter((file) => /\.(md|yaml|yml|json|txt)$/.test(file)) : [];
170
167
 
171
168
  const negativeMarkers = [
172
169
  'do not',
@@ -189,7 +186,8 @@ const negativeMarkers = [
189
186
  '无',
190
187
  '禁止',
191
188
  ];
192
- const positiveCredentialPattern = /\b(read|extract|forward|store|persist|depend on|use|request|expose|get|parse|send)\b.*\b(token|cookie|credentials?|phone number|login state)\b/i;
189
+ const positiveCredentialPattern =
190
+ /\b(read|extract|forward|store|persist|depend on|use|request|expose|get|parse|send)\b.*\b(token|cookie|credentials?|phone number|login state)\b/i;
193
191
  const unsupportedStoragePattern = /\b(removeStorage|clearStorage|getStorageInfo|getStorageV2|delete storage|clear storage)\b/i;
194
192
  const rawProtocolPattern = /\b(raw postMessage|construct bridge|bridge envelope|nonce handling|mutate bridge|sdk\.handshake)\b/i;
195
193
  const removedUserLoginPattern = /\b(?:hbSDK\.)?user\.login\s*\(/;
@@ -199,10 +197,16 @@ for (const file of textFiles) {
199
197
  const content = read(file);
200
198
  if (file.endsWith('.md')) validateLocalMarkdownLinks(file, content);
201
199
  if (removedUserLoginPattern.test(content)) {
202
- fail(`Removed API guidance found in ${relative}: use auth.login() instead of user.login().`);
200
+ fail(
201
+ `Removed API guidance found in ${relative}: use auth.login() for network-enabled server authentication or user.getLocalIdentity() for network-disabled local identity instead of user.login().`,
202
+ );
203
203
  }
204
204
 
205
- if (new RegExp(`${HB_SDK_PACKAGE_NAME.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\/(?!(?:protocol|vite|miniapp-publish)\\b)[A-Za-z0-9_./-]+`).test(content)) {
205
+ if (
206
+ new RegExp(`${HB_SDK_PACKAGE_NAME.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\/(?!(?:protocol|vite|miniapp-publish)\\b)[A-Za-z0-9_./-]+`).test(
207
+ content,
208
+ )
209
+ ) {
206
210
  fail(
207
211
  `Deep/internal hb-sdk import guidance found in ${relative}. Only @heybox/hb-sdk, @heybox/hb-sdk/protocol, @heybox/hb-sdk/vite, and @heybox/hb-sdk/miniapp-publish are allowed.`,
208
212
  );
@@ -211,7 +215,7 @@ for (const file of textFiles) {
211
215
  const lines = content.split('\n');
212
216
  lines.forEach((line, index) => {
213
217
  const lower = line.toLowerCase();
214
- const isNegative = negativeMarkers.some(marker => lower.includes(marker));
218
+ const isNegative = negativeMarkers.some((marker) => lower.includes(marker));
215
219
  if (positiveCredentialPattern.test(line) && !isNegative) {
216
220
  fail(`Unsafe positive credential guidance in ${relative}:${index + 1}: ${line.trim()}`);
217
221
  }