@heybox/hb-sdk 0.1.3 → 0.2.0-alpha.1
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.
- package/README.md +149 -345
- package/bin/hb-sdk.cjs +3 -0
- package/dist/cli.cjs +10117 -0
- package/dist/devtools/mock-host/index.html +252 -0
- package/dist/devtools/mock-host/main.js +975 -0
- package/dist/index.cjs.js +474 -85
- package/dist/index.esm.js +465 -71
- package/dist/protocol.cjs.js +163 -0
- package/dist/protocol.esm.js +148 -0
- package/dist/templates/vue3-vite-ts/.gitignore.ejs +5 -0
- package/dist/templates/vue3-vite-ts/README.md.ejs +42 -0
- package/dist/templates/vue3-vite-ts/index.html.ejs +12 -0
- package/dist/templates/vue3-vite-ts/package.json.ejs +28 -0
- package/dist/templates/vue3-vite-ts/src/App.vue +63 -0
- package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +67 -0
- package/dist/templates/vue3-vite-ts/src/main.ts +5 -0
- package/dist/templates/vue3-vite-ts/src/styles.css +60 -0
- package/dist/templates/vue3-vite-ts/src/vite-env.d.ts +1 -0
- package/dist/templates/vue3-vite-ts/tsconfig.app.json +17 -0
- package/dist/templates/vue3-vite-ts/tsconfig.json +11 -0
- package/dist/templates/vue3-vite-ts/tsconfig.node.json +11 -0
- package/dist/templates/vue3-vite-ts/vite.config.ts +6 -0
- package/dist/templates/vue3-vite-ts/vitest.config.ts +10 -0
- package/package.json +30 -5
- package/skill/SKILL.md +95 -0
- package/skill/references/api-protocol.md +135 -0
- package/skill/references/api-root.md +346 -0
- package/skill/references/cli.md +360 -0
- package/skill/references/examples.md +107 -0
- package/skill/references/llms-index.md +44 -0
- package/skill/references/recipes.md +374 -0
- package/skill/references/safety-boundaries.md +28 -0
- package/skill/references/smoke-evaluation.md +24 -0
- package/skill/scripts/check-references.mjs +14 -0
- package/skill/scripts/package-skill.mjs +60 -0
- package/skill/scripts/package-skill.sh +6 -0
- package/skill/scripts/skill-metadata.mjs +74 -0
- package/skill/scripts/sync-references.mjs +541 -0
- package/skill/scripts/validate-skill.mjs +233 -0
- package/skill/skill.json +11 -0
- package/types/core/client.d.ts +23 -3
- package/types/core/errors.d.ts +45 -2
- package/types/core/sdk.d.ts +78 -10
- package/types/core/singleton.d.ts +33 -7
- package/types/core/utils.d.ts +2 -0
- package/types/index.d.ts +14 -6
- package/types/modules/auth/index.d.ts +35 -0
- package/types/modules/network/index.d.ts +120 -0
- package/types/modules/share/index.d.ts +9 -5
- package/types/modules/share/screenshot.d.ts +9 -3
- package/types/modules/share/show-share-menu.d.ts +9 -3
- package/types/modules/share/types.d.ts +24 -4
- package/types/modules/storage/index.d.ts +56 -0
- package/types/modules/user/get-info.d.ts +6 -2
- package/types/modules/user/index.d.ts +8 -10
- package/types/modules/user/types.d.ts +1 -0
- package/types/modules/viewport/index.d.ts +71 -0
- package/types/protocol/capabilities.d.ts +180 -0
- package/types/protocol/guards.d.ts +6 -1
- package/types/protocol/types.d.ts +19 -4
- package/types/protocol.d.ts +13 -0
- package/types/modules/system/get-storage.d.ts +0 -15
- package/types/modules/system/get-window-info.d.ts +0 -16
- package/types/modules/system/index.d.ts +0 -23
- package/types/modules/system/set-storage.d.ts +0 -12
- package/types/modules/system/types.d.ts +0 -34
- package/types/modules/user/login.d.ts +0 -18
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
# Recipes
|
|
2
|
+
|
|
3
|
+
> Generated by `node packages/hb-sdk/skill/scripts/sync-references.mjs` from the public hb-sdk source/docs. Do not edit by hand; update sources or this generator instead.
|
|
4
|
+
|
|
5
|
+
## Sources
|
|
6
|
+
|
|
7
|
+
- apps/h5/docs/hb_sdk/src/.vuepress/public/llms/guide/quick-start.md
|
|
8
|
+
- apps/h5/docs/hb_sdk/src/.vuepress/public/llms/guide/auth.md
|
|
9
|
+
- apps/h5/docs/hb_sdk/src/.vuepress/public/llms/guide/lifecycle.md
|
|
10
|
+
- apps/h5/docs/hb_sdk/src/.vuepress/public/llms/guide/error-handling.md
|
|
11
|
+
- apps/h5/docs/hb_sdk/src/.vuepress/public/llms/recipes/login-gate.md
|
|
12
|
+
- apps/h5/docs/hb_sdk/src/.vuepress/public/llms/recipes/custom-instance.md
|
|
13
|
+
|
|
14
|
+
## Contents
|
|
15
|
+
|
|
16
|
+
- [Quick start](#quick-start)
|
|
17
|
+
- [User and login](#user-and-login)
|
|
18
|
+
- [Lifecycle events](#lifecycle-events)
|
|
19
|
+
- [Error handling](#error-handling)
|
|
20
|
+
- [Login gate recipe](#login-gate-recipe)
|
|
21
|
+
- [Custom instance recipe](#custom-instance-recipe)
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# 快速开始
|
|
26
|
+
|
|
27
|
+
如果页面不需要黑盒开放能力,可以不接入 SDK。这是一条需要用户能力时的最短接入路径:等待 SDK 完成握手,然后读取当前用户登录态。
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import hbSDK from '@heybox/hb-sdk'
|
|
31
|
+
|
|
32
|
+
async function bootstrap() {
|
|
33
|
+
await hbSDK.ready()
|
|
34
|
+
|
|
35
|
+
const result = await hbSDK.user.getInfo()
|
|
36
|
+
if (result.isLogin && result.userInfo) {
|
|
37
|
+
console.log(result.userInfo.nickname)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log('当前用户未登录')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
bootstrap()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## 推荐业务写法
|
|
48
|
+
|
|
49
|
+
业务页通常还需要监听登录态变化:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import hbSDK from '@heybox/hb-sdk'
|
|
53
|
+
|
|
54
|
+
const stopAuthChange = hbSDK.on('authChange', result => {
|
|
55
|
+
if (result.isLogin) {
|
|
56
|
+
console.log('用户已登录', result.userInfo?.heybox_id)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
await hbSDK.ready()
|
|
61
|
+
|
|
62
|
+
const result = await hbSDK.user.getInfo()
|
|
63
|
+
if (!result.isLogin) {
|
|
64
|
+
await hbSDK.auth.login()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 页面卸载时清理监听
|
|
68
|
+
stopAuthChange()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## ready 的含义
|
|
72
|
+
|
|
73
|
+
`ready()` 表示 SDK 已完成与父容器的握手,可以安全调用开放能力。SDK 在收到 `ready` 前会自动重试握手;如果超过总超时时间仍未成功,会抛出 `READY_TIMEOUT`。它不等价于“用户已登录”,用户状态需要通过 `user.getInfo()` 或 `authChange` 判断。
|
|
74
|
+
|
|
75
|
+
## 默认单例适合什么场景
|
|
76
|
+
|
|
77
|
+
默认单例适合一个页面只有一个 SDK 上下文的情况。大多数小程序页面都应该使用默认单例,因为它可以避免重复握手和重复维护事件监听。
|
|
78
|
+
|
|
79
|
+
需要控制 `timeout`、注入测试 window 或隔离多个上下文时,再使用 [独立实例](../recipes/custom-instance.md)。
|
|
80
|
+
|
|
81
|
+
## User and login
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# 用户与登录
|
|
85
|
+
|
|
86
|
+
用户与授权模块当前分工:
|
|
87
|
+
|
|
88
|
+
- `user.getInfo()`:静默读取当前登录态与公开基础资料。
|
|
89
|
+
- `auth.login()`:唤起黑盒登录流程,并返回登录后的最新公开用户资料。
|
|
90
|
+
|
|
91
|
+
## 静默读取用户信息
|
|
92
|
+
|
|
93
|
+
`getInfo` 不会触发登录流程。用户未登录时,返回 `isLogin: false` 和 `userInfo: null`。
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { ready, user } from '@heybox/hb-sdk'
|
|
97
|
+
|
|
98
|
+
await ready()
|
|
99
|
+
|
|
100
|
+
const result = await user.getInfo()
|
|
101
|
+
if (result.isLogin) {
|
|
102
|
+
console.log(result.userInfo?.nickname)
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## 主动唤起登录
|
|
107
|
+
|
|
108
|
+
当业务动作必须登录才能继续时,再调用 `login`。
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import hbSDK from '@heybox/hb-sdk'
|
|
112
|
+
|
|
113
|
+
async function ensureLogin() {
|
|
114
|
+
await hbSDK.ready()
|
|
115
|
+
|
|
116
|
+
const current = await hbSDK.user.getInfo()
|
|
117
|
+
if (current.isLogin) {
|
|
118
|
+
return current.userInfo
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const next = await hbSDK.auth.login()
|
|
122
|
+
return next.userInfo
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## 暴露字段
|
|
127
|
+
|
|
128
|
+
SDK 只暴露允许给外部小程序读取的公开字段:
|
|
129
|
+
|
|
130
|
+
| 字段 | 类型 | 说明 |
|
|
131
|
+
| ----------- | -------- | ------------ |
|
|
132
|
+
| `heybox_id` | `string` | 黑盒用户 ID |
|
|
133
|
+
| `nickname` | `string` | 用户昵称 |
|
|
134
|
+
| `avatar` | `string` | 用户头像 URL |
|
|
135
|
+
|
|
136
|
+
不会暴露 token、cookie、手机号或任何可用于调用主站私有接口的凭据。
|
|
137
|
+
|
|
138
|
+
## 监听登录态变化
|
|
139
|
+
|
|
140
|
+
如果页面上同时存在登录按钮、权限态 UI 和业务数据,建议监听 `authChange`。
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { on } from '@heybox/hb-sdk'
|
|
144
|
+
|
|
145
|
+
const stop = on('authChange', result => {
|
|
146
|
+
if (result.isLogin) {
|
|
147
|
+
console.log('登录态更新', result.userInfo?.heybox_id)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Lifecycle events
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# 事件与生命周期
|
|
156
|
+
|
|
157
|
+
SDK 通过 `on` 监听父容器派发的小程序生命周期和业务事件。
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { on, off } from '@heybox/hb-sdk'
|
|
161
|
+
|
|
162
|
+
function handleShow(payload: { timestamp: number; source?: string }) {
|
|
163
|
+
console.log('show from', payload.source)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
on('show', handleShow)
|
|
167
|
+
off('show', handleShow)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`on` 也会返回取消监听函数,推荐在组件卸载时调用:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { on } from '@heybox/hb-sdk'
|
|
174
|
+
|
|
175
|
+
const stop = on('hide', () => {
|
|
176
|
+
console.log('小程序页面隐藏')
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
stop()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## 事件列表
|
|
183
|
+
|
|
184
|
+
| 事件 | 触发时机 | 典型用途 |
|
|
185
|
+
| ------------ | ------------------------ | ------------------ |
|
|
186
|
+
| `launch` | 小程序首次完成握手并启动 | 初始化一次性数据 |
|
|
187
|
+
| `ready` | SDK 可安全调用开放能力 | 标记 bridge 可用 |
|
|
188
|
+
| `show` | 小程序页面展示 | 刷新可见态数据 |
|
|
189
|
+
| `hide` | 小程序页面隐藏 | 暂停轮询、暂停播放 |
|
|
190
|
+
| `unload` | 小程序页面即将卸载 | 清理资源 |
|
|
191
|
+
| `error` | 父容器或开放能力运行异常 | 统一错误上报 |
|
|
192
|
+
| `authChange` | 登录状态变化 | 刷新用户信息和权限 |
|
|
193
|
+
|
|
194
|
+
完整载荷与事件名见:
|
|
195
|
+
|
|
196
|
+
- [MiniProgramEventPayloadMap](../reference/protocol/interfaces/MiniProgramEventPayloadMap.md)
|
|
197
|
+
- [MiniProgramEventName](../reference/protocol/types/README.md#miniprogrameventname)
|
|
198
|
+
|
|
199
|
+
## 生命周期建议
|
|
200
|
+
|
|
201
|
+
- 初始化开放能力前先 `await ready()`。
|
|
202
|
+
- UI 可见性相关逻辑放在 `show`、`hide`。
|
|
203
|
+
- 用户状态不要只在页面加载时读一次,登录入口附近要监听 `authChange`。
|
|
204
|
+
- 组件或页面销毁时清理 `on` 注册的监听,避免重复响应。
|
|
205
|
+
|
|
206
|
+
## Error handling
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# 错误处理
|
|
210
|
+
|
|
211
|
+
SDK 对外抛出的标准错误类型是 `HbMiniProgramSDKError`。
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { HbMiniProgramSDKError, ready } from '@heybox/hb-sdk'
|
|
215
|
+
|
|
216
|
+
try {
|
|
217
|
+
await ready()
|
|
218
|
+
} catch (error) {
|
|
219
|
+
if (error instanceof HbMiniProgramSDKError) {
|
|
220
|
+
console.log(error.code, error.message, error.data)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## SDK 内置错误
|
|
226
|
+
|
|
227
|
+
| code | 场景 | 建议处理 |
|
|
228
|
+
| ----------------- | --------------------------------- | ---------------------------------- |
|
|
229
|
+
| `NOT_IN_IFRAME` | 当前页面不在小程序沙盒 iframe 中 | 提示运行环境错误,检查父容器接入 |
|
|
230
|
+
| `MISSING_NONCE` | URL 中缺少 `hb_mini_bridge_nonce` | 检查父容器 URL 注入逻辑 |
|
|
231
|
+
| `READY_TIMEOUT` | SDK 握手超时 | 检查父容器是否幂等响应重试的 `sdk.handshake` |
|
|
232
|
+
| `REQUEST_TIMEOUT` | 开放能力调用超时 | 提示重试,并上报 method |
|
|
233
|
+
| `SDK_DESTROYED` | SDK 已销毁但仍有请求未完成 | 检查销毁时机和并发请求 |
|
|
234
|
+
|
|
235
|
+
父容器返回失败响应时,SDK 也会包装成 `HbMiniProgramSDKError`,此时 `code` 由父容器开放能力定义。
|
|
236
|
+
|
|
237
|
+
## 业务层建议
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
241
|
+
|
|
242
|
+
async function loadUser() {
|
|
243
|
+
try {
|
|
244
|
+
await hbSDK.ready()
|
|
245
|
+
return await hbSDK.user.getInfo()
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (error instanceof HbMiniProgramSDKError) {
|
|
248
|
+
reportSDKError(error.code, error.message, error.data)
|
|
249
|
+
return { isLogin: false, userInfo: null }
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
throw error
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function reportSDKError(code: string, message: string, data?: unknown) {
|
|
257
|
+
console.log('[hb-sdk]', code, message, data)
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## 超时时间
|
|
262
|
+
|
|
263
|
+
默认超时时间是 10000ms。需要调整时,使用独立实例:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
import { createMiniProgramSDK } from '@heybox/hb-sdk'
|
|
267
|
+
|
|
268
|
+
const sdk = createMiniProgramSDK({
|
|
269
|
+
timeout: 15000,
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Login gate recipe
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# 登录门禁
|
|
277
|
+
|
|
278
|
+
当业务动作必须登录后才能继续时,可以把登录态判断收敛成 `ensureLogin`。
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
282
|
+
import type { MiniProgramUserInfo } from '@heybox/hb-sdk'
|
|
283
|
+
|
|
284
|
+
export async function ensureLogin(): Promise<MiniProgramUserInfo | null> {
|
|
285
|
+
try {
|
|
286
|
+
await hbSDK.ready()
|
|
287
|
+
|
|
288
|
+
const current = await hbSDK.user.getInfo()
|
|
289
|
+
if (current.isLogin) {
|
|
290
|
+
return current.userInfo
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const next = await hbSDK.auth.login()
|
|
294
|
+
return next.userInfo
|
|
295
|
+
} catch (error) {
|
|
296
|
+
if (error instanceof HbMiniProgramSDKError) {
|
|
297
|
+
console.log('[hb-sdk]', error.code, error.message)
|
|
298
|
+
return null
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
throw error
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
业务按钮里使用:
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
async function handleSubmit() {
|
|
310
|
+
const userInfo = await ensureLogin()
|
|
311
|
+
if (!userInfo) {
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 继续执行需要登录的业务动作
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## 注意事项
|
|
320
|
+
|
|
321
|
+
- 进入页面时可以用 `getInfo` 静默初始化 UI。
|
|
322
|
+
- 用户主动点击登录、提交、收藏等动作时,再调用 `login`。
|
|
323
|
+
- 登录态变化后,父容器应派发 `authChange`,页面可据此刷新用户相关 UI。
|
|
324
|
+
|
|
325
|
+
## Custom instance recipe
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# 独立 SDK 实例
|
|
329
|
+
|
|
330
|
+
大多数业务页使用默认单例即可。只有在需要隔离上下文时,再创建独立实例。
|
|
331
|
+
|
|
332
|
+
## 自定义 timeout
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
import { createMiniProgramSDK } from '@heybox/hb-sdk'
|
|
336
|
+
|
|
337
|
+
const sdk = createMiniProgramSDK({
|
|
338
|
+
timeout: 15000,
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
await sdk.ready()
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## 测试环境注入 window
|
|
345
|
+
|
|
346
|
+
单元测试可以注入 `selfWindow`、`targetWindow` 和 `nonce`,避免依赖真实 iframe。
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
import { createMiniProgramSDK } from '@heybox/hb-sdk'
|
|
350
|
+
|
|
351
|
+
const sdk = createMiniProgramSDK({
|
|
352
|
+
nonce: 'test_nonce',
|
|
353
|
+
selfWindow: window,
|
|
354
|
+
targetWindow: null,
|
|
355
|
+
})
|
|
356
|
+
|
|
357
|
+
sdk.destroy()
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## 清理实例
|
|
361
|
+
|
|
362
|
+
独立实例不再使用时调用 `destroy`。
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
const sdk = createMiniProgramSDK()
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
await sdk.ready()
|
|
369
|
+
} finally {
|
|
370
|
+
sdk.destroy()
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
`destroy` 会移除 message 监听,并拒绝尚未完成的请求。销毁后不要继续复用该实例。
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Safety boundaries
|
|
2
|
+
|
|
3
|
+
> Generated by `node packages/hb-sdk/skill/scripts/sync-references.mjs` from the public hb-sdk source/docs. Do not edit by hand; update sources or this generator instead.
|
|
4
|
+
|
|
5
|
+
## Sources
|
|
6
|
+
|
|
7
|
+
- packages/hb-sdk/README.md
|
|
8
|
+
- apps/h5/docs/hb_sdk/src/.vuepress/public/llms/guide/auth.md
|
|
9
|
+
## Required boundaries
|
|
10
|
+
|
|
11
|
+
## 能力边界
|
|
12
|
+
|
|
13
|
+
- 调用模块能力前会自动等待 `ready()`,但业务仍建议在页面启动阶段显式 `await ready()`,便于集中处理握手失败。
|
|
14
|
+
- `user.getInfo()` 不会触发登录;登录必须由业务在用户操作后调用 `auth.login()`。
|
|
15
|
+
- 分享、截图、storage 和网络请求只开放稳定窄接口,不透传黑盒客户端内部协议参数。
|
|
16
|
+
- `network.request()` 的 `validateStatus` 只在 SDK 本地执行,不会被序列化给父容器。
|
|
17
|
+
- `on()` 返回取消监听函数;组件卸载或页面销毁时应主动取消监听。
|
|
18
|
+
- 使用 `createMiniProgramSDK()` 创建独立实例后,不再需要时应调用 `destroy()`。
|
|
19
|
+
|
|
20
|
+
## Agent rules
|
|
21
|
+
|
|
22
|
+
- Do not instruct mini-program code to read, extract, forward, store, or depend on token, cookie, phone number, or private credentials.
|
|
23
|
+
- Negative safety statements that explain the SDK does not expose token/cookie/private credentials are correct and should be preserved.
|
|
24
|
+
- Do not use raw share protocol fields, JS callbacks, activity reporting, post publishing, custom buttons, or upload-only flows.
|
|
25
|
+
- Do not use storage delete, clear, info listing, V2, or global Heybox client storage access.
|
|
26
|
+
- Do not pass host-only protocol fields through `network.request`.
|
|
27
|
+
- Do not build raw `postMessage` bridge flows in iframe business code.
|
|
28
|
+
- Do not import from internal hb-sdk implementation paths; only use documented package entrypoints.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# hb-sdk Skill Smoke Evaluation Template
|
|
2
|
+
|
|
3
|
+
Use this template when evaluating whether an agent followed the hb-sdk skill.
|
|
4
|
+
|
|
5
|
+
## Prompt
|
|
6
|
+
|
|
7
|
+
<copy the tested user prompt>
|
|
8
|
+
|
|
9
|
+
## Expected evidence
|
|
10
|
+
|
|
11
|
+
- [ ] Uses `@heybox/hb-sdk` root imports for iframe business code.
|
|
12
|
+
- [ ] Uses `@heybox/hb-sdk/protocol` only for host/runtime/protocol tasks.
|
|
13
|
+
- [ ] Uses `hb-sdk create`, `hb-sdk dev`, or `hb-sdk login` correctly for CLI tasks.
|
|
14
|
+
- [ ] Calls or relies on `ready()` before capability calls.
|
|
15
|
+
- [ ] Handles login, null user, and SDK errors safely.
|
|
16
|
+
- [ ] Keeps CLI login cache separate from iframe SDK login state.
|
|
17
|
+
- [ ] Avoids deep imports, token/cookie access, raw bridge mutation, second mock runtimes, and unsupported capabilities.
|
|
18
|
+
|
|
19
|
+
## Verdict
|
|
20
|
+
|
|
21
|
+
- Pass/Fail:
|
|
22
|
+
- Missing evidence:
|
|
23
|
+
- Unsafe output:
|
|
24
|
+
- Suggested skill improvement:
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
|
|
7
|
+
const scriptPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'sync-references.mjs');
|
|
8
|
+
const result = spawnSync(process.execPath, [scriptPath, '--check'], {
|
|
9
|
+
cwd: process.cwd(),
|
|
10
|
+
encoding: 'utf8',
|
|
11
|
+
stdio: 'inherit',
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
process.exit(result.status ?? 1);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cpSync, existsSync, mkdtempSync, rmSync } from 'node:fs';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import process from 'node:process';
|
|
8
|
+
import { HB_SDK_SKILL_NAME } from './skill-metadata.mjs';
|
|
9
|
+
|
|
10
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const skillDir = path.resolve(scriptDir, '..');
|
|
12
|
+
const packageRoot = path.resolve(skillDir, '..');
|
|
13
|
+
const skillName = HB_SDK_SKILL_NAME;
|
|
14
|
+
const repoRoot = findRepoRoot(process.cwd()) ?? packageRoot;
|
|
15
|
+
const zipPath = path.join(packageRoot, `${skillName}.zip`);
|
|
16
|
+
|
|
17
|
+
function findRepoRoot(startDir) {
|
|
18
|
+
let dir = path.resolve(startDir);
|
|
19
|
+
while (true) {
|
|
20
|
+
if (existsSync(path.join(dir, 'package.json')) && existsSync(path.join(dir, 'packages/hb-sdk/package.json'))) {
|
|
21
|
+
return dir;
|
|
22
|
+
}
|
|
23
|
+
const parent = path.dirname(dir);
|
|
24
|
+
if (parent === dir) return null;
|
|
25
|
+
dir = parent;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!existsSync(path.join(skillDir, 'SKILL.md'))) {
|
|
30
|
+
console.error(`Missing ${path.relative(repoRoot, path.join(skillDir, 'SKILL.md'))}.`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (existsSync(zipPath)) rmSync(zipPath);
|
|
35
|
+
|
|
36
|
+
const tempRoot = mkdtempSync(path.join(tmpdir(), 'hb-sdk-skill-'));
|
|
37
|
+
const packagedSkillRoot = path.join(tempRoot, skillName);
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
cpSync(skillDir, packagedSkillRoot, { recursive: true });
|
|
41
|
+
|
|
42
|
+
const result = spawnSync(
|
|
43
|
+
'zip',
|
|
44
|
+
['-r', zipPath, skillName, '-x', `${skillName}/README.md`, '-x', `${skillName}/**/.DS_Store`],
|
|
45
|
+
{
|
|
46
|
+
cwd: tempRoot,
|
|
47
|
+
encoding: 'utf8',
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
if (result.status !== 0) {
|
|
52
|
+
process.stderr.write(result.stderr || result.stdout);
|
|
53
|
+
process.exit(result.status ?? 1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.error(result.stdout.trim());
|
|
57
|
+
console.log(JSON.stringify({ ok: true, zip: path.relative(repoRoot, zipPath).split(path.sep).join('/') }));
|
|
58
|
+
} finally {
|
|
59
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
60
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
export const HB_SDK_SKILL_NAME = 'hb-sdk';
|
|
4
|
+
export const HB_SDK_PACKAGE_NAME = '@heybox/hb-sdk';
|
|
5
|
+
export const HB_SDK_SKILL_SOURCE = 'https://open.xiaoheihe.cn/agent-skills/hb-sdk';
|
|
6
|
+
|
|
7
|
+
export function createSkillContentHash(fileEntries) {
|
|
8
|
+
const hash = createHash('sha256');
|
|
9
|
+
|
|
10
|
+
for (const entry of [...fileEntries].sort((left, right) => left.path.localeCompare(right.path))) {
|
|
11
|
+
hash.update(entry.path);
|
|
12
|
+
hash.update('\0');
|
|
13
|
+
hash.update(entry.content);
|
|
14
|
+
hash.update('\0');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
hex: hash.digest('hex'),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createSkillManifest({ contentHash, sdkVersion }) {
|
|
23
|
+
const shortHash = contentHash.hex.slice(0, 12);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
name: HB_SDK_SKILL_NAME,
|
|
27
|
+
skillVersion: `${sdkVersion}+skill.${shortHash}`,
|
|
28
|
+
sdk: {
|
|
29
|
+
package: HB_SDK_PACKAGE_NAME,
|
|
30
|
+
version: sdkVersion,
|
|
31
|
+
compatibility: sdkVersion,
|
|
32
|
+
},
|
|
33
|
+
source: HB_SDK_SKILL_SOURCE,
|
|
34
|
+
integrity: `sha256-${contentHash.hex}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function validateSkillManifest({ manifest, sdkVersion }) {
|
|
39
|
+
const errors = [];
|
|
40
|
+
|
|
41
|
+
if (manifest?.name !== HB_SDK_SKILL_NAME) {
|
|
42
|
+
errors.push(`skill.json name must be \`${HB_SDK_SKILL_NAME}\`.`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (manifest?.sdk?.package !== HB_SDK_PACKAGE_NAME) {
|
|
46
|
+
errors.push(`skill.json sdk.package must be \`${HB_SDK_PACKAGE_NAME}\`.`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (manifest?.sdk?.version !== sdkVersion) {
|
|
50
|
+
errors.push('skill.json sdk.version must match packages/hb-sdk/package.json version.');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (manifest?.sdk?.compatibility !== sdkVersion) {
|
|
54
|
+
errors.push('skill.json sdk.compatibility must match packages/hb-sdk/package.json version.');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (typeof manifest?.skillVersion !== 'string' || !manifest.skillVersion.startsWith(`${sdkVersion}+skill.`)) {
|
|
58
|
+
errors.push('skill.json skillVersion must be derived from the current SDK version.');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (manifest?.source !== HB_SDK_SKILL_SOURCE) {
|
|
62
|
+
errors.push('skill.json source must be the public hb-sdk skill URL.');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (typeof manifest?.integrity !== 'string' || !/^sha256-[0-9a-f]{64}$/.test(manifest.integrity)) {
|
|
66
|
+
errors.push('skill.json integrity must be a sha256 hex digest.');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return errors;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function normalizeSkillManifest(manifest) {
|
|
73
|
+
return `${JSON.stringify(manifest, null, 2)}\n`;
|
|
74
|
+
}
|