@pawastation/wechat-kf 0.1.2 → 0.2.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 +34 -28
- package/README.zh-CN.md +34 -28
- package/dist/index.d.ts +5 -15
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/src/accounts.d.ts +2 -1
- package/dist/src/accounts.js +61 -19
- package/dist/src/accounts.js.map +1 -1
- package/dist/src/api.d.ts +31 -2
- package/dist/src/api.js +41 -13
- package/dist/src/api.js.map +1 -1
- package/dist/src/bot.d.ts +10 -8
- package/dist/src/bot.js +232 -79
- package/dist/src/bot.js.map +1 -1
- package/dist/src/channel.d.ts +7 -106
- package/dist/src/channel.js +208 -71
- package/dist/src/channel.js.map +1 -1
- package/dist/src/config-schema.d.ts +0 -6
- package/dist/src/config-schema.js +2 -7
- package/dist/src/config-schema.js.map +1 -1
- package/dist/src/constants.d.ts +20 -0
- package/dist/src/constants.js +29 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/crypto.js +7 -6
- package/dist/src/crypto.js.map +1 -1
- package/dist/src/monitor.d.ts +27 -14
- package/dist/src/monitor.js +67 -120
- package/dist/src/monitor.js.map +1 -1
- package/dist/src/outbound.d.ts +10 -44
- package/dist/src/outbound.js +277 -92
- package/dist/src/outbound.js.map +1 -1
- package/dist/src/reply-dispatcher.d.ts +2 -6
- package/dist/src/reply-dispatcher.js +131 -32
- package/dist/src/reply-dispatcher.js.map +1 -1
- package/dist/src/runtime.d.ts +1 -119
- package/dist/src/runtime.js +2 -1
- package/dist/src/runtime.js.map +1 -1
- package/dist/src/send-utils.d.ts +13 -0
- package/dist/src/send-utils.js +56 -4
- package/dist/src/send-utils.js.map +1 -1
- package/dist/src/token.js +7 -3
- package/dist/src/token.js.map +1 -1
- package/dist/src/types.d.ts +68 -6
- package/dist/src/webhook.d.ts +16 -16
- package/dist/src/webhook.js +92 -75
- package/dist/src/webhook.js.map +1 -1
- package/dist/src/wechat-kf-directives.d.ts +132 -9
- package/dist/src/wechat-kf-directives.js +535 -24
- package/dist/src/wechat-kf-directives.js.map +1 -1
- package/openclaw.plugin.json +1 -3
- package/package.json +4 -4
- package/dist/src/chunk-utils.d.ts +0 -18
- package/dist/src/chunk-utils.js +0 -58
- package/dist/src/chunk-utils.js.map +0 -1
- package/index.ts +0 -32
|
@@ -18,68 +18,61 @@
|
|
|
18
18
|
*
|
|
19
19
|
* accountId = openKfId (dynamically discovered)
|
|
20
20
|
*/
|
|
21
|
-
import { readFile } from "node:fs/promises";
|
|
22
|
-
import { basename, extname } from "node:path";
|
|
23
21
|
import { resolveAccount } from "./accounts.js";
|
|
24
|
-
import { sendLinkMessage, sendTextMessage,
|
|
25
|
-
import { WECHAT_TEXT_CHUNK_LIMIT } from "./constants.js";
|
|
22
|
+
import { sendBusinessCardMessage, sendCaLinkMessage, sendLinkMessage, sendLocationMessage, sendMiniprogramMessage, sendMsgMenuMessage, sendRawMessage, sendTextMessage, } from "./api.js";
|
|
23
|
+
import { CHANNEL_ID, logTag, WECHAT_TEXT_CHUNK_LIMIT } from "./constants.js";
|
|
26
24
|
import { getRuntime } from "./runtime.js";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
25
|
+
import { formatText, mediaKindToWechatType, resolveThumbMediaId, uploadAndSendMedia } from "./send-utils.js";
|
|
26
|
+
import { buildMsgMenuPayload, parseWechatDirective } from "./wechat-kf-directives.js";
|
|
29
27
|
export function createReplyDispatcher(params) {
|
|
30
28
|
const core = getRuntime();
|
|
31
29
|
const { cfg, agentId, externalUserId, openKfId, accountId } = params;
|
|
32
30
|
const account = resolveAccount(cfg, accountId);
|
|
33
31
|
const kfId = openKfId; // accountId IS the kfid
|
|
34
|
-
const textChunkLimit = core.channel.text.resolveTextChunkLimit(cfg,
|
|
32
|
+
const textChunkLimit = core.channel.text.resolveTextChunkLimit(cfg, CHANNEL_ID, accountId, {
|
|
35
33
|
fallbackLimit: WECHAT_TEXT_CHUNK_LIMIT,
|
|
36
34
|
});
|
|
37
|
-
const chunkMode = core.channel.text.resolveChunkMode(cfg,
|
|
35
|
+
const chunkMode = core.channel.text.resolveChunkMode(cfg, CHANNEL_ID);
|
|
38
36
|
const { dispatcher, replyOptions, markDispatchIdle } = core.channel.reply.createReplyDispatcherWithTyping({
|
|
39
37
|
humanDelay: core.channel.reply.resolveHumanDelayConfig(cfg, agentId),
|
|
40
38
|
deliver: async (payload) => {
|
|
41
39
|
const text = payload.text ?? "";
|
|
42
|
-
const
|
|
40
|
+
const mediaUrls = payload.mediaUrls ?? (payload.mediaUrl ? [payload.mediaUrl] : []);
|
|
43
41
|
const { corpId, appSecret } = account;
|
|
44
42
|
if (!corpId || !appSecret) {
|
|
45
|
-
throw new Error(
|
|
43
|
+
throw new Error(`${logTag()} missing corpId/appSecret for send`);
|
|
46
44
|
}
|
|
47
|
-
// Handle media
|
|
48
|
-
for (const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
params.runtime?.error?.(`[wechat-kf] failed to send ${attachment.type ?? "media"} attachment: ${String(err)}`);
|
|
59
|
-
}
|
|
45
|
+
// Handle media (image, voice, video, file) via framework loadWebMedia
|
|
46
|
+
for (const url of mediaUrls) {
|
|
47
|
+
try {
|
|
48
|
+
const loaded = await core.media.loadWebMedia(url, { optimizeImages: false });
|
|
49
|
+
const mediaType = mediaKindToWechatType(loaded.kind);
|
|
50
|
+
await uploadAndSendMedia(corpId, appSecret, externalUserId, kfId, loaded.buffer, loaded.fileName ?? "file", mediaType);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
params.runtime?.error?.(`${logTag()} failed to send media: ${String(err)}`);
|
|
60
54
|
}
|
|
61
55
|
}
|
|
62
|
-
// ── Intercept [[
|
|
63
|
-
// Parse on raw text so
|
|
56
|
+
// ── Intercept [[wechat_*:...]] directives BEFORE formatText ──
|
|
57
|
+
// Parse on raw text so fields stay clean (formatText would
|
|
64
58
|
// convert markdown inside the directive to unicode characters).
|
|
65
59
|
if (text.trim()) {
|
|
66
|
-
const directive =
|
|
60
|
+
const directive = parseWechatDirective(text);
|
|
67
61
|
if (directive.link) {
|
|
68
62
|
let linkSent = false;
|
|
69
63
|
if (directive.link.thumbUrl) {
|
|
70
64
|
try {
|
|
71
|
-
const
|
|
72
|
-
const uploaded = await uploadMedia(corpId, appSecret, "image", downloaded.buffer, downloaded.filename);
|
|
65
|
+
const thumbMediaId = await resolveThumbMediaId(directive.link.thumbUrl, corpId, appSecret);
|
|
73
66
|
await sendLinkMessage(corpId, appSecret, externalUserId, kfId, {
|
|
74
67
|
title: directive.link.title,
|
|
75
68
|
desc: directive.link.desc,
|
|
76
69
|
url: directive.link.url,
|
|
77
|
-
thumb_media_id:
|
|
70
|
+
thumb_media_id: thumbMediaId,
|
|
78
71
|
});
|
|
79
72
|
linkSent = true;
|
|
80
73
|
}
|
|
81
74
|
catch (err) {
|
|
82
|
-
params.runtime?.error?.(
|
|
75
|
+
params.runtime?.error?.(`${logTag()} failed to send link card: ${String(err)}`);
|
|
83
76
|
}
|
|
84
77
|
}
|
|
85
78
|
// Send remaining text (or fallback with title:url if link card failed / no thumbUrl)
|
|
@@ -96,6 +89,112 @@ export function createReplyDispatcher(params) {
|
|
|
96
89
|
}
|
|
97
90
|
}
|
|
98
91
|
}
|
|
92
|
+
else if (directive.location) {
|
|
93
|
+
try {
|
|
94
|
+
await sendLocationMessage(corpId, appSecret, externalUserId, kfId, directive.location);
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
params.runtime?.error?.(`${logTag()} failed to send location: ${String(err)}`);
|
|
98
|
+
}
|
|
99
|
+
if (directive.text?.trim()) {
|
|
100
|
+
const formatted = formatText(directive.text);
|
|
101
|
+
const chunks = core.channel.text.chunkTextWithMode(formatted, textChunkLimit, chunkMode);
|
|
102
|
+
for (const chunk of chunks) {
|
|
103
|
+
await sendTextMessage(corpId, appSecret, externalUserId, kfId, chunk);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (directive.miniprogram) {
|
|
108
|
+
let mpSent = false;
|
|
109
|
+
if (directive.miniprogram.thumbUrl) {
|
|
110
|
+
try {
|
|
111
|
+
const thumbMediaId = await resolveThumbMediaId(directive.miniprogram.thumbUrl, corpId, appSecret);
|
|
112
|
+
await sendMiniprogramMessage(corpId, appSecret, externalUserId, kfId, {
|
|
113
|
+
appid: directive.miniprogram.appid,
|
|
114
|
+
title: directive.miniprogram.title,
|
|
115
|
+
pagepath: directive.miniprogram.pagepath,
|
|
116
|
+
thumb_media_id: thumbMediaId,
|
|
117
|
+
});
|
|
118
|
+
mpSent = true;
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
params.runtime?.error?.(`${logTag()} failed to send miniprogram: ${String(err)}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const rawRemaining = mpSent
|
|
125
|
+
? directive.text
|
|
126
|
+
: directive.text
|
|
127
|
+
? `${directive.text}\n[小程序] ${directive.miniprogram.title}`
|
|
128
|
+
: `[小程序] ${directive.miniprogram.title}`;
|
|
129
|
+
if (rawRemaining?.trim()) {
|
|
130
|
+
const formatted = formatText(rawRemaining);
|
|
131
|
+
const chunks = core.channel.text.chunkTextWithMode(formatted, textChunkLimit, chunkMode);
|
|
132
|
+
for (const chunk of chunks) {
|
|
133
|
+
await sendTextMessage(corpId, appSecret, externalUserId, kfId, chunk);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (directive.menu) {
|
|
138
|
+
try {
|
|
139
|
+
const menuPayload = buildMsgMenuPayload(directive.menu);
|
|
140
|
+
await sendMsgMenuMessage(corpId, appSecret, externalUserId, kfId, menuPayload);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
params.runtime?.error?.(`${logTag()} failed to send menu: ${String(err)}`);
|
|
144
|
+
}
|
|
145
|
+
if (directive.text?.trim()) {
|
|
146
|
+
const formatted = formatText(directive.text);
|
|
147
|
+
const chunks = core.channel.text.chunkTextWithMode(formatted, textChunkLimit, chunkMode);
|
|
148
|
+
for (const chunk of chunks) {
|
|
149
|
+
await sendTextMessage(corpId, appSecret, externalUserId, kfId, chunk);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (directive.businessCard) {
|
|
154
|
+
try {
|
|
155
|
+
await sendBusinessCardMessage(corpId, appSecret, externalUserId, kfId, directive.businessCard);
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
params.runtime?.error?.(`${logTag()} failed to send business card: ${String(err)}`);
|
|
159
|
+
}
|
|
160
|
+
if (directive.text?.trim()) {
|
|
161
|
+
const formatted = formatText(directive.text);
|
|
162
|
+
const chunks = core.channel.text.chunkTextWithMode(formatted, textChunkLimit, chunkMode);
|
|
163
|
+
for (const chunk of chunks) {
|
|
164
|
+
await sendTextMessage(corpId, appSecret, externalUserId, kfId, chunk);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (directive.caLink) {
|
|
169
|
+
try {
|
|
170
|
+
await sendCaLinkMessage(corpId, appSecret, externalUserId, kfId, directive.caLink);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
params.runtime?.error?.(`${logTag()} failed to send ca_link: ${String(err)}`);
|
|
174
|
+
}
|
|
175
|
+
if (directive.text?.trim()) {
|
|
176
|
+
const formatted = formatText(directive.text);
|
|
177
|
+
const chunks = core.channel.text.chunkTextWithMode(formatted, textChunkLimit, chunkMode);
|
|
178
|
+
for (const chunk of chunks) {
|
|
179
|
+
await sendTextMessage(corpId, appSecret, externalUserId, kfId, chunk);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
else if (directive.raw) {
|
|
184
|
+
try {
|
|
185
|
+
await sendRawMessage(corpId, appSecret, externalUserId, kfId, directive.raw.msgtype, directive.raw.payload);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
params.runtime?.error?.(`${logTag()} failed to send raw message: ${String(err)}`);
|
|
189
|
+
}
|
|
190
|
+
if (directive.text?.trim()) {
|
|
191
|
+
const formatted = formatText(directive.text);
|
|
192
|
+
const chunks = core.channel.text.chunkTextWithMode(formatted, textChunkLimit, chunkMode);
|
|
193
|
+
for (const chunk of chunks) {
|
|
194
|
+
await sendTextMessage(corpId, appSecret, externalUserId, kfId, chunk);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
99
198
|
else {
|
|
100
199
|
// No directive — normal path: formatText then chunk and send
|
|
101
200
|
const formatted = formatText(text);
|
|
@@ -107,12 +206,12 @@ export function createReplyDispatcher(params) {
|
|
|
107
206
|
}
|
|
108
207
|
}
|
|
109
208
|
}
|
|
110
|
-
if (!text.trim() &&
|
|
209
|
+
if (!text.trim() && mediaUrls.length === 0) {
|
|
111
210
|
return;
|
|
112
211
|
}
|
|
113
212
|
},
|
|
114
213
|
onError: (err, info) => {
|
|
115
|
-
params.runtime?.error?.(
|
|
214
|
+
params.runtime?.error?.(`${logTag()} ${info?.kind ?? "unknown"} reply failed: ${String(err)}`);
|
|
116
215
|
},
|
|
117
216
|
});
|
|
118
217
|
return { dispatcher, replyOptions, markDispatchIdle };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reply-dispatcher.js","sourceRoot":"","sources":["../../src/reply-dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;
|
|
1
|
+
{"version":3,"file":"reply-dispatcher.js","sourceRoot":"","sources":["../../src/reply-dispatcher.ts"],"names":[],"mappings":"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"}
|
package/dist/src/runtime.d.ts
CHANGED
|
@@ -2,125 +2,7 @@
|
|
|
2
2
|
* Plugin runtime reference
|
|
3
3
|
* Stores the PluginRuntime provided by OpenClaw gateway at startup.
|
|
4
4
|
*/
|
|
5
|
-
import type {
|
|
6
|
-
export type SaveMediaResult = {
|
|
7
|
-
path: string;
|
|
8
|
-
};
|
|
9
|
-
export type AgentRoute = {
|
|
10
|
-
sessionKey: string;
|
|
11
|
-
agentId: string;
|
|
12
|
-
};
|
|
13
|
-
export type ResolveAgentRouteOpts = {
|
|
14
|
-
cfg: OpenClawConfig;
|
|
15
|
-
channel: string;
|
|
16
|
-
accountId: string;
|
|
17
|
-
peer: {
|
|
18
|
-
kind: string;
|
|
19
|
-
id: string;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
export type EnvelopeFormatOptions = Record<string, unknown>;
|
|
23
|
-
export type FormatAgentEnvelopeOpts = {
|
|
24
|
-
channel: string;
|
|
25
|
-
from: string;
|
|
26
|
-
timestamp: Date;
|
|
27
|
-
envelope: EnvelopeFormatOptions;
|
|
28
|
-
body: string;
|
|
29
|
-
};
|
|
30
|
-
export type InboundContext = Record<string, unknown>;
|
|
31
|
-
export type FinalizeInboundContextOpts = {
|
|
32
|
-
Body: string;
|
|
33
|
-
RawBody: string;
|
|
34
|
-
CommandBody: string;
|
|
35
|
-
From: string;
|
|
36
|
-
To: string;
|
|
37
|
-
SessionKey: string;
|
|
38
|
-
AccountId: string;
|
|
39
|
-
ChatType: string;
|
|
40
|
-
SenderName: string;
|
|
41
|
-
SenderId: string;
|
|
42
|
-
Provider: string;
|
|
43
|
-
Surface: string;
|
|
44
|
-
MessageSid: string;
|
|
45
|
-
Timestamp: number;
|
|
46
|
-
WasMentioned: boolean;
|
|
47
|
-
CommandAuthorized: boolean;
|
|
48
|
-
OriginatingChannel: string;
|
|
49
|
-
OriginatingTo: string;
|
|
50
|
-
MediaPaths?: string[];
|
|
51
|
-
MediaTypes?: string[];
|
|
52
|
-
};
|
|
53
|
-
export type HumanDelayConfig = Record<string, unknown>;
|
|
54
|
-
export type ReplyPayload = {
|
|
55
|
-
text?: string;
|
|
56
|
-
attachments?: Array<{
|
|
57
|
-
path?: string;
|
|
58
|
-
type?: string;
|
|
59
|
-
url?: string;
|
|
60
|
-
}>;
|
|
61
|
-
};
|
|
62
|
-
export type ReplyErrorInfo = {
|
|
63
|
-
kind?: string;
|
|
64
|
-
};
|
|
65
|
-
export type ReplyDispatcherResult = {
|
|
66
|
-
dispatcher?: unknown;
|
|
67
|
-
replyOptions?: unknown;
|
|
68
|
-
markDispatchIdle?: () => void;
|
|
69
|
-
};
|
|
70
|
-
export type DispatchReplyResult = {
|
|
71
|
-
queuedFinal?: boolean;
|
|
72
|
-
counts?: {
|
|
73
|
-
final?: number;
|
|
74
|
-
};
|
|
75
|
-
};
|
|
76
|
-
export type SystemEventOpts = {
|
|
77
|
-
sessionKey: string;
|
|
78
|
-
contextKey: string;
|
|
79
|
-
};
|
|
80
|
-
export type ChunkMode = "length" | "newline";
|
|
81
|
-
export interface PluginRuntime {
|
|
82
|
-
channel: {
|
|
83
|
-
media: {
|
|
84
|
-
saveMediaBuffer: (buffer: Buffer, mimeType: string, direction: string, opts: unknown | undefined, filename: string) => Promise<SaveMediaResult>;
|
|
85
|
-
};
|
|
86
|
-
routing: {
|
|
87
|
-
resolveAgentRoute: (opts: ResolveAgentRouteOpts) => AgentRoute;
|
|
88
|
-
};
|
|
89
|
-
reply: {
|
|
90
|
-
resolveEnvelopeFormatOptions: (cfg: OpenClawConfig) => EnvelopeFormatOptions;
|
|
91
|
-
formatAgentEnvelope: (opts: FormatAgentEnvelopeOpts) => string;
|
|
92
|
-
finalizeInboundContext: (opts: FinalizeInboundContextOpts) => InboundContext;
|
|
93
|
-
createReplyDispatcherWithTyping: (opts: {
|
|
94
|
-
humanDelay: HumanDelayConfig;
|
|
95
|
-
deliver: (payload: ReplyPayload) => Promise<void>;
|
|
96
|
-
onError: (err: unknown, info: ReplyErrorInfo) => void;
|
|
97
|
-
}) => ReplyDispatcherResult;
|
|
98
|
-
dispatchReplyFromConfig: (opts: {
|
|
99
|
-
ctx: InboundContext;
|
|
100
|
-
cfg: OpenClawConfig;
|
|
101
|
-
dispatcher: unknown;
|
|
102
|
-
replyOptions: unknown;
|
|
103
|
-
}) => Promise<DispatchReplyResult>;
|
|
104
|
-
resolveHumanDelayConfig: (cfg: OpenClawConfig, agentId: string) => HumanDelayConfig;
|
|
105
|
-
};
|
|
106
|
-
text: {
|
|
107
|
-
resolveTextChunkLimit: (cfg: OpenClawConfig, channel: string, accountId: string, opts: {
|
|
108
|
-
fallbackLimit: number;
|
|
109
|
-
}) => number;
|
|
110
|
-
resolveChunkMode: (cfg: OpenClawConfig, channel: string) => ChunkMode;
|
|
111
|
-
chunkTextWithMode: (text: string, limit: number, mode: ChunkMode) => string[];
|
|
112
|
-
};
|
|
113
|
-
};
|
|
114
|
-
system: {
|
|
115
|
-
enqueueSystemEvent: (message: string, opts: SystemEventOpts) => void;
|
|
116
|
-
};
|
|
117
|
-
state?: {
|
|
118
|
-
resolveStateDir?: () => string;
|
|
119
|
-
};
|
|
120
|
-
/** Optional error logger exposed by some runtime implementations. */
|
|
121
|
-
error?: (...args: unknown[]) => void;
|
|
122
|
-
[key: string]: unknown;
|
|
123
|
-
}
|
|
5
|
+
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
|
124
6
|
export declare function setRuntime(next: PluginRuntime): void;
|
|
125
7
|
export declare function getRuntime(): PluginRuntime;
|
|
126
8
|
/**
|
package/dist/src/runtime.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
* Plugin runtime reference
|
|
3
3
|
* Stores the PluginRuntime provided by OpenClaw gateway at startup.
|
|
4
4
|
*/
|
|
5
|
+
import { logTag } from "./constants.js";
|
|
5
6
|
let runtime = null;
|
|
6
7
|
export function setRuntime(next) {
|
|
7
8
|
runtime = next;
|
|
8
9
|
}
|
|
9
10
|
export function getRuntime() {
|
|
10
11
|
if (!runtime) {
|
|
11
|
-
throw new Error(
|
|
12
|
+
throw new Error(`${logTag()} runtime not initialized — plugin not started via gateway?`);
|
|
12
13
|
}
|
|
13
14
|
return runtime;
|
|
14
15
|
}
|
package/dist/src/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/runtime.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,IAAI,OAAO,GAAyB,IAAI,CAAC;AAEzC,MAAM,UAAU,UAAU,CAAC,IAAmB;IAC5C,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,4DAA4D,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM;IACpB,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC"}
|
package/dist/src/send-utils.d.ts
CHANGED
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
/** Markdown to Unicode text formatting (shared by both outbound paths) */
|
|
12
12
|
export declare function formatText(text: string): string;
|
|
13
|
+
export declare function contentTypeToExt(contentType: string): string;
|
|
14
|
+
/** Detect image MIME type from magic bytes (file header) */
|
|
15
|
+
export declare function detectImageMime(buffer: Buffer): string | null;
|
|
16
|
+
/** Map framework MediaKind to WeChat media type */
|
|
17
|
+
export declare function mediaKindToWechatType(kind: string): "image" | "voice" | "video" | "file";
|
|
13
18
|
/** Map file extension to WeChat media type */
|
|
14
19
|
export declare function detectMediaType(ext: string): "image" | "voice" | "video" | "file";
|
|
15
20
|
/** Upload media to WeChat and send via the appropriate message type */
|
|
@@ -28,3 +33,11 @@ export declare function downloadMediaFromUrl(url: string): Promise<{
|
|
|
28
33
|
filename: string;
|
|
29
34
|
ext: string;
|
|
30
35
|
}>;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a thumbnail reference to a WeChat thumb_media_id.
|
|
38
|
+
*
|
|
39
|
+
* Accepts three kinds of input:
|
|
40
|
+
* - URL (http://, https://) or local path (/, ~, file://, data:) → loadWebMedia + uploadMedia
|
|
41
|
+
* - media_id string (anything else) → used directly
|
|
42
|
+
*/
|
|
43
|
+
export declare function resolveThumbMediaId(thumbRef: string, corpId: string, appSecret: string): Promise<string>;
|
package/dist/src/send-utils.js
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { basename, extname } from "node:path";
|
|
12
12
|
import { sendFileMessage, sendImageMessage, sendVideoMessage, sendVoiceMessage, uploadMedia } from "./api.js";
|
|
13
|
-
import { MEDIA_DOWNLOAD_TIMEOUT_MS } from "./constants.js";
|
|
13
|
+
import { logTag, MEDIA_DOWNLOAD_TIMEOUT_MS } from "./constants.js";
|
|
14
|
+
import { getRuntime } from "./runtime.js";
|
|
14
15
|
import { markdownToUnicode } from "./unicode-format.js";
|
|
15
16
|
/** Markdown to Unicode text formatting (shared by both outbound paths) */
|
|
16
17
|
export function formatText(text) {
|
|
@@ -30,15 +31,46 @@ const CONTENT_TYPE_EXT_MAP = {
|
|
|
30
31
|
"video/mp4": ".mp4",
|
|
31
32
|
"application/pdf": ".pdf",
|
|
32
33
|
};
|
|
33
|
-
function contentTypeToExt(contentType) {
|
|
34
|
+
export function contentTypeToExt(contentType) {
|
|
34
35
|
return CONTENT_TYPE_EXT_MAP[contentType] ?? "";
|
|
35
36
|
}
|
|
37
|
+
/** Detect image MIME type from magic bytes (file header) */
|
|
38
|
+
export function detectImageMime(buffer) {
|
|
39
|
+
if (buffer.length < 4)
|
|
40
|
+
return null;
|
|
41
|
+
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46)
|
|
42
|
+
return "image/gif";
|
|
43
|
+
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47)
|
|
44
|
+
return "image/png";
|
|
45
|
+
if (buffer[0] === 0xff && buffer[1] === 0xd8)
|
|
46
|
+
return "image/jpeg";
|
|
47
|
+
if (buffer[0] === 0x42 && buffer[1] === 0x4d)
|
|
48
|
+
return "image/bmp";
|
|
49
|
+
if (buffer.length >= 12 &&
|
|
50
|
+
buffer.subarray(0, 4).toString() === "RIFF" &&
|
|
51
|
+
buffer.subarray(8, 12).toString() === "WEBP")
|
|
52
|
+
return "image/webp";
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
/** Map framework MediaKind to WeChat media type */
|
|
56
|
+
export function mediaKindToWechatType(kind) {
|
|
57
|
+
switch (kind) {
|
|
58
|
+
case "image":
|
|
59
|
+
return "image";
|
|
60
|
+
case "audio":
|
|
61
|
+
return "voice";
|
|
62
|
+
case "video":
|
|
63
|
+
return "video";
|
|
64
|
+
default:
|
|
65
|
+
return "file"; // "document" | "unknown"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
36
68
|
/** Map file extension to WeChat media type */
|
|
37
69
|
export function detectMediaType(ext) {
|
|
38
70
|
ext = ext.toLowerCase();
|
|
39
71
|
if ([".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"].includes(ext))
|
|
40
72
|
return "image";
|
|
41
|
-
if (
|
|
73
|
+
if (ext === ".amr")
|
|
42
74
|
return "voice";
|
|
43
75
|
if ([".mp4", ".avi", ".mov", ".mkv", ".wmv"].includes(ext))
|
|
44
76
|
return "video";
|
|
@@ -71,7 +103,7 @@ export async function downloadMediaFromUrl(url) {
|
|
|
71
103
|
signal: AbortSignal.timeout(MEDIA_DOWNLOAD_TIMEOUT_MS),
|
|
72
104
|
});
|
|
73
105
|
if (!resp.ok) {
|
|
74
|
-
throw new Error(
|
|
106
|
+
throw new Error(`${logTag()} failed to download media: HTTP ${resp.status} from ${url}`);
|
|
75
107
|
}
|
|
76
108
|
const buffer = Buffer.from(await resp.arrayBuffer());
|
|
77
109
|
const urlPath = new URL(resp.url ?? url).pathname;
|
|
@@ -86,4 +118,24 @@ export async function downloadMediaFromUrl(url) {
|
|
|
86
118
|
}
|
|
87
119
|
return { buffer, filename, ext };
|
|
88
120
|
}
|
|
121
|
+
function isMediaSource(value) {
|
|
122
|
+
return /^(https?:\/\/|file:\/\/|data:|[~/])/.test(value);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Resolve a thumbnail reference to a WeChat thumb_media_id.
|
|
126
|
+
*
|
|
127
|
+
* Accepts three kinds of input:
|
|
128
|
+
* - URL (http://, https://) or local path (/, ~, file://, data:) → loadWebMedia + uploadMedia
|
|
129
|
+
* - media_id string (anything else) → used directly
|
|
130
|
+
*/
|
|
131
|
+
export async function resolveThumbMediaId(thumbRef, corpId, appSecret) {
|
|
132
|
+
if (isMediaSource(thumbRef)) {
|
|
133
|
+
const core = getRuntime();
|
|
134
|
+
const loaded = await core.media.loadWebMedia(thumbRef, { optimizeImages: false });
|
|
135
|
+
const uploaded = await uploadMedia(corpId, appSecret, "image", loaded.buffer, loaded.fileName ?? "thumb.jpg");
|
|
136
|
+
return uploaded.media_id;
|
|
137
|
+
}
|
|
138
|
+
// Treat as raw media_id
|
|
139
|
+
return thumbRef;
|
|
140
|
+
}
|
|
89
141
|
//# sourceMappingURL=send-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-utils.js","sourceRoot":"","sources":["../../src/send-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC9G,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"send-utils.js","sourceRoot":"","sources":["../../src/send-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/src/token.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* access_token retrieval and caching
|
|
3
3
|
*/
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
|
-
import { TOKEN_FETCH_TIMEOUT_MS } from "./constants.js";
|
|
5
|
+
import { logTag, TOKEN_FETCH_TIMEOUT_MS } from "./constants.js";
|
|
6
|
+
import { getSharedContext } from "./monitor.js";
|
|
6
7
|
/** Hash the cache key so appSecret is never stored as a plain-text Map key. @internal */
|
|
7
8
|
export function makeCacheKey(corpId, appSecret) {
|
|
8
9
|
const hash = createHash("sha256").update(appSecret).digest("hex").slice(0, 16);
|
|
@@ -21,6 +22,7 @@ export async function getAccessToken(corpId, appSecret) {
|
|
|
21
22
|
const inflight = pending.get(cacheKey);
|
|
22
23
|
if (inflight)
|
|
23
24
|
return inflight;
|
|
25
|
+
getSharedContext()?.botCtx.log?.debug?.(`${logTag()} fetching new access_token`);
|
|
24
26
|
const promise = fetchAccessToken(corpId, appSecret, cacheKey);
|
|
25
27
|
pending.set(cacheKey, promise);
|
|
26
28
|
try {
|
|
@@ -38,20 +40,22 @@ async function fetchAccessToken(corpId, appSecret, cacheKey) {
|
|
|
38
40
|
});
|
|
39
41
|
if (!resp.ok) {
|
|
40
42
|
const text = await resp.text().catch(() => "");
|
|
41
|
-
throw new Error(
|
|
43
|
+
throw new Error(`${logTag()} gettoken HTTP ${resp.status}: ${text.slice(0, 200)}`);
|
|
42
44
|
}
|
|
43
45
|
const data = (await resp.json());
|
|
44
46
|
if (data.errcode !== 0) {
|
|
45
|
-
throw new Error(
|
|
47
|
+
throw new Error(`${logTag()} gettoken failed: ${data.errcode} ${data.errmsg}`);
|
|
46
48
|
}
|
|
47
49
|
cache.set(cacheKey, {
|
|
48
50
|
token: data.access_token,
|
|
49
51
|
expiresAt: Date.now() + data.expires_in * 1000,
|
|
50
52
|
});
|
|
53
|
+
getSharedContext()?.botCtx.log?.info(`${logTag()} access_token refreshed (expires_in=${data.expires_in}s)`);
|
|
51
54
|
return data.access_token;
|
|
52
55
|
}
|
|
53
56
|
/** Clear cached token (e.g. on auth error) */
|
|
54
57
|
export function clearAccessToken(corpId, appSecret) {
|
|
55
58
|
cache.delete(makeCacheKey(corpId, appSecret));
|
|
59
|
+
getSharedContext()?.botCtx.log?.debug?.(`${logTag()} access_token cache cleared`);
|
|
56
60
|
}
|
|
57
61
|
//# sourceMappingURL=token.js.map
|
package/dist/src/token.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/token.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/token.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,SAAiB;IAC5D,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/E,OAAO,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;AAC7B,CAAC;AAOD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;AAC7C,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEnD,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,kCAAkC;AAE3E,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAc,EAAE,SAAiB;IACpE,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEnC,IAAI,MAAM,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,iBAAiB,EAAE,CAAC;QAChE,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,gBAAgB,EAAE,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,EAAE,4BAA4B,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC;IACvB,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,MAAc,EAAE,SAAiB,EAAE,QAAgB;IACjF,0DAA0D;IAC1D,MAAM,GAAG,GAAG,uDAAuD,kBAAkB,CAAC,MAAM,CAAC,eAAe,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;IAC5I,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC5B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,sBAAsB,CAAC;KACpD,CAAC,CAAC;IACH,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,kBAAkB,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA8B,CAAC;IAE9D,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,GAAG,MAAM,EAAE,qBAAqB,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;QAClB,KAAK,EAAE,IAAI,CAAC,YAAY;QACxB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI;KAC/C,CAAC,CAAC;IAEH,gBAAgB,EAAE,EAAE,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM,EAAE,uCAAuC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;IAE5G,OAAO,IAAI,CAAC,YAAY,CAAC;AAC3B,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,SAAiB;IAChE,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAC9C,gBAAgB,EAAE,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,EAAE,6BAA6B,CAAC,CAAC;AACpF,CAAC"}
|