@blod-nm/user-kit 0.1.1 → 0.1.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/package.json +1 -1
- package/src/schemas.js +145 -81
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blod-nm/user-kit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "CloudBase user-center kit: auth (wechat code / unionid / password / sms / email / signup) + crm_user_detail archive on @blod-nm/base-cb.",
|
package/src/schemas.js
CHANGED
|
@@ -4,57 +4,72 @@
|
|
|
4
4
|
职责: 23 条 user-kit 能力的 title / inputSchema / outputSchema / MCP annotations。
|
|
5
5
|
能力实现(auth.js / user.js)只负责 run;约束集中在这里,挂 MCP 时原样透传。
|
|
6
6
|
|
|
7
|
-
取用:
|
|
8
|
-
withSchemas([[key, ability], ...]) // 把元数据合并进能力对象
|
|
7
|
+
取用: withSchemas([[key, ability], ...])
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
·
|
|
12
|
-
·
|
|
9
|
+
必填约定:
|
|
10
|
+
· required 列出的字段缺一即 400(实现里已有同名校验)
|
|
11
|
+
· 二选一用 anyOf(signup: phone_number/email;sendVerification: phone/email)
|
|
12
|
+
· 可选字段在 description 里写明「可选」
|
|
13
|
+
· 本地/自定义链路 additionalProperties:false(不接受多余参数);网关透传类保持开放
|
|
13
14
|
*/
|
|
14
15
|
const str = (description, extra = {}) => ({ type: 'string', description, ...extra })
|
|
15
|
-
const obj = (properties = {}, required = []
|
|
16
|
+
const obj = (properties = {}, { required = [], anyOf, additionalProperties = true } = {}) => ({
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties,
|
|
19
|
+
...(required.length ? { required } : {}),
|
|
20
|
+
...(anyOf ? { anyOf } : {}),
|
|
21
|
+
additionalProperties,
|
|
22
|
+
})
|
|
16
23
|
const tokens = {
|
|
17
|
-
access_token: str('
|
|
18
|
-
refresh_token: str('
|
|
19
|
-
expires_in: { type: 'number', description: '
|
|
24
|
+
access_token: str('访问令牌(必返)'),
|
|
25
|
+
refresh_token: str('刷新令牌(必返)'),
|
|
26
|
+
expires_in: { type: 'number', description: '有效期秒数(必返)' },
|
|
20
27
|
}
|
|
21
|
-
const
|
|
22
|
-
const
|
|
28
|
+
const tokenOut = { type: 'object', properties: { ...tokens }, required: ['access_token', 'refresh_token', 'expires_in'] }
|
|
29
|
+
const tokenIn = obj({ access_token: str('用户访问令牌(必填,Bearer)') }, { required: ['access_token'], additionalProperties: false })
|
|
23
30
|
|
|
24
31
|
export const SCHEMAS = {
|
|
25
|
-
/* ---------- auth ---------- */
|
|
32
|
+
/* ---------- auth:自定义登录 ---------- */
|
|
26
33
|
'auth.loginByWxcode': {
|
|
27
34
|
title: '微信小程序登录',
|
|
28
|
-
inputSchema: obj({ code: str('wx.login 得到的 code') }, ['code']),
|
|
29
|
-
outputSchema: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
inputSchema: obj({ code: str('wx.login 得到的 code(必填)') }, { required: ['code'], additionalProperties: false }),
|
|
36
|
+
outputSchema: obj({
|
|
37
|
+
uid: str('唯一用户 id(必返)'),
|
|
38
|
+
openid: str('微信 openid(必返)'),
|
|
39
|
+
unionid: { type: ['string', 'null'], description: '微信 unionid,可能为 null(必返)' },
|
|
40
|
+
...tokens,
|
|
41
|
+
config: { type: 'object', description: 'prefix_config(必返,客户端强依赖)' },
|
|
42
|
+
}, { required: ['uid', 'openid', 'unionid', 'access_token', 'refresh_token', 'expires_in', 'config'], additionalProperties: false }),
|
|
34
43
|
annotations: { openWorldHint: true },
|
|
35
44
|
},
|
|
36
45
|
'auth.loginByUnionid': {
|
|
37
46
|
title: '唯一 id 登录',
|
|
38
|
-
inputSchema: obj({ unionid: str('调用方唯一用户 id') }, ['unionid']),
|
|
39
|
-
outputSchema: {
|
|
47
|
+
inputSchema: obj({ unionid: str('调用方唯一用户 id(必填)') }, { required: ['unionid'], additionalProperties: false }),
|
|
48
|
+
outputSchema: obj({
|
|
49
|
+
uid: str('唯一用户 id(必返)'),
|
|
50
|
+
unionid: str('唯一用户 id(必返)'),
|
|
51
|
+
...tokens,
|
|
52
|
+
}, { required: ['uid', 'unionid', 'access_token', 'refresh_token', 'expires_in'], additionalProperties: false }),
|
|
40
53
|
annotations: { openWorldHint: true },
|
|
41
54
|
},
|
|
55
|
+
|
|
56
|
+
/* ---------- auth:透传登录 ---------- */
|
|
42
57
|
'auth.loginByPassword': {
|
|
43
58
|
title: '账号密码登录',
|
|
44
|
-
inputSchema: obj({ username: str('
|
|
45
|
-
outputSchema: obj({ uid: str('唯一用户 id'), access_token: str('
|
|
59
|
+
inputSchema: obj({ username: str('用户名(必填)'), password: str('密码(必填)') }, { required: ['username', 'password'] }),
|
|
60
|
+
outputSchema: obj({ uid: str('唯一用户 id(必返)'), access_token: str('访问令牌(必返)') }, { required: ['uid', 'access_token'] }),
|
|
46
61
|
annotations: { openWorldHint: true },
|
|
47
62
|
},
|
|
48
63
|
'auth.loginBySms': {
|
|
49
64
|
title: '短信验证码登录',
|
|
50
|
-
inputSchema: obj({ verification_token: str('verifyCode
|
|
51
|
-
outputSchema: obj({ uid: str('唯一用户 id'), access_token: str('
|
|
65
|
+
inputSchema: obj({ verification_token: str('verifyCode 得到的令牌(必填)') }, { required: ['verification_token'] }),
|
|
66
|
+
outputSchema: obj({ uid: str('唯一用户 id(必返)'), access_token: str('访问令牌(必返)') }, { required: ['uid', 'access_token'] }),
|
|
52
67
|
annotations: { openWorldHint: true },
|
|
53
68
|
},
|
|
54
69
|
'auth.loginByEmail': {
|
|
55
70
|
title: '邮箱验证码登录',
|
|
56
|
-
inputSchema: obj({ verification_token: str('verifyCode
|
|
57
|
-
outputSchema: obj({ uid: str('唯一用户 id'), access_token: str('
|
|
71
|
+
inputSchema: obj({ verification_token: str('verifyCode 得到的令牌(必填)') }, { required: ['verification_token'] }),
|
|
72
|
+
outputSchema: obj({ uid: str('唯一用户 id(必返)'), access_token: str('访问令牌(必返)') }, { required: ['uid', 'access_token'] }),
|
|
58
73
|
annotations: { openWorldHint: true },
|
|
59
74
|
},
|
|
60
75
|
'auth.signup': {
|
|
@@ -62,118 +77,167 @@ export const SCHEMAS = {
|
|
|
62
77
|
inputSchema: obj({
|
|
63
78
|
phone_number: str('手机号(与 email 二选一)'),
|
|
64
79
|
email: str('邮箱(与 phone_number 二选一)'),
|
|
65
|
-
verification_token: str('
|
|
66
|
-
username: str('
|
|
67
|
-
password: str('
|
|
68
|
-
},
|
|
69
|
-
|
|
80
|
+
verification_token: str('验证码令牌(必填)'),
|
|
81
|
+
username: str('用户名(可选)'),
|
|
82
|
+
password: str('密码(可选)'),
|
|
83
|
+
}, {
|
|
84
|
+
required: ['verification_token'],
|
|
85
|
+
anyOf: [{ required: ['phone_number'] }, { required: ['email'] }],
|
|
86
|
+
}),
|
|
87
|
+
outputSchema: obj({ uid: str('唯一用户 id(必返)'), access_token: str('访问令牌(必返)') }, { required: ['uid', 'access_token'] }),
|
|
70
88
|
annotations: { openWorldHint: true },
|
|
71
89
|
},
|
|
90
|
+
|
|
91
|
+
/* ---------- auth:验证码 ---------- */
|
|
72
92
|
'auth.sendVerification': {
|
|
73
93
|
title: '发送验证码',
|
|
74
|
-
inputSchema: obj({
|
|
75
|
-
|
|
94
|
+
inputSchema: obj({
|
|
95
|
+
phone: str('手机号(与 email 二选一)'),
|
|
96
|
+
email: str('邮箱(与 phone 二选一)'),
|
|
97
|
+
email_redirect_to: str('Magic Link 跳转地址(可选,仅邮箱)'),
|
|
98
|
+
}, { anyOf: [{ required: ['phone'] }, { required: ['email'] }] }),
|
|
99
|
+
outputSchema: obj({ verification_id: str('验证码会话 id(必返)') }, { required: ['verification_id'] }),
|
|
76
100
|
},
|
|
77
101
|
'auth.sendSmsCode': {
|
|
78
102
|
title: '发送短信验证码',
|
|
79
|
-
inputSchema: obj({ phone: str('
|
|
80
|
-
outputSchema: obj({ verification_id: str('验证码会话 id') }, ['verification_id']),
|
|
103
|
+
inputSchema: obj({ phone: str('手机号(必填)') }, { required: ['phone'], additionalProperties: false }),
|
|
104
|
+
outputSchema: obj({ verification_id: str('验证码会话 id(必返)') }, { required: ['verification_id'] }),
|
|
81
105
|
},
|
|
82
106
|
'auth.sendEmailCode': {
|
|
83
107
|
title: '发送邮箱验证码',
|
|
84
|
-
inputSchema: obj({ email: str('
|
|
85
|
-
outputSchema: obj({ verification_id: str('验证码会话 id') }, ['verification_id']),
|
|
108
|
+
inputSchema: obj({ email: str('邮箱(必填)') }, { required: ['email'], additionalProperties: false }),
|
|
109
|
+
outputSchema: obj({ verification_id: str('验证码会话 id(必返)') }, { required: ['verification_id'] }),
|
|
86
110
|
},
|
|
87
111
|
'auth.verifyCode': {
|
|
88
112
|
title: '校验验证码',
|
|
89
|
-
inputSchema: obj({
|
|
90
|
-
|
|
113
|
+
inputSchema: obj({
|
|
114
|
+
verification_id: str('验证码会话 id(必填)'),
|
|
115
|
+
verification_code: str('用户输入的验证码(必填)'),
|
|
116
|
+
}, { required: ['verification_id', 'verification_code'], additionalProperties: false }),
|
|
117
|
+
outputSchema: obj({ verification_token: str('验证码令牌(必返)') }, { required: ['verification_token'] }),
|
|
91
118
|
},
|
|
119
|
+
|
|
120
|
+
/* ---------- auth:会话 ---------- */
|
|
92
121
|
'auth.reauthenticate': {
|
|
93
122
|
title: '敏感操作二次验证',
|
|
94
|
-
inputSchema: obj({
|
|
95
|
-
|
|
123
|
+
inputSchema: obj({
|
|
124
|
+
access_token: str('用户访问令牌(必填)'),
|
|
125
|
+
verify_opt: { type: 'string', enum: ['phone_code', 'email_code'], description: '验证方式(必填)' },
|
|
126
|
+
}, { required: ['access_token', 'verify_opt'], additionalProperties: false }),
|
|
127
|
+
outputSchema: obj({ verification_id: str('验证码会话 id(必返)') }),
|
|
96
128
|
},
|
|
97
129
|
'auth.introspect': {
|
|
98
130
|
title: '校验令牌',
|
|
99
|
-
inputSchema:
|
|
100
|
-
outputSchema: obj({ sub: str('
|
|
131
|
+
inputSchema: tokenIn,
|
|
132
|
+
outputSchema: obj({ sub: str('令牌对应的用户 id'), active: { type: 'boolean', description: '是否有效' } }),
|
|
101
133
|
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
102
134
|
},
|
|
103
135
|
'auth.refresh': {
|
|
104
136
|
title: '刷新令牌',
|
|
105
|
-
inputSchema: obj({ refresh_token: str('
|
|
106
|
-
outputSchema:
|
|
137
|
+
inputSchema: obj({ refresh_token: str('刷新令牌(必填)') }, { required: ['refresh_token'], additionalProperties: false }),
|
|
138
|
+
outputSchema: tokenOut,
|
|
107
139
|
},
|
|
108
140
|
'auth.signOut': {
|
|
109
141
|
title: '退出登录',
|
|
110
|
-
inputSchema:
|
|
111
|
-
|
|
142
|
+
inputSchema: obj({
|
|
143
|
+
access_token: str('用户访问令牌(必填)'),
|
|
144
|
+
client_id: str('客户端 id(可选,默认环境 id)'),
|
|
145
|
+
x_device_id: str('设备 id(可选)'),
|
|
146
|
+
}, { required: ['access_token'] }),
|
|
147
|
+
outputSchema: { type: 'object', description: '网关响应(通常为空对象)' },
|
|
112
148
|
annotations: { destructiveHint: true },
|
|
113
149
|
},
|
|
114
150
|
|
|
115
|
-
/* ---------- user ---------- */
|
|
151
|
+
/* ---------- user:本地档案 ---------- */
|
|
116
152
|
'user.upsert': {
|
|
117
153
|
title: '建档 / 合并档案',
|
|
118
|
-
inputSchema: obj({
|
|
119
|
-
|
|
154
|
+
inputSchema: obj({
|
|
155
|
+
uid: str('唯一用户 id(必填,≤128 字符)'),
|
|
156
|
+
profile: { type: 'object', description: '要合并进档案 profile 段的字段(可选)' },
|
|
157
|
+
env: str('建档环境标签(可选,缺省 prod)'),
|
|
158
|
+
}, { required: ['uid'], additionalProperties: false }),
|
|
159
|
+
outputSchema: obj({ id: str('档案行 id'), data: { type: 'object', description: '档案 data 段' } }, { additionalProperties: false }),
|
|
120
160
|
},
|
|
121
161
|
'user.get': {
|
|
122
162
|
title: '读取档案',
|
|
123
|
-
inputSchema: obj({ uid: str('唯一用户 id') }, ['uid']),
|
|
124
|
-
outputSchema: {
|
|
163
|
+
inputSchema: obj({ uid: str('唯一用户 id(必填)') }, { required: ['uid'], additionalProperties: false }),
|
|
164
|
+
outputSchema: {
|
|
165
|
+
type: ['object', 'null'],
|
|
166
|
+
description: '档案行;不存在时为 null',
|
|
167
|
+
properties: { id: str('档案行 id'), data: { type: 'object' }, status: str('状态'), deleted_at: { type: ['string', 'null'] } },
|
|
168
|
+
},
|
|
125
169
|
annotations: { readOnlyHint: true },
|
|
126
170
|
},
|
|
127
171
|
'user.patchProfile': {
|
|
128
172
|
title: '局部更新档案',
|
|
129
|
-
inputSchema: obj({
|
|
130
|
-
|
|
173
|
+
inputSchema: obj({
|
|
174
|
+
uid: str('唯一用户 id(必填)'),
|
|
175
|
+
patch: { type: 'object', description: '要浅合并进 profile 的字段(必填)' },
|
|
176
|
+
}, { required: ['uid', 'patch'], additionalProperties: false }),
|
|
177
|
+
outputSchema: obj({ section: { type: ['object', 'null'], description: '合并后的 profile 段' } }),
|
|
178
|
+
},
|
|
179
|
+
'user.schemaStatus': {
|
|
180
|
+
title: '档案表状态',
|
|
181
|
+
inputSchema: obj({}, { required: [], additionalProperties: false }),
|
|
182
|
+
outputSchema: obj({
|
|
183
|
+
table: { type: 'boolean', description: '表是否存在' },
|
|
184
|
+
primaryKey: { type: 'boolean', description: '主键是否存在' },
|
|
185
|
+
indexes: { type: 'object', description: '四个索引的存在性' },
|
|
186
|
+
}, { required: ['table', 'primaryKey', 'indexes'], additionalProperties: false }),
|
|
187
|
+
annotations: { readOnlyHint: true },
|
|
188
|
+
},
|
|
189
|
+
'user.ensureSchema': {
|
|
190
|
+
title: '初始化档案表',
|
|
191
|
+
inputSchema: obj({}, { required: [], additionalProperties: false }),
|
|
192
|
+
outputSchema: obj({
|
|
193
|
+
table: { type: 'string', enum: ['created', 'exists'], description: '本次建表结果' },
|
|
194
|
+
indexes: { type: 'object', description: '{ created: string[], existing: string[] }' },
|
|
195
|
+
status: { type: 'object', description: '执行后的探测结果' },
|
|
196
|
+
}, { required: ['table', 'indexes', 'status'], additionalProperties: false }),
|
|
197
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
131
198
|
},
|
|
199
|
+
|
|
200
|
+
/* ---------- user:用户令牌面(网关透传) ---------- */
|
|
132
201
|
'user.me': {
|
|
133
202
|
title: '当前用户',
|
|
134
|
-
inputSchema:
|
|
203
|
+
inputSchema: tokenIn,
|
|
135
204
|
outputSchema: { type: 'object', description: '网关用户信息(原样)' },
|
|
136
205
|
annotations: { readOnlyHint: true },
|
|
137
206
|
},
|
|
138
207
|
'user.updateBasic': {
|
|
139
208
|
title: '修改资料(含手机号/邮箱)',
|
|
140
209
|
inputSchema: obj({
|
|
141
|
-
access_token: str('
|
|
142
|
-
nickname: str('
|
|
143
|
-
username: str('
|
|
144
|
-
phone: str('
|
|
145
|
-
email: str('
|
|
146
|
-
avatar_url: str('头像 URL'),
|
|
147
|
-
gender: { type: 'string', enum: ['MALE', 'FEMALE'], description: '
|
|
148
|
-
description: str('
|
|
149
|
-
verification_token: str('
|
|
150
|
-
}, ['access_token']),
|
|
210
|
+
access_token: str('用户访问令牌(必填)'),
|
|
211
|
+
nickname: str('昵称(可选)'),
|
|
212
|
+
username: str('用户名(可选)'),
|
|
213
|
+
phone: str('手机号(可选,修改需验证码)'),
|
|
214
|
+
email: str('邮箱(可选,修改需验证码)'),
|
|
215
|
+
avatar_url: str('头像 URL(可选)'),
|
|
216
|
+
gender: { type: 'string', enum: ['MALE', 'FEMALE'], description: '性别(可选)' },
|
|
217
|
+
description: str('个人简介(可选)'),
|
|
218
|
+
verification_token: str('手机号/邮箱变更的验证码令牌(可选,改手机/邮箱时需要)'),
|
|
219
|
+
}, { required: ['access_token'] }),
|
|
151
220
|
outputSchema: { type: 'object', description: '网关响应(原样)' },
|
|
152
221
|
},
|
|
153
222
|
'user.changePassword': {
|
|
154
223
|
title: '修改密码',
|
|
155
|
-
inputSchema: obj({
|
|
156
|
-
|
|
224
|
+
inputSchema: obj({
|
|
225
|
+
access_token: str('用户访问令牌(必填)'),
|
|
226
|
+
password: str('新密码(必填)'),
|
|
227
|
+
verification_token: str('二次验证令牌(可选,按网关要求)'),
|
|
228
|
+
}, { required: ['access_token', 'password'] }),
|
|
229
|
+
outputSchema: { type: 'object', description: '网关响应(通常为空对象)' },
|
|
157
230
|
annotations: { destructiveHint: true },
|
|
158
231
|
},
|
|
159
232
|
'user.deleteMe': {
|
|
160
233
|
title: '注销账号',
|
|
161
|
-
inputSchema: obj({
|
|
162
|
-
|
|
234
|
+
inputSchema: obj({
|
|
235
|
+
access_token: str('用户访问令牌(必填)'),
|
|
236
|
+
verification_token: str('二次验证令牌(可选,按网关要求)'),
|
|
237
|
+
}, { required: ['access_token'] }),
|
|
238
|
+
outputSchema: { type: 'object', description: '网关响应(通常为空对象)' },
|
|
163
239
|
annotations: { destructiveHint: true },
|
|
164
240
|
},
|
|
165
|
-
'user.schemaStatus': {
|
|
166
|
-
title: '档案表状态',
|
|
167
|
-
inputSchema: obj(),
|
|
168
|
-
outputSchema: obj({ table: { type: 'boolean' }, primaryKey: { type: 'boolean' }, indexes: { type: 'object', description: '四个索引的存在性' } }, ['table', 'indexes']),
|
|
169
|
-
annotations: { readOnlyHint: true },
|
|
170
|
-
},
|
|
171
|
-
'user.ensureSchema': {
|
|
172
|
-
title: '初始化档案表',
|
|
173
|
-
inputSchema: obj(),
|
|
174
|
-
outputSchema: obj({ table: { type: 'string', enum: ['created', 'exists'] }, indexes: { type: 'object' }, status: { type: 'object' } }, ['table']),
|
|
175
|
-
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
176
|
-
},
|
|
177
241
|
}
|
|
178
242
|
|
|
179
243
|
/** 把元数据合并进 [key, ability] 列表(能力对象原样保留 describe/run) */
|