beervid-app-cli 0.2.5 → 0.2.6
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/dist/cli.mjs +1 -1
- package/package.json +5 -1
- package/skills/beervid-app-cli/docs/oauth-callback.md +22 -19
- package/skills/beervid-app-cli/example/express/server.ts +8 -4
- package/skills/beervid-app-cli/example/nextjs/app/api/oauth/url/route.ts +3 -2
- package/skills/beervid-app-cli/example/standard/get-oauth-url.ts +3 -2
package/dist/cli.mjs
CHANGED
|
@@ -1130,7 +1130,7 @@ function register10(cli2) {
|
|
|
1130
1130
|
|
|
1131
1131
|
// src/cli.ts
|
|
1132
1132
|
var cli = cac("beervid");
|
|
1133
|
-
var cliVersion = true ? "0.2.
|
|
1133
|
+
var cliVersion = true ? "0.2.6" : pkg.version;
|
|
1134
1134
|
register10(cli);
|
|
1135
1135
|
register(cli);
|
|
1136
1136
|
register2(cli);
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "beervid-app-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "BEERVID App CLI — TikTok video publish, account auth, and data query",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/Lupeiwen0/beervid-app-cli"
|
|
8
|
+
},
|
|
5
9
|
"type": "module",
|
|
6
10
|
"engines": {
|
|
7
11
|
"node": ">=20.0.0"
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
2. **用户跳转授权**:将用户重定向到返回的 URL
|
|
17
17
|
3. **接收回调**:用户授权后,TikTok 回调你的服务器
|
|
18
18
|
|
|
19
|
-
>
|
|
20
|
-
>
|
|
19
|
+
> **说明**:获取到的授权链接中**不一定**携带 `state` 参数。
|
|
20
|
+
> - 如果链接中已经包含 `state`,它的值一定是一个 JSON 字符串。你可以解析该 JSON,在其中追加自定义字段后再写回。
|
|
21
|
+
> - 如果链接中没有 `state`,而你需要透传参数(例如防 CSRF 的安全 token),应自行构造一个 JSON 对象作为 `state` 的值追加到授权链接上。
|
|
21
22
|
|
|
22
23
|
---
|
|
23
24
|
|
|
@@ -35,9 +36,11 @@ OAuth 授权完成后,回调 URL 会携带以下关键参数:
|
|
|
35
36
|
|
|
36
37
|
---
|
|
37
38
|
|
|
38
|
-
##
|
|
39
|
+
## 获取授权链接后如何设置或追加 State
|
|
39
40
|
|
|
40
|
-
|
|
41
|
+
授权链接中**可能包含也可能不包含** `state` 参数:
|
|
42
|
+
- 如果已包含 `state`,其值是一个 JSON 字符串,可以解析后追加字段再写回。
|
|
43
|
+
- 如果未包含 `state`,而你需要透传参数,应自行构造一个 JSON 对象设置为 `state`。
|
|
41
44
|
|
|
42
45
|
```typescript
|
|
43
46
|
function tryParseJsonObject(value: string): Record<string, unknown> | null {
|
|
@@ -52,25 +55,25 @@ function tryParseJsonObject(value: string): Record<string, unknown> | null {
|
|
|
52
55
|
}
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
function
|
|
58
|
+
function setOrAppendStateToken(
|
|
56
59
|
rawUrl: string,
|
|
57
60
|
customStateToken: string
|
|
58
61
|
): string {
|
|
59
62
|
const url = new URL(rawUrl)
|
|
60
63
|
const rawState = url.searchParams.get('state')
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
throw new Error('授权链接中缺少 state 参数')
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const parsedState = tryParseJsonObject(rawState)
|
|
67
|
-
if (!parsedState) {
|
|
68
|
-
throw new Error('授权链接中的 state 不是可追加字段的 JSON 对象')
|
|
69
|
-
}
|
|
65
|
+
let nextState: Record<string, unknown>
|
|
70
66
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
if (rawState) {
|
|
68
|
+
// 链接中已有 state,解析后追加字段
|
|
69
|
+
const parsedState = tryParseJsonObject(rawState)
|
|
70
|
+
if (!parsedState) {
|
|
71
|
+
throw new Error('授权链接中的 state 不是可追加字段的 JSON 对象')
|
|
72
|
+
}
|
|
73
|
+
nextState = { ...parsedState, customStateToken }
|
|
74
|
+
} else {
|
|
75
|
+
// 链接中没有 state,自行构造 JSON
|
|
76
|
+
nextState = { customStateToken }
|
|
74
77
|
}
|
|
75
78
|
|
|
76
79
|
url.searchParams.set('state', JSON.stringify(nextState))
|
|
@@ -80,7 +83,7 @@ function appendTokenToOAuthUrlState(
|
|
|
80
83
|
async function getTtOAuthUrlWithState(userId: string): Promise<string> {
|
|
81
84
|
const customStateToken = generateStateToken(userId)
|
|
82
85
|
const rawUrl = await openApiGet<string>('/api/v1/open/thirdparty-auth/tt-url')
|
|
83
|
-
return
|
|
86
|
+
return setOrAppendStateToken(rawUrl, customStateToken)
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
async function getTtsOAuthUrlWithState(userId: string): Promise<string> {
|
|
@@ -88,7 +91,7 @@ async function getTtsOAuthUrlWithState(userId: string): Promise<string> {
|
|
|
88
91
|
const data = await openApiGet<{ crossBorderUrl: string }>(
|
|
89
92
|
'/api/v1/open/thirdparty-auth/tts-url'
|
|
90
93
|
)
|
|
91
|
-
return
|
|
94
|
+
return setOrAppendStateToken(data.crossBorderUrl, customStateToken)
|
|
92
95
|
}
|
|
93
96
|
```
|
|
94
97
|
|
|
@@ -108,7 +111,7 @@ function parseCustomStateToken(state: string): string {
|
|
|
108
111
|
```
|
|
109
112
|
|
|
110
113
|
> **说明**:字段名 `customStateToken` 只是示例,你也可以改成 `token`、`nonce`、`appState` 等业务上更合适的名字。
|
|
111
|
-
>
|
|
114
|
+
> 无论链接中原先是否携带 `state`,你设置的 `state` 值都应该是一个 JSON 对象。
|
|
112
115
|
|
|
113
116
|
---
|
|
114
117
|
|
|
@@ -154,8 +154,10 @@ async function pollVideoStatusInBackground(record: VideoRecord): Promise<void> {
|
|
|
154
154
|
app.get('/oauth/tt', async (_req, res) => {
|
|
155
155
|
try {
|
|
156
156
|
const url = await openApiGet<string>('/api/v1/open/thirdparty-auth/tt-url')
|
|
157
|
-
//
|
|
158
|
-
//
|
|
157
|
+
// 生产环境:授权链接中不一定携带 state 参数。
|
|
158
|
+
// 如果已有 state,其值为 JSON,可解析后追加自定义字段;
|
|
159
|
+
// 如果没有 state,需透传参数时应自行构造 JSON 设置为 state。
|
|
160
|
+
// 详见 docs/oauth-callback.md
|
|
159
161
|
res.redirect(url)
|
|
160
162
|
} catch (err) {
|
|
161
163
|
res.status(500).json({ error: (err as Error).message })
|
|
@@ -168,8 +170,10 @@ app.get('/oauth/tts', async (_req, res) => {
|
|
|
168
170
|
const data = await openApiGet<{ crossBorderUrl: string }>(
|
|
169
171
|
'/api/v1/open/thirdparty-auth/tts-url'
|
|
170
172
|
)
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
+
// 生产环境:授权链接中不一定携带 state 参数。
|
|
174
|
+
// 如果已有 state,其值为 JSON,可解析后追加自定义字段;
|
|
175
|
+
// 如果没有 state,需透传参数时应自行构造 JSON 设置为 state。
|
|
176
|
+
// 详见 docs/oauth-callback.md
|
|
173
177
|
res.redirect(data.crossBorderUrl)
|
|
174
178
|
} catch (err) {
|
|
175
179
|
res.status(500).json({ error: (err as Error).message })
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* GET /api/oauth/url?type=tt|tts
|
|
3
3
|
* 获取 OAuth 授权 URL
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 生产环境:授权链接中不一定携带 state 参数。
|
|
6
|
+
* 如果已有 state,其值为 JSON,可解析后追加自定义字段;
|
|
7
|
+
* 如果没有 state,需透传参数时应自行构造 JSON 设置为 state。
|
|
7
8
|
* 详见 docs/oauth-callback.md
|
|
8
9
|
*/
|
|
9
10
|
import { NextRequest, NextResponse } from 'next/server'
|
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* npx tsx get-oauth-url.ts --type tt
|
|
6
6
|
* npx tsx get-oauth-url.ts --type tts
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* 生产环境:授权链接中不一定携带 state 参数。
|
|
9
|
+
* 如果已有 state,其值为 JSON,可解析后追加自定义字段;
|
|
10
|
+
* 如果没有 state,需透传参数时应自行构造 JSON 设置为 state。
|
|
10
11
|
* 详见 docs/oauth-callback.md
|
|
11
12
|
*/
|
|
12
13
|
|