@zzclub/pipeline 0.4.0 → 0.5.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 +28 -1
- package/package.json +1 -1
- package/src/commands/init.ts +7 -1
- package/src/commands/wx-draft-delete.ts +36 -0
- package/src/commands/wx-drafts.ts +47 -0
- package/src/plugins.ts +4 -0
- package/src/providers/index.ts +8 -0
- package/src/providers/wechat.ts +229 -19
- package/src/schema/state.ts +2 -0
package/README.md
CHANGED
|
@@ -409,7 +409,7 @@ src/
|
|
|
409
409
|
| `review` | Update content review status |
|
|
410
410
|
| `abandon` | Mark one or more tasks as abandoned |
|
|
411
411
|
|
|
412
|
-
`ops` 组,
|
|
412
|
+
`ops` 组,9 个命令:
|
|
413
413
|
|
|
414
414
|
| 命令 | 说明 |
|
|
415
415
|
| --- | --- |
|
|
@@ -420,6 +420,8 @@ src/
|
|
|
420
420
|
| `config` | Read or update pipeline config |
|
|
421
421
|
| `doctor` | Inspect resolved paths and provider health |
|
|
422
422
|
| `hermes-metrics` | Show Hermes execution metrics per task |
|
|
423
|
+
| `wx-drafts` | List or get drafts from WeChat draft box |
|
|
424
|
+
| `wx-draft-delete` | Delete a draft from WeChat draft box |
|
|
423
425
|
|
|
424
426
|
## 常用命令
|
|
425
427
|
|
|
@@ -553,6 +555,31 @@ bun run src/cli.ts wechat-export --body /abs/path/body.md --account default
|
|
|
553
555
|
bun run src/cli.ts cos-upload --file /abs/path/image.png --folder notes/note-id --alt image
|
|
554
556
|
```
|
|
555
557
|
|
|
558
|
+
### 草稿箱管理
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
# 列出草稿(账号不传时使用 wx.defaultAccount)
|
|
562
|
+
bun run src/cli.ts wx-drafts --limit 10
|
|
563
|
+
|
|
564
|
+
# 获取某篇草稿的完整内容(含 HTML)
|
|
565
|
+
bun run src/cli.ts wx-drafts --media-id MEDIA_ID
|
|
566
|
+
|
|
567
|
+
# 删除一篇草稿
|
|
568
|
+
bun run src/cli.ts wx-draft-delete --media-id MEDIA_ID
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
`--account` 参数可选,默认使用配置中的 `wx.defaultAccount`。
|
|
572
|
+
|
|
573
|
+
### init 可选参数
|
|
574
|
+
|
|
575
|
+
```bash
|
|
576
|
+
# 更新已有草稿而非新建(配合 --existing-draft-media-id)
|
|
577
|
+
bun run src/cli.ts init ... --existing-draft-media-id MEDIA_ID
|
|
578
|
+
|
|
579
|
+
# 关联 Nezus note 用于发布结果回调
|
|
580
|
+
bun run src/cli.ts init ... --note-id NOTE_ID
|
|
581
|
+
```
|
|
582
|
+
|
|
556
583
|
## 状态文件
|
|
557
584
|
|
|
558
585
|
最重要的字段是:
|
package/package.json
CHANGED
package/src/commands/init.ts
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
* [--requires-research] \
|
|
17
17
|
* [--requires-style] \
|
|
18
18
|
* [--requires-render] \
|
|
19
|
-
* [--requires-publish]
|
|
19
|
+
* [--requires-publish] \
|
|
20
|
+
* [--existing-draft-media-id MEDIA_ID]
|
|
20
21
|
*
|
|
21
22
|
* Output: JSON state written to {workspace}/.zzhub-media/runs/{run_id}.json
|
|
22
23
|
* Prints the state path to stdout.
|
|
@@ -60,6 +61,7 @@ Options:
|
|
|
60
61
|
--requires-style Flag
|
|
61
62
|
--requires-render Flag
|
|
62
63
|
--requires-publish Flag
|
|
64
|
+
--existing-draft-media-id Update existing WeChat draft instead of creating new one (optional)
|
|
63
65
|
`.trim());
|
|
64
66
|
return;
|
|
65
67
|
}
|
|
@@ -72,6 +74,8 @@ Options:
|
|
|
72
74
|
const accountOverride = optionalArg(parsed, "account");
|
|
73
75
|
const styleHint = optionalArg(parsed, "style-hint") ?? null;
|
|
74
76
|
const newspicRenderSpecFile = optionalArg(parsed, "newspic-render-spec-file");
|
|
77
|
+
const existingDraftMediaId = optionalArg(parsed, "existing-draft-media-id") ?? null;
|
|
78
|
+
const noteId = optionalArg(parsed, "note-id") ?? null;
|
|
75
79
|
const config = loadConfig();
|
|
76
80
|
const workspace = resolveWorkspaceRoot(optionalArg(parsed, "workspace"), config);
|
|
77
81
|
|
|
@@ -112,6 +116,8 @@ Options:
|
|
|
112
116
|
render: flagArg(parsed, "requires-render"),
|
|
113
117
|
publish: flagArg(parsed, "requires-publish"),
|
|
114
118
|
},
|
|
119
|
+
existing_draft_media_id: existingDraftMediaId,
|
|
120
|
+
note_id: noteId,
|
|
115
121
|
};
|
|
116
122
|
|
|
117
123
|
await writeState(statePath, state);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wx-draft-delete — Delete a draft from WeChat draft box.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* zzhub-pipeline wx-draft-delete [--account <account>] --media-id <media_id>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { optionalArg, parseArgs, requireArg } from "../args";
|
|
9
|
+
import { loadConfig } from "../config";
|
|
10
|
+
import { printHelp, printResult } from "../output";
|
|
11
|
+
import { deleteWxDraft } from "../providers/wechat";
|
|
12
|
+
|
|
13
|
+
export async function wxDraftDelete(args: string[]): Promise<void> {
|
|
14
|
+
const parsed = parseArgs(args);
|
|
15
|
+
|
|
16
|
+
if (parsed.help) {
|
|
17
|
+
printHelp(`
|
|
18
|
+
Usage: zzhub-pipeline wx-draft-delete [options]
|
|
19
|
+
|
|
20
|
+
Options:
|
|
21
|
+
--account WeChat account name (defaults to wx.defaultAccount from config)
|
|
22
|
+
--media-id Draft media_id to delete (required)
|
|
23
|
+
|
|
24
|
+
Examples:
|
|
25
|
+
zzhub-pipeline wx-draft-delete --media-id MEDIA_ID
|
|
26
|
+
`.trim());
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const config = loadConfig();
|
|
31
|
+
const account = optionalArg(parsed, "account") || config.wx.defaultAccount;
|
|
32
|
+
const mediaId = requireArg(parsed, "media-id", "draft media_id to delete");
|
|
33
|
+
|
|
34
|
+
const result = await deleteWxDraft({ account, mediaId, config });
|
|
35
|
+
printResult(result);
|
|
36
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wx-drafts — List or get WeChat draft box drafts.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* zzhub-pipeline wx-drafts [--account <account>] [--limit 20] [--offset 0]
|
|
6
|
+
* zzhub-pipeline wx-drafts [--account <account>] --media-id <media_id>
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { optionalArg, parseArgs } from "../args";
|
|
10
|
+
import { loadConfig } from "../config";
|
|
11
|
+
import { printHelp, printResult } from "../output";
|
|
12
|
+
import { getWxDraft, getWxDraftList } from "../providers/wechat";
|
|
13
|
+
|
|
14
|
+
export async function wxDrafts(args: string[]): Promise<void> {
|
|
15
|
+
const parsed = parseArgs(args);
|
|
16
|
+
|
|
17
|
+
if (parsed.help) {
|
|
18
|
+
printHelp(`
|
|
19
|
+
Usage: zzhub-pipeline wx-drafts [options]
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--account WeChat account name (defaults to wx.defaultAccount from config)
|
|
23
|
+
--media-id Draft media_id to fetch a single draft (optional)
|
|
24
|
+
--limit Number of drafts to list, default 20, max 20 (optional)
|
|
25
|
+
--offset Pagination offset, default 0 (optional)
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
zzhub-pipeline wx-drafts --limit 10
|
|
29
|
+
zzhub-pipeline wx-drafts --media-id MEDIA_ID
|
|
30
|
+
`.trim());
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const config = loadConfig();
|
|
35
|
+
const account = optionalArg(parsed, "account") || config.wx.defaultAccount;
|
|
36
|
+
const mediaId = optionalArg(parsed, "media-id") ?? null;
|
|
37
|
+
const limit = optionalArg(parsed, "limit") ? Number.parseInt(optionalArg(parsed, "limit")!, 10) : undefined;
|
|
38
|
+
const offset = optionalArg(parsed, "offset") ? Number.parseInt(optionalArg(parsed, "offset")!, 10) : undefined;
|
|
39
|
+
|
|
40
|
+
if (mediaId) {
|
|
41
|
+
const result = await getWxDraft({ account, mediaId, config });
|
|
42
|
+
printResult(result);
|
|
43
|
+
} else {
|
|
44
|
+
const result = await getWxDraftList({ account, limit, offset, config });
|
|
45
|
+
printResult(result);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/plugins.ts
CHANGED
|
@@ -22,6 +22,8 @@ import { status } from "./commands/status";
|
|
|
22
22
|
import { syncBlog } from "./commands/sync-blog";
|
|
23
23
|
import { tasks } from "./commands/tasks";
|
|
24
24
|
import { wechatExport } from "./commands/wechat-export";
|
|
25
|
+
import { wxDrafts } from "./commands/wx-drafts";
|
|
26
|
+
import { wxDraftDelete } from "./commands/wx-draft-delete";
|
|
25
27
|
|
|
26
28
|
export interface CommandDefinition {
|
|
27
29
|
name: string;
|
|
@@ -69,6 +71,8 @@ export function getCommandPlugins(): CommandPlugin[] {
|
|
|
69
71
|
{ name: "config", summary: "Read or update pipeline config", plugin: "ops", handler: configCommand },
|
|
70
72
|
{ name: "doctor", summary: "Inspect resolved paths and provider health", plugin: "ops", handler: doctor },
|
|
71
73
|
{ name: "hermes-metrics", summary: "Show Hermes execution metrics per task", plugin: "ops", handler: hermesMetrics },
|
|
74
|
+
{ name: "wx-drafts", summary: "List or get drafts from WeChat draft box", plugin: "ops", handler: wxDrafts },
|
|
75
|
+
{ name: "wx-draft-delete", summary: "Delete a draft from WeChat draft box", plugin: "ops", handler: wxDraftDelete },
|
|
72
76
|
],
|
|
73
77
|
},
|
|
74
78
|
];
|
package/src/providers/index.ts
CHANGED
|
@@ -80,6 +80,10 @@ async function publishWechatArticleRoute({
|
|
|
80
80
|
html,
|
|
81
81
|
photos,
|
|
82
82
|
config,
|
|
83
|
+
existingDraftMediaId: state.intent.existing_draft_media_id,
|
|
84
|
+
noteId: state.intent.note_id,
|
|
85
|
+
nezusBaseUrl: process.env.ZZHUB_WX_BASE_URL || config.wx.baseUrl,
|
|
86
|
+
nezusPat: process.env.ZZCLUB_PAT || config.wx.accounts[state.route.account]?.pat || config.wx.accounts[config.wx.defaultAccount]?.pat,
|
|
83
87
|
});
|
|
84
88
|
} catch (error) {
|
|
85
89
|
return {
|
|
@@ -145,6 +149,10 @@ async function publishWechatNewspicRoute({
|
|
|
145
149
|
content: cleanContent,
|
|
146
150
|
photos,
|
|
147
151
|
config,
|
|
152
|
+
existingDraftMediaId: state.intent.existing_draft_media_id,
|
|
153
|
+
noteId: state.intent.note_id,
|
|
154
|
+
nezusBaseUrl: process.env.ZZHUB_WX_BASE_URL || config.wx.baseUrl,
|
|
155
|
+
nezusPat: process.env.ZZCLUB_PAT || config.wx.accounts[state.route.account]?.pat || config.wx.accounts[config.wx.defaultAccount]?.pat,
|
|
148
156
|
});
|
|
149
157
|
} catch (error) {
|
|
150
158
|
return {
|
package/src/providers/wechat.ts
CHANGED
|
@@ -4,7 +4,11 @@ import { PipelineConfig, WxAccountConfig } from "../config";
|
|
|
4
4
|
|
|
5
5
|
const TOKEN_PATH = "/api/v1/wx/cgi-bin/token";
|
|
6
6
|
const MATERIAL_PATH = "/api/v1/wx/cgi-bin/material/add_material";
|
|
7
|
-
const
|
|
7
|
+
const DRAFT_ADD_PATH = "/api/v1/wx/cgi-bin/draft/add";
|
|
8
|
+
const DRAFT_UPDATE_PATH = "/api/v1/wx/cgi-bin/draft/update";
|
|
9
|
+
const DRAFT_GET_PATH = "/api/v1/wx/cgi-bin/draft/get";
|
|
10
|
+
const DRAFT_DELETE_PATH = "/api/v1/wx/cgi-bin/draft/delete";
|
|
11
|
+
const BATCH_GET_PATH = "/api/v1/wx/cgi-bin/draft/batchget";
|
|
8
12
|
const TOKEN_TIMEOUT = 10000;
|
|
9
13
|
const UPLOAD_TIMEOUT = 60000;
|
|
10
14
|
const DRAFT_TIMEOUT = 30000;
|
|
@@ -78,14 +82,19 @@ interface BaseWechatPublishInput {
|
|
|
78
82
|
photos?: string[];
|
|
79
83
|
timeout?: number;
|
|
80
84
|
config: PipelineConfig;
|
|
85
|
+
noteId?: string | null;
|
|
86
|
+
nezusBaseUrl?: string | null;
|
|
87
|
+
nezusPat?: string | null;
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
export interface WechatDraftInput extends BaseWechatPublishInput {
|
|
84
91
|
html: string;
|
|
92
|
+
existingDraftMediaId?: string | null;
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
export interface WechatNewspicInput extends BaseWechatPublishInput {
|
|
88
96
|
content: string;
|
|
97
|
+
existingDraftMediaId?: string | null;
|
|
89
98
|
}
|
|
90
99
|
|
|
91
100
|
function requireValue(name: string, value: string | undefined): string {
|
|
@@ -459,15 +468,21 @@ export async function createWechatDraft(input: WechatDraftInput): Promise<Record
|
|
|
459
468
|
const uploadResult = await uploadPhotos(runtime, accessToken, finalPhotos, uploadTimeout);
|
|
460
469
|
const replacedHtml = replaceImageUrls(input.html, uploadResult.imageUrlMap);
|
|
461
470
|
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
+
const isUpdate = !!input.existingDraftMediaId;
|
|
472
|
+
const draftPath = isUpdate ? DRAFT_UPDATE_PATH : DRAFT_ADD_PATH;
|
|
473
|
+
const draftBody = isUpdate
|
|
474
|
+
? {
|
|
475
|
+
access_token: accessToken,
|
|
476
|
+
media_id: input.existingDraftMediaId,
|
|
477
|
+
index: 0,
|
|
478
|
+
articles: {
|
|
479
|
+
article_type: "news",
|
|
480
|
+
title: input.title,
|
|
481
|
+
content: replacedHtml,
|
|
482
|
+
thumb_media_id: uploadResult.coverMediaId,
|
|
483
|
+
},
|
|
484
|
+
}
|
|
485
|
+
: {
|
|
471
486
|
access_token: accessToken,
|
|
472
487
|
articles: [
|
|
473
488
|
{
|
|
@@ -477,11 +492,34 @@ export async function createWechatDraft(input: WechatDraftInput): Promise<Record
|
|
|
477
492
|
thumb_media_id: uploadResult.coverMediaId,
|
|
478
493
|
},
|
|
479
494
|
],
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
const response = await requestJson(
|
|
498
|
+
`${runtime.baseUrl}${draftPath}`,
|
|
499
|
+
{
|
|
500
|
+
method: "POST",
|
|
501
|
+
headers: {
|
|
502
|
+
"Content-Type": "application/json",
|
|
503
|
+
Authorization: `Bearer ${runtime.pat}`,
|
|
480
504
|
},
|
|
505
|
+
body: draftBody,
|
|
481
506
|
},
|
|
482
507
|
draftTimeout,
|
|
483
508
|
);
|
|
484
509
|
|
|
510
|
+
const draftMediaId = isUpdate ? input.existingDraftMediaId : (response as any)?.data?.media_id || (response as any)?.media_id || null;
|
|
511
|
+
|
|
512
|
+
// ── Callback to Nezus to persist media_id ──
|
|
513
|
+
if (draftMediaId && input.noteId && input.nezusBaseUrl && input.nezusPat) {
|
|
514
|
+
await notifyNezusPublishResult({
|
|
515
|
+
nezusBaseUrl: input.nezusBaseUrl,
|
|
516
|
+
nezusPat: input.nezusPat,
|
|
517
|
+
noteId: input.noteId,
|
|
518
|
+
wechatMediaId: draftMediaId,
|
|
519
|
+
publishType: "article",
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
485
523
|
return {
|
|
486
524
|
account: runtime.accountName,
|
|
487
525
|
articleType: "news",
|
|
@@ -489,6 +527,8 @@ export async function createWechatDraft(input: WechatDraftInput): Promise<Record
|
|
|
489
527
|
photosCount: finalPhotos.length,
|
|
490
528
|
totalUploaded: uploadResult.totalUploaded,
|
|
491
529
|
coverMediaId: uploadResult.coverMediaId,
|
|
530
|
+
isUpdate,
|
|
531
|
+
draftMediaId,
|
|
492
532
|
response,
|
|
493
533
|
};
|
|
494
534
|
}
|
|
@@ -512,15 +552,22 @@ export async function createWechatNewspic(input: WechatNewspicInput): Promise<Re
|
|
|
512
552
|
image_list: uploadResult.uploadedMedia.map((item) => ({ image_media_id: item.mediaId })),
|
|
513
553
|
};
|
|
514
554
|
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
555
|
+
const isUpdate = !!input.existingDraftMediaId;
|
|
556
|
+
const draftPath = isUpdate ? DRAFT_UPDATE_PATH : DRAFT_ADD_PATH;
|
|
557
|
+
const draftBody = isUpdate
|
|
558
|
+
? {
|
|
559
|
+
access_token: accessToken,
|
|
560
|
+
media_id: input.existingDraftMediaId,
|
|
561
|
+
index: 0,
|
|
562
|
+
articles: {
|
|
563
|
+
article_type: "newspic",
|
|
564
|
+
title: input.title,
|
|
565
|
+
content: input.content,
|
|
566
|
+
thumb_media_id: uploadResult.coverMediaId,
|
|
567
|
+
image_info: imageInfo,
|
|
568
|
+
},
|
|
569
|
+
}
|
|
570
|
+
: {
|
|
524
571
|
access_token: accessToken,
|
|
525
572
|
articles: [
|
|
526
573
|
{
|
|
@@ -531,11 +578,34 @@ export async function createWechatNewspic(input: WechatNewspicInput): Promise<Re
|
|
|
531
578
|
image_info: imageInfo,
|
|
532
579
|
},
|
|
533
580
|
],
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
const response = await requestJson(
|
|
584
|
+
`${runtime.baseUrl}${draftPath}`,
|
|
585
|
+
{
|
|
586
|
+
method: "POST",
|
|
587
|
+
headers: {
|
|
588
|
+
"Content-Type": "application/json",
|
|
589
|
+
Authorization: `Bearer ${runtime.pat}`,
|
|
534
590
|
},
|
|
591
|
+
body: draftBody,
|
|
535
592
|
},
|
|
536
593
|
draftTimeout,
|
|
537
594
|
);
|
|
538
595
|
|
|
596
|
+
const draftMediaId = isUpdate ? input.existingDraftMediaId : (response as any)?.data?.media_id || (response as any)?.media_id || null;
|
|
597
|
+
|
|
598
|
+
// ── Callback to Nezus to persist media_id ──
|
|
599
|
+
if (draftMediaId && input.noteId && input.nezusBaseUrl && input.nezusPat) {
|
|
600
|
+
await notifyNezusPublishResult({
|
|
601
|
+
nezusBaseUrl: input.nezusBaseUrl,
|
|
602
|
+
nezusPat: input.nezusPat,
|
|
603
|
+
noteId: input.noteId,
|
|
604
|
+
wechatMediaId: draftMediaId,
|
|
605
|
+
publishType: "newspic",
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
|
|
539
609
|
return {
|
|
540
610
|
account: runtime.accountName,
|
|
541
611
|
articleType: "newspic",
|
|
@@ -543,6 +613,146 @@ export async function createWechatNewspic(input: WechatNewspicInput): Promise<Re
|
|
|
543
613
|
photosCount: finalPhotos.length,
|
|
544
614
|
totalUploaded: uploadResult.totalUploaded,
|
|
545
615
|
coverMediaId: uploadResult.coverMediaId,
|
|
616
|
+
isUpdate,
|
|
617
|
+
draftMediaId,
|
|
618
|
+
response,
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// ── Nezus callback ────────────────────────────────────────────────
|
|
623
|
+
|
|
624
|
+
async function notifyNezusPublishResult(params: {
|
|
625
|
+
nezusBaseUrl: string;
|
|
626
|
+
nezusPat: string;
|
|
627
|
+
noteId: string;
|
|
628
|
+
wechatMediaId: string;
|
|
629
|
+
publishType: string;
|
|
630
|
+
}): Promise<void> {
|
|
631
|
+
try {
|
|
632
|
+
await requestJson(
|
|
633
|
+
`${params.nezusBaseUrl}/api/v1/notes/${params.noteId}/publish-result`,
|
|
634
|
+
{
|
|
635
|
+
method: "POST",
|
|
636
|
+
headers: {
|
|
637
|
+
"Content-Type": "application/json",
|
|
638
|
+
Authorization: `Bearer ${params.nezusPat}`,
|
|
639
|
+
},
|
|
640
|
+
body: {
|
|
641
|
+
wechatMediaId: params.wechatMediaId,
|
|
642
|
+
publishType: params.publishType,
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
10000,
|
|
646
|
+
);
|
|
647
|
+
console.error(`[nezus] publish-result callback OK for note ${params.noteId}`);
|
|
648
|
+
} catch (err) {
|
|
649
|
+
// Non-fatal: the draft was created successfully even if the callback failed
|
|
650
|
+
console.error(`[nezus] publish-result callback failed for note ${params.noteId}:`, err);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// ── Draft management ──────────────────────────────────────────────
|
|
655
|
+
|
|
656
|
+
export interface WxDraftListInput {
|
|
657
|
+
account?: string;
|
|
658
|
+
limit?: number;
|
|
659
|
+
offset?: number;
|
|
660
|
+
config: PipelineConfig;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export interface WxDraftGetInput {
|
|
664
|
+
account?: string;
|
|
665
|
+
mediaId: string;
|
|
666
|
+
config: PipelineConfig;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
export interface WxDraftDeleteInput {
|
|
670
|
+
account?: string;
|
|
671
|
+
mediaId: string;
|
|
672
|
+
config: PipelineConfig;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
export async function getWxDraftList(input: WxDraftListInput): Promise<Record<string, unknown>> {
|
|
676
|
+
const runtime = getWxRuntimeConfig(input.config, input.account);
|
|
677
|
+
const tokenTimeout = resolveTimeout(TOKEN_TIMEOUT, runtime.timeout);
|
|
678
|
+
const accessToken = await fetchAccessToken(runtime, tokenTimeout);
|
|
679
|
+
|
|
680
|
+
const response = await requestJson(
|
|
681
|
+
`${runtime.baseUrl}${BATCH_GET_PATH}`,
|
|
682
|
+
{
|
|
683
|
+
method: "POST",
|
|
684
|
+
headers: {
|
|
685
|
+
"Content-Type": "application/json",
|
|
686
|
+
Authorization: `Bearer ${runtime.pat}`,
|
|
687
|
+
},
|
|
688
|
+
body: {
|
|
689
|
+
access_token: accessToken,
|
|
690
|
+
offset: input.offset ?? 0,
|
|
691
|
+
count: input.limit ?? 20,
|
|
692
|
+
no_content: true,
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
resolveTimeout(30000, runtime.timeout),
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
return {
|
|
699
|
+
account: runtime.accountName,
|
|
700
|
+
response,
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
export async function getWxDraft(input: WxDraftGetInput): Promise<Record<string, unknown>> {
|
|
705
|
+
const runtime = getWxRuntimeConfig(input.config, input.account);
|
|
706
|
+
const tokenTimeout = resolveTimeout(TOKEN_TIMEOUT, runtime.timeout);
|
|
707
|
+
const accessToken = await fetchAccessToken(runtime, tokenTimeout);
|
|
708
|
+
|
|
709
|
+
const response = await requestJson(
|
|
710
|
+
`${runtime.baseUrl}${DRAFT_GET_PATH}`,
|
|
711
|
+
{
|
|
712
|
+
method: "POST",
|
|
713
|
+
headers: {
|
|
714
|
+
"Content-Type": "application/json",
|
|
715
|
+
Authorization: `Bearer ${runtime.pat}`,
|
|
716
|
+
},
|
|
717
|
+
body: {
|
|
718
|
+
access_token: accessToken,
|
|
719
|
+
media_id: input.mediaId,
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
resolveTimeout(30000, runtime.timeout),
|
|
723
|
+
);
|
|
724
|
+
|
|
725
|
+
return {
|
|
726
|
+
account: runtime.accountName,
|
|
727
|
+
mediaId: input.mediaId,
|
|
728
|
+
response,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
export async function deleteWxDraft(input: WxDraftDeleteInput): Promise<Record<string, unknown>> {
|
|
733
|
+
const runtime = getWxRuntimeConfig(input.config, input.account);
|
|
734
|
+
const tokenTimeout = resolveTimeout(TOKEN_TIMEOUT, runtime.timeout);
|
|
735
|
+
const accessToken = await fetchAccessToken(runtime, tokenTimeout);
|
|
736
|
+
|
|
737
|
+
const response = await requestJson(
|
|
738
|
+
`${runtime.baseUrl}${DRAFT_DELETE_PATH}`,
|
|
739
|
+
{
|
|
740
|
+
method: "POST",
|
|
741
|
+
headers: {
|
|
742
|
+
"Content-Type": "application/json",
|
|
743
|
+
Authorization: `Bearer ${runtime.pat}`,
|
|
744
|
+
},
|
|
745
|
+
body: {
|
|
746
|
+
access_token: accessToken,
|
|
747
|
+
media_id: input.mediaId,
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
resolveTimeout(30000, runtime.timeout),
|
|
751
|
+
);
|
|
752
|
+
|
|
753
|
+
return {
|
|
754
|
+
account: runtime.accountName,
|
|
755
|
+
mediaId: input.mediaId,
|
|
546
756
|
response,
|
|
547
757
|
};
|
|
548
758
|
}
|
package/src/schema/state.ts
CHANGED
|
@@ -303,6 +303,8 @@ const IntentSchema = withObjectDefault(
|
|
|
303
303
|
style_hint: z.string().nullable().default(null),
|
|
304
304
|
newspic_render: NewspicRenderSpecSchema.nullable().default(null),
|
|
305
305
|
requires: IntentRequiresSchema,
|
|
306
|
+
existing_draft_media_id: z.string().nullable().default(null),
|
|
307
|
+
note_id: z.string().nullable().default(null),
|
|
306
308
|
}),
|
|
307
309
|
);
|
|
308
310
|
|