@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.
- package/CHANGELOG.md +51 -7
- package/README.md +83 -20
- package/dist/cli-chunks/{build-BtGxhrcV.cjs → build-DLIhlBQA.cjs} +4 -4
- package/dist/cli-chunks/{context-DX1KG-8A.cjs → context-Bl_Q4RKq.cjs} +15 -2
- package/dist/cli-chunks/{create-DAD0OF1r.cjs → create-C--pwY0l.cjs} +1 -1
- package/dist/cli-chunks/{dev-Dh4HY0I8.cjs → dev-B1tyT5ql.cjs} +197 -13
- package/dist/cli-chunks/{doctor-BfKdiD3H.cjs → doctor-D9M2scaJ.cjs} +1 -1
- package/dist/cli-chunks/{index-tCURDEx8.cjs → index-BnBeTd0B.cjs} +15 -14
- package/dist/cli-chunks/{index-DB6Q8HaC.cjs → index-HNB8i51C.cjs} +2 -2
- package/dist/cli-chunks/{login-D60EJLgs.cjs → login-DnX81kof.cjs} +2 -2
- package/dist/cli-chunks/{project-vite-DAUaP0_3.cjs → project-vite-CgnCpNDZ.cjs} +1 -1
- package/dist/cli-chunks/{remote-nQDniAUY.cjs → remote-CETqg77E.cjs} +6 -6
- package/dist/cli-chunks/{runtime-gate-BWlU-R4h.cjs → runtime-gate-CtV7rWyX.cjs} +1 -1
- package/dist/cli-chunks/{runtime-permission-env-DKrhgVM3.cjs → runtime-permission-env-D-8_jPG3.cjs} +2 -0
- package/dist/cli-chunks/{session-D6jOKXeu.cjs → session-Davw2CMd.cjs} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/devtools/mock-host/index.html +9 -2
- package/dist/devtools/mock-host/main.js +426 -802
- package/dist/index.cjs.js +46 -90
- package/dist/index.esm.js +46 -90
- package/dist/miniapp-publish.cjs.js +2 -0
- package/dist/miniapp-publish.esm.js +2 -1
- package/dist/protocol.cjs.js +98 -42
- package/dist/protocol.esm.js +93 -39
- package/dist/templates/vue3-vite-ts/README.md.ejs +1 -1
- package/dist/templates/vue3-vite-ts/src/App.vue +22 -17
- package/dist/templates/vue3-vite-ts/src/__tests__/App.spec.ts +37 -29
- package/dist/templates/vue3-vite-ts/src/auth-handoff.ts +46 -0
- package/dist/vite.cjs.js +2 -2
- package/dist/vite.esm.js +2 -2
- package/package.json +2 -2
- package/skill/SKILL.md +16 -12
- package/skill/references/api-protocol.md +22 -28
- package/skill/references/api-root.md +127 -112
- package/skill/references/cli.md +15 -20
- package/skill/references/examples.md +29 -17
- package/skill/references/recipes.md +180 -134
- package/skill/references/safety-boundaries.md +9 -3
- package/skill/scripts/sync-references.mjs +235 -139
- package/skill/scripts/validate-skill.mjs +18 -14
- package/skill/skill.json +4 -4
- package/types/index.d.ts +4 -4
- package/types/miniapp-publish/index.d.ts +1 -0
- package/types/modules/auth/index.d.ts +16 -28
- package/types/modules/cloud/index.d.ts +2 -2
- package/types/modules/network/index.d.ts +1 -2
- package/types/modules/user/get-info.d.ts +4 -4
- package/types/modules/user/get-local-identity.d.ts +9 -0
- package/types/modules/user/index.d.ts +13 -41
- package/types/modules/user/revoke-authorization.d.ts +7 -0
- package/types/modules/user/steam-game-list.d.ts +72 -0
- package/types/modules/user/types.d.ts +37 -302
- package/types/protocol/capabilities.d.ts +24 -49
- package/types/protocol/constants.d.ts +1 -1
- package/types/protocol/network-policy.d.ts +10 -0
- package/types/protocol/types.d.ts +10 -6
- package/types/protocol.d.ts +4 -3
- package/types/modules/user/get-current-user-detail.d.ts +0 -9
- package/types/modules/user/get-current-user-profile.d.ts +0 -9
- package/types/modules/user/get-platform-account-info.d.ts +0 -12
- package/types/modules/user/get-platform-account-overview.d.ts +0 -9
- package/types/modules/user/get-steam-game-list.d.ts +0 -12
|
@@ -9,40 +9,52 @@
|
|
|
9
9
|
- apps/docs/hb-sdk/recipes/**
|
|
10
10
|
## Positive examples
|
|
11
11
|
|
|
12
|
-
###
|
|
12
|
+
### Local identity for a network-disabled mini-program
|
|
13
13
|
|
|
14
14
|
```ts
|
|
15
|
-
import { ready, user } from '@heybox/hb-sdk';
|
|
15
|
+
import { ready, user, HbMiniProgramSDKError } from '@heybox/hb-sdk';
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
export async function getLocalIdentityFromUserAction() {
|
|
18
|
+
await ready();
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
try {
|
|
21
|
+
return await user.getLocalIdentity();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
29
|
```
|
|
24
30
|
|
|
25
|
-
###
|
|
31
|
+
### Developer server session for a network-enabled mini-program
|
|
26
32
|
|
|
27
33
|
```ts
|
|
28
|
-
import { auth,
|
|
34
|
+
import { auth, network, ready, HbMiniProgramSDKError } from '@heybox/hb-sdk';
|
|
29
35
|
|
|
30
|
-
export async function
|
|
36
|
+
export async function createServerSessionFromUserAction() {
|
|
31
37
|
await ready();
|
|
32
38
|
|
|
33
|
-
const current = await user.getInfo();
|
|
34
|
-
if (current.isLogin && current.userInfo) return current.userInfo;
|
|
35
|
-
|
|
36
39
|
try {
|
|
37
|
-
const
|
|
38
|
-
|
|
40
|
+
const result = await auth.login({ scopes: ['profile'] });
|
|
41
|
+
await exchangeCodeWithDeveloperServer(result.code);
|
|
42
|
+
return { status: 'ready' as const };
|
|
39
43
|
} catch (error) {
|
|
40
|
-
if (error instanceof HbMiniProgramSDKError) {
|
|
41
|
-
|
|
44
|
+
if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
|
|
45
|
+
return { status: 'cancelled' as const };
|
|
42
46
|
}
|
|
43
|
-
|
|
47
|
+
throw error;
|
|
44
48
|
}
|
|
45
49
|
}
|
|
50
|
+
|
|
51
|
+
async function exchangeCodeWithDeveloperServer(code: string) {
|
|
52
|
+
await network.request({
|
|
53
|
+
url: 'https://api.example.com/session/heybox',
|
|
54
|
+
method: 'POST',
|
|
55
|
+
data: { code },
|
|
56
|
+
});
|
|
57
|
+
}
|
|
46
58
|
```
|
|
47
59
|
|
|
48
60
|
### Network request
|
|
@@ -26,157 +26,196 @@
|
|
|
26
26
|
|
|
27
27
|
# 快速开始
|
|
28
28
|
|
|
29
|
-
如果页面不需要小黑盒开放能力,可以不接入 SDK
|
|
29
|
+
如果页面不需要小黑盒开放能力,可以不接入 SDK。需要开放能力时,先等待 `ready()`,再根据小程序是否开通网络权限选择身份流程。
|
|
30
|
+
|
|
31
|
+
## 未开通网络权限
|
|
32
|
+
|
|
33
|
+
无网络小程序可以在本地能力中使用按小程序隔离的 `appUserId`:
|
|
30
34
|
|
|
31
35
|
```ts
|
|
32
|
-
import hbSDK from '@heybox/hb-sdk'
|
|
36
|
+
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
33
37
|
|
|
34
|
-
async function
|
|
38
|
+
async function getLocalIdentityFromUserAction() {
|
|
35
39
|
await hbSDK.ready()
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
try {
|
|
42
|
+
const { appUserId } = await hbSDK.user.getLocalIdentity()
|
|
43
|
+
return appUserId
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
|
|
46
|
+
return undefined
|
|
47
|
+
}
|
|
48
|
+
throw error
|
|
41
49
|
}
|
|
42
|
-
|
|
43
|
-
console.log('当前用户未登录')
|
|
44
50
|
}
|
|
45
|
-
|
|
46
|
-
bootstrap()
|
|
47
51
|
```
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
把 `getLocalIdentityFromUserAction` 绑定到按钮点击等可信用户操作。首次登录或 identity consent 需要 UI 而缺少可信手势时返回 `USER_GESTURE_REQUIRED`;取消或关闭时返回 `AUTHORIZATION_CANCELLED`,不会确认或改变授权状态。这条路径不能获取授权码或调用 OpenAPI,也不要把 `appUserId` 发送到外部服务。
|
|
50
54
|
|
|
51
|
-
|
|
55
|
+
## 已开通网络权限
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
import { onUnmounted } from 'vue'
|
|
55
|
-
import hbSDK from '@heybox/hb-sdk'
|
|
57
|
+
有网络小程序通过 `auth.login()` 获取短期授权码。登录可能展示 UI,因此应绑定到按钮点击等明确的用户操作:
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
console.log('用户已登录', result.userInfo?.heybox_id)
|
|
60
|
-
}
|
|
61
|
-
})
|
|
59
|
+
```ts
|
|
60
|
+
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
62
61
|
|
|
63
62
|
await hbSDK.ready()
|
|
64
63
|
|
|
65
|
-
const initialUser = await hbSDK.user.getInfo()
|
|
66
|
-
|
|
67
64
|
async function loginFromUserAction() {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return
|
|
71
|
-
}
|
|
65
|
+
try {
|
|
66
|
+
const result = await hbSDK.auth.login({ scopes: ['profile'] })
|
|
72
67
|
|
|
73
|
-
|
|
68
|
+
await hbSDK.network.request({
|
|
69
|
+
url: 'https://api.example.com/session/heybox',
|
|
70
|
+
method: 'POST',
|
|
71
|
+
data: { code: result.code },
|
|
72
|
+
})
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
throw error
|
|
78
|
+
}
|
|
74
79
|
}
|
|
75
|
-
|
|
76
|
-
onUnmounted(stopAuthChange)
|
|
77
80
|
```
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
返回值与边界以[用户身份与登录](/guide/auth)为准。页面只把 `code` 提交给自己的服务端。不要在页面初始化阶段自动调用 `auth.login()`。
|
|
80
83
|
|
|
81
84
|
## ready 的含义
|
|
82
85
|
|
|
83
|
-
`ready()`
|
|
86
|
+
`ready()` 只表示 SDK 已就绪,可以安全调用开放能力。它不表示已经取得用户授权,也不返回用户身份。
|
|
84
87
|
|
|
85
|
-
##
|
|
88
|
+
## 默认单例
|
|
86
89
|
|
|
87
90
|
大多数小程序页面都应该使用默认实例。0.6 起不再对业务代码提供独立实例工厂。
|
|
88
91
|
|
|
89
92
|
## User and login
|
|
90
93
|
|
|
91
94
|
|
|
92
|
-
#
|
|
95
|
+
# 用户身份与登录
|
|
93
96
|
|
|
94
|
-
|
|
97
|
+
用户身份接入取决于小程序是否已开通 `network.request`。两类小程序使用不同的身份入口:
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
- `user.getPlatformAccountOverview()` / `getPlatformAccountInfo()`:读取平台账号概览或指定平台详情。
|
|
101
|
-
- `user.getSteamGameList()`:读取当前用户 Steam 游戏库。
|
|
99
|
+
| 小程序类型 | 身份入口 | 结果用途 |
|
|
100
|
+
| -------------- | ------------------------- | ------------------------------------------------------ |
|
|
101
|
+
| 已开通网络权限 | `auth.login({ scopes? })` | 获取短期授权码,由开发者服务端换取 OpenAPI token |
|
|
102
|
+
| 未开通网络权限 | `user.getLocalIdentity()` | 在当前小程序页面和平台代管能力中使用隔离的 `appUserId` |
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
不要混用两条路径。SDK 不向小程序页面提供 token、cookie、黑盒用户 ID 或平台私有凭据。
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
## 已开通网络权限
|
|
107
|
+
|
|
108
|
+
在登录、绑定账号或读取资料等明确的用户操作中调用 `auth.login()`:
|
|
106
109
|
|
|
107
110
|
```ts
|
|
108
|
-
import {
|
|
111
|
+
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
109
112
|
|
|
110
|
-
|
|
113
|
+
async function loginFromUserAction() {
|
|
114
|
+
await hbSDK.ready()
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
try {
|
|
117
|
+
const { code, expiresIn, scopes } = await hbSDK.auth.login({ scopes: ['profile'] })
|
|
118
|
+
// expiresIn 以服务端返回为准,单位秒;当前后端签发 300 秒一次性 code
|
|
119
|
+
|
|
120
|
+
await hbSDK.network.request({
|
|
121
|
+
url: 'https://api.example.com/session/heybox',
|
|
122
|
+
method: 'POST',
|
|
123
|
+
data: { code },
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
console.log(expiresIn, scopes)
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
throw error
|
|
132
|
+
}
|
|
115
133
|
}
|
|
116
134
|
```
|
|
117
135
|
|
|
118
|
-
|
|
136
|
+
返回值固定为 `{ code, expiresIn: 300, scopes }`:
|
|
119
137
|
|
|
120
|
-
|
|
138
|
+
- `code` 是一次性短期授权码,只能提交给当前小程序的开发者服务端。
|
|
139
|
+
- `expiresIn` 固定为 `300` 秒,服务端应尽快使用,失败或过期后重新获取。
|
|
140
|
+
- `scopes` 是本次授权码实际包含的 scope。
|
|
121
141
|
|
|
122
|
-
|
|
123
|
-
import hbSDK from '@heybox/hb-sdk'
|
|
142
|
+
`identity` 始终隐式包含,不需要也不能通过省略它来申请匿名授权。`scopes` 只填写业务确实需要的可选资料,例如 `profile`;不需要额外资料时直接调用 `auth.login()`。
|
|
124
143
|
|
|
125
|
-
|
|
126
|
-
await hbSDK.ready()
|
|
144
|
+
小程序页面只把 `code` 发送到自己的服务端。开发者服务端再按后端 OpenAPI 文档,用服务端保存的应用凭据交换 token;页面不得自行交换,也不得持有应用私密凭据。`auth.login()` 不返回 user、profile、`appUserId` 或 token。
|
|
127
145
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
146
|
+
开发者服务端用 access token 调用 `GET /user_miniprogram/openapi/v1/user` 读取当前用户。响应始终包含 `app_user_id`;token 含 `profile` 时还会返回 `nickname` 和 `avatar`。不要再请求已下线的 `/user/identity` 或 `/user/profile`。
|
|
147
|
+
|
|
148
|
+
## 用户操作和错误
|
|
149
|
+
|
|
150
|
+
需要展示登录或授权 UI 时,调用必须来自按钮点击等可信用户手势,否则返回 `USER_GESTURE_REQUIRED`。用户取消、拒绝或关闭授权页面时返回 `AUTHORIZATION_CANCELLED`,业务应停留在当前页面并允许稍后重试。
|
|
151
|
+
|
|
152
|
+
用户已授权所需 scope 时,`auth.login()` 可以不展示 UI,静默返回新的短期授权码。业务仍应把可能出现的授权 UI 设计在明确的用户操作之后,不要在页面初始化阶段自动调用。
|
|
153
|
+
|
|
154
|
+
## 撤销当前小程序授权
|
|
155
|
+
|
|
156
|
+
已开通和未开通网络权限的小程序都可以在明确的用户操作中撤销授权:
|
|
132
157
|
|
|
133
|
-
|
|
134
|
-
|
|
158
|
+
```ts
|
|
159
|
+
async function revokeAuthorizationFromUserAction() {
|
|
160
|
+
const confirmed = window.confirm('确定撤销当前小程序的用户授权吗?')
|
|
161
|
+
if (!confirmed) return
|
|
162
|
+
|
|
163
|
+
await hbSDK.user.revokeAuthorization()
|
|
164
|
+
clearLocalUserState()
|
|
135
165
|
}
|
|
136
166
|
```
|
|
137
167
|
|
|
138
|
-
|
|
168
|
+
`user.revokeAuthorization()` 不接收参数。小程序页面不能提交小程序 ID、黑盒用户 ID 或手势标记;Runtime 从 Host 启动上下文和用户操作状态注入可信值。调用缺少可信用户手势时返回 `USER_GESTURE_REQUIRED`。
|
|
169
|
+
|
|
170
|
+
撤销成功后,后续 `auth.login()` 或 `user.getLocalIdentity()` 会重新进入授权流程。业务必须立即停止使用并清理此前保存的 `appUserId`、用户资料和开发者服务端会话;SDK 不会删除业务自己的 localStorage、数据库或 cookie。
|
|
171
|
+
|
|
172
|
+
## 当前用户资料由服务端读取
|
|
173
|
+
|
|
174
|
+
已开通网络权限后,页面不再直接读取 Host 当前用户资料。`@heybox/hb-sdk` 根包实际导出的以下调用统一返回 `SERVER_API_REQUIRED`:
|
|
139
175
|
|
|
140
|
-
`user.getInfo()`
|
|
176
|
+
- `user.getInfo()`
|
|
177
|
+
- `user.getSteamGameList(options)`
|
|
178
|
+
- `user.getLocalIdentity()`
|
|
141
179
|
|
|
142
|
-
|
|
143
|
-
| ----------- | -------- | ------------ |
|
|
144
|
-
| `heybox_id` | `string` | 黑盒用户 ID |
|
|
145
|
-
| `nickname` | `string` | 用户昵称 |
|
|
146
|
-
| `avatar` | `string` | 用户头像 URL |
|
|
180
|
+
其他 Host current-user capabilities 属于 Host/runtime 集成边界,不是小程序可从 SDK 根包调用的方法。需要对应数据时,先取得授权码,再由开发者服务端按后端 OpenAPI 文档换取 token 并调用对应接口。不要把 `SERVER_API_REQUIRED` 当作未登录或权限弹窗失败。
|
|
147
181
|
|
|
148
|
-
|
|
182
|
+
`user.revokeAuthorization()` 是例外:它是授权变更操作,在两种网络模式下都可用,但始终要求可信用户手势。
|
|
149
183
|
|
|
150
|
-
|
|
184
|
+
## 未开通网络权限
|
|
185
|
+
|
|
186
|
+
未开通网络权限的小程序不走授权码流程。需要当前用户在本小程序内的稳定隔离身份时调用:
|
|
151
187
|
|
|
152
188
|
```ts
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
189
|
+
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
190
|
+
|
|
191
|
+
async function getLocalIdentityFromUserAction() {
|
|
192
|
+
await hbSDK.ready()
|
|
157
193
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
194
|
+
try {
|
|
195
|
+
const { appUserId } = await hbSDK.user.getLocalIdentity()
|
|
196
|
+
return appUserId
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
|
|
199
|
+
return undefined
|
|
200
|
+
}
|
|
201
|
+
throw error
|
|
202
|
+
}
|
|
161
203
|
}
|
|
162
204
|
```
|
|
163
205
|
|
|
164
|
-
|
|
206
|
+
`user.getLocalIdentity()` 返回 `{ appUserId }`。同一用户在同一小程序中保持稳定,在不同小程序中取值不同;应把它当作不透明字符串,不要解析、跨小程序关联或当作黑盒用户 ID。
|
|
165
207
|
|
|
166
|
-
|
|
208
|
+
首次登录或尚未授予 identity 时,该调用可能展示 UI,因此 `getLocalIdentityFromUserAction` 必须绑定到按钮点击等可信用户操作;缺少可信手势时返回 `USER_GESTURE_REQUIRED`。用户取消、拒绝或关闭时返回 `AUTHORIZATION_CANCELLED`,不会确认或改变授权状态;业务应正常结束当前操作并允许稍后重试。
|
|
167
209
|
|
|
168
|
-
|
|
169
|
-
import { onUnmounted } from 'vue'
|
|
170
|
-
import { on } from '@heybox/hb-sdk'
|
|
210
|
+
这类小程序无法获取授权码,也无法调用 OpenAPI;在未开通网络权限时调用 `auth.login()` 同样返回 `SERVER_API_REQUIRED`。Host 提供的 current-user APIs 与平台代管能力继续按各自权限工作,但页面不能把其中的身份或资料发送到外部服务。
|
|
171
211
|
|
|
172
|
-
|
|
173
|
-
if (result.isLogin) {
|
|
174
|
-
console.log('登录态更新', result.userInfo?.heybox_id)
|
|
175
|
-
}
|
|
176
|
-
})
|
|
212
|
+
## 网络请求边界
|
|
177
213
|
|
|
178
|
-
|
|
179
|
-
|
|
214
|
+
`network.request()` 只用于访问开发者自己的业务服务。平台保留的 runtime auth 与 OpenAPI 内部路径不能通过该能力访问;身份交换必须由开发者服务端按公开后端文档完成。
|
|
215
|
+
|
|
216
|
+
## CLI 登录与用户登录
|
|
217
|
+
|
|
218
|
+
`hb-sdk login` 只给本地开发和远端管理命令建立 CLI 登录态,与小程序页面的 `auth.login()`、`user.getLocalIdentity()` 和用户授权完全无关。
|
|
180
219
|
|
|
181
220
|
## Lifecycle events
|
|
182
221
|
|
|
@@ -210,15 +249,15 @@ onUnmounted(stopLifecycleEvents)
|
|
|
210
249
|
|
|
211
250
|
## 事件列表
|
|
212
251
|
|
|
213
|
-
| 事件
|
|
214
|
-
|
|
|
215
|
-
| `launch`
|
|
216
|
-
| `ready`
|
|
217
|
-
| `show`
|
|
218
|
-
| `hide`
|
|
219
|
-
| `unload`
|
|
220
|
-
| `error`
|
|
221
|
-
| `
|
|
252
|
+
| 事件 | 触发时机 | 典型用途 |
|
|
253
|
+
| ------------------------- | ------------------------ | -------------------------------- |
|
|
254
|
+
| `launch` | 小程序首次启动 | 初始化一次性数据 |
|
|
255
|
+
| `ready` | SDK 可安全调用开放能力 | 标记 SDK 可用 |
|
|
256
|
+
| `show` | 小程序页面展示 | 刷新可见态数据 |
|
|
257
|
+
| `hide` | 小程序页面隐藏 | 暂停轮询、暂停播放 |
|
|
258
|
+
| `unload` | 当前小程序运行环境终止 | 清理资源并停止请求 |
|
|
259
|
+
| `error` | 小程序或开放能力运行异常 | 统一错误上报 |
|
|
260
|
+
| `heybox_app_login_change` | 黑盒 APP 登录状态变化 | 刷新依赖 Host 当前用户的本地能力 |
|
|
222
261
|
|
|
223
262
|
完整载荷与事件名见:
|
|
224
263
|
|
|
@@ -229,7 +268,7 @@ onUnmounted(stopLifecycleEvents)
|
|
|
229
268
|
|
|
230
269
|
- 初始化开放能力前先 `await ready()`。
|
|
231
270
|
- UI 可见性相关逻辑放在 `show`、`hide`。
|
|
232
|
-
-
|
|
271
|
+
- 使用 Host current-user APIs 的无网络小程序,可以在 `heybox_app_login_change` 后刷新本地状态。已开通网络权限的小程序使用 `auth.login()` 获取 code,并由开发者服务端维护业务会话。
|
|
233
272
|
- 组件或页面销毁时清理 `on` 注册的监听,避免重复响应。
|
|
234
273
|
- 事件只派发给注册当时存在的监听器,不会重放;一次性 `launch`/`ready` 状态应以 `ready()` Promise 为准。
|
|
235
274
|
- 收到 `unload` 后,当前 SDK 上下文不可恢复,未完成请求会失败;不要在同一页面上下文继续重试能力调用。
|
|
@@ -245,11 +284,7 @@ SDK 公开两类标准错误:
|
|
|
245
284
|
- `HbMiniProgramNetworkError`:网络请求已返回,但 HTTP 状态未通过 `validateStatus`。
|
|
246
285
|
|
|
247
286
|
```ts
|
|
248
|
-
import {
|
|
249
|
-
HbMiniProgramNetworkError,
|
|
250
|
-
HbMiniProgramSDKError,
|
|
251
|
-
network,
|
|
252
|
-
} from '@heybox/hb-sdk'
|
|
287
|
+
import { HbMiniProgramNetworkError, HbMiniProgramSDKError, network } from '@heybox/hb-sdk'
|
|
253
288
|
|
|
254
289
|
try {
|
|
255
290
|
await network.request({ url: 'https://api.example.com/data' })
|
|
@@ -272,6 +307,9 @@ try {
|
|
|
272
307
|
|
|
273
308
|
- 根据 `error.code` 区分运行环境、权限、超时和业务失败,不要只比对错误文案。
|
|
274
309
|
- 权限失败时给出可理解的提示,不要将它当成未登录。
|
|
310
|
+
- `USER_GESTURE_REQUIRED` 表示潜在授权 UI 缺少可信用户手势,应让用户点击按钮后重试。
|
|
311
|
+
- `AUTHORIZATION_CANCELLED` 表示用户取消、拒绝或关闭授权页面,应正常结束当前操作。
|
|
312
|
+
- `SERVER_API_REQUIRED` 表示当前用户数据必须经开发者服务端 OpenAPI 获取,不应在页面重试对应 Host API。
|
|
275
313
|
- 超时或运行环境不可用时,允许用户重试或退出当前流程。
|
|
276
314
|
- 上报 `code`、`message` 和必要的业务上下文,不要上报用户凭据或敏感数据。
|
|
277
315
|
|
|
@@ -282,16 +320,22 @@ try {
|
|
|
282
320
|
```ts
|
|
283
321
|
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
284
322
|
|
|
285
|
-
type
|
|
286
|
-
| { status: 'ready'
|
|
323
|
+
type LoginViewState =
|
|
324
|
+
| { status: 'ready' }
|
|
325
|
+
| { status: 'cancelled' }
|
|
287
326
|
| { status: 'failed'; error: HbMiniProgramSDKError }
|
|
288
327
|
|
|
289
|
-
async function
|
|
328
|
+
async function loginFromUserAction(): Promise<LoginViewState> {
|
|
290
329
|
try {
|
|
291
330
|
await hbSDK.ready()
|
|
292
|
-
|
|
331
|
+
const result = await hbSDK.auth.login()
|
|
332
|
+
await exchangeCodeWithDeveloperServer(result.code)
|
|
333
|
+
return { status: 'ready' }
|
|
293
334
|
} catch (error) {
|
|
294
335
|
if (error instanceof HbMiniProgramSDKError) {
|
|
336
|
+
if (error.code === 'AUTHORIZATION_CANCELLED') {
|
|
337
|
+
return { status: 'cancelled' }
|
|
338
|
+
}
|
|
295
339
|
reportSDKError(error.code, error.message, error.data)
|
|
296
340
|
return { status: 'failed', error }
|
|
297
341
|
}
|
|
@@ -300,39 +344,45 @@ async function loadUser(): Promise<UserViewState> {
|
|
|
300
344
|
}
|
|
301
345
|
}
|
|
302
346
|
|
|
303
|
-
function
|
|
304
|
-
|
|
347
|
+
async function exchangeCodeWithDeveloperServer(code: string) {
|
|
348
|
+
await hbSDK.network.request({
|
|
349
|
+
url: 'https://api.example.com/session/heybox',
|
|
350
|
+
method: 'POST',
|
|
351
|
+
data: { code },
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function reportSDKError(errorCode: string, message: string, data?: unknown) {
|
|
356
|
+
console.log('[hb-sdk]', errorCode, message, data)
|
|
305
357
|
}
|
|
306
358
|
```
|
|
307
359
|
|
|
360
|
+
授权码在取得后立即交给开发者服务端交换,不要写入页面状态、DOM、日志或持久化存储。UI 只处理服务端会话是否建立成功。
|
|
361
|
+
|
|
308
362
|
## Login gate recipe
|
|
309
363
|
|
|
310
364
|
|
|
311
|
-
#
|
|
365
|
+
# 服务端登录门禁
|
|
312
366
|
|
|
313
|
-
|
|
367
|
+
已开通网络权限的小程序可以把“取得授权码并交给开发者服务端”收敛成一个用户操作函数:
|
|
314
368
|
|
|
315
369
|
```ts
|
|
316
370
|
import hbSDK, { HbMiniProgramSDKError } from '@heybox/hb-sdk'
|
|
317
|
-
import type { MiniProgramUserInfo } from '@heybox/hb-sdk'
|
|
318
371
|
|
|
319
|
-
export async function
|
|
320
|
-
|
|
321
|
-
await hbSDK.ready()
|
|
322
|
-
|
|
323
|
-
const current = await hbSDK.user.getInfo()
|
|
324
|
-
if (current.isLogin) {
|
|
325
|
-
return current.userInfo
|
|
326
|
-
}
|
|
372
|
+
export async function createServerSessionFromUserAction() {
|
|
373
|
+
await hbSDK.ready()
|
|
327
374
|
|
|
328
|
-
|
|
329
|
-
|
|
375
|
+
try {
|
|
376
|
+
const { code } = await hbSDK.auth.login({ scopes: ['profile'] })
|
|
377
|
+
return await hbSDK.network.request({
|
|
378
|
+
url: 'https://api.example.com/session/heybox',
|
|
379
|
+
method: 'POST',
|
|
380
|
+
data: { code },
|
|
381
|
+
})
|
|
330
382
|
} catch (error) {
|
|
331
|
-
if (error instanceof HbMiniProgramSDKError) {
|
|
332
|
-
|
|
333
|
-
return null
|
|
383
|
+
if (error instanceof HbMiniProgramSDKError && error.code === 'AUTHORIZATION_CANCELLED') {
|
|
384
|
+
return undefined
|
|
334
385
|
}
|
|
335
|
-
|
|
336
386
|
throw error
|
|
337
387
|
}
|
|
338
388
|
}
|
|
@@ -342,20 +392,16 @@ export async function ensureLogin(): Promise<MiniProgramUserInfo | null> {
|
|
|
342
392
|
|
|
343
393
|
```ts
|
|
344
394
|
async function handleSubmit() {
|
|
345
|
-
const
|
|
346
|
-
if (!
|
|
347
|
-
return
|
|
348
|
-
}
|
|
395
|
+
const session = await createServerSessionFromUserAction()
|
|
396
|
+
if (!session) return
|
|
349
397
|
|
|
350
|
-
//
|
|
398
|
+
// 继续执行需要开发者服务端身份的业务动作
|
|
351
399
|
}
|
|
352
400
|
```
|
|
353
401
|
|
|
354
402
|
## 注意事项
|
|
355
403
|
|
|
356
|
-
|
|
357
|
-
- 用户主动点击登录、提交、收藏等动作时,再调用 `login`。
|
|
358
|
-
- 登录态变化后,父容器应派发 `authChange`,页面可据此刷新用户相关 UI。
|
|
404
|
+
完整授权契约见[用户身份与登录](/guide/auth)。本页只保留调用骨架。
|
|
359
405
|
|
|
360
406
|
## Community share recipe
|
|
361
407
|
|
|
@@ -10,10 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
## 关键约束
|
|
12
12
|
|
|
13
|
-
- `ready()`
|
|
14
|
-
- `auth.login()`
|
|
13
|
+
- `ready()` 只表示 SDK 可调用,不表示已取得用户授权。
|
|
14
|
+
- `auth.login({ scopes? })` 只返回 `{ code, expiresIn: 300, scopes }`;identity 隐式强制包含,code 只能提交给开发者服务端。
|
|
15
|
+
- 需要授权 UI 时,`auth.login()` 必须来自可信用户手势,否则返回 `USER_GESTURE_REQUIRED`;用户取消或关闭时返回 `AUTHORIZATION_CANCELLED`。已授权时可以静默返回新 code。
|
|
16
|
+
- `user.getSteamGameList()` 仅供未开通网络权限的小程序通过 Host 读取;已开通网络权限时返回 `SERVER_API_REQUIRED`,且授权码与 OpenAPI 不提供 Steam 游戏库 scope 或资源接口。
|
|
17
|
+
- 已开通网络权限时,公开的 `user.getInfo()` 和 `user.getLocalIdentity()` 返回 `SERVER_API_REQUIRED`;对应身份和资料数据应由开发者服务端通过 OpenAPI 获取。
|
|
18
|
+
- 未开通网络权限时,只用 `user.getLocalIdentity()` 获取 `{ appUserId }`,不能获取 code 或调用 OpenAPI。
|
|
19
|
+
- `user.revokeAuthorization()` 在两种网络模式下都要求可信用户手势;成功后必须停止使用并清理业务缓存的旧身份、资料和服务端会话。
|
|
15
20
|
- `on()` 返回取消监听函数,组件卸载或页面销毁时需要调用。
|
|
16
21
|
- 业务网络请求使用 `network.request()`,不要依赖浏览器原生网络出口。
|
|
22
|
+
- `network.request()` 不能访问平台保留的 runtime auth 与 OpenAPI 内部路径;页面不得持有或交换服务端应用凭据。
|
|
17
23
|
- `network.request` 不支持 `multipart/form-data`;App Host 仅支持 form(`application/x-www-form-urlencoded`)与 JSON。表单请用 `URLSearchParams#toString()` 作为 `data`,文件上传请走专用上传能力。
|
|
18
24
|
- 仅当远端已启用 `network.request` 且 `useOfficialDomain=true` 时,`hb-sdk dev` 与 `hb-sdk remote deploy` 构建才会跳过平台 CSP;其他构建继续注入平台 CSP。
|
|
19
25
|
- 构建必须启用 `miniappManifest()`,推荐统一使用 `hb-sdk build`。
|
|
@@ -23,7 +29,7 @@
|
|
|
23
29
|
- Do not instruct mini-program code to read, extract, forward, store, or depend on token, cookie, phone number, or private credentials.
|
|
24
30
|
- Negative safety statements that explain the SDK does not expose token/cookie/private credentials are correct and should be preserved.
|
|
25
31
|
- 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.
|
|
26
|
-
- Do not use storage delete, clear, info listing,
|
|
32
|
+
- Do not use storage delete, clear, info listing, or global Heybox client storage access.
|
|
27
33
|
- Do not pass host-only protocol fields through `network.request`.
|
|
28
34
|
- Do not build raw `postMessage` bridge flows in iframe business code.
|
|
29
35
|
- Do not fetch deployed `dist/manifest.json` from business code; it is a build artifact for the release pipeline, not a CDN runtime asset.
|