@heybox/hb-sdk 0.2.0-alpha.0 → 0.2.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 (47) hide show
  1. package/README.md +193 -452
  2. package/bin/hb-sdk.cjs +1 -1
  3. package/dist/cli.cjs +71660 -3903
  4. package/dist/devtools/mock-host/index.html +13 -387
  5. package/dist/devtools/mock-host/main.js +975 -0
  6. package/dist/index.cjs.js +50 -63
  7. package/dist/index.esm.js +51 -50
  8. package/dist/miniapp-publish.cjs.js +77 -0
  9. package/dist/miniapp-publish.esm.js +66 -0
  10. package/dist/protocol.cjs.js +72 -13
  11. package/dist/protocol.esm.js +72 -14
  12. package/dist/templates/vue3-vite-ts/README.md.ejs +1 -5
  13. package/dist/templates/vue3-vite-ts/package.json.ejs +0 -1
  14. package/dist/templates/vue3-vite-ts/vite.config.ts +2 -1
  15. package/dist/vite.cjs.js +62 -0
  16. package/dist/vite.esm.js +60 -0
  17. package/package.json +30 -1
  18. package/skill/SKILL.md +106 -0
  19. package/skill/references/api-protocol.md +135 -0
  20. package/skill/references/api-root.md +474 -0
  21. package/skill/references/cli.md +376 -0
  22. package/skill/references/examples.md +119 -0
  23. package/skill/references/llms-index.md +44 -0
  24. package/skill/references/recipes.md +374 -0
  25. package/skill/references/safety-boundaries.md +30 -0
  26. package/skill/references/smoke-evaluation.md +24 -0
  27. package/skill/scripts/check-references.mjs +14 -0
  28. package/skill/scripts/package-skill.mjs +60 -0
  29. package/skill/scripts/package-skill.sh +6 -0
  30. package/skill/scripts/skill-metadata.mjs +74 -0
  31. package/skill/scripts/sync-references.mjs +565 -0
  32. package/skill/scripts/validate-skill.mjs +235 -0
  33. package/skill/skill.json +11 -0
  34. package/types/index.d.ts +8 -6
  35. package/types/miniapp-publish/index.d.ts +23 -0
  36. package/types/modules/auth/index.d.ts +2 -9
  37. package/types/modules/network/index.d.ts +6 -11
  38. package/types/modules/share/index.d.ts +3 -9
  39. package/types/modules/share/screenshot.d.ts +1 -7
  40. package/types/modules/share/show-share-menu.d.ts +1 -7
  41. package/types/modules/storage/index.d.ts +2 -16
  42. package/types/modules/user/get-info.d.ts +1 -7
  43. package/types/modules/user/index.d.ts +2 -8
  44. package/types/modules/viewport/index.d.ts +2 -9
  45. package/types/protocol/capabilities.d.ts +180 -0
  46. package/types/protocol.d.ts +8 -13
  47. package/types/vite/index.d.ts +17 -0
@@ -35,7 +35,7 @@
35
35
  gap: 16px;
36
36
  padding: 18px;
37
37
  border-right: 1px solid #d7dee8;
38
- background: #ffffff;
38
+ background: #fff;
39
39
  }
40
40
 
41
41
  .panel h1 {
@@ -72,20 +72,12 @@
72
72
  font-size: 12px;
73
73
  }
74
74
 
75
- .status strong {
76
- display: block;
77
- margin-top: 6px;
78
- overflow-wrap: anywhere;
79
- font-size: 16px;
80
- }
81
-
75
+ .status strong,
82
76
  .block strong {
83
77
  display: block;
84
78
  margin-top: 6px;
85
79
  overflow-wrap: anywhere;
86
80
  word-break: break-word;
87
- font-size: 13px;
88
- line-height: 1.45;
89
81
  }
90
82
 
91
83
  .actions {
@@ -143,7 +135,8 @@
143
135
  font-size: 13px;
144
136
  }
145
137
 
146
- .log pre {
138
+ .log pre,
139
+ .block pre {
147
140
  margin: 8px 0 0;
148
141
  overflow: auto;
149
142
  color: #475569;
@@ -217,6 +210,14 @@
217
210
  <strong id="mini-url"></strong>
218
211
  </section>
219
212
 
213
+ <section class="block">
214
+ <span>Mac App</span>
215
+ <div class="actions" style="margin-top: 10px">
216
+ <button class="primary" id="mac-app-button" type="button">在 Mac 版 APP 中启动</button>
217
+ </div>
218
+ <pre id="mac-app-status"></pre>
219
+ </section>
220
+
220
221
  <section class="block">
221
222
  <label class="field">
222
223
  <span>Nickname</span>
@@ -246,381 +247,6 @@
246
247
  </main>
247
248
  </div>
248
249
 
249
- <script>
250
- const NAMESPACE = 'heybox:miniprogram';
251
- const VERSION = 1;
252
- const NONCE_PARAM = 'hb_mini_bridge_nonce';
253
- const NETWORK_PROXY_PATH = '/__hb_sdk_mock_network__';
254
- const params = new URL(location.href).searchParams;
255
- const miniUrl = params.get('mini_url');
256
- const nonce = createNonce();
257
- const storage = new Map();
258
- const logs = [];
259
- let handshaken = false;
260
- let currentUser = {
261
- heybox_id: 'debug_user',
262
- nickname: 'PC Debug User',
263
- avatar: '',
264
- };
265
-
266
- const elements = {
267
- bridgeStatus: document.querySelector('#bridge-status'),
268
- device: document.querySelector('#device'),
269
- logs: document.querySelector('#logs'),
270
- miniUrl: document.querySelector('#mini-url'),
271
- nicknameInput: document.querySelector('#nickname-input'),
272
- storageSnapshot: document.querySelector('#storage-snapshot'),
273
- userStatus: document.querySelector('#user-status'),
274
- };
275
-
276
- if (!miniUrl) {
277
- elements.device.innerHTML = '<div class="error">Missing mini_url query.</div>';
278
- throw new Error('Missing mini_url query.');
279
- }
280
-
281
- const iframe = document.createElement('iframe');
282
- iframe.src = appendNonce(miniUrl, nonce);
283
- iframe.allow = 'clipboard-read; clipboard-write';
284
- elements.device.appendChild(iframe);
285
- elements.miniUrl.textContent = miniUrl;
286
- updateUserStatus();
287
- updateStorageSnapshot();
288
-
289
- window.addEventListener('message', handleMessage);
290
- window.addEventListener('beforeunload', () => {
291
- postEvent('unload', { timestamp: Date.now() });
292
- });
293
- document.querySelector('#login-button').addEventListener('click', () => {
294
- currentUser = {
295
- heybox_id: 'debug_user',
296
- nickname: elements.nicknameInput.value.trim() || 'PC Debug User',
297
- avatar: '',
298
- };
299
- updateUserStatus();
300
- postEvent('authChange', getUserInfoResult());
301
- });
302
- document.querySelector('#logout-button').addEventListener('click', () => {
303
- currentUser = null;
304
- updateUserStatus();
305
- postEvent('authChange', getUserInfoResult());
306
- });
307
- document.querySelector('#show-button').addEventListener('click', () => {
308
- postEvent('show', { timestamp: Date.now(), source: 'mock-host' });
309
- });
310
- document.querySelector('#hide-button').addEventListener('click', () => {
311
- postEvent('hide', { timestamp: Date.now(), source: 'mock-host' });
312
- });
313
-
314
- function handleMessage(event) {
315
- if (event.source !== iframe.contentWindow || !isBridgeMessage(event.data)) {
316
- return;
317
- }
318
-
319
- const message = event.data;
320
- if (message.type === 'handshake') {
321
- handleHandshake();
322
- return;
323
- }
324
-
325
- if (message.type === 'request') {
326
- void handleRequest(message);
327
- }
328
- }
329
-
330
- function handleHandshake() {
331
- const firstHandshake = !handshaken;
332
- handshaken = true;
333
- elements.bridgeStatus.textContent = 'ready';
334
-
335
- if (firstHandshake) {
336
- postEvent('launch', {
337
- timestamp: Date.now(),
338
- url: iframe.src,
339
- });
340
- }
341
-
342
- postEvent('ready', {
343
- timestamp: Date.now(),
344
- });
345
- pushLog('sdk.handshake', { firstHandshake });
346
- }
347
-
348
- async function handleRequest(message) {
349
- if (!message.id || !message.method) {
350
- return;
351
- }
352
-
353
- try {
354
- const payload = await runMethod(message.method, message.payload);
355
- postResponse(message, payload);
356
- pushLog(message.method, { payload: message.payload, result: payload });
357
- } catch (error) {
358
- const bridgeError = toBridgeError(error);
359
- postResponse(message, undefined, bridgeError);
360
- postEvent('error', bridgeError);
361
- pushLog(message.method, { payload: message.payload, error: bridgeError });
362
- }
363
- }
364
-
365
- async function runMethod(method, payload) {
366
- if (method === 'auth.login') {
367
- currentUser = {
368
- heybox_id: 'debug_user',
369
- nickname: elements.nicknameInput.value.trim() || 'PC Debug User',
370
- avatar: '',
371
- };
372
- updateUserStatus();
373
- const result = getUserInfoResult();
374
- postEvent('authChange', result);
375
- return result;
376
- }
377
-
378
- if (method === 'user.getInfo') {
379
- return getUserInfoResult();
380
- }
381
-
382
- if (method === 'share.showShareMenu') {
383
- return {
384
- ok: true,
385
- platform: 'hb-sdk-mock-host',
386
- type: 'showShareMenu',
387
- params: payload,
388
- };
389
- }
390
-
391
- if (method === 'share.screenshot') {
392
- return {
393
- ok: true,
394
- platform: 'hb-sdk-mock-host',
395
- type: 'screenshot',
396
- params: payload,
397
- };
398
- }
399
-
400
- if (method === 'viewport.getWindowInfo') {
401
- return getWindowInfo();
402
- }
403
-
404
- if (method === 'storage.getStorage') {
405
- return {
406
- data: storage.get(payload && payload.key),
407
- };
408
- }
409
-
410
- if (method === 'storage.setStorage') {
411
- storage.set(payload && payload.key, payload && payload.data);
412
- updateStorageSnapshot();
413
- return undefined;
414
- }
415
-
416
- if (method === 'network.request') {
417
- return requestNetwork(payload || {});
418
- }
419
-
420
- throw {
421
- code: 'METHOD_NOT_FOUND',
422
- message: `未开放小程序能力: ${method}`,
423
- };
424
- }
425
-
426
- async function requestNetwork(config) {
427
- const proxyPayload = createNetworkProxyPayload(config);
428
-
429
- const response = await fetch(NETWORK_PROXY_PATH, {
430
- method: 'POST',
431
- headers: {
432
- 'content-type': 'application/json',
433
- },
434
- body: JSON.stringify(proxyPayload),
435
- });
436
- const payload = await readNetworkProxyResponse(response);
437
-
438
- if (!response.ok) {
439
- throw payload;
440
- }
441
-
442
- return payload;
443
- }
444
-
445
- async function readNetworkProxyResponse(response) {
446
- const text = await response.text();
447
-
448
- if (!text.trim()) {
449
- return undefined;
450
- }
451
-
452
- try {
453
- return JSON.parse(text);
454
- } catch {
455
- return {
456
- code: response.status === 404 ? 'MOCK_NETWORK_PROXY_NOT_FOUND' : 'MOCK_NETWORK_PROXY_ERROR',
457
- message:
458
- response.status === 404
459
- ? 'mock network proxy 不可用,请重启 hb-sdk dev --mock'
460
- : text,
461
- };
462
- }
463
- }
464
-
465
- function createNetworkProxyPayload(config) {
466
- const url = new URL(config.url, iframe.src);
467
-
468
- if (config.params && typeof config.params === 'object') {
469
- Object.entries(config.params).forEach(([key, value]) => {
470
- if (value !== undefined && value !== null) {
471
- url.searchParams.set(key, String(value));
472
- }
473
- });
474
- }
475
-
476
- return {
477
- url: url.toString(),
478
- method: config.method,
479
- data: config.data,
480
- headers: config.headers,
481
- timeout: config.timeout,
482
- withCredentials: config.withCredentials,
483
- };
484
- }
485
-
486
- function postEvent(method, payload) {
487
- postMessageToMiniProgram({
488
- namespace: NAMESPACE,
489
- version: VERSION,
490
- nonce,
491
- type: 'event',
492
- method,
493
- payload,
494
- });
495
- }
496
-
497
- function postResponse(request, payload, error) {
498
- postMessageToMiniProgram({
499
- namespace: NAMESPACE,
500
- version: VERSION,
501
- nonce,
502
- type: 'response',
503
- id: request.id,
504
- method: request.method,
505
- payload,
506
- error,
507
- });
508
- }
509
-
510
- function postMessageToMiniProgram(message) {
511
- iframe.contentWindow && iframe.contentWindow.postMessage(message, readTargetOrigin());
512
- }
513
-
514
- function isBridgeMessage(message) {
515
- return Boolean(
516
- message &&
517
- typeof message === 'object' &&
518
- message.namespace === NAMESPACE &&
519
- message.version === VERSION &&
520
- message.nonce === nonce,
521
- );
522
- }
523
-
524
- function getUserInfoResult() {
525
- return {
526
- isLogin: Boolean(currentUser),
527
- userInfo: currentUser ? { ...currentUser } : null,
528
- };
529
- }
530
-
531
- function getWindowInfo() {
532
- const rect = iframe.getBoundingClientRect();
533
- const width = Math.max(1, Math.round(rect.width));
534
- const height = Math.max(1, Math.round(rect.height));
535
-
536
- return {
537
- pixelRatio: window.devicePixelRatio || 1,
538
- screenWidth: window.screen.width || width,
539
- screenHeight: window.screen.height || height,
540
- windowWidth: width,
541
- windowHeight: height,
542
- statusBarHeight: 0,
543
- safeArea: {
544
- left: 0,
545
- top: 0,
546
- right: width,
547
- bottom: height,
548
- width,
549
- height,
550
- },
551
- screenTop: 0,
552
- };
553
- }
554
-
555
- function updateUserStatus() {
556
- elements.userStatus.textContent = currentUser ? currentUser.nickname : '未登录';
557
- }
558
-
559
- function updateStorageSnapshot() {
560
- elements.storageSnapshot.textContent = JSON.stringify(
561
- Object.fromEntries(storage.entries()),
562
- null,
563
- 2,
564
- );
565
- }
566
-
567
- function pushLog(method, detail) {
568
- logs.unshift({
569
- method,
570
- detail,
571
- timestamp: new Date().toLocaleTimeString(),
572
- });
573
- logs.splice(30);
574
- elements.logs.innerHTML = logs
575
- .map(
576
- log => `<article class="log"><strong>${escapeHtml(log.method)} · ${escapeHtml(
577
- log.timestamp,
578
- )}</strong><pre>${escapeHtml(JSON.stringify(log.detail, null, 2))}</pre></article>`,
579
- )
580
- .join('');
581
- }
582
-
583
- function appendNonce(input, value) {
584
- const url = new URL(input, location.href);
585
- url.searchParams.set(NONCE_PARAM, value);
586
- return url.toString();
587
- }
588
-
589
- function readTargetOrigin() {
590
- try {
591
- return new URL(iframe.src).origin;
592
- } catch {
593
- return '*';
594
- }
595
- }
596
-
597
- function createNonce() {
598
- if (crypto && crypto.randomUUID) {
599
- return crypto.randomUUID();
600
- }
601
-
602
- return `mock_${Date.now()}_${Math.random().toString(16).slice(2)}`;
603
- }
604
-
605
- function toBridgeError(error) {
606
- if (error && typeof error === 'object' && error.code && error.message) {
607
- return error;
608
- }
609
-
610
- return {
611
- code: 'MOCK_RUNTIME_ERROR',
612
- message: error && error.message ? error.message : String(error),
613
- };
614
- }
615
-
616
- function escapeHtml(value) {
617
- return String(value)
618
- .replace(/&/g, '&amp;')
619
- .replace(/</g, '&lt;')
620
- .replace(/>/g, '&gt;')
621
- .replace(/"/g, '&quot;')
622
- .replace(/'/g, '&#039;');
623
- }
624
- </script>
250
+ <script type="module" src="./main.js"></script>
625
251
  </body>
626
252
  </html>